org.caesarj.ui.editor.CaesarJContentOutlinePage.java Source code

Java tutorial

Introduction

Here is the source code for org.caesarj.ui.editor.CaesarJContentOutlinePage.java

Source

/*
 * This source file is part of CaesarJ 
 * For the latest info, see http://caesarj.org/
 * 
 * Copyright  2003-2005 
 * Darmstadt University of Technology, Software Technology Group
 * Also see acknowledgements in readme.txt
 * 
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * $Id: CaesarJContentOutlinePage.java,v 1.10 2006-10-06 17:05:47 gasiunas Exp $
 */

package org.caesarj.ui.editor;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.aspectj.asm.IProgramElement;
import org.aspectj.asm.internal.ProgramElement;
import org.aspectj.bridge.ISourceLocation;
import org.caesarj.compiler.asm.CaesarProgramElement;
import org.caesarj.compiler.asm.LinkNode;
import org.caesarj.ui.CaesarPlugin;
import org.caesarj.ui.util.ProjectProperties;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;

/**
 * Content Outline Page for Caesar Compilation Unit
 * 
 * 
 * @author Ivica Aracic <ivica.aracic@bytelords.de>
 * @author Thiago Tonelli Bartolomei <bart@macacos.org>
 */

public class CaesarJContentOutlinePage extends ContentOutlinePage {

    /**
     * TODO COMMENT!!
     */
    public static final Point BIG_SIZE = new Point(22, 16);

    /**
     * Contains the node categories that are diplayed in the outline 
     */
    protected static HashMap categoryMap = new HashMap();

    /**
     * Loads the node categories
     */
    static {
        categoryMap.put(ProgramElement.Kind.PACKAGE, new Integer(0));
        categoryMap.put(ProgramElement.Kind.FILE_JAVA, new Integer(1));
        categoryMap.put(ProgramElement.Kind.ASPECT, new Integer(5));
        categoryMap.put(ProgramElement.Kind.INTERFACE, new Integer(6));
        categoryMap.put(ProgramElement.Kind.CLASS, new Integer(7));
        categoryMap.put(ProgramElement.Kind.FIELD, new Integer(10));
        categoryMap.put(ProgramElement.Kind.CONSTRUCTOR, new Integer(11));
        categoryMap.put(ProgramElement.Kind.METHOD, new Integer(12));
        categoryMap.put(ProgramElement.Kind.ADVICE, new Integer(13));
        categoryMap.put(ProgramElement.Kind.CODE, new Integer(14));
    }

    /**
     * Log4j logger for the class
     */
    static Logger logger = Logger.getLogger(CaesarJContentOutlinePage.class);

    /**
     * Keep track of all Instances, so they can be updated when needed.
     * The keys for the hastable are project objects and the values are lists
     * of instances for each project.
     * When a Project is compiled, only the instance in the list for a project
     * are updated.
     */
    private static Hashtable instances = new Hashtable();

    /**
     * The CaesarEditor related to this outline page
     */
    protected CaesarEditor caesarEditor;

    /**
     * The project object related to the page the editor is using
     */
    protected IProject project;

    /**
     * The content provider for the tree
     */
    protected CaesarOutlineViewContentProvider contentProvider;

    /**
     * Flag to ignore first selection setting message
     */
    protected boolean bFirstSelection = true;

    /**
     * Creates a new ContentOutlinePage using the given caesarEditor. Puts this
     * new page in the list of instances
     * 
     * @param caesarEditorArg
     *            the caesareditor of this new outline page
     */
    public CaesarJContentOutlinePage(CaesarEditor caesarEditorArg, IProject project) {
        super();
        this.caesarEditor = caesarEditorArg;
        this.project = project;
        // Check if the project already has a instance list. If not, create a new
        List projectInstances = (List) instances.get(project);
        if (projectInstances == null)
            projectInstances = new Vector();

        // Put this instance in the project list and put the list in the hash
        projectInstances.add(this);
        CaesarJContentOutlinePage.instances.put(project, projectInstances);
    }

    /**
     * Creates the JFace control that displays the content
     */
    public void createControl(Composite parent) {
        super.createControl(parent);

        contentProvider = new CaesarOutlineViewContentProvider();

        // Creates the helper classes and associates them to the tree viewer
        TreeViewer viewer = getTreeViewer();
        //viewer.setSorter(new CaesarOutlineViewLexicalSorter());
        viewer.setSorter(new CaesarOutlineViewLineSorter());
        viewer.setContentProvider(contentProvider);
        viewer.setLabelProvider(new CaesarOutlineViewLabelProvider());
        viewer.addSelectionChangedListener(this);

        // Call update to create the initial state
        ProjectProperties properties = ProjectProperties.create(project);
        if (properties.getAsmManager() != null) {
            update(ProjectProperties.create(project));
        }
    }

