eu.esdihumboldt.hale.ui.util.groovy.ast.viewer.ASTViewer.java Source code

Java tutorial

Introduction

Here is the source code for eu.esdihumboldt.hale.ui.util.groovy.ast.viewer.ASTViewer.java

Source

/*
 * Copyright (c) 2013 Data Harmonisation Panel
 * 
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution. If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Data Harmonisation Panel <http://www.dhpanel.eu>
 */

package eu.esdihumboldt.hale.ui.util.groovy.ast.viewer;

import java.util.List;

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.VariableScope;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;

import com.google.common.collect.ListMultimap;

/**
 * A viewer for displaying Groovy AST nodes.
 * 
 * @author Simon Templer
 */
public class ASTViewer {

    private class ViewContentProvider extends ArrayContentProvider implements ITreeContentProvider {

        private ListMultimap<Object, ?> children;

        @Override
        public void dispose() {
            children = null;
        }

        @SuppressWarnings("unchecked")
        @Override
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            ASTToTreeVisitor v = new ASTToTreeVisitor();

            if (newInput instanceof Iterable<?>) {
                for (Object node : ((Iterable<?>) newInput)) {
                    if (node instanceof ASTNode) {
                        if (node instanceof ClassNode)
                            v.visitClass((ClassNode) node);
                    }
                }
            }

            children = v.getChildren();
        }

        @Override
        public Object getParent(Object child) {
            return null;
        }

        @Override
        public Object[] getChildren(Object parent) {
            if (children != null && parent instanceof ASTNode) {
                return children.get(parent).toArray();
            }
            return new Object[0];
        }

        @Override
        public boolean hasChildren(Object parent) {
            if (children != null && parent instanceof ASTNode) {
                return children.containsKey(parent);
            }
            return false;
        }
    }

    private class ViewLabelProvider extends LabelProvider {

        @Override
        public String getText(Object obj) {
            if (obj instanceof ASTNode) {
                ASTNode node = (ASTNode) obj;
                return node.getText();
            }

            return super.getText(obj);
        }

    }

    private final TreeViewer treeViewer;

    private Action doubleClickAction;

    private final ITextViewer textViewer;

    private final Composite page;

    /**
     * Constructor.
     * 
     * @param parent the parent composite
     * @param textViewer a text viewer where the code for an AST node should be
     *            selected on double click, or <code>null</code>
     */
    public ASTViewer(Composite parent, ITextViewer textViewer) {
        this.textViewer = textViewer;

        page = new Composite(parent, SWT.NONE);
        TreeColumnLayout layout = new TreeColumnLayout();
        page.setLayout(layout);

        treeViewer = new TreeViewer(page, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        //      new DrillDownAdapter(viewer);
        treeViewer.setContentProvider(new ViewContentProvider());
        treeViewer.setLabelProvider(new ViewLabelProvider());

        treeViewer.getTree().setHeaderVisible(true);

        TreeViewerColumn mainColumn = new TreeViewerColumn(treeViewer, SWT.NONE);
        mainColumn.setLabelProvider(new StyledCellLabelProvider() {

            @Override
            public void update(ViewerCell cell) {
                Object element = cell.getElement();

                StyledString text = new StyledString();
                text.append(element.getClass().getSimpleName());

                cell.setText(text.getString());
                cell.setStyleRanges(text.getStyleRanges());

                super.update(cell);
            }
        });
        mainColumn.getColumn().setText("Node");
        layout.setColumnData(mainColumn.getColumn(), new ColumnPixelData(200));

        TreeViewerColumn infoColumn = new TreeViewerColumn(treeViewer, SWT.NONE);
        infoColumn.setLabelProvider(new StyledCellLabelProvider() {

            @Override
            public void update(ViewerCell cell) {
                Object element = cell.getElement();

                StyledString text = new StyledString();
                if (element instanceof Parameter) {
                    // getText not implemented for Parameter
                    Parameter param = (Parameter) element;
                    text.append(param.getName());
                } else if (element instanceof ExpressionStatement) {
                    // getText not properly implemented for ExpressionStatement
                    text.append(((ExpressionStatement) element).getExpression().getText());
                } else if (element instanceof ASTNode) {
                    ASTNode node = (ASTNode) element;
                    text.append(node.getText());
                } else if (element instanceof Variable) {
                    Variable var = (Variable) element;
                    text.append(var.getName());
                } else {
                    text.append(element.toString());
                }

                cell.setText(text.getString());
                cell.setStyleRanges(text.getStyleRanges());

                super.update(cell);
            }
        });
        infoColumn.getColumn().setText("Text");
        layout.setColumnData(infoColumn.getColumn(), new ColumnPixelData(300));

        TreeViewerColumn propertiesColumn = new TreeViewerColumn(treeViewer, SWT.NONE);
        propertiesColumn.setLabelProvider(new StyledCellLabelProvider() {

            @Override
            public void update(ViewerCell cell) {
                Object element = cell.getElement();

                StyledString text = new StyledString();
                if (element instanceof Variable || element instanceof ASTNode || element instanceof VariableScope) {
                    ASTNodeUtil.addProperties(element, text);
                }

                cell.setText(text.getString());
                cell.setStyleRanges(text.getStyleRanges());

                super.update(cell);
            }
        });
        propertiesColumn.getColumn().setText("Properties");
        layout.setColumnData(propertiesColumn.getColumn(), new ColumnPixelData(1600));

        makeActions();
        if (textViewer != null) {
            addDoubleClickAction();
        }
    }

    /**
     * @return the control
     */
    public Control getControl() {
        return page;
    }

    /**
     * Set the input of the viewer to a set of AST Nodes
     * 
     * @param ast the AST nodes
     */
    public void setInput(List<ASTNode> ast) {
        treeViewer.setInput(ast);
    }

    private void makeActions() {
        doubleClickAction = new Action() {

            @Override
            public void run() {
                ISelection selection = treeViewer.getSelection();
                Object obj = ((IStructuredSelection) selection).getFirstElement();
                if (obj == null) {
                    return;
                }
                if (obj instanceof ASTNode) {
                    ASTNode node = (ASTNode) obj;
                    if (node.getLineNumber() != -1) {
                        try {
                            int offset0 = textViewer.getDocument().getLineOffset(node.getLineNumber() - 1)
                                    + node.getColumnNumber() - 1;
                            int offset1 = textViewer.getDocument().getLineOffset(node.getLastLineNumber() - 1)
                                    + node.getLastColumnNumber() - 1;
                            textViewer.setSelectedRange(offset0, offset1 - offset0);
                            textViewer.setTopIndex(node.getLineNumber() - 1);
                        } catch (BadLocationException e) {
                            // ignore
                        }
                    }
                }
            }
        };
    }

    private void addDoubleClickAction() {
        treeViewer.addDoubleClickListener(new IDoubleClickListener() {

            @Override
            public void doubleClick(DoubleClickEvent event) {
                doubleClickAction.run();
            }
        });
    }

    /**
     * @return the internal tree viewer
     */
    public TreeViewer getTreeViewer() {
        return treeViewer;
    }

}