ext.org.eclipse.jdt.internal.ui.callhierarchy.CallHierarchyUI.java Source code

Java tutorial

Introduction

Here is the source code for ext.org.eclipse.jdt.internal.ui.callhierarchy.CallHierarchyUI.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2011 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:
 *   Jesper Kamstrup Linnet (eclipse@kamstrup-linnet.dk) - initial API and implementation
 *          (report 36180: Callers/Callees view)
 *   Stephan Herrmann (stephan@cs.tu-berlin.de):
 *          - bug 75800: [call hierarchy] should allow searches for fields
 *******************************************************************************/
package ext.org.eclipse.jdt.internal.ui.callhierarchy;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.widgets.Shell;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;

import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;

import org.eclipse.ui.texteditor.ITextEditor;

import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaUI;

import patch.org.eclipse.jdt.internal.ui.JavaPlugin;

import ext.org.eclipse.jdt.internal.corext.callhierarchy.CallHierarchy;
import ext.org.eclipse.jdt.internal.corext.callhierarchy.CallLocation;
import ext.org.eclipse.jdt.internal.corext.callhierarchy.MethodWrapper;
import ext.org.eclipse.jdt.internal.corext.util.Messages;
import ext.org.eclipse.jdt.internal.ui.IJavaStatusConstants;
import ext.org.eclipse.jdt.internal.ui.actions.SelectionConverter;
import ext.org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import ext.org.eclipse.jdt.internal.ui.util.ExceptionHandler;

public class CallHierarchyUI {
    private static final int DEFAULT_MAX_CALL_DEPTH = 10;
    private static final String PREF_MAX_CALL_DEPTH = "PREF_MAX_CALL_DEPTH"; //$NON-NLS-1$

    private static CallHierarchyUI fgInstance;
    private int fViewCount = 0;
    private final List<IMember[]> fMethodHistory = new ArrayList<IMember[]>();

    /**
     * List of the Call Hierarchy views in LRU order, where the most recently used view is at index 0.
     * @since 3.7
     */
    private List<CallHierarchyViewPart> fLRUCallHierarchyViews = new ArrayList<CallHierarchyViewPart>();

    private CallHierarchyUI() {
        // Do nothing
    }

    public static CallHierarchyUI getDefault() {
        if (fgInstance == null) {
            fgInstance = new CallHierarchyUI();
        }

        return fgInstance;
    }

    /**
     * Returns the maximum tree level allowed
     * @return int
     */
    public int getMaxCallDepth() {
        int maxCallDepth;

        IPreferenceStore settings = JavaPlugin.getDefault().getPreferenceStore();
        maxCallDepth = settings.getInt(PREF_MAX_CALL_DEPTH);
        if (maxCallDepth < 1 || maxCallDepth > 99) {
            maxCallDepth = DEFAULT_MAX_CALL_DEPTH;
        }

        return maxCallDepth;
    }

    public void setMaxCallDepth(int maxCallDepth) {
        IPreferenceStore settings = JavaPlugin.getDefault().getPreferenceStore();
        settings.setValue(PREF_MAX_CALL_DEPTH, maxCallDepth);
    }

    public static void jumpToMember(IJavaElement element) {
        if (element != null) {
            try {
                JavaUI.openInEditor(element, true, true);
            } catch (JavaModelException e) {
                JavaPlugin.log(e);
            } catch (PartInitException e) {
                JavaPlugin.log(e);
            }
        }
    }

    public static void jumpToLocation(CallLocation callLocation) {
        try {
            IEditorPart methodEditor = JavaUI.openInEditor(callLocation.getMember(), false, false);
            if (methodEditor instanceof ITextEditor) {
                ITextEditor editor = (ITextEditor) methodEditor;
                editor.selectAndReveal(callLocation.getStart(), (callLocation.getEnd() - callLocation.getStart()));
            }
        } catch (JavaModelException e) {
            JavaPlugin.log(e);
        } catch (PartInitException e) {
            JavaPlugin.log(e);
        }
    }

