From 9d94af8a4dd20d4356055cf4900d0a5cb84bdc2b Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Thu, 11 Feb 2010 19:41:37 +0000 Subject: [PATCH] [291426] - [breakpoints] Add DSF support for flex-hierarchy breakpoints view. --- .../ui/viewmodel/GdbViewModelAdapter.java | 7 +- .../META-INF/MANIFEST.MF | 1 + .../BreakpointOrganizerVMContext.java | 74 ++++ .../BreakpointOrganizerVMNode.java | 162 ++++++++ .../breakpoints/BreakpointVMContext.java | 57 +++ .../breakpoints/BreakpointVMInput.java | 78 ++++ .../BreakpointVMModelProxyStrategy.java | 60 +++ .../breakpoints/BreakpointVMNode.java | 322 ++++++++++++++++ .../breakpoints/BreakpointVMProvider.java | 358 ++++++++++++++++++ .../breakpoints/BreakpointsChangedEvent.java | 36 ++ .../breakpoints/RawBreakpointVMNode.java | 181 +++++++++ .../DefaultVMContentProviderStrategy.java | 9 +- .../DefaultVMModelProxyStrategy.java | 37 +- .../cdt/dsf/ui/viewmodel/IVMModelProxy.java | 17 +- .../eclipse/cdt/dsf/concurrent/DataCache.java | 200 ++++++++++ 15 files changed, 1587 insertions(+), 12 deletions(-) create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMContext.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMNode.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMContext.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMInput.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMModelProxyStrategy.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMNode.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMProvider.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointsChangedEvent.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/RawBreakpointVMNode.java create mode 100644 dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataCache.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java index 5c08a970518..249fd188996 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java @@ -13,13 +13,14 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; import org.eclipse.cdt.dsf.debug.ui.viewmodel.AbstractDebugVMAdapter; import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.breakpoints.BreakpointVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.ModulesVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider; import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.launch.LaunchVMProvider; import org.eclipse.cdt.dsf.service.DsfSession; -import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider; import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; import org.eclipse.debug.ui.IDebugUIConstants; @@ -43,7 +44,7 @@ public class GdbViewModelAdapter extends AbstractDebugVMAdapter } @Override - protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) { + protected IVMProvider createViewModelProvider(IPresentationContext context) { if ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) { return new LaunchVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) { @@ -54,6 +55,8 @@ public class GdbViewModelAdapter extends AbstractDebugVMAdapter return new ExpressionVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_MODULE_VIEW.equals(context.getId()) ) { return new ModulesVMProvider(this, context, getSession()); + } else if (IDebugUIConstants.ID_BREAKPOINT_VIEW.equals(context.getId()) ) { + return new BreakpointVMProvider(this, context); } return null; } diff --git a/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF index 2c915121b69..39404b77b33 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF +++ b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF @@ -29,6 +29,7 @@ Export-Package: org.eclipse.cdt.dsf.debug.internal.ui.disassembly.provisional, org.eclipse.cdt.dsf.debug.ui.sourcelookup, org.eclipse.cdt.dsf.debug.ui.viewmodel;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.examples.dsf,org.eclipse.cdt.examples.dsf.pda.ui", org.eclipse.cdt.dsf.debug.ui.viewmodel.actions;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.examples.dsf,org.eclipse.cdt.examples.dsf.pda.ui", + org.eclipse.cdt.dsf.debug.ui.viewmodel.breakpoints;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.examples.dsf,org.eclipse.cdt.examples.dsf.pda.ui", org.eclipse.cdt.dsf.debug.ui.viewmodel.expression;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.examples.dsf,org.eclipse.cdt.examples.dsf.pda.ui", org.eclipse.cdt.dsf.debug.ui.viewmodel.launch; x-friends:="org.eclipse.cdt.dsf.gdb.ui, diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMContext.java new file mode 100644 index 00000000000..0d05a2be2c6 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMContext.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointContainer; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer; + +/** + * + * + * @since 2.1 + */ +public class BreakpointOrganizerVMContext extends AbstractVMContext implements IBreakpointContainer { + + private final IAdaptable fCategory; + private final IBreakpoint[] fBreakpoints; + + BreakpointOrganizerVMContext(BreakpointOrganizerVMNode vmNode, IAdaptable category, IBreakpoint[] breakpoints) { + super(vmNode); + fCategory = category; + fBreakpoints = breakpoints; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BreakpointOrganizerVMContext && + getVMNode().equals( ((BreakpointOrganizerVMContext)obj).getVMNode() ) && + getOrganizer().equals( ((BreakpointOrganizerVMContext)obj).getOrganizer() ) && + fCategory.equals(((BreakpointOrganizerVMContext)obj).fCategory); + } + + @Override + public int hashCode() { + return getOrganizer().hashCode() + getVMNode().hashCode() + fCategory.hashCode(); + } + + public IBreakpointOrganizer getOrganizer() { + return ((BreakpointOrganizerVMNode)getVMNode()).getOrganizer(); + } + + public IAdaptable getCategory() { + return fCategory; + } + + public boolean contains(IBreakpoint breakpoint) { + for (IBreakpoint bp : fBreakpoints) { + if (bp.equals(breakpoint)) { + return true; + } + } + return false; + } + + public IBreakpoint[] getBreakpoints() { + return fBreakpoints; + } + + @Override + public String toString() { + return fCategory.toString(); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMNode.java new file mode 100644 index 00000000000..5145596464f --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointOrganizerVMNode.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import java.util.List; + +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants; +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.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +/** + * + * + * @since 2.1 + */ +public class BreakpointOrganizerVMNode extends AbstractVMNode { + + private final IBreakpointOrganizer fOrganizer; + + private final IPropertyChangeListener fOrganizerListener = new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + ((BreakpointVMProvider)getVMProvider()).handleEventInExecThread(event); + } + }; + + public BreakpointOrganizerVMNode(BreakpointVMProvider provider, IBreakpointOrganizer organizer) { + super(provider); + fOrganizer = organizer; + fOrganizer.addPropertyChangeListener(fOrganizerListener); + } + + @Override + public void dispose() { + fOrganizer.removePropertyChangeListener(fOrganizerListener); + super.dispose(); + } + + public IBreakpointOrganizer getOrganizer() { + return fOrganizer; + } + + public void update(final IHasChildrenUpdate[] updates) { + for (final IHasChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getBreakpointOrganizerVMCs( + this, update.getElementPath(), + new ViewerDataRequestMonitor>(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setHasChilren(!getData().isEmpty()); + } else { + update.setHasChilren(false); + } + update.done(); + } + }); + } + } + + public void update(final IChildrenCountUpdate[] updates) { + for (final IChildrenCountUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getBreakpointOrganizerVMCs( + this, update.getElementPath(), + new ViewerDataRequestMonitor>(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setChildCount(getData().size()); + } else { + update.setChildCount(0); + } + update.done(); + } + }); + } + } + + public void update(IChildrenUpdate[] updates) { + for (final IChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getBreakpointOrganizerVMCs( + this, update.getElementPath(), + new ViewerDataRequestMonitor>(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + int updateIdx = update.getOffset() != -1 ? update.getOffset() : 0; + int endIdx = updateIdx + (update.getLength() != -1 ? update.getLength() : (getData().size())); + while (updateIdx < endIdx && updateIdx < getData().size()) { + update.setChild(getData().get(updateIdx), updateIdx); + updateIdx++; + } + } + update.done(); + } + }); + } + } + + protected BreakpointOrganizerVMContext createVMContext(IAdaptable category, IBreakpoint[] breakpoints) { + return new BreakpointOrganizerVMContext(this, category, breakpoints); + } + + public int getDeltaFlags(Object event) { + if (event instanceof BreakpointsChangedEvent) { + return IModelDelta.CONTENT; + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) + { + return IModelDelta.CONTENT; + } + } else if (BreakpointVMProvider.isBreakpointOrganizerEvent(event)) { + return IModelDelta.CONTENT; + } + return 0; + } + + public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor) { + if (event instanceof BreakpointsChangedEvent) { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) + { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + } else if (BreakpointVMProvider.isBreakpointOrganizerEvent(event)) { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + + requestMonitor.done(); + } + +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMContext.java new file mode 100644 index 00000000000..c46ef0fc1da --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMContext.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext; +import org.eclipse.debug.core.model.IBreakpoint; + +/** + * @since 2.1 + */ +public class BreakpointVMContext extends AbstractVMContext { + + private final IBreakpoint fBreakpoint; + + public BreakpointVMContext(BreakpointVMNode node, IBreakpoint breakpoint) { + super(node); + fBreakpoint = breakpoint; + } + + public IBreakpoint getBreakpoint() { + return fBreakpoint; + } + + @Override + @SuppressWarnings("rawtypes") + public Object getAdapter(Class adapter) { + if (adapter.isInstance(fBreakpoint)) { + return fBreakpoint; + } + return super.getAdapter(adapter); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BreakpointVMContext && + getBreakpoint().equals( ((BreakpointVMContext)obj).getBreakpoint() ) && + fBreakpoint.equals(((BreakpointVMContext)obj).fBreakpoint); + } + + @Override + public int hashCode() { + return fBreakpoint.hashCode(); + } + + @Override + public String toString() { + return fBreakpoint.toString(); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMInput.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMInput.java new file mode 100644 index 00000000000..f00ea9dd920 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMInput.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMAdapter; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest; + +/** + * @since 2.1 + */ +public class BreakpointVMInput extends PlatformObject implements IElementMementoProvider { + + private IVMNode fVMNode; + + public BreakpointVMInput(IVMNode node, IDMContext activeDMContext) { + fVMNode = node; + } + + public void encodeElements(IElementMementoRequest[] requests) { + for (IElementMementoRequest request : requests) { + request.getMemento().putString("ELEMENT_NAME", "BreakpointInputMemento"); //$NON-NLS-1$//$NON-NLS-2$ + request.done(); + } + } + + public void compareElements(IElementCompareRequest[] requests) { + for (IElementCompareRequest request : requests) { + request.setEqual( "BreakpointInputMemento".equals(request.getMemento().getString("ELEMENT_NAME")) ); //$NON-NLS-1$//$NON-NLS-2$ + request.done(); + } + } + + @Override + @SuppressWarnings({"rawtypes" }) + public Object getAdapter(Class adapter) { + // If the context implements the given adapter directly, it always takes + // precedence. + if (adapter.isInstance(this)) { + return this; + } + + IVMProvider vmProvider = fVMNode.getVMProvider(); + IVMAdapter vmAdapter = vmProvider.getVMAdapter(); + if (adapter.isInstance(vmAdapter)) { + return vmAdapter; + } else if (adapter.isInstance(vmProvider)) { + return vmProvider; + } else if (adapter.isInstance(fVMNode)) { + return fVMNode; + } + return Platform.getAdapterManager().getAdapter(this, adapter); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BreakpointVMInput; + } + + @Override + public int hashCode() { + return getClass().hashCode(); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMModelProxyStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMModelProxyStrategy.java new file mode 100644 index 00000000000..99b5b83f6f4 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMModelProxyStrategy.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.DefaultVMModelProxyStrategy; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointContainer; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckboxModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.jface.viewers.TreePath; + +/** + * Breakpoints VM model proxy that includes an ICheckboxModelProxy implementation. + * + * @since 2.1 + */ +public class BreakpointVMModelProxyStrategy extends DefaultVMModelProxyStrategy implements ICheckboxModelProxy { + + public BreakpointVMModelProxyStrategy(AbstractVMProvider provider, Object rootElement) { + super(provider, rootElement); + } + + public boolean setChecked(IPresentationContext context, Object viewerInput, TreePath path, boolean checked) { + Object lastSegment = path.getLastSegment(); + if (lastSegment instanceof IBreakpointContainer) { + IBreakpoint[] breakpoints = ((IBreakpointContainer) lastSegment).getBreakpoints(); + for (int i = 0; i < breakpoints.length; ++i) { + try { + breakpoints[i].setEnabled(checked); + } catch (CoreException e) { + return false; + } + } + return true; + } + else { + IBreakpoint breakpoint = (IBreakpoint)DebugPlugin.getAdapter(lastSegment, IBreakpoint.class); + if (breakpoint != null) { + try { + breakpoint.setEnabled(checked); + } catch (CoreException e) { + return false; + } + return true; + } + } + return false; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMNode.java new file mode 100644 index 00000000000..07f4ad95557 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMNode.java @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ICheckUpdate; +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.IElementCompareRequest; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +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.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.ui.IMemento; + +/** + * + * + * @since 2.1 + */ +public class BreakpointVMNode extends AbstractVMNode implements IElementLabelProvider, IElementMementoProvider { + + public BreakpointVMNode(IVMProvider provider) { + super(provider); + } + + public void update(final IHasChildrenUpdate[] updates) { + for (final IHasChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setHasChilren(getData().length != 0); + } else { + update.setHasChilren(false); + } + update.done(); + } + }); + } + } + + public void update(final IChildrenCountUpdate[] updates) { + for (final IChildrenCountUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setChildCount(getData().length); + } else { + update.setChildCount(0); + } + update.done(); + } + }); + } + } + + public void update(IChildrenUpdate[] updates) { + for (final IChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + @SuppressWarnings("unchecked") + Comparator comparator = + (Comparator)getVMProvider().getPresentationContext().getProperty( + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR); + if (comparator != null) { + Arrays.sort(getData(), comparator); + } + fillUpdateWithBreakpointVMCs(update, getData()); + } + update.done(); + } + }); + } + } + + private void fillUpdateWithBreakpointVMCs(IChildrenUpdate update, IBreakpoint[] bps) { + int updateIdx = update.getOffset() != -1 ? update.getOffset() : 0; + int endIdx = updateIdx + (update.getLength() != -1 ? update.getLength() : bps.length); + while (updateIdx < endIdx && updateIdx < bps.length) { + update.setChild(createVMContext(bps[updateIdx]), updateIdx); + updateIdx++; + } + } + + protected BreakpointVMContext createVMContext(IBreakpoint bp) { + return new BreakpointVMContext(this, bp); + } + + public void update(ILabelUpdate[] updates) { + Map> delegatesMap = new HashMap>(1,1); + + for (final ILabelUpdate update : updates) { + final IBreakpoint bp = ((BreakpointVMContext)update.getElement()).getBreakpoint(); + IElementLabelProvider provider = (IElementLabelProvider)bp.getAdapter(IElementLabelProvider.class); + if (provider == null) { + update.done(); + continue; + } + + List delegatesList = delegatesMap.get(provider); + if (delegatesList == null) { + delegatesList = new ArrayList(updates.length); + delegatesMap.put(provider, delegatesList); + } + delegatesList.add(new ICheckUpdate() { + public void setChecked(boolean checked, boolean grayed) { + if (update instanceof ICheckUpdate) { + ((ICheckUpdate)update).setChecked(checked, grayed); + } + } + public String[] getColumnIds() { return update.getColumnIds(); } + public void setLabel(String text, int columnIndex) { + update.setLabel(text, columnIndex); + } + public void setFontData(FontData fontData, int columnIndex) { update.setFontData(fontData, columnIndex); } + public void setImageDescriptor(ImageDescriptor image, int columnIndex) { update.setImageDescriptor(image, columnIndex); } + public void setForeground(RGB foreground, int columnIndex) { update.setForeground(foreground, columnIndex); } + public void setBackground(RGB background, int columnIndex) { update.setBackground(background, columnIndex); } + public IPresentationContext getPresentationContext() { return update.getPresentationContext(); } + public Object getElement() { return bp; } + public TreePath getElementPath() { return update.getElementPath().getParentPath().createChildPath(bp); } + public Object getViewerInput() { return update.getViewerInput(); } + public void setStatus(IStatus status) { update.setStatus(status); } + public IStatus getStatus() { return update.getStatus(); } + public void done() { update.done(); } + public void cancel() { update.cancel(); } + public boolean isCanceled() { return update.isCanceled(); } + }); + } + + for (IElementLabelProvider provider : delegatesMap.keySet()) { + List updatesList = delegatesMap.get(provider); + provider.update(updatesList.toArray(new ILabelUpdate[updatesList.size()])); + } + } + + public void encodeElements(IElementMementoRequest[] updates) { + Map> delegatesMap = new HashMap>(1,1); + + for (final IElementMementoRequest update : updates) { + final IBreakpoint bp = ((BreakpointVMContext)update.getElement()).getBreakpoint(); + IElementMementoProvider provider = (IElementMementoProvider)bp.getAdapter(IElementMementoProvider.class); + if (provider == null) { + update.done(); + continue; + } + + List delegatesList = delegatesMap.get(provider); + if (delegatesList == null) { + delegatesList = new ArrayList(updates.length); + delegatesMap.put(provider, delegatesList); + } + delegatesList.add(new IElementMementoRequest() { + public IMemento getMemento() { return update.getMemento(); } + public IPresentationContext getPresentationContext() { return update.getPresentationContext(); } + public Object getElement() { return bp; } + public TreePath getElementPath() { return update.getElementPath().getParentPath().createChildPath(bp); } + public Object getViewerInput() { return update.getViewerInput(); } + public void setStatus(IStatus status) { update.setStatus(status); } + public IStatus getStatus() { return update.getStatus(); } + public void done() { update.done(); } + public void cancel() { update.cancel(); } + public boolean isCanceled() { return update.isCanceled(); } + }); + } + + for (IElementMementoProvider provider : delegatesMap.keySet()) { + List updatesList = delegatesMap.get(provider); + provider.encodeElements(updatesList.toArray(new IElementMementoRequest[updatesList.size()])); + } + } + + public void compareElements(IElementCompareRequest[] updates) { + Map> delegatesMap = new HashMap>(1,1); + + for (final IElementCompareRequest update : updates) { + final IBreakpoint bp = ((BreakpointVMContext)update.getElement()).getBreakpoint(); + IElementMementoProvider provider = (IElementMementoProvider)bp.getAdapter(IElementMementoProvider.class); + if (provider == null) { + update.done(); + continue; + } + + List delegatesList = delegatesMap.get(provider); + if (delegatesList == null) { + delegatesList = new ArrayList(updates.length); + delegatesMap.put(provider, delegatesList); + } + delegatesList.add(new IElementCompareRequest() { + public IMemento getMemento() { return update.getMemento(); } + public void setEqual(boolean equal) { update.setEqual(equal);} + public IPresentationContext getPresentationContext() { return update.getPresentationContext(); } + public Object getElement() { return bp; } + public TreePath getElementPath() { return update.getElementPath().getParentPath().createChildPath(bp); } + public Object getViewerInput() { return update.getViewerInput(); } + public void setStatus(IStatus status) { update.setStatus(status); } + public IStatus getStatus() { return update.getStatus(); } + public void done() { update.done(); } + public void cancel() { update.cancel(); } + public boolean isCanceled() { return update.isCanceled(); } + }); + } + + for (IElementMementoProvider provider : delegatesMap.keySet()) { + List updatesList = delegatesMap.get(provider); + provider.compareElements(updatesList.toArray(new IElementCompareRequest[updatesList.size()])); + } + } + + public int getDeltaFlags(Object event) { + if (event instanceof BreakpointsChangedEvent) { + BreakpointsChangedEvent bpChangedEvent = ((BreakpointsChangedEvent)event); + if (BreakpointsChangedEvent.Type.ADDED.equals(bpChangedEvent.getType())) { + return IModelDelta.CONTENT | IModelDelta.SELECT | IModelDelta.EXPAND; + } + return IModelDelta.CONTENT; + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty())) + { + return IModelDelta.CONTENT; + } else if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) { + return IModelDelta.EXPAND | IModelDelta.CONTENT; + } + } + return 0; + } + + public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor rm) { + if (event instanceof BreakpointsChangedEvent) { + BreakpointsChangedEvent bpChangedEvent = ((BreakpointsChangedEvent)event); + if (BreakpointsChangedEvent.Type.ADDED.equals(bpChangedEvent.getType())) { + buildBreakpointAddedDelta(bpChangedEvent, parent, nodeOffset, rm); + // Do not call rm.done() in this method! + return; + } else { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty())) + { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } else if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) { + parent.setFlags(parent.getFlags() | IModelDelta.EXPAND | IModelDelta.CONTENT); + } + } + + rm.done(); + } + + private void buildBreakpointAddedDelta(final BreakpointsChangedEvent event, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) { + getVMProvider().updateNode(this, new VMChildrenUpdate( + parent, getVMProvider().getPresentationContext(), -1, -1, + new DataRequestMonitor>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + for (int i = 0; i < event.getBreakpoints().length; i++) { + int bpIndex = getData().indexOf(event.getBreakpoints()[i]); + if (bpIndex >= 0) { + // Select only the first breakpoint that was added + if (i == 0) { + parent.addNode(getData().get(bpIndex), bpIndex, IModelDelta.SELECT); + } + // For all other added breakpoints, expand the parent. + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT | IModelDelta.EXPAND); + } + } + rm.done(); + } + })); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMProvider.java new file mode 100644 index 00000000000..4621ffb37b9 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointVMProvider.java @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataCache; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointsListener; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants; +import org.eclipse.debug.internal.ui.breakpoints.provisional.OtherBreakpointCategory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate; +import org.eclipse.debug.ui.IBreakpointOrganizerDelegate; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TreePath; + +/** + * The expression provider is used to populate the contents of the expressions + * view. The node hierarchy in this view is a little different than in a typical + * provider: the expression manager node should be registered as the single child + * of the root node and no nodes should be registered as children of expression node. + * Instead the top level expression nodes should be registered with a call to + * {@link #setExpressionNodes(IExpressionVMNode[])}. And each expression node can + * have its own sub-hierarchy of elements as needed. However all nodes configured + * with this provider (with the exception of the root and the expression manager) + * should implement {@link IExpressionVMNode}. + * + * @since 2.1 + */ +public class BreakpointVMProvider extends AbstractVMProvider +{ + private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + handleEventInExecThread(event); + } + }; + + private IBreakpointsListener fBreakpointsListener = new IBreakpointsListener() { + public void breakpointsRemoved(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) { + handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.REMOVED, breakpoints)); + } + + public void breakpointsChanged(IBreakpoint[] breakpoints, IMarkerDelta[] deltas) { + handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.CHANGED, breakpoints)); + } + + public void breakpointsAdded(IBreakpoint[] breakpoints) { + handleEventInExecThread(new BreakpointsChangedEvent(BreakpointsChangedEvent.Type.ADDED, breakpoints)); + } + + }; + + private class ContainerBreakpointsCache extends DataCache> { + + private BreakpointOrganizerVMNode fOrganizerVMNode; + private TreePath fParentPath; + + public ContainerBreakpointsCache(BreakpointOrganizerVMNode organizerVMNode, TreePath parentPath) { + super(getExecutor()); + fOrganizerVMNode = organizerVMNode; + fParentPath = parentPath; + } + + @Override + protected void retrieve(final DataRequestMonitor> rm) { + getNestingCategoryBreakpoints( + fParentPath, + new DataRequestMonitor(getExecutor(), rm) { + @SuppressWarnings({ "cast", "unchecked" }) + @Override + protected void handleSuccess() { + Map> bpsLists = new HashMap>(); + for (IBreakpoint bp : getData()) { + IAdaptable[] bpCategories = fOrganizerVMNode.getOrganizer().getCategories(bp); + if (bpCategories == null || bpCategories.length == 0) { + bpCategories = OtherBreakpointCategory.getCategories(fOrganizerVMNode.getOrganizer()); + } + + for (IAdaptable category : bpCategories) { + List categoryBPs = bpsLists.get(category); + if (categoryBPs == null) { + categoryBPs = new ArrayList(); + bpsLists.put(category, categoryBPs); + } + categoryBPs.add(bp); + } + } + + // Only show the empty containers for the top-level node. + if (fParentPath.getSegmentCount() == 0) { + final IAdaptable[] independentCategories = fOrganizerVMNode.getOrganizer().getCategories(); + if (independentCategories != null) { + for (IAdaptable category : independentCategories) { + if (!bpsLists.containsKey(category)) { + bpsLists.put(category, (List)Collections.EMPTY_LIST); + } + } + } + } + + List vmcs = new ArrayList(bpsLists.size()); + for (Map.Entry> entry : bpsLists.entrySet()) { + List bpsList = entry.getValue(); + IBreakpoint[] bpsArray = bpsList.toArray(new IBreakpoint[bpsList.size()]); + + vmcs.add(createBreakpointOrganizerVMContext(fOrganizerVMNode, entry.getKey(), bpsArray)); + } + Comparator comparator = (Comparator)getPresentationContext().getProperty( + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR); + if (comparator != null) { + Collections.sort(vmcs, comparator); + } + + rm.setData(vmcs); + rm.done(); + } + }); + } + }; + + private final Map fContainerBreakpointsCacheMap = + new HashMap(); + + private DataCache fFilteredBreakpointsCache = new DataCache(getExecutor()) { + @Override + protected void retrieve(org.eclipse.cdt.dsf.concurrent.DataRequestMonitor rm) { + calcFileteredBreakpoints(rm); + } + }; + + public BreakpointVMProvider(AbstractVMAdapter adapter, IPresentationContext context) { + super(adapter, context); + + configureLayout(); + context.addPropertyChangeListener(fPresentationContextListener); + DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(fBreakpointsListener); + } + + @Override + protected IVMModelProxy createModelProxyStrategy(Object rootElement) { + return new BreakpointVMModelProxyStrategy(this, rootElement); + } + + protected IVMNode createBreakpointVMNode() { + return new BreakpointVMNode(this); + } + + /** + * Configures the nodes of this provider. This method may be over-ridden by + * sub classes to create an alternate configuration in this provider. + */ + protected void configureLayout() { + /* + * Create the top level node which provides the anchor starting point. + */ + IRootVMNode rootNode = new RootDMVMNode(this); + + IBreakpointOrganizer[] organizers = (IBreakpointOrganizer[]) + getPresentationContext().getProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS); + + IVMNode parentNode = rootNode; + if (organizers != null) { + for (IBreakpointOrganizer organizer : organizers) { + IVMNode organizerNode = new BreakpointOrganizerVMNode(this, organizer); + addChildNodes(parentNode, new IVMNode[] {organizerNode}); + parentNode = organizerNode; + } + } + + IVMNode bpsNode = createBreakpointVMNode(); + addChildNodes(parentNode, new IVMNode[] {bpsNode}); + + /* + * Let the work know which is the top level node. + */ + setRootNode(rootNode); + } + + + @Override + public void dispose() { + getPresentationContext().removePropertyChangeListener(fPresentationContextListener); + DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(fBreakpointsListener); + super.dispose(); + } + + @Override + public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) { + return null; + } + + @Override + public String getColumnPresentationId(IPresentationContext context, Object element) { + return null; + } + + @Override + public void update(IViewerInputUpdate update) { + IStructuredSelection filterSelection = (IStructuredSelection) + update.getPresentationContext().getProperty(IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION); + IDMContext activeDMContext = null; + if (filterSelection != null) { + if (update.getElement() instanceof IDMVMContext) { + activeDMContext = ((IDMVMContext)update.getElement()).getDMContext(); + } + } + update.setInputElement(new BreakpointVMInput(getRootVMNode(), activeDMContext)); + update.done(); + } + + public void getNestingCategoryBreakpoints(TreePath path, final DataRequestMonitor rm) { + BreakpointOrganizerVMContext nestingOrganizerVmc = null; + while (path.getSegmentCount() > 0) { + if (path.getLastSegment() instanceof BreakpointOrganizerVMContext) { + nestingOrganizerVmc = (BreakpointOrganizerVMContext)path.getLastSegment(); + break; + } + path = path.getParentPath(); + } + if (nestingOrganizerVmc == null) { + getFileteredBreakpoints(rm); + } else { + final BreakpointOrganizerVMContext _nestingOrganizerVmc = nestingOrganizerVmc; + getBreakpointOrganizerVMCs( + (BreakpointOrganizerVMNode)_nestingOrganizerVmc.getVMNode(), path.getParentPath(), + new DataRequestMonitor>(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + int newVmcIdx = getData().indexOf(_nestingOrganizerVmc); + + if (newVmcIdx >= 0) { + rm.setData(getData().get(newVmcIdx).getBreakpoints()); + } else { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Breakpoint category not found", null)); //$NON-NLS-1$ + } + } + rm.done(); + } + }); + } + } + + public void getBreakpointOrganizerVMCs(BreakpointOrganizerVMNode organizerVMNode, TreePath path, + DataRequestMonitor> rm) + { + ContainerBreakpointsCache cache = fContainerBreakpointsCacheMap.get(path); + if (cache == null) { + cache = new ContainerBreakpointsCache(organizerVMNode, path); + fContainerBreakpointsCacheMap.put(path, cache); + } + + cache.request(rm); + } + + + protected BreakpointOrganizerVMContext createBreakpointOrganizerVMContext(BreakpointOrganizerVMNode node, IAdaptable category, IBreakpoint[] breakpoints) { + return new BreakpointOrganizerVMContext(node, category, breakpoints); + } + + + public void getFileteredBreakpoints(final DataRequestMonitor rm) { + fFilteredBreakpointsCache.request(rm); + } + + protected void calcFileteredBreakpoints(DataRequestMonitor rm) { + rm.setData(DebugPlugin.getDefault().getBreakpointManager().getBreakpoints()); + rm.done(); + } + + public void handleEventInExecThread(final Object event) { + getExecutor().execute(new DsfRunnable() { + public void run() { + handleEvent(event); + } + }); + } + + @Override + public void handleEvent(Object event, RequestMonitor rm) { + if (isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) + { + clearNodes(); + configureLayout(); + } + } + super.handleEvent(event, rm); + } + + public static boolean isPresentationContextEvent(Object event) { + return event instanceof PropertyChangeEvent && ((PropertyChangeEvent)event).getSource() instanceof IPresentationContext; + } + + public static boolean isBreakpointOrganizerEvent(Object event) { + return event instanceof PropertyChangeEvent && ((PropertyChangeEvent)event).getSource() instanceof IBreakpointOrganizerDelegate; + } + + private static final int MODEL_DELTA_CHANGE_FLAGS = IModelDelta.STATE | IModelDelta.CONTENT | IModelDelta.ADDED | IModelDelta.REMOVED | IModelDelta.REPLACED | IModelDelta.INSERTED; + + @Override + protected void handleEvent(IVMModelProxy proxyStrategy, Object event, RequestMonitor rm) { + // Before generating a delta, flush the caches. + int deltaFlags = proxyStrategy.getEventDeltaFlags(event); + if ((deltaFlags & MODEL_DELTA_CHANGE_FLAGS) != 0) { + flushCaches(); + } + + super.handleEvent(proxyStrategy, event, rm); + } + + private void flushCaches() { + fFilteredBreakpointsCache.reset(); + for (DataCache cache : fContainerBreakpointsCacheMap.values()) { + cache.reset(); + } + fContainerBreakpointsCacheMap.clear(); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointsChangedEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointsChangedEvent.java new file mode 100644 index 00000000000..23dd0c265be --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/BreakpointsChangedEvent.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import org.eclipse.debug.core.model.IBreakpoint; + +/** + * @since 2.1 + */ +public class BreakpointsChangedEvent { + public enum Type { ADDED, REMOVED, CHANGED }; + + private final Type fType; + private final IBreakpoint[] fBreakpoints; + + public BreakpointsChangedEvent(Type type, IBreakpoint[] breakpoints) { + fType = type; + fBreakpoints = breakpoints; + } + + public Type getType() { + return fType; + } + + public IBreakpoint[] getBreakpoints() { + return fBreakpoints; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/RawBreakpointVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/RawBreakpointVMNode.java new file mode 100644 index 00000000000..a9a33e21c6b --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/breakpoints/RawBreakpointVMNode.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2008 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.cdt.dsf.debug.ui.viewmodel.breakpoints; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate; +import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointUIConstants; +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.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.jface.util.PropertyChangeEvent; + +/** + * + * + * @since 2.1 + */ +public class RawBreakpointVMNode extends AbstractVMNode { + + public RawBreakpointVMNode(IVMProvider provider) { + super(provider); + } + + public void update(final IHasChildrenUpdate[] updates) { + for (final IHasChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setHasChilren(getData().length != 0); + } else { + update.setHasChilren(false); + } + update.done(); + } + }); + } + } + + public void update(final IChildrenCountUpdate[] updates) { + for (final IChildrenCountUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + update.setChildCount(getData().length); + } else { + update.setChildCount(0); + } + update.done(); + } + }); + } + } + + public void update(IChildrenUpdate[] updates) { + for (final IChildrenUpdate update : updates) { + if (!checkUpdate(update)) continue; + ((BreakpointVMProvider)getVMProvider()).getNestingCategoryBreakpoints( + update.getElementPath(), + new ViewerDataRequestMonitor(getExecutor(), update) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + @SuppressWarnings("unchecked") + Comparator comparator = + (Comparator)getVMProvider().getPresentationContext().getProperty( + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR); + if (comparator != null) { + Arrays.sort(getData(), comparator); + } + fillUpdateWithBreakpoints(update, getData()); + } + update.done(); + } + }); + } + } + + private void fillUpdateWithBreakpoints(IChildrenUpdate update, IBreakpoint[] bps) { + int updateIdx = update.getOffset() != -1 ? update.getOffset() : 0; + int endIdx = updateIdx + (update.getLength() != -1 ? update.getLength() : bps.length); + while (updateIdx < endIdx && updateIdx < bps.length) { + update.setChild(bps[updateIdx], updateIdx); + updateIdx++; + } + } + + public int getDeltaFlags(Object event) { + if (event instanceof BreakpointsChangedEvent) { + BreakpointsChangedEvent bpChangedEvent = ((BreakpointsChangedEvent)event); + if (BreakpointsChangedEvent.Type.ADDED.equals(bpChangedEvent.getType())) { + return IModelDelta.CONTENT | IModelDelta.SELECT | IModelDelta.EXPAND; + } + return IModelDelta.CONTENT; + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty())) + { + return IModelDelta.CONTENT; + } else if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) { + return IModelDelta.EXPAND | IModelDelta.CONTENT; + } + } + return 0; + } + + public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor rm) { + if (event instanceof BreakpointsChangedEvent) { + BreakpointsChangedEvent bpChangedEvent = ((BreakpointsChangedEvent)event); + if (BreakpointsChangedEvent.Type.ADDED.equals(bpChangedEvent.getType())) { + buildBreakpointAddedDelta(bpChangedEvent, parent, nodeOffset, rm); + // Do not call rm.done() in this method! + return; + } else { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } + } + else if (BreakpointVMProvider.isPresentationContextEvent(event)) { + PropertyChangeEvent propertyEvent = (PropertyChangeEvent)event; + if (IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION.equals(propertyEvent.getProperty()) || + IBreakpointUIConstants.PROP_BREAKPOINTS_ELEMENT_COMPARATOR.equals(propertyEvent.getProperty())) + { + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT); + } else if (IBreakpointUIConstants.PROP_BREAKPOINTS_ORGANIZERS.equals(propertyEvent.getProperty())) { + parent.setFlags(parent.getFlags() | IModelDelta.EXPAND | IModelDelta.CONTENT); + } + } + + rm.done(); + } + + private void buildBreakpointAddedDelta(final BreakpointsChangedEvent event, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) { + getVMProvider().updateNode(this, new VMChildrenUpdate( + parent, getVMProvider().getPresentationContext(), -1, -1, + new DataRequestMonitor>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + for (int i = 0; i < event.getBreakpoints().length; i++) { + int bpIndex = getData().indexOf(event.getBreakpoints()[i]); + if (bpIndex >= 0) { + // Select only the first breakpoint that was added + if (i == 0) { + parent.addNode(getData().get(bpIndex), bpIndex, IModelDelta.SELECT); + } + // For all other added breakpoints, expand the parent. + parent.setFlags(parent.getFlags() | IModelDelta.CONTENT | IModelDelta.EXPAND); + } + } + rm.done(); + } + })); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java index 2c02ff9f70f..66c3599b3af 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java @@ -387,13 +387,12 @@ public class DefaultVMContentProviderStrategy implements IElementContentProvider /** * Convenience method which checks whether given layout node is a node that * is configured in this ViewModelProvider. + *
+ * Note: isOurNode() will also return true if the given node was previously + * configured in the VM provider but was later disposed. */ private boolean isOurNode(IVMNode node) { - for (IVMNode nodeToSearch : getVMProvider().getAllVMNodes()) { - if (nodeToSearch.equals(node)) - return true; - } - return false; + return node.getVMProvider() == getVMProvider(); } } diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java index 9870b8f5dcd..2058141d6df 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java @@ -27,6 +27,7 @@ import org.eclipse.core.runtime.SafeRunner; import org.eclipse.debug.internal.ui.DebugUIPlugin; import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener; 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.ModelDelta; @@ -72,10 +73,17 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { } public boolean isDeltaEvent(Object event) { + return getEventDeltaFlags(event) != IModelDelta.NO_CHANGE; + } + + public int getEventDeltaFlags(Object event) { IRootVMNode rootNode = getVMProvider().getRootVMNode(); - return rootNode != null && - rootNode.isDeltaEvent(getRootElement(), event) && - getDeltaFlags(rootNode, null, event) != IModelDelta.NO_CHANGE; + if (rootNode != null && + rootNode.isDeltaEvent(getRootElement(), event)) + { + return getDeltaFlags(rootNode, null, event); + } + return IModelDelta.NO_CHANGE; } @@ -346,7 +354,9 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { new RequestMonitor(getVMProvider().getExecutor(), rm) { @Override protected void handleSuccess() { - rm.setData(viewRootDelta); + // Get rid of redundant CONTENT and STATE flags in delta and prune + // nodes without flags + rm.setData(pruneDelta((VMDelta)viewRootDelta)); rm.done(); } }); @@ -354,6 +364,25 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { }); } + protected VMDelta pruneDelta(VMDelta delta) { + delta.accept(new IModelDeltaVisitor() { + public boolean visit(IModelDelta deltaNode, int depth) { + if ((deltaNode.getFlags() & (IModelDelta.CONTENT | IModelDelta.STATE)) != 0) { + VMDelta parent = (VMDelta)deltaNode.getParentDelta(); + while (parent != null) { + if ((parent.getFlags() & IModelDelta.CONTENT) != 0) { + ((VMDelta)deltaNode).setFlags(deltaNode.getFlags() & ~(IModelDelta.CONTENT | IModelDelta.STATE)); + break; + } + parent = parent.getParentDelta(); + } + } + return true; + } + }); + return delta; + } + /** * Base implementation that handles calling child nodes to build * the model delta. This method delegates to two other methods: diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java index 9f83281cc96..74026d46f2d 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java @@ -35,7 +35,11 @@ public interface IVMModelProxy extends IModelProxy { /** * Returns whether the given event applies to the root element and the - * nodes in this model proxy. + * nodes in this model proxy. + *

+ * This method is the equivalent of calling + * getEventDeltaFlags(event) != IModelDelta.NO_CHANGE . + *

*/ public boolean isDeltaEvent(Object event); @@ -71,4 +75,15 @@ public interface IVMModelProxy extends IModelProxy { * @since 2.0 */ public TreePath getRootPath(); + + /** + * Returns the delta flags associated with this event. This method is + * + * @param event + * @return + * + * @since 2.1 + */ + public int getEventDeltaFlags(Object event); + } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataCache.java new file mode 100644 index 00000000000..113fb29f990 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataCache.java @@ -0,0 +1,200 @@ +package org.eclipse.cdt.dsf.concurrent; + +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Executor; + +import org.eclipse.cdt.dsf.internal.DsfPlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +/** + * A general purpose cache, which caches the result of a single request. + * Sub classes need to implement {@link #retrieve(DataRequestMonitor)} to fetch + * data from the data source. Clients are responsible for calling + * {@link #disable()} and {@link #reset()} to manage the state of the cache in + * response to events from the data source. + *

+ * This cache requires an executor to use. The executor is used to synchronize + * access to the cache state and data. + *

+ * @since 2.1 + */ +@ConfinedToDsfExecutor("fExecutor") +public abstract class DataCache { + + final private Executor fExecutor; + + private boolean fValid; + + protected DataRequestMonitor fRm; + private V fData; + private IStatus fStatus; + + private List> fWaitingList = new LinkedList>(); + + public DataCache(Executor executor) { + fExecutor = executor; + } + + + /** + * Sub-classes should override this method to retrieve the cache data + * from its source. + * + * @param rm Request monitor for completion of data retrieval. + */ + protected abstract void retrieve(DataRequestMonitor rm); + + /** + * Returns true if the cache is currently valid. I.e. + * whether the cache can return a value immediately without first + * retrieving it from the data source. + */ + public boolean isValid() { + return fValid; + } + + /** + * Returns true if the cache is currently waiting for data + * from the data source. + */ + public boolean isPending() { + return fRm != null; + } + + /** + * Returns the current data value held by this cache. Clients should first + * call isValid() to determine if the data is up to date. + */ + public V getData() { + return fData; + } + + /** + * Returns the status of the source request held by this cache. Clients + * should first call isValid() to determine if the data is up to date. + */ + public IStatus getStatus() { + return fStatus; + } + + /** + * Request data from the cache. The cache is valid, it will complete the + * request immediately, otherwise data will first be retrieved from the + * source. + * @param req + */ + public void request(final DataRequestMonitor rm) { + if (!fValid) { + boolean first = fWaitingList.isEmpty(); + fWaitingList.add(rm); + if(first) { + fRm = new DataRequestMonitor(fExecutor, null) { + @Override + protected void handleCompleted() { + if (!isCanceled()) { + fValid = true; + fRm = null; + set(getData(), getStatus()); + } + } + }; + retrieve(fRm); + } + } else { + rm.setData(fData); + rm.setStatus(fStatus); + rm.done(); + } + } + + + private void set(V data, IStatus status) { + fData = data; + fStatus = status; + List> waitingList = fWaitingList; + fWaitingList = new LinkedList>(); + + for (DataRequestMonitor rm : waitingList) { + rm.setData(data); + rm.setStatus(status); + rm.done(); + } + } + + /** + * Resets the cache with a data value null and an error + * status with code {@link IDsfStatusConstants#INVALID_STATE}. + * + * @see #reset(Object, IStatus) + */ + public void reset() { + reset(null, new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Cache reset", null)); //$NON-NLS-1$ + } + + /** + * Resets the cache with given data and status. Resetting the cache + * forces the cache to be invalid and cancels any current pending requests + * from data source. + *

+ * This method should be called when the data source has issued an event + * indicating that the source data has changed but data may still be + * retrieved. Clients may need to re-request data following cache reset. + *

+ * @param data The data that should be returned to any clients currently + * waiting for cache data. + * @status The status that should be returned to any clients currently + * waiting for cache data. + */ + public void reset(V data, IStatus status) { + fValid = false; + if (fRm != null) { + fRm.cancel(); + fRm = null; + } + set(data, status); + } + + /** + * Disables the cache with a data value null and an error + * status with code {@link IDsfStatusConstants#INVALID_STATE}. + * + * @see #disable(Object, IStatus) + */ + public void disable() { + disable(null, new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Cache disable", null)); //$NON-NLS-1$ + } + + /** + * Resets the cache then disables it. When a cache is disabled it means + * that it is valid and requests to the data source will not be sent. + *

+ * This method should be called when the data source has issued an event + * indicating that the source data has changed and future requests for + * data will return the given data and status. Once the source data + * becomes available again, clients should call {@link #reset()}. + *

+ * @param data The data that should be returned to any clients waiting for + * cache data and for clients requesting data until the cache is reset again. + * @status The status that should be returned to any clients waiting for + * cache data and for clients requesting data until the cache is reset again. + * + * @see #reset(Object, IStatus) + */ + public void disable(V data, IStatus status) { + reset(data, status); + fValid = true; + } +}