Download NetBeans!

20081125 Tuesday November 25, 2008

Sharing ExplorerManagers Between TopComponents

The NetBeans ExplorerManager class is great—it lets you display the same set of nodes in multiple explorer views while synchronizing the selection. In other words, if you select a node in one explorer view, it will automatically also be selected in another explorer view.

An explorer view is placed on a TopComponent that implements ExplorerManager.Provider, with the ExplorerManager's root context being set to the root node. Then everything happens magically from there thanks to the ExplorerManager: each explorer view in the TopComponent will have synchronized selection management for the node hierarchy. But... what if the explorer views are in DIFFERENT TopComponents? Below is a perfect example. The explorer view on the left (BeanTreeView) displays nodes, while the explorer view on the right (PropertySheetView) presents a different view on the same nodes, which should therefore be synchronized with each other:

In other words, the explorer views are in different TopComponents. If, as normal, you instantiate the ExplorerManager in each of the TopComponents, you have TWO ExplorerManagers... which means you will have no selection management between the nodes in the different explorer views.

Here's the solution to this problem.

  1. Create a new Java class that defines an explorer manager:
    package org.my.demo;
    
    import org.openide.explorer.ExplorerManager;
    
    public class MyExplorerManager implements ExplorerManager.Provider {
    
        private ExplorerManager em;
    
        public ExplorerManager getExplorerManager() {
            if (em == null) {
                em = new ExplorerManager();
            }
            return em;
        }
        
    }

  2. Create a new folder (with any name you like) in the layer.xml file and then register the above class there:
    <folder name="ExplorerManagers">
        <file name="org-my-demo-MyExplorerManager.instance"/>
    </folder>

    At runtime, the ExplorerManager is available in the filesystem and any module in the application can make use of it.

  3. In each of your TopComponents, implement ExplorerManager.Provider, exactly as you would always do. However, instead of creating a new ExplorerManager, get the one above from the filesystem via the Lookup. For example, this is the PropertiesTopComponent you see above:
    private ExplorerManager em;
    
    private PropertiesTopComponent() {
    
        initComponents();
    
        setName(NbBundle.getMessage(PropertiesTopComponent.class, "CTL_PropertiesTopComponent"));
        setToolTipText(NbBundle.getMessage(PropertiesTopComponent.class, "HINT_PropertiesTopComponent"));
    
        em = Lookups.forPath("/ExplorerManagers").lookup(Provider.class).getExplorerManager();
        em.setRootContext(new AbstractNode(new WordChildren()));
    
    }

    Note the line in bold, of course, which looks in the specified filesystem folder for a class of the required type.

  4. Do the same for all the other TopComponents that need to have the same ExplorerManager handling the selection for their explorer views.

What's nice about this solution is that it leverages some of the central tenets of the NetBeans Platform: selection management, explorer views, nodes, lookup, filesystem... It's a perfectly NetBeans-centric approach to this problem. The most interesting part is the registration of the ExplorerManager in the layer.xml, because it is yet another example of the cool things you can do if your application has a filesystem. And all NetBeans Platform applications automatically have one of those for the whole system.

Nov 25 2008, 03:21:43 AM PST Permalink