Window System in NetBeans Platform 6.9

NetBeans Platform 6.9 Developer’s Guide


The NetBeans Platform 6.9 is the world’s only modular Swing application framework. It aims
to drastically simplify desktop application development by providing a number of
techniques, patterns, and full-blown Swing components.


Most desktop applications have very similar technical requirements, such as the
following:


• Consistent user interface • Extensibility • Data display • Configuration settings • Help
system • Distribution mechanisms • Online update function • Cross-operating system
support


Fulfilling these technical requirements over and over again for each new application is
expensive, superfluous, and boring. The NetBeans Platform 6.9 gives the developer a
transparent, open source, extensible, and free framework that addresses all of these
technical requirements.


This book doesn’t aim to explicate all that the NetBeans Platform 6.9 offers or to explore
each and every corner of its many features. Rather, this book guides you through the
development of a specific Java desktop application, while showing you everything that is
relevant in the context of the particular application itself. That process, in turn, will lead
you through the main features relevant to the development of most general applications
on the NetBeans Platform 6.9.


The central driver of the book is, therefore, the creation of a complete Java desktop
application, chapter by chapter, step-by-step, sequentially through the progression of
chapters in this book


What This Book Covers


Chapter 1, Module: A module is the basic building block of a NetBeans Platform 6.9
application. In the chapter dealing with this theme, you learn why it makes sense to
develop modular applications, while examining the features of modules, as well as their
interdependencies. Moreover, you examine module versioning and the lifecycle of
modules, as well as the entry points into that lifecycle.


Chapter 2, Forms: Almost every large desktop application needs to provide a number of
forms that accept data from the user. You learn how forms are created for usage on the
NetBeans Platform 6.9, how their layout is set, and how to implement the related handling of
events.


Chapter 3, Window System: The NetBeans Window System, together with the APithat it
exposes, lets you arrange forms on the screen within a docking framework. You learn
how to create windows, what their lifecycle looks like, and how to infl uence that
lifecycle. In addition, you examine how a window is positioned within the layout of the
application, how to influence the window layout, and how to create groups of related
windows.


Chapter 4, Lookup: The Lookup APiprovides a communication mechanism, comparable
to an event bus, which is of central significance in the creation of NetBeans Platform 6.9
applications. You learn how to use the Lookup to find services so that loosely-coupled
communication between modules can be established. You also learn how to listen to the
Lookup so that content can be added dynamically to a NetBeans Platform 6.9 application.
You examine how a Lookup can act as a proxy for another Lookup and how this
functions as the basis of context sensitivity, also known as “selection management”, in
NetBeans Platform 6.9 applications.


Chapter 5, Actions: You learn how to create global actions and how to invoke them from
menus and toolbars. You also examine how to connect actions to shortcuts, allowing
them to be invoked from a keyboard.


Chapter 6, Nodes and Explorer Views: A sophisticated MVC implementation for
displaying business objects is made available via a set of extensible Swing components,
which you can use without very much work at all. You explore how generic hierarchical
models, known as “nodes”, can represent and display business objects in advanced Swing
components called “explorer views”. You use fl at as well as hierarchical structures and
are shown how easily one view can be exchanged for another and how they can be
synchronized with each other. You also spend some time learning about the
asynchronous creation of nodes and how context sensitive actions are attached to a node.
Last but not least, you learn how the properties of a node can be displayed in property
views and how to create the related property editors.


Chapter 7, File System: The File System APilets you access a NetBeans Platform 6.9‘s
virtual filesystem, which serves as the application’s central registry. You learn how to
access the configuration system, as well as other systems that can be created on top of the
same API. Finishing up, you create new folders, files, and attributes in the filesystem.


Chapter 8, Data System: The Datasystems APigives you access to the content of files.
You learn how to extend a NetBeans Platform 6.9 application to provide support for custom
data types. You also discover how the features available to data content can change in
relation to the current status of the underlying file.


Chapter 9, Dialogs: The responsibilities of dialogs in an application extend from the
display of simple messages to the management of step-by-step procedural wizards. In that
context, you learn how to display simple messages, standard dialogs, and sophisticated
multi-step wizards to the user.


Chapter 10, Settings: Large applications, such as those based on the NetBeans Platform 6.9,
typically have many different kinds of users. Not all of them need all the application’s
features and not all of them use those features in the same way. As the application
becomes larger, a centralized approach is needed, so that each module added to the
application can contribute to a centralized Options window. That is the theme of this
chapter, which introduces you to the most important APIs and the entry points into the
centralized Options window.


Chapter 11, Help: HTML files constituting your documentation can be integrated into
the application. When the user clicks on the Help buttons in the application, or when they
invoke an Action to display the entire help content, your HTML files can be displayed to
them. This chapter shows you how to configure the help system and gets you started with
a few help topics, a table of contents, and an indexing system.


