KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > tasklist > core > TaskNode


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.tasklist.core;
21
22
23 import java.awt.Image JavaDoc;
24 import java.awt.datatransfer.Transferable JavaDoc;
25 import java.beans.PropertyChangeEvent JavaDoc;
26 import java.beans.PropertyChangeListener JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.*;
29 import java.util.logging.Level JavaDoc;
30 import java.util.logging.Logger JavaDoc;
31 import org.netbeans.modules.tasklist.core.filter.FilterAction;
32 import org.openide.actions.CopyAction;
33 import org.openide.actions.CutAction;
34 import org.openide.actions.DeleteAction;
35 import org.openide.actions.PasteAction;
36 import org.openide.actions.PropertiesAction;
37 import org.openide.loaders.InstanceSupport;
38
39 import org.openide.nodes.*;
40 import org.openide.util.HelpCtx;
41 import org.openide.util.actions.SystemAction;
42 import org.openide.util.datatransfer.ExTransferable;
43
44 public class TaskNode extends AbstractNode {
45     private static final Logger JavaDoc LOGGER = TLUtils.getLogger(TaskNode.class);
46     
47     static {
48         LOGGER.setLevel(Level.FINE);
49     }
50
51     protected final Task item;
52     private Monitor monitor;
53
54     /**
55      * Task node.
56      */

57     public TaskNode(Task item, Children children) {
58         super(children);
59         this.item = item;
60         init();
61     }
62
63     /**
64      * Leaf node.
65      */

66     public TaskNode(Task item) {
67         this(item, Children.LEAF);
68     }
69
70     /**
71      * On Task.class query returns associated Task.
72      */

73     public Node.Cookie getCookie(Class JavaDoc type) {
74         if (type == Task.class) {
75             return item;
76         } else {
77             return super.getCookie(type);
78         }
79     }
80
81
82     private void init() {
83         setName(item.getSummary());
84
85         monitor = new Monitor();
86         item.addTaskListener(monitor);
87         item.addPropertyChangeListener(monitor);
88         DisposalListener dl = new DisposalListener();
89         addNodeListener(dl); // XXX it comes only if being child of Children.Keys on setKeys() call
90
updateDisplayStuff();
91         getCookieSet().add(new InstanceSupport.Instance(item));
92         
93         // Make reorderable:
94
//TODO getCookieSet().add(new ReorderMe ());
95
}
96
97     private class DisposalListener extends NodeAdapter {
98         public DisposalListener () {}
99         
100         public void nodeDestroyed(NodeEvent ev) {
101             if (ev.getNode() == TaskNode.this) {
102                 item.removeTaskListener(monitor);
103                 item.removePropertyChangeListener(monitor);
104             }
105         }
106     }
107
108     public TaskChildren getTaskChildren() {
109         return (TaskChildren) getChildren();
110     }
111      
112     // Handle cloning specially (so as not to invoke the overhead of FilterNode):
113
// public Node cloneNode () {
114
// if (item.hasSubtasks()) {
115
// return new TaskNode(item, item.subtasksIterator());
116
// } else {
117
// return new TaskNode(item);
118
// }
119
// }
120
public Node cloneNode () {
121       TaskNode clon = new TaskNode(this.item);
122       if (!clon.isLeaf())
123     clon.setChildren((TaskChildren)getTaskChildren().clone());
124       return clon;
125     }
126
127     protected TaskChildren createChildren() {
128       return new TaskChildren(this.item);
129     }
130
131     protected final void updateDisplayStuff() {
132         setDisplayName(item.getSummary());
133         updateIcon();
134     }
135
136     protected void updateIcon() {
137         // This lightbulb icon is really ugly, get something
138
// better!
139
setIconBase((item.getAction() != null) ?
140             "org/netbeans/modules/tasklist/core/lightbulb" : // NOI18N
141
"org/netbeans/modules/tasklist/core/task"); // NOI18N
142
}
143     
144     public Image JavaDoc getIcon(int type) {
145     if (item.getIcon() != null) {
146         return item.getIcon();
147     } else {
148         return super.getIcon(type);
149     }
150     }
151
152     public Image JavaDoc getOpenedIcon(int type) {
153     if (item.getIcon() != null) {
154         return item.getIcon();
155     } else {
156         return super.getOpenedIcon(type);
157     }
158     }
159
160     public HelpCtx getHelpCtx() {
161         return new HelpCtx(TaskNode.class);
162     }
163     
164     protected SystemAction[] createActions() {
165     // TODO Perform lookup here to compute an aggregate
166
// menu from other modules as well. But how do we determine
167
// order? I think NetBeans 4.0's actions re-work will have
168
// some better support for integrating context menus so I won't
169
// try to be too clever here...
170

171         return new SystemAction[] {
172             null,
173             SystemAction.get(FilterAction.class),
174             null,
175             SystemAction.get(ExpandAllAction.class),
176             null,
177             SystemAction.get(CutAction.class),
178             SystemAction.get(CopyAction.class),
179             SystemAction.get(PasteAction.class),
180             null,
181             SystemAction.get(DeleteAction.class),
182             null,
183             SystemAction.get(PropertiesAction.class),
184         };
185     }
186
187     public void destroy() throws IOException JavaDoc {
188         item.removePropertyChangeListener(monitor);
189         item.removeTaskListener(monitor);
190
191         // XXX to alter model use some cookie or so
192
// this call destroy visualization only
193
// Task parent = item.getParent();
194
// if (parent != null) parent.removeSubtask(item);
195

196         // explicitly destroy all children, it's not done automatically
197
Enumeration en = getChildren().nodes();
198         while (en.hasMoreElements()) {
199             Node next = (Node) en.nextElement();
200             next.destroy();
201         }
202         super.destroy();
203     }
204     
205     public boolean canDestroy() {
206         return true;
207     }
208     
209     /** Creates properties.
210      */

211     protected Sheet createSheet() {
212         Sheet s = Sheet.createDefault();
213         Sheet.Set ss = s.get(Sheet.PROPERTIES);
214     ss.put(new SuggestionNodeProperty(item, TaskProperties.PROP_SUMMARY));
215         return s;
216
217 // try {
218
// Node.Property p;
219
// p = new PropertySupport.Reflection(item, String.class, "getSummary", "setSummary"); // NOI18N
220
// p.setName(TaskListView.PROP_TASK_SUMMARY);
221
// p.setDisplayName(NbBundle.getMessage(TaskNode.class, "Description")); // NOI18N
222
// p.setShortDescription(NbBundle.getMessage(TaskNode.class, "DescriptionHint")); // NOI18N
223
// ss.put(p);
224
// } catch (NoSuchMethodException nsme) {
225
// ErrorManager.getDefault().notify(nsme);
226
// }
227

228     }
229     
230     public boolean canRename() {
231         return true;
232     }
233
234     public void setName(String JavaDoc nue) {
235         super.setName(nue);
236         if (!nue.equals(item.getSummary())) {
237             item.setSummary(nue);
238         }
239     }
240     
241     protected void createPasteTypes(Transferable JavaDoc t, List s) {
242     }
243     
244     // Handle copying and cutting specially:
245
public boolean canCopy () {
246         return true;
247     }
248     public boolean canCut () {
249         return true;
250     }
251
252     public Transferable JavaDoc clipboardCopy() throws IOException JavaDoc {
253         LOGGER.fine("entering");
254         return new ExTransferable.Single(TaskTransfer.TODO_FLAVOR) {
255             protected Object JavaDoc getData() {
256                 return item.clone();
257             }
258         };
259     }
260     
261     public Transferable JavaDoc clipboardCut() throws IOException JavaDoc {
262         destroy();
263         return clipboardCopy();
264     }
265
266     /* This isn't ready yet; I need to change the dialog such that it
267        can work as a property sheet (no explicit "ok" action which copies
268        GUI values into the todo item object.)
269     // Permit user to customize whole node at once (instead of per-property):
270     public boolean hasCustomizer () {
271         return true;
272     }
273     public Component getCustomizer () {
274         return new NewTodoItemPanel(this);
275     }
276     */

277
278     /*
279     public Node.Handle getHandle() {
280         return new TodoItemHandle(item);
281     }
282     */

283     
284     // Permit node to be reordered (you may also want to put
285
// MoveUpAction and MoveDownAction on the subnodes, if you can,
286
// but ReorderAction on the parent is enough):
287
/*
288     private class ReorderMe extends Index.Support {
289
290         public Node[] getNodes () {
291             return TaskNode.this.getChildren().getNodes();
292         }
293
294         public int getNodesCount () {
295             return getNodes().length;
296         }
297
298         // This assumes that there is exactly one child node per key.
299         // If you are using e.g. Children.Array, you can use shortcut implementations
300         // of the Index cookie.
301         public void reorder (int[] perm) {
302             // Remember: {2, 0, 1} cycles three items forwards.
303             List old = TaskNode.this.getTaskChildren().myKeys;
304             if (list.size () != perm.length) {
305                 throw new IllegalArgumentException();
306             }
307             List nue = new ArrayList(perm.length);
308             for (int i = 0; i < perm.length; i++)
309                 nue.set (i, old.get(perm[i]));
310             TaskNode.this.getTaskChildren().setKeys(nue);
311
312
313
314         // Remember: {2, 0, 1} cycles three items forwards.
315         MyDataElement[] items = model.getChildElements();
316         if (items.length != perm.length) throw new IllegalArgumentException();
317         MyDataElement[] nue = new MyDataElement[perm.length];
318         for (int i = 0; i < perm.length; i++) {
319         nue[i] = old[perm[i]];
320             }
321             // Should trigger an automatic child node update because the children
322             // should be listening:
323             model.setChildElements(nue);
324         }
325     }
326             */

327
328     /** Given a root node, locate the node below it which represents
329      * the given todoitem.
330      */

331     public static Node find(Node root, Task target) {
332         Task item = getTask(root);
333         if (item == target) {
334             // Done - you called this method on the node which contains the item
335
return root;
336         }
337         
338         // First we've gotta locate the ancestry of the todo item,
339
// such that we can descend the node hierarchy and know which
340
// todoitem to look for (which ancestor) to pursue - that way
341
// we don't have to look at the whole tree of nodes.
342
// (Of course, I suspect that the tree will be really flat - most
343
// todo item will be at the toplevel, at least the way -I- use
344
// the todowindow - but of course other users may use more of
345
// a hierarchical approach and then this will really help)
346

347         // Find parent children objects
348
Task p = target;
349         LinkedList ancestry = new LinkedList();
350         while ((p != null) && (p != item)) {
351             ancestry.addFirst(p);
352             p = p.getParent();
353         }
354         
355         Node n = root;
356         ListIterator it = ancestry.listIterator();
357         while (it.hasNext()) {
358             Task parent = (Task)it.next();
359             // Locate this parent
360
org.openide.nodes.Children c = n.getChildren();
361             Node[] nc = c.getNodes();
362             for (int i = 0; i < nc.length; i++) {
363                 n = nc[i];
364                 if (getTask(n) == parent) {
365                     break;
366                 }
367             }
368         }
369         if (getTask(n) == target) {
370             return n;
371         } else {
372             return null;
373         }
374     }
375
376     /** Find the Task corresponding to a given node, or null
377         if this node does not represent a task */

378     public static Task getTask(Node n) {
379         if (n == null) {
380             return null;
381         }
382         return (Task) n.getCookie(Task.class);
383     }
384     
385     /** Find the TaskNode corresponding to a given node, or null
386         if this node does not represent a TaskNode */

387     public static TaskNode getTaskNode(Node n) {
388         if (n == null) {
389             return null;
390         }
391         if (n instanceof TaskNode) {
392             return (TaskNode)n;
393         } else if (n instanceof FilterTaskNode) {
394             n = ((FilterTaskNode)n).getOriginal();
395             if (n instanceof TaskNode) {
396                 return (TaskNode)n;
397             }
398         }
399         return null;
400     }
401
402     // TaskListener implementation ~~~~~~~~~~~~~~~~~~~~~~
403

404     private class Monitor implements TaskListener, PropertyChangeListener JavaDoc {
405         public Monitor () {}
406         
407         public void selectedTask(Task t) {
408             // it's view job
409
}
410
411         public void warpedTask(Task t) {
412             // it's view job
413
}
414
415         public void addedTask(Task t) {
416             if (t.getParent().getKey() == item.getKey()) {
417                 // Special case -- we've made a leaf into one containing children!
418
Children c = getChildren();
419                 if (c == Children.LEAF) {
420                     assert item.hasSubtasks();
421                     // XXX This seems to get called more frequently than is necessary!
422
setChildren(createChildren());
423                 }
424             }
425         }
426
427         public void removedTask(Task pt, Task t, int index) {
428             // children's job
429
}
430
431         public void structureChanged(Task t) {
432             if (t == null) return;
433             if (t.getKey() == item.getKey()) {
434                 // Special case -- we've made a leaf into one containing children!
435
Children c = getChildren();
436                 if ((c == Children.LEAF) && (item.hasSubtasks())) {
437                     // XXX This seems to get called more frequently than is necessary!
438
setChildren(createChildren());
439                 }
440             }
441         }
442
443         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
444             // Some aspects of the module may have changed. Redisplay everything.
445
updateDisplayStuff();
446             firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
447         }
448
449     }
450 }
451
452
Popular Tags