/******************************************************************************* * Copyright (c) 2007, 2013 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.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.ViewerAdapterService; 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.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() */ @Override public Object getElement() { return fFrame; } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getElementPath() */ @Override public TreePath getElementPath() { return TreePath.EMPTY; } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getPresentationContext() */ @Override public IPresentationContext getPresentationContext() { return fViewerUpdate.getPresentationContext(); } /* (non-Javadoc) * @see org.eclipse.debug.internal.core.commands.Request#done() */ @Override public void done() { fViewerUpdate.setStatus(getStatus()); fViewerUpdate.done(); } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate#getViewerInput() */ @Override public Object getViewerInput() { return fFrame; } } 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) */ @Override 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) */ @Override 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() */ @Override public int getLength() { return fUpdate.getLength(); } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#getOffset() */ @Override public int getOffset() { return fUpdate.getOffset(); } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate#setChild(java.lang.Object, int) */ @Override 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() */ @Override public IMemento getMemento() { return fUpdate.getMemento(); } @Override public Object getElement() { return fUpdate.getElement(); } @Override 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) */ @Override 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) */ @Override 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() */ @Override 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) */ @Override public IModelProxy createModelProxy(Object element, IPresentationContext context) { IModelProxyFactory factory = ViewerAdapterService.getModelProxyFactory(fFrame); if (factory != null) { return factory.createModelProxy(fFrame, context); } return null; } /* (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) */ @Override public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) { IColumnPresentationFactory factory = ViewerAdapterService.getColumnPresentationFactory(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) */ @Override public String getColumnPresentationId(IPresentationContext context, Object element) { IColumnPresentationFactory factory = ViewerAdapterService.getColumnPresentationFactory(fFrame); if (factory != null) { return factory.getColumnPresentationId(context, fFrame); } return null; } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate[]) */ @Override public void update(IChildrenCountUpdate[] updates) { IElementContentProvider provider = ViewerAdapterService.getContentProvider(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[]) */ @Override public void update(IChildrenUpdate[] updates) { IElementContentProvider provider = ViewerAdapterService.getContentProvider(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[]) */ @Override public void update(IHasChildrenUpdate[] updates) { IElementContentProvider provider = ViewerAdapterService.getContentProvider(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(); } } /* (non-Javadoc) * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[]) */ @Override public void compareElements(IElementCompareRequest[] requests) { IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(fFrame); if (provider != null) { List<IElementCompareRequest> others = new ArrayList<IElementCompareRequest>(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(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[]) */ @Override public void encodeElements(IElementMementoRequest[] requests) { IElementMementoProvider provider = ViewerAdapterService.getMementoProvider(fFrame); if (provider != null) { List<IElementMementoRequest> others = new ArrayList<IElementMementoRequest>(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(others.toArray(new IElementMementoRequest[others.size()])); } } else { cancelUpdates(requests); } } }