From 2b72c663b0d52ed1e9c6b4c4aff250f22bd9cb03 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Sat, 11 Nov 2006 00:10:15 +0000 Subject: [PATCH] Added cell-editor support to DSF view model (bug# 159681). --- .../dsf/ui/viewmodel/AbstractVMAdapter.java | 21 +++++- .../ui/viewmodel/AbstractVMLayoutNode.java | 21 ++++++ .../ui/viewmodel/DMContextVMLayoutNode.java | 11 ++- .../dd/dsf/ui/viewmodel/IVMLayoutNode.java | 27 +++++++ .../dd/dsf/ui/viewmodel/VMProvider.java | 72 ++++++++++++++----- ...hreadSafeAndProhibitedFromDsfExecutor.java | 43 +++++++++++ .../dd/dsf/datamodel/AbstractDMContext.java | 2 +- .../dd/dsf/datamodel/AbstractDMEvent.java | 2 +- 8 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMAdapter.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMAdapter.java index 43caaf6a69f..a759c952ec6 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMAdapter.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMAdapter.java @@ -26,6 +26,8 @@ import org.eclipse.dd.dsf.ui.DsfUIPlugin; 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.provisional.IChildrenRequestMonitor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation; import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.IContainerRequestMonitor; @@ -43,7 +45,8 @@ abstract public class AbstractVMAdapter implements IAsynchronousLabelAdapter, IAsynchronousContentAdapter, IModelProxyFactoryAdapter, - IColumnPresentationFactoryAdapter + IColumnPresentationFactoryAdapter, + IColumnEditorFactoryAdapter { private final DsfSession fSession; @@ -193,4 +196,20 @@ abstract public class AbstractVMAdapter } return null; } + + public IColumnEditor createColumnEditor(IPresentationContext context, Object element) { + VMProvider provider = getViewModelProvider(context); + if (provider != null) { + return provider.createColumnEditor(element); + } + return null; + } + + public String getColumnEditorId(IPresentationContext context, Object element) { + VMProvider provider = getViewModelProvider(context); + if (provider != null) { + return provider.getColumnEditorId(element); + } + return null; + } } diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMLayoutNode.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMLayoutNode.java index 562f867f2d6..3fca9124448 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMLayoutNode.java @@ -17,8 +17,11 @@ import org.eclipse.dd.dsf.concurrent.Done; import org.eclipse.dd.dsf.concurrent.DoneCollector; import org.eclipse.dd.dsf.concurrent.DsfExecutor; import org.eclipse.dd.dsf.concurrent.GetDataDone; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor; import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext; /** * @@ -123,6 +126,24 @@ abstract public class AbstractVMLayoutNode implements IVMLayoutNode { }); } + /** + * Default implementation of the IColumnEditorFactoryAdapter delegate. It + * returns null, which means that no cell editor is configured. + * @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object) + */ + public IColumnEditor createColumnEditor(IVMContext vmc) { + return null; + } + + /** + * Default implementation of the IColumnEditorFactoryAdapter delegate. It + * returns null, which means that no cell editor is configured. + * @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object) + */ + public String getColumnEditorId(IVMContext vmc) { + return null; + } + /** * Convenience method that returns the child layout nodes which return * true to the hasDeltaFlags() test for the given diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DMContextVMLayoutNode.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DMContextVMLayoutNode.java index 005aef1da0f..dbfda1753ab 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DMContextVMLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DMContextVMLayoutNode.java @@ -94,6 +94,7 @@ abstract public class DMContextVMLayoutNode extends AbstractV /** Service tracker to be used by sub-classes */ private DsfServicesTracker fServices; + private DsfSession fSession; /** * Concrete class type that the elements of this schema node are based on. @@ -112,10 +113,18 @@ abstract public class DMContextVMLayoutNode extends AbstractV */ public DMContextVMLayoutNode(DsfSession session, Class> dmcClassType) { super(session.getExecutor()); + fSession = session; fServices = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId()); fDMCClassType = dmcClassType; } - + + /** + * Returns the session for use by sub-classes. + */ + protected DsfSession getSession() { + return fSession; + } + /** * Returns the services tracker for sub-class use. */ diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/IVMLayoutNode.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/IVMLayoutNode.java index 4a677ebb2c4..0d2d3f3014f 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/IVMLayoutNode.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/IVMLayoutNode.java @@ -13,6 +13,9 @@ package org.eclipse.dd.dsf.ui.viewmodel; import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.dd.dsf.concurrent.Done; import org.eclipse.dd.dsf.concurrent.GetDataDone; +import org.eclipse.dd.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor; import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta; import org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext; @@ -89,6 +92,30 @@ public interface IVMLayoutNode { */ public void buildDelta(Object event, VMDelta parent, Done done); + /** + * Creates a column editor for the given element. The interface that this + * method is delegated to is synchronous, therefore it also needs to be thread + * safe. + * + * @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object) + * @param vmc VM Context to return the editor for + * @return + */ + @ThreadSafeAndProhibitedFromDsfExecutor("") + public IColumnEditor createColumnEditor(IVMContext vmc); + + /** + * Returns the ID of the editor for the given element. The interface that this + * method is delegated to is synchronous, therefore it also needs to be thread + * safe. + * + * @see IColumnEditorFactoryAdapter#getColumnEditorId(IPresentationContext, Object) + * @param vmc VM Context to return the editor ID for + * @return + */ + @ThreadSafeAndProhibitedFromDsfExecutor("") + public String getColumnEditorId(IVMContext vmc); + /** * Disposes the resources held by this node. */ diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/VMProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/VMProvider.java index 9f26d2e1a40..029b25ff52b 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/VMProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/VMProvider.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.dd.dsf.ui.viewmodel; +import java.util.concurrent.atomic.AtomicReference; + import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -27,8 +29,10 @@ import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy; 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.provisional.IChildrenRequestMonitor; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditor; import org.eclipse.debug.internal.ui.viewers.provisional.IColumnEditorFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation; +import org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentationFactoryAdapter; import org.eclipse.debug.internal.ui.viewers.provisional.IContainerRequestMonitor; import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor; import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta; @@ -67,9 +71,9 @@ public class VMProvider /** * The root node for this model provider. The root layout node could be * null when first created, to allow sub-classes to prorperly configure the - * root node in the sub-class constructor. + * root node in the sub-class constructor. */ - private IVMRootLayoutNode fRootLayoutNode; + private AtomicReference fRootLayoutNodeRef = new AtomicReference(); /** * Constructs the view model provider for given DSF session. The @@ -80,7 +84,7 @@ public class VMProvider @ThreadSafe public VMProvider(DsfSession session, IVMRootLayoutNode rootLayoutNode) { fSession = session; - fRootLayoutNode = rootLayoutNode; + fRootLayoutNodeRef.set(rootLayoutNode); // Add ourselves as listener for DM events events. session.getExecutor().execute(new Runnable() { public void run() { @@ -92,16 +96,25 @@ public class VMProvider }); } - /** Sets the layout nodes */ + /** + * Sets the layout nodes. This method is thread-safe, because it might + * be called fromthe constructor, which itself is thread-safe. + */ + @ThreadSafe public void setRootLayoutNode(IVMRootLayoutNode rootLayoutNode) { - if (fRootLayoutNode != null) { - fRootLayoutNode.dispose(); + final IVMRootLayoutNode oldRootLayoutNode = fRootLayoutNodeRef.getAndSet(rootLayoutNode); + if (oldRootLayoutNode != null) { + // IVMLayoutNode has to be called on dispatch thread... for now at least. + getSession().getExecutor().execute( new Runnable() { + public void run() { + oldRootLayoutNode.dispose(); + } + }); } - fRootLayoutNode = rootLayoutNode; } public IVMRootLayoutNode getRootLayoutNode() { - return fRootLayoutNode; + return fRootLayoutNodeRef.get(); } /** Called to dispose the provider. */ @@ -109,8 +122,8 @@ public class VMProvider if (fRegisteredAsEventListener) { fSession.removeServiceEventListener(this); } - if (fRootLayoutNode != null) { - fRootLayoutNode.dispose(); + if (fRootLayoutNodeRef != null) { + fRootLayoutNodeRef.get().dispose(); } } @@ -256,7 +269,7 @@ public class VMProvider * column info is fairly static, this method is thread-safe, and it will * not be called on the executor thread. * - * @see IColumnEditorFactoryAdapter#createColumnEditor(IPresentationContext, Object) + * @see IColumnPresentationFactoryAdapter#createColumnPresentation(IPresentationContext, Object) */ @ThreadSafe public IColumnPresentation createColumnPresentation(Object element) { @@ -283,6 +296,24 @@ public class VMProvider return null; } + public IColumnEditor createColumnEditor(Object element) { + IVMContext vmc = getVmcForObject(element); + if (vmc == null) { + return null; + } + + return vmc.getLayoutNode().createColumnEditor(vmc); + } + + public String getColumnEditorId(Object element) { + IVMContext vmc = getVmcForObject(element); + if (vmc == null) { + return null; + } + + return vmc.getLayoutNode().getColumnEditorId(vmc); + } + /** * Convenience method that finds the VMC corresponding to given parent @@ -298,9 +329,14 @@ public class VMProvider * root VMC from the root node, and pass this root vmc to the root's * child layout nodes. */ - if (parent.equals(fRootLayoutNode.getRootVMC().getInputObject())) { - return fRootLayoutNode.getRootVMC(); - } else if (parent instanceof IVMContext){ + IVMRootLayoutNode rootLayoutNode = getRootLayoutNode(); + if (rootLayoutNode == null) { + return null; + } + else if (parent.equals(rootLayoutNode.getRootVMC().getInputObject())) { + return rootLayoutNode.getRootVMC(); + } + else if (parent instanceof IVMContext){ /* * The parent is a VMC. Check to make sure that the VMC * originated from a node in this ViewModelProvider. If it didn't @@ -308,7 +344,7 @@ public class VMProvider * request is a stale request. So just ignore it. */ if (isOurLayoutNode( ((IVMContext)parent).getLayoutNode(), - new IVMLayoutNode[] { fRootLayoutNode } )) + new IVMLayoutNode[] { rootLayoutNode } )) { return (IVMContext)parent; } @@ -339,8 +375,10 @@ public class VMProvider */ @DsfServiceEventHandler public void eventDispatched(final IDMEvent event) { - if (fRootLayoutNode.hasDeltaFlags(event)) { - fRootLayoutNode.createDelta(event, new GetDataDone() { + IVMRootLayoutNode rootLayoutNode = getRootLayoutNode(); + + if (rootLayoutNode != null && rootLayoutNode.hasDeltaFlags(event)) { + rootLayoutNode.createDelta(event, new GetDataDone() { public void run() { if (getStatus().isOK()) { fModelProxy.fireModelChangedNonDispatch(getData()); diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java new file mode 100644 index 00000000000..24a41981cfa --- /dev/null +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.concurrent; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation idicating that given package, class, method, can be accessed on + * any thread, except on the dispatch thread of given DsfExecutor. + *
This restriction is desirable if it is expected that the implementation + * behavior is to block the calling thread and execute a transaction using an + * executor. In this situation, if the call is made on the executor's dispach + * thread, the execution would dead-lock. + *
+ * If declared on package or type, a field or method could still be declared + * with an annotation indicating that it's thread-safe. + *

+ * Note: the runtime retention policy is there to allow automated testing + * and validation code. + * + * @param value The value indicates the method to use to obtain the executor. + * It should be null if it cannot be determined from the given object. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR}) +@Inherited +@Documented +public @interface ThreadSafeAndProhibitedFromDsfExecutor { + String value(); +} diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMContext.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMContext.java index 11350e58f13..b428ba83337 100644 --- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMContext.java +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMContext.java @@ -22,7 +22,7 @@ import org.eclipse.dd.dsf.service.DsfSession; * @param Data Model data type that this context is for. */ @Immutable -public class AbstractDMContext extends PlatformObject +abstract public class AbstractDMContext extends PlatformObject implements IDMContext { private final String fSessionId; diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMEvent.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMEvent.java index 68d2fc9842f..9ea389977cc 100644 --- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMEvent.java +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/datamodel/AbstractDMEvent.java @@ -17,7 +17,7 @@ import org.eclipse.dd.dsf.concurrent.Immutable; * required DM-Context reference. */ @Immutable -public class AbstractDMEvent> implements IDMEvent { +abstract public class AbstractDMEvent> implements IDMEvent { private final V fModelContext; public AbstractDMEvent(V context) {