org.eclipse.contribution.xref.internal.ui.utils.XRefUIUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.contribution.xref.internal.ui.utils.XRefUIUtils.java

Source

/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *     Helen Hawkins   - iniital version
 *******************************************************************************/
package org.eclipse.contribution.xref.internal.ui.utils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.contribution.xref.core.IXReferenceAdapter;
import org.eclipse.contribution.xref.internal.ui.providers.TreeObject;
import org.eclipse.contribution.xref.internal.ui.providers.TreeParent;
import org.eclipse.contribution.xref.internal.ui.providers.XReferenceContentProvider;
import org.eclipse.contribution.xref.ui.IDeferredXReference;
import org.eclipse.contribution.xref.ui.XReferenceUIPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportContainer;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.ide.IDE;

/**
 * A utility class which contains common methods which are required
 * for both the Cross Reference View and the Cross Reference Inplace View.
 */
public class XRefUIUtils {

    private static Map workingCopyManagersForEditors = new HashMap();

    private static boolean selectedOutsideJavaElement = false;

    /**
     * Computes and returns the source reference.
     * 
     * This is taken from the computeHighlightRangeSourceReference() method
     * in the JavaEditor class which is used to populate the outline view
     * 
     * @return the computed source reference
     */
    public static ISourceReference computeHighlightRangeSourceReference(JavaEditor editor) {
        ISourceViewer sourceViewer = editor.getViewer();
        if (sourceViewer == null)
            return null;

        StyledText styledText = sourceViewer.getTextWidget();
        if (styledText == null)
            return null;

        int caret = 0;
        if (sourceViewer instanceof ITextViewerExtension5) {
            ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer;
            caret = extension.widgetOffset2ModelOffset(styledText.getCaretOffset());
        } else {
            int offset = sourceViewer.getVisibleRegion().getOffset();
            caret = offset + styledText.getCaretOffset();
        }

        IJavaElement element = getElementAt(editor, caret, false);

        if (!(element instanceof ISourceReference))
            return null;

        if (element.getElementType() == IJavaElement.IMPORT_DECLARATION) {

            IImportDeclaration declaration = (IImportDeclaration) element;
            IImportContainer container = (IImportContainer) declaration.getParent();
            ISourceRange srcRange = null;
            try {
                srcRange = container.getSourceRange();
            } catch (JavaModelException e) {
            }

            if (srcRange != null && srcRange.getOffset() == caret)
                return container;
        }

        return (ISourceReference) element;
    }

