Use Navigation History in Eclipse RCP

2020-03-23 18:49发布

问题:

I like to use the navigation history provided by Eclipse in my RCP Application. Unfortunately this feature isn't well documented. In fact I only found this Wiki entry: http://wiki.eclipse.org/FAQ_How_do_I_hook_my_editor_to_the_Back_and_Forward_buttons%3F

It mentions that every editor can be marked in the navigation history, without having to specify a location. This is exactly what I want.

Regardless of whether the specific editor has any support for navigation history, markLocation will work. If the editor doesn’t implement INavigationLocationProvider, a history entry will be added, allowing the user to jump back to that editor but without returning to any particular location.

I added the following lines of code to my application in order to add a navigation entry each time a new Editor is opened.

IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = page.openEditor( input, MyEditor.ID );
page.getNavigationHistory().markLocation( editor );

My problem is that the code doesn't work. The toolbar icons for the commands org.eclipse.ui.navigate.backwardHistory and org.eclipse.ui.navigate.forwardHistory stay grayed out.

回答1:

I have found the solution. In order to use the Navigation History in your Eclipse RCP application you have to add the following lines of code to your ApplicationActionBarAdvisor.

/**
 * Fills the cool bar with the main toolbars for the window.
 * <p>
 * The default implementation does nothing. Subclasses may override.
 * </p>
 * 
 * @param coolBar
 *            the cool bar manager
 */
protected void fillCoolBar( ICoolBarManager coolBar ) {
    IToolBarManager navigation = new ToolBarManager( SWT.FLAT );

    IAction backward = getAction( IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY );
    IAction forward = getAction( IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY );

    navigation.add( backward );
    navigation.add( forward );

    coolBar.add( navigation );
}

/**
 * Instantiates the actions used in the fill methods. Use
 * {@link #register(IAction)} to register the action with the key binding
 * service and add it to the list of actions to be disposed when the window
 * is closed.
 * 
 * @param window
 *            the window containing the action bars
 */
protected void makeActions( IWorkbenchWindow window ) {
    IAction backward = ActionFactory.BACKWARD_HISTORY.create( window );
    backward.setId( IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY );
    IAction forward = ActionFactory.FORWARD_HISTORY.create( window );
    forward.setId( IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY );

    register( backward );
    register( forward );
}


回答2:

You have to implement the INavigationLocationProvider interface in your editor.

You can see how the Eclipse group implemented the interface in their AbstractTextEditor.



回答3:

Thank you, I have taken a look into the AbstractTextEditor implementation. Since I only want to navigate between the editors and not between the different locations inside an editor, I figured out that the simplest implementation should look like this:

public class MyEditor extends EditorPart implements INavigationLocationProvider {
public static final String ID = "MyEditor";

...

    @Override
    public INavigationLocation createEmptyNavigationLocation() {
        return new MyNavigationLocation( this );
    }

    @Override
    public INavigationLocation createNavigationLocation() {
        return new MyNavigationLocation( this );
    }
}

public class MyNavigationLocation extends NavigationLocation {

    public MyNavigationLocation( IEditorPart part ) {
        super( part );
    }

    @Override
    public boolean mergeInto( INavigationLocation location ) {
        return false;
    }

    @Override
    public void restoreLocation() {

    }

    @Override
    public void restoreState( IMemento memento ) {

    }

    @Override
    public void saveState( IMemento memento ) {

    }

    @Override
    public void update() {

    }
}

My problem is that it still doesn't work. I expect that the failure must lie somewhere else. Maybe I'm missing something in the Eclipse command configuration. Any ideas?

Edit:

The problem lies in the markLocation() method of the class NavigationHistory. It calls the private method addEntry(). The private variable ignoreEntries is in my case set to 1. That is why I can't mark locations in the history. Unfortunately I haven't figured out yet, why ignoreEntries is set to 1. The Eclipse documentation says nothing about it: http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2FINavigationHistory.html

/*
 * Adds a location to the history.
 */
private void addEntry(IEditorPart part) {
    if (ignoreEntries > 0 || part == null) {
        return;
    }

    ...
}

Second Edit:

I found out that each time a new editor is opened a history entry is added via the markEditor() method of NavigationHistory. The marking is done in the display thread and you cannot add further markings until the marking procedure finishes. If you want to mark a location directly after the opening of an editor, you have to call markLocation() in the display thread. Nevertheless my problem still exists. The back and forward NavigationHistoryAction in NavigationHistory are null. That is why my UI icons stay grayed out. Can someone send me the part of the plugin.xml where the navigation commands are specified? Then I can compare it with my configuration.