the Dialogs API including the Wizard API
the Visual Library and the Palette
the Status Bar and Notifications
How to use the progress bar
QuickSearch and the Output window
How to define and persist the settings of your application in the Options window
How to brand and distribute your application
Let’s get started.
Dialogs API
The Dialogs API is similar to javax.swing.JOptionPane and lets you create and display dialogs and wizards in an easy way. One can display predefined dialogs, custom dialogs, and multi-step wizards.
Displaying a dialog requires two steps: creating a NotifyDescriptor to configure the dialog, and a DialogDisplayer to display it. Before you use it, add a dependency to the Dialogs API module.
Predefined Dialogs
Display a message dialog using the Dialogs API
Display a confirmation dialog using the Dialogs API
OK_OPTION: The OK button was clicked.
YES_OPTION: The Yes button was clicked.
NO_OPTION: The No button was clicked.
CANCEL_OPTION: The Cancel button was clicked.
CLOSED_OPTION: The dialog was closed without any button having been pressed.
Display an input dialog using the Dialogs API
Display an error dialog using the Dialogs API
NotifyDescriptor.DEFAULT_OPTION
NotifyDescriptor.OK_CANCEL_OPTION
NotifyDescriptor.YES_NO_OPTION
NotifyDescriptor.YES_NO_CANCEL_OPTION
NotifyDescriptor.PLAIN_MESSAGE
NotifyDescriptor.INFORMATION_MESSAGE
NotifyDescriptor.QUESTION_MESSAGE
NotifyDescriptor.WARNING_MESSAGE
NotifyDescriptor.ERROR_MESSAGE
Display a dialog with custom buttons using the Dialogs API
As an exercise, replace JOptionPane instances with the Dialogs API in the TodoRCP application of the previous chapter.
Custom Dialogs
Display a custom dialog using the Dialogs API
In short, you can pass any kind of java.awt.Component as the first parameter. As an example, let’s extend our TodoRCP application by providing a Login dialog asking for credentials when the application starts, at which point the application should be blocked until the user has been authenticated.
Securing Access
- 1.
Create a new module, as explained in Chapter 7, making sure to add it to the TodoRCP module suite. Name the module Login and give it the Code Base Name todo.login.
- 2.
Open the Login module, if not already open; right-click on the todo.login package; select New ➤ Other from the pop-up menu to display the New File dialog; select the category Swing GUI Forms; and select the JPanel Form file type. Click Next.
- 3.
In Step 2, enter LoginPanel in the Class Name field and click Finish.
- 4.Create the login form shown in Figure 10-6 using:
A label for Username: lblUsername
A label for Password: lblPassword
A label for the error message displayed on the bottom (shown as a red rectangle in Figure 10-6 but will be invisible on your form): lblInfo
A text field for Username: txtUsername
A password field for Password: txtPassword
- 5.
Switch to Source view in the editor window, and add the following methods in Listing 10-7 at the end of the LoginPanel class
Access methods of the LoginPanel
- 6.
Create a new module installer by right-clicking on the todo.login package and selecting New ➤ Other, then Module Development category followed by Installer / Activator as the file type. Then complete the code as shown in Listing 10-8. Notice that apart from createDialog(), that DialogDisplayer also offers both notify() and notifyLater(). The latter allows displaying the Dialog immediately after the initialization phase, which is directly after the splash screen.
The Module Installer class allows the login dialog to be displayed on application start-up
Module Installer actionPerformed() method implementation
The validate(String username, char[] password) method checks in the database whether the provided credentials are valid. You may find its implementation in the source code of the book.
Disallow closing the dialog from the X close button
A module installer using the @OnStart annotation
Wizards
You have already encountered how to use the NetBeans wizards (or multi-pane dialogs) by creating a new File or Project from the File menu of the IDE. The good news is that you can create your own wizards for your projects by using the Dialogs API. Additionally, NetBeans provides a wizard for creating wizards. To use it, right-click on your module, choose New ➤ Other, then choose Module Development category followed by Wizard file type, and click Next.
For custom wizards, you can choose if the wizard should pass through a sequence of separate steps in a linear fashion that are fixed and don’t change (Static), or dynamically based on the choices made by the user (i.e., the user will be able to skip some steps). The first option creates code that lets the user pass through the sequence of panels forward and backward without branching off or skipping panels. The second creates code that, by default, gives you full control over the order of the panels and allows a dynamic ordering of the panels to be created.
Static Wizards
AddTaskWizardAction: the action to invoke the wizard. You need to comment-in the annotations on top in order to register the action to a menu or a toolbar. Listing 10-12 shows these annotations.
Annontations of the AddTaskWizardAction that have been commented-in in order to register the action to a menu or toolbar
At the end of the actionPerformed() method, you need to gather all data and create/update your model. For an example, see Listing 10-13.
actionPerformed() method implementation
AddTaskWizardPanel1, AddTaskWizardPanel2, AddTaskWizardPanel3: WizardDescriptor.Panel classes are responsible for controlling each step. They check the validity of entered values (via method isValid()), support context sensitive help (by returning a help context via the getHelp() method), and initialize the visual panels by reading settings (readSettings() method) as well as storing settings (storeSettings() to be read the next time the user visits this panel or by the other panels). Usually you define an interface with some constant property names to be used by these methods as keys to save the properties. If a wizard panel’s valid status depends on user input, the wizard panel must implement addChangeListener() and removeChangeListener() and fire state change events to its ChangeListeners.
AddTaskVisualPanel1, AddTaskVisualPanel2, AddTaskVisualPanel3: JPanels for the visual representation of each step.
You may also use the Simple Validation API (ide/modules/ext/ValidationAPI.jar) for your validations. You need to wrap it to a module (e.g., in the Libraries module of the TodoRCP application) and make org.netbeans.validation.api public. You may also add ValidationPanel to the palette to use it to your panels (with the help of the Palette Manager). The API provides a number of useful validators: REQUIRE_NON_EMPTY_STRING, NO_WHITESPACE, REQUIRE_VALID_INTEGER, REQUIRE_NON_NEGATIVE_NUMBER, numberRange(minValue, maxValue), EMAIL_ADDRESS, FILE_MUST_EXIST, URL_MUST_BE_VALID, REQUIRE_JAVA_IDENTIFIER, REQUIRE_VALID_FILENAME. You may create your own, too, if you are not satisfied with them. Once you have dropped a ValidationPanel to your JPanels, you can validate the input there (and not in the WizardDescriptor.Panel) by calling group = validationPanel1.getValidationGroup() and then group.add()adding one or more of the validators above.
Dynamic Wizards
A dynamic wizard
Registration of the dynamic wizard to a file type
During execution, an entry to execute the above wizard can be found in the File ➤ New dialog wizard inside category Other. To register the dynamic wizard that you created earlier to a category of the File ➤ Project dialog wizard, enter, for example, folder = "Projects/Other".
Instead of InstantiatingIterator , the AddTaskWizardIterator may also extend AsynchronousInstantiatingIterator (the instantiate() method is invoked outside the EDT), BackgroundInstantiatingIterator (the wizard closes and the instantiate() method is invoked in a background thread), or ProgressInstantiatingIterator (the instantiate() method is invoked outside the EDT and it is called with a ProgressHandle to display its progress in a progress bar, which is described later in this chapter).
WizardPanel, instead of WizardDescriptor.Panel, may also extend WizardDescriptor.ValidatingPanel (for additional validation when the Next or Finish button is clicked), WizardDescriptor.AsynchronousValidatingPanel (for asynchronous validation), WizardDescriptor.ExtendedAsynchronousValidatingPanel (prefer this to AsynchronousValidatingPanel), or WizardDescriptor.FinishablePanel (when Finish button needs to be dynamically enabled; this allows the user to click the Finish button before the final step, because for example s/he accepts the default values of the following steps).
Other Properties of Wizards
PROP_AUTO_WIZARD_STYLE: set to true to enable using the other properties.
PROP_CONTENT_BACK_COLOR: set background color of left pane.
PROP_CONTENT_DATA: sets the array of content items.
PROP_CONTENT_DISPLAYED: set to true for displaying the left pane.
PROP_CONTENT_FOREGROUND_COLOR: set foreground color of left pane.
PROP_CONTENT_NUMBERED: set to true for displaying numbers in the left pane.
PROP_CONTENT_SELECTED_INDEX: represents index of left pane that will be highlighted.
PROP_ERROR_MESSAGE: error message displayed at bottom of the wizard. The wizard’s Next button is disabled when there are errors.
PROP_IMAGE: set the image to be displayed in the left pane.
PROP_IMAGE_ALIGNMENT: set the image’s alignment.
Finally, regarding the other two options displayed in Figure 10-7, consult the documentation at http://wiki.netbeans.org/HtmlUIForTemplates.
As an exercise, build a custom static wizard for the AddTask action. The wizard will contain three steps, and the first panel will ask for the description and the priority of a task (description is mandatory); the second panel the due date, the alert, and the days before; and the third panel the observations and whether the task is completed or not. Try also to create the same wizard for the TodoFXRCP application. Hint! Use JFXPanels in place of JPanels.
As another exercise, use the New File with HTML/Java UI wizard to create a wizard to add a new task for the TodoHTMLJava application.
Miscellaneous
Here we describe some APIs of the NetBeans Platform that you may find useful in your projects.
Status Bar
Display a message in the status bar
Notifications
Display a ballon-shaped pop-up in the status bar
Display a ballon-shaped pop-up with an icon in the status bar
If ActionListener is not null, then a hyperlink is displayed that, when clicked, executes the action. Priority can be: HIGH, NORMAL, LOW, or SILENT.
ImageUtilities
org.openide.util.ImageUtilities is a utility class providing static methods for manipulation and conversion of images and icons. Results are cached. Useful methods include loadImage(), loadImageIcon(), icon2Image(), image2Icon, mergeImages(), etc. We saw an example in Listing 10-18.
Quick Search
XML tags in layer.xml to display the quick search field in the toolbar
Display the quick search in the menu bar instead of the toolbar
If you need to add the quicksearch filter tool to your own panel/toolbar, then follow the tricks found here: http://layerxml.wordpress.com/2011/02/16/place-the-quicksearch-component-anywhere-you-like/, and also at https://blogs.oracle.com/geertjan/place-the-quicksearch-component-anywhere-you-like-part-2.
TaskSearchProvider generated by the Quick Search Provider wizard
The SearchRequest class provides the description of the quick search request. The methods getText() and getShortcut() give you access to the text and shortcut typed into the search field. Typically, the text entered in the search field is matched against an object in the Lookup. When a match succeeds, the object is added to SearchResponse, which is the response object for collecting the results of the SearchRequest and displaying them in the search field drop-down list.
Example implementation of SearchProvider
QuickSearch folder generated in layer.xml from the Quick Search Provider wizard
QuickSearch is not to be confused with QuickFilter. Check ShowCompletedTasksAction implementation in the source code bundle to see how to filter the OutlineView (see also https://jnkjava.wordpress.com/2014/02/26/recipe-9-how-to-filter-an-outlineview/). You may also add your own custom quick filter in order to filter the OutlineView by following the instructions described in this blog (https://jnkjava.wordpress.com/2015/02/01/recipe-14-how-to-add-a-quick-filter/).
Output Window
The Output window is a display area, usually at the bottom of the NetBeans IDE window, for showing messages to the user (see Figure 10-13). Messages from multiple sources can be displayed in different tabs simultaneously.
Output window code example
Settings
As you can see in Figure 10-14, there are Primary panels (for example General, Miscellaneous) and Secondary panels (for example Formatting, Hints, etc.). The Primary Panels can be used to configure the most important groupings of settings in an application. Secondary Panels can be used for less important settings needed for configuring the application. You can also export and import your settings with the two respective buttons in the bottom left of the Options window.
package-info.java contents
The TasksOptionsPanelController for the secondary panel
Whatever you set in this panel is persisted (stored) into the NetBeans Platform user directory with the help of org.openide.util.NbPreferences class to be available the next time you open the application.
You can easily locate the NetBeans Platform user directory by displaying the About dialog box from Help ➤ About or NetBeans ➤ About NetBeans (in MacOS) and verifying the User Directory entry (see Figure 10-16).
Progress
More often than not, when dealing with large amounts of data, the calculation and display of them may take some noticeable time to the user. For example, retrieving data from a filesystem or database can take several seconds on a good day. As a good User Experience rule, the user should be given some visual feedback of the progress that a long task takes.
For example, expanding a Node that creates child elements synchronously in the Event Dispatch Thread (EDT) will freeze the UI. During this time, no UI updates are performed and user gestures are ignored, making the UI unusable for the duration of the process. That is the reason why creating the child elements is done in a different thread. Meanwhile, you should inform the user that child elements are being created and are about to be displayed. During this time, normally a wait cursor and a status message are shown.
In Chapter 8 we saw how ChildFactory class offers support for creating child elements asynchronously (by passing true as the second parameter of the Children.create() method).
By default, the NetBeans Platform status bar has an integrated progress bar. When you are working with long-running tasks, you can plug into the progress bar to let the user visualize progress, either of a single task or multiple tasks.
To plug into the progress bar, you need to add a dependency to the Progress API. The ProgressHandleFactory creates ProgressHandle objects, which display progress and, optionally, enables the user to cancel the progress display. Progress can be displayed with a definite or an indefinite runtime.
Example to display the progress of loading a large number of tasks
To handle a long task that spans many modules, use the ProgressContributor as described in the API (http://bits.netbeans.org/dev/javadoc/org-netbeans-api-progress/index.html).
Visual Library
The Visual Library is used to display selectable, movable, and changeable graphic components (called widgets) on a Scene. The Visual Library is based on Java2D and uses a lightweight window system so that it can be used with Swing, JavaFX, etc.
The Visual Library is normally used in combination with the Component Palette, which allows for dragging and dropping items onto components (like Scenes). To open your appetite, you may start your adventure by exploring the Visual Library examples (https://platform.netbeans.org/graph/examples.html) to see the capabilities of the library as well as take a look at some tutorials and real applications that actually use it (https://platform.netbeans.org/graph/).
Before you can use the Visual Library in your projects, you need to add the Visual Library API from the platform cluster, which is not added by default. You do this by right-clicking on your Module suite and selecting Properties as described and illustrated earlier in Figure 10-10.
The main classes of the Visual Library are described in the subsections to follow.
Widgets
A variety of Widget implementations are provided by the Visual Library (see Figure 10-18), each incorporating predefined behavior consisting of customizable actions, borders, and layouts. Together, Widgets are arranged and displayed in a Scene, of which there are various implementations, too (see Figure 10-17).
A Widget with a Lookup to store model objects
This Lookup is usually proxied by the TopComponent that contains the visual components, which is in turn proxied by Utilities.actionsGlobalContext(), as we have learned in the previous chapters.
Scene
The Scene (see Figures 10-17 and 10-18) is a kind of Widget, too. It is a top-level Widget (the root element of the hierarchical tree structure) that contains other Widgets. It is usually displayed in a Swing component like, for example, a JScrollPane. There are various types of Scenes as one can see in Figure 10-17. For example, ObjectScene maps a Widget to a data object. GraphScene, GraphPinScene and VMDGraphScene (VMD stands for Visual Mobile Designer) are used to simplify creating graphs.
Steps to create a Scene
With createView() or createSatelliteView() methods, you create a JComponent that can be embedded in any Swing container. Similarly, with getSceneAnimator() method, you can create a SceneAnimator (which contains a few built-in animations). LayerWidget acts like a JGlassPane and it is typically used as a container for other widgets.
ConnectionWidget
The ConnectionWidget represents a connection between two locations. The locations are resolved by Anchors (see Figure 10-19). The path of the connection is specified by control points, which are resolved by Routers (see Figure 10-20).
Borders
Define a Border for a Widget
Layouts
A widget can be a container for additional widgets and also has a layout defined and managed by a LayoutManager . The following layout variants are provided:
Define a layout for a Widget
WidgetAction
The behavior of a Widget is described by its Actions, which are defined by the WidgetAction interface (see Figure 10-21). This interface defines methods called by corresponding events, such as the click of a mouse on the Widget to which the Action is assigned. The Visual Library provides predefined Actions, which can also be customized, for standard functionality, such as moving and editing of Widgets. Examples of Actions include MoveAction, HoverAction, ZoomAction, PanAction.
Actions do not need to be defined and instantiated. Instead, they are assigned to a Widget by the ActionFactory class. To create actions for widgets, use ActionFactory and add them to the widgets with method addAction() (see Listing 10-32). Some ActionFactory methods require a provider (such as the EditAction). Other actions have default providers (such as the MoveAction). If you wish to deviate from the default behavior, though, use another provider.
Available providers: AcceptProvider, ConnectProvider, ContiguousSelectProvider, CycleFocusProvider, EditProvider, HoverProvider, InplaceEditorProvider, MoveControlPointProvider, MoveProvider, PopupMenuProvider, ReconnectProvider, RectangularSelectProvider, ResizeProvider, SelectProvider, TwoStateHoverProvider.
Add an action to a Widget
Palette
You usually use the Visual Library in combination with the Palette to drag Widgets from the Palette to a Scene. The Palette is a TopComponent containing items that can be dragged and dropped onto a component of your choice within any other TopComponent.
Associate the Palette with the TopComponent’s Lookup
By default, when an item is dragged from a Palette, it cannot be dropped. You must explicitly define a component as a drop target; otherwise it cannot be a recipient of a Palette’s drop event. If you wish to combine the Palette with the Visual Library, then the drop target is a Scene.
Create a new LabelWidget when drag&drop on a Scene
As an exercise, add a new module (Visual, todo.visual) to TodoRCP that allows the user to drop the Tasks stored in the application from the Palette on a Scene. The user should also be able to connect tasks in order to show dependencies among them.
Branding, Distribution, and Internationalization
- 1.
Right-click your project and select Branding. Here you can select a splash screen and the icon to display when the application is minimized as well as the title to show in the application’s title bar. You can also control the windows behavior of your application (for example, you may disable floating) and finally internationalize the application, that is, change the UI in your preferred language (Internationalization Resource Bundles tab) by translating the resource bundles to that language.
- 2.
Right-click your project and select Properties. In the Application category, you can change the application’s name. In the Libraries category, you can choose which clusters and modules to include to improve performance.
- 3.
To create a distributable .zip or installer of your application, right-click your project, select Properties, and then the Installer category. Check the platform(s) that you wish to create installer(s) for (such as Windows, Mac OSX, Solaris, and Linux), and click OK. You may also provide a license. Right-click the project again, and select Package as and select one of the available options, such as Installers or Zip distribution.
If everything ran smoothly, you created a new dist folder inside your project’s folder, which contains the deployed application. Unzip it, if needed, navigate inside (for example, dist/todorcp/bin) and execute the executable file (depending on your platform, which could be, for example, todorcp.exe or something similar).
- 1.
Enable the Auto Update Services and Auto Update UI modules in the platform cluster (see Figure 10-10). After clean and build, verify that you have a Tools ➤ Plugins menu item that opens the Plugin Manager.
- 2.
Right-click on the project, and select Package as ➤ NBMs. An .nbm (or NetBeans Module) file is created for each module in the build/updates/ directory. The Update Center descriptor (updates.xml) is also created. You need to publish these files to a web server.
- 3.
In the Plugin Manager window, click on Settings tab, then click Add and enter the URL to the Update Center descriptor (updates.xml).
- 4.
Here (https://www.codenameone.com/blog/netbeans-plugin-update-center.html) is an example.
Summary
Table 10-1 shows a grouping of modules that provide functionality from the Apache NetBeans Platform. The table is a summary of the provided functionality by that platform. You may use most of the jar files mentioned in the table outside the NetBeans IDE, that is, using another IDE or a text editor to develop an application based on Apache NetBeans RCP.
Apache NetBeans Platform Modules Overview
Modules grouping | Provided functionality |
---|---|
Core | |
boot.jar core.jar org-openide-filesystems.jar org-openide-modules.jar org-openide-util-lookup.jar org-openide-util.jar | Provide the runtime container. |
org-netbeans-modules-masterfs.jar | Provides the central registry file system functionality (a.k.a. layer). |
UI | |
org-netbeans-core.jar org-netbeans-core-execution.jar org-netbeans-core-ui.jar org-netbeans-core-windows.jar | Provide the basic UI components. |
org-netbeans-windows.jar | Provides the API for processing the window system. |
org-openide-actions.jar | Provides a number of configurable system actions (for example “Cut,” “Copy,” “Paste”). |
org-openide-nodes.jar org-openide-explorer.jar org-netbeans-swing-outline.jar | Provide the APIs for Nodes and Explorer views, that is, the UI part of the platform. |
org-netbeans-core-multiview.jar | Provides the MultiView window. |
org-netbeans-swing-plaf.jar org-netbeans-swing-tabcontrol org-jdesktop-layout.jar | Provides the look and feel and the display of tabs and a wrapper for the Swing Layout Extensions library. |
Extras | |
org-openide-awt.jar | Provides many helper classes for displaying UI elements (for example notifications, see Figure 10-8). |
org-openide-dialogs.jar | Provides an API for displaying standard and customized dialogs and wizards (see beginning of this chapter). |
org-netbeans-api-visual.jar | Provides the widget and graph library API for modeling and displaying visual representations of data. |
org-netbeans-spi-quicksearch.jar | Provides the API for integrating items into the Quick Search field (see Figure 10-9). |
org-netbeans-modules-options-api.jar | Provides the Options window API (see Figure 10-14). |
org-netbeans-modules-settings.jar | Provides an API for saving module-specific settings in a user-defined format. |
org-netbeans-api-progress.jar org-openide-execution.jar org-netbeans-modules-progress-ui.jar | Provides support for asynchronous long-running tasks and integration for long-running tasks with the NetBeans Platform’s progress bar. |
org-netbeans-core-output2.jar org-openide-io.jar | Provides the Output window (see Figure 10-13). |
org-netbeans-modules-autoupdate-services.jar org-netbeans-modules-autoupdate-ui.jar | Provides the update center and plugins functionality. |
org-netbeans-modules-favorites.jar | Provides the Favorites window functionality (menu Window ➤ Favorites). |
org-openide-loaders.jar | Provides an API to work with file types. |
org-netbeans-modules-mimelookup.jar org-netbeans-modules-editor-mimelookup.jar | Provides an API for discovery and creation of settings specific to file types. |
org-netbeans-modules-javahelp.jar | Provides the JavaHelp runtime library that enables JavaHelp sets from different modules to be merged into a single help set. |
org-netbeans-modules-queries.jar | Provides an API for getting information about files and an SPI for creating your own queries. |
org-netbeans-modules-sendopts.jar | Provides an API and SPI for registering your own handlers for accessing the command line. |
org-openide-text.jar | Provides an extension to the javax.swing.text API. |