    /**
     * Returns the most narrow java element including the given offset.
     * 
     * This is taken from the getElementAt(int offset, boolean reconcile) method
     * in the CompilationUnitEditor class.
     */
    private static IJavaElement getElementAt(JavaEditor editor, int offset, boolean reconcile) {
        IWorkingCopyManager manager;
        if (workingCopyManagersForEditors.get(editor) instanceof IWorkingCopyManager) {
            manager = (IWorkingCopyManager) workingCopyManagersForEditors.get(editor);
        } else {
            manager = JavaPlugin.getDefault().getWorkingCopyManager();
        }
        ICompilationUnit unit = manager.getWorkingCopy(editor.getEditorInput());

        if (unit != null) {
            try {
                if (reconcile) {
                    synchronized (unit) {
                        unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
                    }
                    IJavaElement elementAt = unit.getElementAt(offset);
                    if (elementAt != null) {
                        return elementAt;
                    }
                    // this is if the selection in the editor
                    // is outside the {} of the class or aspect
                    IJavaElement[] children = unit.getChildren();
                    for (int i = 0; i < children.length; i++) {
                        if (children[i] instanceof SourceType) {
                            return children[i];
                        }
                    }
                } else if (unit.isConsistent()) {
                    // Bug 96313 - if there is no IJavaElement for the
                    // given offset, then check whether there are any
                    // children for this CU. There are if you've selected
                    // somewhere in the file and there aren't if there are
                    // compilation errors. Therefore, return one of these
                    // children and calculate the xrefs as though the user
                    // wants to display the xrefs for the entire file
                    IJavaElement elementAt = unit.getElementAt(offset);
                    if (elementAt != null) {
                        // a javaElement has been selected, therefore
                        // no need to go any further
                        return elementAt;
                    }
                    IResource res = unit.getCorrespondingResource();
                    if (res instanceof IFile) {
                        IFile file = (IFile) res;
                        IProject containingProject = file.getProject();
                        IMarker[] javaModelMarkers = containingProject.findMarkers(
                                IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
                        for (int i = 0; i < javaModelMarkers.length; i++) {
                            IMarker marker = javaModelMarkers[i];
                            if (marker.getResource().equals(file)) {
                                // there is an error in the file, therefore 
                                // we don't want to return any xrefs
                                return null;
                            }
                        }
                    }
                    // the selection was outside an IJavaElement, however, there
                    // are children for this compilation unit so we think you've
                    // selected outside of a java element.
                    if (elementAt == null && unit.getChildren().length != 0) {
                        selectedOutsideJavaElement = true;
                        return unit.getChildren()[0];
                    }
                }

            } catch (JavaModelException x) {
                if (!x.isDoesNotExist())
                    JavaPlugin.log(x.getStatus());
                // nothing found, be tolerant and go on
            } catch (CoreException e) {
            }
        }

        return null;
    }

    public static void revealInEditor(IJavaElement j) {
        try {
            IEditorPart p = JavaUI.openInEditor(j);
            JavaUI.revealInEditor(p, j);
        } catch (Exception ex) {
        }
    }

    // revealInEditor(IResource) might not work for inplace view
    public static void revealInEditor(IResource r) {
        IMarker m;
        try {
            m = r.createMarker(IMarker.MARKER);
            IDE.openEditor(getActiveWorkbenchWindow().getActivePage(), m, true);
            m.delete();
        } catch (CoreException e) {
        }
    }

    // evaluateXReferences might not work for inplace view 
    public static void evaluateXReferences(IDeferredXReference xr, TreeViewer viewer, Shell shell) {
        try {
            new ProgressMonitorDialog(shell).run(true, true, xr);
            if (!(viewer.getContentProvider() instanceof XReferenceContentProvider)) {
                return;
            }
            ((XReferenceContentProvider) viewer.getContentProvider()).refresh();
            viewer.refresh();
            viewer.expandToLevel(3);
        } catch (InterruptedException intEx) {
            // user cancelled - this is ok...
        } catch (InvocationTargetException invEx) {
            System.err.println("Something nasty here, " + xr + " could not be evaluated: " + invEx); //$NON-NLS-1$ //$NON-NLS-2$
        }
    }

    public static IWorkbenchWindow getActiveWorkbenchWindow() {
        return XReferenceUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
    }

    /**
     * Returns an ArrayList of the IXReferenceAdapters either for the current
     * selection, or for the file (ICompilationUnit) containing the current selection
     */
    public static List getXRefAdapterForSelection(IWorkbenchPart part, ISelection selection,
            boolean showParentCrosscutting) {
        List xrefAdapterList = new ArrayList();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            Object first = structuredSelection.getFirstElement();
            if (first instanceof IJavaElement) {
                return getXRefAdapterListForJavaElement((IJavaElement) first, showParentCrosscutting);
            }
        } else if (part instanceof IEditorPart && selection instanceof ITextSelection) {
            if (part instanceof JavaEditor) {
                JavaEditor je = (JavaEditor) part;
                ISourceReference sourceRef = XRefUIUtils.computeHighlightRangeSourceReference(je);
                IJavaElement javaElement = (IJavaElement) sourceRef;
                // if we want to show the parent crosscutting then need to show the xrefs for 
                // all top level SourceTypes declared in the containing compilation unit
                return getXRefAdapterListForJavaElement(javaElement, showParentCrosscutting);
            }
        }
        return xrefAdapterList;
    }

