fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@3
|
3
|
fiore@0
|
4 Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
|
fiore@0
|
5 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
6
|
fiore@0
|
7 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
8 it under the terms of the GNU General Public License as published by
|
fiore@0
|
9 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
10 (at your option) any later version.
|
fiore@0
|
11
|
fiore@0
|
12 This program is distributed in the hope that it will be useful,
|
fiore@0
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
15 GNU General Public License for more details.
|
fiore@0
|
16
|
fiore@0
|
17 You should have received a copy of the GNU General Public License
|
fiore@0
|
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@3
|
19 */
|
fiore@0
|
20
|
fiore@0
|
21 package uk.ac.qmul.eecs.ccmi.gui;
|
fiore@0
|
22
|
fiore@0
|
23 import java.awt.BorderLayout;
|
fiore@3
|
24 import java.io.IOException;
|
fiore@0
|
25
|
fiore@0
|
26 import javax.swing.JPanel;
|
fiore@0
|
27 import javax.swing.JScrollPane;
|
fiore@0
|
28 import javax.swing.JSplitPane;
|
fiore@0
|
29 import javax.swing.event.ChangeEvent;
|
fiore@0
|
30 import javax.swing.event.ChangeListener;
|
fiore@0
|
31
|
fiore@3
|
32 import uk.ac.qmul.eecs.ccmi.gui.awareness.AwarenessPanel;
|
fiore@3
|
33 import uk.ac.qmul.eecs.ccmi.gui.awareness.DisplayFilter;
|
fiore@3
|
34 import uk.ac.qmul.eecs.ccmi.network.NetDiagram;
|
fiore@3
|
35
|
fiore@0
|
36 /**
|
fiore@0
|
37 * It's the panel which displays a diagram. It contains a {@link GraphPanel}, a {@link DiagramTree}
|
fiore@3
|
38 * a {@link GraphToolbar} and the {@code AwarenessPanel}.
|
fiore@3
|
39 * It's backed up by an instance of {@code Diagram}.
|
fiore@0
|
40 */
|
fiore@0
|
41 @SuppressWarnings("serial")
|
fiore@0
|
42 public class DiagramPanel extends JPanel{
|
fiore@0
|
43
|
fiore@3
|
44 /**
|
fiore@3
|
45 * Creates a new instance of {@code DiagramPanel} holding the diagram passed as argument.
|
fiore@3
|
46 *
|
fiore@3
|
47 * @param diagram the diagram this panel is backed up by
|
fiore@3
|
48 * @param tabbedPane the tabbed pane this DiagramPanel will be added to. This reference
|
fiore@3
|
49 * is used to updated the tab label when the diagram is modified or save (in the former
|
fiore@3
|
50 * case a star is added to the label, in the latter case the star is removed)
|
fiore@3
|
51 */
|
fiore@3
|
52 public DiagramPanel(Diagram diagram, EditorTabbedPane tabbedPane){
|
fiore@3
|
53 this.diagram = diagram;
|
fiore@3
|
54 this.tabbedPane = tabbedPane;
|
fiore@0
|
55
|
fiore@3
|
56 setName(diagram.getLabel());
|
fiore@3
|
57 setLayout(new BorderLayout());
|
fiore@0
|
58
|
fiore@3
|
59 modelChangeListener = new ChangeListener(){
|
fiore@3
|
60 @Override
|
fiore@3
|
61 public void stateChanged(ChangeEvent e) {
|
fiore@3
|
62 setModified(true);
|
fiore@3
|
63 }
|
fiore@3
|
64 };
|
fiore@3
|
65
|
fiore@3
|
66 toolbar = new GraphToolbar(diagram);
|
fiore@3
|
67 graphPanel = new GraphPanel(diagram, toolbar);
|
fiore@3
|
68 /* the focus must be hold by the tree and the tab panel only */
|
fiore@3
|
69 toolbar.setFocusable(false);
|
fiore@3
|
70 graphPanel.setFocusable(false);
|
fiore@3
|
71
|
fiore@3
|
72 tree = new DiagramTree(diagram);
|
fiore@3
|
73
|
fiore@3
|
74 /* the panel containing the graph and the toolbar and the awareness panel */
|
fiore@3
|
75 visualPanel = new JPanel(new BorderLayout());
|
fiore@3
|
76 visualPanel.add(toolbar, BorderLayout.NORTH);
|
fiore@3
|
77 visualPanel.add(new JScrollPane(graphPanel),BorderLayout.CENTER);
|
fiore@3
|
78 awarenessSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
fiore@3
|
79 awarenessSplitPane.setTopComponent(visualPanel);
|
fiore@3
|
80
|
fiore@3
|
81 /* divides the tree from the visual diagram */
|
fiore@3
|
82 JSplitPane treeSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
|
fiore@3
|
83 new JScrollPane(tree),
|
fiore@3
|
84 awarenessSplitPane);
|
fiore@3
|
85 treeSplitPane.setDividerLocation((int)tree.getPreferredSize().width*2);
|
fiore@3
|
86 add(treeSplitPane, BorderLayout.CENTER);
|
fiore@3
|
87 diagram.getCollectionModel().addChangeListener(modelChangeListener);
|
fiore@3
|
88 }
|
fiore@3
|
89
|
fiore@3
|
90 /**
|
fiore@3
|
91 * When a diagram is saved on the file system the its path is associated to the diagram panel
|
fiore@3
|
92 * and it's shown when the user hover on the its tab title.
|
fiore@3
|
93 *
|
fiore@3
|
94 * @return the path of the file where this diagram has been saved last time or {@code null}
|
fiore@3
|
95 */
|
fiore@3
|
96 public String getFilePath(){
|
fiore@3
|
97 return filePath;
|
fiore@3
|
98 }
|
fiore@3
|
99
|
fiore@3
|
100 /**
|
fiore@3
|
101 * Sets the file path to a new path. This method should be called after the backing diagram has
|
fiore@3
|
102 * been saved to a file.
|
fiore@3
|
103 *
|
fiore@3
|
104 * @param newValue the path of the file where the backing diagram has been saved last time
|
fiore@3
|
105 */
|
fiore@3
|
106 public void setFilePath(String newValue){
|
fiore@3
|
107 filePath = newValue;
|
fiore@3
|
108 }
|
fiore@3
|
109
|
fiore@3
|
110 /**
|
fiore@3
|
111 * Returns a reference to the backing diagram of this diagram panel.
|
fiore@3
|
112 *
|
fiore@3
|
113 * @return a reference to the backing diagram of this diagram panel
|
fiore@3
|
114 */
|
fiore@3
|
115 public Diagram getDiagram(){
|
fiore@3
|
116 return diagram;
|
fiore@3
|
117 }
|
fiore@3
|
118
|
fiore@3
|
119 /**
|
fiore@3
|
120 * Enables or disables the awareness panel of this diagram panel. As default the awareness panel
|
fiore@3
|
121 * is disabled but if the diagram is shared (either on a local or on a remote server) the awareness
|
fiore@3
|
122 * panel gets enabled. In fact, from now on, awareness messages will be received from the server and,
|
fiore@3
|
123 * even if the awareness panel is not visible, some messages (username messages)
|
fiore@3
|
124 * will still have to be taken into account.
|
fiore@3
|
125 *
|
fiore@3
|
126 * @param enabled {@code true} if the panel is to be enabled, {@code false} otherwise.
|
fiore@3
|
127 */
|
fiore@3
|
128 public void setAwarenessPanelEnabled(boolean enabled){
|
fiore@3
|
129 if(!(diagram instanceof NetDiagram))
|
fiore@3
|
130 return;
|
fiore@3
|
131 /* if the display filter has not been created yet, do create it */
|
fiore@3
|
132 DisplayFilter filter = DisplayFilter.getInstance();
|
fiore@3
|
133 if(filter == null)
|
fiore@3
|
134 try{
|
fiore@3
|
135 filter = DisplayFilter.createInstance();
|
fiore@3
|
136 }catch(IOException ioe){
|
fiore@3
|
137 SpeechOptionPane.showMessageDialog(this, ioe.getLocalizedMessage());
|
fiore@3
|
138 return;
|
fiore@3
|
139 }
|
fiore@3
|
140
|
fiore@3
|
141 NetDiagram netDiagram = (NetDiagram)diagram;
|
fiore@3
|
142 if(enabled){
|
fiore@3
|
143 awarenessPanel = new AwarenessPanel(diagram.getName());
|
fiore@3
|
144 awarenessPanelScrollPane = new JScrollPane(awarenessPanel);
|
fiore@3
|
145 netDiagram.enableAwareness(awarenessPanel);
|
fiore@3
|
146 if(awarenessPanelListener != null)
|
fiore@3
|
147 awarenessPanelListener.awarenessPanelEnabled(true);
|
fiore@3
|
148 }else{ //disabled
|
fiore@3
|
149 netDiagram.disableAwareness(awarenessPanel);
|
fiore@3
|
150 if(awarenessSplitPane.getRightComponent() != null){
|
fiore@3
|
151 // hide the panel
|
fiore@3
|
152 awarenessSplitPane.remove(awarenessPanelScrollPane);
|
fiore@3
|
153 }
|
fiore@3
|
154 awarenessPanelScrollPane = null;
|
fiore@3
|
155 awarenessPanel = null;
|
fiore@3
|
156 awarenessSplitPane.validate();
|
fiore@3
|
157 if(awarenessPanelListener != null)
|
fiore@3
|
158 awarenessPanelListener.awarenessPanelEnabled(false);
|
fiore@3
|
159 }
|
fiore@3
|
160 }
|
fiore@3
|
161
|
fiore@3
|
162 /**
|
fiore@3
|
163 * Makes the awareness panel visible or invisible, assuming that it has been enabled beforehand. If the
|
fiore@3
|
164 * awareness panel hasn't been enables this call has no effect.
|
fiore@3
|
165 *
|
fiore@3
|
166 * @param visible {@code true} if the panel is to be made visible, {@code false} otherwise.
|
fiore@3
|
167 */
|
fiore@3
|
168 public void setAwarenessPanelVisible(boolean visible){
|
fiore@3
|
169 if(awarenessPanelScrollPane == null)
|
fiore@3
|
170 return;
|
fiore@3
|
171 if(visible){
|
fiore@3
|
172 awarenessSplitPane.setRightComponent(awarenessPanelScrollPane);
|
fiore@3
|
173 awarenessSplitPane.setDividerLocation(0.8);
|
fiore@3
|
174 awarenessSplitPane.setResizeWeight(1.0);
|
fiore@3
|
175 awarenessSplitPane.validate();
|
fiore@3
|
176 if(awarenessPanelListener != null)
|
fiore@3
|
177 awarenessPanelListener.awarenessPanelVisible(true);
|
fiore@3
|
178 }else{
|
fiore@3
|
179 awarenessSplitPane.remove(awarenessPanelScrollPane);
|
fiore@3
|
180 awarenessSplitPane.validate();
|
fiore@3
|
181 if(awarenessPanelListener != null)
|
fiore@3
|
182 awarenessPanelListener.awarenessPanelVisible(false);
|
fiore@3
|
183 }
|
fiore@3
|
184 }
|
fiore@3
|
185
|
fiore@3
|
186 /**
|
fiore@3
|
187 * Queries the diagram panel on whether the awareness panel is currently visible.
|
fiore@3
|
188 *
|
fiore@3
|
189 * @return {@code true} if the awareness panel is currently visible, {@code false} otherwise.
|
fiore@3
|
190 */
|
fiore@3
|
191 public boolean isAwarenessPanelVisible(){
|
fiore@3
|
192 return (awarenessSplitPane.getRightComponent() != null);
|
fiore@3
|
193 }
|
fiore@3
|
194
|
fiore@3
|
195 /**
|
fiore@3
|
196 * Returns a reference to the inner awareness panel.
|
fiore@3
|
197 *
|
fiore@3
|
198 * @return the inner awareness panel if it has been enabled of {@code null} otherwise
|
fiore@3
|
199 */
|
fiore@3
|
200 public AwarenessPanel getAwarenessPanel(){
|
fiore@3
|
201 return awarenessPanel;
|
fiore@3
|
202 }
|
fiore@3
|
203
|
fiore@3
|
204 /**
|
fiore@5
|
205 * Sets the backing up delegate diagram for this panel. This method is used when a diagram is shared
|
fiore@3
|
206 * (or reverted). A shared diagram has a different way of updating the
|
fiore@3
|
207 * The modified status is changed according to
|
fiore@3
|
208 * the modified status of the {@code DiagramModel} internal to the new {@code Diagram}
|
fiore@3
|
209 *
|
fiore@5
|
210 * @param diagram the backing up delegate diagram
|
fiore@3
|
211 */
|
fiore@3
|
212 public void setDiagram(Diagram diagram){
|
fiore@3
|
213 /* remove the listener from the old model */
|
fiore@3
|
214 this.diagram.getCollectionModel().removeChangeListener(modelChangeListener);
|
fiore@3
|
215 diagram.getCollectionModel().addChangeListener(modelChangeListener);
|
fiore@3
|
216
|
fiore@3
|
217 this.diagram = diagram;
|
fiore@3
|
218 tree.setDiagram(diagram);
|
fiore@3
|
219 graphPanel.setModelUpdater(diagram.getModelUpdater());
|
fiore@3
|
220 setName(diagram.getLabel());
|
fiore@3
|
221 /* set the * according to the new diagram's model modification status */
|
fiore@3
|
222 setModified(isModified());
|
fiore@3
|
223 }
|
fiore@3
|
224
|
fiore@3
|
225 /**
|
fiore@3
|
226 * Returns a reference to the graph panel in this diagram panel. The tree's model is the
|
fiore@3
|
227 * model returned by a calling {@code getTreeModel()} on the backing diagram.
|
fiore@3
|
228 *
|
fiore@3
|
229 * @return the graph panel contained by this diagram panel
|
fiore@3
|
230 */
|
fiore@3
|
231 public GraphPanel getGraphPanel(){
|
fiore@3
|
232 return graphPanel;
|
fiore@3
|
233 }
|
fiore@3
|
234
|
fiore@3
|
235 /**
|
fiore@3
|
236 * Returns a reference to the tree in this diagram panel. The graph model is the
|
fiore@3
|
237 * model returned by a calling {@code getCollectionModel()} on the backing diagram.
|
fiore@3
|
238 *
|
fiore@3
|
239 * @return the tree contained by this diagram panel
|
fiore@3
|
240 */
|
fiore@3
|
241 public DiagramTree getTree(){
|
fiore@3
|
242 return tree;
|
fiore@3
|
243 }
|
fiore@3
|
244
|
fiore@3
|
245 /**
|
fiore@3
|
246 * Changes the {@code modified} status of the backing diagram of this panel. If set to {@code true}
|
fiore@3
|
247 * then a star will appear after the name of the diagram, returned by {@code getName()}.
|
fiore@3
|
248 *
|
fiore@3
|
249 * When called passing false as argument (which should be done after the diagram is saved on a file)
|
fiore@3
|
250 * listeners are notified that the diagram has been saved.
|
fiore@3
|
251 *
|
fiore@3
|
252 * @param modified {@code true} when the diagram has been modified, {@code false} when it has been saved
|
fiore@3
|
253 */
|
fiore@3
|
254 public void setModified(boolean modified){
|
fiore@3
|
255 if(!modified)
|
fiore@3
|
256 diagram.getCollectionModel().setUnmodified();
|
fiore@3
|
257 /* add an asterisk to notify that the diagram has changed */
|
fiore@3
|
258 if(modified)
|
fiore@3
|
259 setName(getName()+"*");
|
fiore@3
|
260 else
|
fiore@3
|
261 setName(diagram.getLabel());
|
fiore@3
|
262 tabbedPane.refreshComponentTabTitle(this);
|
fiore@3
|
263 }
|
fiore@3
|
264
|
fiore@3
|
265 /**
|
fiore@3
|
266 * Whether the backing diagram has been modified. The diagram is modified as a result of changes
|
fiore@3
|
267 * to the {@code TreeModel} or {@code CollectionModel} it contains. To change the {@code modified}
|
fiore@3
|
268 * status of the diagram (and of its models) {@code setModified()} must be used.
|
fiore@3
|
269 *
|
fiore@5
|
270 * @return {@code true} if the diagram is modified, {@code false} otherwise
|
fiore@3
|
271 */
|
fiore@3
|
272 public boolean isModified(){
|
fiore@3
|
273 return diagram.getCollectionModel().isModified();
|
fiore@3
|
274 }
|
fiore@3
|
275
|
fiore@3
|
276 void setAwarenessPanelListener(AwarenessPanelEnablingListener listener){
|
fiore@3
|
277 awarenessPanelListener = listener;
|
fiore@3
|
278 }
|
fiore@3
|
279
|
fiore@3
|
280 private Diagram diagram;
|
fiore@3
|
281 private GraphPanel graphPanel;
|
fiore@3
|
282 private JSplitPane awarenessSplitPane;
|
fiore@3
|
283 private DiagramTree tree;
|
fiore@3
|
284 private JPanel visualPanel;
|
fiore@3
|
285 private GraphToolbar toolbar;
|
fiore@3
|
286 private AwarenessPanel awarenessPanel;
|
fiore@3
|
287 private JScrollPane awarenessPanelScrollPane;
|
fiore@3
|
288 private String filePath;
|
fiore@3
|
289 private ChangeListener modelChangeListener;
|
fiore@3
|
290 private EditorTabbedPane tabbedPane;
|
fiore@3
|
291 private AwarenessPanelEnablingListener awarenessPanelListener;
|
fiore@0
|
292 }
|
fiore@3
|
293
|
fiore@3
|
294 interface AwarenessPanelEnablingListener {
|
fiore@3
|
295 public void awarenessPanelEnabled(boolean enabled);
|
fiore@3
|
296 public void awarenessPanelVisible(boolean visible);
|
fiore@3
|
297 }
|
fiore@3
|
298
|