X

Geertjan's Blog

  • November 25, 2008

Sharing ExplorerManagers Between TopComponents

Geertjan Wielenga
Product Manager
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.

Join the discussion

Comments ( 10 )
  • Jesse Glick Tuesday, November 25, 2008

    Seems excessively elaborate. All you need is some public class in some public package:

    public class CommonExplorers {

    public static final ExplorerManager SHARED_MANAGER = new ExplorerManager();

    }

    which you can then reference from your EM.P impls. The layer registration is just overhead for this example.


  • Geertjan Wednesday, November 26, 2008

    But I'm trying to avoid static stuff.


  • Jesse Glick Wednesday, November 26, 2008

    A layer registration IS static stuff. There are just two reasons to put something in a layer, neither of which apply in this case:

    1. You expect that the data might need to be customized and the customizations relative to the default value persisted in the userdir; or, similarly, that it might need to be branded.

    2. You want inversion of control: the module reading the entry has no dependency on the module providing the entry, so they need a way to communicate (and active procedural registration is undesirable for performance reasons).


  • Vincent Cantin Monday, December 1, 2008

    Shouldn't MyExplorerManager be named MyExplorerManagerProvider ?


  • guest Monday, December 1, 2008

    Same remark for "lookup(Provider.class)" -> "lookup(ExplorerManager.Provider.class)" which may be more clear for the reader.


  • Geertjan Tuesday, December 2, 2008

    Good point, Vincent.


  • kelebek Sunday, April 26, 2009

    thanks..


  • emxsys Thursday, June 2, 2011
    This is insightful, and helpful. Thanks!
  • Jorge Friday, December 21, 2012

    Interesting...


  • Sebastian Sunday, September 18, 2016

    Geertjan, thanks for sharing this idea! However, I am not getting the right behavior: Similar to Windows Explorer, I have a BeanTreeView in the Explorer Window and a ListView in the Editor Window. Both of the same ExplorerManager as you described. Initially both views look alike, i.e. they show the initial node structure as expected, the ListView is without the root node.

    When I click in the ListView to open up a node, the children nodes pop up as expected. Also the BeanTreeView responds as expected. Yet, when I click in the BeanTreeView to open up a node, the ListView does not respond. Did I forget something?

    PS: I am using NetBeans 8.0.1. All source files are contained within one Module.


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