com.google.dart.tools.ui.internal.text.editor.LightNodeElements.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.ui.internal.text.editor.LightNodeElements.java

Source

/*
 * Copyright (c) 2013, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
 * 
 * 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.google.dart.tools.ui.internal.text.editor;

import com.google.common.collect.Lists;
import com.google.dart.engine.ast.ASTNode;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.ClassMember;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.CompilationUnitMember;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.FieldDeclaration;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.TopLevelVariableDeclaration;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.tools.ui.DartElementImageDescriptor;
import com.google.dart.tools.ui.DartPluginImages;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.internal.viewsupport.ImageDescriptorRegistry;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.TreeItem;

import java.util.List;

/**
 * Helper for creating and displaying {@link LightNodeElement}s.
 */
public class LightNodeElements {
    /**
     * {@link ViewerComparator} for {@link LightNodeElement} names.
     */
    public static class NameComparator extends ViewerComparator {
        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            if (!(e1 instanceof LightNodeElement)) {
                return 0;
            }
            if (!(e2 instanceof LightNodeElement)) {
                return 0;
            }
            String name1 = ((LightNodeElement) e1).getName();
            String name2 = ((LightNodeElement) e2).getName();
            if (name1 == null || name2 == null) {
                return 0;
            }
            return name1.compareTo(name2);
        }
    }

    /**
     * {@link ViewerComparator} for {@link LightNodeElement} positions.
     */
    public static class PositionComparator extends ViewerComparator {
        @Override
        public int compare(Viewer viewer, Object e1, Object e2) {
            if (!(e1 instanceof LightNodeElement)) {
                return 0;
            }
            if (!(e2 instanceof LightNodeElement)) {
                return 0;
            }
            int offset1 = ((LightNodeElement) e1).getNameOffset();
            int offset2 = ((LightNodeElement) e2).getNameOffset();
            return offset1 - offset2;
        }
    }

    /**
     * {@link ITreeContentProvider} for {@link LightNodeElement}s in {@link CompilationUnit}.
     */
    private static class NodeContentProvider implements ITreeContentProvider {
        private final IFile contextFile;
        private final List<LightNodeElement> elements = Lists.newArrayList();

        public NodeContentProvider(IFile contextFile) {
            this.contextFile = contextFile;
        }

        @Override
        public void dispose() {
        }

        @Override
        public Object[] getChildren(Object parentElement) {
            List<LightNodeElement> children = ((LightNodeElement) parentElement).children;
            return children.toArray(new LightNodeElement[children.size()]);
        }

        @Override
        public Object[] getElements(Object inputElement) {
            return elements.toArray(new LightNodeElement[elements.size()]);
        }

        @Override
        public Object getParent(Object element) {
            return ((LightNodeElement) element).getParent();
        }

        @Override
        public boolean hasChildren(Object element) {
            return getChildren(element).length != 0;
        }

        @Override
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            elements.clear();
            // prepare CompilationUnit
            CompilationUnit unit = (CompilationUnit) newInput;
            if (unit == null) {
                return;
            }
            // create elements
            for (CompilationUnitMember unitMember : unit.getDeclarations()) {
                if (unitMember instanceof TopLevelVariableDeclaration) {
                    TopLevelVariableDeclaration topVarDecl = (TopLevelVariableDeclaration) unitMember;
                    List<VariableDeclaration> variables = topVarDecl.getVariables().getVariables();
                    for (VariableDeclaration variable : variables) {
                        LightNodeElement element = createLightNodeElement(contextFile, null, variable, true);
                        if (element != null) {
                            elements.add(element);
                        }
                    }
                } else {
                    LightNodeElement element = createLightNodeElement(contextFile, null, unitMember, true);
                    if (element != null) {
                        elements.add(element);
                    }
                }
            }
        }
    }

    /**
     * {@link LabelProvider} for {@link LightNodeElement}.
     */
    private static class NodeLabelProvider extends LabelProvider {
        private static final Point SIZE = new Point(22, 16);
        private static final ImageDescriptorRegistry registry = DartToolsPlugin.getImageDescriptorRegistry();

        private static ImageDescriptor getBaseImageDescriptor(ASTNode node, boolean isPrivate) {
            if (node instanceof ClassDeclaration) {
                return isPrivate ? DartPluginImages.DESC_DART_CLASS_PRIVATE
                        : DartPluginImages.DESC_DART_CLASS_PUBLIC;
            }
            if (node instanceof VariableDeclaration) {
                return isPrivate ? DartPluginImages.DESC_DART_FIELD_PRIVATE
                        : DartPluginImages.DESC_DART_FIELD_PUBLIC;
            }
            if (node instanceof FunctionDeclaration || node instanceof ConstructorDeclaration
                    || node instanceof MethodDeclaration) {
                return isPrivate ? DartPluginImages.DESC_DART_METHOD_PRIVATE
                        : DartPluginImages.DESC_DART_METHOD_PUBLIC;
            }
            return null;
        }

        private static ImageDescriptor getImageDescriptor(ASTNode node, boolean isPrivate) {
            ImageDescriptor base = getBaseImageDescriptor(node, isPrivate);
            if (base == null) {
                return null;
            }
            int flags = 0;
            // ClassDeclaration
            if (node instanceof ClassDeclaration) {
                ClassDeclaration classDeclaration = (ClassDeclaration) node;
                if (classDeclaration.getAbstractKeyword() != null) {
                    flags |= DartElementImageDescriptor.ABSTRACT;
                }
            }
            // ConstructorDeclaration
            if (node instanceof ConstructorDeclaration) {
                flags |= DartElementImageDescriptor.CONSTRUCTOR;
            }
            // MethodDeclaration
            if (node instanceof MethodDeclaration) {
                MethodDeclaration method = (MethodDeclaration) node;
                if (method.isAbstract()) {
                    flags |= DartElementImageDescriptor.ABSTRACT;
                }
                if (method.isStatic()) {
                    flags |= DartElementImageDescriptor.STATIC;
                }
                if (method.isGetter()) {
                    flags |= DartElementImageDescriptor.GETTER;
                }
                if (method.isSetter()) {
                    flags |= DartElementImageDescriptor.SETTER;
                }
            }
            // done
            return new DartElementImageDescriptor(base, flags, SIZE);
        }

        @Override
        public Image getImage(Object o) {
            LightNodeElement element = (LightNodeElement) o;
            boolean isPrivate = element.isPrivate();
            ;
            ASTNode node = element.getNode();
            ImageDescriptor descriptor = getImageDescriptor(node, isPrivate);
            if (descriptor != null) {
                return registry.get(descriptor);
            }
            return null;
        }

        @Override
        public String getText(Object element) {
            return ((LightNodeElement) element).getName();
        }
    }

    public static final LabelProvider LABEL_PROVIDER = new NodeLabelProvider();
    public static final ViewerComparator NAME_COMPARATOR = new NameComparator();
    public static final ViewerComparator POSITION_COMPARATOR = new PositionComparator();

    /**
     * @return the {@link LightNodeElement} for given {@link ASTNode}, may be <code>null</code> if
     *         given is not declaration and does not have reasonable declaration child.
     */
    public static LightNodeElement createLightNodeElement(IFile contextFile, ASTNode node) {
        if (node == null) {
            return null;
        }
        // prepare "parent" and "childNode"
        LightNodeElement parent = null;
        ASTNode childNode = null;
        ClassDeclaration enclosingClass = node.getAncestor(ClassDeclaration.class);
        if (enclosingClass != null) {
            parent = createLightNodeElement(contextFile, null, enclosingClass, false);
            {
                MethodDeclaration method = node.getAncestor(MethodDeclaration.class);
                if (method != null) {
                    childNode = method;
                }
            }
            {
                ConstructorDeclaration constructor = node.getAncestor(ConstructorDeclaration.class);
                if (constructor != null) {
                    childNode = constructor;
                }
            }
            if (childNode == null) {
                childNode = node.getAncestor(VariableDeclaration.class);
            }
            if (childNode == null) {
                FieldDeclaration fieldDeclaration = node.getAncestor(FieldDeclaration.class);
                if (fieldDeclaration != null) {
                    List<VariableDeclaration> fields = fieldDeclaration.getFields().getVariables();
                    if (!fields.isEmpty()) {
                        childNode = fields.get(0);
                    }
                }
            }
        } else {
            {
                FunctionDeclaration function = node.getAncestor(FunctionDeclaration.class);
                if (function != null) {
                    childNode = function;
                }
            }
            if (childNode == null) {
                childNode = node.getAncestor(VariableDeclaration.class);
            }
            if (childNode == null) {
                TopLevelVariableDeclaration decl = node.getAncestor(TopLevelVariableDeclaration.class);
                if (decl != null) {
                    List<VariableDeclaration> vars = decl.getVariables().getVariables();
                    if (!vars.isEmpty()) {
                        childNode = vars.get(0);
                    }
                }
            }
        }
        // try to create LightNodeElement
        LightNodeElement element = createLightNodeElement(contextFile, parent, childNode, false);
        if (element == null) {
            element = parent;
        }
        return element;
    }

    /**
     * Expands {@link #viewer} us much as possible while still in the given time budget.
     */
    public static void expandTreeItemsTimeBoxed(TreeViewer viewer, long nanoBudget) {
        int numIterations = 10;
        int childrenLimit = 10;
        TreeItem[] rootTreeItems = viewer.getTree().getItems();
        for (int i = 0; i < numIterations; i++) {
            if (nanoBudget < 0) {
                break;
            }
            nanoBudget = expandTreeItemsTimeBoxed(viewer, rootTreeItems, childrenLimit, nanoBudget);
            childrenLimit *= 2;
        }
    }

    /**
     * @return the root {@link LightNodeElement}s created by {@link #newTreeContentProvider()}.
     */
    public static List<LightNodeElement> getRootElements(TreeViewer viewer) {
        return ((NodeContentProvider) viewer.getContentProvider()).elements;
    }

    /**
     * @return {@link ITreeContentProvider} for {@link TreeViewer} of {@link LightNodeElement}s.
     */
    public static ITreeContentProvider newTreeContentProvider(DartEditor editor) {
        IFile contextFile = editor.getInputResourceFile();
        return newTreeContentProvider(contextFile);
    }

    /**
     * @return {@link ITreeContentProvider} for {@link TreeViewer} of {@link LightNodeElement}s.
     */
    public static ITreeContentProvider newTreeContentProvider(IFile contextFile) {
        return new NodeContentProvider(contextFile);
    }

    private static LightNodeElement createLightNodeElement(IFile contextFile, LightNodeElement parent, ASTNode node,
            boolean withChildren) {
        // VariableDeclaration
        if (node instanceof VariableDeclaration) {
            VariableDeclaration variable = (VariableDeclaration) node;
            SimpleIdentifier nameNode = variable.getName();
            String name = nameNode.getName();
            return new LightNodeElement(contextFile, parent, variable, nameNode, name);
        }
        // ConstructorDeclaration
        if (node instanceof ConstructorDeclaration) {
            ConstructorDeclaration constructor = (ConstructorDeclaration) node;
            String name = parent.getName();
            SimpleIdentifier constructorName = constructor.getName();
            if (constructorName != null) {
                name += "." + constructorName.getName();
                return new LightNodeElement(contextFile, parent, node, constructorName, name);
            } else {
                return new LightNodeElement(contextFile, parent, node, constructor.getReturnType(), name);
            }
        }
        // method
        if (node instanceof MethodDeclaration) {
            MethodDeclaration method = (MethodDeclaration) node;
            SimpleIdentifier nameNode = method.getName();
            String name = nameNode.getName();
            if (method.isSetter()) {
                name += "=";
            }
            return new LightNodeElement(contextFile, parent, node, nameNode, name);
        }
        // ClassDeclaration
        if (node instanceof ClassDeclaration) {
            ClassDeclaration classDeclaration = (ClassDeclaration) node;
            SimpleIdentifier nameNode = classDeclaration.getName();
            LightNodeElement classElement = new LightNodeElement(contextFile, null, node, nameNode,
                    nameNode.getName());
            if (withChildren) {
                for (ClassMember classMember : classDeclaration.getMembers()) {
                    if (classMember instanceof FieldDeclaration) {
                        FieldDeclaration fieldDeclaration = (FieldDeclaration) classMember;
                        List<VariableDeclaration> fields = fieldDeclaration.getFields().getVariables();
                        for (VariableDeclaration field : fields) {
                            createLightNodeElement(contextFile, classElement, field, true);
                        }
                    } else {
                        createLightNodeElement(contextFile, classElement, classMember, true);
                    }
                }
            }
            return classElement;
        }
        // FunctionDeclaration
        if (node instanceof FunctionDeclaration) {
            FunctionDeclaration functionDeclaration = (FunctionDeclaration) node;
            SimpleIdentifier nameNode = functionDeclaration.getName();
            return new LightNodeElement(contextFile, null, functionDeclaration, nameNode, nameNode.getName());
        }
        // unknown
        return null;
    }

    /**
     * Expands given {@link TreeItem}s if they have not too much children and we have time budget.
     */
    private static long expandTreeItemsTimeBoxed(TreeViewer viewer, TreeItem[] items, int childrenLimit,
            long nanoBudget) {
        if (nanoBudget < 0) {
            return -1;
        }
        for (TreeItem item : items) {
            Object itemData = item.getData();
            // prepare LightNodeElement
            if (!(itemData instanceof LightNodeElement)) {
                continue;
            }
            LightNodeElement element = (LightNodeElement) itemData;
            // has children, not too many?
            int numChildren = element.children.size();
            if (numChildren == 0 || numChildren > childrenLimit) {
                continue;
            }
            // expand single item
            {
                long startNano = System.nanoTime();
                viewer.setExpandedState(itemData, true);
                nanoBudget -= System.nanoTime() - startNano;
            }
            // expand children
            nanoBudget = expandTreeItemsTimeBoxed(viewer, item.getItems(), childrenLimit, nanoBudget);
            if (nanoBudget < 0) {
                break;
            }
        }
        return nanoBudget;
    }
}