Chapter 12, Branding: Branding enables the application’s ancillary details, such as icons
and splash screens, to be customized. For example, you learn how to exchange the
custom splash screen with your own.


Chapter 13, Distribution and Updates: To let you distribute applications, you examine
the various distribution mechanisms for NetBeans Platform 6.9 applications. You generate a
distribution and an installer, with a special focus on how to let an application be updated
online.

Window System in NetBeans Platform 6.9


Large desktop applications need to provide many different views for visualizing
data. These views have to be managed and shown and the NetBeans Platform 6.9
handles these requirements for you out of the box via its docking framework.


While it once might have been sufficient for a docking framework to provide static
fixed window layouts, today the user expects far more fl exibility. Windows should
be able to be opened, movable, and, generally, customizable at runtime. The user
tends to assume that the positions of views are modifiable and that they persist
across restarts of the application. Not only that, but applications are assumed to be
so fl exible that views should be detachable from the application’s main window,
enabling them to be displayed on multiple monitors at the same time. While once the
simple fact of the availability of menus and toolbars was sufficient, today a far more
dynamic handling is needed so that window content can be adapted dynamically.
Connected to these expectations of fl exibility, plugins are increasingly becoming a
standard technology, with the user assuming their windows to be pluggable, too.


In short, the requirements for window management have become quite complex
and can only be met by means of an external docking framework, otherwise all these
various concerns would need to be coded (and debugged, tested, and maintained)
by hand. The NetBeans Platform 6.9 provides all of these features via its docking
framework, known as the NetBeans Window System. It also provides an APito let
you programmatically access the Window System. Together, the Window System and
its APifulfill all the requirements described above, letting you concentrate on your
domain knowledge and business logic rather than on the work of creating a custom
window management facility for each of your applications.


This chapter teaches you the following:



  • How to define views

  • How to position views in the main window

  • How to customize the default window layout

  • How to group views so that they open and close as a unit

  • How to change the persistence of views across restarts of the application


Creating a window


The NetBeans Window System simplifies window management by letting you use
a default component for displaying windows. The default component, that is, the
superclass of all windows, is the TopComponent class, which is derived from the
standard JComponent class. It defines many methods for controlling a window
and handles notification of main Window System events.


The WindowManager is the central class controlling all the windows in the
application. Though you can implement this class yourself, this is seldom done
as normally the default WindowManager is sufficient. Similarly, you typically use
the standard TopComponent class, rather than creating your own top-level Swing
components. In contrast to the TopComponent class, the default WindowManager
cannot manage your own top-level Swing components, so these cannot take
advantage of the Window System API.


Now let’s create a TopComponent and let it be an editor for working with tasks. This
is done easily by using the New Window wizard.



  1. In the Projects window, right-click the TaskEditor module project node and
    choose New | Window.

  2. On the first page of the wizard select Editor for Window Position and Open
    on Application Start
    . Click Next.


  3. In the next page of the wizard, type TaskEditor in Class Name Prefix. This
    prefix is used for all the generated files. It is possible to specify an icon that
    will be displayed in the tab of the new window, but let’s skip that for the
    moment. Click Finish and all the files are generated into your module
    source structure.


  4. Next, open the newly created TaskEditorTopComponent and drag the
    TaskEditorPanel from the Palette, which is where you put it at the end
    of the last chapter, onto the form.

  5. The size of the component automatically adjusts to the required size of
    the panel. Position the panel with the preferred spacing to the left and top
    and activate the automatic resizing of the panel in horizontal and vertical
    direction. The form should now look similar to the following screenshot:


  6. Sta rt the application. You now see a tab containing the new TaskEditor
    Window, which holds your form.



Examining the generated files


You have used a wizard to create a new TopComponent. However, the wizard did
more than that. Let’s take a look at all the files that have been created and at all the
files that have been modified, as well as how these files work together.


The only Java class that was generated is the TopComponent that will contain the
TaskEditor, shown as follows:



