diff options
author | Darin Wright | 2007-08-20 19:05:10 +0000 |
---|---|---|
committer | Darin Wright | 2007-08-20 19:05:10 +0000 |
commit | 915e49c30214e6279a4a9fb91a7c70f963c6a256 (patch) | |
tree | 0b6e7d5436cb5e72cd0d8147a28bad158d02d329 /org.eclipse.debug.ui/ui/org/eclipse/debug | |
parent | 38f0eda6752aff71557ebcd7677d8e2bb3e0a66f (diff) | |
download | eclipse.platform.debug-915e49c30214e6279a4a9fb91a7c70f963c6a256.tar.gz eclipse.platform.debug-915e49c30214e6279a4a9fb91a7c70f963c6a256.tar.xz eclipse.platform.debug-915e49c30214e6279a4a9fb91a7c70f963c6a256.zip |
Bug 176627 - [Registers view] Switching stack frames: Unnecessary scrolling to top and group closing
Diffstat (limited to 'org.eclipse.debug.ui/ui/org/eclipse/debug')
10 files changed, 1047 insertions, 7 deletions
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/RegisterGroupProxy.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/RegisterGroupProxy.java new file mode 100644 index 000000000..fc5dc7724 --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/RegisterGroupProxy.java @@ -0,0 +1,516 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.elements.adapters; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IRegisterGroup; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.internal.core.commands.Request; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; +import org.eclipse.debug.internal.ui.views.launch.DebugElementAdapterFactory; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.ui.IMemento; + +/** + * Used as input to the registers view for a stack frame. Insulates register groups + * that do not change across stack frame selection to avoid register groups collapsing + * while stepping between frames. + * <p> + * The standard debug model {@link IStackFrame} uses an + * {@link org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider} to + * create a register group proxy for the register view's input. + * </p> + * <p> + * This class delegates to the underlying stack frame for the following adapters. This way, + * if a standard model provides custom adapters they are still used to present custom content + * in the view and provide stable register groups while stepping. + * <ul> + * <li>{@link IModelProxyFactory}</li> + * <li>{@link IColumnPresentationFactory}</li> + * <li>{@link IElementContentProvider}</li> + * <li>{@link IElementMementoProvider}</li> + * </ul> + * </p> + * @since 3.4 + */ +public class RegisterGroupProxy implements IModelProxyFactory, IColumnPresentationFactory, IElementContentProvider, IElementMementoProvider { + + private IRegisterGroup[] fGroups; + private IStackFrame fFrame; + + private static final String HASH_CODE = "HASH_CODE"; //$NON-NLS-1$ + + /** + * Local implementation of a viewer update request. This class delegates to the underlying frame + * for viewer requests. The requests have to be wrapped such that the request's element provided + * for existing clients is the underlying frame, rather than the register group proxy (as existing + * models do not know or need to know about the proxy). + */ + private class Update extends Request implements IViewerUpdate { + private IViewerUpdate fViewerUpdate; + + Update(IViewerUpdate update) { + fViewerUpdate = update; + } + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElement() + */ + public Object getElement() { + return fFrame; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElementPath() + */ + public TreePath getElementPath() { + return TreePath.EMPTY; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getPresentationContext() + */ + public IPresentationContext getPresentationContext() { + return fViewerUpdate.getPresentationContext(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.core.commands.Request#done() + */ + public void done() { + fViewerUpdate.setStatus(getStatus()); + fViewerUpdate.done(); + } + } + + private class CountUpdate extends Update implements IChildrenCountUpdate { + + private IChildrenCountUpdate fUpdate; + + CountUpdate(IChildrenCountUpdate delegate) { + super(delegate); + fUpdate = delegate; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate#setChildCount(int) + */ + public void setChildCount(int numChildren) { + fUpdate.setChildCount(numChildren); + } + + } + + private class HasUpdate extends Update implements IHasChildrenUpdate { + + private IHasChildrenUpdate fUpdate; + + HasUpdate(IHasChildrenUpdate delegate) { + super(delegate); + fUpdate = delegate; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate#setHasChilren(boolean) + */ + public void setHasChilren(boolean hasChildren) { + fUpdate.setHasChilren(hasChildren); + } + + } + + private class ChildrenUpdate extends Update implements IChildrenUpdate { + + private IChildrenUpdate fUpdate; + + ChildrenUpdate(IChildrenUpdate delegate) { + super(delegate); + fUpdate = delegate; + } + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getLength() + */ + public int getLength() { + return fUpdate.getLength(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getOffset() + */ + public int getOffset() { + return fUpdate.getOffset(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#setChild(java.lang.Object, int) + */ + public void setChild(Object child, int offset) { + fUpdate.setChild(child, offset); + } + + } + + /** + * The memento request has to override {@link #getElement()} to provide the element + * that a memento is requested for (which could be any element in the view, not just + * the root stack frame). + */ + private class MementoRequest extends Update implements IElementMementoRequest { + + private IElementMementoRequest fUpdate; + MementoRequest(IElementMementoRequest request) { + super(request); + fUpdate = request; + } + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest#getMemento() + */ + public IMemento getMemento() { + return fUpdate.getMemento(); + } + public Object getElement() { + return fUpdate.getElement(); + } + public TreePath getElementPath() { + return fUpdate.getElementPath(); + } + + } + + private class ElementCompare extends MementoRequest implements IElementCompareRequest { + + private IElementCompareRequest fRequest; + ElementCompare(IElementCompareRequest request) { + super(request); + fRequest = request; + } + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest#setEqual(boolean) + */ + public void setEqual(boolean equal) { + fRequest.setEqual(equal); + } + + } + + /** + * Creates a new register group proxy for the given stack frame. + * + * @param frame stack frame + * @throws DebugException exception if unable to retrieve register groups + */ + public RegisterGroupProxy(IStackFrame frame) throws DebugException { + fFrame = frame; + init(frame); + } + + /* (non-Javadoc) + * + * A register group proxy is equal to other stack frames that have the same + * register groups. + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof RegisterGroupProxy) { + return Arrays.equals(fGroups, ((RegisterGroupProxy)obj).fGroups); + } + return false; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + int code = getClass().hashCode(); + for (int i = 0; i < fGroups.length; i++) { + code+=fGroups[i].hashCode(); + } + return code; + } + + /** + * Initializes the register groups for this stack frame. + * + * @param frame stack frame + */ + private void init(IStackFrame frame) throws DebugException { + fGroups = frame.getRegisterGroups(); + } + + /** + * Returns cached register groups for this stack frame. + * + * @return register groups + */ + protected IRegisterGroup[] getRegisterGroups() { + return fGroups; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory#createModelProxy(java.lang.Object, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext) + */ + public IModelProxy createModelProxy(Object element, IPresentationContext context) { + IModelProxyFactory factory = getModelProxyFactoryAdapter(fFrame); + if (factory != null) { + return factory.createModelProxy(fFrame, context); + } + return null; + } + + /** + * Returns the model proxy factory for the given element or + * <code>null</code> if none. + * + * @param element + * element to retrieve adapter for + * @return model proxy factory adapter or <code>null</code> + */ + protected IModelProxyFactory getModelProxyFactoryAdapter(Object element) { + IModelProxyFactory adapter = null; + if (element instanceof IModelProxyFactory) { + adapter = (IModelProxyFactory) element; + } else if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + adapter = (IModelProxyFactory) adaptable.getAdapter(IModelProxyFactory.class); + if (adapter == null && !(element instanceof PlatformObject)) { + // for objects that don't properly subclass PlatformObject to inherit default + // adapters, just delegate to the adapter factory + adapter = (IModelProxyFactory) new DebugElementAdapterFactory().getAdapter(element, IModelProxyFactory.class); + } + } + return adapter; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory#createColumnPresentation(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object) + */ + public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) { + IColumnPresentationFactory factory = getColumnPresenetationFactoryAdapter(fFrame); + if (factory != null) { + return factory.createColumnPresentation(context, fFrame); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory#getColumnPresentationId(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object) + */ + public String getColumnPresentationId(IPresentationContext context, Object element) { + IColumnPresentationFactory factory = getColumnPresenetationFactoryAdapter(fFrame); + if (factory != null) { + return factory.getColumnPresentationId(context, fFrame); + } + return null; + } + + /** + * Returns the column presentation factory for the given element or <code>null</code>. + * + * @param input + * @return column presentation factory of <code>null</code> + */ + protected IColumnPresentationFactory getColumnPresenetationFactoryAdapter(Object input) { + IColumnPresentationFactory adapter = null; + if (input instanceof IColumnPresentationFactory) { + adapter = (IColumnPresentationFactory) input; + } else if (input instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) input; + adapter = (IColumnPresentationFactory) adaptable.getAdapter(IColumnPresentationFactory.class); + if (adapter == null && !(input instanceof PlatformObject)) { + // for objects that don't properly subclass PlatformObject to inherit default + // adapters, just delegate to the adapter factory + adapter = (IColumnPresentationFactory) new DebugElementAdapterFactory().getAdapter(input, IColumnPresentationFactory.class); + } + } + return adapter; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate[]) + */ + public void update(IChildrenCountUpdate[] updates) { + IElementContentProvider provider = getContentAdapter(fFrame); + if (provider != null) { + IChildrenCountUpdate[] others = new IChildrenCountUpdate[updates.length]; + for (int i = 0; i < updates.length; i++) { + others[i] = new CountUpdate(updates[i]); + } + provider.update(others); + } else { + cancelUpdates(updates); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate[]) + */ + public void update(IChildrenUpdate[] updates) { + IElementContentProvider provider = getContentAdapter(fFrame); + if (provider != null) { + IChildrenUpdate[] others = new IChildrenUpdate[updates.length]; + for (int i = 0; i < updates.length; i++) { + others[i] = new ChildrenUpdate(updates[i]); + } + provider.update(others); + } else { + cancelUpdates(updates); + } + + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate[]) + */ + public void update(IHasChildrenUpdate[] updates) { + IElementContentProvider provider = getContentAdapter(fFrame); + if (provider != null) { + IHasChildrenUpdate[] others = new IHasChildrenUpdate[updates.length]; + for (int i = 0; i < updates.length; i++) { + others[i] = new HasUpdate(updates[i]); + } + provider.update(others); + } else { + cancelUpdates(updates); + } + } + + /** + * Cancels a collection of update requests. + * + * @param updates updates to cancel + */ + private void cancelUpdates(IViewerUpdate[] updates) { + for (int i = 0; i < updates.length; i++) { + updates[i].setStatus(Status.CANCEL_STATUS); + updates[i].done(); + } + } + + /** + * Returns the content adapter for the given element or + * <code>null</code> if none. + * + * @param element + * element to retrieve adapter for + * @return content adapter or <code>null</code> + */ + protected IElementContentProvider getContentAdapter(Object element) { + IElementContentProvider adapter = null; + if (element instanceof IElementContentProvider) { + adapter = (IElementContentProvider) element; + } else if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + adapter = (IElementContentProvider) adaptable.getAdapter(IElementContentProvider.class); + if (adapter == null && !(element instanceof PlatformObject)) { + // for objects that don't properly subclass PlatformObject to inherit default + // adapters, just delegate to the adapter factory + adapter = (IElementContentProvider) new DebugElementAdapterFactory().getAdapter(element, IElementContentProvider.class); + } + } + return adapter; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[]) + */ + public void compareElements(IElementCompareRequest[] requests) { + IElementMementoProvider provider = getViewerStateAdapter(fFrame); + if (provider != null) { + List others = new ArrayList(requests.length); + for (int i = 0; i < requests.length; i++) { + IElementCompareRequest request = requests[i]; + if (request.getElement().equals(this)) { + Integer integer = request.getMemento().getInteger(HASH_CODE); + if (integer != null) { + request.setEqual(integer.intValue() == hashCode()); + } else { + request.setEqual(false); + } + request.done(); + } else { + others.add(new ElementCompare(request)); + } + } + if (!others.isEmpty()) { + provider.compareElements((IElementCompareRequest[]) others.toArray(new IElementCompareRequest[others.size()])); + } + } else { + cancelUpdates(requests); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[]) + */ + public void encodeElements(IElementMementoRequest[] requests) { + IElementMementoProvider provider = getViewerStateAdapter(fFrame); + if (provider != null) { + List others = new ArrayList(requests.length); + for (int i = 0; i < requests.length; i++) { + IElementMementoRequest request = requests[i]; + if (request.getElement().equals(this)) { + request.getMemento().putInteger(HASH_CODE, this.hashCode()); + request.done(); + } else { + others.add(new MementoRequest(request)); + } + } + if (!others.isEmpty()) { + provider.encodeElements((IElementMementoRequest[]) others.toArray(new IElementMementoRequest[others.size()])); + } + } else { + cancelUpdates(requests); + } + } + + /** + * Returns the viewer state adapter for the given element or + * <code>null</code> if none. + * + * @param element + * element to retrieve adapter for + * @return viewer state adapter or <code>null</code> + */ + protected IElementMementoProvider getViewerStateAdapter(Object element) { + IElementMementoProvider adapter = null; + if (element instanceof IElementMementoProvider) { + adapter = (IElementMementoProvider) element; + } else if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + adapter = (IElementMementoProvider) adaptable.getAdapter(IElementMementoProvider.class); + if (adapter == null && !(element instanceof PlatformObject)) { + // for objects that don't properly subclass PlatformObject to inherit default + // adapters, just delegate to the adapter factory + adapter = (IElementMementoProvider) new DebugElementAdapterFactory().getAdapter(element, IElementMementoProvider.class); + } + } + return adapter; + } +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/StackFrameViewerInputProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/StackFrameViewerInputProvider.java new file mode 100644 index 000000000..ecd1418d8 --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/elements/adapters/StackFrameViewerInputProvider.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.elements.adapters; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.internal.ui.model.elements.ViewerInputProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; +import org.eclipse.debug.ui.IDebugUIConstants; + +/** + * @since 3.4 + */ +public class StackFrameViewerInputProvider extends ViewerInputProvider { + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.model.elements.ViewerInputProvider#getViewerInput(java.lang.Object, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate) + */ + protected Object getViewerInput(Object source, IPresentationContext context, IViewerUpdate update) throws CoreException { + return new RegisterGroupProxy((IStackFrame) source); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.model.elements.ViewerInputProvider#supportsContextId(java.lang.String) + */ + protected boolean supportsContextId(String id) { + return IDebugUIConstants.ID_REGISTER_VIEW.equals(id); + } + +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ViewerInputProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ViewerInputProvider.java new file mode 100644 index 000000000..f1a950e5e --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/model/elements/ViewerInputProvider.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.model.elements; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; + +/** + * Common code for viewer input providers. Creates a job to process request asynchronously. + + * @since 3.4 + */ +public abstract class ViewerInputProvider implements IViewerInputProvider { + + protected static final Object[] EMPTY = new Object[0]; + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider#updateChildren(java.lang.Object, int, int, org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext, org.eclipse.debug.internal.ui.viewers.model.provisional.IElementRequestMonitor) + */ + public void update(final IViewerInputUpdate update) { + Job job = new Job("viewer input resolution") { //$NON-NLS-1$ + protected IStatus run(IProgressMonitor monitor) { + if (!update.isCanceled()) { + retrieveInput(update); + } + update.done(); + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.setRule(getRule(update)); + job.schedule(); + } + + /** + * Computes the viewer input for the specified context. + * + * @param update update request + */ + protected void retrieveInput(IViewerInputUpdate update) { + if (!update.isCanceled()) { + IStatus status = Status.OK_STATUS; + try { + IPresentationContext context = update.getPresentationContext(); + if (supportsContext(context)) { + update.setViewerInput(getViewerInput(update.getElement(), context, update)); + } else { + update.setViewerInput(update.getElement()); + } + } catch (CoreException e) { + status = e.getStatus(); + } + update.setStatus(status); + } + } + + + /** + * Returns the viewer input derived from the given source object in the specified + * context, possibly <code>null</code>. + * + * @param source element to derive a viewer input from + * @param context context for which an input is requested + * @param update viewer update request + * @throws CoreException if an exception occurs retrieving child + */ + protected abstract Object getViewerInput(Object source, IPresentationContext context, IViewerUpdate update) throws CoreException; + + + /** + * Returns whether this adapter supports the given context. + * + * @param context + * @return whether this adapter supports the given context + */ + protected boolean supportsContext(IPresentationContext context) { + return supportsContextId(context.getId()); + } + + /** + * Returns whether this adapter provides content in the specified context id. + * + * @param id part id + * @return whether this adapter provides content in the specified context id + */ + protected abstract boolean supportsContextId(String id); + + /** + * Returns a scheduling rule to use when performing the given updates or + * <code>null</code> if none. + * + * @param updates + * @return scheduling rule or <code>null</code> if none + */ + protected ISchedulingRule getRule(IViewerInputUpdate update) { + return null; + } + +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerInputUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerInputUpdate.java new file mode 100644 index 000000000..9c69c018c --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/ViewerInputUpdate.java @@ -0,0 +1,128 @@ +package org.eclipse.debug.internal.ui.viewers.model; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.internal.core.commands.Request; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputRequestor; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.ui.progress.WorkbenchJob; + +/** + * Internal implementation of the {@link IViewerInputUpdate} interface. Allows + * implementors to translate the active debug context into an appropriate viewer + * input. + * + * @since 3.4 + * @see IViewerInputUpdate + */ +public class ViewerInputUpdate extends Request implements IViewerInputUpdate { + + /** + * Presentation context + */ + private IPresentationContext fContext; + + /** + * New viewer input + */ + private Object fSource; + + /** + * Whether this update is done + */ + private boolean fDone; + + /** + * Viewer input to use + */ + private Object fInput; + + /** + * Client making request + */ + private IViewerInputRequestor fRequestor; + + /** + * When <code>done()</code> is called, the viewer must be informed that the update is complete in the UI thread. + */ + protected WorkbenchJob fViewerInputUpdateJob = new WorkbenchJob("Asynchronous viewer input update") { //$NON-NLS-1$ + public IStatus runInUIThread(IProgressMonitor monitor) { + fRequestor.viewerInputComplete(ViewerInputUpdate.this); + return Status.OK_STATUS; + } + }; + + /** + * Constructs a viewer input update request. + * + * @param context presentation context + * @param requestor client making the request + * @param source source from which to derive a viewer input + */ + public ViewerInputUpdate(IPresentationContext context, IViewerInputRequestor requestor, Object source){ + fContext = context; + fSource = source; + fRequestor = requestor; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate#getPresentationContext() + */ + public IPresentationContext getPresentationContext() { + return fContext; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IProgressMonitor#done() + */ + public final void done() { + synchronized (this) { + if (isDone()) { + return; + } + fDone = true; + } + fViewerInputUpdateJob.schedule(); + } + + /** + * Returns whether this request is done yet. + * + * @return whether this request is done yet + */ + protected synchronized boolean isDone() { + return fDone; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate#getElement() + */ + public Object getElement() { + return fSource; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElementPath() + */ + public TreePath getElementPath() { + return TreePath.EMPTY; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate#setViewerInput(java.lang.Object) + */ + public void setViewerInput(Object element) { + fInput = element; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate#getViewerInput() + */ + public Object getViewerInput() { + return fInput; + } + +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputProvider.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputProvider.java new file mode 100644 index 000000000..dca273093 --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputProvider.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.viewers.model.provisional; + + +/** + * A viewer input provider allows a view to translate the active debug + * context into a viewer input (such that the active debug context does + * not have to be the input to a viewer). Used in conjunction with a + * {@link ViewerInputService}. + * <p> + * Clients may implement this interface. + * </p> + * @since 3.4 + * @see IViewerInputUpdate + * @see ViewerInputService + */ +public interface IViewerInputProvider { + + /** + * Asynchronously determine the viewer input to the based on the active + * debug context and presentation context. + * + * @param update provides details about the request and stores the newly + * computed viewer input + */ + public void update(IViewerInputUpdate update); + + +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputRequestor.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputRequestor.java new file mode 100644 index 000000000..92a74137f --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputRequestor.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.viewers.model.provisional; + +/** + * Clients using a {@link ViewerInputService} implement this interface to be notified of + * the computed viewer input. + * <p> + * Clients may implement this interface. + * </p> + * @see ViewerInputService + * @since 3.4 + */ +public interface IViewerInputRequestor { + + /** + * Notification that a viewer input update request is complete. The given update + * contains the result of the request. + * + * @param update viewer input update request + */ + public void viewerInputComplete(IViewerInputUpdate update); +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputUpdate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputUpdate.java new file mode 100644 index 000000000..5865a0997 --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/IViewerInputUpdate.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.viewers.model.provisional; + + +/** + * A request to provide a viewer input for a given element and presentation context. + * Allows a view to translate the active debug context into an appropriate viewer + * input element. + * <p> + * Clients requesting a viewer input update may implement this interface. + * </p> + * @since 3.4 + * + */ +public interface IViewerInputUpdate extends IViewerUpdate { + + /** + * Sets the input to use for this request's presentation context, or <code>null</code> + * if none (empty viewer). The source used to derive the viewer input is available + * from this request's <code>getElement()</code> method. + * + * @param element viewer input for this request's presentation context, possibly <code>null</code> + */ + public void setViewerInput(Object element); + + /** + * Returns the computed viewer input or <code>null</code> if none. The return value of this method + * only contains valid data if this request is complete (i.e. <code>done()</code> has been called). + * + * @return viewer input or <code>null</code> + */ + public Object getViewerInput(); +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java new file mode 100644 index 000000000..74b1ab6dd --- /dev/null +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/viewers/model/provisional/ViewerInputService.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + *******************************************************************************/ +package org.eclipse.debug.internal.ui.viewers.model.provisional; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.debug.internal.ui.viewers.model.ViewerInputUpdate; +import org.eclipse.debug.internal.ui.views.launch.DebugElementAdapterFactory; + +/** + * Service to compute a viewer input from a source object + * for a given presentation context. + * <p> + * This class may be instantiated. Not intended to be subclassed. + * </p> + * @since 3.4 + */ +public class ViewerInputService { + + // previous update request, cancelled when a new request comes in + private IViewerInputUpdate fPendingUpdate = null; + + private IViewerInputRequestor fRequestor = null; + private IPresentationContext fContext = null; + + private IViewerInputRequestor fProxyRequest = new IViewerInputRequestor() { + public void viewerInputComplete(final IViewerInputUpdate update) { + synchronized (ViewerInputService.this) { + fPendingUpdate = null; + } + fRequestor.viewerInputComplete(update); + } + }; + + /** + * Constructs a viewer input service for the given requester and presentation context. + * + * @param requestor client requesting viewer inputs + * @param context context for which inputs are required + */ + public ViewerInputService(IViewerInputRequestor requestor, IPresentationContext context) { + fRequestor = requestor; + fContext = context; + } + + /** + * Resolves a viewer input derived from the given source object. + * Reports the result to the given this service's requester. A requester may be called back + * in the same or thread, or asynchronously in a different thread. Cancels any previous + * incomplete request from this service's requester. + * + * @param source source from which to derive a viewer input + */ + public void resolveViewerInput(Object source) { + IViewerInputProvider provdier = getInputProvider(source); + synchronized (this) { + // cancel any pending update + if (fPendingUpdate != null) { + fPendingUpdate.cancel(); + } + fPendingUpdate = new ViewerInputUpdate(fContext, fProxyRequest, source); + } + if (provdier == null) { + fPendingUpdate.setViewerInput(source); + fRequestor.viewerInputComplete(fPendingUpdate); + } else { + provdier.update(fPendingUpdate); + } + } + + /** + * Returns the viewer input provider for the given element or + * <code>null</code> if none. + * + * @param element + * element to retrieve adapter for + * @return content adapter or <code>null</code> + */ + private IViewerInputProvider getInputProvider(Object element) { + IViewerInputProvider adapter = null; + if (element instanceof IViewerInputProvider) { + adapter = (IViewerInputProvider) element; + } else if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + adapter = (IViewerInputProvider) adaptable.getAdapter(IViewerInputProvider.class); + if (adapter == null && !(element instanceof PlatformObject)) { + // for objects that don't properly subclass PlatformObject to inherit default + // adapters, just delegate to the adapter factory + adapter = (IViewerInputProvider) new DebugElementAdapterFactory().getAdapter(element, IViewerInputProvider.class); + } + } + return adapter; + } +} diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java index 1988119a9..f2e0a06f8 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/DebugElementAdapterFactory.java @@ -30,6 +30,7 @@ import org.eclipse.debug.internal.ui.elements.adapters.MemoryBlockLabelAdapter; import org.eclipse.debug.internal.ui.elements.adapters.MemoryRetrievalContentAdapter; import org.eclipse.debug.internal.ui.elements.adapters.MemorySegmentLabelAdapter; import org.eclipse.debug.internal.ui.elements.adapters.StackFrameSourceDisplayAdapter; +import org.eclipse.debug.internal.ui.elements.adapters.StackFrameViewerInputProvider; import org.eclipse.debug.internal.ui.elements.adapters.VariableColumnFactoryAdapter; import org.eclipse.debug.internal.ui.model.elements.DebugElementLabelProvider; import org.eclipse.debug.internal.ui.model.elements.DebugTargetContentProvider; @@ -58,6 +59,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProv import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider; import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter; import org.eclipse.debug.internal.ui.viewers.update.DefaultModelProxyFactory; @@ -234,6 +236,12 @@ public class DebugElementAdapterFactory implements IAdapterFactory { } } + if (adapterType.equals(IViewerInputProvider.class)) { + if (adaptableObject instanceof IStackFrame) { + return new StackFrameViewerInputProvider(); // TODO static? + } + } + return null; } @@ -251,7 +259,8 @@ public class DebugElementAdapterFactory implements IAdapterFactory { IElementContentProvider.class, IElementLabelProvider.class, IElementMementoProvider.class, - IElementEditor.class}; + IElementEditor.class, + IViewerInputProvider.class}; } } diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java index e8c48e674..e5248469a 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/variables/VariablesView.java @@ -41,9 +41,12 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputRequestor; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener; import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ViewerInputService; import org.eclipse.debug.internal.ui.views.DebugModelPresentationContext; import org.eclipse.debug.internal.ui.views.IDebugExceptionHandler; import org.eclipse.debug.internal.ui.views.variables.details.AvailableDetailPanesAction; @@ -146,6 +149,26 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis private Listener fDetailPaneActivatedListener; /** + * Viewer input service used to translate active debug context to viewer input. + */ + private ViewerInputService fInputService; + + /** + * Viewer input requester used to update the viewer once the viewer input has been + * resolved. + */ + private IViewerInputRequestor fRequester = new IViewerInputRequestor() { + public void viewerInputComplete(IViewerInputUpdate update) { + if (!update.isCanceled()) { + setViewerInput(update.getViewerInput()); + showViewer(); + updateAction(VARIABLES_FIND_ELEMENT_ACTION); + updateAction(FIND_ACTION); + } + } + }; + + /** * These are used to initialize and persist the position of the sash that * separates the tree viewer from the detail pane. */ @@ -315,6 +338,7 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis JFaceResources.getFontRegistry().addListener(this); TreeModelViewer variablesViewer = createTreeViewer(fSashForm); + fInputService = new ViewerInputService(fRequester, variablesViewer.getPresentationContext()); fSashForm.setMaximizedControl(variablesViewer.getControl()); @@ -879,14 +903,10 @@ public class VariablesView extends AbstractDebugView implements IDebugContextLis if (!isAvailable() || !isVisible()) { return; } - if (selection instanceof IStructuredSelection) { - setViewerInput(((IStructuredSelection)selection).getFirstElement()); + Object source = ((IStructuredSelection)selection).getFirstElement(); + fInputService.resolveViewerInput(source); } - showViewer(); - - updateAction(VARIABLES_FIND_ELEMENT_ACTION); - updateAction(FIND_ACTION); } /** |