Skip navigation links
org.netbeans.spi.navigator/1 1.48

Navigator API
Stable

See: Description

Navigator API 
Package Description
org.netbeans.spi.navigator  

Navigator API is good for clients (module writers) that want to show some structure or outline of their document in dedicated window, allowing end user fast navigation and control over the document.

API allows its clients to plug in their Swing based views easily, which then will be automatically shown in specialized Navigator UI.

org.netbeans.spi.navigator.NavigatorPanel org.netbeans.spi.navigator.NavigatorHandler

What is New (see all changes)?

Use Cases

Basic Usage Steps
In order to plug in a view into Navigator UI for certain document (data) type, module writers need to write a NavigatorPanel implementation marked with @Registration.

Writing NavigatorPanel implementation

Implementing NavigatorPanel interface is easy, you can copy from template basic implementation BasicNavPanelImpl.java.

Advices on important part of panel implementation:
  • Instantiation: Your implementation of NavigatorPanel is instantied automatically by the system if you register it using @Registration.
  • getComponent method: Simply create and return your UI representation of your data in Swing's JComponent envelope. Just be sure that you don't create new JComponent subclass per every call, as performance will suffer then.

  • panelActivated and panelDeactivated methods wraps an 'active' life of your panel implementation. In panelActivated, grab your data from given Lookup, usually by looking up its asociated DataObject or FileObject to take data from. Also remember to attach listeners to lookup result, perhaps also to data itself and trigger UI update with new data. Code will typically look like this:
            /** JavaDataObject used as example, replace with your own data source */
            private static final Lookup.Template MY_DATA = new Lookup.Template(JavaDataObject.class);
    
            public void panelActivated (Lookup context) {
                // lookup context and listen to result to get notified about context changes
                curResult = context.lookup(MY_DATA);
                curResult.addLookupListener(/** your LookupListener impl here*/);
                Collection data = curResult.allInstances();
                // ... compute view from data and trigger repaint
            }
                
    Do *not* perform any long computation in panelActivated directly, see below.
    In panelDeactivated, be sure to remove all listeners to context given to you in panelActivated.

  • Long computation of content: What if rendering your Navigator view takes long time, more than several milliseconds? Right approach is to create and run new task using RequestProcessor techniques, each time when panelActivated call arrived or your listeners on data context got called.
    While computing, UI of Navigator view should show some please wait message.

Registering NavigatorPanel impl

Declarative registration of your NavigatorPanel impl connects this implementation with specific content type, which is type of the document, expressed in mime-type syntax, for example 'text/x-java' for java sources. Infrastructure will automatically load and show your NavigatorPanel impl in UI, when currently activated Node is backed by primary FileObject whose FileObject.getMimeType() equals to content type specified in your registering annotation (see more options below).

Advanced Content Registration - Linking to Node's Lookup

There may be situations where linking between your Navigator view and activated Node's primary FileObject is not enough or not possible at all. This simply happens when the data you want to represent in Navigator are not accessible through primary FileObject or DataObject. Usual example is Multiview environment, where more views of one document exists.

The solution is to bind content of your Navigator view directly to your TopComponent. Then, whenever your TopComponent gets activated in the system, Navigator UI will show th content you connected to it.

Steps to do:
  • Choose your content type, could be either well known or arbitrary, say 'text/my-amazing-type' and do all basic steps described in above use case.

  • Implement NavigatorLookupHint interface like this:
            class AmazingTypeLookupHint implements NavigatorLookupHint {
                public String getContentType () {
                    return "text/my-amazing-type";
                }
            }
                 

  • Alter your TopComponent to contain your NavigatorLookupHint implementation (AmazingTypeLookupHint in this case) in its lookup, returned from TopComponent.getLookup() method.

  • Another option you have is to alter lookup of your Node subclass instead of directly altering lookup of your TopComponent. See Node.getLookup() method. Then Navigator will show your desired content whenever your Node subclass will be active in the system.
    However, keep in mind that this option is less preferred, because it only uses implementation detail knowledge that default implementation of TopComponent.getLookup() includes also results from lookup of asociated Node. So this approach will stop working if you change default behaviour of TopComponent.getLookup() method.

