corner imagecorner image FeaturesPluginsDocs & SupportCommunityPartners


NetBeans Project Type Module Tutorial

This tutorial demonstrates how to create a new project type.

If the projects for which you're creating a project type need to use Ant as their build tool, you should use the NetBeans Ant-Based Project Type Module Tutorial instead.

Contents

Content on this page applies to NetBeans IDE 6.7

To follow this tutorial, you need the software and resources listed in the following table.

Software or Resource Version Required
NetBeans IDE version 6.7
Java Developer Kit (JDK) Version 6 or
version 5

You will also make use of these two icons, which you can right-click here and download:

Optionally, for troubleshooting purposes, you can download the completed sample and inspect the sources.

Introduction to Project Types

A project type is a NetBeans Platform term for a grouping of folders and files that is treated as a single unit. Treating related folders and files as a single unit makes working with them easier for the end user. One way in which a project type simplifies life for the user is that you are able to fill the Projects window only with those folders and files that the end user is most likely to work.

For example, the Java project type in NetBeans IDE helps the end user to work with the folders and files belonging to a single Java application. As you can see below, the folders and files the end user most needs to work with are shown in the Projects window:

installed result

In this tutorial, we will create a project type that will look as follows in the Projects window:

installed result

Our project type will be defined by the existence of a subfolder named "texts". If a folder contains a subfolder with that name, the NetBeans Platform will recognize it as a project type. The user will be able to open the project into a NetBeans Platform application and the content of the "texts" folder will be displayed in the Projects window.

We will also have menu items that are specific to our new project type:

installed result

The following are the main NetBeans API classes we will be implementing in this tutorial:
Class Description
org.netbeans.spi.project.ProjectFactory Determines when a folder or file is a valid project and then creates the implemention of org.netbeans.api.project.Project.
org.netbeans.api.project.Project Represents the project.
org.netbeans.spi.project.ui.LogicalViewProvider Provides the logical view for the project.
org.netbeans.api.project.ProjectInformation Provides supplemental information for the project.
org.netbeans.spi.project.ActionProvider Provides one or more actions for the project.
org.netbeans.spi.project.CopyOperationImplementation Provides the Copy operation for the project.
org.netbeans.spi.project.DeleteOperationImplementation Provides the Delete operation for the project.

At the end of this tutorial, your module source structure will be as follows:

New Sample

Creating the Module Project

We begin by working through the New Module Project wizard. At the end of it, we will have a basic source structure, with some default files, that every NetBeans module requires.

  1. Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select Module. Click Next.
  2. In the Name and Location panel, type DemoProjectType in the Project Name field. Change the Project Location to any directory on your computer. Leave the Standalone Module option and Set as Main Project checkbox selected. Click Next.
  3. In the Basic Module Configuration panel, type org.netbeans.demo.project in Code Name Base.
  4. Do not select "Generate XML Layer", since our module will not need a layer.xml file. Leave the location of the localizing bundle so that it will be stored in a package with the name org/netbeans/demo/project. Click Finish.

The IDE creates the DemoProjectType project. The project contains all of your sources and project metadata, such as the project's Ant build script. The project opens in the IDE. You can view its logical structure in the Projects window (Ctrl-1) and its file structure in the Files window (Ctrl-2).

Setting Dependencies

We will need to make use of several NetBeans APIs. In this step, we select the modules that provide the NetBeans APIs that we will need.

  1. Right-click the project node and choose Properties. The Project Properties dialog box opens.
  2. In the Libraries panel, add dependencies on the following modules:
    • Datasystems API
    • Dialogs API
    • File System API
    • Module System API
    • Nodes API
    • Project API
    • Project UI API
    • UI Utilities API
    • Utilities API

  3. Expand the module's Libraries node in the Projects window and make sure that the list of APIs is as shown in the Libraries node below:

  4. New Sample

Creating the Project Factory