@ConvertAsProperties(dtd = “-//com.netbeansrcp.taskeditor//TaskEditor//
EN”, autostore = false)
public final class TaskEditorTopComponent extends TopComponent {
private static TaskEditorTopComponent instance;
/** path to the icon used by the component and its open action */
// static final String ICON_PATH = “SET/PATH/TO/ICON/HERE”;
private static final String PREFERRED_ID = “TaskEditorTopComponent”;
public TaskEditorTopComponent() {
initComponents();
setName(NbBundle.getMessage(TaskEditorTopComponent.class,
“CTL_TaskEditorTopComponent”));
setToolTipText(NbBundle.getMessage(TaskEditorTopComponent.class,
“HINT_TaskEditorTopComponent”));
// setIcon(ImageUtilities.loadImage(ICON_PATH, true));
}
/**This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate=”collapsed” desc=”Generated Code”>
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.
GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.
Alignment.LEADING).addGap(0, 555, Short.MAX_VALUE));
layout.setVerticalGroup(layout.createParallelGroup(
javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 442, Short.MAX_VALUE)
);
}// </editor-fold>
// Variables declaration – do not modify
// End of variables declaration
/**
* Gets default instance. Do not use directly: reserved for
*.settings files only,
* i.e. deserialization routines; otherwise you could get a
non-deserialized instance.
* To obtain the singleton instance, use {@link #findInstance}.
*/
public static synchronized TaskEditorTopComponent getDefault() {
if (instance == null) {
instance = new TaskEditorTopComponent();
}
return instance;
}
/**
* Obtain the TaskEditorTopComponent instance. Never call {
@link #getDefault} directly!
*/
public static synchronized TaskEditorTopComponent findInstance() {
TopComponent win = WindowManager.getDefault().findTopComponent
(PREFERRED_ID);
if (win == null) {
Logger.getLogger(TaskEditorTopComponent.class.getName()).
warning(“Cannot find ” + PREFERRED_ID + ” component.
It will not be located properly in the window system.”);
return getDefault();
}
if (win instanceof TaskEditorTopComponent) {
return (TaskEditorTopComponent) win;
}
Logger.getLogger(TaskEditorTopComponent.class.getName()).
warning(“There seem to be multiple components with the ‘” +
PREFERRED_ID
+ “‘ ID. That is a potential source of errors and
unexpected behavior.”);
return getDefault();
}
@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_ALWAYS;
}
@Override
public void componentOpened() {
// TODO add custom code on component opening
}
@Override
public void componentClosed() {
// TODO add custom code on component closing
}
void writeProperties(java.util.Properties p) {
// better to version settings since initial version
as advocated at
// http://wiki.apidesign.org/wiki/PropertyFiles
p.setProperty(“version”, “1.0”);
// TODO store your settings
}
Object readProperties(java.util.Properties p) {
if (instance == null) {
instance = this;
}
instance.readPropertiesImpl(p);
return instance;
}
private void readPropertiesImpl(java.util.Properties p) {
String version = p.getProperty(“version”);
// TODO read your settings according to their version
}
@Override
protected String preferredID() {
return PREFERRED_ID;
}
}


As expected, the class TaskEditorTopComponent extends the TopComponent class.


Let’s look at it more closely:



  • For efficient resource usage, the generated TopComponent is implemented
    as a singleton. A private constructor prohibits its incorrect usage from
    outside by disallowing direct instantiation of the class. The static attribute
    instance holds the only instance in existence. The static method getDefault
    creates and returns this instance if necessary on demand. Typically,
    getDefault should never be called directly. Instead of this, you should use
    findInstance, which delegates to getDefault if necessary. findInstance
    tries to retrieve the instance using the Window Manager and the ID of the
    TopComponent before falling back to the singleton instance. This ensures the
    correct usage of persistent information.

  • The constructor creates the component tree for the TaskEditorTopComponent
    by calling the method init Components(). This method contains only code
    generated via the NetBeans “Matisse” Form Builder and is read-only in the
    NetBeans Java editor. You can change the code in this method using the
    Form Builder’s Property Sheet, as will be shown later.

  • The static property PreferredID holds the TopComponent ID used for
    identification of the TopComponent. As indicated by its name, the ID can
    be changed by the Window System, if name clashes occur. The ID is used
    throughout all the configuration files.

  • The methods comp onentOpened() and componentClosed() are part of the
    lifecycle of the TopComponent.

  • You learn about the method getPersistenceType() later, in the section
    about the persistence of TopComponents.



What does the Java code do and not do?
The Java code only defines the visual aspects of the
TaskEditorTopComponent and manages the singleton instance of this
component. In no way does the code describe how and where the instance
is shown. That’s the task of the two XML files, described below.


Two small XML files are created by the wizard. The first is the TopComponent’s
settings file:



<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE settings PUBLIC “-//NetBeans//DTD Session settings 1.0//EN”
“http://www.netbeans.org/dtds/sessionsettings-1_0.dtd”>
<settings version=”1.0″>
<module name=”com.netbeansrcp.taskeditor” spec=”1.0″/>
<instanceof class=”org.openide.windows.TopComponent”/>
<instanceof class=”com.netbeansrcp.taskeditor.
TaskEditorTopComponent”/>
<instance class=”com.netbeansrcp.taskeditor.TaskEditorTopComponent”
method=”getDefault”/>
</settings>


The settings file describes the persistent instance of the TopComponent. As you can
see, the preceding configuration describes that the TopComponent belongs to the
module TaskEditor in the specification version “1.0” and that it is an instance of
the types TopComponent and TaskEditorTopComponent. Also described is that the
instance that is created is done so using the method call TaskEditorTopComponent.
getDefault().



