Thursday 10 November 2011

Automatic window lifecycle management


A further major advantage of the NetBeans Window System is that it provides a WindowManager that controls the lifecycle of all the windows defined in the application. The WindowManager notifies allTopComponents about state changes using callback methods, listed as follows:

componentOpened()It is called after the TopComponent has been opened. If multiple TopComponents are opened into the same position (called mode), the NetBeans Window System uses a tabbed container, with one TopComponent per tab. Of all available TopComponents found within a shared tabbed container, only the content of the selected TopComponent is visible.
componentShowing()It notifies the component that its content is now visible. This TopComponent is now either selected or is the only component in a separate container.
componentActivated()It is called after the TopComponent has gained the input focus or has become the selected component.
componentDeactivated()It is called after the TopComponent has lost the input focus.
componentHidden()It notifies the TopComponent that its content is no longer visible.
componentClosed()It is called after the TopComponent has been closed.
Let's illustrate this lifecycle via an example that logs all the callback methods to the output window of NetBeans IDE, which is your development environment on top of the NetBeans Platform.
  1. Create a new NetBeans Platform application and name it WindowSystemExamples.
  2. Add a new module named LifeCycle, with Code Name Base com.netbeansrcp.lifecycle.
  3. Add a TopComponent, with Class Name Prefix prefix LifeCycleDemo, making sure to indicate that it should be automatically opened in the editor area at application startup.
  4. Override the lifecycle methods as follows:
    public void componentOpened() { super.componentOpened(); System.out.println("componentOpened()"); } protected void componentShowing() { super.componentShowing(); System.out.println("componentShowing()"); } protected void componentActivated() { super.componentActivated(); System.out.println("componentActivated()"); } @Override protected void componentDeactivated() { super.componentDeactivated(); System.out.println("componentDeactivated()"); } @Override protected void componentHidden() { super.componentHidden(); System.out.println("componentHidden()"); } @Override public void componentClosed() { super.componentClosed(); System.out.println("componentClosed()"); }
Start the new application. The TopComponent LifeCyleDemoTopComponent is automatically opened at startup. Select the TopComponent and inspect the output in the NetBeans IDE Output Window. You should see the following:
componentOpened() componentShowing() componentActivated()
The TopComponent has passed the first half of its lifecycle and is now activated.
Close the LifeCyleDemoTopComponent and inspect the output again, to understand the second half of the TopComponent lifecycle. You should see the following output:
componentHidden() componentDeactivated() componentClosed()
You have learned that the TopComponent's lifecycle is automatically controlled by the NetBeans Platform. Between the start and the end of the TopComponent's lifecycle are six different states, all managed by the NetBeans Platform, and with notifications sent via callbacks.

Programmatically managing the Window lifecycle

You can manage the lifecycle of a TopComponent programmatically. For this purpose, theTopComponent provides the following methods:
  • open(): Opens the TopComponent
  • requestVisible(): Requests to select to TopComponent
  • requestActive(): Requests to transfer the input focus to the TopComponent
Let's now modify the LifeCycleDemoTopComponent for demonstration purposes.
  1. Add a JButton to the TopComponent, as follows:
  2. Implement an ActionEventListener as follows:
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { this.close(); RequestProcessor.getDefault().post(new java.lang.Runnable() { public void run() { java.awt.EventQueue.invokeLater(new java.lang.Runnable() { public void run() { com.netbeansrcp.lifecycle.LifeCycleDemoTopComponent.this.open(); } }); } }, 3000); RequestProcessor.getDefault().post(new java.lang.Runnable() { public void run() { java.awt.EventQueue.invokeLater(new java.lang.Runnable() { public void run() { com.netbeansrcp.lifecycle. LifeCycleDemoTopComponent.this.requestActive(); } }); } }, 6000); }
  3. Restart the application. When you click the button, the LifecycleDemoTopComponent is closed via the close() method, called above in the first line of the code you entered.
The RequestProcessor provides a thread pool. The default instance of this pool lets you execute aRunnable after a short delay, thanks to the post() method. As the TopComponent's lifecycle method should be called from the AWT event thread, you do not call them directly in the run() method, but by posting a new Runnable to the EventQueue, which in the end calls the Window System API methods.
The argument 3000 ensures that the execution of the Runnable is delayed for 3000 ms so that theTopComponent is opened again after 3 s.
After six seconds the second Runnable posted to the EventQueue is executed and requestActive() is called for your LifecycleDemoTopComponent. Your TopComponent is now shown in the foreground, if it had been behind other windows previously.
You have learned how to manage the lifecycle of a TopComponent. Via the example you have seen how to open a TopComponent and make it focusable.