We start by implementing the org.netbeans.spi.project.ProjectFactory class.

  1. Create a Java class called DemoProjectFactory.

  2. Change the default code to the following:

    @org.openide.util.lookup.ServiceProvider(service=ProjectFactory.class)
    public class DemoProjectFactory implements ProjectFactory {
    
        public static final String PROJECT_DIR = "texts";
    
        //Specifies when a project is a project, i.e.,
        //if the project directory "texts" is present:
        @Override
        public boolean isProject(FileObject projectDirectory) {
            return projectDirectory.getFileObject(PROJECT_DIR) != null;
        }
    
        //Specifies when the project will be opened, i.e.,
        //if the project exists:
        @Override
        public Project loadProject(FileObject dir, ProjectState state) throws IOException {
            return isProject(dir) ? new DemoProject(dir, state) : null;
        }
    
        @Override
        public void saveProject(final Project project) throws IOException, ClassCastException {
            FileObject projectRoot = project.getProjectDirectory();
            if (projectRoot.getFileObject(PROJECT_DIR) == null) {
                throw new IOException("Project dir " + projectRoot.getPath() +
                        " deleted," +
                        " cannot save project");
            }
            //Force creation of the texts dir if it was deleted:
            ((DemoProject) project).getTextFolder(true);
        }
    
    }

Creating the Project

Next, we implement the org.netbeans.api.project.Project class.

  1. Create a Java class called DemoProject.

  2. Change the default code to the following:

    class DemoProject implements Project {
    
        private final FileObject projectDir;
        private final ProjectState state;
        private Lookup lkp;
    
        public DemoProject(FileObject projectDir, ProjectState state) {
            this.projectDir = projectDir;
            this.state = state;
        }
    
        @Override
        public FileObject getProjectDirectory() {
            return projectDir;
        }
    
        FileObject getTextFolder(boolean create) {
            FileObject result =
                    projectDir.getFileObject(DemoProjectFactory.PROJECT_DIR);
            if (result == null && create) {
                try {
                    result = projectDir.createFolder(DemoProjectFactory.PROJECT_DIR);
                } catch (IOException ioe) {
                    Exceptions.printStackTrace(ioe);
                }
            }
            return result;
        }
    
        //The project type's capabilities are registered in the project's lookup:
        @Override
        public Lookup getLookup() {
            if (lkp == null) {
                lkp = Lookups.fixed(new Object[]{
                            state, //allow outside code to mark the project as needing saving
                            new ActionProviderImpl(), //Provides standard actions like Build and Clean
                            new DemoDeleteOperation(),
                            new DemoCopyOperation(this),
                            new Info(), //Project information implementation
                            new DemoProjectLogicalView(this), //Logical view of project implementation
                        });
            }
            return lkp;
        }
    
        private final class ActionProviderImpl implements ActionProvider {
    
            private String[] supported = new String[]{
                ActionProvider.COMMAND_DELETE,
                ActionProvider.COMMAND_COPY,
            };
    
            @Override
            public String[] getSupportedActions() {
                return supported;
            }
    
            @Override
            public void invokeAction(String string, Lookup lookup) throws IllegalArgumentException {
                if (string.equalsIgnoreCase(ActionProvider.COMMAND_DELETE)) {
                    DefaultProjectOperations.performDefaultDeleteOperation(DemoProject.this);
                }
                if (string.equalsIgnoreCase(ActionProvider.COMMAND_COPY)) {
                    DefaultProjectOperations.performDefaultCopyOperation(DemoProject.this);
                }
            }
    
            @Override
            public boolean isActionEnabled(String command, Lookup lookup) throws IllegalArgumentException {
                if ((command.equals(ActionProvider.COMMAND_DELETE))) {
                    return true;
                } else if ((command.equals(ActionProvider.COMMAND_COPY))) {
                    return true;
                } else {
                    throw new IllegalArgumentException(command);
                }
            }
        }
    
        private final class DemoDeleteOperation implements DeleteOperationImplementation {
    
            public void notifyDeleting() throws IOException {
            }
    
            public void notifyDeleted() throws IOException {
            }
    
            public List<FileObject> getMetadataFiles() {
                List<FileObject> dataFiles = new ArrayList<FileObject>();
                return dataFiles;
            }
    
            public List<FileObject> getDataFiles() {
                List<FileObject> dataFiles = new ArrayList<FileObject>();
                return dataFiles;
            }
        }
    
        private final class DemoCopyOperation implements CopyOperationImplementation {
    
            private final DemoProject project;
            private final FileObject projectDir;
    
            public DemoCopyOperation(DemoProject project) {
                this.project = project;
                this.projectDir = project.getProjectDirectory();
            }
    
            public List<FileObject> getMetadataFiles() {
                return Collections.EMPTY_LIST;
            }
    
            public List<FileObject> getDataFiles() {
                return Collections.EMPTY_LIST;
            }
    
            public void notifyCopying() throws IOException {
            }
    
            public void notifyCopied(Project arg0, File arg1, String arg2) throws IOException {
            }
        }
    
        private final class Info implements ProjectInformation {
    
            @Override
            public Icon getIcon() {
                return new ImageIcon(ImageUtilities.loadImage(
                        "org/netbeans/demo/project/icon2.png"));
            }
    
            @Override
            public String getName() {
                return getProjectDirectory().getName();
            }
    
            @Override
            public String getDisplayName() {
                return getName();
            }
    
            @Override
            public void addPropertyChangeListener(PropertyChangeListener pcl) {
                //do nothing, won't change
            }
    
            @Override
            public void removePropertyChangeListener(PropertyChangeListener pcl) {
                //do nothing, won't change
            }
    
            @Override
            public Project getProject() {
                return DemoProject.this;
            }
        }
    }
    

