Index: src/org/netbeans/modules/masterfs/MasterFileSystem.java =================================================================== RCS file: /cvs/openide/masterfs/src/org/netbeans/modules/masterfs/MasterFileSystem.java,v retrieving revision 1.17 diff -u -r1.17 MasterFileSystem.java --- src/org/netbeans/modules/masterfs/MasterFileSystem.java 7 Oct 2004 12:50:41 -0000 1.17 +++ src/org/netbeans/modules/masterfs/MasterFileSystem.java 2 Feb 2005 17:47:47 -0000 @@ -14,6 +14,7 @@ package org.netbeans.modules.masterfs; +import org.netbeans.modules.masterfs.providers.AnnotationProvider; import org.openide.filesystems.*; import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; @@ -213,6 +214,11 @@ } public SystemAction[] getActions(java.util.Set foSet) { + SystemAction[] some = status.getActions (foSet); + if (some != null) { + return some; + } + SyncSection.getDefault().enterSection(); try { //check if all fileobjects come from the same filesystem @@ -312,7 +318,81 @@ } - private static final class StatusImpl implements FileSystem.HtmlStatus { + private static final class StatusImpl implements FileSystem.HtmlStatus, + org.openide.util.LookupListener, org.openide.filesystems.FileStatusListener { + /** result with providers */ + private org.openide.util.Lookup.Result annotationProviders; + private Collection previousProviders; + { + annotationProviders = org.openide.util.Lookup.getDefault ().lookup ( + new org.openide.util.Lookup.Template (AnnotationProvider.class) + ); + annotationProviders.addLookupListener (this); + resultChanged (null); + } + + public void resultChanged (org.openide.util.LookupEvent ev) { + java.util.Collection now = annotationProviders.allInstances (); + java.util.Collection add; + + if (previousProviders != null) { + add = new HashSet (now); + add.removeAll (previousProviders); + + previousProviders.removeAll (now); + java.util.Iterator it = previousProviders.iterator (); + while (it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + ap.removeFileStatusListener (this); + } + + } else { + add = now; + } + + + + java.util.Iterator it = add.iterator (); + while (it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + try { + ap.addFileStatusListener (this); + } catch (java.util.TooManyListenersException ex) { + org.openide.ErrorManager.getDefault ().notify (ex); + } + } + + previousProviders = now; + } + + public SystemAction[] getActions(java.util.Set foSet) { + + javax.swing.Action[] retVal = null; + java.util.Iterator it = annotationProviders.allInstances ().iterator (); + while (retVal == null && it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + retVal = ap.actions (foSet); + } + if (retVal != null) { + // right now we handle just SystemAction, it can be changed if necessary + SystemAction[] ret = new SystemAction[retVal.length]; + for (int i = 0; i < retVal.length; i++) { + if (retVal[i] instanceof SystemAction) { + ret[i] = (SystemAction)retVal[i]; + } + } + return ret; + } + return null; + } + + public void annotationChanged (org.openide.filesystems.FileStatusEvent ev) { + if (ev.getSource () != MasterFileSystem.getDefault ()) { + throw new IllegalStateException ("The source must be master fs and not : " + ev.getSource ()); // NOI18N + } + MasterFileSystem.getDefault ().fireFileStatusChanged (ev); + } + private FileSystem getDelegateFileSystem (Set files) { FileSystem retVal = null; Iterator it = files.iterator(); @@ -325,7 +405,19 @@ } public Image annotateIcon(Image icon, int iconType, Set files) { - Image retVal = icon; + Image retVal = null; + + Iterator it = annotationProviders.allInstances ().iterator (); + while (retVal == null && it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + retVal = ap.annotateIcon (icon, iconType, files); + } + if (retVal != null) { + return retVal; + } + + + retVal = icon; FileSystem fs = getDelegateFileSystem(files); if (fs != null) { Set transformedSet = new LazySet (files); @@ -336,7 +428,17 @@ } public String annotateName(String name, Set files) { - String retVal = name; + String retVal = null; + Iterator it = annotationProviders.allInstances ().iterator (); + while (retVal == null && it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + retVal = ap.annotateName (name, files); + } + if (retVal != null) { + return retVal; + } + retVal = name; + Set transformedSet = new LazySet (files); FileSystem fs = getDelegateFileSystem(files); if (fs != null) { @@ -346,7 +448,17 @@ } public String annotateNameHtml(String name, Set files) { - String retVal = name; + String retVal = null; + Iterator it = annotationProviders.allInstances ().iterator (); + while (retVal == null && it.hasNext ()) { + AnnotationProvider ap = (AnnotationProvider)it.next (); + retVal = ap.annotateNameHtml (name, files); + } + if (retVal != null) { + return retVal; + } + retVal = name; + FileSystem fs = getDelegateFileSystem(files); if (fs != null) { if (fs != null && fs.getStatus() instanceof FileSystem.HtmlStatus) { Index: src/org/netbeans/modules/masterfs/providers/AnnotationProvider.java =================================================================== RCS file: src/org/netbeans/modules/masterfs/providers/AnnotationProvider.java diff -N src/org/netbeans/modules/masterfs/providers/AnnotationProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/netbeans/modules/masterfs/providers/AnnotationProvider.java 2 Feb 2005 17:47:47 -0000 @@ -0,0 +1,121 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.masterfs.providers; + +import java.io.IOException; + +/** Can provide status and actions for FileObjects. Register it + * in META-INF/services/org.netbeans.modules.masterfs.providers.AnnotationProvider + * file. + * + * @author Jaroslav Tulach + */ +public abstract class AnnotationProvider extends Object { + /** listeners */ + private org.openide.filesystems.FileStatusListener listener; + /** lock for modification of listeners */ + private static Object LOCK = new Object (); + + + /** Annotate the name of a file cluster. + * @param name the name suggested by default + * @param files an immutable set of {@link FileObject}s belonging to this filesystem + * @return the annotated name or null if this provider does not know how to annotate these files + */ + public abstract String annotateName (String name, java.util.Set files); + + /** Annotate the icon of a file cluster. + *
Please do not modify the original; create a derivative icon image,
+ * using a weak-reference cache if necessary.
+ * @param icon the icon suggested by default
+ * @param iconType an icon type from {@link java.beans.BeanInfo}
+ * @param files an immutable set of {@link FileObject}s belonging to this filesystem
+ * @return the annotated icon or null if some other provider shall anotate the icon
+ */
+ public abstract java.awt.Image annotateIcon (java.awt.Image icon, int iconType, java.util.Set files);
+
+ /** Annotate a name such that the returned value contains HTML markup.
+ * The return value less the html content should typically be the same
+ * as the return value from annotateName()
. This is used,
+ * for example, by VCS filesystems to deëphasize the status information
+ * included in the file name by using a light grey font color.
+ *
+ * For consistency with Node.getHtmlDisplayName()
,
+ * filesystems that proxy other filesystems (and so must implement
+ * this interface to supply HTML annotations) should return null if
+ * the filesystem they proxy does not provide an implementation of
+ * HTMLStatus.
+ *
+ * @see org.openide.awt.HtmlRenderer
+ * @see DataNode.getHtmlDisplayName()
+ * @see org.openide.nodes.Node#getHtmlDisplayName
+ **/
+ public abstract String annotateNameHtml (String name, java.util.Set files);
+
+ /** Provides actions that should be added to given set of files.
+ * @return null or array of actions for these files.
+ */
+ public abstract javax.swing.Action[] actions (java.util.Set files);
+
+ //
+ // Listener support
+ //
+
+
+ /** Registers FileStatusListener to receive events.
+ * The implementation registers the listener only when getStatus () is
+ * overriden to return a special value.
+ *
+ * @param listener The listener to register.
+ */
+ public final void addFileStatusListener (
+ org.openide.filesystems.FileStatusListener listener
+ ) throws java.util.TooManyListenersException {
+ synchronized (LOCK) {
+ if (this.listener != null) {
+ throw new java.util.TooManyListenersException ();
+ }
+ this.listener = listener;
+ }
+ }
+
+ /** Removes FileStatusListener from the list of listeners.
+ *@param listener The listener to remove.
+ */
+ public final void removeFileStatusListener (
+ org.openide.filesystems.FileStatusListener listener
+ ) {
+ synchronized (LOCK) {
+ if (this.listener == listener) {
+ this.listener = null;
+ }
+ }
+ }
+
+ /** Notifies all registered listeners about change of status of some files.
+ *
+ * @param event The event to be fired
+ */
+ protected final void fireFileStatusChanged(org.openide.filesystems.FileStatusEvent event) {
+ org.openide.filesystems.FileStatusListener l;
+ synchronized (LOCK) {
+ l = this.listener;
+ }
+ if (l != null) {
+ l.annotationChanged (event);
+ }
+ }
+}
+
+
Index: test/unit/src/org/netbeans/modules/masterfs/providers/AnnotationProviderTest.java
===================================================================
RCS file: test/unit/src/org/netbeans/modules/masterfs/providers/AnnotationProviderTest.java
diff -N test/unit/src/org/netbeans/modules/masterfs/providers/AnnotationProviderTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/netbeans/modules/masterfs/providers/AnnotationProviderTest.java 2 Feb 2005 17:47:47 -0000
@@ -0,0 +1,288 @@
+/*
+ * Sun Public License Notice
+ *
+ * The contents of this file are subject to the Sun Public License
+ * Version 1.0 (the "License"). You may not use this file except in
+ * compliance with the License. A copy of the License is available at
+ * http://www.sun.com/
+ *
+ * The Original Code is NetBeans. The Initial Developer of the Original
+ * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ */
+
+package org.netbeans.modules.masterfs.providers;
+
+import junit.framework.*;
+import java.io.IOException;
+
+/** Check the behaviour of masterfs's annation provider.
+ *
+ * @author Jaroslav Tulach
+ */
+public class AnnotationProviderTest extends org.netbeans.junit.NbTestCase {
+ private AnnoProv a1, a2, a3, a4;
+
+ private org.openide.filesystems.FileSystem fs;
+ private org.openide.filesystems.FileObject fo;
+
+ public AnnotationProviderTest (String testName) {
+ super (testName);
+ }
+
+ static {
+ System.setProperty ("org.openide.util.Lookup", "org.netbeans.modules.masterfs.providers.AnnotationProviderTest$Lkp"); // NOI18N
+ }
+
+ // TODO add test methods here. The name must begin with 'test'. For example:
+ // public void testHello() {}
+
+ protected void setUp () throws java.lang.Exception {
+ assertEquals (Lkp.class, org.openide.util.Lookup.getDefault ().getClass ());
+
+ // we need some masterfs fileobject
+ fs = org.netbeans.modules.masterfs.MasterFileSystem.settingsFactory (null);
+ fo = fs.getRoot ();
+ assertEquals (org.netbeans.modules.masterfs.MasterFileSystem.class, fo.getFileSystem ().getClass ());
+
+
+ a1 = new AnnoProv ();
+ a2 = new AnnoProv ();
+ a3 = new AnnoProv ();
+ a4 = new AnnoProv ();
+
+ Lkp.ic.add (a1);
+ Lkp.ic.add (a2);
+ Lkp.ic.add (a3);
+ Lkp.ic.add (a4);
+ }
+
+ protected void tearDown () throws java.lang.Exception {
+ Lkp.ic.remove (a1);
+ Lkp.ic.remove (a2);
+ Lkp.ic.remove (a3);
+ Lkp.ic.remove (a4);
+ }
+
+ public static junit.framework.Test suite () {
+ junit.framework.TestSuite suite = new junit.framework.TestSuite(AnnotationProviderTest.class);
+
+ return suite;
+ }
+
+ public void testAnnotateName () {
+
+ a2.returnName = "MyName";
+
+ String r = fs.getStatus ().annotateName ("Kuk", java.util.Collections.singleton (fo));
+
+ assertEquals ("My name returned", a2.returnName, r);
+ assertEquals ("Kuk", a1.queriedName);
+ assertEquals ("Kuk", a2.queriedName);
+ assertNull ("Not queried at all", a3.queriedName);
+ assertNull ("Not queried at all", a4.queriedName);
+
+ assertTrue ("fo is the file", a1.filesName.contains (fo));
+ assertTrue ("fo is the file", a2.filesName.contains (fo));
+
+ assertNull (a1.filesActions);
+ assertNull (a1.filesHtml);
+ assertNull (a1.filesIcon);
+
+ assertNull (a2.filesActions);
+ assertNull (a2.filesHtml);
+ assertNull (a2.filesIcon);
+ }
+
+ public void testAnnotateIcon () {
+
+ int t = java.awt.image.BufferedImage.TYPE_BYTE_GRAY;
+ java.awt.image.BufferedImage my = new java.awt.image.BufferedImage (10, 10, t);
+ java.awt.image.BufferedImage his = new java.awt.image.BufferedImage (20, 20, t);
+ a2.returnIcon = his;
+
+ java.awt.Image r = fs.getStatus ().annotateIcon (my, 0, java.util.Collections.singleton (fo));
+
+ assertEquals ("My name returned", his, r);
+ assertSame (my, a1.queriedIcon);
+ assertSame (my, a2.queriedIcon);
+ assertNull ("Not queried at all", a3.queriedIcon);
+ assertNull ("Not queried at all", a4.queriedIcon);
+
+
+ assertNull (a1.filesActions);
+ assertNull (a1.filesHtml);
+ assertNull (a1.filesName);
+
+ assertNull (a2.filesActions);
+ assertNull (a2.filesHtml);
+ assertNull (a2.filesName);
+ }
+
+ public void testAnnotateNameHtml () {
+
+ a2.returnHtml = "MyName";
+
+ Object o = fs.getStatus ();
+ assertTrue ("Must be HtmlStatus", o instanceof org.openide.filesystems.FileSystem.HtmlStatus);
+ org.openide.filesystems.FileSystem.HtmlStatus status = (org.openide.filesystems.FileSystem.HtmlStatus)o;
+
+
+
+ String r = status.annotateNameHtml ("Kuk", java.util.Collections.singleton (fo));
+
+ assertEquals ("My name returned", a2.returnHtml, r);
+ assertEquals ("Kuk", a1.queriedHtml);
+ assertEquals ("Kuk", a2.queriedHtml);
+ assertNull ("Not queried at all", a3.queriedHtml);
+ assertNull ("Not queried at all", a4.queriedHtml);
+
+ assertTrue ("fo is the file", a1.filesHtml.contains (fo));
+ assertTrue ("fo is the file", a2.filesHtml.contains (fo));
+
+ assertNull (a1.filesActions);
+ assertNull (a1.filesName);
+ assertNull (a1.filesIcon);
+
+ assertNull (a2.filesActions);
+ assertNull (a2.filesName);
+ assertNull (a2.filesIcon);
+ }
+
+ public void testActionsWorksOnSystemActionsCorrectly () {
+
+ a2.returnActions = new javax.swing.Action[] {
+ org.openide.actions.OpenAction.get (org.openide.actions.OpenAction.class)
+ };
+
+ java.util.Set s = java.util.Collections.singleton (fo);
+ javax.swing.Action[] actions = fs.getActions (s);
+
+ assertEquals ("Actions has the same size", a2.returnActions.length, actions.length);
+ assertEquals ("And that is one", 1, actions.length);
+ assertEquals ("First elem is same", a2.returnActions[0], actions[0]);
+ assertEquals ("a1 queried", s, a1.filesActions);
+ assertEquals ("a2 queried", s, a2.filesActions);
+ assertNull ("Not queried at all", a3.filesActions);
+ assertNull ("Not queried at all", a4.filesActions);
+
+ assertNull (a1.filesHtml);
+ assertNull (a1.filesName);
+ assertNull (a1.filesIcon);
+
+ assertNull (a2.filesHtml);
+ assertNull (a2.filesName);
+ assertNull (a2.filesIcon);
+ }
+
+ public void testListeningCapabilities () {
+ class L implements org.openide.filesystems.FileStatusListener {
+ public org.openide.filesystems.FileStatusEvent ev;
+
+ public void annotationChanged (org.openide.filesystems.FileStatusEvent ev) {
+ assertNull (this.ev);
+ this.ev = ev;
+ }
+ }
+ L l = new L ();
+
+ try {
+ fs.addFileStatusListener (l);
+
+ a2.returnName = "xyz";
+ String r = fs.getStatus().annotateName ("my name", java.util.Collections.singleton (fo));
+ assertEquals (r, a2.returnName);
+
+ org.openide.filesystems.FileStatusEvent ev;
+ ev = new org.openide.filesystems.FileStatusEvent (fs, false, true);
+ a3.fireFileStatusChanged (ev);
+
+ assertEquals ("Our listener was called", ev, l.ev);
+ l.ev = null;
+ Lkp.ic.remove (a3);
+
+ a3.fireFileStatusChanged (ev);
+ assertNull ("Now our listener was not called", l.ev);
+
+ } finally {
+ fs.removeFileStatusListener (l);
+ }
+ }
+
+ private class AnnotationProviderImpl extends AnnotationProvider {
+
+ public java.lang.String annotateName (java.lang.String name, java.util.Set files) {
+ return null;
+ }
+
+ public java.awt.Image annotateIcon (java.awt.Image icon, int iconType, java.util.Set files) {
+ return null;
+ }
+
+ public java.lang.String annotateNameHtml (java.lang.String name, java.util.Set files) {
+ return null;
+ }
+
+ public javax.swing.Action[] actions (java.util.Set files) {
+ return null;
+ }
+ }
+
+
+ public static final class Lkp extends org.openide.util.lookup.AbstractLookup {
+ static org.openide.util.lookup.InstanceContent ic;
+
+ public Lkp () {
+ this (new org.openide.util.lookup.InstanceContent ());
+ }
+
+ private Lkp (org.openide.util.lookup.InstanceContent ic) {
+ super (ic);
+ this.ic = ic;
+ }
+ } // end of Lkp
+
+ static final class AnnoProv extends AnnotationProvider {
+ public String returnHtml;
+ public String returnName;
+ public java.awt.Image returnIcon;
+ public javax.swing.Action[] returnActions;
+
+ public String queriedHtml;
+ public String queriedName;
+ public java.awt.Image queriedIcon;
+
+ public java.util.Set filesHtml;
+ public java.util.Set filesName;
+ public java.util.Set filesIcon;
+ public java.util.Set filesActions;
+
+ public String annotateNameHtml (String name, java.util.Set files) {
+ assertNull (queriedHtml);
+ queriedHtml = name;
+ filesHtml = files;
+ return returnHtml;
+ }
+
+ public String annotateName (String name, java.util.Set files) {
+ assertNull (queriedName);
+ queriedName = name;
+ filesName = files;
+ return returnName;
+ }
+
+ public java.awt.Image annotateIcon (java.awt.Image icon, int iconType, java.util.Set files) {
+ assertNull (queriedIcon);
+ queriedIcon = icon;
+ filesIcon = files;
+ return returnIcon;
+ }
+
+ public javax.swing.Action[] actions (java.util.Set files) {
+ assertNull (filesActions);
+ filesActions = files;
+ return returnActions;
+ }
+
+ }
+}