KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > favorites > Tab


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.favorites;
21
22 import java.awt.BorderLayout JavaDoc;
23 import java.beans.BeanInfo JavaDoc;
24 import java.beans.PropertyChangeEvent JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.beans.PropertyVetoException JavaDoc;
27 import java.io.ObjectStreamException JavaDoc;
28 import java.util.Stack JavaDoc;
29 import java.util.logging.Level JavaDoc;
30 import java.util.logging.Logger JavaDoc;
31 import javax.swing.ActionMap JavaDoc;
32 import javax.swing.SwingUtilities JavaDoc;
33 import javax.swing.text.DefaultEditorKit JavaDoc;
34 import org.openide.awt.StatusDisplayer;
35 import org.openide.explorer.ExplorerManager;
36 import org.openide.explorer.ExplorerUtils;
37 import org.openide.explorer.view.BeanTreeView;
38 import org.openide.explorer.view.TreeView;
39 import org.openide.filesystems.FileObject;
40 import org.openide.filesystems.FileUtil;
41 import org.openide.loaders.DataObject;
42 import org.openide.loaders.DataObjectNotFoundException;
43 import org.openide.loaders.DataShadow;
44 import org.openide.nodes.Node;
45 import org.openide.nodes.NodeEvent;
46 import org.openide.nodes.NodeListener;
47 import org.openide.nodes.NodeMemberEvent;
48 import org.openide.nodes.NodeOp;
49 import org.openide.nodes.NodeReorderEvent;
50 import org.openide.util.HelpCtx;
51 import org.openide.util.NbBundle;
52 import org.openide.util.WeakListeners;
53 import org.openide.windows.TopComponent;
54 import org.openide.windows.WindowManager;
55
56 /**
57  * Physical tree view showing list of favorites.
58  */

