fiore@0
|
1 /*
|
fiore@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@3
|
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@3
|
18 */
|
fiore@0
|
19 package uk.ac.qmul.eecs.ccmi.diagrammodel;
|
fiore@0
|
20
|
fiore@0
|
21 import java.util.ArrayList;
|
fiore@0
|
22 import java.util.Collection;
|
fiore@0
|
23 import java.util.Collections;
|
fiore@0
|
24 import java.util.Enumeration;
|
fiore@0
|
25 import java.util.LinkedHashMap;
|
fiore@0
|
26 import java.util.LinkedHashSet;
|
fiore@0
|
27 import java.util.LinkedList;
|
fiore@0
|
28 import java.util.List;
|
fiore@0
|
29 import java.util.Map;
|
fiore@0
|
30 import java.util.Set;
|
fiore@3
|
31 import java.util.concurrent.locks.ReentrantLock;
|
fiore@0
|
32
|
fiore@0
|
33 import javax.swing.event.ChangeEvent;
|
fiore@0
|
34 import javax.swing.event.ChangeListener;
|
fiore@0
|
35 import javax.swing.tree.DefaultTreeModel;
|
fiore@0
|
36 import javax.swing.tree.MutableTreeNode;
|
fiore@0
|
37 import javax.swing.tree.TreeNode;
|
fiore@0
|
38
|
fiore@0
|
39 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties.Modifiers;
|
fiore@0
|
40 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
|
fiore@0
|
41
|
fiore@0
|
42 /**
|
fiore@0
|
43 * This class represent a model as per in the model-view control architecture.
|
fiore@0
|
44 * The model is "double sided" in the sense that it can be accessed through either
|
fiore@0
|
45 * a CollectionModel or a TreeModel returned by the respective getter methods.
|
fiore@0
|
46 * The TreeModel is suitable for JTree classes of the swing library, while
|
fiore@0
|
47 * the CollectionModel can be used by view classes by registering a CollectionListener
|
fiore@0
|
48 * to the CollectionModel itself.
|
fiore@0
|
49 * It is important to notice that changes made on one side will reflect on the other,
|
fiore@0
|
50 * eventually triggering the registered listeners.
|
fiore@0
|
51 * The tree model is structured according to a special layout which is suitable for
|
fiore@0
|
52 * browsing the tree view via audio interface ( text to speech synthesis and sound).
|
fiore@0
|
53 *
|
fiore@0
|
54 * @param <N> a subclass of DiagramNode
|
fiore@0
|
55 * @param <E> a subclass of DiagramEdge
|
fiore@0
|
56 */
|
fiore@0
|
57 public class DiagramModel<N extends DiagramNode, E extends DiagramEdge>{
|
fiore@0
|
58 /**
|
fiore@0
|
59 * Create a model instance starting from some nodes and edges prototypes.
|
fiore@0
|
60 * All subsequently added element must be clones of such prototypes.
|
fiore@5
|
61 * @param nodePrototypes an array of {@code DiagramNode} prototypes, from which
|
fiore@5
|
62 * nodes that will be inserted in this model will be cloned
|
fiore@5
|
63 * @param edgePrototypes an array of {@code DiagramEdge} prototypes, from which
|
fiore@5
|
64 * edges that will be inserted in this model will be cloned
|
fiore@0
|
65 */
|
fiore@0
|
66 @SuppressWarnings("serial")
|
fiore@0
|
67 public DiagramModel(N [] nodePrototypes, E [] edgePrototypes) {
|
fiore@3
|
68 root = new DiagramTreeNode(ROOT_LABEL){
|
fiore@0
|
69 @Override
|
fiore@0
|
70 public boolean isRoot(){
|
fiore@0
|
71 return true;
|
fiore@0
|
72 }
|
fiore@0
|
73 };
|
fiore@0
|
74 modified = false;
|
fiore@3
|
75
|
fiore@0
|
76 nodeCounter = 0;
|
fiore@0
|
77 edgeCounter = 0;
|
fiore@3
|
78
|
fiore@3
|
79 notifier = new ReentrantLockNotifier();
|
fiore@3
|
80
|
fiore@0
|
81 treeModel = new InnerTreeModel(root);
|
fiore@0
|
82 treeModel.setEventSource(treeModel);/* default event source is the tree itself */
|
fiore@0
|
83 diagramCollection = new InnerDiagramCollection();
|
fiore@3
|
84
|
fiore@0
|
85 nodes = new ArrayList<N>(INITIAL_NODES_SIZE);
|
fiore@0
|
86 edges = new ArrayList<E>(INITIAL_EDGES_SIZE);
|
fiore@0
|
87 elements = new ArrayList<DiagramElement>(INITIAL_NODES_SIZE+INITIAL_EDGES_SIZE);
|
fiore@3
|
88
|
fiore@0
|
89 changeListeners = new LinkedList<ChangeListener>();
|
fiore@3
|
90
|
fiore@0
|
91 for(N n : nodePrototypes)
|
fiore@0
|
92 addType(n);
|
fiore@0
|
93 for(E e : edgePrototypes){
|
fiore@0
|
94 addType(e);
|
fiore@0
|
95 }
|
fiore@0
|
96 }
|
fiore@3
|
97
|
fiore@0
|
98 /**
|
fiore@0
|
99 * Returns a CollectionModel for this diagram
|
fiore@0
|
100 *
|
fiore@0
|
101 * @return a CollectionModel for this diagram
|
fiore@0
|
102 */
|
fiore@0
|
103 public CollectionModel<N,E> getDiagramCollection(){
|
fiore@0
|
104 return diagramCollection;
|
fiore@0
|
105 }
|
fiore@3
|
106
|
fiore@0
|
107 /**
|
fiore@0
|
108 * Returns a TreeModel for this diagram
|
fiore@0
|
109 *
|
fiore@0
|
110 * @return a TreeModel for this diagram
|
fiore@0
|
111 */
|
fiore@0
|
112 public TreeModel<N,E> getTreeModel(){
|
fiore@0
|
113 return treeModel;
|
fiore@0
|
114 }
|
fiore@3
|
115
|
fiore@3
|
116 private void handleChangeListeners(Object source){
|
fiore@0
|
117 if(modified) // fire the listener only the first time a change happens
|
fiore@0
|
118 return;
|
fiore@0
|
119 modified = true;
|
fiore@0
|
120 fireChangeListeners(source);
|
fiore@0
|
121 }
|
fiore@3
|
122
|
fiore@0
|
123 private void addChangeListener(ChangeListener l){
|
fiore@0
|
124 changeListeners.add(l);
|
fiore@0
|
125 }
|
fiore@3
|
126
|
fiore@0
|
127 private void removeChangeListener(ChangeListener l){
|
fiore@0
|
128 changeListeners.remove(l);
|
fiore@0
|
129 }
|
fiore@3
|
130
|
fiore@0
|
131 protected void fireChangeListeners(Object source){
|
fiore@0
|
132 ChangeEvent changeEvent = new ChangeEvent(source);
|
fiore@0
|
133 for(ChangeListener l : changeListeners)
|
fiore@0
|
134 l.stateChanged(changeEvent);
|
fiore@0
|
135 }
|
fiore@3
|
136
|
fiore@0
|
137 private void addType(DiagramElement element){
|
fiore@3
|
138 DiagramTreeNode typeNode = _lookForChild(root, element.getType());
|
fiore@0
|
139 if(typeNode == null){
|
fiore@0
|
140 typeNode = new TypeMutableTreeNode(element);
|
fiore@0
|
141 treeModel.insertNodeInto(typeNode, root, root.getChildCount());
|
fiore@0
|
142 }
|
fiore@0
|
143 }
|
fiore@3
|
144
|
fiore@0
|
145 private class InnerDiagramCollection implements CollectionModel<N,E> {
|
fiore@0
|
146
|
fiore@0
|
147 public InnerDiagramCollection(){
|
fiore@0
|
148 listeners = new ArrayList<CollectionListener>();
|
fiore@0
|
149 }
|
fiore@3
|
150
|
fiore@0
|
151 @Override
|
fiore@3
|
152 public boolean insert(N n, Object source){
|
fiore@3
|
153 if(source == null)
|
fiore@3
|
154 source = this;
|
fiore@3
|
155 return _insert(n,source);
|
fiore@0
|
156 }
|
fiore@3
|
157
|
fiore@0
|
158 @Override
|
fiore@3
|
159 public boolean insert(E e, Object source){
|
fiore@3
|
160 if(source == null)
|
fiore@3
|
161 source = this;
|
fiore@3
|
162 return _insert(e,source);
|
fiore@0
|
163 }
|
fiore@3
|
164
|
fiore@0
|
165 @Override
|
fiore@3
|
166 public boolean takeOut(DiagramElement element, Object source){
|
fiore@3
|
167 if(source == null)
|
fiore@3
|
168 source = this;
|
fiore@0
|
169 if(element instanceof DiagramNode)
|
fiore@3
|
170 return _takeOut((DiagramNode)element,source);
|
fiore@0
|
171 if(element instanceof DiagramEdge)
|
fiore@3
|
172 return _takeOut((DiagramEdge)element,source);
|
fiore@0
|
173 return false;
|
fiore@0
|
174 }
|
fiore@0
|
175
|
fiore@0
|
176 @Override
|
fiore@0
|
177 public void addCollectionListener(CollectionListener listener) {
|
fiore@0
|
178 listeners.add(listener);
|
fiore@0
|
179 }
|
fiore@0
|
180
|
fiore@0
|
181 @Override
|
fiore@0
|
182 public void removeCollectionListener(CollectionListener listener) {
|
fiore@0
|
183 listeners.remove(listener);
|
fiore@0
|
184 }
|
fiore@3
|
185
|
fiore@0
|
186 protected void fireElementInserted(Object source, DiagramElement element) {
|
fiore@0
|
187 for(CollectionListener l : listeners){
|
fiore@0
|
188 l.elementInserted(new CollectionEvent(source,element));
|
fiore@0
|
189 }
|
fiore@0
|
190 }
|
fiore@3
|
191
|
fiore@0
|
192 protected void fireElementTakenOut(Object source, DiagramElement element) {
|
fiore@0
|
193 for(CollectionListener l : listeners){
|
fiore@0
|
194 l.elementTakenOut(new CollectionEvent(source,element));
|
fiore@0
|
195 }
|
fiore@0
|
196 }
|
fiore@3
|
197
|
fiore@0
|
198 protected void fireElementChanged(ElementChangedEvent evt){
|
fiore@0
|
199 for(CollectionListener l : listeners){
|
fiore@0
|
200 l.elementChanged(evt);
|
fiore@0
|
201 }
|
fiore@0
|
202 }
|
fiore@0
|
203
|
fiore@0
|
204 @Override
|
fiore@0
|
205 public Collection<N> getNodes() {
|
fiore@0
|
206 return Collections.unmodifiableCollection(nodes);
|
fiore@0
|
207 }
|
fiore@0
|
208
|
fiore@0
|
209 @Override
|
fiore@0
|
210 public Collection<E> getEdges() {
|
fiore@0
|
211 return Collections.unmodifiableCollection(edges);
|
fiore@0
|
212 }
|
fiore@3
|
213
|
fiore@0
|
214 @Override
|
fiore@0
|
215 public Collection<DiagramElement> getElements(){
|
fiore@0
|
216 return Collections.unmodifiableCollection(elements);
|
fiore@0
|
217 }
|
fiore@0
|
218
|
fiore@0
|
219 @Override
|
fiore@3
|
220 public ReentrantLock getMonitor(){
|
fiore@3
|
221 return notifier;
|
fiore@0
|
222 }
|
fiore@3
|
223
|
fiore@0
|
224 @Override
|
fiore@0
|
225 public void addChangeListener(ChangeListener l){
|
fiore@0
|
226 DiagramModel.this.addChangeListener(l);
|
fiore@0
|
227 }
|
fiore@3
|
228
|
fiore@0
|
229 @Override
|
fiore@0
|
230 public void removeChangeListener(ChangeListener l){
|
fiore@0
|
231 DiagramModel.this.removeChangeListener(l);
|
fiore@0
|
232 }
|
fiore@3
|
233
|
fiore@0
|
234 /* sort the collections according to the id of nodes */
|
fiore@0
|
235 public void sort(){
|
fiore@0
|
236 Collections.sort(nodes, DiagramElementComparator.getInstance());
|
fiore@0
|
237 Collections.sort(edges, DiagramElementComparator.getInstance());
|
fiore@0
|
238 }
|
fiore@3
|
239
|
fiore@0
|
240 public boolean isModified(){
|
fiore@0
|
241 return modified;
|
fiore@0
|
242 }
|
fiore@3
|
243
|
fiore@0
|
244 public void setUnmodified(){
|
fiore@3
|
245 modified = false;
|
fiore@3
|
246 }
|
fiore@3
|
247
|
fiore@0
|
248 protected ArrayList<CollectionListener> listeners;
|
fiore@0
|
249
|
fiore@0
|
250 }
|
fiore@3
|
251
|
fiore@3
|
252 @SuppressWarnings("serial")
|
fiore@0
|
253 private class InnerTreeModel extends DefaultTreeModel implements TreeModel<N,E>{
|
fiore@0
|
254
|
fiore@3
|
255 public InnerTreeModel(TreeNode root){
|
fiore@3
|
256 super(root);
|
fiore@3
|
257 bookmarks = new LinkedHashMap<String, DiagramTreeNode>();
|
fiore@3
|
258 diagramTreeNodeListeners = new ArrayList<DiagramTreeNodeListener>();
|
fiore@0
|
259 }
|
fiore@0
|
260
|
fiore@0
|
261 @Override
|
fiore@3
|
262 public boolean insertTreeNode(N treeNode, Object source){
|
fiore@3
|
263 if(source == null)
|
fiore@3
|
264 source = this;
|
fiore@3
|
265 return _insert(treeNode,source);
|
fiore@3
|
266 }
|
fiore@3
|
267
|
fiore@3
|
268 @Override
|
fiore@3
|
269 public boolean insertTreeNode(E treeNode, Object source){
|
fiore@3
|
270 if(source == null)
|
fiore@3
|
271 source = this;
|
fiore@3
|
272 return _insert(treeNode,source);
|
fiore@3
|
273 }
|
fiore@3
|
274
|
fiore@3
|
275 @Override
|
fiore@3
|
276 public boolean takeTreeNodeOut(DiagramElement treeNode, Object source){
|
fiore@3
|
277 if(source == null)
|
fiore@3
|
278 source = this;
|
fiore@0
|
279 boolean result;
|
fiore@0
|
280 if(treeNode instanceof DiagramEdge){
|
fiore@3
|
281 result = _takeOut((DiagramEdge)treeNode,source);
|
fiore@0
|
282 }
|
fiore@0
|
283 else{
|
fiore@3
|
284 result = _takeOut((DiagramNode)treeNode,source);
|
fiore@0
|
285 }
|
fiore@0
|
286 /* remove the bookmarks associated with the just deleted diagram element, if any */
|
fiore@0
|
287 for(String key : treeNode.getBookmarkKeys())
|
fiore@0
|
288 bookmarks.remove(key);
|
fiore@0
|
289 return result;
|
fiore@0
|
290 }
|
fiore@0
|
291
|
fiore@0
|
292 @Override
|
fiore@3
|
293 public DiagramTreeNode putBookmark(String bookmark, DiagramTreeNode treeNode, Object source){
|
fiore@0
|
294 if(bookmark == null)
|
fiore@0
|
295 throw new IllegalArgumentException("bookmark cannot be null");
|
fiore@3
|
296 if(source == null)
|
fiore@3
|
297 source = this;
|
fiore@3
|
298 setEventSource(source);
|
fiore@0
|
299 treeNode.addBookmarkKey(bookmark);
|
fiore@3
|
300 DiagramTreeNode result = bookmarks.put(bookmark, treeNode);
|
fiore@0
|
301 nodeChanged(treeNode);
|
fiore@0
|
302 iLog("bookmark added",bookmark);
|
fiore@3
|
303 DiagramTreeNodeEvent evt = new DiagramTreeNodeEvent(treeNode,bookmark,source);
|
fiore@3
|
304 for(DiagramTreeNodeListener l : diagramTreeNodeListeners){
|
fiore@3
|
305 l.bookmarkAdded(evt);
|
fiore@3
|
306 }
|
fiore@3
|
307 handleChangeListeners(this);
|
fiore@0
|
308 return result;
|
fiore@0
|
309 }
|
fiore@0
|
310
|
fiore@0
|
311 @Override
|
fiore@3
|
312 public DiagramTreeNode getBookmarkedTreeNode(String bookmark) {
|
fiore@0
|
313 return bookmarks.get(bookmark);
|
fiore@0
|
314 }
|
fiore@3
|
315
|
fiore@0
|
316 @Override
|
fiore@3
|
317 public DiagramTreeNode removeBookmark(String bookmark,Object source) {
|
fiore@3
|
318 if(source == null)
|
fiore@3
|
319 source = this;
|
fiore@3
|
320 setEventSource(source);
|
fiore@3
|
321 DiagramTreeNode treeNode = bookmarks.remove(bookmark);
|
fiore@0
|
322 treeNode.removeBookmarkKey(bookmark);
|
fiore@0
|
323 nodeChanged(treeNode);
|
fiore@0
|
324 iLog("bookmark removed",bookmark);
|
fiore@3
|
325 DiagramTreeNodeEvent evt = new DiagramTreeNodeEvent(treeNode,bookmark,source);
|
fiore@3
|
326 for(DiagramTreeNodeListener l : diagramTreeNodeListeners){
|
fiore@3
|
327 l.bookmarkRemoved(evt);
|
fiore@3
|
328 }
|
fiore@3
|
329 handleChangeListeners(this);
|
fiore@0
|
330 return treeNode;
|
fiore@0
|
331 }
|
fiore@3
|
332
|
fiore@0
|
333 @Override
|
fiore@0
|
334 public Set<String> getBookmarks(){
|
fiore@0
|
335 return new LinkedHashSet<String>(bookmarks.keySet());
|
fiore@0
|
336 }
|
fiore@3
|
337
|
fiore@0
|
338 @Override
|
fiore@3
|
339 public void setNotes(DiagramTreeNode treeNode, String notes,Object source){
|
fiore@3
|
340 if(source == null)
|
fiore@3
|
341 source = this;
|
fiore@3
|
342 setEventSource(source);
|
fiore@3
|
343 String oldValue = treeNode.getNotes();
|
fiore@3
|
344 treeNode.setNotes(notes,source);
|
fiore@0
|
345 nodeChanged(treeNode);
|
fiore@0
|
346 iLog("notes set for "+treeNode.getName(),"".equals(notes) ? "empty notes" : notes.replaceAll("\n", "\\\\n"));
|
fiore@3
|
347 DiagramTreeNodeEvent evt = new DiagramTreeNodeEvent(treeNode,oldValue,source);
|
fiore@3
|
348 for(DiagramTreeNodeListener l : diagramTreeNodeListeners){
|
fiore@3
|
349 l.notesChanged(evt);
|
fiore@3
|
350 }
|
fiore@3
|
351 handleChangeListeners(source);
|
fiore@0
|
352 }
|
fiore@3
|
353
|
fiore@0
|
354 private void setEventSource(Object source){
|
fiore@0
|
355 this.src = source;
|
fiore@0
|
356 }
|
fiore@3
|
357
|
fiore@0
|
358 @Override
|
fiore@3
|
359 public ReentrantLock getMonitor(){
|
fiore@3
|
360 return notifier;
|
fiore@0
|
361 }
|
fiore@3
|
362
|
fiore@0
|
363 @Override
|
fiore@3
|
364 public void addDiagramTreeNodeListener(DiagramTreeNodeListener l){
|
fiore@3
|
365 diagramTreeNodeListeners.add(l);
|
fiore@0
|
366 }
|
fiore@3
|
367
|
fiore@0
|
368 @Override
|
fiore@3
|
369 public void removeDiagramTreeNodeListener(DiagramTreeNodeListener l){
|
fiore@3
|
370 diagramTreeNodeListeners.remove(l);
|
fiore@0
|
371 }
|
fiore@3
|
372
|
fiore@0
|
373 /* redefine the fire methods so that they set the source object according */
|
fiore@0
|
374 /* to whether the element was inserted from the graph or from the tree */
|
fiore@0
|
375 @Override
|
fiore@0
|
376 protected void fireTreeNodesChanged(Object source, Object[] path,
|
fiore@0
|
377 int[] childIndices, Object[] children) {
|
fiore@0
|
378 super.fireTreeNodesChanged(src, path, childIndices, children);
|
fiore@0
|
379 }
|
fiore@0
|
380
|
fiore@0
|
381 @Override
|
fiore@0
|
382 protected void fireTreeNodesInserted(Object source, Object[] path,
|
fiore@0
|
383 int[] childIndices, Object[] children) {
|
fiore@0
|
384 super.fireTreeNodesInserted(src, path, childIndices, children);
|
fiore@0
|
385 }
|
fiore@0
|
386
|
fiore@0
|
387 @Override
|
fiore@0
|
388 protected void fireTreeNodesRemoved(Object source, Object[] path,
|
fiore@0
|
389 int[] childIndices, Object[] children) {
|
fiore@0
|
390 super.fireTreeNodesRemoved(src, path, childIndices, children);
|
fiore@0
|
391 }
|
fiore@0
|
392
|
fiore@0
|
393 @Override
|
fiore@0
|
394 protected void fireTreeStructureChanged(Object source, Object[] path,
|
fiore@0
|
395 int[] childIndices, Object[] children) {
|
fiore@0
|
396 super.fireTreeStructureChanged(src, path, childIndices, children);
|
fiore@0
|
397 }
|
fiore@3
|
398
|
fiore@0
|
399 public boolean isModified(){
|
fiore@0
|
400 return modified;
|
fiore@0
|
401 }
|
fiore@3
|
402
|
fiore@0
|
403 public void setUnmodified(){
|
fiore@3
|
404 modified = false;
|
fiore@3
|
405 }
|
fiore@3
|
406
|
fiore@0
|
407 private Object src;
|
fiore@3
|
408 private Map<String, DiagramTreeNode> bookmarks;
|
fiore@3
|
409 private ArrayList<DiagramTreeNodeListener> diagramTreeNodeListeners;
|
fiore@3
|
410 }
|
fiore@3
|
411
|
fiore@3
|
412 @SuppressWarnings("serial")
|
fiore@3
|
413 class ReentrantLockNotifier extends ReentrantLock implements ElementNotifier {
|
fiore@3
|
414 @Override
|
fiore@3
|
415 public void notifyChange(ElementChangedEvent evt) {
|
fiore@3
|
416 _change(evt);
|
fiore@3
|
417 handleChangeListeners(evt.getDiagramElement());
|
fiore@3
|
418 }
|
fiore@3
|
419 }
|
fiore@0
|
420
|
fiore@3
|
421 private boolean _insert(N n, Object source) {
|
fiore@3
|
422 assert(n != null);
|
fiore@3
|
423
|
fiore@3
|
424 /* if id has already been given then sync the counter so that a surely new value is given to the next nodes */
|
fiore@3
|
425 if(n.getId() == DiagramElement.NO_ID)
|
fiore@3
|
426 n.setId(++nodeCounter);
|
fiore@3
|
427 else if(n.getId() > nodeCounter)
|
fiore@3
|
428 nodeCounter = n.getId();
|
fiore@3
|
429
|
fiore@3
|
430 treeModel.setEventSource(source);
|
fiore@0
|
431 nodes.add(n);
|
fiore@0
|
432 elements.add(n);
|
fiore@0
|
433 /* add the node to outer node's (if any) inner nodes */
|
fiore@0
|
434 if(n.getExternalNode() != null)
|
fiore@0
|
435 n.getExternalNode().addInternalNode(n);
|
fiore@3
|
436
|
fiore@0
|
437 /* decide where to insert the node based on whether this is an inner node or not */
|
fiore@0
|
438 MutableTreeNode parent;
|
fiore@0
|
439 if(n.getExternalNode() == null){
|
fiore@3
|
440 DiagramTreeNode typeNode = _lookForChild(root, n.getType());
|
fiore@0
|
441 if(typeNode == null)
|
fiore@0
|
442 throw new IllegalArgumentException("Node type "+n.getType()+" not present in the model");
|
fiore@0
|
443 parent = typeNode;
|
fiore@0
|
444 }else{
|
fiore@0
|
445 parent = n.getExternalNode();
|
fiore@0
|
446 }
|
fiore@3
|
447
|
fiore@0
|
448 /* add to the node one child per property type */
|
fiore@0
|
449 for(String propertyType : n.getProperties().getTypes())
|
fiore@0
|
450 n.insert(new PropertyTypeMutableTreeNode(propertyType,n), n.getChildCount());
|
fiore@3
|
451
|
fiore@0
|
452 /* inject the notifier for managing changes internal to the edge */
|
fiore@0
|
453 n.setNotifier(notifier);
|
fiore@0
|
454
|
fiore@0
|
455 /* insert node into tree which fires tree listeners */
|
fiore@0
|
456 treeModel.insertNodeInto(n, parent, parent.getChildCount());
|
fiore@0
|
457 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@0
|
458 treeModel.nodeChanged(parent);
|
fiore@0
|
459 diagramCollection.fireElementInserted(source,n);
|
fiore@3
|
460 handleChangeListeners(n);
|
fiore@3
|
461
|
fiore@0
|
462 iLog("node inserted",DiagramElement.toLogString(n));
|
fiore@0
|
463 return true;
|
fiore@3
|
464 }
|
fiore@3
|
465
|
fiore@3
|
466 private boolean _takeOut(DiagramNode n, Object source) {
|
fiore@3
|
467 treeModel.setEventSource(source);
|
fiore@3
|
468 /* recursively remove internal nodes of this node */
|
fiore@0
|
469 _removeInternalNodes(n,source);
|
fiore@0
|
470 /* clear external node and clear edges attached to this node and updates other ends of such edges */
|
fiore@0
|
471 _clearNodeReferences(n,source);
|
fiore@0
|
472 /* remove the node from the tree (fires listeners) */
|
fiore@0
|
473 treeModel.removeNodeFromParent(n);
|
fiore@0
|
474 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@0
|
475 treeModel.nodeChanged(n.getParent());
|
fiore@0
|
476 /* remove the nodes from the collection */
|
fiore@0
|
477 nodes.remove(n);
|
fiore@0
|
478 elements.remove(n);
|
fiore@0
|
479 /* notify all the listeners a new node has been removed */
|
fiore@0
|
480 diagramCollection.fireElementTakenOut(source,n);
|
fiore@3
|
481 handleChangeListeners(n);
|
fiore@3
|
482
|
fiore@0
|
483 if(nodes.isEmpty()){
|
fiore@0
|
484 nodeCounter = 0;
|
fiore@0
|
485 }else{
|
fiore@0
|
486 long lastNodeId = nodes.get(nodes.size()-1).getId();
|
fiore@0
|
487 if(n.getId() > lastNodeId)
|
fiore@0
|
488 nodeCounter = lastNodeId;
|
fiore@0
|
489 }
|
fiore@0
|
490 iLog("node removed",DiagramElement.toLogString(n));
|
fiore@0
|
491 return true;
|
fiore@3
|
492 }
|
fiore@3
|
493
|
fiore@3
|
494 private boolean _insert(E e, Object source) {
|
fiore@3
|
495 assert(e != null);
|
fiore@3
|
496 /* executes formal controls over the edge's node, which must be specified from the outer class*/
|
fiore@3
|
497 if(e.getNodesNum() < 2)
|
fiore@3
|
498 throw new MalformedEdgeException("too few (" +e.getNodesNum()+ ") nodes");
|
fiore@3
|
499
|
fiore@3
|
500 /* if id has already been given then sync the counter so that a surely new value is given to the next edges */
|
fiore@3
|
501 if(e.getId() > edgeCounter)
|
fiore@3
|
502 edgeCounter = e.getId();
|
fiore@3
|
503 else
|
fiore@3
|
504 e.setId(++edgeCounter);
|
fiore@3
|
505
|
fiore@3
|
506 treeModel.setEventSource(source);
|
fiore@3
|
507 edges.add(e);
|
fiore@3
|
508 elements.add(e);
|
fiore@3
|
509
|
fiore@3
|
510 /* updates the nodes' edge reference and the edge tree references */
|
fiore@0
|
511 for(int i = e.getNodesNum()-1; i >= 0; i--){
|
fiore@0
|
512 DiagramNode n = e.getNodeAt(i);
|
fiore@0
|
513 assert(n != null);
|
fiore@0
|
514 /* insert first the type of the edge, if not already present */
|
fiore@3
|
515 DiagramTreeNode edgeType = _lookForChild(n, e.getType());
|
fiore@0
|
516 if(edgeType == null){
|
fiore@0
|
517 edgeType = new EdgeReferenceHolderMutableTreeNode(e.getType());
|
fiore@0
|
518 treeModel.insertNodeInto(edgeType, n, 0);
|
fiore@0
|
519 }
|
fiore@3
|
520
|
fiore@3
|
521 /* insert the edge reference under its type tree node, in the node*/
|
fiore@0
|
522 treeModel.insertNodeInto(new EdgeReferenceMutableTreeNode(e,n), edgeType, 0);
|
fiore@0
|
523 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@3
|
524 treeModel.nodeChanged(edgeType);
|
fiore@0
|
525
|
fiore@0
|
526 n.addEdge(e);
|
fiore@0
|
527 /* insert the node reference into the edge tree node */
|
fiore@0
|
528 e.insert(new NodeReferenceMutableTreeNode(n,e), 0);
|
fiore@0
|
529 }
|
fiore@3
|
530
|
fiore@3
|
531 DiagramTreeNode parent = _lookForChild(root, e.getType());
|
fiore@0
|
532 if(parent == null)
|
fiore@0
|
533 throw new IllegalArgumentException("Edge type "+e.getType()+" not present in the model");
|
fiore@3
|
534
|
fiore@0
|
535 /* inject the controller and notifier to manage changes internal to the edge */
|
fiore@0
|
536 e.setNotifier(notifier);
|
fiore@3
|
537
|
fiore@0
|
538 /* c'mon baby light my fire */
|
fiore@0
|
539 treeModel.insertNodeInto(e, parent, parent.getChildCount());
|
fiore@0
|
540 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@0
|
541 treeModel.nodeChanged(parent);
|
fiore@0
|
542 diagramCollection.fireElementInserted(source,e);
|
fiore@3
|
543 handleChangeListeners(e);
|
fiore@3
|
544
|
fiore@0
|
545 StringBuilder builder = new StringBuilder(DiagramElement.toLogString(e));
|
fiore@0
|
546 builder.append(" connecting:");
|
fiore@0
|
547 for(int i=0; i<e.getNodesNum();i++)
|
fiore@0
|
548 builder.append(DiagramElement.toLogString(e.getNodeAt(i))).append(' ');
|
fiore@3
|
549
|
fiore@0
|
550 iLog("edge inserted",builder.toString());
|
fiore@0
|
551 return true;
|
fiore@3
|
552 }
|
fiore@3
|
553
|
fiore@3
|
554 private boolean _takeOut(DiagramEdge e, Object source) {
|
fiore@3
|
555 treeModel.setEventSource(source);
|
fiore@0
|
556 /* update the nodes attached to this edge */
|
fiore@3
|
557 _clearEdgeReferences(e);
|
fiore@3
|
558 /* remove the edge from the collection */
|
fiore@3
|
559 edges.remove(e);
|
fiore@3
|
560 elements.remove(e);
|
fiore@3
|
561 /* remove the edge from the tree (fires tree listeners) */
|
fiore@3
|
562 treeModel.removeNodeFromParent(e);
|
fiore@3
|
563 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@0
|
564 treeModel.nodeChanged(e.getParent());
|
fiore@3
|
565 /* notify listeners for collection */
|
fiore@3
|
566 diagramCollection.fireElementTakenOut(source,e);
|
fiore@3
|
567 handleChangeListeners(e);
|
fiore@3
|
568
|
fiore@3
|
569 if(edges.isEmpty()){
|
fiore@3
|
570 edgeCounter = 0;
|
fiore@3
|
571 }else{
|
fiore@3
|
572 long lastEdgeId = edges.get(edges.size()-1).getId();
|
fiore@0
|
573 if(e.getId() > lastEdgeId)
|
fiore@0
|
574 edgeCounter = lastEdgeId;
|
fiore@3
|
575 }
|
fiore@3
|
576 iLog("edge removed",DiagramElement.toLogString(e));
|
fiore@3
|
577 return true;
|
fiore@3
|
578 }
|
fiore@0
|
579
|
fiore@3
|
580 private void _removeInternalNodes(DiagramNode n, Object source){
|
fiore@3
|
581 for(int i=0; i<n.getInternalNodesNum(); i++){
|
fiore@3
|
582 DiagramNode innerNode = n.getInternalNodeAt(i);
|
fiore@3
|
583 _clearNodeReferences(innerNode, source);
|
fiore@3
|
584 _removeInternalNodes(innerNode, source);
|
fiore@3
|
585 n.removeInternalNode(innerNode);
|
fiore@3
|
586 nodes.remove(n);
|
fiore@3
|
587 }
|
fiore@3
|
588 }
|
fiore@3
|
589
|
fiore@3
|
590 /* removes both inner and tree node references to an edge from nodes it's attached to */
|
fiore@3
|
591 private void _clearEdgeReferences(DiagramEdge e){
|
fiore@3
|
592 for(int i=0; i<e.getNodesNum();i++){
|
fiore@3
|
593 DiagramNode n = e.getNodeAt(i);
|
fiore@3
|
594 EdgeReferenceMutableTreeNode reference;
|
fiore@3
|
595 /* find the category tree node under which our reference is */
|
fiore@3
|
596
|
fiore@3
|
597 reference = _lookForEdgeReference(n, e);
|
fiore@3
|
598 assert(reference != null);
|
fiore@3
|
599
|
fiore@3
|
600 treeModel.removeNodeFromParent(reference);
|
fiore@3
|
601 DiagramTreeNode type = _lookForChild(n, e.getType());
|
fiore@3
|
602 if(type.isLeaf())
|
fiore@3
|
603 treeModel.removeNodeFromParent(type);
|
fiore@3
|
604 n.removeEdge(e);
|
fiore@3
|
605 }
|
fiore@3
|
606 }
|
fiore@3
|
607
|
fiore@3
|
608 /* removes references from node */
|
fiore@3
|
609 private void _clearNodeReferences(DiagramNode n, Object source){
|
fiore@3
|
610 /* remove the node itself from its external node, if any */
|
fiore@0
|
611 if(n.getExternalNode() != null)
|
fiore@0
|
612 n.getExternalNode().removeInternalNode(n);
|
fiore@0
|
613 /* remove edges attached to this node from the collection */
|
fiore@0
|
614 ArrayList<DiagramEdge> edgesToRemove = new ArrayList<DiagramEdge>(edges.size());
|
fiore@0
|
615 for(int i=0; i<n.getEdgesNum(); i++){
|
fiore@0
|
616 DiagramEdge e = n.getEdgeAt(i);
|
fiore@4
|
617 if(e.getNodesNum() == 2){ // deleting a node on a two ends edge means deleting the edge itself
|
fiore@0
|
618 edgesToRemove.add(e);
|
fiore@0
|
619 }else{
|
fiore@4
|
620 e.removeNode(n,source);
|
fiore@3
|
621 DiagramTreeNode nodeTreeReference = _lookForNodeReference(e, n);
|
fiore@0
|
622 treeModel.removeNodeFromParent(nodeTreeReference);
|
fiore@0
|
623 }
|
fiore@3
|
624
|
fiore@0
|
625 }
|
fiore@0
|
626 /* remove the edges that must no longer exist as were two ended edges attached to this node */
|
fiore@0
|
627 for(DiagramEdge e : edgesToRemove)
|
fiore@0
|
628 _takeOut(e, source);
|
fiore@3
|
629 }
|
fiore@3
|
630
|
fiore@3
|
631 /* the tree structure is changed as a consequence of this method, therefore it's synchronized *
|
fiore@3
|
632 * so that external classes accessing the tree can get exclusive access through getMonitor() */
|
fiore@3
|
633 private void _change(ElementChangedEvent evt){
|
fiore@3
|
634 synchronized(this){
|
fiore@3
|
635 String changeType = evt.getChangeType();
|
fiore@3
|
636 /* don't use the event source as it might collide with other threads as
|
fiore@3
|
637 * changes on the collections and inner changes on the node are synch'ed thought different monitors */
|
fiore@3
|
638 /* treeModel.setEventSource(evt.getSource());*/
|
fiore@3
|
639 if("name".equals(changeType)){
|
fiore@3
|
640 if(evt.getDiagramElement() instanceof DiagramNode){
|
fiore@3
|
641 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
642 for(int i=0; i<n.getEdgesNum(); i++){
|
fiore@3
|
643 DiagramEdge e = n.getEdgeAt(i);
|
fiore@3
|
644 treeModel.nodeChanged(_lookForNodeReference(e,n));
|
fiore@3
|
645 treeModel.nodeChanged(_lookForEdgeReference(n,e));
|
fiore@3
|
646 for(int j=0; j<e.getNodesNum(); j++){
|
fiore@3
|
647 DiagramNode n2 = e.getNodeAt(j);
|
fiore@3
|
648 if(n2 != n)
|
fiore@3
|
649 treeModel.nodeChanged(_lookForEdgeReference(n2,e));
|
fiore@3
|
650 }
|
fiore@3
|
651 }
|
fiore@3
|
652 iLog("node name changed",DiagramElement.toLogString(n));
|
fiore@3
|
653 }else{
|
fiore@3
|
654 DiagramEdge e = (DiagramEdge)evt.getDiagramElement();
|
fiore@3
|
655 for(int i=0; i<e.getNodesNum();i++){
|
fiore@3
|
656 DiagramNode n = e.getNodeAt(i);
|
fiore@3
|
657 treeModel.nodeChanged(_lookForEdgeReference(n,e));
|
fiore@3
|
658 }
|
fiore@3
|
659 iLog("edge name changed",DiagramElement.toLogString(e));
|
fiore@0
|
660 }
|
fiore@3
|
661 treeModel.nodeChanged(evt.getDiagramElement());
|
fiore@3
|
662 }else if("properties".equals(changeType)){
|
fiore@3
|
663 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
664 for(String type : n.getProperties().getTypes()){
|
fiore@3
|
665 PropertyTypeMutableTreeNode typeNode = null;
|
fiore@3
|
666 for(int i=0; i<n.getChildCount();i++){
|
fiore@3
|
667 /* find the child treeNode corresponding to the current type */
|
fiore@3
|
668 if(n.getChildAt(i) instanceof PropertyTypeMutableTreeNode)
|
fiore@3
|
669 if(type.equals(((PropertyTypeMutableTreeNode)n.getChildAt(i)).getType())){
|
fiore@3
|
670 typeNode = (PropertyTypeMutableTreeNode)n.getChildAt(i);
|
fiore@3
|
671 break;
|
fiore@3
|
672 }
|
fiore@3
|
673 }
|
fiore@3
|
674
|
fiore@3
|
675 if(typeNode == null)
|
fiore@3
|
676 throw new IllegalArgumentException("Inserted Node property type "+ type + " not present in the tree" );
|
fiore@3
|
677
|
fiore@3
|
678 /* set the name and modifier string of all the children PropertyNodes */
|
fiore@3
|
679 typeNode.setValues(n.getProperties().getValues(type), n.getProperties().getModifiers(type));
|
fiore@3
|
680 }
|
fiore@3
|
681 treeModel.nodeStructureChanged(evt.getDiagramElement());
|
fiore@3
|
682 iLog("node properties changed",n.getProperties().toString());
|
fiore@3
|
683 }else if("properties.clear".equals(changeType)){
|
fiore@3
|
684 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
685 List<String> empty = Collections.emptyList();
|
fiore@3
|
686 for(int i=0; i<n.getChildCount();i++){
|
fiore@3
|
687 /* find the child treeNode corresponding to the current type */
|
fiore@3
|
688 if(n.getChildAt(i) instanceof PropertyTypeMutableTreeNode){
|
fiore@3
|
689 ((PropertyTypeMutableTreeNode)n.getChildAt(i)).setValues(empty, null);
|
fiore@3
|
690 }
|
fiore@3
|
691 }
|
fiore@3
|
692 treeModel.nodeStructureChanged(evt.getDiagramElement());
|
fiore@3
|
693 }else if("property.add".equals(changeType)){
|
fiore@3
|
694 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
695 ElementChangedEvent.PropertyChangeArgs args = (ElementChangedEvent.PropertyChangeArgs)evt.getArguments();
|
fiore@3
|
696 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)_lookForChild(n,args.getPropertyType());
|
fiore@3
|
697 PropertyMutableTreeNode propertyNode = new PropertyMutableTreeNode(n.getProperties().getValues(args.getPropertyType()).get(args.getPropertyIndex()));
|
fiore@3
|
698 typeNode.add(propertyNode);
|
fiore@3
|
699 treeModel.insertNodeInto(propertyNode, typeNode, args.getPropertyIndex());
|
fiore@3
|
700 /* this is necessary to increment the child counter displayed between brackets */
|
fiore@3
|
701 treeModel.nodeChanged(typeNode);
|
fiore@3
|
702 iLog("property inserted",propertyNode.getName());
|
fiore@3
|
703 }else if("property.set".equals(changeType)){
|
fiore@3
|
704 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
705 ElementChangedEvent.PropertyChangeArgs args = (ElementChangedEvent.PropertyChangeArgs)evt.getArguments();
|
fiore@3
|
706 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)_lookForChild(n,args.getPropertyType());
|
fiore@3
|
707 ((DiagramTreeNode)typeNode.getChildAt(args.getPropertyIndex()))
|
fiore@3
|
708 .setUserObject(n.getProperties().getValues(args.getPropertyType()).get(args.getPropertyIndex()));
|
fiore@3
|
709 treeModel.nodeChanged((typeNode.getChildAt(args.getPropertyIndex())));
|
fiore@3
|
710 iLog("property changed",n.getProperties().getValues(args.getPropertyType()).get(args.getPropertyIndex()));
|
fiore@3
|
711 }else if("property.remove".equals(changeType)){
|
fiore@3
|
712 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
713 ElementChangedEvent.PropertyChangeArgs args = (ElementChangedEvent.PropertyChangeArgs)evt.getArguments();
|
fiore@3
|
714 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)_lookForChild(n,args.getPropertyType());
|
fiore@3
|
715 iLog("property removed",((DiagramTreeNode)typeNode.getChildAt(args.getPropertyIndex())).getName()); //must do it before actual removing
|
fiore@3
|
716 treeModel.removeNodeFromParent((DiagramTreeNode)typeNode.getChildAt(args.getPropertyIndex()));
|
fiore@3
|
717 /* remove the bookmark keys associated with this property tree node, if any */
|
fiore@3
|
718 for(String key : treeModel.getBookmarks()){
|
fiore@3
|
719 treeModel.bookmarks.remove(key);
|
fiore@3
|
720 }
|
fiore@3
|
721 }else if("property.modifiers".equals(changeType)){
|
fiore@3
|
722 DiagramNode n = (DiagramNode)evt.getDiagramElement();
|
fiore@3
|
723 ElementChangedEvent.PropertyChangeArgs args = (ElementChangedEvent.PropertyChangeArgs)evt.getArguments();
|
fiore@3
|
724 PropertyTypeMutableTreeNode typeNode = (PropertyTypeMutableTreeNode)_lookForChild(n,args.getPropertyType());
|
fiore@3
|
725 PropertyMutableTreeNode propertyNode = ((PropertyMutableTreeNode)typeNode.getChildAt(args.getPropertyIndex()));
|
fiore@3
|
726 StringBuilder builder = new StringBuilder();
|
fiore@3
|
727 Modifiers modifiers = n.getProperties().getModifiers(args.getPropertyType());
|
fiore@3
|
728 for(int index : modifiers.getIndexes(args.getPropertyIndex()))
|
fiore@3
|
729 builder.append(modifiers.getTypes().get(index)).append(' ');
|
fiore@3
|
730 propertyNode.setModifierString(builder.toString());
|
fiore@3
|
731 treeModel.nodeChanged(propertyNode);
|
fiore@3
|
732 }else if("arrowHead".equals(changeType)||"endLabel".equals(changeType)){
|
fiore@3
|
733 /* source is considered to be the node whose end of the edge was changed */
|
fiore@3
|
734 DiagramNode source = (DiagramNode)evt.getArguments();
|
fiore@3
|
735 DiagramEdge e = (DiagramEdge)evt.getDiagramElement();
|
fiore@3
|
736 treeModel.nodeChanged(e);
|
fiore@3
|
737 for(int i=0; i<e.getChildCount();i++){
|
fiore@3
|
738 NodeReferenceMutableTreeNode ref = (NodeReferenceMutableTreeNode)e.getChildAt(i);
|
fiore@3
|
739 if(ref.getNode() == source){
|
fiore@3
|
740 treeModel.nodeChanged(ref);
|
fiore@3
|
741 iLog(("arrowHead".equals(changeType) ? "arrow head changed" :"end label changed"),
|
fiore@3
|
742 "edge:"+DiagramElement.toLogString(e)+" node:"+DiagramElement.toLogString(ref.getNode())+
|
fiore@3
|
743 " value:"+ ("arrowHead".equals(changeType) ? e.getEndDescription(ref.getNode()): e.getEndLabel(ref.getNode())));
|
fiore@3
|
744 break;
|
fiore@3
|
745 }
|
fiore@3
|
746 }
|
fiore@3
|
747 }else if("notes".equals(changeType)){
|
fiore@3
|
748 /* do nothing as the tree update is taken care in the tree itself
|
fiore@3
|
749 * and cannot do it here because it must work for all the diagram tree nodes */
|
fiore@3
|
750
|
fiore@0
|
751 }
|
fiore@3
|
752 }
|
fiore@3
|
753 /* do nothing for other ElementChangedEvents as they only concern the diagram listeners */
|
fiore@3
|
754 /* just forward the event to other listeners which might have been registered */
|
fiore@3
|
755 diagramCollection.fireElementChanged(evt);
|
fiore@3
|
756 }
|
fiore@3
|
757
|
fiore@3
|
758 private static DiagramTreeNode _lookForChild(DiagramTreeNode parentNode, String name){
|
fiore@3
|
759 DiagramTreeNode child = null, temp;
|
fiore@3
|
760 for(@SuppressWarnings("unchecked")
|
fiore@3
|
761 Enumeration<DiagramTreeNode> children = parentNode.children(); children.hasMoreElements();){
|
fiore@0
|
762 temp = children.nextElement();
|
fiore@0
|
763 if(temp.getName().equals(name)){
|
fiore@3
|
764 child = temp;
|
fiore@3
|
765 break;
|
fiore@0
|
766 }
|
fiore@0
|
767 }
|
fiore@3
|
768 return child;
|
fiore@3
|
769 }
|
fiore@3
|
770
|
fiore@3
|
771 private static NodeReferenceMutableTreeNode _lookForNodeReference(DiagramEdge parent, DiagramNode n){
|
fiore@3
|
772 NodeReferenceMutableTreeNode child = null, temp;
|
fiore@3
|
773 for(@SuppressWarnings("unchecked")
|
fiore@3
|
774 Enumeration<DiagramTreeNode> children = parent.children(); children.hasMoreElements();){
|
fiore@3
|
775 temp = (NodeReferenceMutableTreeNode)children.nextElement();
|
fiore@3
|
776 if( ((NodeReferenceMutableTreeNode)temp).getNode().equals(n)){
|
fiore@3
|
777 child = temp;
|
fiore@3
|
778 break;
|
fiore@3
|
779 }
|
fiore@3
|
780 }
|
fiore@3
|
781 return child;
|
fiore@3
|
782 }
|
fiore@3
|
783
|
fiore@3
|
784 private static EdgeReferenceMutableTreeNode _lookForEdgeReference( DiagramNode parentNode, DiagramEdge e){
|
fiore@3
|
785 DiagramTreeNode edgeType = _lookForChild(parentNode, e.getType());
|
fiore@3
|
786 assert(edgeType != null);
|
fiore@3
|
787 EdgeReferenceMutableTreeNode child = null, temp;
|
fiore@3
|
788 for(@SuppressWarnings("unchecked")
|
fiore@3
|
789 Enumeration<DiagramTreeNode> children = edgeType.children(); children.hasMoreElements();){
|
fiore@3
|
790 temp = (EdgeReferenceMutableTreeNode)children.nextElement();
|
fiore@3
|
791 if( ((EdgeReferenceMutableTreeNode)temp).getEdge().equals(e)){
|
fiore@3
|
792 child = temp;
|
fiore@3
|
793 break;
|
fiore@3
|
794 }
|
fiore@3
|
795 }
|
fiore@3
|
796 return child;
|
fiore@3
|
797 }
|
fiore@3
|
798
|
fiore@3
|
799 private void iLog(String action,String args){
|
fiore@3
|
800 InteractionLog.log("MODEL",action,args);
|
fiore@3
|
801 }
|
fiore@3
|
802
|
fiore@3
|
803 private DiagramTreeNode root;
|
fiore@3
|
804 private InnerDiagramCollection diagramCollection;
|
fiore@0
|
805 private ArrayList<N> nodes;
|
fiore@0
|
806 private ArrayList<E> edges;
|
fiore@0
|
807 private ArrayList<DiagramElement> elements;
|
fiore@0
|
808 private InnerTreeModel treeModel;
|
fiore@3
|
809
|
fiore@0
|
810 private long edgeCounter;
|
fiore@0
|
811 private long nodeCounter;
|
fiore@3
|
812
|
fiore@3
|
813 private ReentrantLockNotifier notifier;
|
fiore@0
|
814 private List<ChangeListener> changeListeners;
|
fiore@3
|
815
|
fiore@0
|
816 private boolean modified;
|
fiore@3
|
817
|
fiore@0
|
818 private final static String ROOT_LABEL = "Diagram";
|
fiore@0
|
819 private final static int INITIAL_EDGES_SIZE = 20;
|
fiore@0
|
820 private final static int INITIAL_NODES_SIZE = 30;}
|