    /**
     * This method is called when the user select a node in the content tree.
     * It searches the location of this node and opens it in the editor.
     * 
     * @see org.eclipse.jface.viewers.ISelectionChangedListener 
     */
    public void selectionChanged(SelectionChangedEvent event) {

        super.selectionChanged(event);

        /* ignore the first selection message that comes from initialization */
        /* necessary for navigation by crosscutting links */
        if (bFirstSelection) {
            bFirstSelection = false;
            return;
        }

        ISelection selection = event.getSelection();
        if (selection.isEmpty()) {
        } else {
            Object item = ((IStructuredSelection) selection).getFirstElement();

            if (item instanceof LinkNode) {
                if (((LinkNode) item).getType() == LinkNode.LINK_NODE_RELATIONSHIP) {
                    return;
                }
                item = ((LinkNode) item).getTargetElement();
            }

            IProgramElement selectedNode = (IProgramElement) item;
            ISourceLocation sourceLocation = selectedNode.getSourceLocation();

            if (sourceLocation != null) {
                try {

                    IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();

                    IPath path = new Path(sourceLocation.getSourceFile().getAbsolutePath());
                    IResource resource = root.getFileForLocation(path);
                    IMarker marker;

                    if (resource != null) {
                        marker = resource.createMarker(IMarker.MARKER);
                        marker.setAttribute(IMarker.LINE_NUMBER, sourceLocation.getLine());
                        marker.setAttribute(IMarker.CHAR_START, sourceLocation.getColumn());
                        IDE.openEditor(
                                CaesarPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(),
                                marker);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }

    //Iterates through the StructureModel and return the sourcefile node for 
    // the active editor input.
    protected IProgramElement getInput(IProgramElement node) {
        String filename = null;
        IEditorInput editorInput = this.caesarEditor.getEditorInput();
        if (editorInput instanceof IPathEditorInput) {
            filename = ((IPathEditorInput) editorInput).getPath().toFile().getAbsolutePath();
        }
        if (node == null) {
            return null;
        }
        if (filename == null) {
            return null;
        }
        IProgramElement r = null;
        //if (node.getName().equals(this.caesarEditor.getEditorInput().getName())) {
        if (node.getKind() != null && node.getKind().isSourceFile()
                && node.getSourceLocation().getSourceFile().getAbsolutePath().equals(filename)) {
            r = node;
        } else {
            IProgramElement res = null;
            for (Iterator it = node.getChildren().iterator(); it.hasNext() && res == null;) {
                res = getInput((IProgramElement) it.next());
            }
            r = res;
        }
        return r;
    }

    /**
     * Updates the outline page.
     */
    public void update(ProjectProperties properties) {

        IProgramElement input = getInput(properties.getAsmManager().getHierarchy().getRoot());

        TreeViewer viewer = getTreeViewer();
        if (viewer != null && input != null) {
            Control control = viewer.getControl();
            if (control != null && !control.isDisposed()) {
                control.setRedraw(false);
                viewer.setInput(input);
                viewer.expandAll();
                if (input instanceof CaesarProgramElement) {
                    // find and collapses the import node:
                    Iterator it = ((CaesarProgramElement) input).getChildren().iterator();
                    while (it.hasNext()) {
                        Object next = it.next();
                        if (next instanceof CaesarProgramElement) {
                            if (((CaesarProgramElement) next)
                                    .getCaesarKind() == CaesarProgramElement.Kind.IMPORTS) {
                                viewer.collapseToLevel(next, AbstractTreeViewer.ALL_LEVELS);
                            }
                        }
                    }
                }

                control.setRedraw(true);
            }
        }

    }

    /**
     * This method is called when all the instances for a project must be updated. It iterates
     * over the list and call their update method.
     */
    public static void updateAll(ProjectProperties properties) {
        List list = (List) instances.get(properties.getProject());
        if (list != null) {
            for (Iterator it = list.iterator(); it.hasNext();) {
                ((CaesarJContentOutlinePage) it.next()).update(properties);
            }
        }
    }

    /**
     * Removes the anInstance from the instance list.
     * 
     * @param anInstance a page instance on the list
     * @return true if the instance existed and was removed. False otherwise.
     */
    public static boolean removeInstance(CaesarJContentOutlinePage anInstance) {
        List list = (List) instances.get(anInstance.project);
        if (list != null) {
            // Remove the instance and keep track of the result
            boolean r = list.remove(anInstance);
            // If the list is empty, remove it from the hash
            if (list.size() == 0) {
                instances.remove(list);
            }
            return r;
        }
        return false;
    }

    /**
     * 
     * The sorter for the tree view.
     * 
     * This class sorts the nodes in the following order:
     * 
     *    - packages;
     *  - imports;
     *  - from here, sort using the line number;
     * 
     * @author Thiago Tonelli Bartolomei <bart@macacos.org>
     *
     */
    public class CaesarOutlineViewLineSorter extends ViewerSorter {

        /**
         * The comparator used to sort
         */
        private Comparator comparator;

        /**
         * Constructor, creates a comparator
         */
        public CaesarOutlineViewLineSorter() {

            comparator = new Comparator() {
                public int compare(Object o1, Object o2) {
                    if (o1 instanceof IProgramElement && o2 instanceof IProgramElement) {
                        // Make PACKAGE -> IMPORTS -> rest defined by line
                        IProgramElement.Kind k1 = ((IProgramElement) o1).getKind();
                        IProgramElement.Kind k2 = ((IProgramElement) o2).getKind();

                        // There's only one package, so, return if one is package
                        if (IProgramElement.Kind.PACKAGE == k1)
                            return -1;
                        if (IProgramElement.Kind.PACKAGE == k2)
                            return 1;

                        // There's only one imports, so, return if one is imports
                        // Remember that we have an ERROR node that represents the
                        // list of imports
                        if (IProgramElement.Kind.ERROR == k1)
                            return -1;
                        if (IProgramElement.Kind.ERROR == k2)
                            return 1;

                        // If we got here, return first the one which appears first
                        int l1 = ((IProgramElement) o1).getSourceLocation().getLine();
                        int l2 = ((IProgramElement) o2).getSourceLocation().getLine();
                        return l1 - l2;
                    }
                    if (o1 instanceof IProgramElement) {
                        return 1;
                    }
                    if (o2 instanceof IProgramElement) {
                        return -1;
                    }
                    return 0;
                }
            };
        }

        /**
         * Uses the comparator to sort the elements
         */
        public void sort(final Viewer viewer, Object[] elements) {
            if (elements.length <= 1) {
                return;
            }
            Arrays.sort(elements, comparator);
        }
    }
}