BookNBPlatformCookbookCH0206

Contents

NetBeans Platform Cookbook Chapter 02 06

Using Options Panel

Application must maintain some settings persistent to the next run. NetBeans Platform stores list of opened TopComponent automatically if it is allowed. You can store user preferences, URL to database, URL to update centre. It provides API to extend Options window. It supports add primary panel - new main category to Options panel - or secondary panel that is a tab subcategory under some first one.

NetBeans allows to integrate your panels into Options window – primary or secondary panel. It consists of GUI panel and a controller. The controller implements OptionsPanelController interface to allow Options window to integrate into it. It creates the GUI panel lazily and delegates loading, validating and storing requests to the Panel. Panel's responsibility is GUI, informing the controller about changes by listening its content, validation by valid() method, loading by load() method and store settings by store() method.

For loading and storing of settings util class NbPreferences is suitable. Settings are stored in the <user-dir>/config/Preferences/module/base/package/pref.properties file for module module.base.package. In our example on Windows C:\Documents and Settings\milos\Application Data\.options\dev\config\Preferences\nbpcook\options\pref.properties where oprions (of .options) is application branding name (options.exe) and nbpcook.options is the module base package.

image:nbpcook_02_11_options_book.png

Figure 2.11 Simple Options Panel

image:nbpcook_02_12_options_app.png

Figure 2.12 Complex Options Panel


How to

We suppose you have settings of your application encapsulated in some class, e. g. BookPreferences like this:

package com.packtpub.nbpcook.options.pref.api;
import java.beans.PropertyChangeListener;

/** Settings and Options of Books application.   */
public interface BookPreferences {

    public static final String PROP_DB_CONNECTION_URL =
                                  "db_connection_url";
    ….. other property names
    
    public String getDbConnectionUrl();

    public void setDbConnectionUrl(String dburl);

    … methods for other properties

    public void addPropertyChangeListener(PropertyChangeListener l);

    public void removePropertyChangeListener(PropertyChangeListener l);

    /** Tests if are preferences attributes set
     * if no you can show Options dialog to set preferences
     */
    public boolean ensureSet();
  
}    

Provide its implementation as a service provider. Use NbPreferences to maintain loading/storing data. Note the service provider is registered by annotation.

@ServiceProvider(service=BookPreferences.class)
public class BookPreferencesImpl implements BookPreferences {
 
    public String getDbConnectionUrl() {
        Preferences bookpref =
              NbPreferences.forModule(BookPreferences.class);
        return NbPreferences.forModule(
                BookPreferences.class).get(
                     BookPreferences.PROP_DB_CONNECTION_URL
                   , "");
    }

    public void setDbConnectionUrl(String dbConnectionUrl) {
        String oldDbConnectionUrl = getDbConnectionUrl();
        NbPreferences.forModule(BookPreferences.class).put(
                  BookPreferences.PROP_DB_CONNECTION_URL
                , dbConnectionUrl);
        propertyChangeSupport.firePropertyChange(
                PROP_DB_CONNECTION_URL,
                oldDbConnectionUrl,
                dbConnectionUrl);
    }

    … others settings are similar

    … add/remove-PropertyChangeListener implementation

    public boolean ensureSet() {
        boolean setted = true;
        if (getDbConnectionUrl().isEmpty())  
            setted = false;
        … other tests
        if ( ! setted ) {
             // you can show Book preferences Options window here
        }
        return setted;
    }
} 
    

Usage of BookPreferences is very simple:

    // Usage of preferences. Note the simple access

    BookPreferences pref = Lookup.getDefault().lookup(BookPreferences.class);
    if ( ! pref.ensureSet() )
       handle-no-pref-set show error or Options panel (if is not in ensureSet())

    MyDbProvider.setUrlConnection( pref.getDbConnectionUrl() );

To create primary panel choose New File, Module Development Category a Options Panel. Choose Create Primary Panel radiobutton, type Category Label (e. g. BookOptions) and Keywords and select 32x32 pixels icon. If you want allow secondary panels check Allow Secondary Panels. Press Next button.

Fill class name prefix - you can leave suggested name taken from options Category, update or retype. Press Finish. The wizard created BookOptionsPanel form - the view - and BookOptionsPanelController - the controller. Note in the source how the controller is registered via an annotation to use by NetBeans Platform and how the basic implementation was generated by IDE.

Now open the panel source. It contains hints in comments for you how to implement it.

Create the form GUI placing components on the panel.

After components are initialized register listeners to listen their changes:

 // listen to changes in form fields and call controller.changed()
 DocumentListener doclstr = new DocumentListener() {
        public void insertUpdate(DocumentEvent e) {
         markChanged();
        }
            ...            
     };
 dbConnectionUrlField.getDocument().
                addDocumentListener( doclstr );

 … listeners to other components

