| <!doctype html> |
| <html class="no-js" lang="en" dir="ltr"> |
| <head> |
| <meta charset="utf-8"> |
| <meta http-equiv="x-ua-compatible" content="ie=edge"> |
| <title>NetBeans Project Type Extension Module Tutorial</title> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="description" content="NetBeans Project Type Extension Module Tutorial - Apache NetBeans"> |
| <meta name="author" content="Apache NetBeans"> |
| <meta name="description" content="NetBeans Project Type Extension Module Tutorial - Apache NetBeans"> |
| <meta name="keywords" content="Apache NetBeans Platform, Platform Tutorials, NetBeans Project Type Extension Module Tutorial"> |
| <meta name="generator" content="Apache NetBeans"> |
| <link rel="stylesheet" href="../../../../_/css/font-awesome.min.css"> |
| <link rel="alternate" type="application/atom+xml" title="Apache NetBeans Blog" href="https://netbeans.apache.org/blogs/atom" /> |
| <link rel="stylesheet" href="../../../../_/css/highlightjs/default.min.css"> |
| <link rel="stylesheet" href="../../../../_/css/netbeans.css"> |
| <link rel="apple-touch-icon" sizes="180x180" href="../../../../_/images/fav/apple-touch-icon.png"> |
| <link rel="icon" type="image/png" sizes="32x32" href="../../../../_/images/fav/favicon-32x32.png"> |
| <link rel="icon" type="image/png" sizes="16x16" href="../../../../_/images/fav/favicon-16x16.png"> |
| <link rel="manifest" href="../../../../_/images/fav/site.webmanifest"> |
| <link rel="mask-icon" href="../../../../_/images/fav/safari-pinned-tab.svg" color="#5bbad5"> |
| <meta name="msapplication-TileColor" content="#ffc40d"> |
| <meta name="theme-color" content="#ffffff"> |
| <link href="../../../../_/css/font-open-sans.css" rel="stylesheet"> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| http://www.apache.org/licenses/LICENSE-2.0 |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| </head> |
| <body> |
| <div class="title-bar" data-responsive-toggle="responsive-menu" data-hide-for="medium"> |
| <button type="button" data-toggle="responsive-menu"><i style='font-size: 32px; color: #fff; padding: 8px' class='fa fa-bars'></i></button> |
| <div class="title-bar-title">Apache NetBeans</div> |
| </div> |
| <div class="top-bar" id="responsive-menu"> |
| <div class='top-bar-left'> |
| <a class='title' href="../../../../index.html"><img src='../../../../_/images/apache-netbeans.svg' style='padding: 8px; height: 48px;'> Apache NetBeans</a> |
| </div> |
| <div class="top-bar-right"> |
| <ul class="vertical medium-horizontal menu" data-responsive-menu="drilldown medium-dropdown"> |
| <li> <input id="search-input" type="text" placeholder="Search the docs"> </li> |
| <li> <a href="../../../../front/main/community">Community</a> </li> |
| <li> <a href="../../../../front/main/participate">Participate</a> </li> |
| <li> <a href="../../../../front/main/blogs">Blog</a></li> |
| <li> <a href="../../../../front/main/help">Get Help</a> </li> |
| <li> <a href="https://plugins.netbeans.apache.org/">Plugins</a> </li> |
| <li> <a href="../../../../front/main/download">Download</a> </li> |
| </ul> |
| </div> |
| </div> |
| |
| <!-- src/templates/news --> |
| <section class="hero news alternate"> |
| <div class='grid-container'> |
| <div class='cell'> |
| <div class="annotation">Latest release</div> |
| <h1>Apache NetBeans 27</h1> |
| <p><a class="button success" href="../../../../front/main/download/nb27">Download</a></p> |
| </div> |
| </div> |
| </section> |
| <div class='grid-container main-content tutorial'> |
| <h1 class="sect0">NetBeans Project Type Extension Module Tutorial</h1> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p class='reviewed'><i class="fa fa-check-circle"></i> Last reviewed on 2022-01-19</p> |
| </div> |
| </div> |
| <div id="toc" class="toc"> |
| <div id="toctitle"></div> |
| <ul class="sectlevel1"> |
| <li><a href="#_introduction_to_project_extensions">Introduction to Project Extensions</a></li> |
| <li><a href="#_creating_the_module_project">Creating the Module Project</a></li> |
| <li><a href="#_project_extension_scenarios">Project Extension Scenarios</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_scenario_1_extending_the_project_lookup">Scenario 1: Extending the Project Lookup</a></li> |
| <li><a href="#_scenario_2_extending_the_project_logical_view">Scenario 2: Extending the Project Logical View</a></li> |
| <li><a href="#_scenario_3_extending_the_project_customizer">Scenario 3: Extending the Project Customizer</a></li> |
| </ul> |
| </li> |
| <li><a href="#_next_steps">Next Steps</a></li> |
| </ul> |
| </div> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This tutorial demonstrates how to extend an existing project type.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You will also make use of this icon, which you can right-click here and download: <span class="image"><img src="../../_images/tutorials/projectextensions_webPagesBadge.gif" alt="projectextensions webPagesBadge"></span></p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_introduction_to_project_extensions"><a class="anchor" href="#_introduction_to_project_extensions"></a>Introduction to Project Extensions</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>New NetBeans IDE APIs since NetBeans IDE 6.0 enable you to add new nodes to an existing project type’s logical view, new objects to an existing project type’s lookup, and new panels to an existing project type’s Project Properties dialog box. For example, in this tutorial, to illustrate these extensions, we extend the web application project type’s logical view, by adding a new "Important Files" node, exposing the content of the project’s "nbproject" folder, as shown here:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="../../_images/tutorials/cc_72_result-2.png" alt="cc 72 result 2"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Prior to NetBeans IDE 6.0, no NetBeans IDE APIs existed for extending existing project types. Instead, you would need to create new project types from scratch. From 6.0 onwards, you are recommended to extend existing project types rather than create new ones, where possible. This will keep the number of project types to a minimum and avoid a large number of project types with very small differences. However, it is, of course, always possible to create project types from scratch, as before, following the <a href="../nbm-projecttype/" class="xref page">NetBeans Project Type Module Tutorial</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Annotations are used throughout this tutorial to register the lookup extension, logical view extension, and project customizer extension. As you will see below, the extensions will be registered for the project type "org-netbeans-modules-web-project", which is the web application project type. Here is a list of strings representing other project types supported by NetBeans IDE:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>org-netbeans-modules-ant-freeform</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-apisupport-project</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-apisupport-project-suite</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-j2ee-archiveproject</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-j2ee-clientproject</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-j2ee-earproject</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-j2ee-ejbjarproject</p> |
| </li> |
| <li> |
| <p>org-netbeans-modules-java-j2seproject</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>More project types may be available, depending on the modules that are part of your specific installation of NetBeans IDE or other application on the NetBeans Platform.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_creating_the_module_project"><a class="anchor" href="#_creating_the_module_project"></a>Creating the Module Project</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="1"> |
| <li> |
| <p>Choose File > New Project (Ctrl+Shift+N). Under Categories, select NetBeans Modules. Under Projects, select Module. Click Next.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="2"> |
| <li> |
| <p>In the Name and Location panel, type <code>ImportantWebFiles</code> in the Project Name field. Change the Project Location to any directory on your computer. Click Next.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="3"> |
| <li> |
| <p>In the Basic Module Configuration panel, type <code>org.netbeans.modules.importantwebfiles</code> in Code Name Base. Click Finish. The IDE creates the <code>ImportantWebFiles</code> 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).</p> |
| </li> |
| </ol> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="4"> |
| <li> |
| <p>Right-click the project’s Libraries node, choose Add Module Dependency, and then set dependencies on the following modules:</p> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Datasystems API</p> |
| </li> |
| <li> |
| <p>File System API</p> |
| </li> |
| <li> |
| <p>Lookup API</p> |
| </li> |
| <li> |
| <p>Nodes API</p> |
| </li> |
| <li> |
| <p>Project API</p> |
| </li> |
| <li> |
| <p>Project UI API</p> |
| </li> |
| <li> |
| <p>Utilities API</p> |
| </li> |
| </ul> |
| </div> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>You should now see the following dependencies have been set:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="../../_images/tutorials/cc_72_deps-1.png" alt="cc 72 deps 1"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Your module structure is ready, the dependencies have been set, and you can now begin coding.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_project_extension_scenarios"><a class="anchor" href="#_project_extension_scenarios"></a>Project Extension Scenarios</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Three separate, independent scenarios are described below. Depending on your needs, extend the project of your choice in one or more of the following ways:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="#extendingthelookup">Scenario 1: Extending the Project Lookup</a></p> |
| </li> |
| <li> |
| <p><a href="#extendingthelogicalview">Scenario 2: Extending the Project Logical View</a></p> |
| </li> |
| <li> |
| <p><a href="#extendingthecustomizer">Scenario 3: Extending the Project Customizer</a></p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="_scenario_1_extending_the_project_lookup"><a class="anchor" href="#_scenario_1_extending_the_project_lookup"></a>Scenario 1: Extending the Project Lookup</h3> |
| <div class="paragraph"> |
| <p>In this section, we register a class named <code>ServiceImpl</code> into the <code>Lookup</code> of web projects. We create an <code>Action</code> to verify that the object has been registered successfully.</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="1"> |
| <li> |
| <p>Create a Java class named <code>Service</code> . Change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.swing.JOptionPane; |
| |
| public abstract class Service { |
| |
| static { |
| JOptionPane.showMessageDialog(null, "===> loading Service"); |
| } |
| |
| public abstract String m(); |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="2"> |
| <li> |
| <p>Create a new Java class named <code>ServiceImpl</code> . Change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import javax.swing.JOptionPane; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ProjectUtils; |
| import org.netbeans.spi.project.ProjectServiceProvider; |
| |
| <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectapi/org/netbeans/spi/project/ProjectServiceProvider.html">@ProjectServiceProvider</a>( |
| service=Service.class, |
| projectType="org-netbeans-modules-web-project") |
| public class ServiceImpl extends Service { |
| |
| static { |
| JOptionPane.showMessageDialog(null, "===> loading ServiceImpl"); |
| } |
| private final Project p; |
| |
| public ServiceImpl(Project p) { |
| this.p = p; |
| JOptionPane.showMessageDialog(null, "===> new ServiceImpl on " + p); |
| } |
| |
| @Override |
| public String m() { |
| return ProjectUtils.getInformation(p).getDisplayName(); |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="3"> |
| <li> |
| <p>Create a new Java class named <code>TestAction</code> . Change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import javax.swing.JOptionPane; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ui.OpenProjects; |
| import org.openide.awt.ActionID; |
| import org.openide.awt.ActionReference; |
| import org.openide.awt.ActionRegistration; |
| import org.openide.util.NbBundle.Messages; |
| |
| @ActionID( |
| category = "File", |
| id = "org.netbeans.modules.importantwebfiles.TestAction") |
| @ActionRegistration( |
| displayName = "#CTL_TestAction") |
| @ActionReference( |
| path = "Menu/File", |
| position = 0) |
| @Messages("CTL_TestAction=Test") |
| public final class TestAction implements ActionListener { |
| |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| JOptionPane.showMessageDialog(null, "===> running action"); |
| for (Project p : OpenProjects.getDefault().getOpenProjects()) { |
| Service s = p.getLookup().lookup(Service.class); |
| if (s != null) { |
| JOptionPane.showMessageDialog(null, "===> got a service: " + s.m()); |
| } else { |
| JOptionPane.showMessageDialog(null, "===> nothing for " + p); |
| } |
| } |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Run the module to install it into a new instance of NetBeans IDE. Open a few NetBeans projects. Invoke the <code>Action</code> and observe the <code>JOptionPanes</code> to see the result. Depending on whether a project is a web project, you will get different messages.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_scenario_2_extending_the_project_logical_view"><a class="anchor" href="#_scenario_2_extending_the_project_logical_view"></a>Scenario 2: Extending the Project Logical View</h3> |
| <div class="paragraph"> |
| <p>In this section, we change the node hierarchy in the Projects window for an existing project type. We start by implementing the <code> <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/NodeFactory.html">NodeFactory</a></code> class, which we will register via an annotation.</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="1"> |
| <li> |
| <p>Create a Java class called <code>ImportantFilesNodeFactory</code> . Change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">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.loaders.DataObjectNotFoundException; |
| import org.openide.util.Exceptions; |
| |
| <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/NodeFactory.Registration.html">@NodeFactory.Registration</a>(projectType = "org-netbeans-modules-web-project") |
| public class ImportantFilesNodeFactory implements <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/NodeFactory.html">NodeFactory</a> { |
| |
| @Override |
| public NodeList createNodes(Project project) { |
| |
| //Optionally, only return a new node |
| //if some item is in the project's lookup: |
| //MyCoolLookupItem item = project.getLookup().lookup(MyCoolLookupItem.class); |
| //if (item != null) { |
| try { |
| ImportantFilesNode nd = new ImportantFilesNode(project); |
| return NodeFactorySupport.fixedNodeList(nd); |
| } catch (DataObjectNotFoundException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| //} |
| |
| //If the above try/catch fails, e.g., |
| //our item isn't in the lookup, |
| //then return an empty list of nodes: |
| return NodeFactorySupport.fixedNodeList(); |
| |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="2"> |
| <li> |
| <p>Create a new Java class called <code>ImportantFilesNode</code> , which will filter the node of the project’s "nbproject" folder. A new display name and icon will be defined for that folder. Therefore, change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import java.awt.Image; |
| import org.netbeans.api.annotations.common.StaticResource; |
| import org.netbeans.api.project.Project; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.loaders.DataFolder; |
| import org.openide.loaders.DataObject; |
| import org.openide.loaders.DataObjectNotFoundException; |
| import org.openide.nodes.FilterNode; |
| import org.openide.util.ImageUtilities; |
| |
| public class ImportantFilesNode extends <a href="https://bits.netbeans.org/dev/javadoc/org-openide-nodes/org/openide/nodes/FilterNode.html">FilterNode</a> { |
| |
| @StaticResource |
| private static final String IMAGE = "org/netbeans/modules/" |
| + "importantwebfiles/webPagesBadge.gif"; |
| |
| public ImportantFilesNode(Project proj) throws DataObjectNotFoundException { |
| super(DataObject.find(proj.getProjectDirectory(). |
| getFileObject("nbproject")).getNodeDelegate()); |
| } |
| |
| @Override |
| public String getDisplayName() { |
| return "Important Files"; |
| } |
| |
| //Next, we add icons, for the default state, which is |
| //closed, and the opened state; we will make them the same. |
| // |
| //Icons in project logical views are |
| //based on combinations--you can combine the node's own icon |
| //with a distinguishing badge that is merged with it. Here we |
| //first obtain the icon from a data folder, then we add our |
| //badge to it by merging it via a NetBeans API utility method: |
| @Override |
| public Image getIcon(int type) { |
| DataFolder root = DataFolder.findFolder(FileUtil.getConfigRoot()); |
| Image original = root.getNodeDelegate().getIcon(type); |
| return ImageUtilities.mergeImages(original, |
| ImageUtilities.loadImage(IMAGE), 7, 7); |
| } |
| @Override |
| public Image getOpenedIcon(int type) { |
| DataFolder root = DataFolder.findFolder(FileUtil.getConfigRoot()); |
| Image original = root.getNodeDelegate().getIcon(type); |
| return ImageUtilities.mergeImages(original, |
| ImageUtilities.loadImage(IMAGE), 7, 7); |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="3"> |
| <li> |
| <p>Right-click this icon and save it in the main package of your module: |
| <span class="image"><img src="../../_images/tutorials/projectextensions_webPagesBadge.gif" alt="projectextensions webPagesBadge"></span></p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Run the module and you will notice that web applications have your newly defined node, exposing the project’s "nbproject" folder:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="../../_images/tutorials/cc_72_result-2.png" alt="cc 72 result 2"> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_scenario_3_extending_the_project_customizer"><a class="anchor" href="#_scenario_3_extending_the_project_customizer"></a>Scenario 3: Extending the Project Customizer</h3> |
| <div class="paragraph"> |
| <p>In this section, we create two new tabs in the Project Properties dialog of the web application project type.</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="1"> |
| <li> |
| <p>Create a Java class called <code>ImportantFilesCustomizerTab</code> . Change the default code to the following:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import java.awt.BorderLayout; |
| import javax.swing.JComponent; |
| import javax.swing.JLabel; |
| import javax.swing.JPanel; |
| import org.netbeans.spi.project.ui.support.ProjectCustomizer; |
| import org.netbeans.spi.project.ui.support.ProjectCustomizer.Category; |
| import org.openide.util.Lookup; |
| import org.openide.util.NbBundle; |
| |
| public class ImportantFilesCustomizerTab |
| implements <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/ProjectCustomizer.CompositeCategoryProvider.html">ProjectCustomizer.CompositeCategoryProvider</a> { |
| |
| private final String name; |
| |
| private ImportantFilesCustomizerTab(String name) { |
| this.name = name; |
| } |
| |
| @Override |
| public Category createCategory(Lookup lkp) { |
| return ProjectCustomizer.Category.create(name, name, null); |
| } |
| |
| @Override |
| public JComponent createComponent(Category category, Lookup lkp) { |
| JPanel jPanel1 = new JPanel(); |
| jPanel1.setLayout(new BorderLayout()); |
| jPanel1.add(new JLabel(name), BorderLayout.CENTER); |
| return jPanel1; |
| } |
| |
| @NbBundle.Messages({"LBL_Config=Configuration"}) |
| <a href="https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/ProjectCustomizer.CompositeCategoryProvider.Registration.html">@ProjectCustomizer.CompositeCategoryProvider.Registration</a>( |
| projectType = "org-netbeans-modules-web-project", |
| position = 10) |
| public static ImportantFilesCustomizerTab createMyDemoConfigurationTab() { |
| return new ImportantFilesCustomizerTab(Bundle.LBL_Config()); |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="2"> |
| <li> |
| <p>Run the module. Right-click a web application’s project node and choose Properties. Notice the new tab that has been added. The <code>createCategory</code> method above defines the left side of the screenshot below, while the right side is defined by the <code>createComponent</code> method.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="../../_images/tutorials/cc_72_result-3.png" alt="cc 72 result 3"> |
| </div> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic" start="3"> |
| <li> |
| <p>Now we’ll change the class so that two tabs are created, instead of one:</p> |
| </li> |
| </ol> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">import java.awt.BorderLayout; |
| import javax.swing.JComponent; |
| import javax.swing.JLabel; |
| import javax.swing.JPanel; |
| import org.netbeans.spi.project.ui.support.ProjectCustomizer; |
| import org.netbeans.spi.project.ui.support.ProjectCustomizer.Category; |
| import org.openide.util.Lookup; |
| import org.openide.util.NbBundle; |
| |
| public class ImportantFilesCustomizerTab |
| implements ProjectCustomizer.CompositeCategoryProvider { |
| |
| private final String name; |
| |
| private ImportantFilesCustomizerTab(String name) { |
| this.name = name; |
| } |
| |
| @Override |
| public Category createCategory(Lookup lkp) { |
| ProjectCustomizer.Category toReturn = null; |
| if (Bundle.LBL_Config1().equals(name)) { |
| toReturn = ProjectCustomizer.Category.create( |
| Bundle.LBL_Config1(), |
| Bundle.LBL_Config1(), |
| null); |
| } else { |
| toReturn = ProjectCustomizer.Category.create( |
| Bundle.LBL_Config2(), |
| Bundle.LBL_Config2(), |
| null); |
| } |
| return toReturn; |
| } |
| |
| @Override |
| public JComponent createComponent(Category category, Lookup lkp) { |
| String nm = category.getName(); |
| if (name.equals(nm)) { |
| JPanel jPanel1 = new JPanel(); |
| jPanel1.setLayout(new BorderLayout()); |
| jPanel1.add(new JLabel(name), BorderLayout.CENTER); |
| return jPanel1; |
| } else { |
| JPanel jPanel2 = new JPanel(); |
| jPanel2.setLayout(new BorderLayout()); |
| jPanel2.add(new JLabel(name), BorderLayout.CENTER); |
| return jPanel2; |
| } |
| } |
| |
| @NbBundle.Messages({"LBL_Config1=ConfigurationPart1"}) |
| @ProjectCustomizer.CompositeCategoryProvider.Registration( |
| projectType = "org-netbeans-modules-web-project", |
| position = 10) |
| public static ImportantFilesCustomizerTab createMyDemoConfigurationTab1() { |
| return new ImportantFilesCustomizerTab(Bundle.LBL_Config1()); |
| } |
| |
| @NbBundle.Messages({"LBL_Config2=ConfigurationPart2"}) |
| @ProjectCustomizer.CompositeCategoryProvider.Registration( |
| projectType = "org-netbeans-modules-web-project", |
| position = 20) |
| public static ImportantFilesCustomizerTab createMyDemoConfigurationTab2() { |
| return new ImportantFilesCustomizerTab(Bundle.LBL_Config2()); |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Run the module again and notice that you now have two new tabs:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <img src="../../_images/tutorials/cc_72_result-4.png" alt="cc 72 result 4"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In this tutorial, you have learned how to extend the project’s lookup, logical view, and customizer.</p> |
| </div> |
| <div class="paragraph"> |
| <p><a href="../../../../front/main/community/mailing-lists/" class="xref page">Send Us Your Feedback</a></p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_next_steps"><a class="anchor" href="#_next_steps"></a>Next Steps</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>For more information about creating and developing NetBeans modules, see the following resources:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><a href="../../kb/docs/platform/" class="xref page">Other Related Tutorials</a></p> |
| </li> |
| <li> |
| <p><a href="https://bits.netbeans.org/dev/javadoc/">NetBeans API Javadoc</a></p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <section class='tools'> |
| <ul class="menu align-center"> |
| <li><a title="Facebook" href="https://www.facebook.com/NetBeans"><i class="fa fa-md fa-facebook"></i></a></li> |
| <li><a title="Twitter" href="https://twitter.com/netbeans"><i class="fa fa-md fa-twitter"></i></a></li> |
| <li><a title="Github" href="https://github.com/apache/netbeans"><i class="fa fa-md fa-github"></i></a></li> |
| <li><a title="YouTube" href="https://www.youtube.com/user/netbeansvideos"><i class="fa fa-md fa-youtube"></i></a></li> |
| <li><a title="Atom Feed" href="https://netbeans.apache.org/blogs/atom"><i class="fa fa-mf fa-rss"></i></a></li> |
| <li><a title="Slack" href="https://tinyurl.com/netbeans-slack-signup/"><i class="fa fa-md fa-slack"></i></a></li> |
| <li><a title="Issues" href="https://github.com/apache/netbeans/issues"><i class="fa fa-mf fa-bug"></i></a></li> |
| </ul> |
| <ul class="menu align-center"> |
| <li><a href="https://github.com/apache/netbeans-antora-tutorials/edit/main/modules/ROOT/pages/tutorials/nbm-projectextension.adoc" title="See this page in github"><i class="fa fa-md fa-edit"></i> See this page in GitHub.</a></li> |
| </ul> |
| </section> |
| </div> |
| <div class='grid-container incubator-area' style='margin-top: 64px'> |
| <div class='grid-x grid-padding-x'> |
| <div class='large-auto cell text-center'> |
| <a href="https://www.apache.org/"> |
| <img style="height: 60px" title="Apache Software Foundation" src="../../../../_/images/asf_logo_wide.svg" /> |
| </a> |
| </div> |
| <div class='large-auto cell text-center'> |
| <a href="https://www.apache.org/events/current-event.html"> |
| <img style="width:234px; height: 60px;" title="Apache Software Foundation current event" src="https://www.apache.org/events/current-event-234x60.png"/> |
| </a> |
| </div> |
| </div> |
| </div> |
| <footer> |
| <div class="grid-container"> |
| <div class="grid-x grid-padding-x"> |
| <div class="large-auto cell"> |
| <h1><a href="../../../../front/main/about">About</a></h1> |
| <ul> |
| <li><a href="../../../../front/main/community/who">Who's Who</a></li> |
| <li><a href="https://www.apache.org/foundation/thanks.html">Thanks</a></li> |
| <li><a href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li> |
| <li><a href="https://www.apache.org/security/">Security</a></li> |
| </ul> |
| </div> |
| <div class="large-auto cell"> |
| <h1><a href="../../../../front/main/community">Community</a></h1> |
| <ul> |
| <li><a href="../../../../front/main/community/mailing-lists">Mailing lists</a></li> |
| <li><a href="../../../../front/main/community/committer">Becoming a committer</a></li> |
| <li><a href="../../../../front/main/community/events">NetBeans Events</a></li> |
| <li><a href="https://www.apache.org/events/current-event.html">Apache Events</a></li> |
| </ul> |
| </div> |
| <div class="large-auto cell"> |
| <h1><a href="../../../../front/main/participate">Participate</a></h1> |
| <ul> |
| <li><a href="../../../../front/main/participate/submit-pr">Submitting Pull Requests</a></li> |
| <li><a href="../../../../front/main/participate/report-issue">Reporting Issues</a></li> |
| <li><a href="../../../../front/main/participate/#documentation">Improving the documentation</a></li> |
| </ul> |
| </div> |
| <div class="large-auto cell"> |
| <h1><a href="../../../../front/main/help">Get Help</a></h1> |
| <ul> |
| <li><a href="../../../../front/main/help/#documentation">Documentation</a></li> |
| <li><a href="../../../../wiki/main/wiki">Wiki</a></li> |
| <li><a href="../../../../front/main/help/#support">Community Support</a></li> |
| <li><a href="../../../../front/main/help/commercial-support">Commercial Support</a></li> |
| </ul> |
| </div> |
| <div class="large-auto cell"> |
| <h1><a href="../../../../front/main/download">Download</a></h1> |
| <ul> |
| <li><a href="../../../../front/main/download">Releases</a></li> |
| <li><a href="https://plugins.netbeans.apache.org/">Plugins</a></li> |
| <li><a href="../../../../front/main/download/#_daily_builds_and_building_from_source">Building from source</a></li> |
| <li><a href="../../../../front/main/download/#_older_releases">Previous releases</a></li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </footer> |
| <div class='footer-disclaimer'> |
| <div class="footer-disclaimer-content"> |
| <p>Copyright © 2017-2025 <a href="https://www.apache.org">The Apache Software Foundation</a>.</p> |
| <p>Licensed under the Apache <a href="https://www.apache.org/licenses/">license</a>, version 2.0</p> |
| <div style='max-width: 40em; margin: 0 auto'> |
| <p>Apache, Apache NetBeans, NetBeans, the Apache feather logo and the Apache NetBeans logo are trademarks of <a href="https://www.apache.org">The Apache Software Foundation</a>.</p> |
| <p>Oracle and Java are registered trademarks of Oracle and/or its affiliates.</p> |
| <p>The Apache NetBeans website conforms to the <a href="https://privacy.apache.org/policies/privacy-policy-public.html">Apache Software Foundation Privacy Policy</a></p> |
| </div> |
| </div> |
| </div> |
| |
| |
| <script src="../../../../_/js/vendor/lunr.js"></script> |
| <script src="../../../../_/js/search-ui.js" id="search-ui-script" data-site-root-path="../../../.." data-snippet-length="100" data-stylesheet="../../../../_/css/search.css"></script> |
| <script async src="../../../../search-index.js"></script> |
| <script src="../../../../_/js/vendor/jquery.min.js"></script> |
| <script src="../../../../_/js/vendor/what-input.min.js"></script> |
| <script src="../../../../_/js/vendor/foundation.min.js"></script> |
| <script src="../../../../_/js/vendor/jquery.colorbox-min.js"></script> |
| <script src="../../../../_/js/netbeans.js"></script> |
| <script> |
| $(function(){ $(document).foundation(); }); |
| </script> |
| <script src="../../../../_/js/vendor/highlight.min.js"></script> |
| <script> |
| document.addEventListener('DOMContentLoaded', (event) => { |
| document.querySelectorAll('pre code').forEach((el) => { |
| hljs.highlightElement(el); |
| }); |
| }); |
| </script> |
| </body> |
| </html> |