Creating the Logical View Provider

Finally, we implement the org.netbeans.spi.project.ui.LogicalViewProvider class.

  1. Create a Java class called DemoProjectLogicalView.

  2. Change the default code to the following:

    class DemoProjectLogicalView implements LogicalViewProvider {
    
        private final DemoProject project;
    
        public DemoProjectLogicalView(DemoProject project) {
            this.project = project;
        }
    
        @Override
        public org.openide.nodes.Node createLogicalView() {
            try {
                //Get the Text directory, creating if deleted
                FileObject text = project.getTextFolder(true);
    
                //Get the DataObject that represents it
                DataFolder textDataObject =
                        DataFolder.findFolder(text);
    
                //Get its default node-we'll wrap our node around it to change the
                //display name, icon, etc
                Node realTextFolderNode = textDataObject.getNodeDelegate();
    
                //This FilterNode will be our project node
                return new TextNode(realTextFolderNode, project);
    
            } catch (DataObjectNotFoundException donfe) {
                Exceptions.printStackTrace(donfe);
                //Fallback-the directory couldn't be created -
                //read-only filesystem or something evil happened
                return new AbstractNode(Children.LEAF);
            }
        }
    
        /** This is the node you actually see in the project tab for the project */
        private static final class TextNode extends FilterNode {
    
            final DemoProject project;
    
            public TextNode(Node node, DemoProject project) throws DataObjectNotFoundException {
                super(node, new FilterNode.Children(node),
                        //The projects system wants the project in the Node's lookup.
                        //NewAction and friends want the original Node's lookup.
                        //Make a merge of both
                        new ProxyLookup(new Lookup[]{Lookups.singleton(project),
                            node.getLookup()
                        }));
                this.project = project;
            }
    
            @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("org/netbeans/demo/project/icon1.png");
            }
    
            @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;
        }
    
    }
    

Installing the Module

Finally, we install the module and make use of the result.

  1. Check that the module looks as follows in the Projects window:

  2. finished project

  3. Right-click the module project and choose "Run". The application for which the module is being created starts up and the module installs into it.
  4. Choose File | Open Project and browse to a folder that has a subfolder named "texts". You should see the icon that you defined earlier to identify the project type:

  5. finished project

  6. Open the project and you should see the Projects window displaying your project. The content of the "texts" folder should be shown in the Projects window:

  7. installed result

  8. Right-click the project node and notice the project-level menu items that you defined earlier:

  9. installed result



Next Steps

For more information about creating and developing NetBeans modules, see the following resources:

 
 
loading
Please Confirm