Implement the markChanged() method to inform the controller about changes:

   private void markChanged() {
        if ( ! BookPreferencesPanel.this.controller.isChanged())
            showMessage("BookPreferencesPanel.changedLabel.text_changed");
        BookPreferencesPanel.this.controller.changed();
    }

Implement valid() method to check if data is correct:

    boolean valid() {
        changedLabel.setText( "" );
        // can check validity of the db connection URL 
        // e.g by some service
        // by used persistence implementation
        // ...
        String s = dbConnectionUrl.getText().trim();
        if (s.length() == 0) {
            showMessage("DB_connection_URL_is_empty");
            return false;
        }
       …
       return true;
  }  

Load preferences in the load() method and store them in the store() method:

  void load() {
     BookPreferences pref =
          Lookup.getDefault().lookup(BookPreferences.class);
     dbConnectionUrl.setText( pref.getDbConnectionUrl() );
        ...   

   void store() {
        BookPreferences pref =
           Lookup.getDefault().lookup(BookPreferences.class);
        pref.setDbConnectionUrl( dbConnectionUrl.getText() );

Now we update the controller. You do not need edit it mostly. The standard implementation generated from template is sufficient.

If you want to add any your objects into options-master-lookup that is composed of all lookups given by all controllers of the Options panel override the getLookup() method. This lookup is passed to the controller.getComponent(lkp) method as a parameter.

The controller creates GUI panel by the getComponent() method. Before showing it the controller's update() method is called. It only calls panel.load() method to load data into the form and sets changed flag to false. The update() method can be called not only ones. It would not contain time consuming tasks to not prolong initialization.

The applyChanges() method is called after the OK button was pressed. It is made by calling panel.store() method which sets and stores settings from the form and clears the changed flag.

The cancel() method is called after the Cancel button was pressed. You can do some rollback.

If some data in the panel were changed the isValid() method is called. If it is OK the OK button is available. Its work is delegated to panel.valid() method.

The changed() method is called by panel to propagate change event to the controller and subsequently its registered listeners - Options API. If you want set a special help for your options panel return the HelpCtx by getHelpCtx() method.

Let's Explain!

The Options API looks up all OptionsPanelController implementations and creates its tabs according to all primary panels. Before showing your panel the controller.getComponent() method is called to create GUI panel. Then the update() method. It loads data from properties to the form by panel.load() method. When the user changes some data the change event is propagated to the Options API (that listens changes of the controller). Options API call isValid() method and enables the OK button if it returns true. Then the user can press the OK button, the applyChanges() method is called and panel.store() method stores settings.

Notes/Tips see Registration

Our option panel contribution is registered by annotation. Look what registration source NetBeans Platform generated for you.

Create ZIP distribution file of the application and decompress it.

Explore appname/clustername/modules/module-base-package.jar (decompress it). For our example named options is the folder options/options/modules/ and com-packtpub-nbpcook-options-pref.jar JAR file (where the option panel is defined). Open the generated-layer.xml file in the META-INF folder. There is declared your opiton panel (com-packtpub-nbpcook- was truncated to nbpcook-):

<?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="OptionsDialog">
        <file name="nbpcook-options-pref-BookOptionsPanelController.instance">
            <!--nbpcook.options.pref.BookOptionsPanelController-->
            <attr
                methodvalue="org.netbeans.spi.options.OptionsCategory.createCategory" name="instanceCreate"/>
            <attr name="controller" newvalue="nbpcook.options.pref.BookOptionsPanelController"/>
            <attr
                bundlevalue="nbpcook.options.pref.Bundle#OptionsCategory_Name_Book" name="categoryName"/>
            <attr name="iconBase" stringvalue="nbpcook/options/pref/book32.png"/>
            <attr
                bundlevalue="nbpcook.options.pref.Bundle#OptionsCategory_Keywords_Book" name="keywords"/>
            <attr name="keywordsCategory" stringvalue="Book"/>
        </file>
    </folder>
</filesystem>

This file is added to the module layer.xml content file while application starts.

Notes/Tips Primary Options Category

We create a primary options category Application with two secondary panels defined In the example Options application in module secondary. There is some unknown file package-info.java in the base package with Application options category registration:

@org.netbeans.spi.options.OptionsPanelController.ContainerRegistration(
    id = "Application", categoryName = "#OptionsCategory_Name_Application",
         iconBase = "nbpcook/options/secondary/myoptions.png",
          keywords = "#OptionsCategory_Keywords_Application", 
          keywordsCategory = "Application")
package nbpcook.options.secondary;

This way the NB Platform (6.9.1) registers a primary category in the Option pane.

Sources

Text and sources were created under NB 6.8 6.9, 7.0, 7.1, 7.2.

Navigation

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo