view java/src/uk/ac/qmul/eecs/ccmi/gui/DiagramPanel.java @ 8:ea7885bd9bff tip

fixed bug : render solid line as dotted/dashed when moving the stylus from dotted/dashed to solid
author ccmi-guest
date Thu, 03 Jul 2014 16:12:20 +0100
parents d66dd5880081
children
line wrap: on
line source
/*  
 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool

 Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
 Copyright (C) 2011  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package uk.ac.qmul.eecs.ccmi.gui;

import java.awt.BorderLayout;
import java.io.IOException;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import uk.ac.qmul.eecs.ccmi.gui.awareness.AwarenessPanel;
import uk.ac.qmul.eecs.ccmi.gui.awareness.DisplayFilter;
import uk.ac.qmul.eecs.ccmi.network.NetDiagram;

/**
 * It's the panel which displays a diagram. It contains a {@link GraphPanel}, a {@link DiagramTree} 
 * a {@link GraphToolbar} and the {@code AwarenessPanel}.
 * It's backed up by an instance of {@code Diagram}.
 */
@SuppressWarnings("serial")
public class DiagramPanel extends JPanel{

	/**
	 * Creates a new instance of {@code DiagramPanel} holding the diagram passed as argument. 
	 * 	
	 * @param diagram the diagram this panel is backed up by
	 * @param tabbedPane the tabbed pane this DiagramPanel will be added to. This reference 
	 * is used to updated the tab label when the diagram is modified or save (in the former
	 * case a star is added to the label, in the latter case the star is removed)
	 */
	public DiagramPanel(Diagram diagram, EditorTabbedPane tabbedPane){
		this.diagram = diagram;
		this.tabbedPane = tabbedPane;

		setName(diagram.getLabel());
		setLayout(new BorderLayout());

		modelChangeListener = new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent e) {
				setModified(true);
			}
		};

		toolbar = new GraphToolbar(diagram);
		graphPanel = new GraphPanel(diagram, toolbar);
		/* the focus must be hold by the tree and the tab panel only */
		toolbar.setFocusable(false);
		graphPanel.setFocusable(false);

		tree = new DiagramTree(diagram);

		/* the panel containing the graph and the toolbar and the awareness panel */
		visualPanel = new JPanel(new BorderLayout());
		visualPanel.add(toolbar, BorderLayout.NORTH);
		visualPanel.add(new JScrollPane(graphPanel),BorderLayout.CENTER);
		awarenessSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		awarenessSplitPane.setTopComponent(visualPanel);

		/* divides the tree from the visual diagram */
		JSplitPane treeSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
				new JScrollPane(tree),
				awarenessSplitPane);
		treeSplitPane.setDividerLocation((int)tree.getPreferredSize().width*2);
		add(treeSplitPane, BorderLayout.CENTER);
		diagram.getCollectionModel().addChangeListener(modelChangeListener);
	}

	/**
	 * When a diagram is saved on the file system the its path is associated to the diagram panel 
	 * and it's shown when the user hover on the its tab title.  
	 * 
	 * @return the path of the file where this diagram has been saved last time or {@code null}  
	 */
	public String getFilePath(){
		return filePath;
	}
	
	/**
	 * Sets the file path to a new path. This method should be called after the backing diagram has
	 * been saved to a file.
	 * 
	 * @param newValue the path of the file where the backing diagram has been saved last time
	 */
	public void setFilePath(String newValue){
		filePath = newValue;
	}

	/**
	 * Returns a reference to the backing diagram of this diagram panel.
	 * 
	 * @return a reference to the backing diagram of this diagram panel
	 */
	public Diagram getDiagram(){
		return diagram;
	}

	/**
	 * Enables or disables the awareness panel of this diagram panel. As default the awareness panel 
	 * is disabled but if the diagram is shared (either on a local or on a remote server) the awareness 
	 * panel gets enabled. In fact, from now on, awareness messages will be received from the server and,
	 * even if the awareness panel is not visible, some messages (username messages) 
	 * will still have to be taken into account.
	 *    
	 * @param enabled {@code true} if the panel is to be enabled, {@code false} otherwise.
	 */
	public void setAwarenessPanelEnabled(boolean enabled){
		if(!(diagram instanceof NetDiagram))
			return;
		/* if the display filter has not been created yet, do create it */
		DisplayFilter filter = DisplayFilter.getInstance();
		if(filter == null)
			try{
				filter = DisplayFilter.createInstance();
			}catch(IOException ioe){
				SpeechOptionPane.showMessageDialog(this, ioe.getLocalizedMessage());
				return;
			}

			NetDiagram netDiagram = (NetDiagram)diagram;
			if(enabled){
				awarenessPanel = new AwarenessPanel(diagram.getName());
				awarenessPanelScrollPane = new JScrollPane(awarenessPanel);
				netDiagram.enableAwareness(awarenessPanel);
				if(awarenessPanelListener != null)
					awarenessPanelListener.awarenessPanelEnabled(true);
			}else{ //disabled
				netDiagram.disableAwareness(awarenessPanel);
				if(awarenessSplitPane.getRightComponent() != null){
					// hide the panel
					awarenessSplitPane.remove(awarenessPanelScrollPane);
				}
				awarenessPanelScrollPane = null;
				awarenessPanel = null;
				awarenessSplitPane.validate();
				if(awarenessPanelListener != null)
					awarenessPanelListener.awarenessPanelEnabled(false);
			}
	}

	/**
	 * Makes the awareness panel visible or invisible, assuming that it has been enabled beforehand. If the 
	 * awareness panel hasn't been enables this call has no effect.  
	 * 
	 * @param visible {@code true} if the panel is to be made visible, {@code false} otherwise.
	 */
	public void setAwarenessPanelVisible(boolean visible){
		if(awarenessPanelScrollPane == null)
			return;
		if(visible){
			awarenessSplitPane.setRightComponent(awarenessPanelScrollPane);
			awarenessSplitPane.setDividerLocation(0.8);
			awarenessSplitPane.setResizeWeight(1.0);
			awarenessSplitPane.validate();
			if(awarenessPanelListener != null)
				awarenessPanelListener.awarenessPanelVisible(true);
		}else{
			awarenessSplitPane.remove(awarenessPanelScrollPane);
			awarenessSplitPane.validate();
			if(awarenessPanelListener != null)
				awarenessPanelListener.awarenessPanelVisible(false);
		}
	}

	/**
	 * Queries the diagram panel on whether the awareness panel is currently visible.  
	 * 
	 * @return {@code true} if the awareness panel is currently visible, {@code false} otherwise. 
	 */
	public boolean isAwarenessPanelVisible(){
		return (awarenessSplitPane.getRightComponent() != null);
	}

	/**
	 * Returns a reference to the inner awareness panel. 
	 * 
	 * @return the inner awareness panel if it has been enabled of {@code null} otherwise
	 */
	public AwarenessPanel getAwarenessPanel(){
		return awarenessPanel;
	}

	/**
	 * Sets the backing up delegate diagram for this panel. This method is used when a diagram is shared 
	 * (or reverted). A shared diagram has a different way of updating the   
	 * The modified status is changed according to
	 * the modified status of the {@code DiagramModel} internal to the new {@code Diagram}   
	 * 
	 * @param diagram the backing up delegate diagram 
	 */
	public void setDiagram(Diagram diagram){
		/* remove the listener from the old model  */
		this.diagram.getCollectionModel().removeChangeListener(modelChangeListener);
		diagram.getCollectionModel().addChangeListener(modelChangeListener);

		this.diagram = diagram;
		tree.setDiagram(diagram);
		graphPanel.setModelUpdater(diagram.getModelUpdater());
		setName(diagram.getLabel());
		/* set the * according to the new diagram's model modification status */
		setModified(isModified());
	}

	/**
	 * Returns a reference to the graph panel in this diagram panel. The tree's model is the 
	 * model returned by a calling {@code getTreeModel()} on the backing diagram.   
	 * 
	 * @return the graph panel  contained by this diagram panel 
	 */
	public GraphPanel getGraphPanel(){
		return graphPanel;
	}

	/**
	 * Returns a reference to the tree in this diagram panel. The graph model is the 
	 * model returned by a calling {@code getCollectionModel()} on the backing diagram.   
	 * 
	 * @return the tree contained by this diagram panel 
	 */
	public DiagramTree getTree(){
		return tree;
	}

	/**
	 * Changes the {@code modified} status of the backing diagram of this panel. If set to {@code true} 
	 * then a star will appear after the name of the diagram, returned by {@code getName()}. 
	 * 
	 * When called passing false as argument (which should be done after the diagram is saved on a file)  
	 * listeners are notified that the diagram has been saved. 
	 * 
	 * @param modified {@code true} when the diagram has been modified, {@code false} when it has been saved 	
	 */
	public void setModified(boolean modified){
		if(!modified)
			diagram.getCollectionModel().setUnmodified();
		/* add an asterisk to notify that the diagram has changed */
		if(modified)
			setName(getName()+"*");
		else 
			setName(diagram.getLabel());
		tabbedPane.refreshComponentTabTitle(this);
	}

	/**
	 * Whether the backing diagram has been modified. The diagram is modified as a result of changes
	 * to the {@code TreeModel} or {@code CollectionModel} it contains. To change the {@code modified}
	 * status of the diagram (and of its models) {@code setModified()} must be used. 
	 * 
	 * @return {@code true} if the diagram is modified, {@code false} otherwise
	 */
	public boolean isModified(){
		return diagram.getCollectionModel().isModified();
	}

	void setAwarenessPanelListener(AwarenessPanelEnablingListener listener){
		awarenessPanelListener = listener;
	}

	private Diagram diagram;
	private GraphPanel graphPanel;
	private JSplitPane awarenessSplitPane;
	private DiagramTree tree;
	private JPanel visualPanel;
	private GraphToolbar toolbar;
	private AwarenessPanel awarenessPanel;
	private JScrollPane awarenessPanelScrollPane;
	private String filePath;
	private ChangeListener modelChangeListener;
	private EditorTabbedPane tabbedPane;
	private AwarenessPanelEnablingListener awarenessPanelListener;
}

interface AwarenessPanelEnablingListener {
	public void awarenessPanelEnabled(boolean enabled);
	public void awarenessPanelVisible(boolean visible);
}