Usually options for NetBeans modules are handled via option panel. For that we can use a specialized wizard. You can start the wizard from the contextual menu of the project, where we fire the New - Other - Module Development - Options Panel. In this way we can create primary or secondary panels for options.
This is not our case. That is because for versioning system options, NetBeans has created a panel already. You can find that panel from the main menu by Tools - Options - Miscellaneous - Versioning. Take a look on the dialog box and see what comes next. Our job is to insert another item in the list of versioning systems, handling preferences for Perforce.
We achieve that by extending org.netbeans.spi.options.AdvancedOption. This class represents an advanced interface element for options dialog. We create a new class which extends AdvancedOption.
After that we must configure the layout.xml to inject in the interface this element. The programmatic way is to modify by hand the layout.xml file. This file will look like below:
<folder name="VersioningOptionsDialog">
<file name="PerforceOptions.instance">
<attr name="instanceClass" stringvalue="org.padreati.perforcenb.ui.PerforceOptions"/>
</file>
</folder>
</filesystem>
The listing is clear, we provide a display name and a tooltip for the UI element. I used resources for that. The main method here is create() which returns an instance of PerforceOptionsPanelController.An OptionPanelController is the controller behind UI for managing options (MVC sounds familiar? that's one reason why I love NetBeans and Swing). The controller handles operations of managing data. Here is the listing:public class PerforceOptions extends AdvancedOption {
@Override
public String getDisplayName() {
return NbBundle.getMessage(PerforceVS.class, "CTL_Perforce_DisplayName");
}
@Override
public String getTooltip() {
return NbBundle.getMessage(PerforceVS.class, "CTL_Perforce_OptionsTooltip");
}
@Override
public OptionsPanelController create() {
return new PerforceOptionsPanelController();
}
}
public class PerforceOptionsPanelController extends OptionsPanelController {
private PerforceOptionsPanel panel;
public PerforceOptionsPanelController() {
panel = new PerforceOptionsPanel();
}
@Override
public void update() {
PerforceModuleConfig config = PerforceModuleConfig.getInstance();
config.reload();
panel.setPath(config.getP4Path());
panel.setDefaultPort(config.getP4DefaultPort());
panel.setDefaultWorkspace(config.getP4DefaultWorkspace());
}
@Override
public void applyChanges() {
PerforceModuleConfig config = PerforceModuleConfig.getInstance();
config.setP4Path(panel.getPath());
config.setP4DefaultPort(panel.getDefaultPort());
config.setP4DefaultWorkspace(panel.getDefaultWorkspace());
config.store();
}
@Override
public void cancel() {
PerforceModuleConfig.getInstance().reload();
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return panel.isDirty();
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return panel;
}
@Override
public HelpCtx getHelpCtx() {
return new HelpCtx(PerforceOptionsPanel.class);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
}
}
There are only some methods which are really relevant. The update method is called when IDE loads configuration data from storage, I update the interface at that moment. The applyChanges is called when a save action is fired from interface. Use isChanged to tell IDE if the configuration data was updated in UI. The UI is specified in getComponent method. This method returns an instance of PerforceOptionsPanel, a class which extends JPanel.
This is the interface. Here is how it looks:
For managing the preferences of the module I created a class called PerforceModuleConfig. This is a singleton which calls NbPreferences to persist it's properties. This class I will use in our module to see which are the options for PerforceNB module. Here is a listing:
public final class PerforceModuleConfig {
private static PerforceModuleConfig instance;
private final static String P4_PATH_KEY = "P4_PATH_KEY";
private final static String P4_DEFAULT_PORT_KEY = "P4_DEFAULT_PORT_KEY";
private final static String P4_DEFAULT_WORKSPACE_KEY = "P4_DEFAULT_WORKSPACE_KEY";
private String p4Path;
private String p4DefaultPort;
private String p4DefaultWorkspace;
private PerforceModuleConfig() {
}
public static PerforceModuleConfig getInstance() {
if(instance==null) {
instance = new PerforceModuleConfig();
}
return instance;
}
public String getP4Path() {
return p4Path;
}
public void setP4Path(String p4Path) {
this.p4Path = p4Path;
}
public String getP4DefaultPort() {
return p4DefaultPort;
}
public void setP4DefaultPort(String p4DefaultPort) {
this.p4DefaultPort = p4DefaultPort;
}
public String getP4DefaultWorkspace() {
return p4DefaultWorkspace;
}
public void setP4DefaultWorkspace(String p4DefaultWorkspace) {
this.p4DefaultWorkspace = p4DefaultWorkspace;
}
public void reload() {
Preferences pref = NbPreferences.forModule(PerforceModuleConfig.class);
String p4PathDefault = "p4";
if(System.getProperty("os.name").startsWith("Windows")) {
p4PathDefault = "p4.exe";
}
setP4Path(pref.get(P4_PATH_KEY, p4PathDefault));
setP4DefaultPort(pref.get(P4_DEFAULT_PORT_KEY, ""));
setP4DefaultWorkspace(pref.get(P4_DEFAULT_WORKSPACE_KEY, ""));
}
public void store() {
Preferences pref = NbPreferences.forModule(PerforceModuleConfig.class);
pref.put(P4_PATH_KEY, getP4Path());
pref.put(P4_DEFAULT_PORT_KEY, getP4DefaultPort());
pref.put(P4_DEFAULT_WORKSPACE_KEY, getP4DefaultWorkspace());
}
}
The content is obvious. Only notice that I have used NbPreferences, a utility class from NetBeans Platform for persisting preferences. Very useful one. Here is the result of my work from this episode.
As usual, you can see the whole project and code from the kenai project page at http://kenai.com/projects/perforcenb. See you on the next episode.
No comments:
Post a Comment