comparison java/src/uk/ac/qmul/eecs/ccmi/gui/DiagramTree.java @ 3:9e67171477bc

PHANTOM Omni Heptic device release
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Wed, 25 Apr 2012 17:09:09 +0100
parents 4b2f975e35fa
children d66dd5880081
comparison
equal deleted inserted replaced
2:4b2f975e35fa 3:9e67171477bc
38 import javax.swing.tree.TreeNode; 38 import javax.swing.tree.TreeNode;
39 import javax.swing.tree.TreePath; 39 import javax.swing.tree.TreePath;
40 import javax.swing.tree.TreeSelectionModel; 40 import javax.swing.tree.TreeSelectionModel;
41 41
42 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement; 42 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement;
43 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramModelTreeNode; 43 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramTreeNode;
44 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramNode; 44 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramNode;
45 import uk.ac.qmul.eecs.ccmi.diagrammodel.EdgeReferenceMutableTreeNode; 45 import uk.ac.qmul.eecs.ccmi.diagrammodel.EdgeReferenceMutableTreeNode;
46 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeReferenceMutableTreeNode; 46 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeReferenceMutableTreeNode;
47 import uk.ac.qmul.eecs.ccmi.diagrammodel.TreeModel; 47 import uk.ac.qmul.eecs.ccmi.diagrammodel.TreeModel;
48 import uk.ac.qmul.eecs.ccmi.diagrammodel.TypeMutableTreeNode; 48 import uk.ac.qmul.eecs.ccmi.diagrammodel.TypeMutableTreeNode;
49 import uk.ac.qmul.eecs.ccmi.network.Command;
50 import uk.ac.qmul.eecs.ccmi.network.DiagramEventActionSource;
49 import uk.ac.qmul.eecs.ccmi.sound.PlayerListener; 51 import uk.ac.qmul.eecs.ccmi.sound.PlayerListener;
50 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent; 52 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
51 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; 53 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
52 import uk.ac.qmul.eecs.ccmi.speech.Narrator; 54 import uk.ac.qmul.eecs.ccmi.speech.Narrator;
53 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory; 55 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
54 import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities; 56 import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;
55 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog; 57 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
56 58
59
57 @SuppressWarnings("serial") 60 @SuppressWarnings("serial")
58 public class DiagramTree extends JTree { 61 public class DiagramTree extends JTree {
62 /**
63 * Creates a new diagram tree. The model of this tree is set to the tree model
64 * held by the instance of {@code Diagram} passed as argument. The model is retrieved by a call
65 * to {@code getTreeModel()} on the diagram.
66 * <p>
67 * The tree doesn't allow interaction via the mouse. It can be navigated via the keyboard using
68 * the arrow keys. When a node is selected, cursoring up and down allows the user to go through
69 * all the sibling of the selected node. Cursoring right will expand the selected node (if it has children)
70 * and select its first child. Cursoring left will collapse a node and select its father. All the motions
71 * trigger a text to speech utterance (possibly accompanied by sound) about the new selected node.
72 *
73 * @param diagram a reference to the diagram holding the tree model for this tree.
74 */
59 public DiagramTree(Diagram diagram){ 75 public DiagramTree(Diagram diagram){
60 super(diagram.getTreeModel()); 76 super(diagram.getTreeModel());
61 this.diagram = diagram; 77 this.diagram = diagram;
62 resources = ResourceBundle.getBundle(EditorFrame.class.getName()); 78 resources = ResourceBundle.getBundle(EditorFrame.class.getName());
63 79
64 TreePath rootPath = new TreePath((DiagramModelTreeNode)diagram.getTreeModel().getRoot()); 80 TreePath rootPath = new TreePath((DiagramTreeNode)diagram.getTreeModel().getRoot());
65 setSelectionPath(rootPath); 81 setSelectionPath(rootPath);
66 collapsePath(rootPath); 82 collapsePath(rootPath);
67 selectedNodes = new ArrayList<Node>(); 83 selectedNodes = new ArrayList<Node>();
68 setEditable(false); 84 setEditable(false);
69 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 85 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
70 overwriteTreeKeystrokes(); 86 overwriteTreeKeystrokes();
71 /* don't use the swing focus system as we provide one on our own */ 87 /* don't use the swing focus system as we provide one on our own */
72 setFocusTraversalKeysEnabled(false); 88 setFocusTraversalKeysEnabled(false);
73 getAccessibleContext().setAccessibleName(""); 89 getAccessibleContext().setAccessibleName("tree");
74 } 90 }
75 91
76 @SuppressWarnings("unchecked") 92 @SuppressWarnings("unchecked")
77 @Override 93 @Override
78 public TreeModel<Node,Edge> getModel(){ 94 public TreeModel<Node,Edge> getModel(){
79 return (TreeModel<Node,Edge>)super.getModel(); 95 return (TreeModel<Node,Edge>)super.getModel();
80 } 96 }
81 97
98 /**
99 * @see javax.swing.JTree#setModel(javax.swing.tree.TreeModel)
100 *
101 * @param newModel the new mnodel for this tree
102 */
82 public void setModel(TreeModel<Node,Edge> newModel){ 103 public void setModel(TreeModel<Node,Edge> newModel){
83 DiagramModelTreeNode selectedTreeNode = (DiagramModelTreeNode)getSelectionPath().getLastPathComponent(); 104 DiagramTreeNode selectedTreeNode = (DiagramTreeNode)getSelectionPath().getLastPathComponent();
84 super.setModel(newModel); 105 super.setModel(newModel);
85 collapseRow(0); 106 collapseRow(0);
86 setSelectionPath(new TreePath(selectedTreeNode.getPath())); 107 setSelectionPath(new TreePath(selectedTreeNode.getPath()));
87 } 108 }
88 109
110 /**
111 * Set a new diagram for this tree. As a result of this call the tree model
112 * of this tree will be set to the model return by {@code diagram.getTreeModel()}
113 *
114 * @param diagram the new diagram for this tree
115 */
89 public void setDiagram(Diagram diagram){ 116 public void setDiagram(Diagram diagram){
90 this.diagram = diagram; 117 this.diagram = diagram;
91 setModel(diagram.getTreeModel()); 118 setModel(diagram.getTreeModel());
92 } 119 }
93 120
94 public void selectNode(final Node n){ 121 private void selectNode(final Node n){
95 selectedNodes.add(n); 122 selectedNodes.add(n);
96 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName()); 123 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName());
97 124
98 SoundFactory.getInstance().play(SoundEvent.OK,new PlayerListener(){ 125 SoundFactory.getInstance().play(SoundEvent.OK,new PlayerListener(){
99 @Override 126 @Override
102 } 129 }
103 }); 130 });
104 InteractionLog.log(INTERACTIONLOG_SOURCE,"node selected for edge",n.getName()); 131 InteractionLog.log(INTERACTIONLOG_SOURCE,"node selected for edge",n.getName());
105 } 132 }
106 133
107 public void unselectNode(final Node n){ 134 private void unselectNode(final Node n){
108 selectedNodes.remove(n); 135 selectedNodes.remove(n);
109 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName()); 136 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName());
110 137
111 SoundFactory.getInstance().play(SoundEvent.OK,new PlayerListener(){ 138 SoundFactory.getInstance().play(SoundEvent.OK,new PlayerListener(){
112 @Override 139 @Override
115 } 142 }
116 }); 143 });
117 InteractionLog.log(INTERACTIONLOG_SOURCE,"node unselected for edge",DiagramElement.toLogString(n)); 144 InteractionLog.log(INTERACTIONLOG_SOURCE,"node unselected for edge",DiagramElement.toLogString(n));
118 } 145 }
119 146
147 /**
148 * Returns an array containing the references to all the nodes that have so far been selected
149 * for edge creation. A new array is created each time this method is called.
150 *
151 * @return an array of nodes
152 */
120 public DiagramNode[] getSelectedNodes(){ 153 public DiagramNode[] getSelectedNodes(){
121 DiagramNode[] array = new DiagramNode[selectedNodes.size()]; 154 DiagramNode[] array = new DiagramNode[selectedNodes.size()];
122 return selectedNodes.toArray(array); 155 return selectedNodes.toArray(array);
123 } 156 }
124 157
158 /**
159 * Makes all the nodes selected for edge creation unselected. This method should
160 * be called after an edge has been created, to get the user restart
161 * go over the selection process again.
162 *
163 */
125 public void clearNodeSelections(){ 164 public void clearNodeSelections(){
126 ArrayList<Node> tempList = new ArrayList<Node>(selectedNodes); 165 ArrayList<Node> tempList = new ArrayList<Node>(selectedNodes);
127 selectedNodes.clear(); 166 selectedNodes.clear();
128 for(Node n : tempList){ 167 for(Node n : tempList){
129 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName()); 168 treeModel.valueForPathChanged(new TreePath(n.getPath()),n.getName());
130 diagram.getModelUpdater().yieldLock(n, Lock.MUST_EXIST); 169 diagram.getModelUpdater().yieldLock(n, Lock.MUST_EXIST, new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.INSERT_EDGE,n.getId(),n.getName()));
131 } 170 }
132 } 171 }
133 172
173 /**
174 * Returns a string for a text to speech synthesizer, describing the currently selected
175 * tree node. The one that is at the end of the current selection path.
176 *
177 * @return a description string suitable for text to speech synthesis
178 */
134 public String currentPathSpeech(){ 179 public String currentPathSpeech(){
135 TreePath path = getSelectionPath(); 180 TreePath path = getSelectionPath();
136 DiagramModelTreeNode selectedPathTreeNode = (DiagramModelTreeNode)path.getLastPathComponent(); 181 DiagramTreeNode selectedPathTreeNode = (DiagramTreeNode)path.getLastPathComponent();
137 if(selectedNodes.contains(selectedPathTreeNode)) 182 if(selectedNodes.contains(selectedPathTreeNode))
138 /* add information about the fact that the node is selected */ 183 /* add information about the fact that the node is selected */
139 return MessageFormat.format(resources.getString("speech.node_selected"), selectedPathTreeNode.spokenText()); 184 return MessageFormat.format(resources.getString("speech.node_selected"), selectedPathTreeNode.spokenText());
140 else 185 else
141 return selectedPathTreeNode.spokenText(); 186 return selectedPathTreeNode.spokenText();
142 } 187 }
143 188
144 /** 189 /**
145 * this method changes the selected tree node from an edge/node reference 190 * Changes the selected tree path from the current to one defined by
146 * to the related edge/node itself 191 * the {@code JumpTo enum}
192 *
193 * @see JumpTo
194 *
195 * @param jumpTo a {@code JumpTo enum}
147 */ 196 */
148 public void jump(JumpTo jumpTo){ 197 public void jump(JumpTo jumpTo){
149 final Narrator narrator = NarratorFactory.getInstance(); 198 final Narrator narrator = NarratorFactory.getInstance();
150 TreePath oldPath; 199 TreePath oldPath;
151 switch(jumpTo){ 200 switch(jumpTo){
152 case REFERENCE : 201 case REFERENCE :
153 oldPath = getSelectionPath(); 202 oldPath = getSelectionPath();
154 DiagramModelTreeNode selectedTreeNode = (DiagramModelTreeNode)oldPath.getLastPathComponent(); 203 DiagramTreeNode selectedTreeNode = (DiagramTreeNode)oldPath.getLastPathComponent();
155 if(selectedTreeNode instanceof NodeReferenceMutableTreeNode){ 204 if(selectedTreeNode instanceof NodeReferenceMutableTreeNode){
156 final Node n = (Node)((NodeReferenceMutableTreeNode)selectedTreeNode).getNode(); 205 final Node n = (Node)((NodeReferenceMutableTreeNode)selectedTreeNode).getNode();
157 setSelectionPath(new TreePath(n.getPath())); 206 setSelectionPath(new TreePath(n.getPath()));
158 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 207 SoundFactory.getInstance().play(SoundEvent.JUMP, new PlayerListener(){
159 @Override 208 @Override
160 public void playEnded() { 209 public void playEnded() {
161 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),n.spokenText())); 210 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),n.spokenText()));
162 } 211 }
163 }, SoundEvent.JUMP); 212 });
164 }else if(selectedTreeNode instanceof EdgeReferenceMutableTreeNode){ 213 }else if(selectedTreeNode instanceof EdgeReferenceMutableTreeNode){
165 final Edge e = (Edge)((EdgeReferenceMutableTreeNode)selectedTreeNode).getEdge(); 214 final Edge e = (Edge)((EdgeReferenceMutableTreeNode)selectedTreeNode).getEdge();
166 setSelectionPath(new TreePath(e.getPath())); 215 setSelectionPath(new TreePath(e.getPath()));
167 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 216 SoundFactory.getInstance().play(SoundEvent.JUMP,new PlayerListener(){
168 @Override 217 @Override
169 public void playEnded() { 218 public void playEnded() {
170 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),e.spokenText())); 219 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),e.spokenText()));
171 } 220 }
172 }, SoundEvent.JUMP); 221 });
173 } 222 }
174 /* assume the referee has only root in common with the reference and collapse everything up to the root (excluded) */ 223 /* assume the referee has only root in common with the reference and collapse everything up to the root (excluded) */
175 collapseAll(selectedTreeNode, (DiagramModelTreeNode)selectedTreeNode.getPath()[1]); 224 collapseAll(selectedTreeNode, (DiagramTreeNode)selectedTreeNode.getPath()[1]);
176 break; 225 break;
177 case ROOT : 226 case ROOT :
178 final DiagramModelTreeNode from =(DiagramModelTreeNode)getSelectionPath().getLastPathComponent(); 227 final DiagramTreeNode from =(DiagramTreeNode)getSelectionPath().getLastPathComponent();
179 setSelectionRow(0); 228 setSelectionRow(0);
180 collapseAll(from,from.getRoot()); 229 collapseAll(from,from.getRoot());
181 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 230 SoundFactory.getInstance().play(SoundEvent.JUMP, new PlayerListener(){
182 @Override 231 @Override
183 public void playEnded() { 232 public void playEnded() {
184 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),from.getRoot().spokenText())); 233 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),from.getRoot().spokenText()));
185 } 234 }
186 }, SoundEvent.JUMP); 235 });
187 break; 236 break;
188 case TYPE : // jumps to the ancestor type node of the current node, never used 237 // case TYPE : // jumps to the ancestor type node of the current node, never used
189 oldPath = getSelectionPath(); 238 // oldPath = getSelectionPath();
190 int index = 0; 239 // int index = 0;
191 Object[] pathComponents = oldPath.getPath(); 240 // Object[] pathComponents = oldPath.getPath();
192 for(int i=0;i<pathComponents.length;i++){ 241 // for(int i=0;i<pathComponents.length;i++){
193 if(pathComponents[i] instanceof TypeMutableTreeNode){ 242 // if(pathComponents[i] instanceof TypeMutableTreeNode){
194 index=i; 243 // index=i;
195 break; 244 // break;
196 } 245 // }
197 } 246 // }
198 final DiagramModelTreeNode typeTreeNode = (DiagramModelTreeNode)oldPath.getPathComponent(index); 247 // final DiagramTreeNode typeTreeNode = (DiagramTreeNode)oldPath.getPathComponent(index);
199 setSelectionPath(new TreePath(typeTreeNode.getPath())); 248 // setSelectionPath(new TreePath(typeTreeNode.getPath()));
200 collapseAll((DiagramModelTreeNode)oldPath.getLastPathComponent(),typeTreeNode); 249 // collapseAll((DiagramTreeNode)oldPath.getLastPathComponent(),typeTreeNode);
201 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 250 // SoundFactory.getInstance().play(SoundEvent.JUMP, new PlayerListener(){
202 @Override 251 // @Override
203 public void playEnded() { 252 // public void playEnded() {
204 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),typeTreeNode.spokenText())); 253 // narrator.speak(MessageFormat.format(resources.getString("speech.jump"),typeTreeNode.spokenText()));
205 } 254 // }
206 }, SoundEvent.JUMP); 255 // });
207 break; 256 // break;
208 case SELECTED_TYPE : 257 case SELECTED_TYPE :
209 DiagramModelTreeNode root = (DiagramModelTreeNode)getModel().getRoot(); 258 DiagramTreeNode root = (DiagramTreeNode)getModel().getRoot();
210 Object[] types = new Object[root.getChildCount()]; 259 Object[] types = new Object[root.getChildCount()];
211 for(int i=0; i< root.getChildCount();i++) 260 for(int i=0; i< root.getChildCount();i++)
212 types[i] = ((TypeMutableTreeNode)root.getChildAt(i)).getName();//not to spokenText as it would be too long 261 types[i] = ((TypeMutableTreeNode)root.getChildAt(i)).getName();//not to spokenText as it would be too long
213 oldPath = getSelectionPath(); 262 oldPath = getSelectionPath();
214 /* initial value is the type node whose branch node is currently selected */ 263 /* initial value is the type node whose branch node is currently selected */
240 break; 289 break;
241 } 290 }
242 } 291 }
243 setSelectionPath(new TreePath(typeNode.getPath())); 292 setSelectionPath(new TreePath(typeNode.getPath()));
244 if(oldPath.getPath().length >= 2) 293 if(oldPath.getPath().length >= 2)
245 collapseAll((DiagramModelTreeNode)oldPath.getLastPathComponent(), (DiagramModelTreeNode)initialValue); 294 collapseAll((DiagramTreeNode)oldPath.getLastPathComponent(), (DiagramTreeNode)initialValue);
246 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 295 SoundFactory.getInstance().play(SoundEvent.JUMP, new PlayerListener(){
247 @Override 296 @Override
248 public void playEnded() { 297 public void playEnded() {
249 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),selectedValue)); 298 narrator.speak(MessageFormat.format(resources.getString("speech.jump"),selectedValue));
250 } 299 }
251 }, SoundEvent.JUMP); 300 });
252 break; 301 break;
253 case BOOKMARK : 302 case BOOKMARK :
254 TreeModel<Node,Edge> treeModel = getModel(); 303 TreeModel<Node,Edge> treeModel = getModel();
255 304
256 if(treeModel.getBookmarks().size() == 0){ 305 if(treeModel.getBookmarks().size() == 0){
275 bookmarkArray[0] 324 bookmarkArray[0]
276 ); 325 );
277 326
278 if(bookmark != null){ 327 if(bookmark != null){
279 oldPath = getSelectionPath(); 328 oldPath = getSelectionPath();
280 DiagramModelTreeNode treeNode = treeModel.getBookmarkedTreeNode(bookmark); 329 DiagramTreeNode treeNode = treeModel.getBookmarkedTreeNode(bookmark);
281 collapseAll((DiagramModelTreeNode)oldPath.getLastPathComponent(), (DiagramModelTreeNode)treeModel.getRoot()); 330 collapseAll((DiagramTreeNode)oldPath.getLastPathComponent(), (DiagramTreeNode)treeModel.getRoot());
282 setSelectionPath(new TreePath(treeNode.getPath())); 331 setSelectionPath(new TreePath(treeNode.getPath()));
283 final String currentPathSpeech = currentPathSpeech(); 332 final String currentPathSpeech = currentPathSpeech();
284 SoundFactory.getInstance().setPlayerListener(new PlayerListener(){ 333 SoundFactory.getInstance().play(SoundEvent.JUMP, new PlayerListener(){
285 @Override 334 @Override
286 public void playEnded() { 335 public void playEnded() {
287 narrator.speak(currentPathSpeech); 336 narrator.speak(currentPathSpeech);
288 } 337 }
289 }, SoundEvent.JUMP); 338 });
290 InteractionLog.log(INTERACTIONLOG_SOURCE,"bookmark selected",bookmark); 339 InteractionLog.log(INTERACTIONLOG_SOURCE,"bookmark selected",bookmark);
291 }else{ 340 }else{
292 /* it speaks anyway, as we set up the speech in the EditorFrame class. no need to use the narrator then */ 341 /* it speaks anyway, as we set up the speech in the EditorFrame class. no need to use the narrator then */
293 SoundFactory.getInstance().play(SoundEvent.CANCEL); 342 SoundFactory.getInstance().play(SoundEvent.CANCEL);
294 InteractionLog.log(INTERACTIONLOG_SOURCE,"cancel select bookmark dialog",""); 343 InteractionLog.log(INTERACTIONLOG_SOURCE,"cancel select bookmark dialog","");
295 return; 344 return;
296 } 345 }
297 break; 346 break;
298 347
299 } 348 }
300 InteractionLog.log(INTERACTIONLOG_SOURCE,"jumped to "+jumpTo.toString(),((DiagramModelTreeNode)getSelectionPath().getLastPathComponent()).getName()); 349 InteractionLog.log(INTERACTIONLOG_SOURCE,"jumped to "+jumpTo.toString(),((DiagramTreeNode)getSelectionPath().getLastPathComponent()).getName());
301 SoundFactory.getInstance().play(SoundEvent.JUMP); 350 }
302 } 351
303 352 /**
353 * Changes the selected tree path from the current to the one from the root
354 * to the {@code Diagramelement} passed as argument. Note that a {@code Diagramelement}
355 * is also an instance of {@code DuagramTreeNode} and it's placed in a {@code TreeModel}
356 * when it's inserted into a {@code DiagramModel}
357 *
358 * @param de the diagram element to be selected on the tree
359 */
304 public void jumpTo(final DiagramElement de){ 360 public void jumpTo(final DiagramElement de){
305 TreePath oldPath = getSelectionPath(); 361 TreePath oldPath = getSelectionPath();
306 collapseAll((DiagramModelTreeNode)oldPath.getLastPathComponent(),de); 362 collapseAll((DiagramTreeNode)oldPath.getLastPathComponent(),de);
307 setSelectionPath(new TreePath(de.getPath())); 363 setSelectionPath(new TreePath(de.getPath()));
308 SoundFactory.getInstance().play( SoundEvent.JUMP, new PlayerListener(){ 364 SoundFactory.getInstance().play( SoundEvent.JUMP, new PlayerListener(){
309 @Override 365 @Override
310 public void playEnded() { 366 public void playEnded() {
311 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("speech.jump"),de.spokenText())); 367 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("speech.jump"),de.spokenText()));
312 } 368 }
313 }); 369 });
314 } 370 }
315 371
316 /* collapse all the nodes in the path from "from" to "to" upwards(with the same direction as going from a leaf to the root)*/ 372 /* collapse all the nodes in the path from "from" to "to" upwards(with the same direction as going from a leaf to the root)*/
317 private void collapseAll(DiagramModelTreeNode from, DiagramModelTreeNode to){ 373 private void collapseAll(DiagramTreeNode from, DiagramTreeNode to){
318 DiagramModelTreeNode currentNode = from; 374 DiagramTreeNode currentNode = from;
319 while(currentNode.getParent() != null && currentNode != to){ 375 while(currentNode.getParent() != null && currentNode != to){
320 currentNode = currentNode.getParent(); 376 currentNode = currentNode.getParent();
321 collapsePath(new TreePath(currentNode.getPath())); 377 collapsePath(new TreePath(currentNode.getPath()));
322 } 378 }
323 } 379 }
324 380
381 /**
382 * Mouse events are ignored by this tree. This is just a blank method.
383 *
384 * @param e a mouse event
385 */
325 @Override 386 @Override
326 protected void processMouseEvent(MouseEvent e){ 387 protected void processMouseEvent(MouseEvent e){
327 //do nothing as the tree does not have to be editable with mouse 388 //do nothing as the tree does not have to be editable with mouse
328 } 389 }
329 390
391 /**
392 * Allows only cursor keys, tab key, delete, and actions (CTRL+something)
393 *
394 * @param e a key event
395 *
396 */
330 @Override 397 @Override
331 protected void processKeyEvent(KeyEvent e){ 398 protected void processKeyEvent(KeyEvent e){
332 /* allow only cursor keys, tab key, delete, and actions (CTRL+something) */ 399 /* allow only cursor keys, tab key, delete, and actions (CTRL+something) */
333 if(e.getKeyChar() == KeyEvent.CHAR_UNDEFINED 400 if(e.getKeyChar() == KeyEvent.CHAR_UNDEFINED
334 || e.getKeyCode() == KeyEvent.VK_TAB 401 || e.getKeyCode() == KeyEvent.VK_TAB
335 || e.getKeyCode() == KeyEvent.VK_SPACE 402 || e.getKeyCode() == KeyEvent.VK_SPACE
336 || e.getKeyCode() == KeyEvent.VK_DELETE
337 || e.isControlDown() 403 || e.isControlDown()
338 || e.isAltDown()) 404 || e.isAltDown())
339 super.processKeyEvent(e); 405 super.processKeyEvent(e);
340 } 406 }
341 407
346 /* Overwrite keystrokes up,down,left,right arrows and space, shift, ctrl */ 412 /* Overwrite keystrokes up,down,left,right arrows and space, shift, ctrl */
347 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),"down"); 413 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),"down");
348 getActionMap().put("down", new AbstractAction(){ 414 getActionMap().put("down", new AbstractAction(){
349 @Override 415 @Override
350 public void actionPerformed(ActionEvent evt) { 416 public void actionPerformed(ActionEvent evt) {
351 DiagramModelTreeNode treeNode = (DiagramModelTreeNode)getLastSelectedPathComponent(); 417 DiagramTreeNode treeNode = (DiagramTreeNode)getLastSelectedPathComponent();
352 /* look if we've got a sibling node after (we are not at the bottom) */ 418 /* look if we've got a sibling node after (we are not at the bottom) */
353 DiagramModelTreeNode nextTreeNode = treeNode.getNextSibling(); 419 DiagramTreeNode nextTreeNode = treeNode.getNextSibling();
354 SoundEvent loop = null; 420 SoundEvent loop = null;
355 if(nextTreeNode == null){ 421 if(nextTreeNode == null){
356 DiagramModelTreeNode parent = treeNode.getParent(); 422 DiagramTreeNode parent = treeNode.getParent();
357 if(parent == null) /* root node, just stay there */ 423 if(parent == null) /* root node, just stay there */
358 nextTreeNode = treeNode; 424 nextTreeNode = treeNode;
359 else /* loop = go to first child of own parent */ 425 else /* loop = go to first child of own parent */
360 nextTreeNode = (DiagramModelTreeNode)parent.getFirstChild(); 426 nextTreeNode = (DiagramTreeNode)parent.getFirstChild();
361 loop = SoundEvent.LIST_BOTTOM_REACHED; 427 loop = SoundEvent.LIST_BOTTOM_REACHED;
362 } 428 }
363 setSelectionPath(new TreePath(nextTreeNode.getPath())); 429 setSelectionPath(new TreePath(nextTreeNode.getPath()));
364 final InputStream finalSound = getTreeNodeSound(nextTreeNode); 430 final InputStream finalSound = getTreeNodeSound(nextTreeNode);
365 final String currentPathSpeech = currentPathSpeech(); 431 final String currentPathSpeech = currentPathSpeech();
374 440
375 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"up"); 441 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"up");
376 getActionMap().put("up", new AbstractAction(){ 442 getActionMap().put("up", new AbstractAction(){
377 @Override 443 @Override
378 public void actionPerformed(ActionEvent evt) { 444 public void actionPerformed(ActionEvent evt) {
379 DiagramModelTreeNode treeNode = (DiagramModelTreeNode)getLastSelectedPathComponent(); 445 DiagramTreeNode treeNode = (DiagramTreeNode)getLastSelectedPathComponent();
380 DiagramModelTreeNode previousTreeNode = treeNode.getPreviousSibling(); 446 DiagramTreeNode previousTreeNode = treeNode.getPreviousSibling();
381 SoundEvent loop = null; 447 SoundEvent loop = null;
382 if(previousTreeNode == null){ 448 if(previousTreeNode == null){
383 DiagramModelTreeNode parent = treeNode.getParent(); 449 DiagramTreeNode parent = treeNode.getParent();
384 if(parent == null) /* root node */ 450 if(parent == null) /* root node */
385 previousTreeNode = treeNode; 451 previousTreeNode = treeNode;
386 else 452 else
387 previousTreeNode = (DiagramModelTreeNode)parent.getLastChild(); 453 previousTreeNode = (DiagramTreeNode)parent.getLastChild();
388 loop = SoundEvent.LIST_TOP_REACHED; 454 loop = SoundEvent.LIST_TOP_REACHED;
389 } 455 }
390 setSelectionPath(new TreePath(previousTreeNode.getPath())); 456 setSelectionPath(new TreePath(previousTreeNode.getPath()));
391 final InputStream finalSound = getTreeNodeSound(previousTreeNode); 457 final InputStream finalSound = getTreeNodeSound(previousTreeNode);
392 final String currentPathSpeech = currentPathSpeech(); 458 final String currentPathSpeech = currentPathSpeech();
402 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"right"); 468 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"right");
403 getActionMap().put("right", new AbstractAction(){ 469 getActionMap().put("right", new AbstractAction(){
404 @Override 470 @Override
405 public void actionPerformed(ActionEvent evt) { 471 public void actionPerformed(ActionEvent evt) {
406 TreePath path = getSelectionPath(); 472 TreePath path = getSelectionPath();
407 DiagramModelTreeNode treeNode = (DiagramModelTreeNode)path.getLastPathComponent(); 473 DiagramTreeNode treeNode = (DiagramTreeNode)path.getLastPathComponent();
408 if(treeNode.isLeaf()){ 474 if(treeNode.isLeaf()){
409 notifyBorderReached(treeNode); 475 notifyBorderReached(treeNode);
410 InteractionLog.log(INTERACTIONLOG_SOURCE,"move right","border reached"); 476 InteractionLog.log(INTERACTIONLOG_SOURCE,"move right","border reached");
411 } 477 }
412 else{ 478 else{
413 expandPath(path); 479 expandPath(path);
414 setSelectionPath(new TreePath(((DiagramModelTreeNode)treeNode.getFirstChild()).getPath())); 480 setSelectionPath(new TreePath(((DiagramTreeNode)treeNode.getFirstChild()).getPath()));
415 final String currentPathSpeech = currentPathSpeech(); 481 final String currentPathSpeech = currentPathSpeech();
416 SoundFactory.getInstance().play(SoundEvent.TREE_NODE_EXPAND,new PlayerListener(){ 482 SoundFactory.getInstance().play(SoundEvent.TREE_NODE_EXPAND,new PlayerListener(){
417 @Override 483 @Override
418 public void playEnded() { 484 public void playEnded() {
419 NarratorFactory.getInstance().speak(currentPathSpeech); 485 NarratorFactory.getInstance().speak(currentPathSpeech);
420 } 486 }
421 }); 487 });
422 InteractionLog.log(INTERACTIONLOG_SOURCE,"move right",((DiagramModelTreeNode)treeNode.getFirstChild()).toString()); 488 InteractionLog.log(INTERACTIONLOG_SOURCE,"move right",((DiagramTreeNode)treeNode.getFirstChild()).toString());
423 } 489 }
424 } 490 }
425 }); 491 });
426 492
427 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),"left"); 493 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),"left");
428 getActionMap().put("left", new AbstractAction(){ 494 getActionMap().put("left", new AbstractAction(){
429 @Override 495 @Override
430 public void actionPerformed(ActionEvent evt) { 496 public void actionPerformed(ActionEvent evt) {
431 TreePath path = getSelectionPath(); 497 TreePath path = getSelectionPath();
432 DiagramModelTreeNode treeNode = (DiagramModelTreeNode)path.getLastPathComponent(); 498 DiagramTreeNode treeNode = (DiagramTreeNode)path.getLastPathComponent();
433 DiagramModelTreeNode parent = treeNode.getParent(); 499 DiagramTreeNode parent = treeNode.getParent();
434 if(parent == null){/* root node */ 500 if(parent == null){/* root node */
435 notifyBorderReached(treeNode); 501 notifyBorderReached(treeNode);
436 InteractionLog.log(INTERACTIONLOG_SOURCE,"move left","border reached"); 502 InteractionLog.log(INTERACTIONLOG_SOURCE,"move left","border reached");
437 } 503 }
438 else{ 504 else{
439 TreePath newPath = new TreePath(((DiagramModelTreeNode)parent).getPath()); 505 TreePath newPath = new TreePath(((DiagramTreeNode)parent).getPath());
440 setSelectionPath(newPath); 506 setSelectionPath(newPath);
441 collapsePath(newPath); 507 collapsePath(newPath);
442 final String currentPathSpeech = currentPathSpeech(); 508 final String currentPathSpeech = currentPathSpeech();
443 SoundFactory.getInstance().play(SoundEvent.TREE_NODE_COLLAPSE,new PlayerListener(){ 509 SoundFactory.getInstance().play(SoundEvent.TREE_NODE_COLLAPSE,new PlayerListener(){
444 @Override 510 @Override
445 public void playEnded() { 511 public void playEnded() {
446 NarratorFactory.getInstance().speak(currentPathSpeech); 512 NarratorFactory.getInstance().speak(currentPathSpeech);
447 } 513 }
448 }); 514 });
449 InteractionLog.log(INTERACTIONLOG_SOURCE,"move left",((DiagramModelTreeNode)parent).toString()); 515 InteractionLog.log(INTERACTIONLOG_SOURCE,"move left",((DiagramTreeNode)parent).toString());
450 } 516 }
451 } 517 }
452 }); 518 });
453 519
454 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"space"); 520 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"space");
472 * builder.append(", "); 538 * builder.append(", ");
473 * } 539 * }
474 * Narrator.getInstance().speak(builder.toString(), null); 540 * Narrator.getInstance().speak(builder.toString(), null);
475 */ 541 */
476 TreePath path = getSelectionPath(); 542 TreePath path = getSelectionPath();
477 DiagramModelTreeNode treeNode = (DiagramModelTreeNode)path.getLastPathComponent(); 543 DiagramTreeNode treeNode = (DiagramTreeNode)path.getLastPathComponent();
478 NarratorFactory.getInstance().speak(treeNode.detailedSpokenText()); 544 NarratorFactory.getInstance().speak(treeNode.detailedSpokenText());
479 InteractionLog.log(INTERACTIONLOG_SOURCE,"detailed info requested",""); 545 InteractionLog.log(INTERACTIONLOG_SOURCE,"detailed info requested","");
480 } 546 }
481 }); 547 });
482 548
484 getActionMap().put("shift",new AbstractAction(){ 550 getActionMap().put("shift",new AbstractAction(){
485 @Override 551 @Override
486 public void actionPerformed(ActionEvent evt) { 552 public void actionPerformed(ActionEvent evt) {
487 if(getSelectionPath().getLastPathComponent() instanceof Node){ 553 if(getSelectionPath().getLastPathComponent() instanceof Node){
488 Node node = (Node)getSelectionPath().getLastPathComponent(); 554 Node node = (Node)getSelectionPath().getLastPathComponent();
489
490
491 if(selectedNodes.contains(node)){ 555 if(selectedNodes.contains(node)){
492 unselectNode(node); 556 unselectNode(node);
493 diagram.getModelUpdater().yieldLock(node, Lock.MUST_EXIST); 557 diagram.getModelUpdater().yieldLock(node, Lock.MUST_EXIST,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.UNSELECT_NODE_FOR_EDGE_CREATION,node.getId(),node.getName()));
494 } 558 }else{
495 else{ 559 if(!diagram.getModelUpdater().getLock(node, Lock.MUST_EXIST,new DiagramEventActionSource(DiagramEventSource.TREE,Command.Name.SELECT_NODE_FOR_EDGE_CREATION,node.getId(),node.getName()))){
496 if(!diagram.getModelUpdater().getLock(node, Lock.MUST_EXIST)){
497 InteractionLog.log(INTERACTIONLOG_SOURCE,"Could not get lock on node fro edge creation selection",DiagramElement.toLogString(node)); 560 InteractionLog.log(INTERACTIONLOG_SOURCE,"Could not get lock on node fro edge creation selection",DiagramElement.toLogString(node));
498 SpeechOptionPane.showMessageDialog( 561 SpeechOptionPane.showMessageDialog(
499 SpeechOptionPane.getFrameForComponent(DiagramTree.this), 562 SpeechOptionPane.getFrameForComponent(DiagramTree.this),
500 resources.getString("dialog.lock_failure.must_exist"), 563 resources.getString("dialog.lock_failure.must_exist"),
501 SpeechOptionPane.INFORMATION_MESSAGE); 564 SpeechOptionPane.INFORMATION_MESSAGE);
519 /* make the tree ignore the page up and page down keys */ 582 /* make the tree ignore the page up and page down keys */
520 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,0),"none"); 583 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,0),"none");
521 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,0),"none"); 584 getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,0),"none");
522 } 585 }
523 586
524 private static InputStream getTreeNodeSound(DiagramModelTreeNode node){ 587 private static InputStream getTreeNodeSound(DiagramTreeNode node){
525 InputStream sound = null; 588 InputStream sound = null;
526 TreeNode[] newPath = node.getPath(); 589 TreeNode[] newPath = node.getPath();
527 if(!node.isRoot()){ 590 if(!node.isRoot()){
528 if(node.getChildCount() > 0){ // check whether it's the folder containing Node/Edge references 591 if(node.getChildCount() > 0){ // check whether it's the folder containing Node/Edge references
529 if(node.getChildAt(0) instanceof EdgeReferenceMutableTreeNode){ 592 if(node.getChildAt(0) instanceof EdgeReferenceMutableTreeNode){
548 public void setSelectionPath(TreePath path){ 611 public void setSelectionPath(TreePath path){
549 super.setSelectionPath(path); 612 super.setSelectionPath(path);
550 scrollPathToVisible(path); 613 scrollPathToVisible(path);
551 } 614 }
552 615
553 private void notifyBorderReached(DiagramModelTreeNode n) { 616 private void notifyBorderReached(DiagramTreeNode n) {
554 SoundFactory.getInstance().play(SoundEvent.ERROR); 617 SoundFactory.getInstance().play(SoundEvent.ERROR);
555 } 618 }
556 619
557 @Override 620 @Override
558 public String convertValueToText(Object value, 621 public String convertValueToText(Object value,
580 private Diagram diagram; 643 private Diagram diagram;
581 private ResourceBundle resources; 644 private ResourceBundle resources;
582 private static final char SELECTED_NODE_MARK_BEGIN = '<'; 645 private static final char SELECTED_NODE_MARK_BEGIN = '<';
583 private static final char SELECTED_NODE_MARK_END = '>'; 646 private static final char SELECTED_NODE_MARK_END = '>';
584 private static final String INTERACTIONLOG_SOURCE = "TREE"; 647 private static final String INTERACTIONLOG_SOURCE = "TREE";
585 static enum JumpTo {REFERENCE, ROOT, TYPE, SELECTED_TYPE, BOOKMARK} 648 /**
649 * A list of possible destination for a jump (a change of the selected path without
650 * using the navigation arrow keys)
651 */
652 public static enum JumpTo {
653 /**
654 * if the current selection is a edge/node reference tree node, the jump destination
655 * is the referee tree node (see {@link uk.ac.qmul.eecs.ccmi.diagrammodel.NodeReferenceMutableTreeNode} and
656 * {@link uk.ac.qmul.eecs.ccmi.diagrammodel.EdgeReferenceMutableTreeNode })
657 */
658 REFERENCE,
659 /**
660 * the destination is the root of the diagram
661 */
662 ROOT,
663 /**
664 * the destination will be a node or edge type selected
665 * (via a selection dialog) by the user
666 */
667 SELECTED_TYPE,
668 /**
669 * the destination will be a bookmark selected (via a selection dialog) by the user
670 */
671 BOOKMARK}
586 672
587 /* the methods of the TreeModelHandler are overwritten in order to provide a consistent way 673 /* the methods of the TreeModelHandler are overwritten in order to provide a consistent way
588 * of updating the tree selection upon tree change. Bear in mind that the tree can possibly be changed 674 * of updating the tree selection upon tree change. Bear in mind that the tree can possibly be changed
589 * by another peer on a network, and therefore not only as a response to a user's action. 675 * by another peer on a network, and therefore not only as a response to a user's action.
590 * The algorithm works as follows (being A the tree node selected before any handler method M being called): 676 * The algorithm works as follows (being A the tree node selected before any handler method M being called):
612 Object[] pathArray = getSelectionPath().getPath(); 698 Object[] pathArray = getSelectionPath().getPath();
613 DefaultMutableTreeNode root = (DefaultMutableTreeNode)getModel().getRoot(); 699 DefaultMutableTreeNode root = (DefaultMutableTreeNode)getModel().getRoot();
614 /* go along the path from the selected node to the root looking for a node * 700 /* go along the path from the selected node to the root looking for a node *
615 * attached to the tree or with sibling nodes attached to the tree */ 701 * attached to the tree or with sibling nodes attached to the tree */
616 for(int i=pathArray.length-1;i>=0;i--){ 702 for(int i=pathArray.length-1;i>=0;i--){
617 DiagramModelTreeNode onPathTreeNode = (DiagramModelTreeNode)pathArray[i]; 703 DiagramTreeNode onPathTreeNode = (DiagramTreeNode)pathArray[i];
618 if(onPathTreeNode.isNodeRelated(root)){// if can reach the root from here a.k.a. the node is still part of the tree 704 if(onPathTreeNode.isNodeRelated(root)){// if can reach the root from here a.k.a. the node is still part of the tree
619 super.treeStructureChanged(e); 705 super.treeStructureChanged(e);
620 setSelectionPath(new TreePath(onPathTreeNode.getPath())); 706 setSelectionPath(new TreePath(onPathTreeNode.getPath()));
621 break; 707 break;
622 }else{ 708 }else{
623 /* check sibling nodes*/ 709 /* check sibling nodes*/
624 DefaultMutableTreeNode parent = (DiagramModelTreeNode)pathArray[i-1]; 710 DefaultMutableTreeNode parent = (DiagramTreeNode)pathArray[i-1];
625 if(parent.isNodeRelated(root) && parent.getChildCount() > 0){ 711 if(parent.isNodeRelated(root) && parent.getChildCount() > 0){
626 super.treeStructureChanged(e); 712 super.treeStructureChanged(e);
627 setSelectionPath(new TreePath(((DefaultMutableTreeNode)parent.getLastChild()).getPath())); 713 setSelectionPath(new TreePath(((DefaultMutableTreeNode)parent.getLastChild()).getPath()));
628 break; 714 break;
629 } 715 }
643 729
644 @Override 730 @Override
645 public void treeNodesRemoved(final TreeModelEvent e){ 731 public void treeNodesRemoved(final TreeModelEvent e){
646 /* check first if what we're removing is in the selecton path */ 732 /* check first if what we're removing is in the selecton path */
647 TreePath path = e.getTreePath(); 733 TreePath path = e.getTreePath();
648 DiagramModelTreeNode removedTreeNode = (DiagramModelTreeNode)e.getChildren()[0]; 734 DiagramTreeNode removedTreeNode = (DiagramTreeNode)e.getChildren()[0];
649 boolean isInSelectionPath = false; 735 boolean isInSelectionPath = false;
650 for(Object t : getSelectionPath().getPath()){ 736 for(Object t : getSelectionPath().getPath()){
651 if(removedTreeNode == t){ 737 if(removedTreeNode == t){
652 isInSelectionPath = true; 738 isInSelectionPath = true;
653 break; 739 break;
654 } 740 }
655 } 741 }
656 DiagramModelTreeNode parentTreeNode = (DiagramModelTreeNode)path.getLastPathComponent(); 742 DiagramTreeNode parentTreeNode = (DiagramTreeNode)path.getLastPathComponent();
657 /* update the selection only if the tree node involved is in the selection path * 743 /* update the selection only if the tree node involved is in the selection path *
658 * this always holds true for tree nodes deleted from the tree */ 744 * this always holds true for tree nodes deleted from the tree */
659 if(isInSelectionPath){ 745 if(isInSelectionPath){
660 if(e.getSource() instanceof TreeModel){ 746 if(e.getSource() instanceof TreeModel){
661 /* update the path only if the node has been removed from the tree or * 747 /* update the path only if the node has been removed from the tree or *
668 /* if we deleted from another source, then select the first non null node in the path * 754 /* if we deleted from another source, then select the first non null node in the path *
669 * including the deleted node. E.g. if we're deleting the first child of a parent * 755 * including the deleted node. E.g. if we're deleting the first child of a parent *
670 * and the node has siblings than the new first sibling will be selected */ 756 * and the node has siblings than the new first sibling will be selected */
671 int limitForParentDeletion = (parentTreeNode instanceof Edge) ? 1 : 0; // an edge with one node is to be deleted 757 int limitForParentDeletion = (parentTreeNode instanceof Edge) ? 1 : 0; // an edge with one node is to be deleted
672 if(parentTreeNode.getChildCount() > limitForParentDeletion){ 758 if(parentTreeNode.getChildCount() > limitForParentDeletion){
673 setSelectionPath(new TreePath(((DiagramModelTreeNode)parentTreeNode.getChildAt( 759 setSelectionPath(new TreePath(((DiagramTreeNode)parentTreeNode.getChildAt(
674 /* select the n-th sibling node (see algorithm description above or the highest index sibling node */ 760 /* select the n-th sibling node (see algorithm description above or the highest index sibling node */
675 Math.min(e.getChildIndices()[0],parentTreeNode.getChildCount()-1) 761 Math.min(e.getChildIndices()[0],parentTreeNode.getChildCount()-1)
676 )).getPath())); 762 )).getPath()));
677 }else{ 763 }else{
678 /* the deleted node had no siblings, thus select the node checking from the parent up in the path to the first still existing node */ 764 /* the deleted node had no siblings, thus select the node checking from the parent up in the path to the first still existing node */
679 Object[] pathArray = path.getPath(); 765 Object[] pathArray = path.getPath();
680 for(int i=path.getPathCount()-1;i>=0;i--){ 766 for(int i=path.getPathCount()-1;i>=0;i--){
681 DiagramModelTreeNode itr = (DiagramModelTreeNode)pathArray[i]; 767 DiagramTreeNode itr = (DiagramTreeNode)pathArray[i];
682 if(itr.getPath()[0] == getModel().getRoot()){ 768 if(itr.getPath()[0] == getModel().getRoot()){
683 TreePath newPath = new TreePath(itr.getPath()); 769 TreePath newPath = new TreePath(itr.getPath());
684 setSelectionPath(newPath); 770 setSelectionPath(newPath);
685 collapsePath(newPath); 771 collapsePath(newPath);
686 break; 772 break;
690 } 776 }
691 }else 777 }else
692 super.treeNodesRemoved(e); 778 super.treeNodesRemoved(e);
693 779
694 /* if the node was selected for edge creation, then remove it from the list */ 780 /* if the node was selected for edge creation, then remove it from the list */
695 DiagramModelTreeNode removedNode = (DiagramModelTreeNode)e.getChildren()[0]; 781 DiagramTreeNode removedNode = (DiagramTreeNode)e.getChildren()[0];
696 selectedNodes.remove(removedNode); 782 selectedNodes.remove(removedNode);
697 } 783 }
698 } 784 }
699 } 785 }