diff --git a/core/org.eclipse.cdt.ui/icons/dlcl16/pin_view.gif b/core/org.eclipse.cdt.ui/icons/dlcl16/pin_view.gif new file mode 100644 index 00000000000..61615d57dbe Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/dlcl16/pin_view.gif differ diff --git a/core/org.eclipse.cdt.ui/icons/elcl16/pin_view.gif b/core/org.eclipse.cdt.ui/icons/elcl16/pin_view.gif new file mode 100644 index 00000000000..ec50b70fab1 Binary files /dev/null and b/core/org.eclipse.cdt.ui/icons/elcl16/pin_view.gif differ diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index b6fcfa05921..9a712d3953f 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -285,7 +285,8 @@ class="org.eclipse.cdt.internal.ui.callhierarchy.CHViewPart" icon="icons/view16/call_hierarchy.gif" id="org.eclipse.cdt.ui.callHierarchy" - name="%callHierarchy.name"/> + name="%callHierarchy.name" + allowMultiple="true"/> adapter= new IListAdapter() { + @Override public void customButtonPressed(ListDialogField field, int index) { doCustomButtonPressed(); } + @Override public void selectionChanged(ListDialogField field) { doSelectionChanged(); } + @Override public void doubleClicked(ListDialogField field) { doDoubleClicked(); } @@ -171,10 +174,10 @@ public class CHHistoryListAction extends Action { */ @Override public void run() { - ICElement[] historyEntries= fView.getHistoryEntries(); + ICElement[] historyEntries= CallHierarchyUI.getHistoryEntries(); HistoryListDialog dialog= new HistoryListDialog(fView.getSite().getShell(), historyEntries); if (dialog.open() == Window.OK) { - fView.setHistoryEntries(dialog.getRemaining()); + CallHierarchyUI.setHistoryEntries(dialog.getRemaining()); fView.setInput(dialog.getResult()); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.java index 127fcd48c6f..620ceba59e8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -55,6 +55,8 @@ public class CHMessages extends NLS { public static String OpenElementInCallHierarchyAction_message; public static String OpenElementInCallHierarchyAction_title; public static String OpenElementInCallHierarchyAction_upperListLabel; + public static String CHPinAction_label; + public static String CHPinAction_tooltip; static { // initialize resource bundle diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.properties index 2e8321e562a..0d8f98b6daa 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. +# Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -50,3 +50,5 @@ OpenElementInCallHierarchyAction_title=Open Element in Call Hierarchy OpenElementInCallHierarchyAction_upperListLabel=&Matching Elements: OpenElementInCallHierarchyAction_message=&Choose an element (? = any character, * = any string): OpenElementInCallHierarchyAction_errorNoDefinition=Could not locate definition of element ''{0}'' +CHPinAction_label=Pi&n Call Hierarchy View +CHPinAction_tooltip=Pin the Call Hierarchy View diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHPinAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHPinAction.java new file mode 100644 index 00000000000..3b770e66d62 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHPinAction.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2011, 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: + * IBM Corporation - initial API and implementation + * Marc-Andre Laperle - Adapted to CDT from JDT + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.callhierarchy; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; + +import org.eclipse.cdt.internal.ui.CPluginImages; + +public class CHPinAction extends Action { + private CHViewPart fView= null; + + /** + * Constructs a 'Pin Call Hierarchy view' action. + * + * @param view the Call Hierarchy view + */ + public CHPinAction(CHViewPart view) { + super(CHMessages.CHPinAction_label, IAction.AS_CHECK_BOX); + setToolTipText(CHMessages.CHPinAction_tooltip); + CPluginImages.setImageDescriptors(this, CPluginImages.T_LCL, "pin_view.gif"); //$NON-NLS-1$ + fView= view; + } + + /* + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + fView.setPinned(isChecked()); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHViewPart.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHViewPart.java index dc1a0895479..9fd2f0163d2 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHViewPart.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CHViewPart.java @@ -11,8 +11,6 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.callhierarchy; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; import org.eclipse.jface.action.Action; @@ -47,8 +45,11 @@ import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IViewReference; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.PartInitException; @@ -91,7 +92,6 @@ import org.eclipse.cdt.internal.ui.viewsupport.WorkingSetFilterUI; * The view part for the include browser. */ public class CHViewPart extends ViewPart { - private static final int MAX_HISTORY_SIZE = 10; private static final String TRUE = String.valueOf(true); private static final String KEY_WORKING_SET_FILTER = "workingSetFilter"; //$NON-NLS-1$ private static final String KEY_FILTER_VARIABLES = "variableFilter"; //$NON-NLS-1$ @@ -101,8 +101,6 @@ public class CHViewPart extends ViewPart { private boolean fShowsMessage; private CHNode fNavigationNode; private int fNavigationDetail; - - private ArrayList fHistoryEntries= new ArrayList(MAX_HISTORY_SIZE); // widgets private PageBook fPagebook; @@ -131,6 +129,7 @@ public class CHViewPart extends ViewPart { private Action fHistoryAction; private Action fShowReference; private Action fOpenElement; + private Action fPinViewAction; private CopyTreeAction fCopyAction; // action groups @@ -138,6 +137,8 @@ public class CHViewPart extends ViewPart { private SelectionSearchGroup fSelectionSearchGroup; private CRefactoringActionGroup fRefactoringActionGroup; private IContextActivation fContextActivation; + private boolean fIsPinned = false; + private IPartListener2 fPartListener; @Override public void setFocus() { @@ -171,7 +172,7 @@ public class CHViewPart extends ViewPart { fTreeViewer.setInput(input); fPagebook.showPage(fViewerPage); updateDescription(); - updateHistory(input); + CallHierarchyUI.updateHistory(input); updateActionEnablement(); } @@ -218,8 +219,48 @@ public class CHViewPart extends ViewPart { } PlatformUI.getWorkbench().getHelpSystem().setHelp(fPagebook, ICHelpContextIds.CALL_HIERARCHY_VIEW); + addPartListener(); } + private void addPartListener() { + fPartListener= new IPartListener2() { + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partActivated(IWorkbenchPartReference partRef) { + if (isThisView(partRef)) + CallHierarchyUI.callHierarchyViewActivated(CHViewPart.this); + } + + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partClosed(IWorkbenchPartReference partRef) { + if (isThisView(partRef)) { + CallHierarchyUI.callHierarchyViewClosed(CHViewPart.this); + } + } + + @Override + public void partDeactivated(IWorkbenchPartReference partRef) {} + @Override + public void partOpened(IWorkbenchPartReference partRef) { } + @Override + public void partHidden(IWorkbenchPartReference partRef) { } + @Override + public void partVisible(IWorkbenchPartReference partRef) { } + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { } + }; + getViewSite().getPage().addPartListener(fPartListener); + + } + @Override public void dispose() { if (fContextActivation != null) { @@ -245,6 +286,10 @@ public class CHViewPart extends ViewPart { fWorkingSetFilterUI.dispose(); fWorkingSetFilterUI= null; } + if (fPartListener != null) { + getViewSite().getPage().removePartListener(fPartListener); + fPartListener= null; + } super.dispose(); } @@ -276,6 +321,19 @@ public class CHViewPart extends ViewPart { super.init(site, memento); } + /** + * Tells whether the given part reference references this view. + * + * @param partRef the workbench part reference + * @return true if the given part reference references this view + */ + private boolean isThisView(IWorkbenchPartReference partRef) { + if (!CUIPlugin.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); + } @Override public void saveState(IMemento memento) { @@ -291,7 +349,8 @@ public class CHViewPart extends ViewPart { MenuManager manager = new MenuManager(); manager.setRemoveAllWhenShown(true); manager.addMenuListener(new IMenuListener() { - public void menuAboutToShow(IMenuManager m) { + @Override + public void menuAboutToShow(IMenuManager m) { onContextMenuAboutToShow(m); } }); @@ -315,6 +374,7 @@ public class CHViewPart extends ViewPart { fTreeViewer.setLabelProvider(new DecoratingCLabelProvider(fLabelProvider)); fTreeViewer.setAutoExpandLevel(2); fTreeViewer.addOpenListener(new IOpenListener() { + @Override public void open(OpenEvent event) { onShowSelectedReference(event.getSelection()); } @@ -484,6 +544,7 @@ public class CHViewPart extends ViewPart { fHistoryAction = new CHHistoryDropDownAction(this); fCopyAction= new CopyCallHierarchyAction(this, fTreeViewer); + fPinViewAction= new CHPinAction(this); // setup action bar // global action hooks @@ -509,6 +570,7 @@ public class CHViewPart extends ViewPart { tm.add(fMakesReferenceToAction); tm.add(fHistoryAction); tm.add(fRefreshAction); + tm.add(fPinViewAction); // local menu IMenuManager mm = actionBars.getMenuManager(); @@ -608,16 +670,6 @@ public class CHViewPart extends ViewPart { fTreeViewer.refresh(); } - private void updateHistory(ICElement input) { - if (input != null) { - fHistoryEntries.remove(input); - fHistoryEntries.add(0, input); - if (fHistoryEntries.size() > MAX_HISTORY_SIZE) { - fHistoryEntries.remove(MAX_HISTORY_SIZE-1); - } - } - } - private void updateSorter() { if (fReferencedByAction.isChecked()) { fTreeViewer.setComparator(fSorterAlphaNumeric); @@ -662,7 +714,7 @@ public class CHViewPart extends ViewPart { } private void updateActionEnablement() { - fHistoryAction.setEnabled(!fHistoryEntries.isEmpty()); + fHistoryAction.setEnabled(CallHierarchyUI.getHistoryEntries().length > 0); fNextAction.setEnabled(!fShowsMessage); fPreviousAction.setEnabled(!fShowsMessage); fRefreshAction.setEnabled(!fShowsMessage); @@ -782,16 +834,7 @@ public class CHViewPart extends ViewPart { public Control getPageBook() { return fPagebook; } - - public ICElement[] getHistoryEntries() { - return fHistoryEntries.toArray(new ICElement[fHistoryEntries.size()]); - } - - public void setHistoryEntries(ICElement[] remaining) { - fHistoryEntries.clear(); - fHistoryEntries.addAll(Arrays.asList(remaining)); - } - + public ICElement getInput() { Object input= fTreeViewer.getInput(); if (input instanceof ICElement) { @@ -809,4 +852,22 @@ public class CHViewPart extends ViewPart { super(CHMessages.CHViewPart_CopyCallHierarchy_label, view, viewer); } } + + /** + * Marks the view as pinned. + * + * @param pinned if true the view is marked as pinned + */ + void setPinned(boolean pinned) { + fIsPinned= pinned; + } + + /** + * Indicates whether the Call Hierarchy view is pinned. + * + * @return true if the view is pinned, false otherwise + */ + boolean isPinned() { + return fIsPinned; + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CallHierarchyUI.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CallHierarchyUI.java index 3aba5d15132..e0093cf82ac 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CallHierarchyUI.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/callhierarchy/CallHierarchyUI.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2011 Wind River Systems, Inc. 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 @@ -10,6 +10,11 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.callhierarchy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -18,6 +23,7 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.text.ITextSelection; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IViewReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.texteditor.ITextEditor; @@ -57,6 +63,15 @@ public class CallHierarchyUI { private static final ICElement[] NO_ELEMENTS = {}; private static boolean sIsJUnitTest= false; + /** + * List of the Call Hierarchy views in LRU order, where the most recently used view is at index 0. + */ + private static List fLRUCallHierarchyViews= new ArrayList(); + private static int fViewCount = 0; + + private static final int MAX_HISTORY_SIZE = 10; + private static List fHistoryEntries= new ArrayList(MAX_HISTORY_SIZE); + public static void setIsJUnitTest(boolean val) { sIsJUnitTest= val; } @@ -87,9 +102,19 @@ public class CallHierarchyUI { private static CHViewPart internalOpen(IWorkbenchWindow window, ICElement input) { IWorkbenchPage page= window.getActivePage(); try { - CHViewPart result= (CHViewPart) page.showView(CUIPlugin.ID_CALL_HIERARCHY); - result.setInput(input); - return result; + CHViewPart viewPart = findLRUCallHierarchyViewPart(page); //find the first view which is not pinned + String secondaryId = null; + if (viewPart == null) { + if (page.findViewReference(CUIPlugin.ID_CALL_HIERARCHY) != null) { //all the current views are pinned, open a new instance + secondaryId = String.valueOf(++fViewCount); + } + } else { + secondaryId = viewPart.getViewSite().getSecondaryId(); + } + + viewPart = (CHViewPart) page.showView(CUIPlugin.ID_CALL_HIERARCHY, secondaryId, IWorkbenchPage.VIEW_ACTIVATE); + viewPart.setInput(input); + return viewPart; } catch (CoreException e) { ExceptionHandler.handle(e, window.getShell(), CHMessages.OpenCallHierarchyAction_label, null); } @@ -331,4 +356,88 @@ public class CallHierarchyUI { } return false; } + + + /** + * Adds the activated view part to the head of the list. + * + * @param view the Call Hierarchy view part + */ + static void callHierarchyViewActivated(CHViewPart view) { + fLRUCallHierarchyViews.remove(view); + fLRUCallHierarchyViews.add(0, view); + } + + /** + * Removes the closed view part from the list. + * + * @param view the closed view part + */ + static void callHierarchyViewClosed(CHViewPart view) { + fLRUCallHierarchyViews.remove(view); + } + + /** + * Clears the history and updates all the open views. + */ + static void clearHistory() { + setHistoryEntries(new ICElement[0]); + for (Iterator iter= fLRUCallHierarchyViews.iterator(); iter.hasNext();) { + CHViewPart part= iter.next(); + part.setInput(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 null if none found + */ + private static CHViewPart findLRUCallHierarchyViewPart(IWorkbenchPage page) { + boolean viewFoundInPage= false; + for (Iterator iter= fLRUCallHierarchyViews.iterator(); iter.hasNext();) { + CHViewPart 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 (CUIPlugin.ID_CALL_HIERARCHY.equals(curr.getId()) && page.equals(curr.getPage())) { + CHViewPart view= (CHViewPart)curr.getView(true); + if (view != null && !view.isPinned()) { + return view; + } + } + } + } + return null; + } + + static public ICElement[] getHistoryEntries() { + return fHistoryEntries.toArray(new ICElement[fHistoryEntries.size()]); + } + + static public void setHistoryEntries(ICElement[] remaining) { + fHistoryEntries.clear(); + fHistoryEntries.addAll(Arrays.asList(remaining)); + } + + static public void updateHistory(ICElement input) { + if (input != null) { + fHistoryEntries.remove(input); + fHistoryEntries.add(0, input); + if (fHistoryEntries.size() > MAX_HISTORY_SIZE) { + fHistoryEntries.remove(MAX_HISTORY_SIZE-1); + } + } + } + } diff --git a/doc/org.eclipse.cdt.doc.user/images/view_call_hierarchy.png b/doc/org.eclipse.cdt.doc.user/images/view_call_hierarchy.png index 6485a3bdccb..5e7d19ae682 100644 Binary files a/doc/org.eclipse.cdt.doc.user/images/view_call_hierarchy.png and b/doc/org.eclipse.cdt.doc.user/images/view_call_hierarchy.png differ diff --git a/doc/org.eclipse.cdt.doc.user/reference/cdt_u_call_hierarchy_view.htm b/doc/org.eclipse.cdt.doc.user/reference/cdt_u_call_hierarchy_view.htm index 8cd0d98f645..72ac6f8f195 100644 --- a/doc/org.eclipse.cdt.doc.user/reference/cdt_u_call_hierarchy_view.htm +++ b/doc/org.eclipse.cdt.doc.user/reference/cdt_u_call_hierarchy_view.htm @@ -60,6 +60,11 @@ Refresh View Contents Refreshes the view to reflect the current state of the function. + +
Pin the Call Hierarchy View icon
+ Pin the Call Hierarchy View + Pins the current view and enables the user to open multiple Call Hierarchy views at the same time. +
Menu icon
View Menu