KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > loaders > DataNode


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.openide.loaders;
21
22
23 import java.awt.datatransfer.*;
24 import java.beans.*;
25 import java.io.*;
26 import java.util.*;
27 import javax.swing.Action JavaDoc;
28 import org.netbeans.modules.openide.loaders.UIException;
29 import org.openide.filesystems.*;
30 import org.openide.nodes.*;
31 import org.openide.util.*;
32 import org.openide.util.actions.SystemAction;
33 import org.openide.util.datatransfer.ExTransferable;
34
35 /** Standard node representing a data object.
36 *
37 * @author Jaroslav Tulach
38 */

39 public class DataNode extends AbstractNode {
40
41     /** generated Serialized Version UID */
42     static final long serialVersionUID = -7882925922830244768L;
43
44     /** DataObject of this node. */
45     private DataObject obj;
46
47     /** property change listener */
48     private PropL propL;
49
50     /** should file extensions be displayed? */
51     private static boolean showFileExtensions = true;
52
53     /** Create a data node with the given children set for the given data object.
54     * @param obj object to work with
55     * @param ch children container for the node
56     * @see #getShowFileExtensions
57     */

58     public DataNode (DataObject obj, Children ch) {
59         this(obj, ch, null);
60     }
61
62     /** Create a data node for a given data object.
63     * The provided children object will be used to hold all child nodes.
64     * The name is always set to the base name of the primary file;
65     * the display name may instead be set to the base name with extension.
66     * @param obj object to work with
67     * @param ch children container for the node
68     * @param lookup the lookup to provide content of {@link #getLookup}
69     * and also {@link #getCookie}
70     * @see #getShowFileExtensions
71     *
72     * @since 5.6
73     * @author Libor Kotouc
74     */

75     public DataNode (DataObject obj, Children ch, Lookup lookup) {
76         super (ch, lookup);
77         this.obj = obj;
78
79         propL = new PropL ();
80         if (lookup == null) {
81             setCookieSet(CookieSet.createGeneric(propL));
82         }
83
84         obj.addPropertyChangeListener (org.openide.util.WeakListeners.propertyChange (propL, obj));
85
86         super.setName (obj.getName ());
87         updateDisplayName ();
88     }
89
90     private void updateDisplayName () {
91         FileObject prim = obj.getPrimaryFile ();
92         String JavaDoc newDisplayName;
93         
94         if (prim.isRoot()) {
95             // Special case - getName{,Ext} will just return "".
96
// Used to be handled by org.netbeans.core.RootFolderNode
97
// but might as well do it here.
98
// XXX replace with #37549
99
File f = FileUtil.toFile(prim);
100             if (f == null) {
101                 // Check for a JAR root explicitly.
102
FileObject archiveFile = FileUtil.getArchiveFile(prim);
103                 if (archiveFile != null) {
104                     f = FileUtil.toFile(archiveFile);
105                 }
106             }
107             if (f != null) {
108                 // E.g. /tmp/foo or /tmp/foo.jar
109
newDisplayName = f.getAbsolutePath();
110             } else {
111                 try {
112                     // E.g. http://webdavhost.nowhere.net/mystuff/
113
newDisplayName = prim.getURL().toExternalForm();
114                 } catch (FileStateInvalidException e) {
115                     // Should not happen in practice.
116
newDisplayName = "???"; // NOI18N
117
}
118             }
119         } else if (showFileExtensions || obj instanceof DataFolder || obj instanceof DefaultDataObject) {
120             newDisplayName = prim.getNameExt();
121         } else {
122             newDisplayName = prim.getName ();
123         }
124
125         if (displayFormat != null)
126             setDisplayName (displayFormat.format (new Object JavaDoc[] { newDisplayName }));
127         else
128             setDisplayName (newDisplayName);
129     }
130
131     /** Get the represented data object.
132      * @return the data object
133     */

134     public DataObject getDataObject() {
135         return obj;
136     }
137
138     /** Changes the name of the node and may also rename the data object.
139     * If the object is renamed and file extensions are to be shown,
140     * the display name is also updated accordingly.
141     *
142     * @param name new name for the object
143     * @param rename rename the data object?
144     * @exception IllegalArgumentException if the rename failed
145     */

146     public void setName (String JavaDoc name, boolean rename) {
147         try {
148             if (rename) {
149                 obj.rename (name);
150             }
151
152             super.setName (name);
153             updateDisplayName ();
154         } catch (IOException ex) {
155             String JavaDoc msg = null;
156             if ((ex.getLocalizedMessage() == null) ||
157                 (ex.getLocalizedMessage().equals(ex.getMessage()))) {
158                 msg = NbBundle.getMessage (DataNode.class, "MSG_renameError", getName (), name); // NOI18N
159
} else {
160                 msg = ex.getLocalizedMessage();
161             }
162             
163             RuntimeException JavaDoc e = new IllegalArgumentException JavaDoc();
164             UIException.annotateUser(e, null, msg, ex, null);
165             throw e;
166         }
167     }
168
169     /* Rename the data object.
170     * @param name new name for the object
171     * @exception IllegalArgumentException if the rename failed
172     */

173     public void setName (String JavaDoc name) {
174         setName (name, true);
175     }
176
177
178     /** Get the display name for the node.
179      * A filesystem may {@link org.openide.filesystems.FileSystem#getStatus specially alter} this.
180      * Subclassers overriding this method should consider the recommendations
181      * in {@link DataObject#createNodeDelegate}.
182      * @return the desired name
183     */

184     public String JavaDoc getDisplayName () {
185         String JavaDoc s = super.getDisplayName ();
186
187         try {
188             s = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateName (s, new LazyFilesSet());
189         } catch (FileStateInvalidException e) {
190             // no fs, do nothing
191
}
192
193         return s;
194     }
195
196      
197      /** Get a display name formatted using the limited HTML subset supported
198       * by <code>HtmlRenderer</code>. If the underlying
199       * <code>FileSystem.Status</code> is an instance of HmlStatus,
200       * this method will return non-null if status information is added.
201       *
202       * @return a string containing compliant HTML markup or null
203       * @see org.openide.awt.HtmlRenderer
204       * @see org.openide.nodes.Node#getHtmlDisplayName
205       * @since 4.13
206       */

207      public String JavaDoc getHtmlDisplayName() {
208          try {
209              FileSystem.Status stat =
210                  obj.getPrimaryFile().getFileSystem().getStatus();
211              if (stat instanceof FileSystem.HtmlStatus) {
212                  FileSystem.HtmlStatus hstat = (FileSystem.HtmlStatus) stat;
213                  
214                  String JavaDoc result = hstat.annotateNameHtml (
215                      super.getDisplayName(), new LazyFilesSet());
216                  
217                  //Make sure the super string was really modified
218
if (!super.getDisplayName().equals(result)) {
219                      return result;
220                  }
221              }
222          } catch (FileStateInvalidException e) {
223              //do nothing and fall through
224
}
225          return super.getHtmlDisplayName();
226      }
227
228     /** Get the displayed icon for this node.
229      * A filesystem may {@link org.openide.filesystems.FileSystem#getStatus specially alter} this.
230      * Subclassers overriding this method should consider the recommendations
231      * in {@link DataObject#createNodeDelegate}.
232      * @param type the icon type from {@link java.beans.BeanInfo}
233      * @return the desired icon
234     */

235     public java.awt.Image JavaDoc getIcon (int type) {
236         java.awt.Image JavaDoc img = super.getIcon (type);
237
238         try {
239             img = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateIcon (img, type, new LazyFilesSet());
240         } catch (FileStateInvalidException e) {
241             // no fs, do nothing
242
}
243
244         return img;
245     }
246
247     /** Get the displayed icon for this node.
248     * A filesystem may {@link org.openide.filesystems.FileSystem#getStatus specially alter} this.
249      * Subclassers overriding this method should consider the recommendations
250      * in {@link DataObject#createNodeDelegate}.
251     * @param type the icon type from {@link java.beans.BeanInfo}
252     * @return the desired icon
253     */

254     public java.awt.Image JavaDoc getOpenedIcon (int type) {
255         java.awt.Image JavaDoc img = super.getOpenedIcon(type);
256
257         try {
258             img = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateIcon (img, type, new LazyFilesSet());
259         } catch (FileStateInvalidException e) {
260             // no fs, do nothing
261
}
262
263         return img;
264     }
265     
266     public HelpCtx getHelpCtx () {
267         return obj.getHelpCtx ();
268     }
269
270     /** Indicate whether the node may be renamed.
271     * @return tests {@link DataObject#isRenameAllowed}
272     */

273     public boolean canRename () {
274         return obj.isRenameAllowed ();
275     }
276
277     /** Indicate whether the node may be destroyed.
278      * @return tests {@link DataObject#isDeleteAllowed}
279      */

280     public boolean canDestroy () {
281         return obj.isDeleteAllowed ();
282     }
283
284     /* Destroyes the node
285     */

286     public void destroy () throws IOException {
287         if (obj.isDeleteAllowed ()) {
288             obj.delete ();
289         }
290         super.destroy ();
291     }
292
293     /* Returns true if this object allows copying.
294     * @returns true if this object allows copying.
295     */

296     public boolean canCopy () {
297         return obj.isCopyAllowed ();
298     }
299
300     /* Returns true if this object allows cutting.
301     * @returns true if this object allows cutting.
302     */

303     public boolean canCut () {
304         return obj.isMoveAllowed ();
305     }
306
307     /** This method returns null to signal that actions
308     * provide by DataLoader.getActions should be returned from
309     * method getActions. If overriden to provide some actions,
310     * then these actions will be preferred to the loader's ones.
311     *
312     * @return null
313      * @deprecated Use {@link #getActions(boolean)} or do nothing and let the
314      * data loader specify actions.
315     */

316     @Deprecated JavaDoc
317     protected SystemAction[] createActions () {
318         return null;
319     }
320
321     /** Get actions for this data object.
322     * @see DataLoader#getActions
323     * @return array of actions or <code>null</code>
324     */

325     public Action JavaDoc[] getActions (boolean context) {
326         if (systemActions == null) {
327             systemActions = createActions ();
328         }
329
330         if (systemActions != null) {
331             return systemActions;
332         }
333
334         return obj.getLoader ().getSwingActions ();
335     }
336
337     /** Get actions for this data object.
338     * @deprecated Use getActions(boolean)
339     * @return array of actions or <code>null</code>
340     */

341     @Deprecated JavaDoc
342     public SystemAction[] getActions () {
343         if (systemActions == null) {
344             systemActions = createActions ();
345         }
346
347         if (systemActions != null) {
348             return systemActions;
349         }
350
351         return obj.getLoader ().getActions ();
352     }
353
354     
355     /** Get default action. In the current implementation the
356     *<code>null</code> is returned in case the underlying data
357     * object is a template. The templates should not have any default
358     * action.
359     * @return no action if the underlying data object is a template.
360     * Otherwise the abstract node's default action is returned, if <code>null</code> then
361     * the first action returned from getActions (false) method is used.
362     */

363     public Action JavaDoc getPreferredAction () {
364         if (obj.isTemplate ()) {
365             return null;
366         } else {
367             Action JavaDoc action = super.getPreferredAction ();
368             if (action != null) {
369                 return action;
370             }
371             Action JavaDoc[] arr = getActions(false);
372             if (arr != null && arr.length > 0) {
373                 return arr[0];
374             }
375             return null;
376         }
377     }
378
379     /** Get a cookie.
380      * First of all {@link DataObject#getCookie} is
381     * called. If it produces non-<code>null</code> result, that is returned.
382     * Otherwise the superclass is tried.
383     * Subclassers overriding this method should consider the recommendations
384     * in {@link DataObject#createNodeDelegate}. Since version 5.6, if
385     * non-null {@link Lookup} is passed to the constructor, then this
386     * method directly delegates to <a HREF="@org-openide-nodes@/org/openide/nodes/Node.html">super.getCookie</a> and does
387     * not query data object at all. This is supposed to provide consistency
388     * between results in <code>getLookup().lookup</code> and <code>getCookie</code>.
389     *
390     * @return the cookie or <code>null</code>
391     */

392     @Override JavaDoc
393     public <T extends Node.Cookie> T getCookie(Class JavaDoc<T> cl) {
394         if (ownLookup()) {
395             return super.getCookie(cl);
396         }
397         T c = obj.getCookie(cl);
398         if (c != null) {
399             return c;
400         } else {
401             return super.getCookie (cl);
402         }
403     }
404
405     /* Initializes sheet of properties. Allow subclasses to
406     * overwrite it.
407     * @return the default sheet to use
408     */

409     protected Sheet createSheet () {
410         Sheet s = Sheet.createDefault ();
411         Sheet.Set ss = s.get (Sheet.PROPERTIES);
412
413         Node.Property p;
414
415         p = createNameProperty (obj);
416         ss.put (p);
417
418         FileObject fo = getDataObject().getPrimaryFile();
419         if (couldBeTemplate(fo) && fo.canWrite()) {
420             try {
421                 p = new PropertySupport.Reflection<Boolean JavaDoc>(obj, Boolean.TYPE, "isTemplate", "setTemplate"); // NOI18N
422
p.setName(DataObject.PROP_TEMPLATE);
423                 p.setDisplayName(DataObject.getString("PROP_template"));
424                 p.setShortDescription(DataObject.getString("HINT_template"));
425                 ss.put(p);
426             } catch (Exception JavaDoc ex) {
427                 throw new InternalError JavaDoc();
428             }
429         }
430
431         if (fo.isData()) {
432             ss.put(new AllFilesProperty());
433             ss.put(new SizeProperty());
434             ss.put(new LastModifiedProperty());
435         }
436
437         return s;
438     }
439     
440     private static boolean couldBeTemplate(FileObject fo) {
441         FileSystem fs;
442         try {
443             fs = fo.getFileSystem();
444         } catch (FileStateInvalidException e) {
445             return false;
446         }
447         return fs.isDefault() && fo.getPath().startsWith("Templates/"); // NOI18N
448
}
449     
450     /**
451      * A property with a list of all contained files.
452      * Sorted to first show primary file, then all secondary files alphabetically.
453      * Shows absolute file path or the closest equivalent.
454      */

455     private final class AllFilesProperty extends PropertySupport.ReadOnly<String JavaDoc[]> {
456         
457         public AllFilesProperty() {
458             super(DataObject.PROP_FILES, String JavaDoc[].class,
459                   DataObject.getString("PROP_files"), DataObject.getString("HINT_files"));
460         }
461        
462         public String JavaDoc[] getValue() {
463             Set<FileObject> files = obj.files();
464             FileObject primary = obj.getPrimaryFile();
465             String JavaDoc[] res = new String JavaDoc[files.size()];
466             assert files.contains(primary);
467
468             int i=1;
469             for (Iterator<FileObject> it = files.iterator(); it.hasNext(); ) {
470                 FileObject next = it.next();
471                 res[next == primary ? 0 : i++] = name(next);
472             }
473             
474             Arrays.sort(res, 1, res.length);
475             return res;
476         }
477         
478         private String JavaDoc name(FileObject fo) {
479             return FileUtil.getFileDisplayName(fo);
480         }
481         
482     }
483     
484     private final class SizeProperty extends PropertySupport.ReadOnly<Long JavaDoc> {
485         
486         public SizeProperty() {
487             super("size", Long.TYPE, DataObject.getString("PROP_size"), DataObject.getString("HINT_size"));
488         }
489         
490         public Long JavaDoc getValue() {
491             return new Long JavaDoc(getDataObject().getPrimaryFile().getSize());
492         }
493         
494     }
495     
496     private final class LastModifiedProperty extends PropertySupport.ReadOnly<Date> {
497         
498         public LastModifiedProperty() {
499             super("lastModified", Date.class, DataObject.getString("PROP_lastModified"), DataObject.getString("HINT_lastModified"));
500         }
501         
502         public Date getValue() {
503             return getDataObject().getPrimaryFile().lastModified();
504         }
505         
506     }
507     
508     /** Copy this node to the clipboard.
509     *
510     * @return {@link org.openide.util.datatransfer.ExTransferable.Single} with one copy flavor
511     * @throws IOException if it could not copy
512     * @see org.openide.nodes.NodeTransfer
513     */

514     public Transferable clipboardCopy () throws IOException {
515         ExTransferable t = ExTransferable.create (super.clipboardCopy ());
516         t.put (LoaderTransfer.transferable (
517             getDataObject (),
518             LoaderTransfer.CLIPBOARD_COPY)
519         );
520         //add extra data flavors to allow dragging the file outside the IDE window
521
addExternalFileTransferable( t, getDataObject() );
522         return t;
523     }
524
525     /** Cut this node to the clipboard.
526     *
527     * @return {@link org.openide.util.datatransfer.ExTransferable.Single} with one cut flavor
528     * @throws IOException if it could not cut
529     * @see org.openide.nodes.NodeTransfer
530     */

531     public Transferable clipboardCut () throws IOException {
532         ExTransferable t = ExTransferable.create (super.clipboardCut ());
533         t.put (LoaderTransfer.transferable (
534             getDataObject (),
535             LoaderTransfer.CLIPBOARD_CUT)
536         );
537         //add extra data flavors to allow dragging the file outside the IDE window
538
addExternalFileTransferable( t, getDataObject() );
539         return t;
540     }
541     
542     private void addExternalFileTransferable( ExTransferable t, DataObject d ) {
543         FileObject fo = d.getPrimaryFile();
544         File file = FileUtil.toFile( fo );
545         if( null != file ) {
546             //windows & mac
547
final ArrayList<File> list = new ArrayList<File>(1);
548             list.add( file );
549             t.put( new ExTransferable.Single( DataFlavor.javaFileListFlavor ) {
550                 public Object JavaDoc getData() {
551                     return list;
552                 }
553             });
554             //linux
555
final String JavaDoc uriList = file.toURI().toString() + "\r\n";
556             t.put( new ExTransferable.Single( createUriListFlavor() ) {
557                 public Object JavaDoc getData() {
558                     return uriList;
559                 }
560             });
561         }
562     }
563
564     private DataFlavor createUriListFlavor () {
565         try {
566             return new DataFlavor("text/uri-list;class=java.lang.String");
567         } catch (ClassNotFoundException JavaDoc ex) {
568             //cannot happen
569
throw new AssertionError JavaDoc(ex);
570         }
571     }
572
573     /** Creates a name property for given data object.
574     */

575     static Node.Property createNameProperty (final DataObject obj) {
576         Node.Property p = new org.openide.nodes.PropertySupport.ReadWrite<String JavaDoc>(org.openide.loaders.DataObject.PROP_NAME,
577                                                         String JavaDoc.class,
578                                                         org.openide.loaders.DataObject.getString("PROP_name"),
579                                                         org.openide.loaders.DataObject.getString("HINT_name")) {
580
581             public String JavaDoc getValue() {
582                 return obj.getName();
583             }
584
585             public void setValue(String JavaDoc val) throws IllegalAccessException JavaDoc,
586                                                               IllegalArgumentException JavaDoc,
587                                                               java.lang.reflect.InvocationTargetException JavaDoc {
588                 if (!canWrite())
589                     throw new java.lang.IllegalAccessException JavaDoc();
590                 if (!(val instanceof java.lang.String JavaDoc))
591                     throw new java.lang.IllegalArgumentException JavaDoc();
592                 try {
593                     obj.rename((java.lang.String JavaDoc) val);
594                 }
595                 catch (java.io.IOException JavaDoc ex) {
596                     java.lang.String JavaDoc msg = null;
597
598                     if ((ex.getLocalizedMessage() == null) ||
599                         (ex.getLocalizedMessage().equals(ex.getMessage()))) {
600                         msg = org.openide.util.NbBundle.getMessage(org.openide.loaders.DataNode.class,
601                                                                    "MSG_renameError",
602                                                                    obj.getName(),
603                                                                    val);
604                     } else {
605                         msg = ex.getLocalizedMessage();
606                     }
607                     UIException.annotateUser(ex, null, msg, null, null);
608                     throw new java.lang.reflect.InvocationTargetException JavaDoc(ex);
609                 }
610             }
611
612             public boolean canWrite() {
613                 return obj.isRenameAllowed();
614             }
615             // #33296 - suppress custom editor
616

617             public Object JavaDoc getValue(String JavaDoc key) {
618                 if ("suppressCustomEditor".equals(key)) {
619                     return Boolean.TRUE;
620                 } else {
621                     return super.getValue(key);
622                 }
623             }
624         };
625
626         return p;
627     }
628     
629     /** Update files, if we are using CookieSet
630      */

631     private void updateFilesInCookieSet(Set<FileObject> obj) {
632         if (ownLookup()) {
633             return;
634         }
635         getCookieSet().assign(FileObject.class, obj.toArray(new FileObject[0]));
636     }
637
638     /** Support for firing property change.
639     * @param ev event describing the change
640     */

641     void fireChange(final PropertyChangeEvent ev) {
642         Mutex.EVENT.writeAccess(new Runnable JavaDoc() {
643             public void run() {
644
645                 if (DataFolder.PROP_CHILDREN.equals(ev.getPropertyName())) {
646                     // the node is not interested in children changes
647
return;
648                 }
649
650                 if (DataObject.PROP_PRIMARY_FILE.equals(ev.getPropertyName())) {
651                     propL.updateStatusListener();
652                     setName(obj.getName(), false);
653                     updateFilesInCookieSet(obj.files());
654                     return;
655                 }
656
657                 if (DataObject.PROP_FILES.equals(ev.getPropertyName())) {
658                     updateFilesInCookieSet(obj.files());
659                 }
660
661                 if (DataObject.PROP_NAME.equals(ev.getPropertyName())) {
662                     DataNode.super.setName(obj.getName());
663                     updateDisplayName();
664                 }
665                 if (DataObject.PROP_COOKIE.equals(ev.getPropertyName())) {
666                     fireCookieChange();
667                     //return;
668
}
669         
670                 // if the DataOjbect is not valid the node should be
671
// removed
672
if (DataObject.PROP_VALID.equals(ev.getPropertyName())) {
673                     Object JavaDoc newVal = ev.getNewValue();
674                     if ((newVal instanceof Boolean JavaDoc) && (!((Boolean JavaDoc) newVal).booleanValue())) {
675                         fireNodeDestroyed();
676                     }
677                     return;
678                 }
679                 
680                  /*See #31413*/
681                 List transmitProperties = Arrays.asList(new String JavaDoc[] {
682                     DataObject.PROP_NAME, DataObject.PROP_FILES, DataObject.PROP_TEMPLATE});
683                 if (transmitProperties.contains(ev.getPropertyName())) {
684                     firePropertyChange(ev.getPropertyName(), ev.getOldValue(), ev.getNewValue());
685                 }
686             }
687         });
688     }
689
690     /** Handle for location of given data object.
691     * @return handle that remembers the data object.
692     */

693     public Node.Handle getHandle () {
694         return new ObjectHandle(obj, obj.isValid() ? (this != obj.getNodeDelegate()) : /* to be safe */ true);
695     }
696
697     /** Access method to fire icon change.
698     */

699     final void fireChangeAccess (boolean icon, boolean name) {
700         if (name) {
701             fireDisplayNameChange (null, null);
702         }
703         if (icon) {
704             fireIconChange ();
705         }
706     }
707
708     /** Determine whether file extensions should be shown by default.
709     * By default, no.
710     * @return <code>true</code> if so
711     */

712     public static boolean getShowFileExtensions () {
713         return showFileExtensions;
714     }
715
716     /** Set whether file extensions should be shown by default.
717     * @param s <code>true</code> if so
718     */

719     public static void setShowFileExtensions (boolean s) {
720         boolean refresh = ( showFileExtensions != s );
721         showFileExtensions = s;
722         
723         if ( refresh ) {
724             // refresh current nodes display name
725
RequestProcessor.getDefault().post(new Runnable JavaDoc() {
726                 public void run () {
727                     Iterator it = DataObjectPool.getPOOL().getActiveDataObjects();
728                     while ( it.hasNext() ) {
729                         DataObject obj = ((DataObjectPool.Item)it.next()).getDataObjectOrNull();
730                         if ( obj != null && obj.getNodeDelegate() instanceof DataNode ) {
731                             ((DataNode)obj.getNodeDelegate()).updateDisplayName();
732                         }
733                     }
734                 }
735             }, 300, Thread.MIN_PRIORITY);
736         }
737         
738     }
739
740     private static Class JavaDoc defaultLookup;
741     /** Returns true if this node is using own lookup and not the standard one.
742      */

743     private boolean ownLookup() {
744         if (defaultLookup == null) {
745             try {
746                 defaultLookup = Class.forName("org.openide.nodes.NodeLookup", false, Node.class.getClassLoader());
747             } catch (ClassNotFoundException JavaDoc ex) {
748                 Exceptions.printStackTrace(ex);
749                 return false;
750             }
751         }
752         return !defaultLookup.isInstance(getLookup());
753     }
754     
755     /** Request processor task to update a bunch of names/icons.
756      * Potentially faster to do many nodes at once; see #16478.
757      */

758     private static RequestProcessor.Task refreshNamesIconsTask = null;
759     /** nodes which should be refreshed */
760     private static Set<DataNode> refreshNameNodes = null;
761     private static Set<DataNode> refreshIconNodes = null;
762     /** whether the task is current scheduled and will still look in above sets */
763     private static boolean refreshNamesIconsRunning = false;
764     private static final Object JavaDoc refreshNameIconLock = "DataNode.refreshNameIconLock"; // NOI18N
765

766     /** Property listener on data object that delegates all changes of
767     * properties to this node.
768     */

769     private class PropL extends Object JavaDoc
770     implements PropertyChangeListener, FileStatusListener, CookieSet.Before {
771         /** weak version of this listener */
772         private FileStatusListener weakL;
773         /** previous filesystem we were attached to */
774         private FileSystem previous;
775
776         public PropL () {
777             updateStatusListener ();
778         }
779
780         public void propertyChange (PropertyChangeEvent ev) {
781             fireChange (ev);
782         }
783
784         /** Updates listening on a status of filesystem.
785         */

786         private void updateStatusListener () {
787             if (previous != null) {
788                 previous.removeFileStatusListener (weakL);
789             }
790             try {
791                 previous = obj.getPrimaryFile ().getFileSystem ();
792
793                 if (weakL == null) {
794                     weakL = org.openide.filesystems.FileUtil.weakFileStatusListener (this, null);
795                 }
796
797                 previous.addFileStatusListener (weakL);
798             } catch (FileStateInvalidException ex) {
799                 previous = null;
800             }
801         }
802
803         /** Notifies listener about change in annotataion of a few files.
804         * @param ev event describing the change
805         */

806         public void annotationChanged (FileStatusEvent ev) {
807             // #16541: listen for changes in both primary and secondary files
808
boolean thisChanged = false;
809             Iterator it = obj.files().iterator();
810             while (it.hasNext()) {
811                 FileObject fo = (FileObject)it.next();
812                 if (ev.hasChanged(fo)) {
813                     thisChanged = true;
814                     break;
815                 }
816             }
817             if (thisChanged) {
818                 // #12368: fire display name & icon changes asynch
819
synchronized (refreshNameIconLock) {
820                     boolean post = false;
821                     if (ev.isNameChange()) {
822                         if (refreshNameNodes == null) {
823                             refreshNameNodes = new HashSet<DataNode>();
824                         }
825                         post |= refreshNameNodes.add(DataNode.this);
826                     }
827                     if (ev.isIconChange()) {
828                         if (refreshIconNodes == null) {
829                             refreshIconNodes = new HashSet<DataNode>();
830                         }
831                         post |= refreshIconNodes.add(DataNode.this);
832                     }
833                     if (post && !refreshNamesIconsRunning) {
834                         refreshNamesIconsRunning = true;
835                         if (refreshNamesIconsTask == null) {
836                             refreshNamesIconsTask = RequestProcessor.getDefault().post(new NamesUpdater());
837                         } else {
838                             // Should be OK even if it is running right now.
839
// (Cf. RequestProcessorTest.testScheduleWhileRunning.)
840
refreshNamesIconsTask.schedule(0);
841                         }
842                     }
843                 }
844             }
845         }
846
847         public void beforeLookup(Class JavaDoc<?> clazz) {
848             if (clazz.isAssignableFrom(FileObject.class)) {
849                 updateFilesInCookieSet(obj.files());
850             }
851         }
852     }
853             
854     private static class NamesUpdater implements Runnable JavaDoc {
855         /** Refreshes names and icons for a whole batch of data nodes at once.
856          */

857         public void run() {
858             DataNode[] _refreshNameNodes, _refreshIconNodes;
859             synchronized (refreshNameIconLock) {
860                 if (refreshNameNodes != null) {
861                     _refreshNameNodes = refreshNameNodes.toArray(new DataNode[refreshNameNodes.size()]);
862                     refreshNameNodes.clear();
863                 } else {
864                     _refreshNameNodes = new DataNode[0];
865                 }
866                 if (refreshIconNodes != null) {
867                     _refreshIconNodes = refreshIconNodes.toArray(new DataNode[refreshIconNodes.size()]);
868                     refreshIconNodes.clear();
869                 } else {
870                     _refreshIconNodes = new DataNode[0];
871                 }
872                 refreshNamesIconsRunning = false;
873             }
874             for (int i = 0; i < _refreshNameNodes.length; i++) {
875                 _refreshNameNodes[i].fireChangeAccess(false, true);
876             }
877             for (int i = 0; i < _refreshIconNodes.length; i++) {
878                 _refreshIconNodes[i].fireChangeAccess(true, false);
879             }
880         }
881         
882     }
883
884     /** Handle for data object nodes */
885     private static class ObjectHandle implements Node.Handle {
886         private FileObject obj;
887         private boolean clone;
888
889         static final long serialVersionUID =6616060729084681518L;
890
891
892         public ObjectHandle (DataObject obj, boolean clone) {
893             this.obj = obj.getPrimaryFile ();
894             this.clone = clone;
895         }
896
897         public Node getNode () throws IOException {
898             if (obj == null) {
899                 // Serialization problem? Seems to occur frequently with connection support:
900
// java.lang.IllegalArgumentException: Called DataObject.find on null
901
// at org.openide.loaders.DataObject.find(DataObject.java:435)
902
// at org.openide.loaders.DataNode$ObjectHandle.getNode(DataNode.java:757)
903
// at org.netbeans.modules.java.JavaDataObject$PersistentConnectionHandle.getNode(JavaDataObject.java:977)
904
// at org.openide.loaders.ConnectionSupport$Pair.getNode(ConnectionSupport.java:357)
905
// at org.openide.loaders.ConnectionSupport.register(ConnectionSupport.java:94)
906
// at org.netbeans.modules.java.codesync.SourceConnectionSupport.registerDependency(SourceConnectionSupport.java:475)
907
// at org.netbeans.modules.java.codesync.SourceConnectionSupport.addDependency(SourceConnectionSupport.java:554)
908
// at org.netbeans.modules.java.codesync.ClassDependencyImpl.supertypesAdded(ClassDependencyImpl.java:241)
909
// at org.netbeans.modules.java.codesync.ClassDependencyImpl.refreshClass(ClassDependencyImpl.java:121)
910
// at org.netbeans.modules.java.codesync.SourceConnectionSupport.refreshLinks(SourceConnectionSupport.java:357)
911
// at org.netbeans.modules.java.codesync.SourceConnectionSupport.access$000(SourceConnectionSupport.java:44)
912
// at org.netbeans.modules.java.codesync.SourceConnectionSupport$2.run(SourceConnectionSupport.java:223)
913
throw new IOException("File could not be restored"); // NOI18N
914
}
915             Node n = DataObject.find (obj).getNodeDelegate ();
916             return clone ? n.cloneNode () : n;
917         }
918     }
919     
920     /** Wrapping class for obj.files(). Used in getIcon() and getDisplayName()
921         to have something lazy to pass to annotateIcon() and annotateName()
922         instead of calling obj.files() immediately. */

923     private class LazyFilesSet implements Set<FileObject> {
924         
925         private Set<FileObject> obj_files;
926         
927         synchronized private void lazyInitialization () {
928            obj_files = obj.files();
929         }
930         
931         public boolean add(FileObject o) {
932             lazyInitialization();
933             return obj_files.add(o);
934         }
935         
936         public boolean addAll(Collection<? extends FileObject> c) {
937             lazyInitialization();
938             return obj_files.addAll(c);
939         }
940         
941         public void clear() {
942             lazyInitialization();
943             obj_files.clear();
944         }
945         
946         public boolean contains(Object JavaDoc o) {
947             lazyInitialization();
948             return obj_files.contains(o);
949         }
950         
951         public boolean containsAll(Collection c) {
952             lazyInitialization();
953             return obj_files.containsAll(c);
954         }
955         
956         public boolean isEmpty() {
957             lazyInitialization();
958             return obj_files.isEmpty();
959         }
960         
961         public Iterator<FileObject> iterator() {
962             return new FilesIterator ();
963         }
964         
965         public boolean remove(Object JavaDoc o) {
966             lazyInitialization();
967             return obj_files.remove(o);
968         }
969         
970         public boolean removeAll(Collection c) {
971             lazyInitialization();
972             return obj_files.removeAll(c);
973         }
974         
975         public boolean retainAll(Collection c) {
976             lazyInitialization();
977             return obj_files.retainAll(c);
978         }
979         
980         public int size() {
981             lazyInitialization();
982             return obj_files.size();
983         }
984         
985         public Object JavaDoc[] toArray() {
986             lazyInitialization();
987             return obj_files.toArray();
988         }
989         
990         public <FileObject> FileObject[] toArray(FileObject[] a) {
991             lazyInitialization();
992             return obj_files.toArray(a);
993         }
994
995         public boolean equals(Object JavaDoc obj) {
996             lazyInitialization();
997             return obj_files.equals(obj);
998         }
999
1000        public String JavaDoc toString() {
1001            lazyInitialization();
1002            return obj_files.toString();
1003        }
1004
1005        public int hashCode() {
1006            lazyInitialization();
1007            return obj_files.hashCode();
1008        }
1009        
1010        /** Iterator for FilesSet. It returns the primaryFile first and
1011         * then initialize the delegate iterator for secondary files.
1012         */

1013        private final class FilesIterator implements Iterator<FileObject> {
1014            /** Was the first element (primary file) already returned?
1015             */

1016            private boolean first = true;
1017
1018            /** Delegation iterator for secondary files. It is lazy initialized after
1019             * the first element is returned.
1020             */

1021            private Iterator<FileObject> itDelegate = null;
1022
1023            FilesIterator() {}
1024
1025            public boolean hasNext() {
1026                return first ? true : getIteratorDelegate().hasNext();
1027            }
1028
1029            public FileObject next() {
1030                if (first) {
1031                    first = false;
1032                    return obj.getPrimaryFile ();
1033                }
1034                else {
1035                    return getIteratorDelegate().next();
1036                }
1037            }
1038
1039            public void remove() {
1040                getIteratorDelegate().remove();
1041            }
1042
1043            /** Initialize the delegation iterator.
1044             */

1045            private Iterator<FileObject> getIteratorDelegate() {
1046                if (itDelegate == null) {
1047                    lazyInitialization ();
1048                    // this should return iterator of all files of the MultiDataObject...
1049
itDelegate = obj_files.iterator ();
1050                    // ..., so it is necessary to skip the primary file
1051
itDelegate.next();
1052                }
1053                return itDelegate;
1054            }
1055        }
1056    }
1057    
1058    
1059    
1060}
1061
Popular Tags