X

Geertjan's Blog

  • December 22, 2010

Loosely Coupled Coffee Maker on the NetBeans Platform

Geertjan Wielenga
Product Manager
Let's say we want to make a coffee machine on the NetBeans Platform. It can be enabled...

...it can also be disabled:

However, interestingly, the checkbox to enable the coffee machine is in one module, while the window that shows the results of the coffee production is in a different module:

There is no dependency between the two modules, i.e., the one module does not use code or refer to code in the other module. Because the two modules are loosely coupled, we can easily exchange the window for a completely different window, so that we're enabling 3rd party providers to provide alternative implementations of coffee machines that can plug seamlessly into this infrastructure.

Here's all the code. Firstly, the Action provided by the first module, which includes a Presenter.Toolbar so that the Action is presented in the toolbar:

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.JCheckBox;
import org.openide.awt.ActionRegistration;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionID;
import org.openide.util.NbPreferences;
import org.openide.util.actions.Presenter;
@ActionID(category = "Build", id = "org.coffee.enabler.CoffeeProductionEnableAction")
@ActionRegistration(displayName = "#CTL_CoffeeProductionEnableAction")
@ActionReferences({
@ActionReference(path = "Toolbars/File", position = 0)
})
public final class CoffeeProductionEnableAction extends AbstractAction implements Presenter.Toolbar {
@Override
public void actionPerformed(ActionEvent e) {
//empty, because we delegate to the CheckBox, below.
}
@Override
public Component getToolbarPresenter() {
final JCheckBox box = new JCheckBox();
box.setText("Enable Coffee Production");
box.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (box.isSelected()) {
NbPreferences.root().putBoolean("coffeeProduction", true);
} else {
NbPreferences.root().putBoolean("coffeeProduction", false);
}
}
});
return box;
}
}

Next, here's the window, in the second module. We listen for a change in the preference and then change the JLabel accordingly:

import java.awt.BorderLayout;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import javax.swing.JLabel;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.util.NbPreferences;
import org.openide.windows.TopComponent;
@ConvertAsProperties(dtd = "-//org.coffee.visualizer//CoffeeProductionWindow//EN", autostore = false)
@TopComponent.Description(preferredID = "CoffeeProductionWindow", persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "editor", openAtStartup = true)
@ActionID(category = "Window", id = "org.coffee.visualizer.CoffeeProductionWindow")
@ActionReference(path = "Menu/Window")
@TopComponent.OpenActionRegistration(displayName = "#CTL_CoffeeProductionWindowAction", preferredID = "CoffeeProductionWindow")
public class CoffeeProductionWindow extends TopComponent {
public CoffeeProductionWindow() {
setDisplayName("Coffee Producer");
setLayout(new BorderLayout());
final JLabel label = new JLabel();
add(label, BorderLayout.CENTER);
NbPreferences.root().addPreferenceChangeListener(new PreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
if(evt.getKey().equals("coffeeProduction")){
if (evt.getNewValue().equals("true")){
label.setText("enabled to produce coffee");
} else {
label.setText("not able to produce coffee");
}
}
}
});
}
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
}
void readProperties(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
}
}

That's all. The only "connection" between the two modules is the knowledge of a preference that has been set in the user directory of the application, more about which can be read in the NetBeans Platform Options Window Tutorial.

Join the discussion

Comments ( 2 )
  • Miguel Garcia-Lopez Sunday, December 26, 2010

    He, he, nice post Geertjan! As usual very informative and with a nice tint of humor... after all, programmers are often thought of as devices turning caffeine into computer programs :)


  • Vintesh Tuesday, August 16, 2011

    one thing it is "implements Presenter.Toolbar"


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha