com.reprezen.swagedit.editor.outline.QuickOutline.java Source code

Java tutorial

Introduction

Here is the source code for com.reprezen.swagedit.editor.outline.QuickOutline.java

Source

/*******************************************************************************
 * Copyright (c) 2016 ModelSolv, 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:
 *    ModelSolv, Inc. - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.reprezen.swagedit.editor.outline;

import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlExtension;
import org.eclipse.jface.text.IInformationControlExtension2;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.part.ShowInContext;

import com.google.common.base.Strings;
import com.reprezen.swagedit.Messages;
import com.reprezen.swagedit.editor.SwaggerEditor;
import com.reprezen.swagedit.model.AbstractNode;
import com.reprezen.swagedit.model.Model;
import com.reprezen.swagedit.utils.DocumentUtils;
import com.reprezen.swagedit.utils.SwaggerFileFinder;
import com.reprezen.swagedit.utils.SwaggerFileFinder.Scope;

public class QuickOutline extends PopupDialog
        implements IInformationControl, IInformationControlExtension, IInformationControlExtension2 {

    public static final String COMMAND_ID = "com.reprezen.swagedit.commands.quickoutline";

    private Scope currentScope = Scope.LOCAL;
    private TreeViewer treeViewer;
    private SwaggerEditor editor;
    private Text filterText;
    private TriggerSequence triggerSequence;
    private String bindingKey;
    private Timer filterTimer = null;

    public QuickOutline(Shell parent, SwaggerEditor editor) {
        super(parent, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE, true, true, true, true, true, null, null);

        IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench()
                .getAdapter(IBindingService.class);
        this.bindingKey = bindingService.getBestActiveBindingFormattedFor(COMMAND_ID);
        this.triggerSequence = bindingService.getBestActiveBindingFor(COMMAND_ID);
        this.editor = editor;

        setInfoText(statusMessage());
        create();
    }

    @Override
    protected Control createTitleControl(Composite parent) {
        filterText = new Text(parent, SWT.NONE);
        Dialog.applyDialogFont(filterText);

        GridData data = new GridData(GridData.FILL_HORIZONTAL);
        data.horizontalAlignment = GridData.FILL;
        data.verticalAlignment = GridData.CENTER;
        filterText.setLayoutData(data);

        filterText.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                if (isInvocationEvent(e)) {
                    e.doit = false;
                    handleMultiView();
                } else if (e.keyCode == SWT.CR) {
                    handleSelection();
                    QuickOutline.this.close();
                } else if (e.keyCode == SWT.ARROW_DOWN) {
                    treeViewer.getTree().setFocus();
                } else if (e.keyCode == SWT.ARROW_UP) {
                    treeViewer.getTree().setFocus();
                } else if (e.character == SWT.ESC) {
                    QuickOutline.this.close();
                }
            }

            public void keyReleased(KeyEvent e) {
                // do nothing
            }
        });

        filterText.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                // refresh tree to apply filter

                if (filterTimer != null) {
                    filterTimer.cancel();
                }
                // reset the timer each time there is a
                // text modification, so that only the last
                // one will be executed.
                filterTimer = new Timer();
                filterTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        if (filterText.isDisposed()) {
                            return;
                        }

                        // Make sure we access the text in the correct thread.
                        filterText.getDisplay().asyncExec(new Runnable() {
                            @Override
                            public void run() {
                                // refreshing the tree will execute the filter.
                                if (Strings.emptyToNull(filterText.getText()) == null) {
                                    treeViewer.refresh();
                                    treeViewer.collapseAll();
                                } else {
                                    treeViewer.refresh();
                                    TreeItem[] items = treeViewer.getTree().getItems();
                                    if (items != null && items.length > 0) {
                                        treeViewer.getTree().setSelection(items[0]);
                                        treeViewer.getTree().showItem(items[0]);
                                    } else {
                                        treeViewer.setSelection(StructuredSelection.EMPTY);
                                    }
                                    treeViewer.expandAll();
                                }
                            }
                        });
                    }
                }, 500);
            }
        });
        return filterText;
    }

    protected void handleMultiView() {
        currentScope = currentScope.next();
        SwaggerFileFinder fileFinder = new SwaggerFileFinder();
        IEditorInput input = editor.getEditorInput();

        IFile currentFile = null;
        if (input instanceof IFileEditorInput) {
            currentFile = ((IFileEditorInput) input).getFile();
        }

        Iterable<IFile> files = fileFinder.collectFiles(currentScope, currentFile);
        setInfoText(statusMessage());

        if (currentScope == Scope.LOCAL) {
            treeViewer.setAutoExpandLevel(2);
        } else {
            treeViewer.setAutoExpandLevel(0);
        }

        setInput(Model.parseYaml(files));
    }

    protected String statusMessage() {
        switch (currentScope) {
        case PROJECT:
            return String.format(Messages.outline_proposal_workspace, bindingKey);
        case WORKSPACE:
            return String.format(Messages.outline_proposal_local, bindingKey);
        default: // LOCAL
            return String.format(Messages.outline_proposal_project, bindingKey);
        }
    }

    protected boolean isInvocationEvent(KeyEvent e) {
        int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
        KeySequence keySequence = KeySequence.getInstance(SWTKeySupport.convertAcceleratorToKeyStroke(accelerator));

        return keySequence.startsWith(triggerSequence, true);
    }

    protected TreeViewer createTreeViewer(Composite parent) {
        final Tree tree = new Tree(parent, SWT.SINGLE);
        GridData gd = new GridData(GridData.FILL_BOTH);
        gd.heightHint = tree.getItemHeight();
        tree.setLayoutData(gd);

        final TreeViewer treeViewer = new TreeViewer(tree);
        treeViewer.setContentProvider(new OutlineContentProvider());
        treeViewer.setLabelProvider(new OutlineStyledLabelProvider());
        treeViewer.addFilter(new NamePatternFilter());
        // Using ALL_LEVELS will cause editor to hang on large specs
        treeViewer.setAutoExpandLevel(2);
        treeViewer.setUseHashlookup(true);

        tree.addKeyListener(new KeyListener() {
            @Override
            public void keyReleased(KeyEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void keyPressed(KeyEvent e) {
                if (isInvocationEvent(e)) {
                    e.doit = false;
                    handleMultiView();
                } else if (e.keyCode == SWT.CR) {
                    handleSelection();
                    QuickOutline.this.close();
                }
            }
        });
        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDown(MouseEvent e) {
                super.mouseDown(e);
            }

            public void mouseUp(MouseEvent e) {
                if (tree.getSelectionCount() < 1) {
                    return;
                }
                if (e.button != 1) {
                    return;
                }

                if (tree.equals(e.getSource())) {
                    Object o = tree.getItem(new Point(e.x, e.y));
                    TreeItem selection = tree.getSelection()[0];
                    if (selection.equals(o)) {
                        handleSelection();
                    }
                }
            }
        });
        tree.addSelectionListener(new SelectionListener() {
            public void widgetSelected(SelectionEvent e) {
                // do nothing
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                handleSelection();
            }
        });

        return treeViewer;
    }

    protected void handleSelection() {
        ITreeSelection selection = (ITreeSelection) treeViewer.getSelection();

        if (selection != null) {
            Object element = selection.getFirstElement();

            if (element instanceof AbstractNode) {
                Model model = ((AbstractNode) element).getModel();

                if (model.getPath() != null) {
                    DocumentUtils.openAndReveal(model.getPath(), selection);
                } else {
                    editor.show(new ShowInContext(null, selection));
                }
            }
        }
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        treeViewer = createTreeViewer(parent);
        return treeViewer.getControl();
    }

    @Override
    public void setInput(Object input) {
        if (input instanceof Model) {
            Model model = (Model) input;
            if (model.getPath() == null) {
                IFile currentFile = null;
                IEditorInput editorInput = editor.getEditorInput();

                if (editorInput instanceof IFileEditorInput) {
                    currentFile = ((IFileEditorInput) editorInput).getFile();
                }
                if (currentFile != null) {
                    model.setPath(currentFile.getFullPath());
                }
            }
        }

        treeViewer.setInput(input);
        treeViewer.setSelection(null, true);
    }

    @Override
    public boolean hasContents() {
        if (treeViewer == null || treeViewer.getInput() == null) {
            return false;
        }
        return true;
    }

    @Override
    public void setInformation(String information) {
    }

    @Override
    public void setSizeConstraints(int maxWidth, int maxHeight) {
        getShell().setSize(maxWidth, maxHeight);
    }

    @Override
    public Point computeSizeHint() {
        return getShell().getSize();
    }

    @Override
    public void setVisible(boolean visible) {
        if (visible) {
            open();
        } else {
            saveDialogBounds(getShell());
            getShell().setVisible(false);
        }
    }

    @Override
    public void setSize(int width, int height) {
        getShell().setSize(width, height);
    }

    @Override
    public void setLocation(Point location) {
        getShell().setLocation(location);
    }

    @Override
    public void dispose() {
        close();
    }

    @Override
    public void addDisposeListener(DisposeListener listener) {
        getShell().addDisposeListener(listener);
    }

    @Override
    public void removeDisposeListener(DisposeListener listener) {
        getShell().removeDisposeListener(listener);
    }

    @Override
    public void setForegroundColor(Color foreground) {
        applyForegroundColor(foreground, getContents());
    }

    @Override
    public void setBackgroundColor(Color background) {
        applyBackgroundColor(background, getContents());
    }

    @Override
    public boolean isFocusControl() {
        return treeViewer.getTree().isFocusControl() || filterText.isFocusControl();
    }

    @Override
    public void setFocus() {
        getShell().forceFocus();
        if (filterText != null) {
            filterText.setFocus();
        }
    }

    @Override
    public void addFocusListener(FocusListener listener) {
        getShell().addFocusListener(listener);
    }

    @Override
    public void removeFocusListener(FocusListener listener) {
        getShell().removeFocusListener(listener);
    }

    private boolean matchesFilter(Object element) {
        if (treeViewer == null) {
            return true;
        }

        if (element instanceof AbstractNode) {
            String matchName = ((AbstractNode) element).getText();
            String text = filterText.getText();

            if (Strings.emptyToNull(text) == null) {
                return true;
            }

            if (matchName != null) {
                return matchName.toLowerCase().contains(text.toLowerCase());
            }
        }

        return false;
    }

    public class NamePatternFilter extends ViewerFilter {

        @Override
        public boolean select(Viewer viewer, Object parentElement, Object element) {
            if (viewer == null || matchesFilter(element)) {
                return true;
            }

            return hasUnfilteredChild((TreeViewer) viewer, element);
        }

        /*
         * Returns true if one of it's children is a filter element.
         */
        private boolean hasUnfilteredChild(TreeViewer viewer, Object element) {
            Object[] children = ((OutlineContentProvider) viewer.getContentProvider()).getChildren(element);
            for (Object o : children) {
                if (select(viewer, element, o)) {
                    return true;
                }
            }
            return false;
        }
    }

}