    public static IJavaElement getSelectedJavaElement(IWorkbenchPart part, ISelection selection) {
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            Object first = structuredSelection.getFirstElement();
            if (first instanceof IJavaElement) {
                if (!(first instanceof IJavaProject)) {
                    return (IJavaElement) first;
                }
            }
        } else if (part instanceof IEditorPart && selection instanceof ITextSelection) {
            if (part instanceof JavaEditor) {
                JavaEditor je = (JavaEditor) part;
                ISourceReference sourceRef = XRefUIUtils.computeHighlightRangeSourceReference(je);
                IJavaElement javaElement = (IJavaElement) sourceRef;
                return javaElement;
            }
        }
        return null;
    }

    public static List getXRefAdapterListForJavaElement(IJavaElement javaElement, boolean showParentCrosscutting) {
        List xrefAdapterList = new ArrayList();
        if (javaElement != null && !javaElement.exists()) {
            return xrefAdapterList;
        }
        // if we've selected outside a javaElement, for example before
        // the aspect declaration, or we've opted to show crosscutting for
        // the entire file then want to return a list of everything.
        if (javaElement != null && (showParentCrosscutting || selectedOutsideJavaElement)) {

            ICompilationUnit parent = (ICompilationUnit) javaElement.getAncestor(IJavaElement.COMPILATION_UNIT);
            if (parent != null) {
                try {
                    IType[] types = parent.getAllTypes();
                    for (int i = 0; i < types.length; i++) {
                        if ((types[i] instanceof SourceType)
                                && (types[i].getParent() instanceof ICompilationUnit)) {
                            IAdaptable a = types[i];
                            if (a != null) {
                                xrefAdapterList.add(a.getAdapter(IXReferenceAdapter.class));
                            }
                        }
                    }
                } catch (JavaModelException e) {
                }
            }
        } else {
            IAdaptable a = javaElement;
            if (a != null) {
                xrefAdapterList.add(a.getAdapter(IXReferenceAdapter.class));
            }
        }
        selectedOutsideJavaElement = false;
        return xrefAdapterList;
    }

    /**
     * Returns the current selection in the workbench
     */
    public static ISelection getCurrentSelection() {
        IWorkbenchWindow window = JavaPlugin.getActiveWorkbenchWindow();
        if (window != null) {
            return window.getSelectionService().getSelection();
        }
        return null;
    }

    public static TreeObject getTreeObjectForSelection(TreeViewer viewer, ISelection selection,
            IWorkbenchPart part) {
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            Object first = structuredSelection.getFirstElement();
            if (first instanceof IJavaElement) {
                return getTreeObjectForJavaElement(viewer.getTree().getItems(), (IJavaElement) first);
            } else if (first instanceof TreeObject) {
                Object data = ((TreeObject) first).getData();
                if (data instanceof IJavaElement) {
                    return getTreeObjectForJavaElement(viewer.getTree().getItems(), (IJavaElement) data);
                }
            }
        } else if (part instanceof IEditorPart && selection instanceof ITextSelection) {
            if (part instanceof JavaEditor) {
                JavaEditor je = (JavaEditor) part;
                ISourceReference sourceRef = XRefUIUtils.computeHighlightRangeSourceReference(je);
                IJavaElement javaElement = (IJavaElement) sourceRef;
                return getTreeObjectForJavaElement(viewer.getTree().getItems(), javaElement);
            }
        }
        return null;
    }

    public static TreeObject getTreeObjectForJavaElement(TreeItem[] items, IJavaElement javaElement) {
        for (int i = 0; i < items.length; i++) {
            Object o = items[i].getData();
            TreeParent treeParent = null;
            TreeObject treeObject = null;
            if (o instanceof TreeParent) {
                treeParent = (TreeParent) o;
            } else if (o instanceof TreeObject) {
                treeObject = (TreeObject) o;
            }
            TreeObject element = null;
            if (treeParent == null) {
                element = treeObject;
            } else {
                element = treeParent;
            }

            if (element != null && element.getData() != null) {
                if (element.getData().equals(javaElement)) {
                    return element;
                }
            }
            element = getTreeObjectForJavaElement(items[i].getItems(), javaElement);
            if (element != null)
                return element;
        }
        return null;
    }

    public static void setSelection(IWorkbenchPart part, ISelection selection, TreeViewer viewer) {
        TreeObject o = XRefUIUtils.getTreeObjectForSelection(viewer, selection, part);
        if (o != null) {
            viewer.setSelection(new StructuredSelection(o), true);
            viewer.reveal(o);
        } else if (selection != null) {
            viewer.setSelection(selection, true);
            viewer.reveal(selection);
        }
    }

    /**
     * Clients should call this if an editor is not managed by the default Java
     * WorkingCopyManager.  This enables elements in the editor to be found.
     * @param editor
     * @param workingCopyManager
     */
    // TODO: Is there a nicer way of doing this?
    public static void addWorkingCopyManagerForEditor(IEditorPart editor, IWorkingCopyManager workingCopyManager) {
        workingCopyManagersForEditors.put(editor, workingCopyManager);
    }

    /**
     * Clients should call this when an editor added to the set
     * of editors with different working copy managers is being disposed.
     * @param editor
     * @param workingCopyManager
     */
    public static void removeWorkingCopyManagerForEditor(IEditorPart editor) {
        workingCopyManagersForEditors.remove(editor);
    }
}