Programmatic activation of NavigatorPanel

Programmatic activation of specific navigator panel activates and shows navigator panel in navigation area, as if user had selected the panel manually. API clients are expected to use programmatic activation to activate/select preferred panel from a set of available panels.

Example: Several TopComponents in multiview arrangement, TopComponentA and TopComponentB. Both components provide the same NavigatorLookupHint impl, which is recognized by two providers NavigatorPanelA and NavigatorPanelB. Now when TopComponentA becomes activated (has a focus), it's desirable to select/show NavigatorPanelA from navigator panels. On the other side, when TopComponentB is activated, NavigatorPanelB should be activated automatically.

Steps to do to activate panel programmatically:
Setting activated node of Navigator window

Sometimes clients need to alter activated Nodes of Navigator window, to better represent Navigator area content within the whole application. See TopComponent.getActivatedNodes() and TopComponent.Registry.html#getActivatedNodes() to find out what activated nodes of TopComponent and whole system mean.

Use Case Example: NavigatorPanel implementation shows list or tree of some Nodes in Navigator area. When user selects a Node in the list or tree, it is desirable to show selected Node's properties in Properties window and enable proper actions in main menu. Exactly this can be done by presenting Node selected in the list/tree as activated Node of Navigator window.

Steps to specify activated Nodes of Navigator window:
  • In your implementation of NavigatorPanel, implement method getLookup() to return Lookup instance filled with Node(s) that you want to set as activated Nodes of Navigator window.

  • Be sure to update Lookup content properly, for example using InstanceContent as follows:
            class MyNavigatorPanel implements NavigatorPanel {
            
                /** Dynamic Lookup content */
                private final InstanceContent ic;
                /** Lookup instance */
                private final Lookup lookup;
                
                public MyNavigatorPanel () {
                    this.ic = new InstanceContent();
                    this.lookup = new AbstractLookup(ic);
                }
            
                public Lookup getLookup () {
                    return lookup;
                }
    
                /** Call this method when activated Nodes change is needed, 
                * for example when selection changes in your NavigatorPanel's Component
                */
                private void selectionChanged (Node oldSel, Node newSel) {
                    ic.remove(oldSel);
                    ic.add(newSel);
                }
                
                ... impl of rest of your NavigatorPanel
                
            }
                 
Adding UndoRedo support to the navigation view

Some complex navigation views need support for undoing and redoing edit changes done either directly in the view or in document which the view is representing.

Steps to support undo and redo in navigation view:
  • Implement your navigation view as NavigatorPanelWithUndo, which is NavigatorPanel interface with extra method getUndoRedo().

  • All other things remain the same as with basic NavigatorPanel usage. UndoRedo support returned from NavigatorPanelWithUndo.getUndoRedo() is propagated to the Navigator TopComponent and returned as its UndoRedo support. For details see TopComponent.getUndoRedo() and UndoRedo interface.

  • Example of NavigatorPanelWithUndo implementation:
            class MyNavigatorPanelWithUndo implements NavigatorPanelWithUndo {
            
                /** UndoRedo support, substitute with your impl */
                private final UndoRedo undo = new UndoRedo.Manager();
            
                public UndoRedo getUndoRedo () {
                    return undo;
                }
                
                ... rest of the NavigatorPanelWithUndo impl ...
    
            }
                 
Removing active Node/DataObject related NavigatorPanels from Navigator window

In certain situations it's not desired to show NavigatorPanel implementations related to DataObject of active Node in Navigator window. Typically you need to have active Node of some type, so that actions in the system works properly. But you don't want to show NavigatorPanels that "come" with such active Node.

Steps to remove such NavigatorPanels:
  • Implement interface NavigatorLookupPanelsPolicy, return kind of policy that suits you from getPanelsPolicy() method.

  • Put implementation instance into your TopComponent's subclass lookup, see TopComponent.getLookup() for details.

  • Now when your TopComponent becomes active in the system, found panels policy is used to limit/affect set of available NavigatorPanel implementations.

