org.eclipse.cdt.internal.ui.includebrowser.IBViewPart.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.cdt.internal.ui.includebrowser.IBViewPart.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2013 Wind River Systems, Inc. and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Markus Schorn - initial API and implementation
 *     Ed Swartz (Nokia)
 *     Martin Oberhuber (Wind River) - bug 398195: consider external API in IB 
 *******************************************************************************/
package org.eclipse.cdt.internal.ui.includebrowser;

import java.util.ArrayList;
import java.util.Arrays;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.search.ui.IContextMenuConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ContributionItemFactory;
import org.eclipse.ui.actions.OpenFileAction;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.navigator.resources.ProjectExplorer;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IndexLocationFactory;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IWorkingCopy;
import org.eclipse.cdt.ui.CUIPlugin;

import org.eclipse.cdt.internal.ui.CPluginImages;
import org.eclipse.cdt.internal.ui.ICHelpContextIds;
import org.eclipse.cdt.internal.ui.navigator.OpenCElementAction;
import org.eclipse.cdt.internal.ui.util.Messages;
import org.eclipse.cdt.internal.ui.viewsupport.EditorOpener;
import org.eclipse.cdt.internal.ui.viewsupport.ExtendedTreeViewer;
import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
import org.eclipse.cdt.internal.ui.viewsupport.TreeNavigator;
import org.eclipse.cdt.internal.ui.viewsupport.WorkingSetFilterUI;

/**
 * The view part for the include browser.
 */
public class IBViewPart extends ViewPart implements IShowInSource, IShowInTarget, IShowInTargetList {
    private static final int MAX_HISTORY_SIZE = 10;
    private static final String TRUE = "true"; //$NON-NLS-1$
    private static final String FALSE = "false"; //$NON-NLS-1$
    private static final String KEY_WORKING_SET_FILTER = "workingSetFilter"; //$NON-NLS-1$
    private static final String KEY_FILTER_SYSTEM = "systemFilter"; //$NON-NLS-1$
    private static final String KEY_FILTER_INACTIVE = "inactiveFilter"; //$NON-NLS-1$
    private static final String KEY_INPUT_PATH = "inputPath"; //$NON-NLS-1$
    private static final String KEY_INCLUDED_BY = "includedBy"; //$NON-NLS-1$
    private static final String KEY_SHOW_FOLDERS = "showFolders"; //$NON-NLS-1$

    private IMemento fMemento;
    private boolean fShowsMessage;
    private IBNode fLastNavigationNode;
    private ArrayList<ITranslationUnit> fHistoryEntries = new ArrayList<ITranslationUnit>(MAX_HISTORY_SIZE);

    // widgets
    private PageBook fPagebook;
    private Composite fViewerPage;
    private Label fInfoText;

    // treeviewer
    private IBContentProvider fContentProvider;
    private IBLabelProvider fLabelProvider;
    private ExtendedTreeViewer fTreeViewer;

    // filters, sorter
    private IBWorkingSetFilter fWorkingSetFilter;
    private ViewerFilter fInactiveFilter;
    private ViewerFilter fSystemFilter;
    private ViewerComparator fSorterAlphaNumeric;
    private ViewerComparator fSorterReferencePosition;

    // actions
    private Action fIncludedByAction;
    private Action fIncludesToAction;
    private Action fFilterInactiveAction;
    private Action fFilterSystemAction;
    private Action fShowFolderInLabelsAction;
    private Action fNextAction;
    private Action fPreviousAction;
    private Action fRefreshAction;
    private Action fHistoryAction;
    private IContextActivation fContextActivation;
    private WorkingSetFilterUI fWorkingSetFilterUI;
    private IBSetInputJob fSetInputJob;

    @Override
    public void setFocus() {
        fPagebook.setFocus();
    }

    public void setMessage(String msg) {
        fInfoText.setText(msg);
        fPagebook.showPage(fInfoText);
        fShowsMessage = true;
        updateActionEnablement();
        updateDescription();
    }

