|  | <!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 Nodes API Tutorial for NetBeans Platform 7.1</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="tboudreau@netbeans.org"/> | 
|  | <meta name="indexed" content="y"/> | 
|  | <meta name="description" | 
|  | content="A walk-through of enhancing Nodes with properties and other decorations."/> | 
|  | <!--      Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. --> | 
|  | <!--     Use is subject to license terms.--> | 
|  | </head> | 
|  | <body> | 
|  | <h1>NetBeans Nodes API Tutorial</h1> | 
|  |  | 
|  | <p>This tutorial shows how to make use of some of the features of the Nodes API | 
|  | in NetBeans.  It shows how to do the following:</p> | 
|  | <ul> | 
|  | <li>Decorate Nodes with icons</li> | 
|  | <li>Use HTML markup to enhance how Nodes are displayed</li> | 
|  | <li>Create properties for display in the property sheet</li> | 
|  | <li>Provide Actions from Nodes</li> | 
|  | </ul> | 
|  |  | 
|  | <p>This tutorial is intended as a follow-on to the | 
|  | <a href="nbm-selection-1.html">NetBeans Selection Management Tutorial</a>, which | 
|  | covers how <code>Lookup</code> is used in managing selection in the NetBeans | 
|  | windowing system, and its <a href="nbm-selection-2.html">follow-on tutorial</a> | 
|  | which demonstrates how to use the Nodes API in managing selection.</p> | 
|  |  | 
|  | <p>As its basis, this tutorial uses the source code created in the first tutorial | 
|  | and enhanced further in the second.  If you have not yet done these tutorials, | 
|  | it is recommended to do them first.</p> | 
|  |  | 
|  | <p><strong class="notes">Note: </strong>This document uses NetBeans Platform 7.1 and | 
|  | NetBeans IDE 7.1. If you | 
|  | are using an earlier version, see <a href="../70/nbm-nodesapi2.html">the previous version | 
|  | of this document</a>.</p> | 
|  |  | 
|  | <p><b>Contents</b></p> | 
|  | <p><img src="../../images/articles/71/netbeans-stamp.png" class="stamp" width="114" height="114" alt="Content on this page applies to NetBeans IDE 7.1" title="Content on this page applies to NetBeans IDE 7.1"/></p> | 
|  | <ul class="toc"> | 
|  | <li><a href="#nodes-background">Creating a Node subclass</a></li> | 
|  | <li><a href="#displayname-html">Enhancing Display Names with HTML</a></li> | 
|  | <li><a href="#icons">Providing Icons</a></li> | 
|  | <li><a href="#actions">Actions and Nodes</a></li> | 
|  | <li><a href="#action-presenters">Presenters</a></li> | 
|  | <li><a href="#propertysheet">Properties and the Property Sheet</a></li> | 
|  | <li><a href="#read-write-properties">Read-Write Properties</a></li> | 
|  | <li><a href="#separate-property-groups">Grouping Property Sets</a></li> | 
|  | <li><a href="#caveats">General Property Sheet Caveats</a></li> | 
|  | <li><a href="#review">Review of Concepts</a></li> | 
|  | <li><a href="#next">Next Steps</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"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td> | 
|  | <td class="tbltd1">version 7.1 or above</td> | 
|  | </tr> | 
|  | <tr> | 
|  | <td class="tbltd1"><a href="http://java.sun.com/javase/downloads/index.jsp">Java Developer Kit (JDK)</a></td> | 
|  | <td class="tbltd1">version 6 or above</td> | 
|  | </tr> | 
|  | </tbody> | 
|  | </table> | 
|  |  | 
|  | <h2><a name="nodes-background"></a>Creating a Node subclass</h2> | 
|  | <p>As mentioned in the <a href="nbm-selection-2.html">previous tutorial</a>, | 
|  | Nodes are <i>presentation objects</i>.  That means that they are not a data | 
|  | model themselves—rather, they are a presentation layer for an | 
|  | <i>underlying data model</i>.  In the Projects or Files windows in the NetBeans | 
|  | IDE, you can see <code>Node</code>s used in a case where the underlying data model is | 
|  | files on disk.  In the Services window in the IDE, you can see them used in a case | 
|  | where the underlying objects are configurable aspects of NetBeans runtime | 
|  | environment, such as available application servers and databases.</p> | 
|  | <p> | 
|  | As a presentation layer, <code>Node</code>s add human-friendly attributes to the | 
|  | objects they model.  The essential ones are:</p> | 
|  | <ul> | 
|  | <li><b>Display Name</b>—a human readable, user-friendly display name</li> | 
|  | <li><b>Description</b>—a human readable, user-friendly description, often shown as a tooltip</li> | 
|  | <li><b>Icon</b>—some glyph that graphically indicates the type of object shown and possibly | 
|  | its state</li> | 
|  | <li><b>Actions</b>—actions that appear on the context menu when the node is | 
|  | right-clicked, which can be invoked by the user</li> | 
|  | </ul> | 
|  | <p>In the preceding tutorial, you used your <code>EventChildFactory</code> class | 
|  | to create <code>Node</code>s, by calling</p> | 
|  | <pre class="examplecode"> | 
|  | new AbstractNode(Children.create(new EventChildFactory(), true), Lookups.singleton(key));</pre> | 
|  | <p>and then calling <code>setDisplayName(key.toString())</code> to provide a basic | 
|  | display name.  There is much more that can be done to make your <code>Node</code>s more | 
|  | user-friendly.  First you will need to create a <code>Node</code> subclass to | 
|  | work with:</p> | 
|  |  | 
|  | <ol> | 
|  | <li>In the My Editor project, right click the package <code>org.myorg.myeditor</code> | 
|  | and choose New > Java Class.</li> | 
|  | <li>When the wizard opens, name the class "EventNode" and press Enter | 
|  | or click Finish.</li> | 
|  | <li>Change the signature and constructors of the class as follows: | 
|  | <pre class="examplecode"> | 
|  | public class EventNode extends AbstractNode { | 
|  |  | 
|  | public EventNode(Event obj) { | 
|  | super (Children.create(new EventChildFactory(), true), Lookups.singleton(obj)); | 
|  | setDisplayName ("Event " + obj.getIndex()); | 
|  | } | 
|  |  | 
|  | public EventNode() { | 
|  | super (Children.create(new EventChildFactory(), true)); | 
|  | setDisplayName ("Root"); | 
|  | } | 
|  |  | 
|  | .... | 
|  | .... | 
|  | .... | 
|  |  | 
|  | </pre> | 
|  | </li> | 
|  | <li>Open <code>MyEditor</code> from the same package, in the code editor.</li> | 
|  | <li>Replace these lines in the constructor: | 
|  | <pre class="examplecode"> | 
|  | mgr.setRootContext(new AbstractNode(new EventChildFactory())); | 
|  | setDisplayName ("My Editor");</pre> | 
|  | with this single line of code: | 
|  | <pre class="examplecode"> | 
|  | mgr.setRootContext(new EventNode());</pre> | 
|  | </li> | 
|  | <li>Now you will make a similar change to the Children object.  Open | 
|  | the <code>EventChildFactory</code> class in the editor, and change its | 
|  | <code>createNodes</code> method as follows: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | protected Node createNodeForKey(Event key) { | 
|  | return new EventNode(key); | 
|  | }</pre> | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  | <h2><a name="displayname-html"></a>Enhancing Display Names with HTML</h2> | 
|  |  | 
|  | <p>The code is now runnable, but so far all you've done is moved logic around.  It | 
|  | will do exactly what it did before.  The only (non-user-visible) difference you | 
|  | now are using a Node subclass instead of just using AbstractNode.</p> | 
|  | <p> | 
|  | The first thing you will do is provide an enhanced display name.  The Nodes and | 
|  | Explorer APIs support a limited subset of HTML which you can use to enhance how | 
|  | the labels for <code>Node</code>s are shown in Explorer UI components.  The following | 
|  | tags are supported:</p> | 
|  | <ul> | 
|  | <li>font color—font size and face settings are not supported, but color is, | 
|  | using standard html syntax</li> | 
|  | <li>font style tags—b,i,u and s tags—bold, italic, underline, strikethrough</li> | 
|  | <li>A limited subset of SGML entities: &quot;, &lt;, &amp;, &lsquo;, | 
|  | &rsquo;, &ldquo;, &rdquo;, &ndash;, | 
|  | &mdash;, &ne;, &le;, &ge;, | 
|  | &copy;, &reg;, &trade;, and &nbsp; | 
|  | </li> | 
|  | </ul> | 
|  |  | 
|  | <p>Since | 
|  | there is no terribly exciting data available from your <code>Event</code>, which | 
|  | only has an integer and a creation date, you'll extend this artificial example, | 
|  | and decide that odd numbered <code>Events</code> should appear with blue text.</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Add the following method to <code>EventNode</code>: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public String getHtmlDisplayName() { | 
|  | Event obj = getLookup().lookup (Event.class); | 
|  | if (obj!=null && obj.getIndex() % 2 != 0) { | 
|  | return "<font color='0000FF'>Event " + obj.getIndex() + "</font>"; | 
|  | } else { | 
|  | return null; | 
|  | } | 
|  | }</pre></li> | 
|  |  | 
|  | <li><p>What the above code accomplishes is this—when painting, the Explorer component showing | 
|  | the nodes calls <code>getHtmlDisplayName()</code> first.  If it gets a non-null | 
|  | value back, then it will use the HTML string it received and a fast, lightweight HTML | 
|  | renderer to render it.  If it is null, then it will fall back to whatever is | 
|  | returned by <code>getDisplayName()</code>.  So this way, any <code>EventNode</code> | 
|  | whose <code>Event</code> has an index not divisible by 2 will have a non-null | 
|  | HTML display name.</p> | 
|  | <p>Run the Event Manager again and you should see the following:</p> | 
|  |  | 
|  | <p> | 
|  | <img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-71.png"/></p> | 
|  |  | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  | <p>There are two reasons for <code>getDisplayName()</code> and | 
|  | <code>getHtmlDisplayName()</code> being | 
|  | separate methods—first, it is an optimization;  second, as you will see later, | 
|  | it makes it possible to compose HTML strings together, without needing to strip | 
|  | <html> marker tags.</p> | 
|  |  | 
|  | <p>You can enhance this further—in the previous tutorial, the date was included | 
|  | in the HTML string, and you have removed it here.  So let's make your HTML string | 
|  | a little more complex, and provide HTML display names for all of your nodes.</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Modify the <code>getHtmlDisplayName()</code> method as follows: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public String getHtmlDisplayName() { | 
|  | Event obj = getLookup().lookup (Event.class); | 
|  | if (obj != null) { | 
|  | return "<font color='#0000FF'>Event " + obj.getIndex() + "</font>" + | 
|  | "<font color='AAAAAA'><i>" + obj.getDate() + "</i></font>"; | 
|  | } else { | 
|  | return null; | 
|  | } | 
|  | }</pre> | 
|  | </li> | 
|  | <li><p>Run the Event Manager again and now you should see the following:</p> | 
|  |  | 
|  | <p><img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-2-71.png"/></p></li> | 
|  | </ol> | 
|  |  | 
|  | <p>One minor thing you can do to improve appearance here:  You are currently using | 
|  | hard-coded colors in your HTML.  Yet NetBeans can run under various look and | 
|  | feels, and there's no guarantee that your hard-coded color will not be the same as | 
|  | or very close to the background color of the tree or other UI component your Node appears in.</p> | 
|  |  | 
|  | <p>The NetBeans HTML renderer provides a minor extension to the HTML spec | 
|  | which makes it possible to look up colors by passing UIManager keys. | 
|  | The look and feel Swing is using provides a UIManager, | 
|  | which manages a name-value map of the colors and fonts a given | 
|  | look and feel uses.  Most (but not all) look and feels find the colors to | 
|  | use for different GUI elements by calling <code>UIManager.getColor(String)</code>, | 
|  | where the string key is some agreed-upon value.  So by using values from | 
|  | UIManager, you can guarantee that | 
|  | you will always be producing readable text.  The two keys you will use are | 
|  | "textText", which returns the default color for text (usually black | 
|  | unless using a look and feel with a dark-background theme), and | 
|  | "controlShadow" which should give us a color that contrasts, but not | 
|  | too much, with the default control background color.</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Modify the <code>getHtmlDisplayName()</code> method as follows: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public String getHtmlDisplayName() { | 
|  | Event obj = getLookup().lookup (Event.class); | 
|  | if (obj != null) { | 
|  | return "<font color='!textText'>Event " + obj.getIndex() + "</font>" + | 
|  | "<font color='!controlShadow'><i>" + obj.getDate() + "</i></font>"; | 
|  | } else { | 
|  | return null; | 
|  | } | 
|  | }</pre> | 
|  | </li> | 
|  | <li><p>Run the Event Manager again and now you should see the following:</p> | 
|  |  | 
|  | <p><img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-3-71.png"/></p></li> | 
|  | </ol> | 
|  |  | 
|  | <p>You'll note above that you got rid of your blue color and switched to plain old | 
|  | black.  Using the value of <code>UIManager.getColor("textText")</code> guarantees us | 
|  | text that will always be readable under any look and feel, which is valuable; | 
|  | also, color should be used sparingly in user interfaces, to avoid the | 
|  | <a href="http://www.catb.org/jargon/html/A/angry-fruit-salad.html">angry fruit salad</a> | 
|  | effect.  If you really want to use wilder colors in your UI, the best bet is to | 
|  | either find a UIManager key/value pair that consistently gets what you want, or | 
|  | create a <a href="http://wiki.netbeans.org/wiki/view/DevFaqModulesGeneral">ModuleInstall</a> | 
|  | class and | 
|  | <a target="other" href="http://core.netbeans.org/source/browse/*checkout*/core/swing/plaf/src/org/netbeans/swing/plaf/util/RelativeColor.java"> | 
|  | <i>derive the color</i></a> <i>from a color you can get from UIManager</i>, or if | 
|  | you are sure you know the color theme of the look and feel, hard-code it on a | 
|  | per-look and feel basis (<code>if ("aqua".equals(UIManager.getLookAndFeel().getID())...</code>).</p> | 
|  |  | 
|  | <h2><a name="icons"></a>Providing Icons</h2> | 
|  | <p>Icons, used judiciously, also enhance user interfaces.  So providing 16x16 pixel | 
|  | icon is another way to improve the appearance of your UI.  One caveat of using | 
|  | icons is, do not attempt to convey too much information via an icon—there are | 
|  | not a lot of pixels there to work with.  A second caveat that applies to both | 
|  | icons and display names is, <i>never use only color to distinguish a node</i>— | 
|  | there are many people in the world who are colorblind.</p> | 
|  |  | 
|  | <p>Providing an icon is quite simple—you just load an image and set it.  You | 
|  | will need to have a GIF or PNG file to use. If you do not have one easily | 
|  | available, here is one you can use:</p> | 
|  |  | 
|  | <p><img src="../../images/tutorials/nodes-2/icon.png" /></p> | 
|  |  | 
|  | <ol> | 
|  | <li>Copy the image linked above, or another 16x16 PNG or GIF, into the same package as | 
|  | the <code>MyEditor</code> class. | 
|  | </li> | 
|  | <li> | 
|  | Add the following method to the <code>EventNode</code> class: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public Image getIcon (int type) { | 
|  | return ImageUtilities.loadImage ("org/myorg/myeditor/icon.png"); | 
|  | }</pre> | 
|  | Note that it is possible to have different icon sizes and styles—the possible | 
|  | int values passed to <code>getIcon()</code> are constants on <code>java.beans.BeanInfo</code>, | 
|  | such as <code>BeanInfo.ICON_COLOR_16x16</code>.  Also, while you can use the | 
|  | standard JDK <code>ImageIO.read()</code> to load your images, <code>ImageUtilities.loadImage()</code> | 
|  | is more optimized, has better caching behavior, and supports branding of images. | 
|  | </li> | 
|  | <li><p>If you run the code now, you will notice one thing—the icon is used for | 
|  | some nodes but not others!  The reason for this is that it is common to use a | 
|  | different icon for an unexpanded versus an expanded <code>Node</code>.  All you | 
|  | need to do to fix this is to override another method.</p> | 
|  |  | 
|  | <p>Add the following additional method to the <code>EventNode</code>:</p> | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public Image getOpenedIcon(int i) { | 
|  | return getIcon (i); | 
|  | }</pre> | 
|  | </li> | 
|  |  | 
|  |  | 
|  | <li><p>Now if you run the Event Manager, all of the Nodes will have the correct icon, as shown below: | 
|  | </p> | 
|  | <p><img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-4-71.png"/></p></li> | 
|  |  | 
|  | </ol> | 
|  |  | 
|  | <h2><a name="actions"></a>Actions and Nodes</h2> | 
|  | <p>The next aspect of <code>Node</code>s you will treat is <i>Actions</i>.  A | 
|  | <code>Node</code> has a popup menu which can contain actions that the user | 
|  | can invoke against that <code>Node</code>.  Any subclass of <code>javax.swing.Action</code> can | 
|  | be provided by a <code>Node</code>, and will show up in its popup menu.  Additionally, there | 
|  | is the concept of <i>presenters</i>, which you will cover later.</p> | 
|  | <p> | 
|  | First, let's create a simple action for your nodes to provide:</p> | 
|  | <ol> | 
|  | <li>Override the <code>getActions()</code> method of <code>EventNode</code> as | 
|  | follows: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public Action[] getActions (boolean popup) { | 
|  | return new Action[] { new MyAction() }; | 
|  | }</pre> | 
|  | </li> | 
|  | <li>Now, create the <code>MyAction</code> class as an inner class of <code>EventNode</code>: | 
|  | <pre class="examplecode"> | 
|  | private class MyAction extends AbstractAction { | 
|  |  | 
|  | public MyAction () { | 
|  | putValue (NAME, "Do Something"); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void actionPerformed(ActionEvent e) { | 
|  | Event obj = getLookup().lookup(Event.class); | 
|  | JOptionPane.showMessageDialog(null, "Hello from " + obj); | 
|  | } | 
|  |  | 
|  | } </pre> </li> | 
|  |  | 
|  | <li><p>Run the Event Manager again and notice that when you right-click | 
|  | on a node, a menu item is shown:</p> | 
|  | <p><img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-5-71.png"/></p></li> | 
|  | <p>When you select the menu item, the action is invoked:</p> | 
|  | <p><img alt="" src="../../images/tutorials/nodes-2/71/technicolor-nodes-6-71.png"/></p></li> | 
|  | </ol> | 
|  |  | 
|  |  | 
|  | <h2><a name="action-presenters"></a>Presenters</h2> | 
|  | <p>Of course, sometimes you will want to provide a submenu or checkbox menu item or | 
|  | some other component, other than a JMenuItem, to display in the popup menu.  This | 
|  | is quite easy:</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Add to the signature of <code>MyAction</code> that it implements <code>Presenter.Popup</code>: | 
|  | <pre class="examplecode">private class MyAction extends AbstractAction implements Presenter.Popup {</pre> | 
|  | </li> | 
|  |  | 
|  | <li>Press Ctrl-Shift-I to fix imports.</li> | 
|  |  | 
|  | <li>Position the caret in the class signature line of <code>MyAction</code> and | 
|  | press Alt-Enter when the lightbulb glyph appears in the margin, and accept | 
|  | the hint "Implement All Abstract Methods".</li> | 
|  |  | 
|  | <li>Implement the newly created method <code>getPopupPresenter()</code> as follows: | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | public JMenuItem getPopupPresenter() { | 
|  | JMenu result = new JMenu("Submenu");  //remember JMenu is a subclass of JMenuItem | 
|  | result.add (new JMenuItem(this)); | 
|  | result.add (new JMenuItem(this)); | 
|  | return result; | 
|  | }</pre></li> | 
|  |  | 
|  | <li><p>Run the Event Manager again and notice that you now have the following:</p> | 
|  | <p> <img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/action-with-presenter-71.png"/> | 
|  | </p> | 
|  | <p>The result is not too exciting—you now have a submenu called "Submenu" with two | 
|  | identical menu items.  But again, you should get the idea of what is possible | 
|  | here—if you want to return a <code>JCheckBoxMenuItem</code> or some other kind | 
|  | of menu item, it is possible to do that.</p> | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  | <h2><a name="propertysheet"></a>Properties and the Property Sheet</h2> | 
|  |  | 
|  | <p>The last subject you'll cover in this tutorial is properties.  You are probably aware that NetBeans | 
|  | IDE contains a "property sheet" which can display the | 
|  | "properties" of a <code>Node</code>.  What exactly "properties" means | 
|  | depends on how the <code>Node</code> is implemented.  Properties are essentially | 
|  | name-value pairs which have a Java type, which are grouped in sets and shown in | 
|  | the property sheet—where writable properties can be edited via their <i>property editors</i> | 
|  | (see <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/PropertyEditor.html"><code>java.beans.PropertyEditor</code></a> | 
|  | for general information about property editors).</p> | 
|  |  | 
|  | <p>So, built into <code>Node</code>s from the ground up is the idea that a Node may | 
|  | have properties that can be viewed and, optionally, edited on a property sheet. | 
|  | Adding support for this is quite easy.  There is a convenience class in the | 
|  | Nodes API, <code>Sheet</code>, which represents the entire set of properties for | 
|  | a Node.  To it you may add instances of <code>Sheet.Set</code>, which represent | 
|  | "property sets", which appear in the property sheet as groups of | 
|  | properties.</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Override <code>EventNode.createSheet()</code> as follows: | 
|  |  | 
|  | <pre class="examplecode">@Override | 
|  | protected Sheet createSheet() { | 
|  |  | 
|  | Sheet sheet = Sheet.createDefault(); | 
|  | Sheet.Set set = Sheet.createPropertiesSet(); | 
|  | Event obj = getLookup().lookup(Event.class); | 
|  |  | 
|  | try { | 
|  |  | 
|  | Property indexProp = new PropertySupport.Reflection(obj, Integer.class, "getIndex", null); | 
|  | Property dateProp = new PropertySupport.Reflection(obj, Date.class, "getDate", null); | 
|  |  | 
|  | indexProp.setName("index"); | 
|  | dateProp.setName("date"); | 
|  |  | 
|  | set.put(indexProp); | 
|  | set.put(dateProp); | 
|  |  | 
|  | } catch (NoSuchMethodException ex) { | 
|  | ErrorManager.getDefault(); | 
|  | } | 
|  |  | 
|  | sheet.put(set); | 
|  | return sheet; | 
|  |  | 
|  | }</pre> | 
|  | </li> | 
|  |  | 
|  | <li>Press Ctrl-Shift-I to Fix Imports.</li> | 
|  | <li>Right click the EventManager and choose Run and then, once it is started up, | 
|  | use Window > Open Editor to show your editor.</li> | 
|  | <li>Select Window > Properties to show the NetBeans property sheet.</li> | 
|  | <li><p>Click in your editor window and move the selection between different | 
|  | nodes, and notice the property sheet updating, just as your <code>MyViewer</code> | 
|  | component does, as shown below:</p> | 
|  |  | 
|  | <p><img alt="" src="../../images/tutorials/nodes-2/71/property-sheet-71.png"/></p> | 
|  |  | 
|  | </li> | 
|  | </ol> | 
|  | <p>The above code makes use of a very convenient class:  <code>PropertySupport.Reflection</code>, | 
|  | which may simply be passed an object, a type, and getter and setter method names, and | 
|  | it will create a Property object that can read (and optionally write) that property | 
|  | of the object in question.  So you use <code>PropertySupport.Reflection</code> a | 
|  | simple way to wire one <code>Property</code> | 
|  | object up to the <code>getIndex()</code> method of <code>Event</code>.</p> | 
|  |  | 
|  | <p>If you want <code>Property</code> objects for nearly all of the getters/setters | 
|  | on an underlying model object, you may want to use or subclass <code>BeanNode</code>, | 
|  | which is a full implementation of <code>Node</code> that can be given a random object | 
|  | and will try to create all the necessary properties for it (and listen for changes) | 
|  | via reflection (how exactly they are presented can be controlled by creating a | 
|  | <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/BeanInfo.html"><code>BeanInfo</code></a> | 
|  | for the class of the object to be represented by the node).</p> | 
|  |  | 
|  | <blockquote> | 
|  | <p><font color="red"><b>Caveat:</b> Setting the <code>name</code> of your properties is | 
|  | very important.  Property objects test their equality based on names.  If you | 
|  | are adding some properties to a <code>Sheet.Set</code> and they seem to be | 
|  | disappearing, very probably their name is not set—so putting one property | 
|  | in a <code>HashSet</code> with the same (empty) name as another is causing | 
|  | later added ones to displace earlier added ones.</font></p> | 
|  | </blockquote> | 
|  |  | 
|  | <h2><a name="read-write-properties"></a>Read-Write Properties</h2> | 
|  |  | 
|  | <p>To play with this concept further, what you really need is a read/write property. | 
|  | So the next step is to add some additional support to <code>Event</code> to | 
|  | make the <code>Date</code> property settable.</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Open <code>org.myorg.myapi.Event</code> in the code editor.</li> | 
|  | <li>Remove the <code>final</code> keyword from the line declaring the <code>date</code> field</li> | 
|  | <li>Add the following setter and property change support methods to <code>Event</code>: | 
|  | <pre class="examplecode"> | 
|  | private List listeners = Collections.synchronizedList(new LinkedList()); | 
|  |  | 
|  | public void addPropertyChangeListener (PropertyChangeListener pcl) { | 
|  | listeners.add (pcl); | 
|  | } | 
|  |  | 
|  | public void removePropertyChangeListener (PropertyChangeListener pcl) { | 
|  | listeners.remove (pcl); | 
|  | } | 
|  |  | 
|  | private void fire (String propertyName, Object old, Object nue) { | 
|  | //Passing 0 below on purpose, so you only synchronize for one atomic call: | 
|  | PropertyChangeListener[] pcls = (PropertyChangeListener[]) listeners.toArray(new PropertyChangeListener[0]); | 
|  | for (int i = 0; i < pcls.length; i++) { | 
|  | pcls[i].propertyChange(new PropertyChangeEvent (this, propertyName, old, nue)); | 
|  | } | 
|  | }</pre> | 
|  | </li> | 
|  | <li>Now, within the <tt>Event</tt>, call the <tt>fire</tt> method above: | 
|  |  | 
|  | <pre>public void setDate(Date d) { | 
|  | Date oldDate = date; | 
|  | date = d; | 
|  | fire("date", oldDate, date); | 
|  | }</pre>    </li> | 
|  |  | 
|  | <li>In <code>EventNode.createSheet()</code>, change the way <code>dateProp</code> is | 
|  | declared, so that it will be writable as well as readable: | 
|  | <pre class="examplecode"> | 
|  | Property dateProp = new PropertySupport.Reflection(obj, Date.class, "date");</pre> | 
|  | Now, rather than specifying explicit getters and setters, you are just providing | 
|  | the property name, and <code>PropertySupport.Reflection</code> will find the | 
|  | getter and setter methods for us (and in fact it will also find the | 
|  | <code>addPropertyChangeListener()</code> method automatically). | 
|  | </li> | 
|  | <li><p>Re-run the module Event Manager, and notice that you can now select an instance of | 
|  | <code>EventNode</code> in <code>MyEditor</code> and actually edit the date value, as shown | 
|  | below:</p> | 
|  | <p> <img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/action-with-presenter-71-2.png"/> | 
|  | </p> | 
|  |  | 
|  | <p><b>Note:</b> The result is persisted when you restart the IDE.</p></li> | 
|  | </ol> | 
|  |  | 
|  | <p>However, there is still one bug in this code—when you change the Date property, | 
|  | you should also update the display name of your node.  So you will make one more | 
|  | change to <code>EventNode</code> and have it listen for property changes on | 
|  | <code>Event</code>.</p> | 
|  | <ol> | 
|  | <li>Modify the signature of <code>EventNode</code> so that it implements | 
|  | <code>java.beans.PropertyChangeListener</code>: | 
|  | <pre class="examplecode"> | 
|  | public class EventNode extends AbstractNode implements PropertyChangeListener {</pre> | 
|  | </li> | 
|  | <li>Press Ctrl-Shift-I to Fix Imports.</li> | 
|  | <li>Placing the caret in the signature line, accept the hint "Implement | 
|  | All Abstract Methods".</li> | 
|  | <li>Add the following line to the constructor which takes an argument of | 
|  | <code>Event</code>: | 
|  | <pre class="examplecode">obj.addPropertyChangeListener(WeakListeners.propertyChange(this, obj));</pre> | 
|  | Note that here you are using a utility method on <code>org.openide.util.WeakListeners</code>. | 
|  | This is a technique for avoiding memory leaks—an <code>Event</code> will only | 
|  | weakly reference its <code>EventNode</code>, so if the <code>Node</code>'s parent | 
|  | is collapsed, the <code>Node</code> can be garbage collected.  If the <code>Node</code> | 
|  | were still referenced in the list of listeners owned by <code>Event</code>, | 
|  | it would be a memory leak. | 
|  | In your case, the <code>Node</code> actually owns the <code>Event</code>, | 
|  | so this is not a terrible situation—but in real world programming, objects in | 
|  | a data model (such as files on disk) may be much longer-lived than <code>Node</code>s | 
|  | displayed to the user.  Whenever you add a listener to an object which you never | 
|  | explicitly remove, it is preferable to use <code>WeakListeners</code>—otherwise | 
|  | you may create memory leaks which will be quite a headache later.  If you instantiate | 
|  | a separate listener class, though, be sure to keep a strong reference to it from | 
|  | the code that attaches it—otherwise it will be garbage collected almost as soon | 
|  | as it is added. | 
|  | </li> | 
|  | <li>Finally, implement the <code>propertyChange()</code> method: | 
|  | <pre class="examplecode"> | 
|  | public void propertyChange(PropertyChangeEvent evt) { | 
|  | if ("date".equals(evt.getPropertyName())) { | 
|  | this.fireDisplayNameChange(null, getDisplayName()); | 
|  | } | 
|  | }</pre> | 
|  | </li> | 
|  | <li><p>Run the module Event Manager again, select a <code>EventNode</code> in the | 
|  | <code>MyEditor</code> window and change its <code>Date</code> property—notice | 
|  | that the display name of the <code>Node</code> is now updated | 
|  | correctly, as shown below, where the year 2009 and is now reflected both | 
|  | on the node and in the property sheet:</p> | 
|  | <p> <img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/action-with-presenter-71-3.png"/> | 
|  | </p> | 
|  |  | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  | <h2><a name="separate-property-groups"></a>Grouping Property Sets</h2> | 
|  | <p>You may have noticed when running Matisse, NetBeans IDE's | 
|  | form editor, that there is a set | 
|  | of buttons at the top of the property sheet, for switching between groups of | 
|  | property sets.</p> | 
|  |  | 
|  | <p>Generally this is only advisable if you have a really large number of | 
|  | properties, and generally it's not advisable for ease-of-use <i>to</i> have a | 
|  | really large number of properties.  Nonetheless, if you feel you need to split | 
|  | out your sets of properties into groups, this is easy to accomplish.</p> | 
|  |  | 
|  | <p><code>Property</code> has the methods <code>getValue()</code> and | 
|  | <code>setValue()</code>, as does <code>PropertySet</code> (both of them | 
|  | inherit this from | 
|  | <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/beans/FeatureDescriptor.html"><code>java.beans.FeatureDescriptor</code></a>). | 
|  | These methods can be used in certain cases, for passing ad-hoc "hints" | 
|  | between a given <code>Property</code> or <code>PropertySet</code> | 
|  | and the property sheet or certain kinds of property | 
|  | editor (for example, passing a default filechooser directory to an editor for | 
|  | <code>java.io.File</code>). | 
|  | And that is the technique by which you can specify a group name (to be | 
|  | displayed on a button) for one or more <code>PropertySet</code>s.  In real world | 
|  | coding, this should be a localized string, not a hard-coded string as below:</p> | 
|  |  | 
|  | <ol> | 
|  | <li>Open <code>EventNode</code> in the code editor</li> | 
|  | <li>Modify the method <code>createSheet()</code> as follows (modified and | 
|  | added lines are highlighted): | 
|  | <pre class="examplecode"> | 
|  | @Override | 
|  | protected Sheet createSheet() { | 
|  |  | 
|  | Sheet sheet = Sheet.createDefault(); | 
|  | Sheet.Set set = sheet.createPropertiesSet(); | 
|  | <b>Sheet.Set set2 = sheet.createPropertiesSet(); | 
|  | set2.setDisplayName("Other"); | 
|  | set2.setName("other");</b> | 
|  | Event obj = getLookup().lookup (Event.class); | 
|  |  | 
|  | try { | 
|  |  | 
|  | Property indexProp = new PropertySupport.Reflection(obj, Integer.class, "getIndex", null); | 
|  | Property dateProp = new PropertySupport.Reflection(obj, Date.class, "date"); | 
|  |  | 
|  | indexProp.setName("index"); | 
|  | dateProp.setName ("date"); | 
|  | set.put (indexProp); | 
|  |  | 
|  | <b>set2.put (dateProp); | 
|  | set2.setValue("tabName", "Other Tab");</b> | 
|  |  | 
|  | } catch (NoSuchMethodException ex) { | 
|  | ErrorManager.getDefault(); | 
|  | } | 
|  |  | 
|  | sheet.put(set); | 
|  | <b>sheet.put(set2);</b> | 
|  | return sheet; | 
|  |  | 
|  | }</pre> | 
|  | </li> | 
|  | <li><p>Run the Event Manager again, and notice that there are now buttons at the top | 
|  | of the property sheet, and there is one property under each, as seen here:</p> | 
|  |  | 
|  | <p> <img style="border:1px solid black" alt="" src="../../images/tutorials/nodes-2/71/other-tab-71.png"/> | 
|  | </p> | 
|  |  | 
|  | </li> | 
|  | </ol> | 
|  |  | 
|  |  | 
|  | <h2><a name="caveats"></a>General Property Sheet Caveats</h2> | 
|  | <p>If you used NetBeans 3.6 or earlier, you may | 
|  | notice that older versions of NetBeans employed the property sheet very heavily | 
|  | as a core element of the UI, whereas it's not so prevalent today.  The reason is | 
|  | simple:  <i>property sheet based UIs are not terribly user-friendly</i>.  That | 
|  | doesn't mean don't use the property sheet, but use it judiciously.  If you have | 
|  | the option of providing a customizer with a nice GUI, do so—your users will | 
|  | thank you.  </p> | 
|  | <p>And if you have an enormous number of properties on one object, try | 
|  | to find some overall settings that encapsulate the most probable combinations of | 
|  | settings.  For example, think of what the settings for a tool for managing imports on a Java | 
|  | class can be—you can provide integers for setting the threshold number of usages of a package | 
|  | required for wildcard imports, the threshold number of uses of a fully qualified | 
|  | class name required before importing it at all, and lots of other numbers ad | 
|  | nauseum.  Or you can ask yourself the question, <i>what is the user trying to | 
|  | do?</i>.  In this case, it's either going to be getting rid of import statements | 
|  | or getting rid of fully qualified names.  So probably settings | 
|  | of <i>low noise, medium noise</i> and <i>high noise</i> where "noise" | 
|  | refers to the amount of fully qualified class/package names in the | 
|  | edited source file would do just as well and be much | 
|  | easier to use.  Where you can make life simpler for the user, do so.</p> | 
|  |  | 
|  | <h2><a name="review"></a>Review of Concepts</h2> | 
|  | This tutorial has sought to get across the following ideas: | 
|  | <p></p> | 
|  | <ul> | 
|  | <li>Nodes are a presentation layer</li> | 
|  | <li>The display names of Nodes can be customized using a limited subset of HTML</li> | 
|  | <li>Nodes have icons, and you can provide custom icons for nodes you create</li> | 
|  | <li>Nodes have Actions;  an Action which implements Presenter.Popup can provide | 
|  | its own component to display in a popup menu;  the same is true for main | 
|  | menu items using Presenter.Menu, and toolbar items using Presenter.Toolbar</li> | 
|  | <li>Nodes have properties, which can be displayed on the property sheet</li> | 
|  | </ul> | 
|  |  | 
|  | <div class="feedback-box"><a href="https://netbeans.org/about/contact_form.html?to=3&subject=Feedback:%20Nodes%20API%207.1%20Module%20Tutoria">Send Us Your Feedback</a></div> | 
|  |  | 
|  | <h2><a name="next"></a>Next Steps</h2> | 
|  | <p>You've now begun to delve into how to get more out of the property sheet in | 
|  | NetBeans.  In the <a href="nbm-property-editors.html">next tutorial</a>, you will | 
|  | cover how to write custom editors and provide a custom inline editor for use | 
|  | in the property sheet.</p> | 
|  |  | 
|  | </body> | 
|  | </html> |