X

Geertjan's Blog

  • July 21, 2015

Empty Node Populated On The Fly

Geertjan Wielenga
Product Manager

Sometimes you need to create a Node that initially has no Children:

Later, when something has happened, e.g., as above, a menu item is clicked and a dialog is filled out, you want to populate the Node hierarchy:

How to achieve this?

Start by creating this class, to centrally manage changes:

import javax.swing.event.ChangeListener;
import org.openide.util.ChangeSupport;
public class PropertiesNotifier {
private static final ChangeSupport cs =
new ChangeSupport(PropertiesNotifier.class);
public static void addChangeListener(ChangeListener listener) {
cs.addChangeListener(listener);
}
public static void removeChangeListener(ChangeListener listener) {
cs.removeChangeListener(listener);
}
public static void changed() {
cs.fireChange();
}
}

Next, make sure that your Children are created only when a property change is received:

import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openide.nodes.BeanNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;
import org.openide.util.NbPreferences;
class MusicBandChildFactory extends ChildFactory.Detachable<String> {
private final List<String> bandNames;
private ChangeListener listener;
public MusicBandChildFactory() {
this.bandNames = new ArrayList<String>();
}
@Override
protected void addNotify() {
PropertiesNotifier.addChangeListener(listener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent ev) {
String bandName =
NbPreferences.forModule(MusicBandsNode.class).
get("bandName", "error!");
bandNames.add(bandName);
refresh(true);
}
});
}
@Override
protected void removeNotify() {
if (listener != null) {
PropertiesNotifier.removeChangeListener(listener);
listener = null;
}
}
@Override
protected boolean createKeys(List<String> list) {
list.addAll(bandNames);
return true;
}
@Override
protected Node createNodeForKey(String key) {
BeanNode node = null;
try {
node = new BeanNode(key);
node.setDisplayName(key);
} catch (IntrospectionException ex) {
Exceptions.printStackTrace(ex);
}
return node;
}
}

Finally, fire a property change at an appropriate moment, such as when the user has entered something into a dialog:

import java.io.IOException;
import javax.swing.Action;
import org.netbeans.api.core.ide.ServicesTabNodeRegistration;
import org.openide.*;
import org.openide.actions.NewAction;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.actions.SystemAction;
import org.openide.util.datatransfer.NewType;
@ServicesTabNodeRegistration(
displayName = "#LBL_Bands",
iconResource = "org/demo/enpotf/band.gif",
name = "#LBL_Bands")
@NbBundle.Messages({"LBL_Bands=Music Bands"})
public class MusicBandsNode extends AbstractNode {
public MusicBandsNode() {
super(Children.create(new MusicBandChildFactory(), true));
setDisplayName(Bundle.LBL_Bands());
setShortDescription(Bundle.LBL_Bands());
setIconBaseWithExtension("org/demo/enpotf/band.gif");
}
@Override
public Action[] getActions(boolean context) {
return new Action[]{SystemAction.get(NewAction.class)};
}
@NbBundle.Messages({
"LBL_Title=Band Name Definition",
"LBL_Text=Enter Band Name:"})
@Override
public NewType[] getNewTypes() {
return new NewType[]{
new NewType() {
@Override
public String getName() {
return Bundle.LBL_Title();
}
@Override
public void create() throws IOException {
NotifyDescriptor.InputLine msg = new NotifyDescriptor.InputLine(
Bundle.LBL_Text(),
Bundle.LBL_Title());
Object result = DialogDisplayer.getDefault().notify(msg);
if (result == NotifyDescriptor.OK_OPTION) {
String bandName = msg.getInputText();
NbPreferences.forModule(MusicBandsNode.class).
put("bandName", bandName);
PropertiesNotifier.changed();
}
}
}
};
}
}

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.