| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <!-- -*- xhtml -*- --> |
| <title>NetBeans Platform Porting Tutorial for NetBeans Platform 6.9</title> |
| <link rel="stylesheet" type="text/css" href="https://netbeans.org/netbeans.css"/> |
| <meta name="AUDIENCE" content="NBUSER"/> |
| <meta name="TYPE" content="ARTICLE"/> |
| <meta name="EXPIRES" content="N"/> |
| <meta name="developer" content="gwielenga@netbeans.org"/> |
| <meta name="indexed" content="y"/> |
| <meta name="description" |
| content="A short guide to porting a Swing application to the NetBeans PLatform."/> |
| <!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. --> |
| <!-- Use is subject to license terms.--> |
| </head> |
| <body> |
| <h1>NetBeans Platform Porting Tutorial</h1> |
| |
| <p>This tutorial demonstrates how to port a simple Swing application to the <a href="https://platform.netbeans.org/screenshots.html">NetBeans Platform</a>. |
| Though the scenario below is simple, the basic concepts of "porting" an application to the NetBeans |
| Platform will become clear. In the end, some general principles will be identified, based on the |
| steps taken in the tutorial. Hopefully, they will be useful to you when porting your own |
| Swing applications to the NetBeans Platform.</p> |
| |
| <p><b>Contents</b></p> |
| |
| <p><img src="../images/articles/69/netbeans-stamp69.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8" title="Content on this page applies to NetBeans IDE 6.5, 6.7, 6.8"/></p> |
| <ul class="toc"> |
| <li><a href="#intro">Introduction to Porting</a></li> |
| <li><a href="#getting">Getting the Anagram Game</a></li> |
| <li><a href="#compliance">Levels of Compliance</a> |
| <ul> |
| <li><a href="#creating">Creating the NetBeans Platform Application</a></li> |
| <li><a href="#porting0">Porting Level 0: Launchable</a></li> |
| <li><a href="#porting1">Porting Level 1: Integration</a></li> |
| <li><a href="#porting3">Porting Level 2: Use Case Support</a></li> |
| <li><a href="#porting4">Porting Level 3: Aligned</a></li> |
| </ul></li> |
| <li><a href="#tips">Porting Tips & Tricks</a></li> |
| </ul> |
| |
| <p><b>To follow this tutorial, you need the software and resources listed in the following |
| table.</b></p> |
| |
| <table> |
| <tbody> |
| <tr> |
| <th class="tblheader" scope="col">Software or Resource</th> |
| <th class="tblheader" scope="col">Version Required</th> |
| </tr> |
| <tr> |
| <td class="tbltd1">NetBeans IDE</td> |
| <td class="tbltd1">version 6.9 or above</td> |
| </tr> |
| <tr> |
| <td class="tbltd1">Java Developer Kit (JDK)</td> |
| <td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">version 6</a></td> |
| </tr> |
| <!-- <tr> |
| <td class="tbltd1"><a href="http://plugins.netbeans.org/PluginPortal/faces/PluginDetailPage.jsp?pluginid=2753">Download the Sample</a></td> |
| <td class="tbltd1"></td> |
| </tr>--> |
| </tbody> |
| </table> |
| |
| <h2 class="tutorial"><a name="intro"></a>Introduction to Porting</h2> |
| |
| <p>Before beginning this procedure, it makes sense to ask why one would want to do so in the |
| first place. A typical Swing application consists of a domain-specific layer on top of a |
| general framework. The general framework normally provides features dealing with an |
| application's infrastructure, such |
| as an application's menu bar, windowing system (also known as "docking framework"), and |
| lifecycle management. Typically this framework is very generic and is (or could be) |
| reused by many applications within the |
| same organization. The NetBeans Platform exists specifically to cater to these infrastructural |
| concerns. You do not need to create these on your own for your own Swing applications. You |
| can simply move the useful domain-specific parts of your application to the |
| NetBeans Platform and then, |
| from that point onwards, the NetBeans Platform will be the new underlying 'plumbing' layer |
| of your application. You can then focus on the more interesting parts of your application, |
| specifically, the domain-specific parts. This will speed up your development process and give you |
| a consistent basis for all your applications.</p> |
| |
| <p>In this tutorial, we will begin with the Anagram Game, which is a standard Swing application |
| sample that is distributed with NetBeans IDE. We will, step by step, move it to the NetBeans |
| Platform and gradually see the advantages of doing so.</p> |
| |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="getting"></a>Getting the Anagram Game</h2> |
| |
| <p>We begin by getting the Anagram Game, which is one of the IDE's standard Java samples, |
| from the New Project wizard. Then we run it and analyze its parts.</p> |
| |
| <ol> |
| <li><p>Choose File > New Project (Ctrl-Shift-N). Under Categories, select Samples > Java. Under Projects, |
| select Anagram Game. Click Next and Finish.</p> |
| |
| <p>You should now see the Anagram Game application outlined in the Projects window, as shown here:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ag0.png"/></p> |
| |
| <p>The application contains the following classes:</p> |
| |
| <ul> |
| <li><b><tt>WordLibrary.java</tt></b>. Provides an abstract class, with |
| abstract methods like <code>getWord(int idx)</code>, <code>getScrambledWord(int idx)</code>, |
| and <code>isCorrect(int idx, String userGuess)</code>.</li> |
| <li><b><tt>StaticWordLibrary.java</tt></b>. Extends <code>WordLibrary.java</code>, |
| providing a list of scrambled words, as well |
| as their unscrambled equivalents, together with the getters and setters for accessing them |
| and for evaluating them.</li> |
| <li><b><tt>Anagrams.java</tt></b>. Provides the main user interface of the application, |
| principally consisting of a <code>JFrame</code> with |
| a <tt>JPanel</tt> containing labels and text fields. Also included |
| is a menu bar containing a File menu, with the menu items 'About' and 'Exit'.</li> |
| <li><b><tt>About.java</tt></b>. Provides the About box, accessed from the File menu.</li> |
| </ul></li> |
| |
| <li><p>Run the application and you should see the following:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ag1.png"/></p></li> |
| |
| <li><p>When you specify the correctly unscrambled word, you will see this:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ag2.png"/></p></li> |
| |
| </ol> |
| |
| <p>Before porting this application to the NetBeans Platform, we need to think |
| about <i>the stages in which we want to port our application</i>. In other |
| words, you do not need to port everything at once. And there are different |
| levels to which you can integrate your application, from a mostly superfical |
| level to a level that aligns your application completely with the paradigms |
| and purposes of the NetBeans Platform. The next section will show the levels |
| of compliance your application can have with the NetBeans Platform.</p> |
| |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="compliance"></a>Levels of Compliance</h2> |
| |
| <p>Converting an application to be fit for a framework such as the NetBeans Platform can be done |
| on various levels. The integration can be shallow and use just a few integration points or |
| it can be deeper, tightly following the paradigms of the NetBeans Platform.</p> |
| |
| <p>The stages can be described as follows:</p> |
| |
| <h4 id="section-LevelsOfCompliance-Level0Launchable">Level 0: Launchable</h4> |
| |
| <p>One or more of the following can be done to make your application launchable with as |
| few changes as possible:</p> |
| |
| <ul> |
| <li>Enhance your manifest with NetBeans key/value pairs so that your JAR is recognized as an |
| OSGi bundle or as a |
| NetBeans module.</li> |
| <li>Set dependencies between modules. In the manifest, with instances of plain Class-Path you can set dependencies |
| between modules.</li> |
| <li>Register a menu item in the declarative |
| layer file (<tt>layer.xml</tt>) of your module, to |
| invoke your original application. This file can be created automatically when you create a new |
| module project in NetBeans IDE, as you will see later.</li> |
| </ul> |
| |
| <p>In this tutorial, we will do all of the above. We will enhance the manifest, which the module |
| project wizard will do for us. We will create a menu item that will |
| invoke our application. To do so, we will move our application's classes into a module source |
| structure. Then we will use the New Action wizard to create a new menu item, which will |
| automatically be registered for us, and a dependency will be set on the UI Utilities API, which |
| we will need to implement the Action. From that action, we will invoke our application.</p> |
| |
| <h4 id="section-LevelsOfCompliance-Level1Integrated">Level 1: Integrated</h4> |
| |
| <p>Here are some pointers for integrating the application more |
| tightly with the NetBeans Platform:</p> |
| |
| <ul> |
| <li>Integrate visually to get the benefits of the NetBeans Window System, which is |
| its docking framework.</li> |
| <li>Use NetBeans Window System API and the Dialog APIs, primarily the <tt>TopComponent</tt> class and the |
| <tt>DialogDisplayer</tt> class.</li> |
| <li>Change initialization code of your application, use the <tt>ModuleInstall</tt> |
| class or declarative registrations, through the layer file or the META-INF/services folder.</li> |
| </ul> |
| |
| <p>In this tutorial, we will move the relevant parts of the <tt>JPanel</tt> |
| from the <tt>JFrame</tt> to a new <tt>TopComponent</tt>. The <tt>TopComponent</tt> class |
| creates a window on the NetBeans Platform, which in our case will show our <tt>JPanel</tt>.</p> |
| |
| <h4 id="section-LevelsOfCompliance-Level2UseCaseSupport">Level 2: Use Case Support</h4> |
| |
| <p>This level of compliance with the NetBeans Platform is concerned with one or more of the following activities:</p> |
| |
| <ul> |
| <li>Bind your application to other modules by inspecting existing functionality and trying to use it.</li> |
| <li>Simplify the workflow to fit into the NetBeans Platform paradigms.</li> |
| <li>Listen to the global selection to discover what other modules are doing and update your state accordingly.</li> |
| </ul> |
| |
| <p>In this tutorial, we will listen for the existence of <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-text/org/openide/cookies/EditorCookie.html">EditorCookie</a>s</tt>. |
| A cookie is a <i>capability</i>. |
| With a Java interface, your object's capabilities are fixed at compile time, while NetBeans Platform cookies |
| allow your object to behave dynamically because your object can expose capabilities, or |
| not, based on its state. An <tt>EditorCookie</tt> |
| defines an editor, with interfaces for common activities such as opening a document, closing the editor, |
| background loading of files, document saving, and modification notifications. We will listen for the |
| existence of such a cookie and then we will pass the content of the editor to the <tt>TopComponent</tt>, in the |
| form of words. By doing this, we are doing what the first item above outlines, i.e., inspecting existing |
| functionality and reusing it within the context of our ported application. This is a modest level of integration. |
| However, it pays off because you are reusing functionality provided by the NetBeans Platform.</p> |
| |
| <h4 id="section-LevelsOfCompliance-Level3Aligned">Level 3: Aligned</h4> |
| |
| <p>In this final stage of your porting activity, you are concerned with the following thoughts, first and foremost:</p> |
| |
| <ul> |
| <li>Become a good citizen of the NetBeans Platform, by exposing your own state to other modules so that they know what you are doing.</li> |
| <li>Eliminate duplicated functionality, by |
| reusing the Navigator, Favorites window, Task List, Progress API, etc., instead of creating or maintaining your own.</li> |
| <li>Cooperate with other modules and adapt your application to the NetBeans Platform way of doing things.</li> |
| </ul> |
| |
| <p>Towards the end of this tutorial, we will adopt this level of compliance by letting our <tt>TopComponent</tt> |
| expose a <tt>SaveCookie</tt> when changes are made to the "Guessed Word" text field. By doing this, we will |
| enable the Save menu item under the Tools menu. This kind of integration brings the full benefits of the |
| NetBeans Platform, however it also requires some effort to attain.</p> |
| |
| |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="creating"></a>Creating the NetBeans Platform Application</h2> |
| |
| <p>First, let's create the basis of our application. We use a wizard to do so. This |
| is the typical first practical step of creating a new application |
| on top of the NetBeans Platform application.</p> |
| |
| <ol> |
| <li><p>Choose File > New Project (Ctrl-Shift-N). Under Categories, select NetBeans Modules. |
| Under Projects, |
| select NetBeans Platform Application, as shown below:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agp0.png"/></p> |
| |
| <p>Click Next.</p></li> |
| <li><p>Name the application <code>AnagramApplication</code>, as shown below:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agp01.png"/></p> |
| <p>Click Finish</p> |
| <p>You now have a NetBeans Platform application. You can run it and |
| you will see an empty main window, with a menu bar and a tool bar. Look |
| under some of the menus, click a few toolbar buttons, and explore the |
| basis of your new application.</p> |
| |
| <p>Next, we create our first custom module. We will name it |
| <code>AnagramUI</code> because, in the end, it will |
| only contain the user interface (UI) of the application. |
| In a subsequent tutorial, we |
| will add additional modules, which will provide an API and an |
| implementation of the business logic. But, for the moment, we |
| will port everything into the module that will ultimately provide |
| only the UI of the application.</p></li> |
| |
| <li><p>Choose File > New Project (Ctrl-Shift-N) again. Under Categories, select NetBeans Modules. |
| Under Projects, |
| select Module, as shown below:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agp1.png"/></p> |
| |
| <p>Click Next.</p></li> |
| |
| <li><p>Type <tt>AnagramGameUI</tt> in Project Name and choose somewhere |
| to store the module, as shown below:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agp2.png"/></p> |
| |
| <p>Click Next.</p></li> |
| |
| <li><p>Type a unique name in the Code Name Base field, |
| which provides the unique identifier for your module. |
| It could be anything, but here it is <tt>org.anagram.ui</tt>.</p> |
| <p><img alt="" src="../images/tutorials/porting/agp3.png"/></p> |
| <p><b>Note:</b> Optionally, check "Generate XML Layer". If you do |
| not select it, that's fine, because later in this tutorial |
| you will be shown how to create it manually and you will also |
| learn what it is |
| used for.</p></li> |
| <li><p>Click Finish.</p> |
| |
| <p>Below the Anagram Game sample, you should now see the source structure of your |
| new module, as shown here:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agp4.png"/></p></li> |
| |
| </ol> |
| |
| <p>Above, we can see that we now have the original application, |
| together with the module to which it |
| will be ported. In the next sections, we will begin porting the application to |
| the module, using the porting levels described earlier.</p> |
| |
| <!-- ===================================================================================== --> |
| <h2 class="tutorial"><a name="porting0"></a>Porting Level 0: Launchable</h2> |
| |
| |
| <p>At this stage, we simply want to be able to launch our application from |
| a module. To do that we will create a menu item that invokes the application. |
| We begin |
| by copying the application's sources into the module source structure.</p> |
| |
| <ol> |
| <li><p>Copy the two packages from the Anagram Game into the module. Below, |
| the new packages and classes in the module are highlighted:</p> |
| <p><img alt="" src="../images/tutorials/porting/agport0.png"/></p></li> |
| |
| <li><p>In the <code>org.anagram.ui</code> package, create a new Java |
| class named <code>OpenAnagramGameAction</code>, implementing |
| the standard JDK <code>ActionListener</code> as follows:</p> |
| |
| <pre class="examplecode">import com.toy.anagrams.ui.Anagrams; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| |
| public class OpenAnagramGameAction implements ActionListener { |
| |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| new Anagrams().setVisible(true); |
| } |
| |
| }</pre> |
| |
| <p>When the user |
| invokes the <code>OpenAnagramGameAction</code>, the |
| <code>JFrame</code> from the Anagram Game will open.</p> |
| |
| </li> |
| |
| <li><p>Next, we need to register the new <code>OpenAnagramGameAction</code> in |
| the NetBeans central registry, which is also known as the "System FileSystem".</p> |
| |
| <p>If you do not have a file named <code>layer.xml</code> yet, |
| create one in the <code>org.anagram.ui</code> package, |
| with this content:</p> |
| |
| <pre class="examplecode"><?xml version="1.0" encoding="UTF-8"?> |
| <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "https://netbeans.org/dtds/filesystem-1_2.dtd"> |
| <filesystem> |
| |
| <folder name="Actions"> |
| <folder name="Window"> |
| <file name="org-anagram-ui-OpenAnagramGameAction.instance"> |
| <attr name="delegate" newvalue="org.anagram.ui.OpenAnagramGameAction"/> |
| <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/> |
| <attr name="displayName" bundlevalue="org.anagram.ui.Bundle#CTL_OpenAnagramGameAction"/> |
| </file> |
| </folder> |
| </folder> |
| <folder name="Menu"> |
| <folder name="Window"> |
| <file name="OpenLibraryViewerWindowAction.shadow"> |
| <attr name="originalFile" stringvalue="Actions/Window/org-anagram-ui-OpenAnagramGameAction.instance"/> |
| </file> |
| </folder> |
| </folder> |
| |
| </filesystem></pre> |
| <p>Each module in your application can have, at most, one |
| <code>layer.xml</code> file. The file is used to register |
| contributions to the NetBeans Platform application. For example, |
| new windows and new Actions are registered here, in folders |
| specifically dedicated to the contribution in question. Above, you |
| can see we are dealing with the "Actions" folder and the "Menu" |
| folder. Some notes on the elements and attributes above:</p> |
| <ul> |
| <li><p>Above, in the "delegate" attribute, you have registered the <code>OpenAnagramGameAction</code> |
| class. In the "instanceCreate" attribute, you have specified that the |
| NetBeans Platform method <code><a href="http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/Actions.html#alwaysEnabled%28java.awt.event.ActionListener,%20java.lang.String,%20java.lang.String,%20boolean%29">org.openide.awt.Actions.alwaysEnabled</a></code> |
| will be called when the <code>OpenAnagramGameAction</code> is invoked. This |
| is a NetBeans Platform method that creates an Action that is always enabled, |
| regardless of the context of the application. Since you want the Anagram Game |
| to be able to be started at any time, it makes sense for the Action to |
| always be enabled.</p></li> |
| <li> <p>The "displayName" attribute above points to a key in the <code>Bundle.properties</code> |
| file, which is the central file for storing all the localizable strings |
| in the module.</p></li> |
| <li><p>While the "Actions" folder registers the Action, the "Menu" folder specifies |
| where the Action will be displayed. Above, you can see that the Action |
| will be displayed in the Window menu.</p></li> |
| </ul> |
| </li> |
| |
| <li><p>In the <code>Bundle.properties</code> file, add the following key/value pair, |
| based on the "displayName" attribute above:</p> |
| <pre class="examplecode">CTL_OpenAnagramGameAction=Open Anagram Game</pre> |
| |
| </li> |
| |
| <li><p>In the Module Manifest, which you can find in the Important Files node |
| in the module, and which is <code>manifest.mf</code> on disk, |
| register the <code>layer.xml</code> file as follows:</p> |
| <pre class="examplecode">OpenIDE-Module-Layer: org/anagram/ui/layer.xml</pre> |
| |
| </li> |
| |
| |
| <li><p>In the Projects window, |
| right-click the AnagramApplication project node |
| and choose Run. The application starts up, installing |
| all the modules provided by the application, which |
| includes our custom module.</p></li> |
| |
| <li>Under the Window menu, |
| you should find the menu item "Open Anagram Game". |
| Choose it and your application appears.</li> |
| |
| </ol> |
| |
| <p>The application is displayed, but note that it is not |
| well integrated with the NetBeans Platform. For example, |
| it is not modal and it is impossible to close the <code>JFrame</code>, |
| unless you close the entire application. The latter is because |
| the entire application now manages the lifecycle of the <code>JFrame</code>. |
| In the next section, |
| we will integrate |
| the Anagram Game more tightly with the NetBeans Platform.</p> |
| |
| <p><b>Note:</b> In the section above, you manually created and registered a <code>layer.xml</code> file |
| and you manually created an <code>ActionListener</code> and you |
| manually registered the <code>ActionListener</code> in the <code>layer.xml</code> file. |
| Now that you know how and why and where these activities occur, you |
| can automate the process. Whenever you create a new module, |
| select the "Generate XML Layer" checkbox, which will let the IDE |
| automatically create the <code>layer.xml</code> file and the IDE |
| will also register it in the <code>manifest.mf</code> file for you. |
| In addition, you can automate the creation and registration of Actions |
| by using the "New Action" wizard, which is available in the New File dialog (Ctrl-N). |
| Also, whenever you use a wizard that registers something in the <code>layer.xml</code> |
| file, such as the New Action wizard does, and the <code>layer.xml</code> file does not |
| exist, the <code>layer.xml</code> file will automatically be created for you.</p> |
| |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="porting1"></a>Porting Level 1: Integration</h2> |
| |
| <p>In this section, we integrate the application |
| more tightly by creating a new window, so that we have a user |
| interface, that is., |
| a window, to which we can move those contents of |
| the <tt>JFrame</tt> that are useful to our new application.</p> |
| |
| <ol> |
| <li><p>Right-click the <code>org.anagram.ui</code> package in the Projects window and then |
| choose New > Other. Under Categories, select Module Development. Under File Types, |
| select Window.</p> |
| <p><img alt="" src="../images/tutorials/porting/agport4.png"/></p> |
| <p>Click Next.</p> |
| </li> |
| |
| <li><p>Choose the position where you would |
| like the window to appear. For purposes of this |
| tutorial choose "editor", which will place the |
| Anagram Game in the main part of the application:</p> |
| <p><img alt="" src="../images/tutorials/porting/agport5.png"/></p> |
| <p>Optionally, specify whether the window should |
| open automatically when the application starts up.</p> |
| <p>Click Next.</p> |
| </li> |
| |
| |
| <li><p>Type <tt>Anagram</tt> in Class Name |
| Prefix and select <tt>org.anagram.ui</tt> |
| in Package, as shown here:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agport6.png"/></p> |
| |
| <p>Above, notice that the IDE shows the files it |
| will create and modify.</p></li> |
| |
| <li><p>Click Finish.</p> |
| <p>Now you have a set of new Java and XML source |
| files, as shown here:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agport7.png"/></p></li> |
| |
| <li><p>Open the <tt>Anagrams</tt> class in |
| the <code>com.toy.anagrams.ui</code> package. Also open |
| the <tt>AnagramTopComponent</tt>, which was created |
| in the previous step. When you click the mouse in the |
| Anagram class, notice that the labels and |
| text fields are in a Swing container, in |
| this case a <tt>JPanel</tt>, as shown here:</p> |
| |
| <p><img alt="" style="border: 1px solid" src="../images/tutorials/porting/agport8.png"/></p> |
| |
| <p><b>Tip:</b> If the Swing components were not within a container, |
| you could select them all with the mouse, then right-click and |
| choose "Enclose In", to let the IDE create a container within which |
| all the selected components would be enclosed.</p></li> |
| |
| <li><p>Right-click the <tt>JPanel</tt> and copy it. |
| Paste it in the TopComponent and you should see |
| the old user interface in your new <code>TopComponent</code> class:</p> |
| |
| <p><img alt="" style="border: 1px solid" src="../images/tutorials/porting/agport9.png"/></p></li> |
| |
| <li><p>You have now ported the user interface of the Anagram Game. |
| A few variables need still to be moved from the <code>Anagrams</code> |
| class to the new <code>AnagramTopComponent</code> class. Declare these |
| two, which are in the <code>Anagrams</code> class, at the top of your |
| new <code>AnagramTopComponent</code> class.</p> |
| |
| <pre class="examplecode">private int wordIdx = 0; |
| private WordLibrary wordLibrary;</pre> |
| |
| <p>Next, look in the constructor of the <code>Anagrams</code> class. The first line |
| in the constructor is as follows:</p> |
| |
| <pre class="examplecode">wordLibrary = WordLibrary.getDefault();</pre> |
| |
| <p>Copy that statement. Paste it into the <code>TopComponent</code> class, making it |
| the new first statement in the constructor of the <code>TopComponent</code> class.</p></li> |
| |
| |
| <li><p>Next, open the <code>Bundle.properties</code> file. The content should be something |
| similar to this:</p> |
| |
| <pre class="examplecode">CTL_AnagramAction=Anagram |
| CTL_AnagramTopComponent=Anagram Window |
| HINT_AnagramTopComponent=This is a Anagram window |
| OpenIDE-Module-Name=AnagramGameUI |
| CTL_OpenAnagramGameAction=Open Anagram Game |
| AnagramTopComponent.feedbackLabel.text=\ |
| AnagramTopComponent.guessLabel.text=Your Guess: |
| AnagramTopComponent.scrambledLabel.text=Scrambled Word: |
| AnagramTopComponent.nextTrial.toolTipText=Fetch a new word. |
| AnagramTopComponent.nextTrial.text=New Word |
| AnagramTopComponent.guessButton.toolTipText=Guess the scrambled word. |
| AnagramTopComponent.guessButton.text=Guess</pre> |
| |
| <p>Notice line 6 above. The IDE erroneously created a backslash |
| instead of a space in the key/value pair in line 6 above. If |
| you have a line where the value is set to be a backslash, simply |
| delete the backslash.</p> |
| |
| <p>If you do not delete the backslash, when you run the application, in the |
| next step, you will see error messages such as these:</p> |
| |
| <pre class="examplecode">--java.util.MissingResourceException: Can't find resource for bundle |
| org.openide.util.NbBundle$PBundle, key AnagramTopComponent.guessLabel.text |
| |
| --java.lang.AssertionError: Component cannot be created for {component=null, |
| displayName=Anagram, instanceCreate=AlwaysEnabledAction[Anagram]}</pre> |
| |
| |
| <p>If you see the above error messages, open the <code>Bundle.properties</code> |
| file and remove the erroneously generated backslash. This is a known bug.</p></li> |
| |
| <li><p>Run the application again. When the |
| application starts up, you should now see the Anagram Game window, which |
| you defined in this section. You will also find |
| a new menu item that opens the window, under the |
| Window menu. Also notice that the game works as before. You |
| need to click the "New Word" button once, to have the module |
| call up a new word, and then you can use it as |
| before:</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/agport10.png"/></p></li> |
| |
| |
| <li><p>As a final step in this section, you can simply delete |
| the <code>com.toy.anagrams.ui</code> package. That package |
| contains the two UI classes from the original Anagram Game. |
| You do not need either of these two classes anymore. Simply |
| delete the package that contains them, since you have ported everything of interest |
| to the NetBeans Platform.</p> |
| |
| <p>Then also delete the <code>OpenAnagramGameAction</code> class, as well |
| as the registration entries you manually added to the <code>layer.xml</code> |
| file earlier in this tutorial. Be careful when you delete these |
| entries, since others have been added to the <code>layer.xml</code> |
| file in the meantime and you do not want to delete entries that |
| do not relate to this specific Action that you are deleting!</p> |
| </li> |
| |
| </ol> |
| |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="porting3"></a>Porting Level 2: Use Case Support</h2> |
| |
| <p>In this section, we are concerned with listening to the global selection and making use |
| of data we find there. The global selection is the registry for |
| global singletons and instances of objects which have been registered in the system by modules. |
| Here we query the lookup for <tt><a href="http://bits.netbeans.org/dev/javadoc/org-openide-text/org/openide/cookies/EditorCookie.html">EditorCookie</a></tt>s and make use of the <tt>EditorCookie</tt>'s |
| document to fill the string array that defines the scrambled words displayed in |
| the <tt>TopComponent</tt>. </p> |
| |
| |
| <p>A cookie is a capability. With a Java interface, your object's capabilities are |
| fixed at compile time, while NetBeans Platform cookies allow your object to behave dynamically |
| because your object can expose capabilities, or not, based on its state. An <code>EditorCookie</code> |
| defines an editor, with interfaces for common activities such as opening a document, closing the |
| editor, background loading of files, document saving, and modification notifications. We will |
| listen for the existence of such a cookie and then we will pass the content of the editor |
| to the TopComponent, in the form of words. By doing this, we are inspecting existing functionality |
| and reusing it within the context of our ported application. This is a modest level of |
| integration. However, it pays off because you are reusing functionality provided by the NetBeans Platform.</p> |
| |
| <ol> |
| <li>We begin by tweaking the <tt>StaticWordLibrary</tt> class. We do this so that |
| we can set its list of words externally. The sample provides a hardcoded list, |
| but we want to be able to set that list ourselves, via an external action. Therefore, |
| add this method to <tt>StaticWordLibrary</tt>: |
| |
| <pre class="examplecode">public static void setScrambledWordList(String[] inScrambledWordList) { |
| SCRAMBLED_WORD_LIST = inScrambledWordList; |
| }</pre> |
| |
| <p>Importantly, change the class signature of <tt>StaticWordLibrary</tt> |
| to <code>public class</code> and remove the <code>final</code> |
| from the signature of <code>SCRAMBLED_WORD_LIST</code></p> |
| |
| <p>Next, we will create an action that will obtain the content of a Manifest file, |
| break the content down into words, and fill the <tt>SCRAMBLED_WORD_LIST</tt> string array |
| with these words.</p> |
| |
| </li> |
| |
| <li>Right-click the module, choose Properties, and then open the Libraries |
| tab in the Project Properties dialog. Click "Add Dependency" and |
| then set dependencies on the Text API and the Nodes API.</li> |
| |
| <li>In the Source Editor, create a Java class |
| named <code>SetScrambledAnagramsAction</code> |
| and define it as follows: |
| |
| <pre class="examplecode">public final class SetScrambledAnagramsAction implements ActionListener { |
| |
| private final EditorCookie context; |
| |
| public SetScrambledAnagramsAction(EditorCookie context) { |
| this.context = context; |
| } |
| |
| @Override |
| public void actionPerformed(ActionEvent ev) { |
| try { |
| //Get the EditorCookie's document: |
| StyledDocument doc = context.getDocument(); |
| //Get the complete textual content: |
| String all = doc.getText(0, doc.getLength()); |
| //Make words from the content: |
| String[] tokens = all.split(" "); |
| //Pass the words to the WordLibrary class: |
| StaticWordLibrary.setScrambledWordList(tokens); |
| //Open the TopComponent: |
| TopComponent win = AnagramTopComponent.findInstance(); |
| win.open(); |
| win.requestActive(); |
| } catch (BadLocationException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| |
| }</pre></li> |
| |
| <li><p>Register the Action above in the layer file. Unlike the previous Action, |
| the Action above should not always be enabled. It should be available |
| for Manifest files only, since that is the file type we happen to be |
| interested in. Furthermore, the Action should only be enabled if |
| an <code>EditorCookie</code> is present. The result of these requirements |
| is a registration with this content:</p> |
| |
| <pre class="examplecode"><folder name="Actions"> |
| <folder name="Window"> |
| <file name="org-anagram-ui-SetScrambledAnagramsAction.instance"> |
| <attr name="delegate" methodvalue="org.openide.awt.Actions.inject"/> |
| <attr name="displayName" bundlevalue="org.anagram.ui.Bundle#CTL_SetScrambledAnagramsAction"/> |
| <attr name="injectable" stringvalue="org.anagram.ui.SetScrambledAnagramsAction"/> |
| <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.context"/> |
| <attr name="noIconInMenu" boolvalue="false"/> |
| <attr name="selectionType" stringvalue="EXACTLY_ONE"/> |
| <attr name="type" stringvalue="org.openide.cookies.EditorCookie"/> |
| </file> |
| </folder> |
| </folder> |
| <folder name="Editors"> |
| <folder name="text"> |
| <folder name="x-manifest"> |
| <folder name="Popup"> |
| <file name="org-anagram-ui-SetScrambledAnagramsAction.shadow"> |
| <attr name="originalFile" stringvalue="Actions/Window/org-anagram-ui-SetScrambledAnagramsAction.instance"/> |
| <attr name="position" intvalue="900"/> |
| </file> |
| </folder> |
| </folder> |
| </folder> |
| </folder></pre> |
| |
| <p>Many of the attributes above you have used previously. For example, the "displayName" |
| attribute points to a key in the <code>Bundle.properties</code> file. This key does not |
| exist yet. Create it now, in the <code>Bundle.properties</code> file, as follows:</p> |
| |
| <pre class="examplecode">CTL_SetScrambledAnagramsAction=Set Scrambled Words</pre> |
| |
| <p>The <code>instanceCreate</code> attribute specifies that |
| the <a href="http://bits.netbeans.org/dev/javadoc/org-openide-awt/org/openide/awt/Actions.html#context%28java.lang.Class,%20boolean,%20boolean,%20org.openide.util.ContextAwareAction,%20java.lang.String,%20java.lang.String,%20java.lang.String,%20boolean%29">org.openide.awt.Actions.context</a> |
| method handles the Action.</p> |
| |
| <p><b>Note:</b> Above, you manually created an Action class and registered it in the <code>layer.xml</code> |
| file. Now that you know how to do this, feel free to use the New Action wizard (in the New File dialog, |
| Ctrl-N) instead to |
| create context-sensitive Actions from now onwards.</p> |
| |
| </li> |
| |
| |
| <li><p>As discussed above, when we run the application we want to be able to right-click |
| within a Manifest file, choose a menu item, and invoke our Action. Right now, |
| however, the NetBeans Platform is unable to distinguish Manifest files |
| from any other file. Therefore, we need to enable Manifest support in our |
| application.</p> |
| <p>For demonstration purposes, we will enable ALL the modules in the NetBeans Platform, |
| as well as those provided by NetBeans IDE. As a result, when we run the |
| application, a new instance of NetBeans IDE will start up, together with |
| our custom module.</p> |
| <p>To achieve the above, expand the Important Files node, then open |
| the NetBeans Platform Config file, which on disk |
| is named <code>platform.properties</code>. Notice that many modules have |
| been disabled. You can enable them via the Project Properties dialog |
| of the NetBeans Platform application. Since we are simply going to enable |
| ALL of them, we need only change the content of the <code>platform.properties</code> |
| file to the following:</p> |
| |
| <pre class="examplecode">cluster.path=\ |
| ${nbplatform.active.dir}/apisupport:\ |
| ${nbplatform.active.dir}/harness:\ |
| ${nbplatform.active.dir}/ide:\ |
| ${nbplatform.active.dir}/java:\ |
| ${nbplatform.active.dir}/nb:\ |
| ${nbplatform.active.dir}/platform:\ |
| ${nbplatform.active.dir}/profiler:\ |
| ${nbplatform.active.dir}/websvccommon |
| disabled.modules= |
| nbplatform.active=default</pre> |
| |
| <p>In the next step, when we run the application, all the groups |
| of modules (called "clusters") will be enabled, nothing will |
| be excluded, and you will see NetBeans IDE started up.</p></li> |
| |
| <li><p>Run the application. Go to the Window menu and choose |
| Favorites. In the Favorites window, browse to a Manifest |
| file. Open the file. Inside the file, i.e., in the Manifest |
| Editor, right-click, and invoke the Set Scrambled Words |
| action via the menu item.</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ageditorcookie3.png"/></p> |
| |
| <p>The <code>AnagramTopComponent</code> is displayed and, |
| when you click the Next Word button, you will see that |
| the scrambled words all come from the selected Manifest file.</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ageditorcookie4.png"/></p> |
| |
| |
| </li> |
| |
| </ol> |
| |
| <p>The result of this exercise is that you now see the content of the Manifest |
| file in the Scrambled Word text field. |
| Of course, these words are not really scrambled and you cannot |
| really unscramble them. However, your module is |
| making use of the content of a file that is supported by a |
| different set of modules altogether, that is, the Manifest support |
| modules, as well as related editor modules.</p> |
| |
| |
| <p>Optionally, before continuing, you can now remove all the groups of |
| modules (known as "clusters") provided by NetBeans IDE, which |
| may not be relevant for your own application. To do so, right-click |
| the <code>AnagramApplication</code> node in the Projects window, |
| choose Properties, go to the Libraries tab, and uncheck all the |
| checkboxes, except for <code>harness</code> and <code>platform</code>. |
| Run the application again and you will see that all the project-related |
| and editor-related features of the application have now been removed.</p> |
| |
| <!-- ===================================================================================== --> |
| <h2 class="tutorial"><a name="porting4"></a>Porting Level 3: Aligned</h2> |
| |
| |
| <p>In this section, we are concerned with becoming a "good citizen" of the |
| NetBeans Platform. We are going to expose the state of the TopComponent to |
| the other modules, so that we can cooperate with them.</p> |
| <p>As an example of this, we |
| will modify the TopComponent to offer a <tt>SaveCookie</tt>, which gives |
| the user a way to store the text typed in the text field. By offering the |
| <tt>SaveCookie</tt> when changes are made in the text field, the Save button |
| and the Save menu item under the File menu will become enabled. That is because |
| the NetBeans Platform provides a context-sensitive Action called <code>SaveAction</code>. |
| The <code>SaveAction</code> becomes enabled whenever the capability of being saved, |
| in other words, the <code>SaveCookie</code>, is available. In this case, |
| we will make the <code>SaveCookie</code> available whenever the user types |
| something in the <code>guessedWord</code> text field. Then the <code>SaveAction</code> |
| will automatically become enabled.</p> |
| <p>When the user |
| selects the enabled button or menu item, a dialog will be displayed and the button |
| and menu item will become disabled, until the next time that a change is made |
| to the text field.</p> |
| <ol> |
| |
| <li>Begin by setting a dependency on the Dialogs API. |
| Do this by right-clicking |
| the project node in the Projects window, choosing Properties, and |
| then using the Libraries tab to add the Dialogs API as |
| a dependency of the module.</li> |
| |
| <li>Next, we define an implementation of the <code>SaveCookie</code>, somewhere |
| within the <code>AnagramTopComponent</code> class: |
| |
| <pre class="examplecode">private class SaveCookieImpl implements SaveCookie { |
| |
| @Override |
| public void save() throws IOException { |
| |
| Confirmation msg = new NotifyDescriptor.Confirmation("Do you want to save \"" |
| + guessedWord.getText() + "\"?", NotifyDescriptor.OK_CANCEL_OPTION, |
| NotifyDescriptor.QUESTION_MESSAGE); |
| |
| Object result = DialogDisplayer.getDefault().notify(msg); |
| |
| //When user clicks "Yes", indicating they really want to save, |
| //we need to disable the Save button and Save menu item, |
| //so that it will only be usable when the next change is made |
| //to the text field: |
| if (NotifyDescriptor.YES_OPTION.equals(result)) { |
| fire(false); |
| //Implement your save functionality here. |
| } |
| |
| } |
| |
| }</pre> |
| |
| <p>We have not defined the <code>fire</code> method yet, so the related |
| statement above will be underlined in red until we do so.</p> |
| </li> |
| |
| <li><p>In the constructor, call the as-yet-undefined <code>fire</code> method, |
| passing in true this time, whenever a change is detected in the |
| <code>guessedWord</code> text field:</p> |
| |
| <pre class="examplecode">guessedWord.getDocument().addDocumentListener(new DocumentListener() { |
| |
| @Override |
| public void insertUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| |
| public void removeUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| |
| public void changedUpdate(DocumentEvent arg0) { |
| fire(true); |
| } |
| |
| });</pre></li> |
| |
| <li><p>Now we declare an <code><a href="http://bits.netbeans.org/dev/javadoc/org-openide-util-lookup/org/openide/util/lookup/InstanceContent.html">InstanceContent</a></code> at the top of the class. The |
| <code>InstanceContent</code> class is a very powerful class in the NetBeans Platform, |
| enabling you to update the Lookup on the fly, at runtime. We also declare |
| the implementation of our <code>SaveCookie</code>:</p> |
| |
| |
| <pre class="examplecode">InstanceContent ic; |
| SaveCookieImpl impl;</pre></li> |
| |
| <li><p>Next, at the end of the constructor, we instantiate the <code>SaveCookie</code> and the <code>InstanceContent</code>, |
| while adding the <code>InstanceContent</code> to the <code>Lookup</code> |
| of the <code>AnagramTopComponent</code>:</p> |
| |
| <pre class="examplecode">impl = new SaveCookieImpl(); |
| |
| ic = new InstanceContent(); |
| |
| associateLookup(new AbstractLookup(ic));</pre></li> |
| |
| <li><p>Now we can add the <code>fire</code> method, which |
| dynamically adds and removes the <code>SaveCookie</code> |
| from the <code>InstanceContent</code>:</p> |
| |
| <pre class="examplecode">public void fire(boolean modified) { |
| if (modified) { |
| //If the text is modified, |
| //we add the SaveCookie implementation |
| //to the InstanceContent, which |
| //is in the Lookup of the TopComponent: |
| ic.add(impl); |
| } else { |
| //Otherwise, we remove the SaveCookie |
| //from the InstanceContent: |
| ic.remove(impl); |
| } |
| }</pre></li> |
| |
| <li>By default, you have a Save menu item under the File menu, but no Save button |
| in the toolbar. For testing purposes, that is, to simplify |
| checking whether the <code>SaveAction</code> is enabled, |
| you may want a Save button in the toolbar. |
| For this purpose, add the following to the layer: |
| |
| <pre class="examplecode"><folder name="Toolbars"> |
| <folder name="File"> |
| <file name="org-openide-actions-SaveAction.shadow"> |
| <attr name="originalFile" stringvalue="Actions/System/org-openide-actions-SaveAction.instance"/> |
| <attr name="position" intvalue="444"/> |
| </file> |
| </folder> |
| </folder></pre></li> |
| |
| <li><p>Run the application again. Make a change in the "Guessed Word" text field and |
| notice that the Save button |
| and the Save menu item become enabled:</p> |
| <p><img alt="" src="../images/tutorials/porting/ageditorcookie2.png"/></p> |
| |
| |
| <p>Select either the button or the menu item, |
| click the "OK" button in the |
| dialog...</p> |
| |
| <p><img alt="" src="../images/tutorials/porting/ageditorcookie5.png"/></p> |
| |
| <p>...and notice that the Save functionality is disabled afterwards.</p> |
| |
| </li> |
| |
| </ol> |
| |
| <p>Congratulations! Now that your application is making use of existing NetBeans Platform functionality, |
| you have taken |
| one further step |
| in successfully aligning it with the NetBeans Platform. Other modules can be now be |
| plugged into the NetBeans Platform to take advantage of, or even extend, features added by your |
| application. Hence, not only can your application benefit from what the NetBeans Platform provides, |
| but you can create features that other modules can use as well.</p> |
| <!-- |
| <p>You need to continue finding ways |
| to further align your original application with the functionality offered by the NetBeans Platform, |
| in order to make it even more of a good "good citizen" and useful member of the community of modules |
| within the application.</p> |
| |
| <p>For example, you can write a new node, with child nodes for each |
| word defined in the class:</p> |
| |
| <pre class="examplecode">public class WordListNode extends AbstractNode { |
| |
| private int index; |
| private final WordLibrary wordLibrary; |
| |
| public WordListNode() { |
| this(WordLibrary.getDefault()); |
| } |
| |
| private WordListNode(WordLibrary w) { |
| super(new WordListChildren(w)); |
| wordLibrary = w; |
| } |
| |
| WordListNode(int index, WordLibrary w) { |
| super(Children.LEAF); |
| this.index = index; |
| this.wordLibrary = w; |
| |
| setName("Index: " + index); |
| setDisplayName(wordLibrary.getWord(index)); |
| } |
| |
| @Override |
| public String getHtmlDisplayName() { |
| return "<b>" + wordLibrary.getWord(index) + "</b> (<i>" + wordLibrary.getScrambledWord(index) + "</i>)"; |
| } |
| |
| private static class WordListChildren extends Children.Keys<Integer> { |
| private final WordLibrary wordLibrary; |
| |
| public WordListChildren(WordLibrary wordLibrary) { |
| this.wordLibrary = wordLibrary; |
| } |
| |
| @Override |
| protected void addNotify() { |
| List<Integer> arr = new ArrayList<Integer>(); |
| for (int i = 0; i < wordLibrary.getSize(); i++) { |
| arr.add(i); |
| } |
| setKeys(arr); |
| } |
| |
| @Override |
| protected void removeNotify() { |
| setKeys(Collections.<Integer>emptyList()); |
| } |
| |
| @Override |
| protected Node[] createNodes(Integer index) { |
| WordListNode node = new WordListNode(index, wordLibrary); |
| return new Node[] { node }; |
| } |
| } |
| |
| }</pre> |
| |
| <p>In return, the lifecycle of the original application is now handled by the NetBeans Platform |
| and you can leverage as much of the existing modules' functionality as is reasonable for your module. In fact, |
| your original application is now no longer an application, but an integral part of a larger application.</p> |
| --> |
| <!-- ===================================================================================== --> |
| |
| <h2 class="tutorial"><a name="tips"></a>Porting Tips & Tricks</h2> |
| |
| <p>There are several next steps one can take at this point, aside from further aligning |
| the application with the NetBeans Platform, as outlined above:</p> |
| |
| <ul> |
| |
| <li><b>Attain a thorough understanding of what the NetBeans Platform provides.</b> |
| As you port your application, you will learn more and more about the |
| various features that the NetBeans Platform makes available. A central |
| problem is that the NetBeans Platform is quite large and attaining a thorough |
| overview of all that it offers can be a lengthy process. A quick shortcut |
| is to download and print out the <a href="http://refcardz.dzone.com/refcardz/essential-netbeans-platform">Essential NetBeans Platform Refcard</a>, |
| which is a free DZone document that highlights all the NetBeans Platform |
| benefits, features, APIs, and many tips and tricks in an easy |
| to digest format.</li> |
| |
| <li><b>Become aware of the differences between standard Swing applications |
| and the NetBeans Platform.</b> For the most part, the standard Swing approach to |
| creating a user interface will continue to work for your NetBeans Platform |
| application. However, the NetBeans Platform approach is better, easier, or both |
| in some cases. One example is that of the NetBeans Dialogs API. The standard Swing approach, |
| via, for example, the <tt>JOptionsPane</tt>, works OK, but using the NetBeans Dialogs API is easier, |
| because it automatically centers your dialog in the application and allows you to dismiss it |
| with the ESC key. Using the Dialogs API also lets you plug in a different DialogDisplayer, |
| which can make it easier to customize or test your application. |
| |
| <p>Below is a list of the principle differences between the typical Swing approach |
| and that of the NetBeans Platform:</p> |
| |
| <ul> |
| <li>Loading of images</li> |
| <li>Loading of resource bundles and localized string</li> |
| <li>Assigning of mnemonics to labels and buttons</li> |
| <li>Showing dialogs</li> |
| </ul> |
| <p>For details on all of the above items, read |
| this FAQ: <a href="http://wiki.netbeans.org/wiki/view/DevFaqNbIdeosyncracies">Common calls that should be done slightly differently in NetBeans than standard Swing apps (loading images, localized strings, showing dialogs)</a>.</p> |
| |
| <p>In addition, note that, since the NetBeans Platform now handles the lifecycle of your module, since it is |
| now part of the whole application, you can no longer use <tt>System.exit</tt>. Instead, you need to use <tt>LifecycleManager</tt>. To |
| run code on start up, which should only be done when absolutely necessary, you need to use the NetBeans <tt>ModuleInstall</tt> class and, |
| specifically, its <tt>restored</tt> method. A useful reference in this context is <a href="http://www.ociweb.com/jnb/jnbOct2005.html#porting">Porting a Java Swing Application to the NetBeans Platform</a>, |
| by Tom Wheeler, in <a href="http://www.ociweb.com/jnb/jnbOct2005.html#porting">Building A Complete NetBeans Platform Application</a>.</p></li> |
| |
| <li><p><b>Create a module project for each distinct part of your application.</b> The |
| NetBeans Platform provides a modular architecture out of the box. Break your |
| application into one or more modules. Doing so requires some analysis of your |
| original application and an assessment of which parts could best fit within |
| a new module and how to communicate between them. Since the example in this |
| tutorial was simple, we only needed one module. A next step might be to put the |
| <tt>WordLibrary</tt> class in a separate module and expose it as a public API. |
| The <tt>StaticWordLibrary</tt> would be put into another module, providing |
| an implementation of the <tt>WordLibrary</tt> API. Doing so would let other modules |
| provide user interfaces on top of the API provided by the first module, without |
| depending in any way on the implementations.</p> |
| |
| <p>As shown above, you need to put the modules in a module suite. Then set |
| a dependency in the plugin module on the API module, using the Libraries |
| panel in the plugin module's Project Properties dialog box. The size of each module, i.e., |
| when one should create a new module or continue developing within an existing one, is a |
| question of debate. Smaller is better, in general.</p></li> |
| |
| <li><b>Always keep reevaluating what you really need to port.</b> Look at the NetBeans Platform and |
| decide where there is overlap with your own application. Where there is overlap, |
| such as the menu bar and About box, decide what you want to do. Typically, you |
| want to leverage as much as possible from the NetBeans Platform. Therefore, you |
| would port as little as possible from your own application, while keeping as much |
| of it as is useful to you.</li> |
| |
| <li><b>Move distinct parts of your user interface to one or more TopComponents.</b> On the NetBeans |
| Platform, the <tt>TopComponent</tt> class provides the top level Swing container. In effect, |
| it is a window. Move the user interface from your original application to one or |
| more of these windows and discard your original <tt>JFrame</tt>s.</li> |
| |
| <li><b>Copy the Java classes that do not provide user interface elements.</b> We simply |
| copied the original <tt>WordLibrary.java</tt> class. You can do the same with the model |
| of your own Swing applications. You might need to tweak some code to smoothen the transition |
| between the old Swing application and the new NetBeans Platform application, but (as |
| in the case shown in this tutorial) this might not even be necessary.</li> |
| |
| <li><b>Learn from others.</b> Aside from joining the dev@platform.netbeans.org mailing list, |
| also read the following two crucial articles: |
| <ul> |
| <li><a href="http://netbeans.dzone.com/10-tips-4-porting-2-netbeans">Top 10 Tips for Porting to the NetBeans Platform</a></li> |
| <li><a href="http://java.dzone.com/news/how-to-split-into-modules">How to Split an Application into Modules?</a></li> |
| </ul> |
| </li> |
| |
| <li><b>Watch the Top 10 NetBeans APIs Screencast.</b> The <a href="https://platform.netbeans.org/tutorials/nbm-10-top-apis.html">screencast series</a> |
| gives a good overview of the NetBeans Platform, with many useful code snippets and coding patterns.</li> |
| |
| </ul> |
| |
| |
| <div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20NetBeans%20Platform%20Porting%20Tutorial">Send Us Your Feedback</a></div> |
| <br style="clear:both;" /> |
| <!-- ======================================================================================== --> |
| |
| <h2><a name="nextsteps"></a>Next Steps</h2> |
| |
| <p>For more information about creating and developing NetBeans modules, see the following resources:</p> |
| <ul> |
| <li><a href="https://netbeans.org/kb/trails/platform.html">Other Related Tutorials</a></li> |
| <li><a href="https://netbeans.org/download/dev/javadoc/">NetBeans API Javadoc</a></li> |
| </ul> |
| |
| <!-- ======================================================================================== --> |
| |
| |
| </body> |
| </html> |