X

Geertjan's Blog

  • August 11, 2009

Lookup in Toolbar

Geertjan Wielenga
Product Manager
I've been wanting to figure out how to use Lookup from a toolbar for a while and now I have it working. When OK is clicked in the toolbar below, a new Person object is created and added to the InstanceContent that is in the Lookup of the toolbar. The ChildFactory that creates the Nodes in the Person window in the explorer mode is listening for Person objects and recreates the Nodes whenever a new Person object is identified.

Once you realize that... the toolbar is a TopComponent, everything should be clear(er):

All the sample code for the above can be found here: http://kenai.com/projects/lookup-in-toolbar

Here are the highlights:

  1. Create your domain object:
    package org.demo.sample;
    public class Person {
    String name;
    String city;
    String country;
    public String getCity() {return city;}
    public void setCity(String city) {this.city = city;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getCountry() {return country;}
    public void setCountry(String country) {this.country = country;}
    }

  2. Create a TopComponent called "EntryTopComponent", with the JLabels, JTextFields, and JButton you see in the screenshot above. When OK is clicked, create a new Person object and add it to an InstanceContent, which you've associated with the Lookup of the TopComponent, as outlined in NetBeans Platform Quick Start.

  3. Add the "EntryTopComponent" to the toolbar, by first creating a new ActionListener, specifying that you'd like your TopComponent to be presented in the toolbar...
    public class EntryActionListener implements ActionListener, Presenter.Toolbar {
    @Override
    public void actionPerformed(ActionEvent e) {
    //Nothing needs to happen here.
    }
    @Override
    public Component getToolbarPresenter() {
    return EntryTopComponent.findInstance();
    }
    }

    ...and then register it in the layer:

    <folder name="Actions">
    <folder name="File">
    <file name="org-demo-sample-EntryActionListener.instance">
    <attr name="delegate" newvalue="org.demo.sample.EntryActionListener"/>
    </file>
    </folder>
    </folder>
    <folder name="Toolbars">
    <folder name="Person">
    <file name="org-demo-sample-EntryActionListener.shadow">
    <attr name="originalFile" stringvalue="Actions/File/org-demo-sample-EntryActionListener.instance"/>
    </file>
    </folder>
    </folder>

  4. Create a ChildFactory that listens for Person objects in the lookup of the "EntryTopComponent" and then recreate the nodes whenever a new Person object is found there:
    public class PersonChildFactory extends ChildFactory<Person> implements LookupListener {
    private Result<Person> result;
    private List<Person> persons;
    public PersonChildFactory() {//Listen for Person objects in the EntryTopComponent's lookup:
    result = WindowManager.getDefault().findTopComponent("EntryTopComponent").getLookup().lookupResult(Person.class);
    result.addLookupListener(this);//Call once to 'resultChanged' to activate the listener:
    resultChanged(new LookupEvent(result));
    }//When there is a new Person object in the lookup of the EntryTopComponent,
    //add that Person object to our list of Person objects,
    //and then call 'refresh' to recreate the keys:

    @Override
    public void resultChanged(LookupEvent arg0) {
    persons = new ArrayList();
    Collection<? extends Person> coll = result.allInstances();
    for (Person person : coll) {
    persons.add(person);
    }
    refresh(true);
    }//When the keys are created, iterate through the list of Person objects,
    //creating a new person object for each instance,
    //and then add each one to the list,
    //which will trigger the 'createNodeForKey':

    @Override
    protected boolean createKeys(List<Person> list) {
    if (!persons.isEmpty()) {
    for (int i = 0; i < persons.size(); i++) {
    Person person = new Person();
    person.setName(persons.get(i).getName());
    person.setCity(persons.get(i).getCity());
    person.setCountry(persons.get(i).getCountry());
    list.add(person);
    }
    } else {
    Person person = new Person();
    person.setName("<empty>");
    person.setCity("<empty>");
    person.setCountry("<empty>");
    list.add(person);
    }
    return true;
    }//Whenever a new Person object is added to the list above,
    //create a new node:

    @Override
    protected Node createNodeForKey(Person person) {
    return new PersonNode(person);
    }//Use the values from the current Person object to define the node:
    public class PersonNode extends AbstractNode {
    private final Person person;
    public PersonNode(Person person) {
    super(Children.LEAF);
    this.person = person;
    setDisplayName(person.getName());
    setShortDescription(person.getCity());
    setIconBaseWithExtension("/org/demo/sample/resources/tv.gif");
    }
    @Override
    public Action[] getActions(boolean context) {
    return new Action[]{new ShowCountryAction(person)};
    }//Double-clicking on the node will invoke this:
    @Override
    public Action getPreferredAction() {
    return new ShowCountryAction(person);
    }
    public class ShowCountryAction extends AbstractAction {
    private final Person person;
    public ShowCountryAction(Person person) {
    this.person = person;
    putValue(Action.NAME,"Show Country");
    }
    @Override
    public void actionPerformed(ActionEvent e) {
    StatusDisplayer.getDefault().setStatusText(person.getCountry());
    }
    }
    }
    }

  5. Create a second TopComponent, implement an ExplorerManager, add a BeanTreeView, and then add the above ChildFactory to the root context of the ExplorerManager, as explained in numerous places elsewhere.

You're done. The question to ask is, of course, whether it makes sense to have a toolbar like this. Nevertheless, if needed, you can now see how to implement it.

Join the discussion

Comments ( 4 )
  • jmborer Wednesday, August 12, 2009

    Question:

    How does "WindowManager.getDefault().findTopComponent("EntryTopComponent")" work?

    Do you need to define the key "EntryTopComponent" somewhere (didn't find it in you code) or does it use some reflexion to discover the component based on its class?


  • Geertjan Wielenga Wednesday, August 12, 2009

    "EntryTopComponent" is an ID generated in the TopComponent by the New Window Component wizard. (Since I didn't code it myself, I didn't mention it, because it was generated in the step where this TopComponent was generated.) It identifies the TopComponent to the WindowManager and is used by the WindowManager to find the TopComponent so that we can listen to its lookup.


  • jmborer Wednesday, August 12, 2009

    Can I send you my questions to your Yahoo email account?


  • Geertjan Wednesday, August 12, 2009

    You can send your questions to dev@openide.netbeans.org where developers with far more knowledge than me are found.


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