    /**
     * Opens the element in the editor or shows an error dialog if that fails.
     *
     * @param element the element to open
     * @param shell parent shell for error dialog
     * @param activateOnOpen <code>true</code> if the editor should be activated
     * @return <code>true</code> iff no error occurred while trying to open the editor,
     *         <code>false</code> iff an error dialog was raised.
     */
    public static boolean openInEditor(Object element, Shell shell, boolean activateOnOpen) {
        CallLocation callLocation = CallHierarchy.getCallLocation(element);

        try {
            IMember enclosingMember;
            int selectionStart;
            int selectionLength;

            if (callLocation != null) {
                enclosingMember = callLocation.getMember();
                selectionStart = callLocation.getStart();
                selectionLength = callLocation.getEnd() - selectionStart;
            } else if (element instanceof MethodWrapper) {
                enclosingMember = ((MethodWrapper) element).getMember();
                ISourceRange selectionRange = enclosingMember.getNameRange();
                if (selectionRange == null)
                    selectionRange = enclosingMember.getSourceRange();
                if (selectionRange == null)
                    return true;
                selectionStart = selectionRange.getOffset();
                selectionLength = selectionRange.getLength();
            } else {
                return true;
            }

            IEditorPart methodEditor = JavaUI.openInEditor(enclosingMember, activateOnOpen, false);
            if (methodEditor instanceof ITextEditor) {
                ITextEditor editor = (ITextEditor) methodEditor;
                editor.selectAndReveal(selectionStart, selectionLength);
            }
            return true;
        } catch (JavaModelException e) {
            JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR,
                    CallHierarchyMessages.CallHierarchyUI_open_in_editor_error_message, e));

