### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.ui Index: ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java,v retrieving revision 1.46 diff -u -r1.46 TypeHierarchyLifeCycle.java --- ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java 31 Dec 2008 21:13:30 -0000 1.46 +++ ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java 9 Nov 2009 19:55:13 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2009 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 @@ -14,12 +14,19 @@ import java.util.ArrayList; import java.util.List; +import org.eclipse.swt.widgets.Display; + import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.ui.progress.IWorkbenchSiteProgressService; + import org.eclipse.jdt.core.ElementChangedEvent; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; @@ -37,6 +44,9 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.ui.JavaElementLabels; import org.eclipse.jdt.internal.ui.JavaPlugin; @@ -52,8 +62,37 @@ private List fChangeListeners; - public TypeHierarchyLifeCycle() { + /** + * The type hierarchy view part. + * + * @since 3.6 + */ + private TypeHierarchyViewPart fTypeHierarchyViewPart; + + /** + * The job that runs in the background to refresh the type hierarchy. + * + * @since 3.6 + */ + private Job fRefreshHierarchyJob; + + /** + * Indicates whether the refresh job was canceled implicitly. + * + * @since 3.6 + */ + private boolean fIsCancelImplicit= false; + + /** + * Creates the type hierarchy life cycle. + * + * @param part the type hierarchy view part + * @since 3.6 + */ + public TypeHierarchyLifeCycle(TypeHierarchyViewPart part) { this(false); + fTypeHierarchyViewPart= part; + fRefreshHierarchyJob= null; } public TypeHierarchyLifeCycle(boolean isSuperTypesOnly) { @@ -98,7 +137,29 @@ } } + /** + * Refreshes the type hierarchy for the java element if it exists. + * + * @param element the java element for which the type hierarchy is computed + * @param context the runnable context + * @throws InterruptedException thrown from the OperationCanceledException when the monitor is canceled + * @throws InvocationTargetException thrown from the JavaModelException if the java element does not exist or if an exception occurs while accessing its corresponding resource + */ public void ensureRefreshedTypeHierarchy(final IJavaElement element, IRunnableContext context) throws InvocationTargetException, InterruptedException { + synchronized (this) { + if (fRefreshHierarchyJob != null) { + fRefreshHierarchyJob.cancel(); + fIsCancelImplicit= true; + try { + fRefreshHierarchyJob.join(); + } catch (InterruptedException e) { + // ignore + } finally { + fRefreshHierarchyJob= null; + fIsCancelImplicit= false; + } + } + } if (element == null || !element.exists()) { freeHierarchy(); return; @@ -106,21 +167,86 @@ boolean hierachyCreationNeeded= (fHierarchy == null || !element.equals(fInputElement)); if (hierachyCreationNeeded || fHierarchyRefreshNeeded) { - - IRunnableWithProgress op= new IRunnableWithProgress() { - public void run(IProgressMonitor pm) throws InvocationTargetException, InterruptedException { - try { - doHierarchyRefresh(element, pm); - } catch (JavaModelException e) { - throw new InvocationTargetException(e); - } catch (OperationCanceledException e) { - throw new InterruptedException(); + if (fTypeHierarchyViewPart == null) { + IRunnableWithProgress op= new IRunnableWithProgress() { + public void run(IProgressMonitor pm) throws InvocationTargetException, InterruptedException { + try { + doHierarchyRefresh(element, pm); + } catch (JavaModelException e) { + throw new InvocationTargetException(e); + } catch (OperationCanceledException e) { + throw new InterruptedException(); + } + } + }; + fHierarchyRefreshNeeded= true; + context.run(true, true, op); + fHierarchyRefreshNeeded= false; + } else { + final String label= Messages.format(TypeHierarchyMessages.TypeHierarchyLifeCycle_computeInput, JavaElementLabels.getElementLabel(element, JavaElementLabels.ALL_DEFAULT)); + fRefreshHierarchyJob= new Job(label) { + /* + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus run(IProgressMonitor pm) { + pm.beginTask(label, LONG); + try { + doHierarchyRefreshBackground(element, pm); + } catch (OperationCanceledException e) { + fTypeHierarchyViewPart.setCanceledViewer(fIsCancelImplicit); + return Status.CANCEL_STATUS; + } catch (JavaModelException e) { + return e.getStatus(); + } finally { + fHierarchyRefreshNeeded= true; + pm.done(); + } + return Status.OK_STATUS; } + }; + fRefreshHierarchyJob.setUser(true); + IWorkbenchSiteProgressService progressService= (IWorkbenchSiteProgressService)fTypeHierarchyViewPart.getSite() + .getAdapter(IWorkbenchSiteProgressService.class); + progressService.schedule(fRefreshHierarchyJob, 0); + + } + } + } + + /** + * Returns true if the refresh job is running, false otherwise. + * + * @return true if the refresh job is running, false otherwise + * + * @since 3.6 + */ + public boolean isRefreshJob() { + return fRefreshHierarchyJob != null; + } + + /** + * Refreshes the hierarchy in the background and updates the hierarchy viewer asynchronously in + * the UI thread. + * + * @param element the java element on which the hierarchy is computed + * @param pm the progress monitor + * @throws JavaModelException if the java element does not exist or if an exception occurs while + * accessing its corresponding resource. + * + * @since 3.6 + */ + protected void doHierarchyRefreshBackground(final IJavaElement element, final IProgressMonitor pm) throws JavaModelException { + doHierarchyRefresh(element, pm); + if (!pm.isCanceled()) { + Display.getDefault().asyncExec(new Runnable() { + /* + * @see java.lang.Runnable#run() + */ + public void run() { + fTypeHierarchyViewPart.setViewersInput(); + fTypeHierarchyViewPart.updateViewers(); } - }; - fHierarchyRefreshNeeded= true; - context.run(true, true, op); - fHierarchyRefreshNeeded= false; + }); } } @@ -160,7 +286,7 @@ } - public synchronized void doHierarchyRefresh(IJavaElement element, IProgressMonitor pm) throws JavaModelException { + public void doHierarchyRefresh(IJavaElement element, IProgressMonitor pm) throws JavaModelException { boolean hierachyCreationNeeded= (fHierarchy == null || !element.equals(fInputElement)); // to ensure the order of the two listeners always remove / add listeners on operations // on type hierarchies @@ -176,6 +302,8 @@ fInputElement= element; } else { fHierarchy.refresh(pm); + if (pm != null && pm.isCanceled()) + throw new OperationCanceledException(); } fHierarchy.addTypeHierarchyChangedListener(this); JavaCore.addElementChangedListener(this); Index: ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.java,v retrieving revision 1.12 diff -u -r1.12 TypeHierarchyMessages.java --- ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.java 6 Aug 2009 13:53:47 -0000 1.12 +++ ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.java 9 Nov 2009 19:55:13 -0000 @@ -72,6 +72,7 @@ public static String TypeHierarchyViewPart_ws_tooltip; public static String TypeHierarchyViewPart_restoreinput; public static String TypeHierarchyViewPart_layout_submenu; + public static String TypeHierarchyLifeCycle_computeInput; public static String ToggleViewAction_subtypes_label; public static String ToggleViewAction_subtypes_tooltip; public static String ToggleViewAction_subtypes_description; Index: ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.properties,v retrieving revision 1.59 diff -u -r1.59 TypeHierarchyMessages.properties --- ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.properties 17 Aug 2009 15:28:36 -0000 1.59 +++ ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyMessages.properties 9 Nov 2009 19:55:13 -0000 @@ -62,6 +62,7 @@ SortByDefiningTypeAction_label=Sort by the Defining Type SortByDefiningTypeAction_tooltip=Sort Methods by the Defining Type SortByDefiningTypeAction_description=Sort methods by the defining type +TypeHierarchyLifeCycle_computeInput=Computing type hierarchy of ''{0}''... TypeHierarchyViewPart_error_title=Open Type Hierarchy TypeHierarchyViewPart_createinput=Creating type hierarchy of ''{0}''... Index: ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java,v retrieving revision 1.227 diff -u -r1.227 TypeHierarchyViewPart.java --- ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java 6 Aug 2009 13:53:47 -0000 1.227 +++ ui/org/eclipse/jdt/internal/ui/typehierarchy/TypeHierarchyViewPart.java 9 Nov 2009 19:55:14 -0000 @@ -242,6 +242,20 @@ private OpenAction fOpenAction; + /** + * Indicates whether the restore job was canceled implicitly. + * + * @since 3.6 + */ + private boolean fIsCancelImplicit= false; + + /** + * Indicates whether the current viewer shown is the empty viewer. + * + * @since 3.6 + */ + private boolean fIsShowingEmptyViewer= true; + public TypeHierarchyViewPart() { fSelectedType= null; @@ -251,7 +265,7 @@ fSelectInEditor= true; fRestoreStateJob= null; - fHierarchyLifeCycle= new TypeHierarchyLifeCycle(); + fHierarchyLifeCycle= new TypeHierarchyLifeCycle(this); fTypeHierarchyLifeCycleListener= new ITypeHierarchyLifeCycleListener() { public void typeHierarchyChanged(TypeHierarchyLifeCycle typeHierarchy, IType[] changedTypes) { doTypeHierarchyChanged(typeHierarchy, changedTypes); @@ -511,6 +525,7 @@ synchronized (this) { if (fRestoreStateJob != null) { fRestoreStateJob.cancel(); + fIsCancelImplicit= true; try { fRestoreStateJob.join(); } catch (InterruptedException e) { @@ -529,6 +544,11 @@ if (inputElement == null) { clearInput(); } else { + if (!inputElement.equals(prevInput)) { + for (int i= 0; i < fAllViewers.length; i++) { + fAllViewers[i].setInput(null); + } + } fInputElement= inputElement; fNoHierarchyShownLabel.setText(Messages.format(TypeHierarchyMessages.TypeHierarchyViewPart_createinput, JavaElementLabels.getElementLabel(inputElement, JavaElementLabels.ALL_DEFAULT))); try { @@ -537,34 +557,45 @@ } catch (InvocationTargetException e) { ExceptionHandler.handle(e, getSite().getShell(), TypeHierarchyMessages.TypeHierarchyViewPart_exception_title, TypeHierarchyMessages.TypeHierarchyViewPart_exception_message); clearInput(); - return; + return;// panic code. This code wont be executed. } catch (InterruptedException e) { fNoHierarchyShownLabel.setText(TypeHierarchyMessages.TypeHierarchyViewPart_empty); - return; + return;// panic code. This code wont be executed. } if (inputElement.getElementType() != IJavaElement.TYPE) { setHierarchyMode(HIERARCHY_MODE_CLASSIC); } - // turn off member filtering - fSelectInEditor= false; - setMemberFilter(null); - internalSelectType(null, false); // clear selection - fIsEnableMemberFilter= false; - if (!inputElement.equals(prevInput)) { - updateHierarchyViewer(true); - } - IType root= getSelectableType(inputElement); - internalSelectType(root, true); - updateMethodViewer(root); - updateToolbarButtons(); - updateToolTipAndDescription(); - showMembersInHierarchy(false); - fPagebook.showPage(fTypeMethodsSplitter); - fSelectInEditor= true; + updateViewers(); } } + /** + * Updates the viewers, toolbar buttons and tooltip. + * + * @since 3.6 + */ + public void updateViewers() { + if (!fHierarchyLifeCycle.isRefreshJob()) { + setViewersInput(); + } + setViewerVisibility(true); + // turn off member filtering + fSelectInEditor= false; + setMemberFilter(null); + internalSelectType(null, false); // clear selection + fIsEnableMemberFilter= false; + updateHierarchyViewer(true); + IType root= getSelectableType(fInputElement); + internalSelectType(root, true); + updateMethodViewer(root); + updateToolbarButtons(); + updateToolTipAndDescription(); + showMembersInHierarchy(false); + fPagebook.showPage(fTypeMethodsSplitter); + fSelectInEditor= true; + } + private void processOutstandingEvents() { Display display= getDisplay(); if (display != null && !display.isDisposed()) @@ -1086,7 +1117,7 @@ /* * Toggles between the empty viewer page and the hierarchy */ - private void setViewerVisibility(boolean showHierarchy) { + public void setViewerVisibility(boolean showHierarchy) { if (showHierarchy) { fViewerbook.showPage(getCurrentViewer().getControl()); } else { @@ -1124,7 +1155,7 @@ * updateHierarchyViewer brings up the correct view and refreshes * the current tree */ - private void updateHierarchyViewer(final boolean doExpand) { + public void updateHierarchyViewer(final boolean doExpand) { if (fInputElement == null) { fNoHierarchyShownLabel.setText(TypeHierarchyMessages.TypeHierarchyViewPart_empty); fPagebook.showPage(fNoHierarchyShownLabel); @@ -1139,7 +1170,7 @@ if (!isChildVisible(fViewerbook, getCurrentViewer().getControl())) { setViewerVisibility(true); } - } else { + } else if (!fIsShowingEmptyViewer) {//Show the empty hierarchy viewer till fresh computation is done. fEmptyTypesViewer.setText(Messages.format(TypeHierarchyMessages.TypeHierarchyViewPart_nodecl, JavaElementLabels.getElementLabel(fInputElement, JavaElementLabels.ALL_DEFAULT))); setViewerVisibility(false); } @@ -1566,6 +1597,7 @@ } catch (JavaModelException e) { return e.getStatus(); } catch (OperationCanceledException e) { + setCanceledViewer(fIsCancelImplicit); return Status.CANCEL_STATUS; } return Status.OK_STATUS; @@ -1579,17 +1611,16 @@ private void doRestoreInBackground(final IMemento memento, final IJavaElement hierarchyInput, IProgressMonitor monitor) throws JavaModelException { fHierarchyLifeCycle.doHierarchyRefresh(hierarchyInput, monitor); final boolean doRestore= !monitor.isCanceled(); - Display.getDefault().asyncExec(new Runnable() { - public void run() { - // running async: check first if view still exists - if (fPagebook != null && !fPagebook.isDisposed()) { - if (doRestore) + if (doRestore) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + // running async: check first if view still exists + if (fPagebook != null && !fPagebook.isDisposed()) { doRestoreState(memento, hierarchyInput); - else - fNoHierarchyShownLabel.setText(TypeHierarchyMessages.TypeHierarchyViewPart_empty); + } } - } - }); + }); + } } @@ -1602,6 +1633,7 @@ } fWorkingSetActionGroup.restoreState(memento); + setShowingEmptyViewer(false); setInputElement(input); Integer viewerIndex= memento.getInteger(TAG_VIEW); @@ -1640,6 +1672,19 @@ } /** + * Sets whether the previous viewer shown was an empty viewer. + * + * @param isShowingEmptyViewer true if the previous viewer was empty, + * false otherwise + * + * @since 3.6 + */ + private void setShowingEmptyViewer(boolean isShowingEmptyViewer) { + fIsShowingEmptyViewer= isShowingEmptyViewer; + + } + + /** * View part becomes visible. * * @param isVisible true if visible @@ -1731,4 +1776,46 @@ fNeedRefresh= false; } + /** + * Sets the empty viewer if the user cancels the computation. + * + * @param isCancelImplicit false when the user cancels the computation explicitly, + * true otherwise + * + * @since 3.6 + */ + public void setCanceledViewer(final boolean isCancelImplicit) { + if (!isCancelImplicit) { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + clearInput(); + setShowingEmptyViewer(true); + } + }); + } + } + + /** + * Returns the type hierarchy life cycle. + * + * @return the type hierarchy life cycle + * + * @since 3.6 + */ + public TypeHierarchyLifeCycle getTypeHierarchyLifeCycle() { + return fHierarchyLifeCycle; + + } + + /** + * Sets the input for all the hierarchy viewers with their respective viewer instances. + * + * @since 3.6 + */ + public void setViewersInput() { + for (int i= 0; i < fAllViewers.length; i++) { + fAllViewers[i].setInput(fAllViewers[i]); + } + setShowingEmptyViewer(false); + } }