Java tutorial
/* * Copyright (c) 2012, 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.callhierarchy; import com.google.dart.tools.core.model.DartElement; import com.google.dart.tools.core.model.TypeMember; import com.google.dart.tools.core.search.SearchScope; import com.google.dart.tools.ui.DartElementLabels; import com.google.dart.tools.ui.DartToolsPlugin; import com.google.dart.tools.ui.DartUI; import com.google.dart.tools.ui.IContextMenuConstants; import com.google.dart.tools.ui.Messages; import com.google.dart.tools.ui.actions.CCPActionGroup; import com.google.dart.tools.ui.actions.DartSearchActionGroup; import com.google.dart.tools.ui.actions.GenerateActionGroup; import com.google.dart.tools.ui.actions.OpenEditorActionGroup; import com.google.dart.tools.ui.internal.callhierarchy.CallHierarchy; import com.google.dart.tools.ui.internal.callhierarchy.CallLocation; import com.google.dart.tools.ui.internal.callhierarchy.MethodWrapper; import com.google.dart.tools.ui.internal.callhierarchy.RealCallers; import com.google.dart.tools.ui.internal.text.DartHelpContextIds; import com.google.dart.tools.ui.internal.text.editor.CompositeActionGroup; import com.google.dart.tools.ui.internal.text.editor.EditorUtility; import com.google.dart.tools.ui.internal.util.DartUIHelp; import com.google.dart.tools.ui.internal.util.SelectionUtil; import com.google.dart.tools.ui.internal.viewsupport.SelectionProviderMediator; import com.google.dart.tools.ui.internal.viewsupport.StatusBarUpdater; import org.eclipse.core.runtime.Assert; import org.eclipse.help.IContextProvider; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.util.OpenStrategy; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IMemento; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IViewReference; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.OpenAndLinkWithEditorHelper; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.part.IShowInSource; import org.eclipse.ui.part.IShowInTargetList; import org.eclipse.ui.part.PageBook; import org.eclipse.ui.part.ShowInContext; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; import org.eclipse.ui.texteditor.ITextEditor; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * This is the main view for the call hierarchy. It builds a tree of callers/callees and allows the * user to double click an entry to go to the selected method. */ public class CallHierarchyViewPart extends ViewPart implements ICallHierarchyViewPart, ISelectionChangedListener { private final class CallHierarchyOpenEditorHelper extends OpenAndLinkWithEditorHelper { public CallHierarchyOpenEditorHelper(StructuredViewer viewer) { super(viewer); } @Override protected void activate(ISelection selection) { final Object selectedElement = SelectionUtil.getSingleElement(selection); if (selectedElement != null) { CallHierarchyUI.openInEditor(selectedElement, getSite().getShell(), true); } } @Override protected void linkToEditor(ISelection selection) { // not supported by this part } @Override protected void open(ISelection selection, boolean activate) { if (selection instanceof IStructuredSelection) { for (Iterator<?> iter = ((IStructuredSelection) selection).iterator(); iter.hasNext();) { boolean noError = CallHierarchyUI.openInEditor(iter.next(), getSite().getShell(), OpenStrategy.activateOnOpen()); if (!noError) { return; } } } } } private class CallHierarchySelectionProvider extends SelectionProviderMediator { public CallHierarchySelectionProvider(StructuredViewer[] viewers) { super(viewers, null); } @Override public ISelection getSelection() { ISelection selection = super.getSelection(); if (!selection.isEmpty()) { return CallHierarchyUI.convertSelection(selection); } return selection; } } static final int VIEW_ORIENTATION_VERTICAL = 0; static final int VIEW_ORIENTATION_HORIZONTAL = 1; static final int VIEW_ORIENTATION_SINGLE = 2; static final int VIEW_ORIENTATION_AUTOMATIC = 3; static final int CALL_MODE_CALLERS = 0; static final int CALL_MODE_CALLEES = 1; static final String GROUP_SEARCH_SCOPE = "MENU_SEARCH_SCOPE"; //$NON-NLS-1$ static final String ID_CALL_HIERARCHY = "com.google.dart.tools.ui.callhierarchy.view"; //$NON-NLS-1$ private static final String DIALOGSTORE_VIEWORIENTATION = "CallHierarchyViewPart.orientation"; //$NON-NLS-1$ private static final String DIALOGSTORE_CALL_MODE = "CallHierarchyViewPart.call_mode"; //$NON-NLS-1$ private static final String DIALOGSTORE_FIELD_MODE = "CallHierarchyViewPart.field_mode"; //$NON-NLS-1$ /** The key to be used is <code>DIALOGSTORE_RATIO + fCurrentOrientation</code>. */ private static final String DIALOGSTORE_RATIO = "CallHierarchyViewPart.ratio"; //$NON-NLS-1$ private static final String GROUP_FOCUS = "group.focus"; //$NON-NLS-1$ private static final int PAGE_EMPTY = 0; private static final int PAGE_VIEWER = 1; static CallHierarchyViewPart findAndShowCallersView(IWorkbenchPartSite site) { IWorkbenchPage workbenchPage = site.getPage(); CallHierarchyViewPart callersView = null; try { callersView = (CallHierarchyViewPart) workbenchPage.showView(CallHierarchyViewPart.ID_CALL_HIERARCHY); } catch (PartInitException e) { DartToolsPlugin.log(e); } return callersView; } private static String getShortLabel(DartElement member) { return DartElementLabels.getElementLabel(member, 0L); } protected Composite parent; int orientation = VIEW_ORIENTATION_AUTOMATIC; private Label noHierarchyShownLabel; private PageBook pagebook; private final IDialogSettings dialogSettings; private int currentOrientation; private int currentCallMode; // private int currentFieldMode; // TODO change type to MatchKind private MethodWrapper[] calleeRoots; private MethodWrapper[] callerRoots; private IMemento savedMemento; private DartElement[] currentInputElements; private CallHierarchySelectionProvider selectionProviderMediator; private LocationViewer locationViewer; private SashForm hierarchyLocationSplitter; private Clipboard clipboard; private SearchScopeActionGroup searchScopeActions; private ToggleOrientationAction[] toggleOrientationActions; private ToggleCallModeAction[] toggleCallModeActions; // private SelectFieldModeAction[] toggleFieldModeActions; private CallHierarchyFiltersActionGroup filtersActionGroup; private HistoryDropDownAction historyDropDownAction; private RefreshElementAction refreshSingleElementAction; private RefreshViewAction refreshViewAction; private OpenLocationAction openLocationAction; private LocationCopyAction locationCopyAction; private FocusOnSelectionAction focusOnSelectionAction; private CopyCallHierarchyAction copyAction; private CancelSearchAction cancelSearchAction; // private ExpandWithConstructorsAction expandWithConstructorsAction; private RemoveFromViewAction removeFromViewAction; private ShowSearchInDialogAction showSearchInDialogAction; private CompositeActionGroup actionGroups; private CallHierarchyViewer callHierarchyViewer; private boolean showCallDetails; private IPartListener2 fPartListener; private boolean isPinned; private PinCallHierarchyViewAction pinViewAction; public CallHierarchyViewPart() { super(); dialogSettings = DartToolsPlugin.getDefault().getDialogSettings(); isPinned = false; } @Override public void createPartControl(Composite parent) { this.parent = parent; addResizeListener(parent); pagebook = new PageBook(parent, SWT.NONE); // Page 1: Viewers createHierarchyLocationSplitter(pagebook); createCallHierarchyViewer(hierarchyLocationSplitter); createLocationViewer(hierarchyLocationSplitter); // Page 2: Nothing selected noHierarchyShownLabel = new Label(pagebook, SWT.TOP + SWT.LEFT + SWT.WRAP); noHierarchyShownLabel.setText(CallHierarchyMessages.CallHierarchyViewPart_empty); // showPage(PAGE_EMPTY); PlatformUI.getWorkbench().getHelpSystem().setHelp(pagebook, DartHelpContextIds.CALL_HIERARCHY_VIEW); selectionProviderMediator = new CallHierarchySelectionProvider( new StructuredViewer[] { callHierarchyViewer, locationViewer }); IStatusLineManager slManager = getViewSite().getActionBars().getStatusLineManager(); selectionProviderMediator.addSelectionChangedListener(new StatusBarUpdater(slManager)); getSite().setSelectionProvider(selectionProviderMediator); callHierarchyViewer.initContextMenu(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager menu) { fillCallHierarchyViewerContextMenu(menu); } }, getSite(), selectionProviderMediator); clipboard = new Clipboard(parent.getDisplay()); makeActions(); fillViewMenu(); fillActionBars(); initDragAndDrop(); initOrientation(); initCallMode(); initFieldMode(); if (savedMemento != null) { restoreState(savedMemento); } restoreSplitterRatio(); addPartListener(); } @Override public void dispose() { if (actionGroups != null) { actionGroups.dispose(); } if (clipboard != null) { clipboard.dispose(); } if (fPartListener != null) { getViewSite().getPage().removePartListener(fPartListener); fPartListener = null; } super.dispose(); } @Override public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { if (adapter == IContextProvider.class) { return DartUIHelp.getHelpContextProvider(this, DartHelpContextIds.CALL_HIERARCHY_VIEW); } if (adapter == IShowInSource.class) { return new IShowInSource() { @Override public ShowInContext getShowInContext() { return new ShowInContext(null, selectionProviderMediator.getSelection()); } }; } if (adapter == IShowInTargetList.class) { return new IShowInTargetList() { @Override public String[] getShowInTargetIds() { return new String[] { DartUI.ID_FILE_VIEW }; } }; } return super.getAdapter(adapter); } public MethodWrapper[] getCurrentMethodWrappers() { if (currentCallMode == CALL_MODE_CALLERS) { return callerRoots; } else { return calleeRoots; } } /** * Gets all history entries. * * @return all history entries */ public DartElement[][] getHistoryEntries() { if (getMethodHistory().size() > 0) { updateHistoryEntries(); } return getMethodHistory().toArray(new DartElement[getMethodHistory().size()][]); } public DartElement[] getInputElements() { return currentInputElements; } /** * Fetches the search scope with the appropriate include mask. * * @param includeMask the include mask * @return the search scope with the appropriate include mask */ public SearchScope getSearchScope(int includeMask) { return searchScopeActions.getSearchScope(includeMask); } /** * Returns the call hierarchy viewer. * * @return the call hierarchy viewer */ public CallHierarchyViewer getViewer() { return callHierarchyViewer; } /** * Goes to the selected entry, without updating the order of history entries. * * @param entry the history entry */ public void gotoHistoryEntry(DartElement[] entry) { for (Iterator<DartElement[]> iter = getMethodHistory().iterator(); iter.hasNext();) { if (Arrays.equals(entry, iter.next())) { setInputElements(entry); return; } } } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); savedMemento = memento; } public void refresh() { setCalleeRoots(null); setCallerRoots(null); updateView(); } @Override public void saveState(IMemento memento) { if (pagebook == null) { // part has not been created if (savedMemento != null) { //Keep the old state; memento.putMemento(savedMemento); } return; } searchScopeActions.saveState(memento); } @Override public void selectionChanged(SelectionChangedEvent e) { if (e.getSelectionProvider() == callHierarchyViewer) { methodSelectionChanged(e.getSelection()); } } @Override public void setFocus() { pagebook.setFocus(); } /** * Sets the history entries * * @param entries the new history entries */ public void setHistoryEntries(DartElement[][] entries) { getMethodHistory().clear(); for (int i = 0; i < entries.length; i++) { getMethodHistory().add(entries[i]); } updateHistoryEntries(); } public void setInputElements(DartElement[] members) { DartElement[] oldMembers = currentInputElements; currentInputElements = members; if (members == null || members.length == 0) { showPage(PAGE_EMPTY); return; } if (!Arrays.equals(members, oldMembers)) { addHistoryEntry(members); } refresh(); } public void setShowCallDetails(boolean show) { showCallDetails = show; showOrHideCallDetailsView(); } @Override public void showBusy(boolean busy) { super.showBusy(busy); if (!busy) { getProgressService().warnOfContentChange(); } } protected void fillCallHierarchyViewerContextMenu(IMenuManager menu) { DartToolsPlugin.createStandardGroups(menu); menu.appendToGroup(IContextMenuConstants.GROUP_SHOW, refreshSingleElementAction); menu.appendToGroup(IContextMenuConstants.GROUP_SHOW, new Separator(GROUP_FOCUS)); if (focusOnSelectionAction.canActionBeAdded()) { menu.appendToGroup(GROUP_FOCUS, focusOnSelectionAction); } // if (fExpandWithConstructorsAction.canActionBeAdded()) { // menu.appendToGroup(GROUP_FOCUS, fExpandWithConstructorsAction); // } if (removeFromViewAction.canActionBeAdded()) { menu.appendToGroup(GROUP_FOCUS, removeFromViewAction); } actionGroups.setContext(new ActionContext(getSelection())); actionGroups.fillContextMenu(menu); actionGroups.setContext(null); if (copyAction.canActionBeAdded()) { menu.appendToGroup("group.edit" /* ICommonMenuConstants.GROUP_EDIT */, copyAction); } } protected void fillLocationViewerContextMenu(IMenuManager menu) { DartToolsPlugin.createStandardGroups(menu); menu.appendToGroup(IContextMenuConstants.GROUP_SHOW, openLocationAction); menu.appendToGroup(IContextMenuConstants.GROUP_SHOW, refreshSingleElementAction); menu.appendToGroup(IContextMenuConstants.GROUP_REORGANIZE, locationCopyAction); } /** * Returns the location viewer. * * @return the location viewer */ protected LocationViewer getLocationViewer() { return locationViewer; } /** * Returns the current selection. * * @return selection */ protected ISelection getSelection() { StructuredViewer viewerInFocus = selectionProviderMediator.getViewerInFocus(); if (viewerInFocus != null) { return viewerInFocus.getSelection(); } return StructuredSelection.EMPTY; } protected void saveViewSettings() { saveSplitterRatio(); dialogSettings.put(DIALOGSTORE_VIEWORIENTATION, orientation); } /** * Adds the new input elements to the current list. * * @param newElements the new input elements to add */ void addInputElements(TypeMember[] newElements) { // Caveat: RemoveFromViewAction#run() disposes TreeItems. When we add a previously removed element, // we have to consider the real Tree state, not only fInputElements. List<DartElement> inputElements = Arrays.asList(currentInputElements); List<DartElement> treeElements = new ArrayList<DartElement>(); TreeItem[] treeItems = callHierarchyViewer.getTree().getItems(); for (int i = 0; i < treeItems.length; i++) { Object data = treeItems[i].getData(); if (data instanceof MethodWrapper) { treeElements.add(((MethodWrapper) data).getMember()); } } List<DartElement> newInput = new ArrayList<DartElement>(); newInput.addAll(inputElements); List<DartElement> addedElements = new ArrayList<DartElement>(); for (int i = 0; i < newElements.length; i++) { TypeMember newElement = newElements[i]; if (!inputElements.contains(newElement)) { newInput.add(newElement); } if (!treeElements.contains(newElement)) { addedElements.add(newElement); } } if (treeElements.size() == 0) { updateInputHistoryAndDescription(currentInputElements, newElements); } else if (newInput.size() > currentInputElements.length) { updateInputHistoryAndDescription(currentInputElements, newInput.toArray(new TypeMember[newInput.size()])); } if (addedElements.size() > 0) { updateViewWithAddedElements(addedElements.toArray(new TypeMember[addedElements.size()])); } } /** * Cancels the caller/callee search jobs that are currently running. */ void cancelJobs() { callHierarchyViewer.cancelJobs(); } void computeOrientation() { saveSplitterRatio(); dialogSettings.put(DIALOGSTORE_VIEWORIENTATION, orientation); if (orientation != VIEW_ORIENTATION_AUTOMATIC) { setOrientation(orientation); } else { if (orientation == VIEW_ORIENTATION_SINGLE) { return; } Point size = parent.getSize(); if (size.x != 0 && size.y != 0) { if (size.x > size.y) { setOrientation(VIEW_ORIENTATION_HORIZONTAL); } else { setOrientation(VIEW_ORIENTATION_VERTICAL); } } } } /** * Returns the current call mode. * * @return the current call mode: CALL_MODE_CALLERS or CALL_MODE_CALLEES */ int getCallMode() { return currentCallMode; } /** * Indicates whether the Call Hierarchy view is pinned. * * @return <code>true</code> if the view is pinned, <code>false</code> otherwise */ boolean isPinned() { return isPinned; } /** * called from ToggleCallModeAction. * * @param mode CALL_MODE_CALLERS or CALL_MODE_CALLEES */ void setCallMode(int mode) { if (currentCallMode != mode) { for (int i = 0; i < toggleCallModeActions.length; i++) { toggleCallModeActions[i].setChecked(mode == toggleCallModeActions[i].getMode()); } currentCallMode = mode; dialogSettings.put(DIALOGSTORE_CALL_MODE, mode); updateView(); } } /** * Sets the enablement state of the cancel button. * * @param enabled <code>true</code> if cancel should be enabled */ void setCancelEnabled(boolean enabled) { cancelSearchAction.setEnabled(enabled); } /** * called from SelectFieldModeAction. * * @param mode IJavaSearchConstants.{REFERENCES,WRITE_ACCESS,READ_ACCESS} */ void setFieldMode(int mode) { // if (currentFieldMode != mode) { // for (int i = 0; i < toggleFieldModeActions.length; i++) { // toggleFieldModeActions[i].setChecked(mode == toggleFieldModeActions[i].getMode()); // } // // currentFieldMode = mode; // dialogSettings.put(DIALOGSTORE_FIELD_MODE, mode); // // updateView(); // } } /** * called from ToggleOrientationAction. * * @param orientation VIEW_ORIENTATION_HORIZONTAL or VIEW_ORIENTATION_VERTICAL */ void setOrientation(int orientation) { if (currentOrientation != orientation) { if ((locationViewer != null) && !locationViewer.getControl().isDisposed() && (hierarchyLocationSplitter != null) && !hierarchyLocationSplitter.isDisposed()) { if (orientation == VIEW_ORIENTATION_SINGLE) { setShowCallDetails(false); } else { if (currentOrientation == VIEW_ORIENTATION_SINGLE) { setShowCallDetails(true); } boolean horizontal = orientation == VIEW_ORIENTATION_HORIZONTAL; hierarchyLocationSplitter.setOrientation(horizontal ? SWT.HORIZONTAL : SWT.VERTICAL); } hierarchyLocationSplitter.layout(); } updateCheckedState(); currentOrientation = orientation; restoreSplitterRatio(); } } /** * Marks the view as pinned. * * @param pinned if <code>true</code> the view is marked as pinned */ void setPinned(boolean pinned) { isPinned = pinned; } /** * Updates the input, history and description for the new input. * * @param currentInput the current input * @param entry the new input elements */ void updateInputHistoryAndDescription(DartElement[] currentInput, DartElement[] entry) { updateHistoryEntries(currentInput, entry); currentInputElements = entry; setContentDescription(getIncludeMask()); } @SuppressWarnings("unused") private void addDragAdapters(StructuredViewer viewer) { // int ops = DND.DROP_COPY | DND.DROP_LINK; // // Transfer[] transfers = new Transfer[] { // LocalSelectionTransfer.getTransfer(), ResourceTransfer.getInstance(), // FileTransfer.getInstance()}; // // DelegatingDragAdapter dragAdapter = new DelegatingDragAdapter() { // @Override // public void dragStart(DragSourceEvent event) { // IStructuredSelection selection = (IStructuredSelection) fSelectionProviderMediator.getSelection(); // if (selection.isEmpty()) { // event.doit = false; // return; // } // super.dragStart(event); // } // }; // dragAdapter.addDragSourceListener(new SelectionTransferDragAdapter(fSelectionProviderMediator)); // dragAdapter.addDragSourceListener(new EditorInputTransferDragAdapter(fSelectionProviderMediator)); // dragAdapter.addDragSourceListener(new ResourceTransferDragAdapter(fSelectionProviderMediator)); // dragAdapter.addDragSourceListener(new FileTransferDragAdapter(fSelectionProviderMediator)); // // viewer.addDragSupport(ops, transfers, dragAdapter); } @SuppressWarnings("unused") private void addDropAdapters(StructuredViewer viewer) { // Transfer[] transfers = new Transfer[] { // LocalSelectionTransfer.getTransfer(), PluginTransfer.getInstance()}; // int ops = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK | DND.DROP_DEFAULT; // // DelegatingDropAdapter delegatingDropAdapter = new DelegatingDropAdapter(); // delegatingDropAdapter.addDropTargetListener(new CallHierarchyTransferDropAdapter(this, viewer)); // delegatingDropAdapter.addDropTargetListener(new PluginTransferDropAdapter(viewer)); // // viewer.addDropSupport(ops, transfers, delegatingDropAdapter); } /** * Adds the entry if new. Inserted at the beginning of the history entries list. * * @param entry the entry to add */ private void addHistoryEntry(DartElement[] entry) { updateHistoryEntries(entry, entry); } private void addPartListener() { fPartListener = new IPartListener2() { @Override public void partActivated(IWorkbenchPartReference partRef) { if (isThisView(partRef)) { CallHierarchyUI.getDefault().callHierarchyViewActivated(CallHierarchyViewPart.this); } } @Override public void partBroughtToTop(IWorkbenchPartReference partRef) { } @Override public void partClosed(IWorkbenchPartReference partRef) { if (isThisView(partRef)) { CallHierarchyUI.getDefault().callHierarchyViewClosed(CallHierarchyViewPart.this); saveViewSettings(); } } @Override public void partDeactivated(IWorkbenchPartReference partRef) { if (isThisView(partRef)) { saveViewSettings(); } } @Override public void partHidden(IWorkbenchPartReference partRef) { } @Override public void partInputChanged(IWorkbenchPartReference partRef) { } @Override public void partOpened(IWorkbenchPartReference partRef) { } @Override public void partVisible(IWorkbenchPartReference partRef) { } }; getViewSite().getPage().addPartListener(fPartListener); } private void addResizeListener(Composite parent) { parent.addControlListener(new ControlListener() { @Override public void controlMoved(ControlEvent e) { } @Override public void controlResized(ControlEvent e) { computeOrientation(); } }); } /** * Computes the content description for the call hierarchy computation. * * @param includeMask the include mask * @return the content description */ private String computeContentDescription(int includeMask) { // see also HistoryAction.getElementLabel(TypeMember[]) String scopeDescription = searchScopeActions.getFullDescription(includeMask); if (currentInputElements.length == 1) { DartElement element = currentInputElements[0]; String elementName = DartElementLabels.getElementLabel(element, DartElementLabels.ALL_DEFAULT); String[] args = new String[] { elementName, scopeDescription }; if (currentCallMode == CALL_MODE_CALLERS) { switch (element.getElementType()) { case DartElement.TYPE: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsToConstructors, args); case DartElement.FIELD: // switch (this.currentFieldMode) { // case IJavaSearchConstants.READ_ACCESSES: // return Messages.format( // CallHierarchyMessages.CallHierarchyViewPart_callsToFieldRead, args); // case IJavaSearchConstants.WRITE_ACCESSES: // return Messages.format( // CallHierarchyMessages.CallHierarchyViewPart_callsToFieldWrite, args); // default: // all references return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsToField, args); // } case DartElement.METHOD: default: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsToMethod, args); } } else { switch (element.getElementType()) { case DartElement.TYPE: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsFromConstructors, args); case DartElement.FIELD: case DartElement.METHOD: default: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsFromMethod, args); } } } else { if (currentCallMode == CALL_MODE_CALLERS) { switch (currentInputElements.length) { case 0: Assert.isTrue(false); return null; case 2: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsToMembers_2, new String[] { getShortLabel(currentInputElements[0]), getShortLabel(currentInputElements[1]), scopeDescription }); default: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsToMembers_more, new String[] { getShortLabel(currentInputElements[0]), getShortLabel(currentInputElements[1]), scopeDescription }); } } else { switch (currentInputElements.length) { case 0: Assert.isTrue(false); return null; case 2: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsFromMembers_2, new String[] { getShortLabel(currentInputElements[0]), getShortLabel(currentInputElements[1]), scopeDescription }); default: return Messages.format(CallHierarchyMessages.CallHierarchyViewPart_callsFromMembers_more, new String[] { getShortLabel(currentInputElements[0]), getShortLabel(currentInputElements[1]), scopeDescription }); } } } } private void createCallHierarchyViewer(Composite parent) { callHierarchyViewer = new CallHierarchyViewer(parent, this); callHierarchyViewer.addSelectionChangedListener(this); } private void createHierarchyLocationSplitter(Composite parent) { hierarchyLocationSplitter = new SashForm(parent, SWT.NONE); } private void createLocationViewer(Composite parent) { locationViewer = new LocationViewer(parent); locationViewer.initContextMenu(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager menu) { fillLocationViewerContextMenu(menu); } }, ID_CALL_HIERARCHY, getSite()); } private void fillActionBars() { IActionBars actionBars = getActionBars(); actionBars.setGlobalActionHandler(ActionFactory.REFRESH.getId(), refreshSingleElementAction); actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), removeFromViewAction); IToolBarManager toolBar = actionBars.getToolBarManager(); actionGroups.fillActionBars(actionBars); toolBar.add(refreshViewAction); toolBar.add(cancelSearchAction); for (int i = 0; i < toggleCallModeActions.length; i++) { toolBar.add(toggleCallModeActions[i]); } toolBar.add(historyDropDownAction); toolBar.add(pinViewAction); } private void fillViewMenu() { IActionBars actionBars = getViewSite().getActionBars(); IMenuManager viewMenu = actionBars.getMenuManager(); viewMenu.add(new Separator()); for (int i = 0; i < toggleCallModeActions.length; i++) { viewMenu.add(toggleCallModeActions[i]); } viewMenu.add(new Separator()); MenuManager layoutSubMenu = new MenuManager(CallHierarchyMessages.CallHierarchyViewPart_layout_menu); for (int i = 0; i < toggleOrientationActions.length; i++) { layoutSubMenu.add(toggleOrientationActions[i]); } viewMenu.add(layoutSubMenu); viewMenu.add(new Separator(IContextMenuConstants.GROUP_SEARCH)); // MenuManager fieldSubMenu = new MenuManager( // CallHierarchyMessages.CallHierarchyViewPart_field_menu); // for (int i = 0; i < toggleFieldModeActions.length; i++) { // fieldSubMenu.add(toggleFieldModeActions[i]); // } // viewMenu.add(fieldSubMenu); // viewMenu.add(showSearchInDialogAction); } private IActionBars getActionBars() { return getViewSite().getActionBars(); } private MethodWrapper[] getCalleeRoots() { if (calleeRoots == null) { calleeRoots = CallHierarchy.getDefault().getCalleeRoots(currentInputElements); } return calleeRoots; } private MethodWrapper[] getCallerRoots() { // if (callerRoots != null && callerRoots.length > 0) { // // all caller roots have the same field mode, just check the first: // if (callerRoots[0].getFieldSearchMode() != currentFieldMode) { // callerRoots = null; // field mode changed, re-initialize below // } // } if (callerRoots == null) { callerRoots = CallHierarchy.getDefault().getCallerRoots(currentInputElements); // for (int i = 0; i < callerRoots.length; i++) { // callerRoots[i].setFieldSearchMode(currentFieldMode); // } } return callerRoots; } /** * Gets the include mask. * * @return the include mask */ private int getIncludeMask() { return showSearchInDialogAction.getSearchInDialog().getIncludeMask(); } /** * Returns the method history. * * @return the method history */ private List<DartElement[]> getMethodHistory() { return CallHierarchyUI.getDefault().getMethodHistory(); } /** * Fetches the progress service for the workbench part site. * * @return the progress service for the workbench part site */ private IWorkbenchSiteProgressService getProgressService() { IWorkbenchSiteProgressService service = null; Object siteService = getSite().getAdapter(IWorkbenchSiteProgressService.class); if (siteService != null) { service = (IWorkbenchSiteProgressService) siteService; } return service; } private void initCallMode() { int mode; try { mode = dialogSettings.getInt(DIALOGSTORE_CALL_MODE); if ((mode < 0) || (mode > 1)) { mode = CALL_MODE_CALLERS; } } catch (NumberFormatException e) { mode = CALL_MODE_CALLERS; } // force the update currentCallMode = -1; // will fill the main tool bar setCallMode(mode); } private void initDragAndDrop() { // addDragAdapters(fCallHierarchyViewer); // addDropAdapters(fCallHierarchyViewer); // addDropAdapters(fLocationViewer); // // //dnd on empty hierarchy // DropTarget dropTarget = new DropTarget(fPagebook, DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK // | DND.DROP_DEFAULT); // dropTarget.setTransfer(new Transfer[] {LocalSelectionTransfer.getTransfer()}); // dropTarget.addDropListener(new CallHierarchyTransferDropAdapter(this, fCallHierarchyViewer)); } private void initFieldMode() { int mode; try { mode = dialogSettings.getInt(DIALOGSTORE_FIELD_MODE); // switch (mode) { // case IJavaSearchConstants.REFERENCES: // case IJavaSearchConstants.READ_ACCESSES: // case IJavaSearchConstants.WRITE_ACCESSES: // break; // OK // default: // mode = IJavaSearchConstants.REFERENCES; // } } catch (NumberFormatException e) { // mode = IJavaSearchConstants.REFERENCES; mode = 7; } // force the update // currentFieldMode = -1; // will fill the main tool bar setFieldMode(mode); } private void initOrientation() { try { orientation = dialogSettings.getInt(DIALOGSTORE_VIEWORIENTATION); if ((orientation < 0) || (orientation > 3)) { orientation = VIEW_ORIENTATION_AUTOMATIC; } } catch (NumberFormatException e) { orientation = VIEW_ORIENTATION_AUTOMATIC; } // force the update currentOrientation = -1; setOrientation(orientation); } /** * Tells whether the given part reference references this view. * * @param partRef the workbench part reference * @return <code>true</code> if the given part reference references this view */ private boolean isThisView(IWorkbenchPartReference partRef) { if (!ID_CALL_HIERARCHY.equals(partRef.getId())) { return false; } String partRefSecondaryId = ((IViewReference) partRef).getSecondaryId(); String thisSecondaryId = getViewSite().getSecondaryId(); return thisSecondaryId == null && partRefSecondaryId == null || thisSecondaryId != null && thisSecondaryId.equals(partRefSecondaryId); } private void makeActions() { refreshViewAction = new RefreshViewAction(this); refreshSingleElementAction = new RefreshElementAction(callHierarchyViewer); new CallHierarchyOpenEditorHelper(locationViewer); new CallHierarchyOpenEditorHelper(callHierarchyViewer); openLocationAction = new OpenLocationAction(this, getSite()); locationCopyAction = locationViewer.initCopyAction(getViewSite(), clipboard); focusOnSelectionAction = new FocusOnSelectionAction(this); copyAction = new CopyCallHierarchyAction(this, clipboard, callHierarchyViewer); searchScopeActions = new SearchScopeActionGroup(this, dialogSettings); showSearchInDialogAction = new ShowSearchInDialogAction(this, callHierarchyViewer); filtersActionGroup = new CallHierarchyFiltersActionGroup(this, callHierarchyViewer); historyDropDownAction = new HistoryDropDownAction(this); historyDropDownAction.setEnabled(false); cancelSearchAction = new CancelSearchAction(this); setCancelEnabled(false); // expandWithConstructorsAction = new ExpandWithConstructorsAction(this, fCallHierarchyViewer); removeFromViewAction = new RemoveFromViewAction(this, callHierarchyViewer); pinViewAction = new PinCallHierarchyViewAction(this); toggleOrientationActions = new ToggleOrientationAction[] { new ToggleOrientationAction(this, VIEW_ORIENTATION_VERTICAL), new ToggleOrientationAction(this, VIEW_ORIENTATION_HORIZONTAL), new ToggleOrientationAction(this, VIEW_ORIENTATION_AUTOMATIC), new ToggleOrientationAction(this, VIEW_ORIENTATION_SINGLE) }; removeFromViewAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_DELETE); toggleCallModeActions = new ToggleCallModeAction[] { new ToggleCallModeAction(this, CALL_MODE_CALLERS), new ToggleCallModeAction(this, CALL_MODE_CALLEES) }; // toggleFieldModeActions = new SelectFieldModeAction[] { // new SelectFieldModeAction(this, IJavaSearchConstants.REFERENCES), // new SelectFieldModeAction(this, IJavaSearchConstants.READ_ACCESSES), // new SelectFieldModeAction(this, IJavaSearchConstants.WRITE_ACCESSES)}; actionGroups = new CompositeActionGroup(new ActionGroup[] { new OpenEditorActionGroup(this), new CCPActionGroup(this), new GenerateActionGroup(this), new DartSearchActionGroup(this), searchScopeActions, filtersActionGroup }); } private void methodSelectionChanged(ISelection selection) { if (selection instanceof IStructuredSelection && ((IStructuredSelection) selection).size() == 1) { Object selectedElement = ((IStructuredSelection) selection).getFirstElement(); if (selectedElement instanceof MethodWrapper) { MethodWrapper methodWrapper = (MethodWrapper) selectedElement; revealElementInEditor(methodWrapper, callHierarchyViewer); updateLocationsView(methodWrapper); } else { updateLocationsView(null); } } else { updateLocationsView(null); } } private void restoreSplitterRatio() { String ratio = dialogSettings.get(DIALOGSTORE_RATIO + currentOrientation); if (ratio == null) { return; } int intRatio = Integer.parseInt(ratio); hierarchyLocationSplitter.setWeights(new int[] { intRatio, 1000 - intRatio }); } /** * Restores the type hierarchy settings from a memento. * * @param memento the memento */ private void restoreState(IMemento memento) { searchScopeActions.restoreState(memento); } private void revealElementInEditor(Object elem, Viewer originViewer) { // only allow revealing when the type hierarchy is the active pagae // no revealing after selection events due to model changes if (getSite().getPage().getActivePart() != this) { return; } if (selectionProviderMediator.getViewerInFocus() != originViewer) { return; } if (elem instanceof MethodWrapper) { CallLocation callLocation = CallHierarchy.getCallLocation(elem); if (callLocation != null) { IEditorPart editorPart = CallHierarchyUI.isOpenInEditor(callLocation); if (editorPart != null) { getSite().getPage().bringToTop(editorPart); if (editorPart instanceof ITextEditor) { ITextEditor editor = (ITextEditor) editorPart; editor.selectAndReveal(callLocation.getStartPosition(), (callLocation.getEndPosition() - callLocation.getStartPosition())); } } } else { IEditorPart editorPart = CallHierarchyUI.isOpenInEditor(elem); getSite().getPage().bringToTop(editorPart); EditorUtility.revealInEditor(editorPart, ((MethodWrapper) elem).getMember()); } } else if (elem instanceof DartElement) { IEditorPart editorPart = EditorUtility.isOpenInEditor(elem); if (editorPart != null) { // getSite().getPage().removePartListener(fPartListener); getSite().getPage().bringToTop(editorPart); EditorUtility.revealInEditor(editorPart, (DartElement) elem); // getSite().getPage().addPartListener(fPartListener); } } } private void saveSplitterRatio() { if (hierarchyLocationSplitter != null && !hierarchyLocationSplitter.isDisposed()) { int[] weigths = hierarchyLocationSplitter.getWeights(); int ratio = (weigths[0] * 1000) / (weigths[0] + weigths[1]); String key = DIALOGSTORE_RATIO + currentOrientation; dialogSettings.put(key, ratio); } } private void setCalleeRoots(MethodWrapper[] calleeRoots) { this.calleeRoots = calleeRoots; } private void setCallerRoots(MethodWrapper[] callerRoots) { this.callerRoots = callerRoots; } /** * Sets the content description. * * @param includeMask the include mask */ private void setContentDescription(int includeMask) { setContentDescription(computeContentDescription(includeMask)); } private void showOrHideCallDetailsView() { if (showCallDetails) { hierarchyLocationSplitter.setMaximizedControl(null); } else { hierarchyLocationSplitter.setMaximizedControl(callHierarchyViewer.getControl()); } } private void showPage(int page) { boolean isEmpty = page == PAGE_EMPTY; Control control = isEmpty ? (Control) noHierarchyShownLabel : hierarchyLocationSplitter; if (isEmpty) { setContentDescription(""); //$NON-NLS-1$ setTitleToolTip(getPartName()); getViewSite().getActionBars().getStatusLineManager().setMessage(""); //$NON-NLS-1$ getViewer().clearViewer(); } pagebook.showPage(control); if (refreshViewAction != null) { refreshViewAction.setEnabled(!isEmpty); } if (refreshSingleElementAction != null) { refreshSingleElementAction.setEnabled(!isEmpty); } } private void updateCheckedState() { for (int i = 0; i < toggleOrientationActions.length; i++) { toggleOrientationActions[i].setChecked(orientation == toggleOrientationActions[i].getOrientation()); } } private void updateHistoryEntries() { for (int i = getMethodHistory().size() - 1; i >= 0; i--) { DartElement[] members = getMethodHistory().get(i); for (int j = 0; j < members.length; j++) { DartElement member = members[j]; if (!member.exists()) { getMethodHistory().remove(i); break; } } } historyDropDownAction.setEnabled(!getMethodHistory().isEmpty()); } /** * Updates the history with the latest input. * * @param currentInput the current input * @param entry the new input elements */ private void updateHistoryEntries(DartElement[] currentInput, DartElement[] entry) { for (Iterator<DartElement[]> iter = getMethodHistory().iterator(); iter.hasNext();) { if (Arrays.equals(currentInput, iter.next())) { iter.remove(); } } getMethodHistory().add(0, entry); historyDropDownAction.setEnabled(true); } private void updateLocationsView(MethodWrapper methodWrapper) { if (methodWrapper != null && methodWrapper.getMethodCall().hasCallLocations()) { locationViewer.setInput(methodWrapper.getMethodCall().getCallLocations()); } else { locationViewer.clearViewer(); } } private void updateView() { if (currentInputElements != null) { showPage(PAGE_VIEWER); int includeMask = getIncludeMask(); CallHierarchy.getDefault().setSearchScope(getSearchScope(includeMask)); // set input to null so that setComparator does not cause a refresh on the old contents: callHierarchyViewer.setInput(null); if (currentCallMode == CALL_MODE_CALLERS) { // sort caller hierarchy alphabetically (bug 111423) and make RealCallers the last in 'Expand With Constructors' mode callHierarchyViewer.setComparator(new ViewerComparator() { @Override public int category(Object element) { return element instanceof RealCallers ? 1 : 0; } }); callHierarchyViewer.setMethodWrappers(getCallerRoots()); } else { callHierarchyViewer.setComparator(null); callHierarchyViewer.setMethodWrappers(getCalleeRoots()); } setContentDescription(includeMask); } } /** * Updates the view with the newly added input elements. * * @param newElements the newly added elements */ private void updateViewWithAddedElements(TypeMember[] newElements) { setCalleeRoots(null); setCallerRoots(null); MethodWrapper[] roots; if (getCallMode() == CALL_MODE_CALLERS) { roots = CallHierarchy.getDefault().getCallerRoots(newElements); } else { roots = CallHierarchy.getDefault().getCalleeRoots(newElements); } CallHierarchyViewer hierarchyViewer = getViewer(); TreeRoot treeRoot = hierarchyViewer.getTreeRoot(roots, true); hierarchyViewer.add(treeRoot, roots); for (int i = 0; i < roots.length; i++) { hierarchyViewer.setExpandedState(roots[i], true); } hierarchyViewer.setSelection(new StructuredSelection(roots), true); } }