59 public class Tab extends TopComponent
60 implements Runnable JavaDoc, ExplorerManager.Provider {
61     static final long serialVersionUID =-8178367548546385799L;
62
63     /** data object which should be selected in EQ; synch array when accessing */
64     private static final DataObject[] needToSelect = new DataObject[1];
65
66
67     private static transient Tab DEFAULT;
68
69     /** composited view */
70     transient protected TreeView view;
71     /** listeners to the root context and IDE settings */
72     transient private PropertyChangeListener JavaDoc weakRcL;
73     transient private NodeListener weakNRcL;
74
75     transient private NodeListener rcListener;
76     /** validity flag */
77     transient private boolean valid = true;
78     
79     private ExplorerManager manager;
80     
81     /** Creates */
82     private Tab() {
83         this.manager = new ExplorerManager();
84         
85         ActionMap JavaDoc map = this.getActionMap ();
86         map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
87         map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
88         map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
89         map.put("delete", ExplorerUtils.actionDelete (manager, true)); // or false
90

91         // following line tells the top component which lookup should be associated with it
92
associateLookup (ExplorerUtils.createLookup (manager, map));
93     }
94     
95     public HelpCtx getHelpCtx () {
96         return new HelpCtx(Tab.class);
97     }
98     
99     public ExplorerManager getExplorerManager() {
100         return manager;
101     }
102     
103     /** Return preferred ID */
104     protected String JavaDoc preferredID () {
105         return "favorites"; //NOI18N
106
}
107     
108     /** Initialize visual content of component */
109     protected void componentShowing () {
110         super.componentShowing ();
111
112         if (view == null) {
113             view = initGui ();
114
115             view.getAccessibleContext().setAccessibleName(
116                 NbBundle.getMessage(
117                     Tab.class, "ACSN_ExplorerBeanTree"));
118             view.getAccessibleContext().setAccessibleDescription(
119                 NbBundle.getMessage(
120                     Tab.class, "ACSD_ExplorerBeanTree"));
121         }
122         
123         run();
124     }
125
126     /** Initializes gui of this component. Subclasses can override
127     * this method to install their own gui.
128     * @return Tree view that will serve as main view for this explorer.
129     */

130     protected TreeView initGui () {
131         TreeView view = new BeanTreeView();
132         view.setRootVisible(false);
133         view.setDragSource (true);
134         setLayout(new BorderLayout JavaDoc());
135         add (view);
136         return view;
137     }
138
139     protected void componentActivated() {
140         ExplorerUtils.activateActions(manager, true);
141     }
142     protected void componentDeactivated() {
143         ExplorerUtils.activateActions(manager, false);
144     }
145     
146     /** Transfer focus to view. */
147     @SuppressWarnings JavaDoc("deprecation") @Override JavaDoc
148     public void requestFocus () {
149         super.requestFocus();
150         if (view != null) {
151             view.requestFocus();
152         }
153     }
154
155     /** Transfer focus to view. */
156     @SuppressWarnings JavaDoc("deprecation") @Override JavaDoc
157     public boolean requestFocusInWindow () {
158         super.requestFocusInWindow();
159         if (view != null) {
160             return view.requestFocusInWindow();
161         } else {
162             return false;
163         }
164     }
165
166     /** Sets new root context to view. Name, icon, tooltip
167     * of this top component will be updated properly */

168     public void setRootContext (Node rc) {
169         Node oldRC = getExplorerManager().getRootContext();
170         // remove old listener, if possible
171
if (weakRcL != null) {
172             oldRC.removePropertyChangeListener(weakRcL);
173         }
174         if (weakNRcL != null) {
175             oldRC.removeNodeListener(weakNRcL);
176         }
177         getExplorerManager().setRootContext(rc);
178         initializeWithRootContext(rc);
179     }
180
181     public Node getRootContext () {
182         return getExplorerManager().getRootContext();
183     }
184
185     /** Implementation of DeferredPerformer.DeferredCommand
186     * Performs initialization of component's attributes
187     * after deserialization (component's name, icon etc,
188     * according to the root context) */

189     public void run() {
190         if (!valid) {
191             valid = true;
192             validateRootContext();
193         }
194     }
195
196     // Bugfix #5891 04 Sep 2001 by Jiri Rechtacek
197
// the title is derived from the root context
198
// it isn't changed by a selected node in the tree
199
/** Called when the explored context changes.
200     * Overriden - we don't want title to change in this style.
201     */

202     protected void updateTitle () {
203         // set name by the root context
204
setName(getExplorerManager ().getRootContext().getDisplayName());
205     }
206
207     private NodeListener rcListener () {
208         if (rcListener == null) {
209             rcListener = new RootContextListener();
210         }
211         return rcListener;
212     }
213
214     /** Initialize this top component properly with information
215     * obtained from specified root context node */

216     private void initializeWithRootContext (Node rc) {
217         // update TC's attributes
218
setIcon(rc.getIcon(BeanInfo.ICON_COLOR_16x16));
219         setToolTipText(rc.getDisplayName());
220         setName(rc.getDisplayName());
221         updateTitle();
222         // attach listener
223
if (weakRcL == null) {
224             weakRcL = WeakListeners.propertyChange(
225                 rcListener(), rc
226             );
227         }
228         rc.addPropertyChangeListener(weakRcL);
229
230         if (weakNRcL == null) {
231             weakNRcL = NodeOp.weakNodeListener (
232                 rcListener(), rc
233             );
234         }
235         rc.addNodeListener(weakNRcL);
236     }
237
238     // put a request for later validation
239
// we must do this here, because of ExplorerManager's deserialization.
240
// Root context of ExplorerManager is validated AFTER all other
241
// deserialization, so we must wait for it
242
protected final void scheduleValidation() {
243         valid = false;
244 // WindowManagerImpl.deferredPerformer().putRequest(this, null);
245
SwingUtilities.invokeLater(this); // TEMP
246
}
247
248     /* Updated accessible name of the tree view */
249     public void setName(String JavaDoc name) {
250         super.setName(name);
251         if (view != null) {
252             view.getAccessibleContext().setAccessibleName(name);
253         }
254     }
255
256     /* Updated accessible description of the tree view */
257     public void setToolTipText(String JavaDoc text) {
258         super.setToolTipText(text);
259         if (view != null) {
260             view.getAccessibleContext().setAccessibleDescription(text);
261         }
262     }
263
264     /** Multi - purpose listener, listens to: <br>
265     * 1) Changes of name, icon, short description of root context.
266     * 2) Changes of IDE settings, namely delete confirmation settings */

267     private final class RootContextListener implements NodeListener {
268         public void propertyChange (PropertyChangeEvent JavaDoc evt) {
269             String JavaDoc propName = evt.getPropertyName();
270             Object JavaDoc source = evt.getSource();
271
272             // root context node change
273
Node n = (Node)source;
274             if (Node.PROP_DISPLAY_NAME.equals(propName) ||
275                     Node.PROP_NAME.equals(propName)) {
276                 setName(n.getDisplayName());
277             } else if (Node.PROP_ICON.equals(propName)) {
278                 setIcon(n.getIcon(BeanInfo.ICON_COLOR_16x16));
279             } else if (Node.PROP_SHORT_DESCRIPTION.equals(propName)) {
280                 setToolTipText(n.getShortDescription());
281             }
282         }
283
284         public void nodeDestroyed(NodeEvent nodeEvent) {
285             //Tab.this.setCloseOperation(TopComponent.CLOSE_EACH);
286
Tab.this.close();
287         }
288
289         public void childrenRemoved(NodeMemberEvent e) {}
290         public void childrenReordered(NodeReorderEvent e) {}
291         public void childrenAdded(NodeMemberEvent e) {}
292
293     } // end of RootContextListener inner class
294

295     /** Gets default instance. Don't use directly, it reserved for deserialization routines only,
296      * e.g. '.settings' file in xml layer, otherwise you can get non-deserialized instance. */

297     public static synchronized Tab getDefault() {
298         if (DEFAULT == null) {
299             DEFAULT = new Tab();
300             // put a request for later validation
301
// we must do this here, because of ExplorerManager's deserialization.
302
// Root context of ExplorerManager is validated AFTER all other
303
// deserialization, so we must wait for it
304
DEFAULT.scheduleValidation();
305         }
306
307         return DEFAULT;
308     }
309
310     /** Finds default instance. Use in client code instead of {@link #getDefault()}. */
311     public static synchronized Tab findDefault() {
312         if(DEFAULT == null) {
313             TopComponent tc = WindowManager.getDefault().findTopComponent("favorites"); // NOI18N
314
if(DEFAULT == null) {
315                 Logger.getLogger(Tab.class.getName()).log(Level.WARNING, null,
316                                   new IllegalStateException JavaDoc("Can not find project component for its ID. Returned " +
317                                                             tc)); // NOI18N
318
DEFAULT = new Tab();
319                 // XXX Look into getDefault method.
320
DEFAULT.scheduleValidation();
321             }
322         }
323
324         return DEFAULT;
325     }
326
327     /** Overriden to explicitely set persistence type of ProjectsTab
328      * to PERSISTENCE_ALWAYS */

329     public int getPersistenceType() {
330         return TopComponent.PERSISTENCE_ALWAYS;
331     }
332     
333     // ---- private implementation
334

335     /** Finds a node for given data object.
336     */

337     private static Node findClosestNode (DataObject obj, Node start, boolean useLogicalViews) {
338         DataObject original = obj;
339         
340         Stack JavaDoc<DataObject> stack = new Stack JavaDoc<DataObject> ();
341         while (obj != null) {
342             stack.push(obj);
343             DataObject tmp = obj.getFolder();
344             if (tmp == null) {
345                 //Skip archive file root and do not stop at archive file root
346
//ie. continue to root of filesystem.
347
FileObject fo = FileUtil.getArchiveFile(obj.getPrimaryFile());
348                 if (fo != null) {
349                     try {
350                         obj = DataObject.find(fo);
351                         //Remove archive root from stack
352
stack.pop();
353                     } catch (DataObjectNotFoundException exc) {
354                         obj = null;
355                     }
356                 } else {
357                     obj = null;
358                 }
359             } else {
360                 obj = tmp;
361             }
362         }
363         
364         Node current = start;
365         int topIdx = stack.size();
366         int i = 0;
367         while (i < topIdx) {
368             Node n = findDataObject (current, stack.get (i));
369             if (n != null) {
370                 current = n;
371                 topIdx = i;
372                 i = 0;
373             } else {
374                 i++;
375             }
376         }
377         if (!check(current, original) && useLogicalViews) {
378             Node[] children = current.getChildren().getNodes();
379             for (int j = 0; j < children.length; j++) {
380                 Node child = children[j];
381                 Node n = selectInLogicalViews(original, child);
382                 if (check(n, original)) {
383                     current = n;
384                     break;
385                 }
386             }
387         }
388         return current;
389     }
390
391     private static Node selectInLogicalViews(DataObject original, Node start) {
392         return start;
393         /* Nothing for now.
394         DataShadow shadow = (DataShadow)start.getCookie(DataShadow.class);
395         if (shadow == null) {
396             return findClosestNode(original, start, false);
397         }
398         return start;
399          */

400     }
401
402     /** Selects a node for given data object.
403     */

404     private boolean selectNode (DataObject obj, Node root) {
405         Node node = findClosestNode(obj, root, true);
406         try {
407             getExplorerManager ().setSelectedNodes (new Node[] { node });
408         } catch (PropertyVetoException JavaDoc e) {
409             // you are out of luck!
410
throw new IllegalStateException JavaDoc();
411         }
412         return check(node, obj);
413     }
414
415     private static boolean check(Node node, DataObject obj) {
416         DataObject dObj = (DataObject)node.getLookup().lookup(DataObject.class);
417         if (obj == dObj) {
418             return true;
419         }
420         if (dObj instanceof DataShadow && obj == ((DataShadow)dObj).getOriginal()) {
421             return true;
422         }
423         return false;
424     }
425
426     /** Finds a data object among children of given node.
427     * @param node the node to search in
428     * @param obj the object to look for
429     */

430     private static Node findDataObject (Node node, DataObject obj) {
431         Node[] arr = node.getChildren ().getNodes (true);
432         for (int i = 0; i < arr.length; i++) {
433             DataShadow ds = (DataShadow) arr[i].getCookie (DataShadow.class);
434             if ((ds != null) && (obj == ds.getOriginal())) {
435                 return arr[i];
436             } else {
437                 DataObject o = (DataObject) arr[i].getCookie (DataObject.class);
438                 if ((o != null) && (obj == o)) {
439                     return arr[i];
440                 }
441             }
442         }
443         return null;
444     }
445
446     /** Exchanges deserialized root context to projects root context
447     * to keep the uniquennes. */

448     protected void validateRootContext () {
449         Node projectsRc = Favorites.getNode ();
450         setRootContext(projectsRc);
451     }
452     
453     
454
455     protected boolean containsNode(DataObject obj) {
456         Node node = findClosestNode(obj, getExplorerManager ().getRootContext (), true);
457         return check(node, obj);
458     }
459
460     protected void doSelectNode (DataObject obj) {
461         Node root = getExplorerManager ().getRootContext ();
462         if (selectNode (obj, root)) {
463             requestActive();
464             StatusDisplayer.getDefault().setStatusText(""); // NOI18N
465
} else {
466             StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Tab.class,"MSG_NodeNotFound"));
467         }
468     }
469
470     /** Old (3.2) deserialization of the ProjectTab */
471     public Object JavaDoc readResolve() throws ObjectStreamException JavaDoc {
472         getDefault().scheduleValidation();
473         return getDefault();
474     }
475     
476 } // end of Tab inner class
477
Popular Tags