Positioning of windows

The NetBeans Window System divides the available space in the main window into areas that are called "modes". Each mode represents a specific area of the main window, providing a container for windows in a predefined position in the frame. You can add windows, that is, TopComponents, to a mode, either declaratively or programmatically.
A standard layout is provided by the NetBeans Window System, corresponding to the layout of NetBeans IDE. For example, the predefined modes correspond to the names used in the corresponding positions in NetBeans IDE, such as "editor" and "explorer". If needed, you can define your own modes, too. No wizard is provided for this purpose in NetBeans IDE, so you need to create the mode definition files yourself manually.
In the previous section you learned about the layer.xml file. To create a default layout for an application, each TopComponent needs to be declaratively registered within the Windows2 | Modes folder, within a subfolder named after the mode in which the TopComponent should be docked.
To demonstrate declarative registration of TopComponents, edit the layer.xml in the LifeCycle module, changing the folder name Windows2 | Modes | editor to Windows | Modes | rightSlidingSide, as shown in the following code snippet:
layer.xml // <folder name="Windows2"> <folder name="Components"> <file name="LifecycleDemoTopComponent.settings" url="LifecycleDemoTopComponentSettings.xml"/> </folder> <folder name="Modes"> <folder name="rightSlidingSide"> <file name="LifecycleDemoTopComponent.wstcref" url="LifecycleDemoTopComponentWstcref.xml"/> </folder> </folder> </folder> //
Select Clean and Build on the application node in the Projects window, to remove the build folder containing the last used window layout, and start the application again. When the application starts up, notice that the LifecycleDemoTopComponent is not opened in the editor mode. Instead, it is represented by a button on the right sidebar of the application (as shown in the screenshot below). That is therightSlidingSide mode, providing a container for minimized windows.
As you have seen, providing a default layout via declarative registrations of TopComponents is rather easy. You only need to create an entry in the layer.xml for the TopComponent, in a folder with the name of the desired mode, within the Windows2 | Modes folder.
Sometimes declarative registration alone is too static for your business needs. Fortunately, positioning ofTopComponents can also be done programmatically. In the next example, you create a TopComponentthat moves to new modes via a click of a button.
  1. Add to the WindowSystemExamples application a new module named Modes, with the Code Name Base com.netbeansrcp.modes.
  2. Within the module, create a TopComponent called ModesDemo, which is opened when the application starts into the "editor" mode.
Add two JButtons to the TopComponent with the texts Back and Forward, as well as a JLabel with an empty initial text. The TopComponent should look as shown in the following screenshot:
In the Source view, add the following code:
private static final String[] MODES = new String[] { "properties", "commonpalette", "rightSlidingSide", "bottomSlidingSide", "output", "debugger", "navigator", "explorer", "leftSlidingSide", "editor" }; private void changeMode(boolean next) { Mode currentMode = WindowManager.getDefault().findMode(this); String currentModeName = currentMode.getName(); String nextModeName = "editor"; for (int i = 0; i < MODES.length; i++) { String modeName = MODES[i]; if (modeName.equals(currentModeName)) { if (next) { nextModeName = (i + 1 < MODES.length) ? MODES[i + 1] : MODES[0]; } else { nextModeName = (i - 1 >= 0) ? MODES[i - 1] : MODES[MODES.length - 1]; } break; } } Mode nextMode = WindowManager.getDefault().findMode(nextModeName); if (nextMode != null) { this.jLabel1.setText(nextModeName); nextMode.dockInto(this); this.open(); this.requestActive(); } } private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { this.changeMode(true); } private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { this.changeMode(false); }
The static string array contains the names of the most important modes. These modes can also be identified dynamically, by calling WindowManager.getDefault().getModes().
The ActionListener delegates the call to the method changeMode() and gives the desired back/forward direction. This method determines via WindowManager.getDefault ().findMode (this) the mode in which theTopComponent is displayed, as well as the name of the current mode.
The string array is then searched and dockInto(this) is called to dock the TopComponent into a different mode.
How to revert to the default layout?
As the layout of the NetBeans Platform is persisted when the application shuts down, first perform a Clean and Build on the application project. With the removal of the build folder, the layout settings are also deleted, so that the default layout is used when the application starts again.
Using the two buttons, you can let the TopComponent be docked in some of the most commonly used modes (as shown in the screenshot below).
You have programmatically docked a TopComponent into various places within the available modes in the application. In the process, you have learned how TopComponents can be docked dynamically, that is, at runtime, into desired positions. Both the declarative and the programmatic approaches to docking should now be familiar to you.

No comments:

Post a Comment