fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@0
|
3
|
fiore@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@0
|
5
|
fiore@0
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@0
|
7 it under the terms of the GNU General Public License as published by
|
fiore@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@0
|
9 (at your option) any later version.
|
fiore@0
|
10
|
fiore@0
|
11 This program is distributed in the hope that it will be useful,
|
fiore@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@0
|
14 GNU General Public License for more details.
|
fiore@0
|
15
|
fiore@0
|
16 You should have received a copy of the GNU General Public License
|
fiore@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@0
|
18 */
|
fiore@0
|
19 package uk.ac.qmul.eecs.ccmi.gui;
|
fiore@0
|
20
|
fiore@0
|
21 import java.awt.geom.Point2D;
|
fiore@0
|
22 import java.util.Set;
|
fiore@0
|
23
|
fiore@0
|
24 import uk.ac.qmul.eecs.ccmi.diagrammodel.CollectionModel;
|
fiore@0
|
25 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement;
|
fiore@0
|
26 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModel;
|
fiore@3
|
27 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramTreeNode;
|
fiore@0
|
28 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties;
|
fiore@0
|
29 import uk.ac.qmul.eecs.ccmi.diagrammodel.TreeModel;
|
fiore@0
|
30 import uk.ac.qmul.eecs.ccmi.gui.persistence.PrototypePersistenceDelegate;
|
fiore@3
|
31 import uk.ac.qmul.eecs.ccmi.network.AwarenessMessage;
|
fiore@3
|
32 import uk.ac.qmul.eecs.ccmi.network.DiagramEventActionSource;
|
fiore@0
|
33
|
fiore@0
|
34 /**
|
fiore@3
|
35 * The {@code Diagram} class holds all the data needed for a representation of the diagram. It is used by component classes
|
fiore@0
|
36 * such as {@link GraphPanel} and {@link DiagramTree} to draw the diagram by accessing the diagram model or by
|
fiore@0
|
37 * {@link EditorTabbedPane} to assign a title to the tabs out of the diagram name.
|
fiore@0
|
38 *
|
fiore@0
|
39 */
|
fiore@0
|
40 public abstract class Diagram implements Cloneable {
|
fiore@0
|
41
|
fiore@3
|
42 /**
|
fiore@3
|
43 * Crates a new instance of a Diagram. The diagram created through this method is not shared with any peer via
|
fiore@3
|
44 * a server.
|
fiore@3
|
45 * @param name the name of the diagram.
|
fiore@3
|
46 * @param nodes an array of node prototypes. Nodes inserted by users in the diagram will be created by cloning these nodes.
|
fiore@3
|
47 * @param edges an array of edge prototypes. Edges inserted by users in the diagram will be created by cloning these edges.
|
fiore@3
|
48 * @param prototypePersistenceDelegate a delegate class to handle nodes and edges persistence.
|
fiore@3
|
49 * @return a new instance of {@code Diagram}
|
fiore@3
|
50 */
|
fiore@0
|
51 public static Diagram newInstance(String name, Node[] nodes, Edge[] edges, PrototypePersistenceDelegate prototypePersistenceDelegate){
|
fiore@0
|
52 return new LocalDiagram(name,nodes,edges,prototypePersistenceDelegate);
|
fiore@0
|
53 }
|
fiore@0
|
54
|
fiore@3
|
55 /**
|
fiore@3
|
56 * Returns the name of the diagram. The name identifies the diagram uniquely in the editor. There cannot
|
fiore@3
|
57 * be two diagrams with the same name open at the same time. This makes things easier when sharing diagrams
|
fiore@3
|
58 * with other users via the network.
|
fiore@3
|
59 *
|
fiore@3
|
60 * @return the name of the diagram
|
fiore@3
|
61 */
|
fiore@0
|
62 public abstract String getName();
|
fiore@0
|
63
|
fiore@3
|
64 /**
|
fiore@3
|
65 * Assign this diagram a new name.
|
fiore@3
|
66 * @param name the new name of the diagram
|
fiore@3
|
67 */
|
fiore@0
|
68 public abstract void setName(String name);
|
fiore@0
|
69
|
fiore@3
|
70 /**
|
fiore@3
|
71 * Returns an array with the node prototypes. Node prototypes are used when creating new node
|
fiore@3
|
72 * instances via the {@code clone()} method.
|
fiore@3
|
73 *
|
fiore@3
|
74 * @return an array of nodes
|
fiore@3
|
75 */
|
fiore@0
|
76 public abstract Node[] getNodePrototypes();
|
fiore@0
|
77
|
fiore@3
|
78 /**
|
fiore@3
|
79 * Returns an array with the edge prototypes. Edge prototypes are used when creating new edge
|
fiore@3
|
80 * instances via the {@code clone()} method.
|
fiore@3
|
81 *
|
fiore@3
|
82 * @return an array of edges
|
fiore@3
|
83 */
|
fiore@0
|
84 public abstract Edge[] getEdgePrototypes();
|
fiore@0
|
85
|
fiore@3
|
86 /**
|
fiore@3
|
87 * Returns the tree model of this diagram. Note that each diagram holds a {@code DiagramModel}
|
fiore@3
|
88 * which has two sub-models ({@code TreeModel} and {@code CollectionModel}). Changes on one
|
fiore@3
|
89 * sub-model will affect the other model as well.
|
fiore@3
|
90 *
|
fiore@3
|
91 * @return the tree model of this diagram
|
fiore@3
|
92 *
|
fiore@3
|
93 * @see uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModel uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModel
|
fiore@3
|
94 */
|
fiore@0
|
95 public abstract TreeModel<Node,Edge> getTreeModel();
|
fiore@0
|
96
|
fiore@3
|
97 /**
|
fiore@3
|
98 * Returns the collection model of this diagram. Note that each diagram holds a {@code DiagramModel}
|
fiore@3
|
99 * which has two sub-models ({@code TreeModel} and {@code CollectionModel}). Changes on one
|
fiore@3
|
100 * sub-model will affect the other model as well.
|
fiore@3
|
101 *
|
fiore@3
|
102 * @return the tree model of this diagram
|
fiore@3
|
103 *
|
fiore@3
|
104 * @see uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModel uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModel
|
fiore@3
|
105 */
|
fiore@0
|
106 public abstract CollectionModel<Node,Edge> getCollectionModel();
|
fiore@0
|
107
|
fiore@3
|
108 /**
|
fiore@3
|
109 * Returns the model updater of this diagram. The model updater is the delegate for all the
|
fiore@3
|
110 * update operations affecting the diagram model.
|
fiore@3
|
111 *
|
fiore@3
|
112 * @return the model updater for this diagram
|
fiore@3
|
113 */
|
fiore@0
|
114 public abstract DiagramModelUpdater getModelUpdater();
|
fiore@0
|
115
|
fiore@3
|
116 /**
|
fiore@3
|
117 * Returns the label of the diagram. The label is slightly different from the name as it's the string
|
fiore@3
|
118 * appearing in the tabbed pane of the editor. It includes asterisk character at the end when the {@code DiagramModel}
|
fiore@3
|
119 * of this class has been changed and not yet saved on hard disk.
|
fiore@3
|
120 *
|
fiore@3
|
121 * @return a label for this diagram
|
fiore@3
|
122 */
|
fiore@0
|
123 public abstract String getLabel();
|
fiore@0
|
124
|
fiore@3
|
125 /**
|
fiore@3
|
126 * Returns the delegates for this diagram for nodes and edges prototypes persistence.
|
fiore@3
|
127 * When saving a diagram to an xml file each node and edge of the prototypes is encoded
|
fiore@3
|
128 * in the xml file. Indeed the template of a diagram is made of of its prototypes.
|
fiore@3
|
129 * In the template is held the general attributes common to all the nodes and edges, like
|
fiore@3
|
130 * for instance the type of a node but not its current position.
|
fiore@3
|
131 *
|
fiore@3
|
132 * @return the PrototypePersistenceDelegate for this diagram
|
fiore@3
|
133 */
|
fiore@0
|
134 public abstract PrototypePersistenceDelegate getPrototypePersistenceDelegate();
|
fiore@0
|
135
|
fiore@0
|
136 @Override
|
fiore@0
|
137 public Object clone(){
|
fiore@0
|
138 try {
|
fiore@0
|
139 return super.clone();
|
fiore@0
|
140 } catch (CloneNotSupportedException e) {
|
fiore@0
|
141 throw new RuntimeException(e);
|
fiore@0
|
142 }
|
fiore@0
|
143 }
|
fiore@0
|
144
|
fiore@0
|
145 private static class LocalDiagram extends Diagram {
|
fiore@0
|
146
|
fiore@0
|
147 private LocalDiagram(String name, Node[] nodes, Edge[] edges,PrototypePersistenceDelegate prototypePersistenceDelegate){
|
fiore@0
|
148 this.name = name;
|
fiore@0
|
149 this.nodes = nodes;
|
fiore@0
|
150 this.edges = edges;
|
fiore@0
|
151 this.prototypePersistenceDelegate = prototypePersistenceDelegate;
|
fiore@0
|
152 diagramModel = new DiagramModel<Node,Edge>(nodes,edges);
|
fiore@0
|
153 innerModelUpdater = new InnerModelUpdater();
|
fiore@0
|
154 }
|
fiore@0
|
155
|
fiore@0
|
156 @Override
|
fiore@0
|
157 public String getName(){
|
fiore@0
|
158 return name;
|
fiore@0
|
159 }
|
fiore@0
|
160
|
fiore@0
|
161 @Override
|
fiore@0
|
162 public void setName(String name){
|
fiore@0
|
163 this.name = name;
|
fiore@0
|
164 }
|
fiore@0
|
165
|
fiore@0
|
166 @Override
|
fiore@0
|
167 public Node[] getNodePrototypes(){
|
fiore@0
|
168 return nodes;
|
fiore@0
|
169 }
|
fiore@0
|
170
|
fiore@0
|
171 @Override
|
fiore@0
|
172 public Edge[] getEdgePrototypes(){
|
fiore@0
|
173 return edges;
|
fiore@0
|
174 }
|
fiore@0
|
175
|
fiore@0
|
176 @Override
|
fiore@0
|
177 public TreeModel<Node,Edge> getTreeModel(){
|
fiore@0
|
178 return diagramModel.getTreeModel();
|
fiore@0
|
179 }
|
fiore@0
|
180
|
fiore@0
|
181 @Override
|
fiore@0
|
182 public CollectionModel<Node,Edge> getCollectionModel(){
|
fiore@0
|
183 return diagramModel.getDiagramCollection();
|
fiore@0
|
184 }
|
fiore@0
|
185
|
fiore@0
|
186 @Override
|
fiore@0
|
187 public String getLabel(){
|
fiore@0
|
188 return name;
|
fiore@0
|
189 }
|
fiore@0
|
190
|
fiore@0
|
191 @Override
|
fiore@0
|
192 public DiagramModelUpdater getModelUpdater(){
|
fiore@0
|
193 return innerModelUpdater;
|
fiore@0
|
194 }
|
fiore@0
|
195
|
fiore@0
|
196 @Override
|
fiore@0
|
197 public String toString(){
|
fiore@0
|
198 return name;
|
fiore@0
|
199 }
|
fiore@0
|
200
|
fiore@0
|
201 @Override
|
fiore@0
|
202 public PrototypePersistenceDelegate getPrototypePersistenceDelegate(){
|
fiore@0
|
203 return prototypePersistenceDelegate;
|
fiore@0
|
204 }
|
fiore@0
|
205
|
fiore@3
|
206 /**
|
fiore@3
|
207 * Creates a new {@code Diagram} by clonation.
|
fiore@3
|
208 */
|
fiore@0
|
209 @Override
|
fiore@0
|
210 public Object clone(){
|
fiore@0
|
211 LocalDiagram clone = (LocalDiagram)super.clone();
|
fiore@0
|
212 clone.name = getName();
|
fiore@0
|
213 clone.nodes = getNodePrototypes();
|
fiore@0
|
214 clone.edges = getEdgePrototypes();
|
fiore@0
|
215 /* constructor with no args makes just a dummy wrapper */
|
fiore@0
|
216 clone.diagramModel = new DiagramModel<Node,Edge>(nodes,edges);
|
fiore@0
|
217 clone.innerModelUpdater = clone.new InnerModelUpdater();
|
fiore@0
|
218 return clone;
|
fiore@0
|
219 }
|
fiore@0
|
220
|
fiore@0
|
221 private DiagramModel<Node,Edge> diagramModel;
|
fiore@0
|
222 private InnerModelUpdater innerModelUpdater;
|
fiore@0
|
223 private PrototypePersistenceDelegate prototypePersistenceDelegate;
|
fiore@0
|
224 private String name;
|
fiore@0
|
225 private Node[] nodes;
|
fiore@0
|
226 private Edge[] edges;
|
fiore@0
|
227
|
fiore@0
|
228 private class InnerModelUpdater implements DiagramModelUpdater {
|
fiore@0
|
229
|
fiore@0
|
230 @Override
|
fiore@3
|
231 public boolean getLock(DiagramTreeNode treeNode, Lock lock, DiagramEventActionSource source) {
|
fiore@0
|
232 /* using a non shared diagram requires no actual lock, therefore the answer is always yes */
|
fiore@0
|
233 return true;
|
fiore@0
|
234 }
|
fiore@0
|
235
|
fiore@0
|
236 @Override
|
fiore@3
|
237 public void yieldLock(DiagramTreeNode treeNode, Lock lock, DiagramEventActionSource actionSource) {}
|
fiore@0
|
238
|
fiore@3
|
239 @Override
|
fiore@3
|
240 public void sendAwarenessMessage(AwarenessMessage.Name awMsgName, Object source){}
|
fiore@3
|
241
|
fiore@0
|
242 @Override
|
fiore@3
|
243 public void insertInCollection(DiagramElement element,DiagramEventSource source) {
|
fiore@0
|
244 if(element instanceof Node)
|
fiore@3
|
245 diagramModel.getDiagramCollection().insert((Node)element,source);
|
fiore@0
|
246 else
|
fiore@3
|
247 diagramModel.getDiagramCollection().insert((Edge)element,source);
|
fiore@0
|
248 }
|
fiore@0
|
249
|
fiore@0
|
250 @Override
|
fiore@0
|
251 public void insertInTree(DiagramElement element) {
|
fiore@0
|
252 if(element instanceof Node)
|
fiore@3
|
253 diagramModel.getTreeModel().insertTreeNode((Node)element,DiagramEventSource.TREE);
|
fiore@0
|
254 else
|
fiore@3
|
255 diagramModel.getTreeModel().insertTreeNode((Edge)element,DiagramEventSource.TREE);
|
fiore@0
|
256 }
|
fiore@0
|
257
|
fiore@0
|
258 @Override
|
fiore@3
|
259 public void takeOutFromCollection(DiagramElement element, DiagramEventSource source) {
|
fiore@3
|
260 diagramModel.getDiagramCollection().takeOut(element,source);
|
fiore@0
|
261 }
|
fiore@0
|
262
|
fiore@0
|
263 @Override
|
fiore@0
|
264 public void takeOutFromTree(DiagramElement element) {
|
fiore@3
|
265 diagramModel.getTreeModel().takeTreeNodeOut(element,DiagramEventSource.TREE);
|
fiore@0
|
266 }
|
fiore@0
|
267
|
fiore@0
|
268 @Override
|
fiore@3
|
269 public void setName(DiagramElement element, String name,DiagramEventSource source) {
|
fiore@3
|
270 element.setName(name,source);
|
fiore@0
|
271 }
|
fiore@0
|
272
|
fiore@0
|
273 @Override
|
fiore@3
|
274 public void setNotes(DiagramTreeNode treeNode, String notes,DiagramEventSource source) {
|
fiore@3
|
275 diagramModel.getTreeModel().setNotes(treeNode, notes,source);
|
fiore@0
|
276 }
|
fiore@0
|
277
|
fiore@0
|
278 @Override
|
fiore@0
|
279 public void setProperty(Node node, String type, int index,
|
fiore@3
|
280 String value,DiagramEventSource source) {
|
fiore@3
|
281 node.setProperty(type, index, value,source);
|
fiore@0
|
282 }
|
fiore@0
|
283
|
fiore@0
|
284 @Override
|
fiore@3
|
285 public void setProperties(Node node, NodeProperties properties,DiagramEventSource source) {
|
fiore@3
|
286 node.setProperties(properties,source);
|
fiore@0
|
287 }
|
fiore@0
|
288
|
fiore@0
|
289 @Override
|
fiore@3
|
290 public void clearProperties(Node node,DiagramEventSource source) {
|
fiore@3
|
291 node.clearProperties(source);
|
fiore@0
|
292 }
|
fiore@0
|
293
|
fiore@0
|
294 @Override
|
fiore@3
|
295 public void addProperty(Node node, String type, String value,DiagramEventSource source) {
|
fiore@3
|
296 node.addProperty(type, value,source);
|
fiore@0
|
297 }
|
fiore@0
|
298
|
fiore@0
|
299 @Override
|
fiore@3
|
300 public void removeProperty(Node node, String type, int index,DiagramEventSource source) {
|
fiore@3
|
301 node.removeProperty(type, index,source);
|
fiore@0
|
302 }
|
fiore@0
|
303
|
fiore@0
|
304 @Override
|
fiore@0
|
305 public void setModifiers(Node node, String type, int index,
|
fiore@3
|
306 Set<Integer> modifiers,DiagramEventSource source) {
|
fiore@3
|
307 node.setModifierIndexes(type, index, modifiers,source);
|
fiore@0
|
308 }
|
fiore@0
|
309
|
fiore@0
|
310 @Override
|
fiore@3
|
311 public void setEndLabel(Edge edge, Node node, String label,DiagramEventSource source) {
|
fiore@3
|
312 edge.setEndLabel(node, label,source);
|
fiore@0
|
313 }
|
fiore@0
|
314
|
fiore@0
|
315 @Override
|
fiore@0
|
316 public void setEndDescription(Edge edge, Node node,
|
fiore@3
|
317 int index,DiagramEventSource source) {
|
fiore@3
|
318 edge.setEndDescription(node, index,source);
|
fiore@0
|
319 }
|
fiore@0
|
320
|
fiore@0
|
321 @Override
|
fiore@3
|
322 public void translate(GraphElement ge, Point2D p, double x, double y,DiagramEventSource source) {
|
fiore@3
|
323 ge.translate(p, x, y,source);
|
fiore@0
|
324 }
|
fiore@0
|
325
|
fiore@0
|
326 @Override
|
fiore@3
|
327 public void startMove(GraphElement ge, Point2D p,DiagramEventSource source) {
|
fiore@3
|
328 ge.startMove(p,source);
|
fiore@0
|
329 }
|
fiore@0
|
330
|
fiore@0
|
331 @Override
|
fiore@3
|
332 public void bend(Edge edge, Point2D p,DiagramEventSource source) {
|
fiore@3
|
333 edge.bend(p,source);
|
fiore@0
|
334 }
|
fiore@0
|
335
|
fiore@0
|
336 @Override
|
fiore@3
|
337 public void stopMove(GraphElement ge,DiagramEventSource source) {
|
fiore@3
|
338 ge.stopMove(source);
|
fiore@0
|
339 }
|
fiore@0
|
340 }
|
fiore@0
|
341 }
|
fiore@0
|
342
|
fiore@0
|
343 } |