3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2005-2009 Albert Cardona and Rodney Douglas.
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation (http://www.gnu.org/licenses/gpl.txt )
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 You may contact Albert Cardona at acardona at ini.phys.ethz.ch
20 Institute of Neuroinformatics, University of Zurich / ETH, Switzerland.
23 package ini
.trakem2
.tree
;
25 import ij
.gui
.GenericDialog
;
27 import ini
.trakem2
.ControlWindow
;
28 import ini
.trakem2
.Project
;
29 import ini
.trakem2
.display
.Display
;
30 import ini
.trakem2
.display
.DLabel
;
31 import ini
.trakem2
.display
.Layer
;
32 import ini
.trakem2
.display
.LayerSet
;
33 import ini
.trakem2
.persistence
.DBObject
;
34 import ini
.trakem2
.persistence
.FSLoader
;
35 import ini
.trakem2
.utils
.IJError
;
36 import ini
.trakem2
.utils
.Utils
;
37 import ini
.trakem2
.utils
.Search
;
39 import java
.awt
.Component
;
40 import java
.awt
.Point
;
41 import java
.awt
.Color
;
42 import java
.awt
.Event
;
43 import java
.awt
.event
.ActionEvent
;
44 import java
.awt
.event
.ActionListener
;
45 import java
.awt
.event
.MouseEvent
;
46 import java
.awt
.event
.MouseListener
;
47 import java
.util
.Hashtable
;
48 import java
.util
.Iterator
;
49 //import java.util.Enumeration;
50 import java
.util
.ArrayList
;
51 import java
.util
.HashSet
;
53 import javax
.swing
.JMenuItem
;
54 import javax
.swing
.JPopupMenu
;
55 import javax
.swing
.JScrollPane
;
56 import javax
.swing
.tree
.DefaultMutableTreeNode
;
57 import javax
.swing
.tree
.DefaultTreeModel
;
58 import javax
.swing
.tree
.TreePath
;
59 import javax
.swing
.tree
.TreeSelectionModel
;
61 public final class LayerTree
extends DNDTree
implements MouseListener
, ActionListener
{
63 private DefaultMutableTreeNode selected_node
= null;
65 public LayerTree(Project project
, LayerThing root
) {
66 super(project
, DNDTree
.makeNode(root
), new Color(230, 235, 255)); // Color(200, 200, 255));
68 addMouseListener(this);
69 // enable multiple discontiguous selection
70 this.getSelectionModel().setSelectionMode(TreeSelectionModel
.DISCONTIGUOUS_TREE_SELECTION
);
73 /** Get a custom, context-sensitive popup menu for the selected node. */
74 private JPopupMenu
getPopupMenu(DefaultMutableTreeNode node
) {
75 Object ob
= node
.getUserObject();
76 LayerThing thing
= null;
77 if (ob
instanceof LayerThing
) {
78 thing
= (LayerThing
)ob
;
82 // context-sensitive popup
83 JMenuItem
[] item
= thing
.getPopupItems(this);
84 if (0 == item
.length
) return null;
85 JPopupMenu popup
= new JPopupMenu();
86 for (int i
=0; i
<item
.length
; i
++) {
87 if (null == item
[i
] || "" == item
[i
].getText()) popup
.addSeparator();
88 else popup
.add(item
[i
]);
93 public void mousePressed(MouseEvent me
) {
94 Object source
= me
.getSource();
95 if (!source
.equals(this) || !Project
.getInstance(this).isInputEnabled()) {
99 // ignore if doing multiple selection
100 if (!me
.isPopupTrigger() && (me
.isShiftDown() || (!ij
.IJ
.isMacOSX() && me
.isControlDown()))) {
107 // check if there is a multiple selection
108 TreePath
[] paths
= this.getSelectionPaths();
109 if (null != paths
&& paths
.length
> 1) {
110 if (me
.isPopupTrigger() || MouseEvent
.BUTTON2
== me
.getButton() || 0 != (me
.getModifiers() & Event
.META_MASK
)) {
111 // check that all items are of the same type
112 String type_first
= ((LayerThing
)((DefaultMutableTreeNode
)paths
[0].getLastPathComponent()).getUserObject()).getType();
113 for (int i
=1; i
<paths
.length
; i
++) {
114 String type
= ((LayerThing
)((DefaultMutableTreeNode
)paths
[i
].getLastPathComponent()).getUserObject()).getType();
115 if (!type
.equals(type_first
)) {
116 Utils
.showMessage("All selected items must be of the same type for operations on multiple items.");
120 // prepare popup menu
121 JPopupMenu popup
= new JPopupMenu();
122 JMenuItem item
= null;
123 if (type_first
.equals("layer")) {
124 item
= new JMenuItem("Reverse layer Z coords"); item
.addActionListener(this); popup
.add(item
);
125 item
= new JMenuItem("Translate layers in Z..."); item
.addActionListener(this); popup
.add(item
);
126 item
= new JMenuItem("Scale Z and thickness..."); item
.addActionListener(this); popup
.add(item
);
127 item
= new JMenuItem("Delete..."); item
.addActionListener(this); popup
.add(item
);
129 if (popup
.getSubElements().length
> 0) {
130 popup
.show(this, x
, y
);
133 // disable commands depending upon a single node being selected
134 selected_node
= null;
138 // find the node and set it selected
139 TreePath path
= getPathForLocation(x
, y
);
143 setSelectionPath(path
);
144 selected_node
= (DefaultMutableTreeNode
)path
.getLastPathComponent();
146 if (2 == me
.getClickCount() && !me
.isPopupTrigger() && MouseEvent
.BUTTON1
== me
.getButton()) {
147 // create a new Display
148 LayerThing thing
= (LayerThing
)selected_node
.getUserObject();
149 DBObject ob
= (DBObject
)thing
.getObject();
150 if (thing
.getType().toLowerCase().replace('_', ' ').equals("layer set") && null == ((LayerSet
)ob
).getParent()) { // the top level LayerSet
153 //new Display(ob.getProject(), thing.getType().toLowerCase().equals("layer") ? (Layer)ob : ((LayerSet)ob).getParent());
154 Display
.createDisplay(ob
.getProject(), thing
.getType().toLowerCase().equals("layer") ?
(Layer
)ob
: ((LayerSet
)ob
).getParent());
156 } else if (me
.isPopupTrigger() /*|| me.isControlDown()*/ || MouseEvent
.BUTTON2
== me
.getButton() || 0 != (me
.getModifiers() & Event
.META_MASK
)) {
157 JPopupMenu popup
= getPopupMenu(selected_node
);
158 if (null == popup
) return;
159 popup
.show(this, x
, y
);
164 public void mouseDragged(MouseEvent me
) {
166 public void mouseReleased(MouseEvent me
) {
168 public void mouseEntered(MouseEvent me
) {
170 public void mouseExited(MouseEvent me
) {
172 public void mouseClicked(MouseEvent me
) {
175 public void actionPerformed(ActionEvent ae
) {
177 String command
= ae
.getActionCommand();
179 // commands for multiple selections:
180 TreePath
[] paths
= this.getSelectionPaths();
181 if (null != paths
&& paths
.length
> 1) {
182 if (command
.equals("Reverse layer Z coords")) {
183 // check that all layers belong to the same layer set
185 Layer
[] layer
= new Layer
[paths
.length
];
187 for (int i
=0; i
<paths
.length
; i
++) {
188 layer
[i
] = (Layer
) ((LayerThing
)((DefaultMutableTreeNode
)paths
[i
].getLastPathComponent()).getUserObject()).getObject();
189 if (null == ls
) ls
= layer
[i
].getParent();
190 else if (!ls
.equals(layer
[i
].getParent())) {
191 Utils
.showMessage("To reverse, all layers must belong to the same layer set");
195 final ArrayList
<Layer
> al
= new ArrayList
<Layer
>();
196 for (int i
=0; i
<layer
.length
; i
++) al
.add(layer
[i
]);
197 ls
.addLayerEditedStep(al
);
198 // ASSSUMING layers are already Z ordered! CHECK
199 for (int i
=0, j
=layer
.length
-1; i
<layer
.length
/2; i
++, j
--) {
200 double z
= layer
[i
].getZ();
201 layer
[i
].setZ(layer
[j
].getZ());
205 ls
.addLayerEditedStep(al
);
206 Display
.updateLayerScroller(ls
);
207 } else if (command
.equals("Translate layers in Z...")) {
208 GenericDialog gd
= ControlWindow
.makeGenericDialog("Range");
209 gd
.addMessage("Translate selected range in the Z axis:");
210 gd
.addNumericField("by: ", 0, 4);
212 if (gd
.wasCanceled()) return;
214 double dz
= gd
.getNextNumber();
215 if (Double
.isNaN(dz
)) {
216 Utils
.showMessage("Invalid number");
219 HashSet hs_parents
= new HashSet();
220 for (int i
=0; i
<paths
.length
; i
++) {
221 Layer layer
= (Layer
) ((LayerThing
)((DefaultMutableTreeNode
)paths
[i
].getLastPathComponent()).getUserObject()).getObject();
222 layer
.setZ(layer
.getZ() + dz
);
223 hs_parents
.add(layer
.getParent());
225 for (Iterator it
= hs_parents
.iterator(); it
.hasNext(); ) {
226 updateList((LayerSet
)it
.next());
228 // now update all profile's Z ordering in the ProjectTree
229 final Project project
= Project
.getInstance(this);
230 ProjectThing root_pt
= project
.getRootProjectThing();
231 ArrayList al_pl
= root_pt
.findChildrenOfType("profile_list");
232 for (Iterator it
= al_pl
.iterator(); it
.hasNext(); ) {
233 ProjectThing pt
= (ProjectThing
)it
.next();
235 project
.getProjectTree().updateList(pt
);
237 project
.getProjectTree().updateUILater();
238 //Display.updateLayerScroller((LayerSet)((DefaultMutableTreeNode)getModel().getRoot()).getUserObject());
239 } else if (command
.equals("Delete...")) {
240 if (!Utils
.check("Really remove all selected layers?")) return;
241 for (int i
=0; i
<paths
.length
; i
++) {
242 DefaultMutableTreeNode lnode
= (DefaultMutableTreeNode
)paths
[i
].getLastPathComponent();
243 LayerThing lt
= (LayerThing
)lnode
.getUserObject();
244 Layer layer
= (Layer
)lt
.getObject();
245 if (!layer
.remove(false)) {
246 Utils
.showMessage("Could not delete layer " + layer
);
247 this.updateUILater();
250 if (lt
.remove(false)) {
251 ((DefaultTreeModel
)this.getModel()).removeNodeFromParent(lnode
);
254 this.updateUILater();
255 } else if (command
.equals("Scale Z and thickness...")) {
256 GenericDialog gd
= new GenericDialog("Scale Z");
257 gd
.addNumericField("scale: ", 1.0, 2);
259 double scale
= gd
.getNextNumber();
260 if (Double
.isNaN(scale
) || 0 == scale
) {
261 Utils
.showMessage("Imvalid scaling factor: " + scale
);
264 for (int i
=0; i
<paths
.length
; i
++) {
265 DefaultMutableTreeNode lnode
= (DefaultMutableTreeNode
)paths
[i
].getLastPathComponent();
266 LayerThing lt
= (LayerThing
)lnode
.getUserObject();
267 Layer layer
= (Layer
)lt
.getObject();
268 layer
.setZ(layer
.getZ() * scale
);
269 layer
.setThickness(layer
.getThickness() * scale
);
271 this.updateUILater();
273 Utils
.showMessage("Don't know what to do with command " + command
+ " for multiple selected nodes");
278 // commands for single selection:
279 if (null == selected_node
) return;
280 LayerThing thing
= (LayerThing
)selected_node
.getUserObject();
281 LayerThing new_thing
= null;
282 TemplateThing tt
= null;
286 if (command
.startsWith("new ")) {
287 String name
= command
.substring(4).toLowerCase();
288 if (name
.equals("layer")) {
289 // Create new Layer and add it to the selected node
290 LayerSet set
= (LayerSet
)thing
.getObject();
291 Layer new_layer
= Layer
.create(thing
.getProject(), set
);
292 if (null == new_layer
) return;
293 tt
= thing
.getChildTemplate("layer");
295 Display
.updateTitle(set
);
296 } else if (name
.equals("layer set")) { // with space in the middle
297 // Create a new LayerSet and add it in the middle
298 Layer layer
= (Layer
)thing
.getObject();
299 LayerSet new_set
= layer
.getParent().create(layer
);
300 if (null == new_set
) return;
302 // add it at the end of the list
303 tt
= thing
.getChildTemplate("layer_set");
305 i_position
= selected_node
.getChildCount();
306 Display
.update(layer
);
308 Utils
.log("LayerTree.actionPerformed: don't know what to do with the command: " + command
);
311 } else if (command
.equals("many new layers...")) {
312 LayerSet set
= (LayerSet
)thing
.getObject();
313 Layer
[] layer
= Layer
.createMany(set
.getProject(), set
);
314 // add them to the tree as LayerThing
315 if (null == layer
) return;
316 for (int i
=0; i
<layer
.length
; i
++) {
317 addLayer(set
, layer
[i
]); // null layers will be skipped
319 Display
.updateTitle(set
);
321 } else if (command
.equals("Show")) {
322 // create a new Display
323 DBObject dbo
= (DBObject
)thing
.getObject();
324 if (thing
.getType().equals("layer_set") && null == ((LayerSet
)dbo
).getParent()) return; // the top level LayerSet
325 new Display(dbo
.getProject(), thing
.getType().equals("layer") ?
(Layer
)dbo
: ((LayerSet
)dbo
).getParent());
327 } else if (command
.equals("Show centered in Display")) {
328 LayerSet ls
= (LayerSet
)thing
.getObject();
329 Display
.showCentered(ls
.getParent(), ls
, false, false);
330 } else if (command
.equals("Delete...")) {
331 remove(true, thing
, selected_node
);
333 } else if (command
.equals("Import stack...")) {
335 DBObject dbo
= (DBObject
)thing
.getObject();
337 if (thing
.getObject() instanceof LayerSet
) {
338 LayerSet set
= (LayerSet
)thing
.getObject();
340 if (0 == set
.getLayers().size()) {
341 layer
= Layer
.create(set
.getProject(), set
);
342 if (null == layer
) return;
343 tt
= thing
.getChildTemplate("Layer");
345 } else return; // click on a desired, existing layer.
346 if (null == layer
) return;
347 layer
.getProject().getLoader().importStack(layer
, null, true);
348 } else if (thing
.getObject() instanceof Layer
) {
349 Layer layer
= (Layer
)thing
.getObject();
350 layer
.getProject().getLoader().importStack(layer
, null, true);
353 } else if (command
.equals("Import grid...")) {
354 if (thing
.getObject() instanceof Layer
) {
355 Layer layer
= (Layer
)thing
.getObject();
356 layer
.getProject().getLoader().importGrid(layer
);
358 } else if (command
.equals("Import sequence as grid...")) {
359 if (thing
.getObject() instanceof Layer
) {
360 Layer layer
= (Layer
)thing
.getObject();
361 layer
.getProject().getLoader().importSequenceAsGrid(layer
);
363 } else if (command
.equals("Import from text file...")) {
364 if (thing
.getObject() instanceof Layer
) {
365 Layer layer
= (Layer
)thing
.getObject();
366 layer
.getProject().getLoader().importImages(layer
);
368 } else if (command
.equals("Resize LayerSet...")) {
369 if (thing
.getObject() instanceof LayerSet
) {
370 LayerSet ls
= (LayerSet
)thing
.getObject();
371 ij
.gui
.GenericDialog gd
= ControlWindow
.makeGenericDialog("Resize LayerSet");
372 gd
.addNumericField("new width: ", ls
.getLayerWidth(), 3);
373 gd
.addNumericField("new height: ",ls
.getLayerHeight(),3);
374 gd
.addChoice("Anchor: ", LayerSet
.ANCHORS
, LayerSet
.ANCHORS
[0]);
376 if (gd
.wasCanceled()) return;
377 double new_width
= gd
.getNextNumber();
378 double new_height
=gd
.getNextNumber();
379 ls
.setDimensions(new_width
, new_height
, gd
.getNextChoiceIndex()); // will complain and prevent cropping existing Displayable objects
381 } else if (command
.equals("Autoresize LayerSet")) {
382 if (thing
.getObject() instanceof LayerSet
) {
383 LayerSet ls
= (LayerSet
)thing
.getObject();
384 ls
.setMinimumDimensions();
386 } else if (command
.equals("Adjust...")) {
387 if (thing
.getObject() instanceof Layer
) {
388 Layer layer
= (Layer
)thing
.getObject();
389 ij
.gui
.GenericDialog gd
= ControlWindow
.makeGenericDialog("Adjust Layer");
390 gd
.addNumericField("new z: ", layer
.getZ(), 4);
391 gd
.addNumericField("new thickness: ",layer
.getThickness(),4);
393 if (gd
.wasCanceled()) return;
394 double new_z
= gd
.getNextNumber();
395 layer
.setThickness(gd
.getNextNumber());
396 if (new_z
!= layer
.getZ()) {
400 DefaultMutableTreeNode child = findNode(thing, this);
401 DefaultMutableTreeNode parent = (DefaultMutableTreeNode)child.getParent();
402 parent.remove(child);
404 int n = parent.getChildCount();
407 DefaultMutableTreeNode child_node = (DefaultMutableTreeNode)parent.getChildAt(i);
408 LayerThing child_thing = (LayerThing)child_node.getUserObject();
409 if (!child_thing.getType().equals("Layer")) continue;
410 double iz = ((Layer)child_thing.getObject()).getZ();
411 if (iz < new_z) continue;
412 // else, add the layer here, after this one
415 ((DefaultTreeModel)this.getModel()).insertNodeInto(child, parent, i);
418 // fix tree crappiness (empty slot ?!?)
419 /* // the fix doesn't work. ARGH TODO
420 Enumeration e = parent.children();
421 parent.removeAllChildren();
423 while (e.hasMoreElements()) {
424 //parent.add((DefaultMutableTreeNode)e.nextElement());
425 ((DefaultTreeModel)this.getModel()).insertNodeInto(child, parent, i);
429 // easier and correct: overkill
430 updateList(layer
.getParent());
433 DefaultMutableTreeNode child
= findNode(thing
, this);
434 TreePath treePath
= new TreePath(child
.getPath());
435 this.scrollPathToVisible(treePath
);
436 this.setSelectionPath(treePath
);
440 } else if (command
.equals("Rename...")) {
441 GenericDialog gd
= ControlWindow
.makeGenericDialog("Rename");
442 gd
.addStringField("new name: ", thing
.getTitle());
444 if (gd
.wasCanceled()) return;
445 thing
.setTitle(gd
.getNextString());
446 } else if (command
.equals("Translate layers in Z...")) {
447 /// TODO: this method should use multiple selections directly on the tree
448 if (thing
.getObject() instanceof LayerSet
) {
449 LayerSet ls
= (LayerSet
)thing
.getObject();
450 ArrayList al_layers
= ls
.getLayers();
451 String
[] layer_names
= new String
[al_layers
.size()];
452 for (int i
=0; i
<layer_names
.length
; i
++) {
453 layer_names
[i
] = ls
.getProject().findLayerThing(al_layers
.get(i
)).toString();
455 GenericDialog gd
= ControlWindow
.makeGenericDialog("Range");
456 gd
.addMessage("Translate selected range in the Z axis:");
457 gd
.addChoice("from: ", layer_names
, layer_names
[0]);
458 gd
.addChoice("to: ", layer_names
, layer_names
[layer_names
.length
-1]);
459 gd
.addNumericField("by: ", 0, 4);
461 if (gd
.wasCanceled()) return;
463 double dz
= gd
.getNextNumber();
464 if (Double
.isNaN(dz
)) {
465 Utils
.showMessage("Invalid number");
468 int i_start
= gd
.getNextChoiceIndex();
469 int i_end
= gd
.getNextChoiceIndex();
470 for (int i
= i_start
; i
<=i_end
; i
++) {
471 Layer layer
= (Layer
)al_layers
.get(i
);
472 layer
.setZ(layer
.getZ() + dz
);
474 // update node labels and position
477 } else if (command
.equals("Reverse layer Z coords...")) {
478 /// TODO: this method should use multiple selections directly on the tree
479 if (thing
.getObject() instanceof LayerSet
) {
480 LayerSet ls
= (LayerSet
)thing
.getObject();
481 ArrayList al_layers
= ls
.getLayers();
482 String
[] layer_names
= new String
[al_layers
.size()];
483 for (int i
=0; i
<layer_names
.length
; i
++) {
484 layer_names
[i
] = ls
.getProject().findLayerThing(al_layers
.get(i
)).toString();
486 GenericDialog gd
= ControlWindow
.makeGenericDialog("Range");
487 gd
.addMessage("Reverse Z coordinates of selected range:");
488 gd
.addChoice("from: ", layer_names
, layer_names
[0]);
489 gd
.addChoice("to: ", layer_names
, layer_names
[layer_names
.length
-1]);
491 if (gd
.wasCanceled()) return;
492 int i_start
= gd
.getNextChoiceIndex();
493 int i_end
= gd
.getNextChoiceIndex();
494 for (int i
= i_start
, j
=i_end
; i
<i_end
/2; i
++, j
--) {
495 Layer layer1
= (Layer
)al_layers
.get(i
);
496 double z1
= layer1
.getZ();
497 Layer layer2
= (Layer
)al_layers
.get(j
);
498 layer1
.setZ(layer2
.getZ());
501 // update node labels and position
504 } else if (command
.equals("Search...")) {
507 Utils
.log("LayerTree.actionPerformed: don't know what to do with the command: " + command
);
511 if (null == tt
) return;
513 new_thing
= new LayerThing(tt
, thing
.getProject(), ob
);
515 if (-1 == i_position
&& new_thing
.getType().equals("layer")) {
516 // find the node whose 'z' is larger than z, and add the Layer before that.
517 // (just because there could be objects other than LayerThing with a Layer in it in the future, so set.getLayers().indexOf(layer) may not be useful)
518 double z
= ((Layer
)ob
).getZ();
519 int n
= selected_node
.getChildCount();
522 DefaultMutableTreeNode child_node
= (DefaultMutableTreeNode
)selected_node
.getChildAt(i
);
523 LayerThing child_thing
= (LayerThing
)child_node
.getUserObject();
524 if (!child_thing
.getType().equals("layer")) {
527 double iz
= ((Layer
)child_thing
.getObject()).getZ();
531 // else, add the layer here, after this one
536 thing
.addChild(new_thing
);
537 DefaultMutableTreeNode new_node
= new DefaultMutableTreeNode(new_thing
);
538 ((DefaultTreeModel
)this.getModel()).insertNodeInto(new_node
, selected_node
, i_position
);
539 TreePath treePath
= new TreePath(new_node
.getPath());
540 this.scrollPathToVisible(treePath
);
541 this.setSelectionPath(treePath
);
542 } catch (Exception e
) {
547 public boolean remove(Layer layer
, boolean check
) {
548 DefaultMutableTreeNode root
= (DefaultMutableTreeNode
)this.getModel().getRoot();
549 LayerThing thing
= (LayerThing
)(((LayerThing
)root
.getUserObject()).findChild(layer
));
550 if (null == thing
) { Utils
.log2("LayerTree.remove(Layer): thing not found"); return false; }
551 DefaultMutableTreeNode node
= DNDTree
.findNode(thing
, this);
552 if (null == node
) { Utils
.log2("LayerTree.remove(Layer): node not found"); return false; }
553 if (thing
.remove(check
)) {
554 ((DefaultTreeModel
)this.getModel()).removeNodeFromParent(node
);
555 this.updateUILater();
560 /** Used by the Loader.importStack and the "many new layers" command. */
561 public void addLayer(LayerSet layer_set
, Layer layer
) {
562 if (null == layer_set
|| null == layer
) return;
564 // find the node that contains the LayerSet
565 DefaultMutableTreeNode root_node
= (DefaultMutableTreeNode
)this.getModel().getRoot();
566 LayerThing root_lt
= (LayerThing
)root_node
.getUserObject();
568 if (root_lt
.getObject().equals(layer_set
)) thing
= root_lt
;
569 else thing
= root_lt
.findChild(layer_set
);
570 DefaultMutableTreeNode parent_node
= DNDTree
.findNode(thing
, this);
571 if (null == parent_node
) { Utils
.log("LayerTree: LayerSet not found."); return; }
572 LayerThing parent_thing
= (LayerThing
)parent_node
.getUserObject();
573 double z
= layer
.getZ();
574 // find the node whose 'z' is larger than z, and add the Layer before that.
575 int n
= parent_node
.getChildCount();
578 DefaultMutableTreeNode child_node
= (DefaultMutableTreeNode
)parent_node
.getChildAt(i
);
579 LayerThing child_thing
= (LayerThing
)child_node
.getUserObject();
580 if (!child_thing
.getType().equals("layer")) {
583 double iz
= ((Layer
)child_thing
.getObject()).getZ();
587 // else, add the layer here, after the 'i' layer which has a larger z
590 TemplateThing tt
= parent_thing
.getChildTemplate("layer");
592 Utils
.log("LayerTree: Null template Thing!");
595 LayerThing new_thing
= new LayerThing(tt
, layer
.getProject(), layer
);
596 // Add the new_thing to the tree
597 if (null != new_thing
) {
598 parent_thing
.addChild(new_thing
);
599 DefaultMutableTreeNode new_node
= new DefaultMutableTreeNode(new_thing
);
600 //TODO when changing the Z of a layer, the insertion is proper but an empty space is left //Utils.log("LayerTree: inserting at: " + i);
601 ((DefaultTreeModel
)this.getModel()).insertNodeInto(new_node
, parent_node
, i
);
602 TreePath treePath
= new TreePath(new_node
.getPath());
603 this.scrollPathToVisible(treePath
);
604 this.setSelectionPath(treePath
);
606 } catch (Exception e
) { IJError
.print(e
); }
609 public void destroy() {
611 this.selected_node
= null;
614 /** Remove all layer nodes from the given layer_set, and add them again according to the layer's Z value. */
615 public void updateList(LayerSet layer_set
) {
617 // store scrolling position for restoring purposes
619 Component c = this.getParent();
621 if (c instanceof JScrollPane) {
622 point = ((JScrollPane)c).getViewport().getViewPosition();
626 LayerThing lt
= layer_set
.getProject().findLayerThing(layer_set
);
628 Utils
.log2("LayerTree.updateList: could not find LayerSet " + layer_set
);
634 DefaultMutableTreeNode ls_node = DNDTree.findNode(lt, this);
635 if (null == ls_node) {
636 Utils.log2("LayerTree.updateList: could not find a node for LayerThing " + lt);
639 Hashtable ht = new Hashtable();
640 for (Enumeration e = ls_node.children(); e.hasMoreElements(); ) {
641 DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
642 ht.put(node.getUserObject(), node);
644 ls_node.removeAllChildren();
645 for (Iterator it = lt.getChildren().iterator(); it.hasNext(); ) {
646 Object ob = ht.remove(it.next());
647 ls_node.add((DefaultMutableTreeNode)ob);
649 if (0 != ht.size()) {
650 Utils.log2("WARNING LayerTree.updateList: did not end up adding this nodes:");
651 for (Iterator it = ht.keySet().iterator(); it.hasNext(); ) {
652 Utils.log2(it.next().toString());
655 this.updateUILater();
657 // restore viewport position
659 ((JScrollPane)c).getViewport().setViewPosition(point);
663 this.getSelectionModel().setSelectionMode(TreeSelectionModel
.DISCONTIGUOUS_TREE_SELECTION
);
666 /** If the given node is null, it will be searched for. */
667 public boolean remove(boolean check
, LayerThing thing
, DefaultMutableTreeNode node
) {
668 if (null == thing
|| null == thing
.getParent()) return false; // can't remove the root LayerSet
669 return thing
.remove(check
) && removeNode(null != node ? node
: findNode(thing
, this));