Tuesday Mar 05, 2013

Synchronizing an Editor Window with a Viewer Window

Now that we're able to open a TopComponent per Node, let's... synchronize back to the viewer window from the editor window.

Below you can see that right now there's a TopComponent open for each of the Nodes. However, wouldn't it be nice if selecting one of the open TopComponents would cause the related Node to automatically be selected? In other words, below I have clicked on the "professor" window, which automatically results in the "professor" node in the viewer window being highlighted:

How to achieve this? Via a very elegant NetBeans Platform mechanism.

  1. Create a "Synchronizable" Capability. Here it is, in the domain module:
    package org.person.domain.capabilities;
    
    import org.person.domain.Person;
    
    public interface Synchronizable {
        Person getPerson();
    }
  2. Add an Implementation of the Capability to the Node Lookup. You can see that the Synchronizable capability has been added to the Lookup of the Node, in the Node constructor, as shown in the highlighted bit below:
    private PersonNode(final Person person, InstanceContent ic) throws IntrospectionException {
        super(person, Children.LEAF, new AbstractLookup(ic));
        ic.add(new Openable() {
            @Override
            public void open() {
                TopComponent tc = findTopComponent(person);
                if (tc == null) {
                    tc = new PersonEditorTopComponent(person);
                    tc.open();
                }
                tc.requestActive();
            }
        });
        ic.add(new Synchronizable() {
            @Override
            public Person getPerson() {
                return person;
            }
        });
        setDisplayName(person.getType());
    }

    Note: There's no 'naked' Person object in the Node Lookup, only a Person object wrapped in a capability. This way, you have more control over the Object; since various other parts of the application may (and currently are already) be listening/responding to Person objects, using a capability gives you a fresh access point to the Object.

  3. Retrieve the Capability from the Lookup in the Viewer. In the Viewer window, implement LookupListener, listen for the current Person object, and set the Node that has the same Person object in the Synchronizable in its Lookup to be the selected Node in the ExplorerManager:
    @Override
    public void resultChanged(LookupEvent le) {
        Collection<? extends Person> p = personResult.allInstances();
        if (p.size() == 1) {
            Person currentPerson = p.iterator().next();
            for (Node node : em.getRootContext().getChildren().getNodes()) {
                if (node.getLookup().lookup(Synchronizable.class).getPerson() == currentPerson) {
                    try {
                        em.setSelectedNodes(new Node[]{node});
                    } catch (PropertyVetoException ex) {
                        Exceptions.printStackTrace(ex);
                    }
                }
            }
        }
    }

And these are the three files created/changed during the above instructions:

Source code of the current state of the sample above:

http://java.net/projects/nb-api-samples/sources/api-samples/show/versions/7.3/misc/SimpleApp

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« March 2013 »
SunMonTueWedThuFriSat
     
10
11
12
13
14
15
18
23
24
27
28
      
Today