<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE tc-ref PUBLIC “-//NetBeans//DTD Top Component in Mode Properties
2.0//EN” “http://www.netbeans.org/dtds/tc-ref2_0.dtd”>
<tc-ref version=”2.0″ >
<module name=”com.netbeansrcp.taskeditor” spec=”1.0″/>
<tc-id id=”TaskEditorTopComponent”/>
<state opened=”true”/>
</tc-ref>


The WSTCREF (Window System creation file) describes the position of the
TopComponent within the main window. This becomes clearer with the following
file. The other important information in the WSTCREF file is the opened state at
application start.


Typically, you do not have to change these two configuration files by hand. This
is not true for the following file, the layer.xml, which you often need to change
manually, to register new folders and files in the filesystem.



<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE filesystem PUBLIC “-//NetBeans//DTD Filesystem 1.2//EN” “http://
www.netbeans.org/dtds/filesystem-1_2.dtd”>
<filesystem>
<folder name=”Actions”>
<folder name=”Window”>
<file name=”com-netbeansrcp-taskeditor.TaskEditorAction.instance”>
<attr name=”component”
methodvalue=”com.netbeansrcp.taskeditor.
TaskEditorTopComponent.findInstance”/>
<attr name=”displayName”
bundlevalue=”com.netbeansrcp.taskeditor.
Bundle#CTL_TaskEditorAction”/>
<attr name=”instanceCreate” methodvalue=”org.openide.windows.
TopComponent.openAction”/>
</file>
</folder>
</folder>
<folder name=”Menu”>
<folder name=”Window”>
<file name=”TaskEditorAction.shadow”>
<attr name=”originalFile” stringvalue=”Actions/Window/com
netbeansrcp-taskeditor-TaskEditorAction.instance”/>
</file>
</folder>
</folder>
<folder name=”Windows2″>
<folder name=”Components”>
<file name=”TaskEditorTopComponent.settings”
url=”TaskEditorTopComponentSettings.xml”/>
</folder>
<folder name=”Modes”>
<folder name=”editor”>
<file name=”TaskEditorTopComponent.wstcref”
url=”TaskEditorTopComponentWstcref.xml”/>
</folder>
</folder>
</folder>
</filesystem>


The layer.xml is integrated into the central registry (also known as the
SystemFileSystem) using the via a registration entry in the module’s manifest
file. The SystemFileSystem is a virtual filesystem for user settings. Each module
can supply a layer file for merging configuration data from the module into the
SystemFileSystem.


The Window System APiand the Actions APireserve a number of folders in the
central registry for holding its configuration data. These folders enable specific
subfolders and files relating to Window System registration to be added to
the filesystem.



  • Let’s have a look at the folder Windows2. Windows2 contains a folder
    named Components, which contains a virtual file with the name of the
    TopComponent and the extension .settings. This .settings file redirects
    to the real settings file. It is used to make the configuration known to the
    Window System.

  • In addition, the Windows2 folder contains a folder named Modes, which
    contains a folder named editor. Modes represent the possible positions at
    which TopComponents can be shown in the application. The editor folder
    contains a .wstcref file for our TopComponent, which refers to the real
    WSTCREF file. This registers the TopComponent in the mode editor, so it
    shows up where typically editor windows are opened, which is the central
    part of the main window.

  • Next, take a look at the folder Actions. It contains a folder named
    Window which contains a file declaring the action opening the
    TaskEditorTopComponent. The name is typically following Java class
    naming conventions with dots replaced by dashes and ending in .instance.
    The declaration of the virtual file itself consists of three critical parts. The
    attribute component describes how to create the component (methodvalue
    declares which method to call). The attribute displayName describes the
    default action name as shown in the example, in menu items. A possible
    declaration is the bundle value which describes the bundle and key to use
    to retrieve the display name. The attribute instanceCreate uses a static
    method call to create a real action to use.

  • The folder Menu describes the application main menu. The folder Window
    contains a .shadow file. The attribute originalFile uses the full path in the
    SystemFileSytem to delegate to the original action declaration. As described
    above, .shadow files are used as symbolic links to real-defined virtual files.
    This declaration adds the action to the real menu bar of the application.


As a result, important parts of the Window System APiare not called
programmatically, but are simply used declaratively. Declarative aspects include
configuration and the positioning of windows, as well as the construction of
the menu.


In addition, you discovered that the wizard for creating TopComponents always
creates singleton views. If you would like to change that, you need to adapt the
code created by the wizard. For the time being, it is sufficient to use the singleton
approach, particularly as it is more resource-friendly.

NetBeans Articles

Comments

comments

Pages: 1 2 3 4

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Speak Your Mind

*