tinyos.dlrc.editors.outline.NesCOutlinePage.java Source code

Java tutorial

Introduction

Here is the source code for tinyos.dlrc.editors.outline.NesCOutlinePage.java

Source

/*
 * Dlrc 2, NesC development in Eclipse.
 * Copyright (C) 2009 DLRC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Web:  http://tos-ide.ethz.ch
 * Mail: tos-ide@tik.ee.ethz.ch
 */
package tinyos.dlrc.editors.outline;

import static tinyos.dlrc.ep.parser.ASTNodeFilterFactory.and;
import static tinyos.dlrc.ep.parser.ASTNodeFilterFactory.not;
import static tinyos.dlrc.ep.parser.ASTNodeFilterFactory.subset;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
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.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
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.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;

import tinyos.dlrc.ProjectTOS;
import tinyos.dlrc.TinyOSPlugin;
import tinyos.dlrc.editors.INesCEditorParserClient;
import tinyos.dlrc.editors.NesCEditor;
import tinyos.dlrc.ep.parser.IASTModel;
import tinyos.dlrc.ep.parser.IASTModelElement;
import tinyos.dlrc.ep.parser.INesCParser;
import tinyos.dlrc.ep.parser.Tag;
import tinyos.dlrc.nature.MissingNatureException;
import tinyos.dlrc.preferences.PreferenceConstants;
import tinyos.dlrc.views.NodeContentProvider;
import tinyos.dlrc.views.NodeLabelComparator;
import tinyos.dlrc.views.NodeLabelProvider;
import tinyos.dlrc.views.NodeLocationComparator;
import tinyos.dlrc.views.NodeContentProvider.Element;

public class NesCOutlinePage extends ContentOutlinePage implements INesCEditorParserClient {
    private NesCEditor editor;

    private String contextMenuID = "outlineMenu";
    private Menu menu;

    private OpenFileAction openAction;

    private SorterAction sorterAction;

    private FilterSelectionAction filterAction;

    private MultiOutlineFilter filter;

    private IASTModel model;

    private NodeContentProvider provider;

    private boolean selecting = false;
    private long awaitSelectionEvent = 0;

    private org.eclipse.jface.util.IPropertyChangeListener propertyChangeListener;

