Major cleanup of Utils class.
[trakem2.git] / ini / trakem2 / tree / LayerThing.java
bloba3496924b34904adffb25e446db22d772621f6be
1 /**
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.
21 **/
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;
33 import java.util.*;
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
71 super(project);
72 // specifics:
73 this.template = template;
74 if (null == template) throw new Exception("LayerThing constructor: null template!");
75 this.object = ob;
76 if (null == ob) throw new Exception("LayerThing constructor: null Object!");
77 addToDatabase();
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) {
82 super(project, id);
83 this.template = template;
84 this.object = ob;
85 this.title = title;
86 if (null != title && (0 == title.length() || title.toLowerCase().equals("null"))) {
87 this.title = 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. */
94 public void setup() {
95 if (null != ht_attributes) {
96 for (Iterator it = ht_attributes.values().iterator(); it.hasNext(); ) {
97 ProjectAttribute pa = (ProjectAttribute)it.next(); // ?? A ProjectAttribute? WARNING
98 pa.setup(this);
101 if (null != al_children) {
102 Iterator it = al_children.iterator();
103 /* // Taken care of in the Loader
104 Class[] class_types = null;
105 try {
106 class_types = new Class[]{Class.forName("ini.trakem2.DBObject")};
107 } catch (Exception e) {
108 Utils.log("LayerThing.setup: " + e);
109 return;
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
116 try {
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);
121 continue;
124 child.parent = this;
125 child.setup();
130 public Thing getParent() {
131 return parent;
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);
142 sb.append(' ');
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;
150 this.title = title;
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() {
159 return this.title;
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)) {
169 return false;
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);
178 } else {
179 try {
180 al_children.add(i, child);
181 } catch (Exception e) {
182 Utils.log2("LayerThing.addChild: " + e);
183 al_children.add(child); // at the end
186 } else {
187 al_children.add(child);
189 child.setParent(this);
190 return true;
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);
196 return true;
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() {
213 return al_children;
216 public Object getObject() {
217 return object;
220 public void setParent(Thing parent) {
221 this.parent = (LayerThing)parent;
222 updateInDatabase("parent_id");
225 public JMenuItem[] getPopupItems(ActionListener listener) {
226 JMenuItem item;
227 ArrayList al_items = new ArrayList();
229 JMenu menu = new JMenu("Add...");
230 ArrayList tc = template.getChildren();
231 if (null != tc) {
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);
235 menu.add(item);
237 if (template.getType().replaceAll("_", " ").equals("layer set")) {
238 item = new JMenuItem("many new layers...");
239 item.addActionListener(listener);
240 menu.add(item);
243 if (0 != menu.getItemCount()) {
244 al_items.add(menu);
247 // Add a "Show" for all except the root LayerSet
248 if (null != parent) {
249 item = new JMenuItem("Show");
250 item.addActionListener(listener);
251 al_items.add(item);
253 if (template.getType().equals("layer")) {
254 item = new JMenuItem("Adjust..."); // adjust z and thickness
255 item.addActionListener(listener);
256 al_items.add(item);
258 item = new JMenuItem("Rename...");
259 item.addActionListener(listener);
260 al_items.add(item);
261 if (template.getType().replaceAll("_", " ").equals("layer set")) {
262 if (null != parent) {
263 item = new JMenuItem("Show centered in Display");
264 item.addActionListener(listener);
265 al_items.add(item);
267 item = new JMenuItem("Resize LayerSet...");
268 item.addActionListener(listener);
269 al_items.add(item);
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);
276 al_items.add(item);
277 if (empty) item.setEnabled(false);
279 item = new JMenuItem("Translate layers in Z...");
280 item.addActionListener(listener);
281 al_items.add(item);
282 if (empty) item.setEnabled(false);
284 item = new JMenuItem("Reverse layer Z coords...");
285 item.addActionListener(listener);
286 al_items.add(item);
287 if (empty) item.setEnabled(false);
289 item = new JMenuItem("Search...");
290 item.addActionListener(listener);
291 al_items.add(item);
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);
297 al_items.add(item);
298 if (template.getType().equals("layer")) {
299 item = new JMenuItem("Import grid...");
300 item.addActionListener(listener);
301 al_items.add(item);
302 item = new JMenuItem("Import sequence as grid...");
303 item.addActionListener(listener);
304 al_items.add(item);
305 item = new JMenuItem("Import from text file...");
306 item.addActionListener(listener);
307 al_items.add(item);
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);
315 al_items.add(item);
318 JMenuItem[] items = new JMenuItem[al_items.size()];
319 al_items.toArray(items);
320 return 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]);
334 return false;
338 al_children.clear();
340 // TODO the attributes are being ignored! (not even created either)
342 // remove the object
343 if (null != object && object instanceof DBObject) {
344 if (!((DBObject)object).remove(false)) {
345 Utils.showMessage("Could not delete " + object);
346 return false;
350 // remove the Thing itself
351 if (null != parent && !parent.removeChild(this)) {
352 Utils.showMessage("Could not delete LayerThing with id=" + id);
353 return false;
355 removeFromDatabase();
356 return true;
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;
367 return null;
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(",");
382 sb_at.append(")");
383 // append object
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 !");
389 return;
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() : "");