            ErrorDialog.openError(shell, CallHierarchyMessages.OpenLocationAction_error_title,
                    CallHierarchyMessages.CallHierarchyUI_open_in_editor_error_message, e.getStatus());
            return false;
        } catch (PartInitException x) {
            String name;
            if (callLocation != null)
                name = callLocation.getCalledMember().getElementName();
            else if (element instanceof MethodWrapper)
                name = ((MethodWrapper) element).getName();
            else
                name = ""; //$NON-NLS-1$
            MessageDialog.openError(shell, CallHierarchyMessages.OpenLocationAction_error_title,
                    Messages.format(CallHierarchyMessages.CallHierarchyUI_open_in_editor_error_messageArgs,
                            new String[] { name, x.getMessage() }));
            return false;
        }
    }

    public static IEditorPart isOpenInEditor(Object elem) {
        IJavaElement javaElement = null;
        if (elem instanceof MethodWrapper) {
            javaElement = ((MethodWrapper) elem).getMember();
        } else if (elem instanceof CallLocation) {
            javaElement = ((CallLocation) elem).getCalledMember();
        }
        if (javaElement != null) {
            return EditorUtility.isOpenInEditor(javaElement);
        }
        return null;
    }

    public static CallHierarchyViewPart openSelectionDialog(IMember[] candidates, IWorkbenchWindow window) {
        Assert.isTrue(candidates != null);

        IMember input = null;
        if (candidates.length > 1) {
            String title = CallHierarchyMessages.CallHierarchyUI_selectionDialog_title;
            String message = CallHierarchyMessages.CallHierarchyUI_selectionDialog_message;
            input = (IMember) SelectionConverter.selectJavaElement(candidates, window.getShell(), title, message);
        } else if (candidates.length == 1) {
            input = candidates[0];
        }
        if (input == null)
            return openView(new IMember[] {}, window);

        return openView(new IMember[] { input }, window);
    }

    public static CallHierarchyViewPart openView(IMember[] input, IWorkbenchWindow window) {
        if (input.length == 0) {
            MessageDialog.openInformation(window.getShell(),
                    CallHierarchyMessages.CallHierarchyUI_selectionDialog_title,
                    CallHierarchyMessages.CallHierarchyUI_open_operation_unavialable);
            return null;
        }
        IWorkbenchPage page = window.getActivePage();
        try {
            CallHierarchyViewPart viewPart = getDefault().findLRUCallHierarchyViewPart(page); //find the first view which is not pinned
            String secondaryId = null;
            if (viewPart == null) {
                if (page.findViewReference(CallHierarchyViewPart.ID_CALL_HIERARCHY) != null) //all the current views are pinned, open a new instance
                    secondaryId = String.valueOf(++getDefault().fViewCount);
            } else
                secondaryId = viewPart.getViewSite().getSecondaryId();
            viewPart = (CallHierarchyViewPart) page.showView(CallHierarchyViewPart.ID_CALL_HIERARCHY, secondaryId,
                    IWorkbenchPage.VIEW_ACTIVATE);
            viewPart.setInputElements(input);
            return viewPart;
        } catch (CoreException e) {
            ExceptionHandler.handle(e, window.getShell(), CallHierarchyMessages.CallHierarchyUI_error_open_view,
                    e.getMessage());
        }
        return null;
    }

    /**
     * Finds the first Call Hierarchy view part instance that is not pinned.
     * 
     * @param page the active page
     * @return the Call Hierarchy view part to open or <code>null</code> if none found
     * @since 3.7
     */
    private CallHierarchyViewPart findLRUCallHierarchyViewPart(IWorkbenchPage page) {
        boolean viewFoundInPage = false;
        for (Iterator<CallHierarchyViewPart> iter = fLRUCallHierarchyViews.iterator(); iter.hasNext();) {
            CallHierarchyViewPart view = iter.next();
            if (page.equals(view.getSite().getPage())) {
                if (!view.isPinned()) {
                    return view;
                }
                viewFoundInPage = true;
            }
        }
        if (!viewFoundInPage) {
            // find unresolved views
            IViewReference[] viewReferences = page.getViewReferences();
            for (int i = 0; i < viewReferences.length; i++) {
                IViewReference curr = viewReferences[i];
                if (CallHierarchyViewPart.ID_CALL_HIERARCHY.equals(curr.getId()) && page.equals(curr.getPage())) {
                    CallHierarchyViewPart view = (CallHierarchyViewPart) curr.getView(true);
                    if (view != null && !view.isPinned()) {
                        return view;
                    }
                }
            }
        }
        return null;
    }

    /**
     * Adds the activated view part to the head of the list.
     * 
     * @param view the Call Hierarchy view part
     * @since 3.7
     */
    void callHierarchyViewActivated(CallHierarchyViewPart view) {
        fLRUCallHierarchyViews.remove(view);
        fLRUCallHierarchyViews.add(0, view);
    }

    /**
     * Removes the closed view part from the list.
     * 
     * @param view the closed view part
     * @since 3.7
     */
    void callHierarchyViewClosed(CallHierarchyViewPart view) {
        fLRUCallHierarchyViews.remove(view);
    }

    /**
     * Converts an ISelection (containing MethodWrapper instances) to an ISelection
     * with the MethodWrapper's replaced by their corresponding IMembers. If the selection
     * contains elements which are not MethodWrapper instances or not already IMember instances
     * they are discarded.
     * @param selection The selection to convert.
     * @return An ISelection containing IMember's in place of MethodWrapper instances.
     */
    static ISelection convertSelection(ISelection selection) {
        if (selection.isEmpty()) {
            return selection;
        }

        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            List<IMember> javaElements = new ArrayList<IMember>();
            for (Iterator<?> iter = structuredSelection.iterator(); iter.hasNext();) {
                Object element = iter.next();
                if (element instanceof MethodWrapper) {
                    IMember member = ((MethodWrapper) element).getMember();
                    if (member != null) {
                        javaElements.add(member);
                    }
                } else if (element instanceof IMember) {
                    javaElements.add((IMember) element);
                } else if (element instanceof CallLocation) {
                    IMember member = ((CallLocation) element).getMember();
                    javaElements.add(member);
                }
            }
            return new StructuredSelection(javaElements);
        }
        return StructuredSelection.EMPTY;
    }

    /**
     * Clears the history and updates all the open views.
     * 
     * @since 3.7
     */
    void clearHistory() {
        for (Iterator<CallHierarchyViewPart> iter = fLRUCallHierarchyViews.iterator(); iter.hasNext();) {
            CallHierarchyViewPart part = iter.next();
            part.setHistoryEntries(new IMember[0][]);
            part.setInputElements(null);
        }
    }

    /**
     * Returns the method history.
     * 
     * @return the method history
     * @since 3.7
     */
    List<IMember[]> getMethodHistory() {
        return fMethodHistory;
    }
}