Integration of Explorer view into Navigator

Explorer views comes handy when showing Nodes in varienty of situations and it is just natural to be able to integrate them into Navigator window. Working with explorer views is described at ExplorerUtils javadoc. Integration with Navigator is easy and there are only subtle differencies from integration into TopComponent.

Steps to integrate some kind of Explorer View into Navigator:
  • Implement NavigatorPanel interface and return created explorer view from getComponent() method. Creating explorer view is described in ExplorerUtils.

  • Return lookup created using ExplorerUtils.createLookup(ExplorerManager, ActionMap) from getLookup() method of NavigatorPanel.

  • Use ExplorerUtils.activateActions(ExplorerManager, boolean) for actions activation and deactivation in panelActivated and panelDeactivated.

  • Take inspiration from following example code which integrates ListView with Navigator:
            public class ListViewNavigatorPanel extends JPanel implements NavigatorPanel, ExplorerManager.Provider {
    
                private ExplorerManager manager;
                private ListView listView;
                private Lookup lookup;
                private Action copyAction;
    
                public ListViewNavigatorPanel () {
                    manager = new ExplorerManager();
                    ActionMap map = getActionMap();
                    copyAction = ExplorerUtils.actionCopy(manager);
                    map.put(DefaultEditorKit.copyAction, copyAction);
                    map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
                    map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
                    map.put("delete", ExplorerUtils.actionDelete(manager, true)); // or false
    
                    lookup = ExplorerUtils.createLookup(manager, map);
    
                    listView = new ListView();
                    fillListView(listView);
    
                    add(listView);
                }
    
                public String getDisplayName() {
                    return "List view panel";
                }
    
                public String getDisplayHint() {
                    return "List view based navigator panel";
                }
    
                public JComponent getComponent() {
                    return this;
                }
    
                public void panelActivated(Lookup context) {
                    ExplorerUtils.activateActions(manager, true);
                }
    
                public void panelDeactivated() {
                    ExplorerUtils.activateActions(manager, false);
                }
    
                public Lookup getLookup() {
                    return lookup;
                }
    
                public ExplorerManager getExplorerManager() {
                    return manager;
                }
    
                private void fillListView(ListView listView) {
                    try {
                        Node testNode = new AbstractNode(Children.LEAF);
                        manager.setRootContext(testNode);
                        manager.setSelectedNodes(new Node[]{testNode});
                    } catch (PropertyVetoException ex) {
                        Exceptions.printStackTrace(ex);
                    }
                }
            }
                    

Exported Interfaces

This table lists all of the module exported APIs with defined stability classifications. It is generated based on answers to questions about the architecture of the module. Read them all...
Group of java interfaces
Interface NameIn/OutStabilitySpecified in What Document?
org.netbeans.spi.navigator.NavigatorPanelExportedStable
org.netbeans.spi.navigator.NavigatorHandlerExportedUnder Development

Group of lookup interfaces
Interface NameIn/OutStabilitySpecified in What Document?
activated_nodeExportedUnder Development

Navigator listen to system activated node changes and sets activated node for Navigator top component accordingly. Local activated node is set from system activated node if any provider agrees to display content for data object behind the node. Navigator relies on default lookup mechanism of TopComponent to populate its activated node. Currently it means that if node backed by JavaDataObject is activated node in the system, it is also activated node for Navigator's top component. So main menu actions like Compile File, Move Class etc. work as usual when Navigator window is active. Also, lookup of currently selected Node is searched for NavigatorPanel SPI instances.

Implementation Details

Where are the sources for the module?

The sources for the module are in the Apache Git repositories or in the GitHub repositories.

What do other modules need to do to declare a dependency on this one, in addition to or instead of a plain module dependency?

Nothing.

Read more about the implementation in the answers to architecture questions.

Skip navigation links
org.netbeans.spi.navigator/1 1.48