3 TrakEM2 plugin for ImageJ(C).
4 Copyright (C) 2005, 2006 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
;
26 import ini
.trakem2
.Project
;
27 import ini
.trakem2
.display
.Display
;
28 import ini
.trakem2
.display
.LayerSet
;
29 import ini
.trakem2
.display
.Layer
;
30 import ini
.trakem2
.persistence
.DBObject
;
31 import ini
.trakem2
.utils
.Utils
;
34 import javax
.swing
.JMenuItem
;
35 import javax
.swing
.JMenu
;
36 import java
.awt
.event
.ActionListener
;
38 public final class LayerThing
extends DBObject
implements Thing
{
40 /** The model for this LayerThing instance. */
41 private TemplateThing template
;
43 /** If null, this instance is root. */
44 private LayerThing parent
;
46 private Object object
; // a Layer or a LayerSet
48 private ArrayList al_children
= null;
50 private HashMap ht_attributes
= null;
51 // TODO : attributes, at all?
52 private String title
= null;
54 /** A new copy with same template, same project, same id, same object and cloned table of same attributes, and same title, but no parent and no children. */
55 public Thing
shallowCopy() {
56 return new LayerThing(this);
59 /** For shallow copying purposes. */
60 private LayerThing(final LayerThing lt
) {
61 super(lt
.project
, lt
.id
);
62 this.title
= lt
.title
;
63 this.object
= lt
.object
;
64 if (null != lt
.ht_attributes
) {
65 this.ht_attributes
= (HashMap
) lt
.ht_attributes
.clone();
69 public LayerThing(TemplateThing template
, Project project
, Object ob
) throws Exception
{
70 // call super constructor
73 this.template
= template
;
74 if (null == template
) throw new Exception("LayerThing constructor: null template!");
76 if (null == ob
) throw new Exception("LayerThing constructor: null Object!");
80 /** Reconstruct from database, in combination with the setup() method. */
81 public LayerThing(TemplateThing template
, Project project
, long id
, String title
, Object ob
, ArrayList al_children
, HashMap ht_attributes
) {
83 this.template
= template
;
86 if (null != title
&& (0 == title
.length() || title
.toLowerCase().equals("null"))) {
89 this.al_children
= al_children
;
90 this.ht_attributes
= ht_attributes
;
93 /** Tell the attributes who owns them, and the children's attributes as well, and set the parent to the children; used to finish up reconstruction from the database. */
95 if (null != ht_attributes
) {
96 for (Iterator it
= ht_attributes
.values().iterator(); it
.hasNext(); ) {
97 ProjectAttribute pa
= (ProjectAttribute
)it
.next(); // ?? A ProjectAttribute? WARNING
101 if (null != al_children
) {
102 Iterator it
= al_children
.iterator();
103 /* // Taken care of in the Loader
104 Class[] class_types = null;
106 class_types = new Class[]{Class.forName("ini.trakem2.DBObject")};
107 } catch (Exception e) {
108 Utils.log("LayerThing.setup: " + e);
111 Method method = this.object.getClass().getDeclaredMethod("addSilently", class_types);
113 while (it
.hasNext()) {
114 LayerThing child
= (LayerThing
)it
.next();
115 /* // Taken care of in the Loader
117 // add LayerSets to Layers, and viceversa (Patches, profiles, etc. do not belong to Things so they won't be as children of this Thing)
118 method.invoke(this.object, new Object[]{child.getObject()});
119 } catch (Exception e) {
120 Utils.log("LayerThing.setup: " + e);
130 public Thing
getParent() {
134 public TemplateThing
getChildTemplate(String type
) {
135 return template
.getChildTemplate(type
);
138 public String
toString() {
139 final StringBuffer sb
= new StringBuffer();
140 if (null != parent
) sb
.append(Integer
.toString(parent
.indexOf(this) + 1)).append(':').append(' ');
141 if (null != title
) sb
.append(title
);
143 if (null == object
) sb
.append(template
.getType());
144 else sb
.append(object
.toString()).append(' ').append('[').append(template
.getType()).append(']');
145 return sb
.toString();
148 public void setTitle(String title
) {
149 if (null == title
|| title
.equals(this.title
)) return;
151 updateInDatabase("title");
152 if (object
instanceof Layer
) { // haha, bad design ... the DBObject should have a get/setTitle method pair
153 Display
.updateTitle((Layer
)object
);
157 /** May be null or empty; call toString() to get a textual representation. */
158 public String
getTitle() {
162 public boolean canHaveAsChild(Thing thing
) {
163 if (null == thing
) return false;
164 return template
.canHaveAsChild(thing
);
167 public boolean addChild(Thing child
) {
168 if (!template
.canHaveAsChild(child
)) {
171 if (null == al_children
) al_children
= new ArrayList();
172 if (null != child
.getObject() && child
.getObject() instanceof Layer
) { // this is a patch, but hey, do you want to redesign the events, which are based on layer titles and toString() contents? TODO ...
173 Layer l
= (Layer
)child
.getObject();
174 int i
= l
.getParent().indexOf(l
);
175 //Utils.log2("al_children.size(): " + al_children.size() + ", i=" + i);
176 if (i
>= al_children
.size()) { //TODO happens when importing a stack
177 al_children
.add(child
);
180 al_children
.add(i
, child
);
181 } catch (Exception e
) {
182 Utils
.log2("LayerThing.addChild: " + e
);
183 al_children
.add(child
); // at the end
187 al_children
.add(child
);
189 child
.setParent(this);
193 public boolean removeChild(LayerThing child
) {
194 if (null == al_children
|| null == child
|| -1 == al_children
.indexOf(child
)) return false;
195 al_children
.remove(child
);
199 public String
getType() {
200 return template
.getType();
203 public HashMap
getAttributes() {
204 return ht_attributes
; // TODO for now, Layer and LayerSet have no attributes
207 public boolean canHaveAsAttribute(String type
) {
208 if (null == type
) return false;
209 return template
.canHaveAsAttribute(type
);
212 public ArrayList
getChildren() {
216 public Object
getObject() {
220 public void setParent(Thing parent
) {
221 this.parent
= (LayerThing
)parent
;
222 updateInDatabase("parent_id");
225 public JMenuItem
[] getPopupItems(ActionListener listener
) {
227 ArrayList al_items
= new ArrayList();
229 JMenu menu
= new JMenu("Add...");
230 ArrayList tc
= template
.getChildren();
232 for (Iterator it
= tc
.iterator(); it
.hasNext(); ) {
233 item
= new JMenuItem("new " + ((Thing
)it
.next()).getType().replace('_', ' ')); // changing underscores for spaces, for the 'layer_set' type to read nice
234 item
.addActionListener(listener
);
237 if (template
.getType().replaceAll("_", " ").equals("layer set")) {
238 item
= new JMenuItem("many new layers...");
239 item
.addActionListener(listener
);
243 if (0 != menu
.getItemCount()) {
247 // Add a "Show" for all except the root LayerSet
248 if (null != parent
) {
249 item
= new JMenuItem("Show");
250 item
.addActionListener(listener
);
253 if (template
.getType().equals("layer")) {
254 item
= new JMenuItem("Adjust..."); // adjust z and thickness
255 item
.addActionListener(listener
);
258 item
= new JMenuItem("Rename...");
259 item
.addActionListener(listener
);
261 if (template
.getType().replaceAll("_", " ").equals("layer set")) {
262 if (null != parent
) {
263 item
= new JMenuItem("Show centered in Display");
264 item
.addActionListener(listener
);
267 item
= new JMenuItem("Resize LayerSet...");
268 item
.addActionListener(listener
);
271 LayerSet layer_set
= (LayerSet
)object
;
272 final boolean empty
= 0 == layer_set
.getLayers().size();
274 item
= new JMenuItem("Autoresize LayerSet");
275 item
.addActionListener(listener
);
277 if (empty
) item
.setEnabled(false);
279 item
= new JMenuItem("Translate layers in Z...");
280 item
.addActionListener(listener
);
282 if (empty
) item
.setEnabled(false);
284 item
= new JMenuItem("Reverse layer Z coords...");
285 item
.addActionListener(listener
);
287 if (empty
) item
.setEnabled(false);
289 item
= new JMenuItem("Search...");
290 item
.addActionListener(listener
);
292 if (empty
) item
.setEnabled(false);
294 item
= new JMenuItem("Import stack...");
295 if (template
.getType().replaceAll("_", " ").equals("layer set") && 0 != ((LayerSet
)object
).getLayers().size()) item
.setEnabled(false); // contains layers already, wouldn't know where to put it!
296 item
.addActionListener(listener
);
298 if (template
.getType().equals("layer")) {
299 item
= new JMenuItem("Import grid...");
300 item
.addActionListener(listener
);
302 item
= new JMenuItem("Import sequence as grid...");
303 item
.addActionListener(listener
);
305 item
= new JMenuItem("Import from text file...");
306 item
.addActionListener(listener
);
310 // add a delete to all except the root LayerSet
311 if (null != parent
) {
312 al_items
.add(new JMenuItem(""));
313 item
= new JMenuItem("Delete...");
314 item
.addActionListener(listener
);
318 JMenuItem
[] items
= new JMenuItem
[al_items
.size()];
319 al_items
.toArray(items
);
323 /** Remove this instance, cascading the remove action to the children and the objects. Will also cleanup the nodes in the ProjectTree. */
324 public boolean remove(boolean check
) {
325 if (check
&& !Utils
.check("Really delete " + this.toString() + (object
instanceof Layer
&& ((Layer
)object
).getDisplayables().size() > 0 ?
" and all its children?" : ""))) return false;
326 // remove the children, which will propagate to their own objects
327 if (null != al_children
) {
328 Object
[] ob
= new Object
[al_children
.size()];
329 al_children
.toArray(ob
);
330 for (int i
=0; i
<ob
.length
; i
++) {
331 if (ob
[i
] instanceof DBObject
) {
332 if (!((DBObject
)ob
[i
]).remove(false)) {
333 Utils
.showMessage("Could not delete " + ob
[i
]);
340 // TODO the attributes are being ignored! (not even created either)
343 if (null != object
&& object
instanceof DBObject
) {
344 if (!((DBObject
)object
).remove(false)) {
345 Utils
.showMessage("Could not delete " + object
);
350 // remove the Thing itself
351 if (null != parent
&& !parent
.removeChild(this)) {
352 Utils
.showMessage("Could not delete LayerThing with id=" + id
);
355 removeFromDatabase();
359 /** Recursive search for the thing that contains the given object. */
360 public Thing
findChild(Object ob
) {
361 if (this.object
.equals(ob
)) return this;
362 if (null == al_children
) return null;
363 for (Iterator it
= al_children
.iterator(); it
.hasNext(); ) {
364 Thing found
= ((Thing
)it
.next()).findChild(ob
);
365 if (null != found
) return found
;
370 public int indexOf(LayerThing child
) {
371 return al_children
.indexOf(child
);
374 public void debug(String indent
) {
375 StringBuffer sb_at
= new StringBuffer(" (id,"); // 'id' exists regardless
376 if (null != ht_attributes
) {
377 for (Iterator it
= ht_attributes
.values().iterator(); it
.hasNext(); ) {
378 ProjectAttribute ta
= (ProjectAttribute
)it
.next();
379 sb_at
.append(ta
.getTitle()).append(",");
384 sb_at
.append(" object: ").append(object
);
385 System
.out
.println(indent
+ template
.getType() + sb_at
.toString());
386 if (null != al_children
) {
387 if (indent
.length() > 20) {
388 System
.out
.println("INDENT OVER 20 !");
391 for (Iterator it
= al_children
.iterator(); it
.hasNext(); ) {
392 ((Thing
)it
.next()).debug(indent
+ "\t");
397 public boolean isExpanded() {
398 return project
.getLayerTree().isExpanded(this);
401 /** Return information on this node and its object. */ // TODO: make it recursive on all children objects, listing their attributes and their object's info
402 public String
getInfo() {
403 return "Node: " + object
+ "\n" + (object
instanceof DBObject ?
((DBObject
)object
).getInfo() : "");