    public void setInput(ITranslationUnit input) {
        if (fPagebook.isDisposed()) {
            return;
        }
        if (input instanceof IWorkingCopy) {
            input = ((IWorkingCopy) input).getOriginalElement();
        }
        fSetInputJob.cancel();
        if (input == null) {
            setMessage(IBMessages.IBViewPart_instructionMessage);
            fTreeViewer.setInput(null);
            return;
        }

        if (CCorePlugin.getIndexManager().isIndexerIdle()) {
            setInputIndexerIdle(input);
        } else {
            setMessage(IBMessages.IBViewPart_waitingOnIndexerMessage);
            fSetInputJob.setInput(input);
            fSetInputJob.schedule();
        }
    }

    private void setInputIndexerIdle(final ITranslationUnit input) {
        fShowsMessage = false;
        boolean isHeader = input.isHeaderUnit();

        fTreeViewer.setInput(null);
        if (!isHeader) {
            fContentProvider.setComputeIncludedBy(isHeader);
            fIncludedByAction.setChecked(isHeader);
            fIncludesToAction.setChecked(!isHeader);
            fIncludedByAction.setEnabled(false);
            updateSorter();
        } else {
            fIncludedByAction.setEnabled(true);
        }
        fTreeViewer.setInput(input);
        fPagebook.showPage(fViewerPage);
        updateHistory(input);

        updateActionEnablement();
        updateDescription();
        final Display display = Display.getCurrent();
        Job job = new Job(IBMessages.IBViewPart_jobCheckInput) {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                try {
                    final ICProject[] projects = CoreModel.getDefault().getCModel().getCProjects();
                    IIndex index = CCorePlugin.getIndexManager().getIndex(projects,
                            IIndexManager.ADD_EXTENSION_FRAGMENTS_INCLUDE_BROWSER);
                    index.acquireReadLock();
                    try {
                        if (!IndexUI.isIndexed(index, input)) {
                            // Bug 306879: Try to find an alternative translation unit for the file by the location.
                            final ITranslationUnit alt = CoreModelUtil
                                    .findTranslationUnitForLocation(input.getLocation(), input.getCProject());
                            if (alt != null && IndexUI.isIndexed(index, alt)) {
                                display.asyncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        if (fTreeViewer.getInput() == input) {
                                            setInput(alt);
                                        }
                                    }
                                });
                            } else {
                                final String msg = IndexUI.getFileNotIndexedMessage(input);
                                display.asyncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        if (fTreeViewer.getInput() == input) {
                                            setMessage(msg);
                                            fTreeViewer.setInput(null);
                                        }
                                    }
                                });
                            }
                        }
                        return Status.OK_STATUS;
                    } finally {
                        index.releaseReadLock();
                    }
                } catch (CoreException e) {
                    return Status.OK_STATUS;
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return Status.CANCEL_STATUS;
                }
            }
        };
        job.setSystem(true);
        job.schedule();
    }

    private void updateActionEnablement() {
        fHistoryAction.setEnabled(!fHistoryEntries.isEmpty());
        fNextAction.setEnabled(!fShowsMessage);
        fPreviousAction.setEnabled(!fShowsMessage);
        fRefreshAction.setEnabled(!fShowsMessage);
    }

    @Override
    public void createPartControl(Composite parent) {
        fSetInputJob = new IBSetInputJob(this, Display.getCurrent());

        fPagebook = new PageBook(parent, SWT.NULL);
        createInfoPage();
        createViewerPage();

        initDragAndDrop();
        createActions();
        createContextMenu();

        getSite().setSelectionProvider(fTreeViewer);
        setMessage(IBMessages.IBViewPart_instructionMessage);

        initializeActionStates();
        restoreInput();
        fMemento = null;

        IContextService ctxService = (IContextService) getSite().getService(IContextService.class);
        if (ctxService != null) {
            fContextActivation = ctxService.activateContext(CUIPlugin.CVIEWS_SCOPE);
        }

        PlatformUI.getWorkbench().getHelpSystem().setHelp(fPagebook, ICHelpContextIds.INCLUDE_BROWSER_VIEW);
    }

    @Override
    public void dispose() {
        putDialogSettings();
        if (fContextActivation != null) {
            IContextService ctxService = (IContextService) getSite().getService(IContextService.class);
            if (ctxService != null) {
                ctxService.deactivateContext(fContextActivation);
            }
        }
        if (fWorkingSetFilterUI != null) {
            fWorkingSetFilterUI.dispose();
        }
    }

    private void initializeActionStates() {
        IDialogSettings ds = getDialogSettings();

        boolean includedBy = !FALSE.equals(ds.get(KEY_INCLUDED_BY));
        fIncludedByAction.setChecked(includedBy);
        fIncludesToAction.setChecked(!includedBy);
        fContentProvider.setComputeIncludedBy(includedBy);

        fFilterInactiveAction.setChecked(TRUE.equals(ds.get(KEY_FILTER_INACTIVE)));
        fFilterInactiveAction.run();
        fFilterSystemAction.setChecked(TRUE.equals(ds.get(KEY_FILTER_SYSTEM)));
        fFilterSystemAction.run();
        fShowFolderInLabelsAction.setChecked(TRUE.equals((ds.get(KEY_SHOW_FOLDERS))));
        fShowFolderInLabelsAction.run();
        updateSorter();
    }

    private void restoreInput() {
        if (fMemento != null) {
            String pathStr = fMemento.getString(KEY_INPUT_PATH);
            if (pathStr != null) {
                IPath path = Path.fromPortableString(pathStr);
                if (path.segmentCount() > 1) {
                    String name = path.segment(0);
                    ICProject project = CoreModel.getDefault().getCModel().getCProject(name);
                    if (project != null) {
                        ICElement celement;
                        try {
                            celement = project.findElement(path);
                            if (celement instanceof ITranslationUnit) {
                                setInput((ITranslationUnit) celement);
                            }
                        } catch (CModelException e) {
                            // ignore
                        }
                    }
                }
            }
        }
    }

    @Override
    public void init(IViewSite site, IMemento memento) throws PartInitException {
        fMemento = memento;
        super.init(site, memento);
    }

    @Override
    public void saveState(IMemento memento) {
        putDialogSettings();
        if (memento != null) {
            if (fWorkingSetFilter != null) {
                fWorkingSetFilter.getUI().saveState(memento, KEY_WORKING_SET_FILTER);
            }
            ITranslationUnit input = getInput();
            if (input != null) {
                IPath path = input.getPath();
                if (path != null) {
                    memento.putString(KEY_INPUT_PATH, path.toPortableString());
                }
            }
        }
        super.saveState(memento);
    }

    private void putDialogSettings() {
        IDialogSettings ds = getDialogSettings();
        ds.put(KEY_FILTER_INACTIVE, String.valueOf(fFilterInactiveAction.isChecked()));
        ds.put(KEY_FILTER_SYSTEM, String.valueOf(fFilterSystemAction.isChecked()));
        ds.put(KEY_INCLUDED_BY, String.valueOf(fIncludedByAction.isChecked()));
        ds.put(KEY_SHOW_FOLDERS, String.valueOf(fShowFolderInLabelsAction.isChecked()));
    }

    private IDialogSettings getDialogSettings() {
        IDialogSettings ds = CUIPlugin.getDefault().getDialogSettings();
        final String name = IBViewPart.class.getName();
        IDialogSettings result = ds.getSection(name);
        if (result == null) {
            result = ds.addNewSection(name);
        }
        return result;
    }

    private void createContextMenu() {
        MenuManager manager = new MenuManager();
        manager.setRemoveAllWhenShown(true);
        manager.addMenuListener(new IMenuListener() {
            @Override
            public void menuAboutToShow(IMenuManager m) {
                onContextMenuAboutToShow(m);
            }
        });
        Menu menu = manager.createContextMenu(fTreeViewer.getControl());
        fTreeViewer.getControl().setMenu(menu);
        IWorkbenchPartSite site = getSite();
        site.registerContextMenu(CUIPlugin.ID_INCLUDE_BROWSER, manager, fTreeViewer);
    }

    private void createViewerPage() {
        Display display = getSite().getShell().getDisplay();
        fViewerPage = new Composite(fPagebook, SWT.NULL);
        fViewerPage.setLayoutData(new GridData(GridData.FILL_BOTH));
        fViewerPage.setSize(100, 100);
        fViewerPage.setLayout(new FillLayout());

        fContentProvider = new IBContentProvider(display);
        fLabelProvider = new IBLabelProvider(display, fContentProvider);
        fTreeViewer = new ExtendedTreeViewer(fViewerPage);
        fTreeViewer.setUseHashlookup(true);
        fTreeViewer.setContentProvider(fContentProvider);
        fTreeViewer.setLabelProvider(fLabelProvider);
        fTreeViewer.setAutoExpandLevel(2);
        fTreeViewer.addOpenListener(new IOpenListener() {
            @Override
            public void open(OpenEvent event) {
                onShowInclude(event.getSelection());
            }
        });
    }

    private void createInfoPage() {
        fInfoText = new Label(fPagebook, SWT.TOP | SWT.LEFT | SWT.WRAP);
    }

    private void initDragAndDrop() {
        IBDropTargetListener dropListener = new IBDropTargetListener(this);
        Transfer[] dropTransfers = new Transfer[] { LocalSelectionTransfer.getTransfer(),
                ResourceTransfer.getInstance(), FileTransfer.getInstance() };
        DropTarget dropTarget = new DropTarget(fPagebook,
                DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK | DND.DROP_DEFAULT);
        dropTarget.setTransfer(dropTransfers);
        dropTarget.addDropListener(dropListener);

        Transfer[] dragTransfers = new Transfer[] { ResourceTransfer.getInstance(), FileTransfer.getInstance() };
        IBDragSourceListener dragListener = new IBDragSourceListener(fTreeViewer);
        dragListener.setDependentDropTargetListener(dropListener);
        fTreeViewer.addDragSupport(DND.DROP_COPY, dragTransfers, dragListener);
    }

    private void createActions() {
        fWorkingSetFilterUI = new WorkingSetFilterUI(this, fMemento, KEY_WORKING_SET_FILTER) {
            @Override
            protected void onWorkingSetChange() {
                updateWorkingSetFilter(this);
            }

            @Override
            protected void onWorkingSetNameChange() {
                updateDescription();
            }
        };

        fIncludedByAction = new Action(IBMessages.IBViewPart_showIncludedBy_label, IAction.AS_RADIO_BUTTON) {
            @Override
            public void run() {
                if (isChecked()) {
                    onSetDirection(true);
                }
            }
        };
        fIncludedByAction.setToolTipText(IBMessages.IBViewPart_showIncludedBy_tooltip);
        CPluginImages.setImageDescriptors(fIncludedByAction, CPluginImages.T_LCL,
                CPluginImages.IMG_ACTION_SHOW_REF_BY);

        fIncludesToAction = new Action(IBMessages.IBViewPart_showIncludesTo_label, IAction.AS_RADIO_BUTTON) {
            @Override
            public void run() {
                if (isChecked()) {
                    onSetDirection(false);
                }
            }
        };
        fIncludesToAction.setToolTipText(IBMessages.IBViewPart_showIncludesTo_tooltip);
        CPluginImages.setImageDescriptors(fIncludesToAction, CPluginImages.T_LCL,
                CPluginImages.IMG_ACTION_SHOW_RELATES_TO);

        fInactiveFilter = new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                if (element instanceof IBNode) {
                    IBNode node = (IBNode) element;
                    return node.isActiveCode();
                }
                return true;
            }
        };
        fFilterInactiveAction = new Action(IBMessages.IBViewPart_hideInactive_label, IAction.AS_CHECK_BOX) {
            @Override
            public void run() {
                if (isChecked()) {
                    fTreeViewer.addFilter(fInactiveFilter);
                } else {
                    fTreeViewer.removeFilter(fInactiveFilter);
                }
            }
        };
        fFilterInactiveAction.setToolTipText(IBMessages.IBViewPart_hideInactive_tooltip);
        CPluginImages.setImageDescriptors(fFilterInactiveAction, CPluginImages.T_LCL,
                CPluginImages.IMG_ACTION_HIDE_INACTIVE);

        fSystemFilter = new ViewerFilter() {
            @Override
            public boolean select(Viewer viewer, Object parentElement, Object element) {
                if (element instanceof IBNode) {
                    IBNode node = (IBNode) element;
                    return !node.isSystemInclude();
                }
                return true;
            }
        };
        fFilterSystemAction = new Action(IBMessages.IBViewPart_hideSystem_label, IAction.AS_CHECK_BOX) {
            @Override
            public void run() {
                if (isChecked()) {
                    fTreeViewer.addFilter(fSystemFilter);
                } else {
                    fTreeViewer.removeFilter(fSystemFilter);
                }
            }
        };
        fFilterSystemAction.setToolTipText(IBMessages.IBViewPart_hideSystem_tooltip);
        CPluginImages.setImageDescriptors(fFilterSystemAction, CPluginImages.T_LCL,
                CPluginImages.IMG_ACTION_HIDE_SYSTEM);

        fSorterAlphaNumeric = new ViewerComparator();
        fSorterReferencePosition = new ViewerComparator() {
            @Override
            public int category(Object element) {
                if (element instanceof IBNode) {
                    return 0;
                }
                return 1;
            }

            @Override
            public int compare(Viewer viewer, Object e1, Object e2) {
                if (!(e1 instanceof IBNode)) {
                    if (!(e2 instanceof IBNode)) {
                        return 0;
                    }
                    return -1;
                }
                if (!(e2 instanceof IBNode)) {
                    return 1;
                }
                IBNode n1 = (IBNode) e1;
                IBNode n2 = (IBNode) e2;
                return n1.getDirectiveCharacterOffset() - n2.getDirectiveCharacterOffset();
            }
        };

        fShowFolderInLabelsAction = new Action(IBMessages.IBViewPart_showFolders_label, IAction.AS_CHECK_BOX) {
            @Override
            public void run() {
                onShowFolderInLabels(isChecked());
            }
        };
        fShowFolderInLabelsAction.setToolTipText(IBMessages.IBViewPart_showFolders_tooltip);
        fNextAction = new Action(IBMessages.IBViewPart_nextMatch_label) {
            @Override
            public void run() {
                onNextOrPrevious(true);
            }
        };
        fNextAction.setToolTipText(IBMessages.IBViewPart_nextMatch_tooltip);
        CPluginImages.setImageDescriptors(fNextAction, CPluginImages.T_LCL, CPluginImages.IMG_SHOW_NEXT);

        fPreviousAction = new Action(IBMessages.IBViewPart_previousMatch_label) {
            @Override
            public void run() {
                onNextOrPrevious(false);
            }
        };
        fPreviousAction.setToolTipText(IBMessages.IBViewPart_previousMatch_tooltip);
        CPluginImages.setImageDescriptors(fPreviousAction, CPluginImages.T_LCL, CPluginImages.IMG_SHOW_PREV);

        fRefreshAction = new Action(IBMessages.IBViewPart_refresh_label) {
            @Override
            public void run() {
                onRefresh();
            }
        };
        fRefreshAction.setToolTipText(IBMessages.IBViewPart_refresh_tooltip);
        CPluginImages.setImageDescriptors(fRefreshAction, CPluginImages.T_LCL, CPluginImages.IMG_REFRESH);

        fHistoryAction = new IBHistoryDropDownAction(this);

        // setup action bar
        // global action hooks
        IActionBars actionBars = getViewSite().getActionBars();
        actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), fNextAction);
        actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), fPreviousAction);
        actionBars.setGlobalActionHandler(ActionFactory.REFRESH.getId(), fRefreshAction);
        actionBars.updateActionBars();

        // local toolbar
        IToolBarManager tm = actionBars.getToolBarManager();
        tm.add(fNextAction);
        tm.add(fPreviousAction);
        tm.add(new Separator());
        tm.add(fFilterSystemAction);
        tm.add(fFilterInactiveAction);
        tm.add(new Separator());
        tm.add(fIncludedByAction);
        tm.add(fIncludesToAction);
        tm.add(fHistoryAction);
        tm.add(fRefreshAction);

        // local menu
        IMenuManager mm = actionBars.getMenuManager();

        fWorkingSetFilterUI.fillActionBars(actionBars);
        mm.add(fIncludedByAction);
        mm.add(fIncludesToAction);
        mm.add(new Separator());
        mm.add(fShowFolderInLabelsAction);
        mm.add(new Separator());
        mm.add(fFilterSystemAction);
        mm.add(fFilterInactiveAction);
    }

    private IBNode getNextNode(boolean forward) {
        TreeNavigator navigator = new TreeNavigator(fTreeViewer.getTree(), IBNode.class);
        TreeItem selectedItem = navigator.getSelectedItemOrFirstOnLevel(1, forward);
        if (selectedItem == null) {
            return null;
        }

        if (selectedItem.getData().equals(fLastNavigationNode)) {
            selectedItem = navigator.getNextSibbling(selectedItem, forward);
        }

        return selectedItem == null ? null : (IBNode) selectedItem.getData();
    }

    protected void onNextOrPrevious(boolean forward) {
        IBNode nextItem = getNextNode(forward);
        if (nextItem != null) {
            StructuredSelection sel = new StructuredSelection(nextItem);
            fTreeViewer.setSelection(sel);
            onShowInclude(sel);
        }
    }

    protected void onRefresh() {
        fContentProvider.recompute();
    }

    protected void onShowFolderInLabels(boolean show) {
        fLabelProvider.setShowFolders(show);
        fTreeViewer.refresh();
    }

    private void updateHistory(ITranslationUnit input) {
        if (input != null) {
            fHistoryEntries.remove(input);
            fHistoryEntries.add(0, input);
            if (fHistoryEntries.size() > MAX_HISTORY_SIZE) {
                fHistoryEntries.remove(MAX_HISTORY_SIZE - 1);
            }
        }
    }

    private void updateSorter() {
        if (fIncludedByAction.isChecked()) {
            fTreeViewer.setComparator(fSorterAlphaNumeric);
        } else {
            fTreeViewer.setComparator(fSorterReferencePosition);
        }
    }

    private void updateDescription() {
        String message = ""; //$NON-NLS-1$
        if (!fShowsMessage) {
            ITranslationUnit tu = getInput();
            if (tu != null) {
                IPath path = tu.getPath();
                if (path != null) {
                    String format, file, scope;

                    file = path.lastSegment() + "(" + path.removeLastSegments(1) + ")"; //$NON-NLS-1$//$NON-NLS-2$
                    if (fWorkingSetFilter == null) {
                        scope = IBMessages.IBViewPart_workspaceScope;
                    } else {
                        scope = fWorkingSetFilter.getLabel();
                    }

                    if (fIncludedByAction.isChecked()) {
                        format = IBMessages.IBViewPart_IncludedByContentDescription;
                    } else {
                        format = IBMessages.IBViewPart_IncludesToContentDescription;
                    }
                    message = Messages.format(format, file, scope);
                }
            }
        }
        setContentDescription(message);
    }

    private void updateWorkingSetFilter(WorkingSetFilterUI filterUI) {
        if (filterUI.getWorkingSet() == null) {
            if (fWorkingSetFilter != null) {
                fTreeViewer.removeFilter(fWorkingSetFilter);
                fWorkingSetFilter = null;
            }
        } else {
            if (fWorkingSetFilter != null) {
                fTreeViewer.refresh();
            } else {
                fWorkingSetFilter = new IBWorkingSetFilter(filterUI);
                fTreeViewer.addFilter(fWorkingSetFilter);
            }
        }
    }

    public void onSetDirection(boolean includedBy) {
        if (includedBy != fContentProvider.getComputeIncludedBy()) {
            Object input = fTreeViewer.getInput();
            fTreeViewer.setInput(null);
            fContentProvider.setComputeIncludedBy(includedBy);
            updateSorter();
            fTreeViewer.setInput(input);
            updateDescription();
        }
    }

    protected void onContextMenuAboutToShow(IMenuManager m) {
        final IStructuredSelection selection = (IStructuredSelection) fTreeViewer.getSelection();
        final IBNode node = IBConversions.selectionToNode(selection);

        if (node != null) {
            final IWorkbenchPage page = getSite().getPage();

            // open include
            if (node.getParent() != null && node.getDirectiveFile() != null) {
                m.add(new Action(IBMessages.IBViewPart_showInclude_label) {
                    @Override
                    public void run() {
                        onShowInclude(selection);
                    }
                });
            }

            final ITranslationUnit tu = node.getRepresentedTranslationUnit();
            if (tu != null) {
                // open
                OpenCElementAction ofa = new OpenCElementAction(page);
                ofa.selectionChanged(selection);
                m.add(ofa);

                // show in
                IMenuManager submenu = new MenuManager(IBMessages.IBViewPart_ShowInMenu_label);
                submenu.add(ContributionItemFactory.VIEWS_SHOW_IN.create(getSite().getWorkbenchWindow()));
                m.add(submenu);
                if (node.getParent() != null) {
                    m.add(new Separator());
                    m.add(new Action(
                            Messages.format(IBMessages.IBViewPart_FocusOn_label, tu.getPath().lastSegment())) {
                        @Override
                        public void run() {
                            setInput(tu);
                        }
                    });
                }
            }
        }
        m.add(new Separator(IContextMenuConstants.GROUP_ADDITIONS));
    }

    protected void onShowInclude(ISelection selection) {
        IBNode node = IBConversions.selectionToNode(selection);
        if (node != null) {
            fLastNavigationNode = node;

            IWorkbenchPage page = getSite().getPage();
            IBFile ibf = node.getDirectiveFile();
            if (ibf != null) {
                IRegion region = new Region(node.getDirectiveCharacterOffset(), node.getDirectiveLength());
                long timestamp = node.getTimestamp();

                IFile f = ibf.getResource();
                if (f != null) {
                    EditorOpener.open(page, f, region, timestamp);
                } else {
                    IIndexFileLocation ifl = ibf.getLocation();
                    if (ifl != null) {
                        IPath location = IndexLocationFactory.getAbsolutePath(ifl);
                        if (location != null) {
                            EditorOpener.openExternalFile(page, location, region, timestamp);
                        }
                    }
                }
            } else {
                ITranslationUnit tu = IBConversions.selectionToTU(selection);
                if (tu != null) {
                    IResource r = tu.getResource();
                    if (r != null) {
                        OpenFileAction ofa = new OpenFileAction(page);
                        ofa.selectionChanged((IStructuredSelection) selection);
                        ofa.run();
                    }
                }
            }
        }
    }

    @Override
    public ShowInContext getShowInContext() {
        return new ShowInContext(null,
                IBConversions.nodeSelectionToRepresentedTUSelection(fTreeViewer.getSelection()));
    }

    @Override
    public boolean show(ShowInContext context) {
        ITranslationUnit tu = IBConversions.selectionToTU(context.getSelection());
        if (tu == null) {
            tu = IBConversions.objectToTU(context.getInput());
            if (tu == null) {
                setMessage(IBMessages.IBViewPart_falseInputMessage);
                return false;
            }
        }

        setInput(tu);
        return true;
    }

    @Override
    public String[] getShowInTargetIds() {
        return new String[] { ProjectExplorer.VIEW_ID, IPageLayout.ID_PROJECT_EXPLORER };
    }

    // access for tests
    public TreeViewer getTreeViewer() {
        return fTreeViewer;
    }

    public ITranslationUnit[] getHistoryEntries() {
        return fHistoryEntries.toArray(new ITranslationUnit[fHistoryEntries.size()]);
    }

    public void setHistoryEntries(ITranslationUnit[] remaining) {
        fHistoryEntries.clear();
        fHistoryEntries.addAll(Arrays.asList(remaining));
    }

    public ITranslationUnit getInput() {
        Object input = fTreeViewer.getInput();
        if (input instanceof ITranslationUnit) {
            return (ITranslationUnit) input;
        }
        return null;
    }
}