    /**
     * Creates a content outline page using the given provider and the given editor.
     * @param editor the editor whose content this outline shows
     */
    public NesCOutlinePage(NesCEditor editor) {
        super();
        this.editor = editor;

        openAction = new OpenFileAction();

        editor.addParserClient(this);

        editor.getEditorSourceViewer().addPostSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                if (awaitSelectionEvent + 5000 > System.currentTimeMillis()) {
                    awaitSelectionEvent = 0;
                    return;
                }

                if (!selecting) {
                    try {
                        selecting = true;

                        IASTModelElement[] nodes = NesCOutlinePage.this.editor.getSelectedElements();
                        if (nodes != null) {
                            for (IASTModelElement node : nodes) {
                                Element element = provider.getElement(node);
                                if (element != null) {
                                    TreeSelection selection = new TreeSelection(
                                            new TreePath[] { element.getTreePath() });
                                    getTreeViewer().setSelection(selection);
                                    break;
                                }
                            }
                        }
                    } finally {
                        selecting = false;
                    }
                }
            }
        });

        // shows only the range in editor
        editor.showHighlightRangeOnly(false);

        this.addSelectionChangedListener(openAction);

    }

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

        final TreeViewer viewer = getTreeViewer();

        provider = new NodeContentProvider(and(not(subset(Tag.INCLUDED)), subset(Tag.OUTLINE)));
        provider.setExpandBaseTree(true);

        IProject project = editor.getProject();
        if (project != null) {
            try {
                ProjectTOS tos = TinyOSPlugin.getDefault().getProjectTOS(project);
                if (tos != null) {
                    provider.setBackup(0, tos.getModel());
                }
            } catch (MissingNatureException ex) {
                // ignore
            }
        }

        viewer.setContentProvider(provider);
        viewer.setLabelProvider(new NodeLabelProvider());
        viewer.addSelectionChangedListener(this);
        viewer.getTree().addMouseListener(new MouseListener() {
            public void mouseDoubleClick(MouseEvent e) {
                openAction.run();
            }

            public void mouseDown(MouseEvent e) {
                // ignore
            }

            public void mouseUp(MouseEvent e) {
                // ignore
            }
        });

        // Menu for Outlinepage
        MenuManager manager = new MenuManager(contextMenuID, contextMenuID);
        manager.setRemoveAllWhenShown(false);

        menu = manager.createContextMenu(viewer.getControl());
        viewer.getControl().setMenu(menu);

        getSite().registerContextMenu(contextMenuID, manager, viewer);

        manager.add(openAction);

        manager.add(new Separator());

        menu = manager.createContextMenu(viewer.getControl());

        //             required, for extensions
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));

        sorterAction = new SorterAction();
        filterAction = new FilterSelectionAction(this);

        contributeToActionBars();
        setFilters();

        // set a dummy input, the NodeContentProvider will take care of the rest
        viewer.setInput(new Object());

        setModel(editor.getASTModel());
        parent.layout();
    }

    private void contributeToActionBars() {
        IActionBars bars = getSite().getActionBars();
        fillLocalToolBar(bars.getToolBarManager());
    }

    private void fillLocalToolBar(IToolBarManager toolBar) {
        toolBar.add(sorterAction);
        toolBar.add(filterAction);
    }

    private void setFilters() {
        setFiltersSilent(getFilters());
    }

    @Override
    public void dispose() {
        if (propertyChangeListener != null) {
            TinyOSPlugin plugin = TinyOSPlugin.getDefault();
            if (plugin != null) {
                plugin.getPreferenceStore().removePropertyChangeListener(propertyChangeListener);
            }
            propertyChangeListener = null;
        }
        super.dispose();
    }

    public void setFilters(String[] ids) {
        IPreferenceStore store = TinyOSPlugin.getDefault().getPreferenceStore();
        StringBuilder builder = new StringBuilder();
        for (String id : ids) {
            builder.append(id);
            builder.append(';');
        }
        store.setValue(PreferenceConstants.OUTLINE_FILTER, builder.toString());

        setFiltersSilent(ids);
    }

    public String[] getFilters() {
        IPreferenceStore store = TinyOSPlugin.getDefault().getPreferenceStore();
        if (propertyChangeListener == null) {
            propertyChangeListener = new IPropertyChangeListener() {
                public void propertyChange(PropertyChangeEvent event) {
                    if (PreferenceConstants.OUTLINE_FILTER.equals(event.getProperty())) {
                        setFilters();
                    }
                }
            };
            store.addPropertyChangeListener(propertyChangeListener);
        }

        String ids = store.getString(PreferenceConstants.OUTLINE_FILTER);
        if (ids != null) {
            return ids.split(";");
        } else {
            return new String[] {};
        }
    }

    private void setFiltersSilent(String[] ids) {
        OutlineFilterFactory[] factories = TinyOSPlugin.getDefault().getOutlineFilters();
        Set<String> check = new HashSet<String>();
        for (String id : ids) {
            check.add(id);
        }
        filter = new MultiOutlineFilter();
        for (OutlineFilterFactory factory : factories) {
            if (check.contains(factory.getId())) {
                filter.add(factory.create());
            }
        }

        setFilter(filter);
    }

    private void setFilter(IOutlineFilter filter) {
        if (filter == null) {
            getTreeViewer().setFilters(new ViewerFilter[] {});
        } else {
            filter.setEditor(editor);
            getTreeViewer().setFilters(new ViewerFilter[] { new OutlineViewFilter(filter) });
        }
    }

    @Override
    public void selectionChanged(SelectionChangedEvent event) {
        super.selectionChanged(event);

        if (getTreeViewer().getControl().isFocusControl()) {
            if (!selecting) {
                try {
                    selecting = true;

                    ISelection selection = event.getSelection();

                    if (selection.isEmpty())
                        editor.resetHighlightRange();
                    else {
                        Object first = ((IStructuredSelection) selection).getFirstElement();
                        NodeContentProvider.Element element = (NodeContentProvider.Element) first;
                        editor.selectAndReveal(element.getRegion());
                    }
                    awaitSelectionEvent = System.currentTimeMillis();
                } finally {
                    selecting = false;
                }
            }
        }
    }

    protected class SorterAction extends SortTreeAction {
        private static final String SORT_TREE = "SortMembers"; //$NON-NLS-1$

        public SorterAction() {
            super(getSettings().getBoolean(SORT_TREE), new NodeLabelComparator(NodeContentProvider.PROPERTY_LABEL),
                    new NodeLocationComparator(NodeContentProvider.PROPERTY_LABEL,
                            NodeContentProvider.PROPERTY_ORDER));
        }

        @Override
        protected void setComparator(ViewerComparator comparator) {
            TreeViewer viewer = getTreeViewer();

            TreePath[] expanded = viewer.getExpandedTreePaths();
            viewer.setComparator(comparator);
            viewer.setExpandedTreePaths(expanded);
        }

        @Override
        protected void informSelected(boolean checked) {
            getSettings().put(SORT_TREE, checked);
        }
    }

    /**
     * Returns setting for this control.
     * 
     * @return Settings.
     */
    private IDialogSettings getSettings() {
        final String sectionName = "TinyOS.view.Outline";
        IDialogSettings settings = TinyOSPlugin.getDefault().getDialogSettings().getSection(sectionName);
        if (settings == null) {
            settings = TinyOSPlugin.getDefault().getDialogSettings().addNewSection(sectionName);
        }
        return settings;
    }

    public void setupParser(NesCEditor editor, INesCParser parser) {
        // nothing to do
    }

    public void closeParser(NesCEditor editor, boolean successful, INesCParser parser) {
        if (successful || model == null)
            setModel(parser.getASTModel());
    }

    public void setModel(final IASTModel model) {
        if (this.model != model) {
            this.model = model;

            UIJob job = new UIJob("Update outline") {
                @Override
                public IStatus runInUIThread(IProgressMonitor monitor) {
                    IASTModel model = NesCOutlinePage.this.model;

                    TreeViewer viewer = getTreeViewer();
                    if (viewer != null) {
                        Control control = viewer.getControl();
                        if (!control.isDisposed()) {
                            provider.setModel(model);
                        }
                    }

                    return Status.OK_STATUS;
                }
            };

            job.setSystem(true);
            job.setPriority(Job.INTERACTIVE);
            job.schedule();
        }
    }
}