com.palantir.typescript.text.OutlinePage.java Source code

Java tutorial

Introduction

Here is the source code for com.palantir.typescript.text.OutlinePage.java

Source

/*
 * Copyright 2013 Palantir Technologies, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.palantir.typescript.text;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.List;

import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;

import com.google.common.collect.ImmutableList;
import com.palantir.typescript.navigate.NavigationBarItemLabelProvider;
import com.palantir.typescript.services.language.NavigationBarItem;
import com.palantir.typescript.services.language.TextSpan;
import com.palantir.typescript.text.actions.CollapseAllAction;

/**
 * The outline view.
 *
 * @author dcicerone
 */
public final class OutlinePage extends ContentOutlinePage {

    private final TypeScriptEditor editor;
    private final MySelectionListener selectionListener;

    public OutlinePage(TypeScriptEditor editor) {
        checkNotNull(editor);

        this.editor = editor;
        this.selectionListener = new MySelectionListener();
    }

    @Override
    public void createControl(Composite parent) {
        super.createControl(parent);

        List<NavigationBarItem> navigationBarItems = this.editor.getLanguageService().getNavigationBarItems();

        TreeViewer treeViewer = this.getTreeViewer();
        treeViewer.addSelectionChangedListener(new MySelectionChangedListener());
        treeViewer.setContentProvider(new ContentProvider());
        treeViewer.setLabelProvider(new NavigationBarItemLabelProvider());
        treeViewer.setInput(navigationBarItems);

        // add collapse all button
        IPageSite site = this.getSite();
        IActionBars actionBars = site.getActionBars();
        IToolBarManager toolBarManager = actionBars.getToolBarManager();
        toolBarManager.add(new CollapseAllAction(treeViewer));

        // expand all the nodes if there aren't too many of them
        if (navigationBarItems.size() < 500) {
            treeViewer.expandAll();
        }

        site.getWorkbenchWindow().getSelectionService().addPostSelectionListener(this.selectionListener);
    }

    @Override
    public void dispose() {
        super.dispose();

        this.getSite().getWorkbenchWindow().getSelectionService()
                .removePostSelectionListener(this.selectionListener);
    }

    public boolean isVisible() {
        Control control = this.getControl();

        return control != null && !control.isDisposed() && control.isVisible();
    }

    public void refreshInput() {
        List<NavigationBarItem> navigationBarItems = this.editor.getLanguageService().getNavigationBarItems();

        this.setInput(navigationBarItems);
    }

    public void setInput(List<NavigationBarItem> navigateToItems) {
        checkNotNull(navigateToItems);

        if (!navigateToItems.equals(this.getTreeViewer().getInput())) {
            List<TreePath> newExpandedTreePaths = mapTreePaths(navigateToItems);

            this.getTreeViewer().setInput(navigateToItems);
            this.getTreeViewer().setExpandedTreePaths(newExpandedTreePaths.toArray(new TreePath[0]));
        }
    }

    @Override
    protected int getTreeStyle() {
        return SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL;
    }

    private NavigationBarItem mapSegment(List<NavigationBarItem> lexicalStructure, NavigationBarItem segment) {
        for (NavigationBarItem item : lexicalStructure) {
            if (segment.getText().equals(item.getText())) {
                return item;
            }
        }

        return null;
    }

    private List<TreePath> mapTreePaths(List<NavigationBarItem> lexicalStructure) {
        ImmutableList.Builder<TreePath> treePaths = ImmutableList.builder();

        for (TreePath treePath : this.getTreeViewer().getExpandedTreePaths()) {
            TreePath newTreePath = TreePath.EMPTY;

            for (int i = 0; i < treePath.getSegmentCount(); i++) {
                NavigationBarItem segment = (NavigationBarItem) treePath.getSegment(i);
                NavigationBarItem newSegment = mapSegment(lexicalStructure, segment);
                if (newSegment != null) {
                    newTreePath = newTreePath.createChildPath(newSegment);
                }
            }

            treePaths.add(newTreePath);
        }

        return treePaths.build();
    }

    private final class MySelectionChangedListener implements ISelectionChangedListener {
        @Override
        public void selectionChanged(SelectionChangedEvent event) {
            // only respond to the selection change if the Tree is focused
            if (Display.getCurrent().getFocusControl() instanceof Tree) {
                TreeSelection selection = (TreeSelection) event.getSelection();
                NavigationBarItem item = (NavigationBarItem) selection.getFirstElement();

                if (item != null) {
                    TextSpan textSpan = item.getSpans().get(0);

                    OutlinePage.this.editor.selectAndReveal(textSpan.getStart(), textSpan.getLength(),
                            item.getText());
                }
            }
        }
    }

    private final class MySelectionListener implements ISelectionListener {
        @Override
        public void selectionChanged(IWorkbenchPart part, ISelection selection) {
            if (part instanceof TypeScriptEditor) {
                TextSelection textSelection = (TextSelection) selection;
                int offset = textSelection.getOffset();
                Tree tree = OutlinePage.this.getTreeViewer().getTree();
                TreeItem[] treeItems = tree.getItems();

                TreeItem bestItem = this.findBestMatch(treeItems, offset, null, -1);
                if (bestItem != null) {
                    tree.select(bestItem);
                } else {
                    tree.deselectAll();
                }
            }
        }

        private TreeItem findBestMatch(TreeItem[] treeItems, int offset, TreeItem bestItem, int bestSpanLength) {
            for (TreeItem treeItem : treeItems) {
                NavigationBarItem navigateToItem = (NavigationBarItem) treeItem.getData();

                if (navigateToItem != null) {
                    List<TextSpan> spans = navigateToItem.getSpans();

                    for (TextSpan span : spans) {
                        if (span.contains(offset)) {
                            // the best item is the one with the smallest span which contains the offset
                            if (bestItem == null || (span.getLength() < bestSpanLength)) {
                                bestItem = treeItem;
                                bestSpanLength = span.getLength();
                            }
                        }
                    }

                    bestItem = this.findBestMatch(treeItem.getItems(), offset, bestItem, bestSpanLength);
                }
            }

            return bestItem;
        }
    }
}