@NodeFactory.Registration

Following on from yesterday's blog entry, about the @AntBasedProjectRegistration annotation, let's now add a logical view for our project type, making use of the new @NodeFactory.Registration annotation in the process. That's a new 6.7 annotation that you use to add nodes to a logical view. Your default logical view does not need to have any nodes itself, other than the root node.

Here's a simple LogicalViewProvider:

import java.awt.Image;
import javax.swing.Action;
import org.netbeans.spi.project.ui.LogicalViewProvider;
import org.netbeans.spi.project.ui.support.CommonProjectActions;
import org.netbeans.spi.project.ui.support.NodeFactorySupport;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Node;
import org.openide.util.ImageUtilities;

class DemoProjectLogicalView implements LogicalViewProvider {

    private final DemoProject project;

    public DemoProjectLogicalView(DemoProject project) {
        this.project = project;
    }

    @Override
    public Node createLogicalView() {
        return new RootNode(project);
    }

    private static final class RootNode extends AbstractNode {
        
        public static final String DEMO_PROJECT_ICON_PATH =
                "org/netbeans/demo/project/icon.png";

        public static final String REGISTERED_NODE_LOCATION =
                "Projects/org-netbeans-demo-project-DemoProject/Nodes";

        final DemoProject project;

        public RootNode(DemoProject project) {
            super(NodeFactorySupport.createCompositeChildren
                    (project, REGISTERED_NODE_LOCATION));
            this.project = project;
            setIconBaseWithExtension(DEMO_PROJECT_ICON_PATH);
        }

        @Override
        public Action[] getActions(boolean arg0) {
            Action[] nodeActions = new Action[7];
            nodeActions[0] = CommonProjectActions.newFileAction();
            nodeActions[1] = CommonProjectActions.copyProjectAction();
            nodeActions[2] = CommonProjectActions.deleteProjectAction();
            nodeActions[5] = CommonProjectActions.setAsMainProjectAction();
            nodeActions[6] = CommonProjectActions.closeProjectAction();
            return nodeActions;
        }

        @Override
        public Image getIcon(int type) {
            return ImageUtilities.loadImage(DEMO_PROJECT_ICON_PATH);
        }

        @Override
        public Image getOpenedIcon(int type) {
            return getIcon(type);
        }

        @Override
        public String getDisplayName() {
            return project.getProjectDirectory().getName();
        }
    }

    @Override
    public Node findPath(Node root, Object target) {
        //leave unimplemented for now
        return null;
    }

}

Note: After defining the above, you need to add the DemoProjectLogicalView to the Lookup of the DemoProject. I.e., in the DemoProject's Lookup, instantiate the DemoProjectLogicalView and pass in "this", which is the DemoProject:

@Override
public Lookup getLookup() {
    return Lookups.fixed(new Object[]{
        new Info(),
        new DemoProjectLogicalView(this)
    });
}

What's interesting in the DemoProjectLogicalView, defined above, are the lines highlighted in bold. They specify that the children of the root node must be retrieved from the "Projects/org-netbeans-demo-project-DemoProject/Nodes" folder. In the past, i.e., prior to 6.7, that could only be a reference to a folder in the layer.xml file, as described in the section "Registering the New Extensions" in the NetBeans Project Type Extension Module Tutorial.

Now, however, you simply need an annotation (highlighted in bold in the code below)! Forget the whole layer.xml file, some more. Here's a simplistic NodeFactory, that registers itself as an extension to the DemoProject type, using the type that was defined in the @AntBasedProjectRegistration shown yesterday:

import org.netbeans.api.project.Project;
import org.netbeans.spi.project.ui.support.NodeFactory;
import org.netbeans.spi.project.ui.support.NodeFactorySupport;
import org.netbeans.spi.project.ui.support.NodeList;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;

@NodeFactory.Registration(projectType="org-netbeans-demo-project-DemoProject", position=200)
public class DemoNodeFactory implements NodeFactory {

    public DemoNodeFactory() {
    }

    @Override
    public NodeList createNodes(Project arg0) {

        AbstractNode nd = new AbstractNode(Children.LEAF);
        nd.setDisplayName("Hello World!");
        return NodeFactorySupport.fixedNodeList(nd);

    }

}

For a more realistic example of a NodeFactory, see the NetBeans Project Type Extension Module Tutorial. In the above rather trivial example, you'd end up with a logical view like this:

...while the Files window continues to show the file structure on disk:

Also, thanks to the @NodeFactory.Registration annotation, ANYONE can extend my project type. So, let's say the application (whatever it is, insurance application, oil flow application, etc) is now out in the field and being used by customers. One of them thinks, "Hmmm. Would be cool if the project type had a few additional nodes in the logical view." All they'd need to do would be to create a new module, define a NodeFactory, register it to the project type via the @NodeFactory.Registration annotation, build the NBM and deliver it to other customers... without needing to have access to the sources of the DemoProject! The only required info is the type of the project and then you can use that to register the NodeFactory via the annotation. In other words, this particular annotation enables a project type to be pluggable. Pretty cool.

Now, let's add the DemoProject to the root node's Lookup:

public RootNode(DemoProject project) {
    super(NodeFactorySupport.createCompositeChildren
            (project, REGISTERED_NODE_LOCATION), Lookups.singleton(project));
    this.project = project;
    setIconBaseWithExtension(DEMO_PROJECT_ICON_PATH);
}

That results in some of the items being enabled when you right-click the project in the logical view:

Plus, the highlighted items do exactly what you'd expect.

Comments:

Well, anybody could extend your project type before, as well, by providing their own layer.xml file.

Posted by Rich Unger on May 05, 2009 at 11:47 PM PDT #

Right, except that now it's done via annotations.

Posted by Geertjan on May 06, 2009 at 06:50 PM PDT #

(Although the layer.xml approach is still supported.)

Posted by Geertjan on May 06, 2009 at 06:50 PM PDT #

Hello! Can you help me.
I have my class FactoryNodesInstance implements NodeFactory, and I have a special structure List<MyModels>, so I want to update project tree with my nodes. I have register FactoryNodesInstance in layer.xml. The first time it works and I can see nodes, but when some changes were made in List<MyModels>, I don't know how to call in class FactoryNodesInstance method node to refresh nodes?
Thank you.

Posted by venic on July 06, 2009 at 09:58 PM PDT #

Hi Gj

These tutorials are very helpful for creating new projecttypes. One thing am struggling to do is to add the source folder and my own jars to the classpath when the project is opened but I'm not getting anywhere. I have been looking in the java.j2seproject module for ideas especially J2SEProject.java

One very typicall use of this is to create project types for your company that will have project dependencies and everything added to the classpath.

Regards

Posted by Farouk Alhassan on July 26, 2010 at 04:11 PM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today