Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Piech2010-09-24 18:58:49 +0000
committerPawel Piech2010-09-24 18:58:49 +0000
commit4d3edd80a2216db9e44594bc2b001410392147f4 (patch)
treeaead2d9e55ec05d9edd459f5aaddd2f104d210ed
parentde6322ba9cc997cda01596d337f44c00cf636183 (diff)
downloadorg.eclipse.cdt-4d3edd80a2216db9e44594bc2b001410392147f4.tar.gz
org.eclipse.cdt-4d3edd80a2216db9e44594bc2b001410392147f4.tar.xz
org.eclipse.cdt-4d3edd80a2216db9e44594bc2b001410392147f4.zip
Bug 321932 - [update policy] When in manual mode, switching number format should still show value in other formats if value is cached.
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java4
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelForeground.java60
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelText.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/MessagesForDebugVM.properties2
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueLabelText.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueRetriever.java608
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueVMUtil.java105
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java71
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java67
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/DebugManualUpdatePolicy.java73
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java76
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java3
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdateListener.java30
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java1
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.properties3
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesBasedLabelProvider.java75
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesUpdateStatus.java218
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMDelegatingPropertiesUpdate.java19
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMPropertiesUpdate.java38
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java206
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICacheEntry.java90
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension2.java30
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicyExtension.java33
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/IViewerUpdatesListenerConstants.java51
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ServiceEventWaitor.java25
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ViewerUpdatesListener.java644
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTest1.java141
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTestBase.java128
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/DummyFormattedValueService.java58
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValueTests.java372
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValuesListener.java200
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/IFormattedValuesListener.java22
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/ITestModelUpdatesListenerConstants.java40
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/JFaceViewerFormattedValueTests.java38
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/PerformanceTests.java32
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestElementVMContext.java17
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModel.java293
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelCachingVMProvider.java113
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelDMVMNode.java252
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelUpdatesListener.java451
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMAdapter.java2
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMNode.java22
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMProvider.java3
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/VirtualViewerPerformanceTests.java2
44 files changed, 3953 insertions, 841 deletions
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java
index 5b7e54bf394..3f6fd2c8060 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java
@@ -323,7 +323,7 @@ public class NumberFormatDetailPane implements IDetailPane2, IAdaptable, IProper
IDebugVMConstants.PROP_FORMATTED_VALUE_AVAILABLE_FORMATS);
if (formats != null) {
for (String format : formats) {
- properties.add(FormattedValueVMUtil.getPropertyForFormatId(format));
+ properties.add(FormattedValueVMUtil.getPropertyForFormatId(format, null));
}
}
@@ -341,7 +341,7 @@ public class NumberFormatDetailPane implements IDetailPane2, IAdaptable, IProper
finalResult.append(SPACES);
finalResult.append( FormattedValueVMUtil.getFormatLabel(formatId) );
finalResult.append(FORMAT_SEPARATOR);
- finalResult.append( getData().get(FormattedValueVMUtil.getPropertyForFormatId(formatId)) );
+ finalResult.append( getData().get(FormattedValueVMUtil.getPropertyForFormatId(formatId, null)) );
if ( i < formats.length + 1 ) {
finalResult.append(CRLF);
}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelForeground.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelForeground.java
new file mode 100644
index 00000000000..a7e80fc7ba8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelForeground.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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;
+
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelForeground;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.preference.JFacePreferences;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * Label attribute that sets the label color to the standard workbench
+ * error color. The color is activated when the property update contains
+ * a status with error codes: {@link IDsfStatusConstants#INTERNAL_ERROR},
+ * {@link IDsfStatusConstants#REQUEST_FAILED}, or
+ * {@link IDsfStatusConstants#NOT_SUPPORTED}.
+ *
+ * @since 2.2
+ */
+public class ErrorLabelForeground extends LabelForeground {
+
+ private static final RGB DEFAULT_COLOR = new RGB(255, 0, 0);
+
+ public ErrorLabelForeground() {
+ super(DEFAULT_COLOR);
+ }
+
+ @Override
+ public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
+ return !status.isOK() && status.getCode() >= IDsfStatusConstants.NOT_SUPPORTED;
+ }
+
+ @Override
+ public RGB getForeground() {
+ IThemeManager themeManager = PlatformUI.getWorkbench().getThemeManager();
+ ITheme currentTheme = themeManager.getCurrentTheme();
+
+ ColorRegistry colorRegistry = currentTheme.getColorRegistry();
+
+ Color color = colorRegistry.get(JFacePreferences.ERROR_COLOR);
+
+ if (color != null) {
+ return color.getRGB();
+ }
+ return super.getForeground();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelText.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelText.java
index 09e0e7ead1c..0dfec709a1e 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelText.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/ErrorLabelText.java
@@ -16,6 +16,9 @@ import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.core.runtime.IStatus;
/**
+ * Label attribute that fills in the text of an error status into the label
+ * column.
+ *
* @since 2.0
*/
public class ErrorLabelText extends LabelText {
@@ -23,16 +26,14 @@ public class ErrorLabelText extends LabelText {
protected final static String PROP_ERROR_MESSAGE = "error_message"; //$NON-NLS-1$
public ErrorLabelText() {
- this(
- MessagesForDebugVM.ErrorLabelText__text_format,
- new String[] { PROP_ERROR_MESSAGE });
+ this(MessagesForDebugVM.ErrorLabelText__text_format, new String[] {});
}
public ErrorLabelText(String formatPattern, String[] propertyNames) {
- super(formatPattern, addActiveFormatPropertyNames(propertyNames));
+ super(formatPattern, addErrorMessageProperty(propertyNames));
}
- private static String[] addActiveFormatPropertyNames(String[] propertyNames) {
+ private static String[] addErrorMessageProperty(String[] propertyNames) {
String[] newPropertyNames = new String[propertyNames.length + 1];
System.arraycopy(propertyNames, 0, newPropertyNames, 0, propertyNames.length);
newPropertyNames[propertyNames.length + 0] = PROP_ERROR_MESSAGE;
@@ -42,12 +43,24 @@ public class ErrorLabelText extends LabelText {
@Override
protected Object getPropertyValue(String propertyName, IStatus status, Map<String, Object> properties) {
if (PROP_ERROR_MESSAGE.equals(propertyName)) {
- return status.getMessage().replaceAll(
- "\n", MessagesForDebugVM.ErrorLabelText_Error_message__text_page_break_delimiter); //$NON-NLS-1$
+ if (status.getChildren().length < 2) {
+ return replaceNewlines(status.getMessage());
+ } else {
+ StringBuffer buf = new StringBuffer( status.getMessage() );
+ for (IStatus childStatus : status.getChildren()) {
+ buf.append(MessagesForDebugVM.ErrorLabelText_Error_message__text_page_break_delimiter);
+ buf.append( replaceNewlines(childStatus.getMessage()) );
+ }
+ return buf.toString();
+ }
}
return super.getPropertyValue(propertyName, status, properties);
}
+ private String replaceNewlines(String message) {
+ return message.replaceAll("\n", MessagesForDebugVM.ErrorLabelText_Error_message__text_page_break_delimiter); //$NON-NLS-1$
+ }
+
@Override
public boolean checkProperty(String propertyName, IStatus status, Map<String,Object> properties) {
if (PROP_ERROR_MESSAGE.equals(propertyName)) {
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/MessagesForDebugVM.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/MessagesForDebugVM.properties
index d043fac2d3e..741813118c0 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/MessagesForDebugVM.properties
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/MessagesForDebugVM.properties
@@ -14,4 +14,4 @@ ErrorLabelText__text_format=Error: {0}
# If multiple errors are shown in the combined error message, this
# string is used as a separator between them.
-ErrorLabelText_Error_message__text_page_break_delimiter= \ \ No newline at end of file
+ErrorLabelText_Error_message__text_page_break_delimiter= \\ \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueLabelText.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueLabelText.java
index 77fd4d9fc2c..16963873297 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueLabelText.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueLabelText.java
@@ -10,45 +10,62 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat;
-import com.ibm.icu.text.MessageFormat;
import java.util.Map;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.core.runtime.IStatus;
+import com.ibm.icu.text.MessageFormat;
+
/**
- *
+ * Label attribute that fills in the formatted value text using the active
+ * number format for the view.
*
* @since 2.0
*/
public class FormattedValueLabelText extends LabelText {
+ private final String fPropertyPrefix;
+ private final String PROP_ACTIVE_FORMAT;
+ private final String PROP_ACTIVE_FORMAT_VALUE;
+
public FormattedValueLabelText() {
- this(
- MessagesForNumberFormat.FormattedValueLabelText__text_format,
- new String[] { IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE });
+ this(MessagesForNumberFormat.FormattedValueLabelText__text_format, new String[0], ""); //$NON-NLS-1$
+ }
+
+ public FormattedValueLabelText(String popertyPrefix) {
+ this(MessagesForNumberFormat.FormattedValueLabelText__text_format, new String[0], popertyPrefix);
}
public FormattedValueLabelText(String formatPattern, String[] propertyNames) {
- super(formatPattern, addActiveFormatPropertyNames(propertyNames));
+ this(formatPattern, propertyNames, ""); //$NON-NLS-1$
}
-
- private static String[] addActiveFormatPropertyNames(String[] propertyNames) {
- String[] newPropertyNames = new String[propertyNames.length + 2];
+
+ public FormattedValueLabelText(String formatPattern, String[] propertyNames, String propertyPrefix) {
+ super(formatPattern, addActiveFormatPropertyNames(propertyNames, propertyPrefix));
+ fPropertyPrefix = propertyPrefix;
+ PROP_ACTIVE_FORMAT = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT).intern();
+ PROP_ACTIVE_FORMAT_VALUE = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).intern();
+ }
+
+ private static String[] addActiveFormatPropertyNames(String[] propertyNames, String prefix) {
+ String[] newPropertyNames = new String[propertyNames.length + 4];
System.arraycopy(propertyNames, 0, newPropertyNames, 0, propertyNames.length);
- newPropertyNames[propertyNames.length + 0] = IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT;
- newPropertyNames[propertyNames.length + 1] = IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE;
+ newPropertyNames[propertyNames.length + 0] = (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).intern();
+ newPropertyNames[propertyNames.length + 1] = (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT).intern();
+ newPropertyNames[propertyNames.length + 2] = (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_AVAILABLE_FORMATS).intern();
+ newPropertyNames[propertyNames.length + 3] = IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE;
return newPropertyNames;
}
@Override
protected Object getPropertyValue(String propertyName, IStatus status, Map<String, Object> properties) {
// If the format is not the same as the preferred format, include it in the value string.
- if ( IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE.equals(propertyName) ) {
- Object activeFormat = properties.get(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT);
+ if ( PROP_ACTIVE_FORMAT_VALUE.equals(propertyName) ) {
+ Object activeFormat = properties.get(PROP_ACTIVE_FORMAT);
Object preferredFormat = properties.get(IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE);
- Object value = properties.get(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE);
+ Object value = properties.get(PROP_ACTIVE_FORMAT_VALUE);
if (value != null && activeFormat != null && !activeFormat.equals(preferredFormat)) {
return MessageFormat.format(
MessagesForNumberFormat.FormattedValueLabelText__Value__text_format,
@@ -63,8 +80,8 @@ public class FormattedValueLabelText extends LabelText {
@Override
public boolean isEnabled(IStatus status, Map<String, Object> properties) {
for (String property : getPropertyNames()) {
- if ( IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT.equals(property) ||
- IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE.equals(property) )
+ if ( PROP_ACTIVE_FORMAT.equals(property) ||
+ IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE.equals(property) )
{
continue;
}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueRetriever.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueRetriever.java
new file mode 100644
index 00000000000..f9f389c6885
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueRetriever.java
@@ -0,0 +1,608 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.numberformat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+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.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesUpdateStatus;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICacheEntry;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProviderExtension2;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicyExtension;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * A helper class for View Model Node implementations that support elements
+ * to be formatted using different number formats. This object can be
+ * instantiated by a VM node to retrieve formatted values from a given service
+ * using given DMC type.
+ * <p>
+ * Note: This class is a replacement for the {@link FormattedValueVMUtil#updateFormattedValues(IPropertiesUpdate[], IFormattedValues, Class, RequestMonitor)}
+ * static method. This new implementation retrieves cached values if they are
+ * available in the VM Cache.
+ * </p>
+ *
+ * @see FormattedValueVMUtil
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider
+ * @see org.eclipse.cdt.dsf.debug.service.IFormattedValues
+ *
+ * @since 2.0
+ */
+public class FormattedValueRetriever {
+
+ private final IVMNode fNode;
+ private final ICachingVMProviderExtension2 fCache;
+ private final ServiceTracker fServiceTracker;
+ private final Class<? extends IFormattedDataDMContext> fDmcType;
+ private final String fPropertyPrefix;
+
+ private final String PROP_AVAILABLE_FORMATS;
+ private final String PROP_ACTIVE_FORMAT;
+ private final String PROP_ACTIVE_FORMAT_VALUE;
+ private final String PROP_BASE;
+
+ public FormattedValueRetriever(IVMNode node, DsfSession session, Class<?> serviceClass, Class<? extends IFormattedDataDMContext> dmcType) {
+ this(node, createFilter(session, serviceClass), dmcType, null);
+ }
+
+ public FormattedValueRetriever(IVMNode node, DsfSession session, Class<?> serviceClass, Class<? extends IFormattedDataDMContext> dmcType, String propertyPrefix) {
+ this(node, createFilter(session, serviceClass), dmcType, propertyPrefix);
+ }
+
+ public FormattedValueRetriever(IVMNode node, Filter filter, Class<? extends IFormattedDataDMContext> dmcType, String propertyPrefix) {
+ fNode = node;
+ fCache = (ICachingVMProviderExtension2)node.getVMProvider();
+ fServiceTracker = new ServiceTracker(DsfUIPlugin.getBundleContext(), filter, null);
+ fServiceTracker.open();
+ fDmcType = dmcType;
+ if (propertyPrefix == null) {
+ propertyPrefix = ""; //$NON-NLS-1$
+ }
+ fPropertyPrefix = propertyPrefix;
+ PROP_AVAILABLE_FORMATS = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_AVAILABLE_FORMATS).intern();
+ PROP_ACTIVE_FORMAT = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT).intern();
+ PROP_ACTIVE_FORMAT_VALUE = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).intern();
+ PROP_BASE = (fPropertyPrefix + IDebugVMConstants.PROP_FORMATTED_VALUE_BASE).intern();
+ }
+
+ /**
+ * Creates an OSGI service filter for the given service type in a given
+ * DSF session.
+ */
+ private static Filter createFilter(DsfSession session, Class<?> serviceClass) {
+ try {
+ return DsfUIPlugin.getBundleContext().createFilter( DsfServices.createServiceFilter(serviceClass, session.getId()) );
+ } catch (InvalidSyntaxException e) {
+ throw new RuntimeException("Unable to create service filter for " + serviceClass, e); //$NON-NLS-1$
+ }
+ }
+
+ public void dispose() {
+ fServiceTracker.close();
+ }
+
+ /**
+ * This method fills in the formatted value properties in the given array
+ * of property update objects using data retrieved from the given
+ * formatted values service.
+ * <p>
+ * Note: The node parameter must return a <code>ICachingVMProviderExtension2</code>
+ * through its {@link IVMNode#getVMProvider()} method.
+ *
+ * @param node This method also takes an <code>IVMNode</code> parameter
+ * which allows for retrieving the format value data from the View Model
+ * cache. If the needed value property is cached already, the cached
+ * value will be used otherwise the properties will be retrieved from the
+ * service.
+ *
+ * @param updates The array of updates to fill in information to. This
+ * update is used to retrieve the data model context and to write the
+ * properties into. Implementation will not directly mark these updates
+ * complete, but contribute towards that end by marking [monitor] complete.
+ *
+ * @param service The service to be used to retrieve the values from.
+ *
+ * @param dmcType The class type of the data model context. Some updates
+ * can contain multiple formatted data data model contexts, and this
+ * method assures that there is no ambiguity in which context should be
+ * used.
+ *
+ * @param rm Request monitor used to signal completion of work
+ *
+ * @since 2.2
+ */
+ @ConfinedToDsfExecutor("node.getExecutor()")
+ public void update(final IPropertiesUpdate updates[], final RequestMonitor rm)
+ {
+ final Map<IPropertiesUpdate, String[]> cachedAvailableFormatsMap = calcCachedAvailableFormatsMap(updates);
+ if (cachedAvailableFormatsMap != null && cachedAvailableFormatsMap.size() == updates.length) {
+ // All updates were satisfied by the cache.
+ doUpdateWithAvailableFormats(updates, cachedAvailableFormatsMap, rm);
+ } else {
+ final IFormattedValues service = (IFormattedValues)fServiceTracker.getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Service not available " + fServiceTracker, null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ try {
+ service.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ retrieveAvailableFormats(
+ calcOutstandingAvailableFormatsUpdates(updates, cachedAvailableFormatsMap),
+ new DataRequestMonitor<Map<IPropertiesUpdate, String[]>>(fNode.getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ Map<IPropertiesUpdate, String[]> availableFormatsMap;
+ if (cachedAvailableFormatsMap != null) {
+ availableFormatsMap = cachedAvailableFormatsMap;
+ availableFormatsMap.putAll(getData());
+ } else {
+ availableFormatsMap = getData();
+ }
+ // Retrieve the formatted values now that we have the available formats (where needed).
+ // Note that we are passing off responsibility of our parent monitor
+ doUpdateWithAvailableFormats(updates, availableFormatsMap, rm);
+ }
+ });
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Service executor shut down " + service.getExecutor(), e)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ }
+
+ /**
+ * Retrieves the <code>PROP_FORMATTED_VALUE_AVAILABLE_FORMATS</code>
+ * property for each update and returns it in a map. The returned
+ * map may be <code>null</code> if no cache data is available.
+ *
+ * @since 2.2
+ */
+ private Map<IPropertiesUpdate, String[]> calcCachedAvailableFormatsMap(IPropertiesUpdate updates[]) {
+ Map<IPropertiesUpdate, String[]> cachedAvailableFormatsMap = null; // delay creating map till needed
+ for (IPropertiesUpdate update : updates) {
+ ICacheEntry cacheEntry = fCache.getCacheEntry(fNode, update.getViewerInput(), update.getElementPath());
+ if (cacheEntry != null && cacheEntry.getProperties() != null) {
+ String[] availableFormats = (String[])
+ cacheEntry.getProperties().get(PROP_AVAILABLE_FORMATS);
+ // Add the cached entry to the cached map even if its null. This will help keep track
+ // of whether we need to call the service for data.
+ if (availableFormats != null || !isAvailableFormatsPropertyNeeded(update)) {
+ if (cachedAvailableFormatsMap == null) {
+ cachedAvailableFormatsMap = new HashMap<IPropertiesUpdate, String[]>(updates.length * 4/3);
+ }
+ cachedAvailableFormatsMap.put(update, availableFormats);
+ continue;
+ }
+ }
+ }
+ return cachedAvailableFormatsMap;
+ }
+
+ /**
+ * Generates a list of updates which still need the
+ * <code>PROP_FORMATTED_VALUE_AVAILABLE_FORMATS</code> property.
+ *
+ * @since 2.2
+ */
+ private List<IPropertiesUpdate> calcOutstandingAvailableFormatsUpdates(IPropertiesUpdate[] updates, Map<IPropertiesUpdate, String[]> cachedAvailableFormatsMap) {
+ if (cachedAvailableFormatsMap != null) {
+ List<IPropertiesUpdate> outstandingUpdates = new ArrayList<IPropertiesUpdate>(updates.length - cachedAvailableFormatsMap.size());
+ for (IPropertiesUpdate update : updates) {
+ if (!cachedAvailableFormatsMap.containsKey(update)) {
+ outstandingUpdates.add(update);
+ }
+ }
+ return outstandingUpdates;
+ } else {
+ return Arrays.asList(updates);
+ }
+ }
+
+ /**
+ * Method to retrieve available formats for each update's element (if
+ * needed). The result is returned in a map and in the
+ * update object (if requested).
+ * <p>
+ * Note that we use a synchronized map because it's updated by a request
+ * monitor with an ImmediateExecutor.
+ *
+ * @since 2.2
+ */
+ @ConfinedToDsfExecutor("service.getExecutor()")
+ private void retrieveAvailableFormats(
+ final List<IPropertiesUpdate> updates,
+ final DataRequestMonitor<Map<IPropertiesUpdate, String[]>> rm)
+ {
+ IFormattedValues service = (IFormattedValues)fServiceTracker.getService();
+ assert service.getExecutor().isInExecutorThread();
+
+ final Map<IPropertiesUpdate, String[]> availableFormats = Collections.synchronizedMap(new HashMap<IPropertiesUpdate, String[]>(updates.size() * 4/3));
+ rm.setData(availableFormats);
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(service.getExecutor(), rm);
+ int count = 0;
+
+ for (final IPropertiesUpdate update : updates) {
+
+ if (!isAvailableFormatsPropertyNeeded(update)) {
+ continue;
+ }
+
+ IFormattedDataDMContext dmc = getFormattedDataDMContext(update);
+ if (dmc == null) {
+ continue;
+ }
+
+ service.getAvailableFormats(
+ dmc,
+ new ViewerDataRequestMonitor<String[]>(ImmediateExecutor.getInstance(), update) {
+ /**
+ * Note we don't mark the update object done, and we
+ * avoid calling our base implementation so that it
+ * doesn't either. The completion of this request is
+ * just a step in servicing the update.
+ */
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ // Set the result (available formats) into the update object if it was requested
+ if (update.getProperties().contains(PROP_AVAILABLE_FORMATS)) {
+ update.setProperty(PROP_AVAILABLE_FORMATS, getData());
+ }
+
+ if (getData().length != 0) {
+ // also add it to the map; we'll need to access it when querying the element's value.
+ availableFormats.put(update, getData());
+ } else {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "No number formats available for " + update.getElement(), null)); //$NON-NLS-1$
+ }
+ } else {
+ update.setStatus(getStatus());
+ }
+ countingRm.done();
+ }
+ });
+ count++;
+ }
+ countingRm.setDoneCount(count);
+
+ }
+
+ /**
+ * This method continues retrieving formatted value properties. It is
+ * called once the available formats are calculated for each requested
+ * update.
+ *
+ * @param availableFormatsMap Prior to calling this method, the caller
+ * queries (where necessary) the formats supported by the element in each
+ * update, and it puts that information in this map. If an entry in
+ * [updates] does not appear in this map, it means that its view-model
+ * element doesn't support any formats (very unlikely), or that the
+ * available formats aren't necessary to service the properties specified
+ * in the update
+ *
+ * @since 2.2
+ */
+ @ConfinedToDsfExecutor("fNode.getExecutor()")
+ private void doUpdateWithAvailableFormats(
+ IPropertiesUpdate updates[],
+ final Map<IPropertiesUpdate, String[]> availableFormatsMap,
+ final RequestMonitor rm)
+ {
+ final List<IPropertiesUpdate> outstandingUpdates = new ArrayList<IPropertiesUpdate>(updates.length);
+ final Map<IPropertiesUpdate, List<String>> requestedFormatsMap = new HashMap<IPropertiesUpdate, List<String>>(updates.length * 4 / 3);
+ final Map<IPropertiesUpdate, String> activeFormatsMap = new HashMap<IPropertiesUpdate, String>(updates.length * 4 / 3);
+
+ for (final IPropertiesUpdate update : updates) {
+ String preferredFormat = FormattedValueVMUtil.getPreferredFormat(update.getPresentationContext());
+ if (update.getProperties().contains(IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE)) {
+ update.setProperty(IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, preferredFormat);
+ }
+
+ final String activeFormat = calcActiveFormat(update, preferredFormat, availableFormatsMap);
+
+ if (update.getProperties().contains(PROP_ACTIVE_FORMAT)) {
+ assert activeFormat != null : "Our caller should have provided the available formats if this property was specified; given available formats, an 'active' nomination is guaranteed."; //$NON-NLS-1$
+ update.setProperty(PROP_ACTIVE_FORMAT, activeFormat);
+ }
+ List<String> requestedFormats = calcRequestedFormats(update, activeFormat, availableFormatsMap.get(update));
+
+ ICacheEntry cacheEntry = fCache.getCacheEntry(fNode, update.getViewerInput(), update.getElementPath());
+ if (cacheEntry != null && cacheEntry.getProperties() != null) {
+ IVMUpdatePolicyExtension updatePolicy = getVMUpdatePolicyExtension();
+ Iterator<String> itr = requestedFormats.iterator();
+ while (itr.hasNext()) {
+ String format = itr.next();
+ String formatProperty = FormattedValueVMUtil.getPropertyForFormatId(format, fPropertyPrefix);
+ Object value = cacheEntry.getProperties().get(formatProperty);
+ if (value != null || !canUpdateProperty(cacheEntry, updatePolicy, formatProperty)) {
+ itr.remove();
+ setUpdateFormatProperty(update, activeFormat, format, value);
+ }
+ }
+ }
+
+ if (!requestedFormats.isEmpty()) {
+ outstandingUpdates.add(update);
+ requestedFormatsMap.put(update, requestedFormats);
+ activeFormatsMap.put(update, activeFormat);
+ }
+ }
+ final IFormattedValues service = (IFormattedValues)fServiceTracker.getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Service not available " + fServiceTracker, null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ try {
+ service.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ doUpdateWithRequestedFormats(outstandingUpdates, requestedFormatsMap, activeFormatsMap, rm);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Service executor shut down " + service.getExecutor(), e)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ private IVMUpdatePolicyExtension getVMUpdatePolicyExtension() {
+ if( fCache.getActiveUpdatePolicy() instanceof IVMUpdatePolicyExtension) {
+ return (IVMUpdatePolicyExtension)fCache.getActiveUpdatePolicy();
+ }
+ return null;
+ }
+
+ private static boolean canUpdateProperty(ICacheEntry entry, IVMUpdatePolicyExtension updatePolicy, String property) {
+ return !entry.isDirty() || (updatePolicy != null && updatePolicy.canUpdateDirtyProperty(entry, property));
+ }
+
+ /**
+ * Retrieves the specified formatted values from the service.
+ *
+ * @param requestedFormatsMap Map containing the formats to be retrieved
+ * and filled in for each given update.
+ * @param activeFormatsMap Map containing the active format for each given
+ * update. The active format value needs to be set in the update using the
+ * special property <code>PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE</code>.
+ *
+ * @since 2.2
+ */
+ @ConfinedToDsfExecutor("service.getExecutor()")
+ private void doUpdateWithRequestedFormats(
+ List<IPropertiesUpdate> updates,
+ final Map<IPropertiesUpdate, List<String>> requestedFormatsMap,
+ final Map<IPropertiesUpdate, String> activeFormatsMap,
+ final RequestMonitor monitor)
+ {
+ IFormattedValues service = (IFormattedValues)fServiceTracker.getService();
+ assert service.getExecutor().isInExecutorThread();
+
+ // Use a single counting RM for all the requested formats for each update.
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), monitor);
+ int count = 0;
+
+ for (final IPropertiesUpdate update : updates) {
+ IFormattedDataDMContext dmc = getFormattedDataDMContext(update);
+ if (dmc == null) {
+ continue;
+ }
+
+ List<String> requestedFormats = requestedFormatsMap.get(update);
+ for (String requestedFormat : requestedFormats) {
+ final FormattedValueDMContext formattedValueDmc = service.getFormattedValueContext(dmc, requestedFormat);
+ service.getFormattedExpressionValue(
+ formattedValueDmc,
+ // Here also use the ViewerDataRequestMonitor in order to propagate the update's cancel request.
+ // However, when operation is complete, call the counting RM's done().
+ // Use an immediate executor to avoid the possibility of a rejected execution exception.
+ new ViewerDataRequestMonitor<FormattedValueDMData>(ImmediateExecutor.getInstance(), update) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ setUpdateFormatProperty(
+ update,
+ activeFormatsMap.get(update),
+ formattedValueDmc.getFormatID(),
+ getData().getFormattedValue());
+ } else {
+ update.setStatus(getStatus());
+ }
+ // Note: we must not call the update's done method, instead call counting RM done.
+ countingRm.done();
+
+ };
+ });
+ count++;
+ }
+ }
+ countingRm.setDoneCount(count);
+ }
+
+ /**
+ * Determine the 'active' value format. It is the view preference if
+ * and only if the element supports it. Otherwise it is the first
+ * format supported by the element.
+ * <p>
+ * Note: If the availableFormatsMap doesn't contain the available formats
+ * for the given update, it means the update doesn't request any properties
+ * which requires the active format to be calculated.
+ *
+ * @param update Properties update to calculate the active format for.
+ * @param availableFormatsMap The map of available formats.
+ * @return The active format, or null if active format not requested in
+ * update.
+ */
+ private String calcActiveFormat(IPropertiesUpdate update, String preferredFormat, Map<IPropertiesUpdate, String[]> availableFormatsMap) {
+ String[] availableFormats = availableFormatsMap.get(update);
+ if (availableFormats != null && availableFormats.length != 0) {
+ if (isFormatAvailable(preferredFormat, availableFormats)) {
+ return preferredFormat;
+ } else {
+ return availableFormats[0];
+ }
+ }
+ return null; // null means we don't need to know what the active format is
+ }
+
+ /**
+ * Returns <code>true</code> if the given availableFormats array contains
+ * the given format.
+ */
+ private boolean isFormatAvailable(String format, String[] availableFormats) {
+ for (String availableFormat : availableFormats) {
+ if (availableFormat.equals(format)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Service the properties that ask for the value in a specific
+ * format. If the update request contains the property
+ * PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE, and the active format
+ * has not been explicitly requested, then we need an additional
+ * iteration to provide it.
+ */
+ private List<String> calcRequestedFormats(IPropertiesUpdate update, String activeFormat, String[] availableFormats) {
+ List<String> requestedFormats = new ArrayList<String>(10);
+
+ boolean activeFormatValueHandled = false; // have we come across a specific format request that is the active format?
+
+ for (Iterator<String> itr = update.getProperties().iterator(); itr.hasNext() || (activeFormat != null && !activeFormatValueHandled);) {
+ String nextFormat;
+ if (itr.hasNext()) {
+ String propertyName = itr.next();
+ if (propertyName.startsWith(PROP_BASE)) {
+ nextFormat = FormattedValueVMUtil.getFormatFromProperty(propertyName, fPropertyPrefix);
+ if (nextFormat.equals(activeFormat)) {
+ activeFormatValueHandled = true;
+ }
+ // if we know the supported formats (we may not), then no-op if this format is unsupported
+ if (availableFormats != null && !isFormatAvailable(nextFormat, availableFormats)) {
+ continue;
+ }
+ }
+ else {
+ continue;
+ }
+ } else {
+ // the additional iteration to handle the active format
+ nextFormat = activeFormat;
+ activeFormatValueHandled = true;
+ }
+ requestedFormats.add(nextFormat);
+ }
+ return requestedFormats;
+ }
+
+ /**
+ * Writes the given formatted property value into the update. It also
+ * writes the active format property if needed.
+ * <p>
+ * If the given property value is null, this method writes an error status
+ * instead.
+ */
+ private void setUpdateFormatProperty(IPropertiesUpdate update, String activeFormat, String format, Object value) {
+ String formatProperty = FormattedValueVMUtil.getPropertyForFormatId(format, fPropertyPrefix);
+ if (value != null) {
+ update.setProperty(formatProperty, value);
+ if (update.getProperties().contains(PROP_ACTIVE_FORMAT_VALUE) &&
+ format.equals(activeFormat))
+ {
+ update.setProperty(PROP_ACTIVE_FORMAT_VALUE, value);
+ }
+ } else {
+ IStatus staleDataStatus = DsfUIPlugin.newErrorStatus(IDsfStatusConstants.INVALID_STATE, "Cache contains stale data. Refresh view.", null );//$NON-NLS-1$
+ if (update.getProperties().contains(PROP_ACTIVE_FORMAT_VALUE) &&
+ format.equals(activeFormat))
+ {
+ PropertiesUpdateStatus.getPropertiesStatus(update).setStatus(
+ new String[] { PROP_ACTIVE_FORMAT_VALUE, formatProperty },
+ staleDataStatus);
+ } else {
+ PropertiesUpdateStatus.getPropertiesStatus(update).setStatus(formatProperty, staleDataStatus);
+ }
+ }
+ }
+
+ /**
+ * For each update, query the formats available for the update's
+ * element...but only if necessary. The available formats are necessary
+ * only if the update explicitly requests that information, or if the
+ * update is asking what the active format is or is asking for the value
+ * of the element in that format. The reason we need them in the last
+ * two cases is that we can't establish the 'active' format for an
+ * element without knowing its available formats. See
+ * updateFormattedValuesWithAvailableFormats(), as that's where we make
+ * that determination.
+ * @param update
+ * @return
+ */
+ private boolean isAvailableFormatsPropertyNeeded(IPropertiesUpdate update) {
+ return update.getProperties().contains(PROP_AVAILABLE_FORMATS) ||
+ update.getProperties().contains(PROP_ACTIVE_FORMAT) ||
+ update.getProperties().contains(PROP_ACTIVE_FORMAT_VALUE);
+ }
+
+ /**
+ * Extracts the formatted data DMC from the update. If update doesn't
+ * contain DMC-based elemtn, it writes an error to the update and returns
+ * <code>null</code>.
+ */
+ private IFormattedDataDMContext getFormattedDataDMContext(IPropertiesUpdate update)
+ {
+ IFormattedDataDMContext dmc = null;
+ if (update.getElement() instanceof IDMVMContext) {
+ dmc = DMContexts.getAncestorOfType(((IDMVMContext)update.getElement()).getDMContext(), fDmcType);
+ }
+
+ if (dmc == null) {
+ update.setStatus(DsfUIPlugin.newErrorStatus(IDsfStatusConstants.INVALID_HANDLE, "Update element did not contain a valid context: " + fDmcType, null)); //$NON-NLS-1$
+ }
+ return dmc;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueVMUtil.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueVMUtil.java
index 62a369a6927..187ffff3ff1 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueVMUtil.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValueVMUtil.java
@@ -10,12 +10,11 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat;
-import com.ibm.icu.text.MessageFormat;
-
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.TreeMap;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
@@ -34,6 +33,8 @@ import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import com.ibm.icu.text.MessageFormat;
+
/**
* A helper class for View Model Node implementations that support elements
* to be formatted using different number formats. The various static methods in
@@ -48,6 +49,12 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
public class FormattedValueVMUtil {
/**
+ * Cache to avoid creating many duplicate strings of formats and properties.
+ */
+ private static Map<String, Map<String, String>> fFormatProperties =
+ Collections.synchronizedMap(new TreeMap<String, Map<String, String>>());
+
+ /**
* Common map of user-readable labels for format IDs.
*/
private static Map<String, String> fFormatLabels = new HashMap<String, String>(8);
@@ -66,7 +73,7 @@ public class FormattedValueVMUtil {
* add its label to the map of format IDs using this method.
*
* @param formatId Format ID to set the label for.
- * @param label User-readable lable for a format.
+ * @param label User-readable label for a format.
*/
public static void setFormatLabel(String formatId, String label) {
fFormatLabels.put(formatId, label);
@@ -87,20 +94,102 @@ public class FormattedValueVMUtil {
/**
* Returns an element property representing an element value in a given format.
+
+ * @deprecated Replaced by {@link #getPropertyForFormatId(String, String)}
*/
public static String getPropertyForFormatId(String formatId) {
+ return getPropertyForFormatId(formatId, ""); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns an element property representing an element value in a given format.
+ *
+ * @param Format ID to create the property for.
+ * @param prefix The prefix for the property that is used to distinguish
+ * it from other number format values in a given property map. May be
+ * <code>null</code> or an empty string if no prefix is used.
+ * @return The generated property name.
+ *
+ * @since 2.2
+ */
+ public static String getPropertyForFormatId(String formatId, String prefix) {
if (formatId == null) {
return null;
}
- return IDebugVMConstants.PROP_FORMATTED_VALUE_BASE + "." + formatId; //$NON-NLS-1$
+ if (prefix == null) {
+ prefix = ""; //$NON-NLS-1$
+ }
+ synchronized(fFormatProperties) {
+ Map<String, String> formatsMap = getFormatsMap(prefix);
+ String property = formatsMap.get(formatId);
+ if (property == null) {
+ property = (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_BASE + "." + formatId).intern(); //$NON-NLS-1$
+ formatsMap.put(formatId, property);
+ }
+ return property;
+ }
}
+ private static Map<String, String> getFormatsMap(String prefix) {
+ synchronized(fFormatProperties) {
+ Map<String, String> prefixMap = fFormatProperties.get(prefix);
+ if (prefixMap == null) {
+ prefixMap = new TreeMap<String, String>();
+ fFormatProperties.put(prefix, prefixMap);
+ }
+ return prefixMap;
+ }
+ }
+
/**
* Returns a format ID based on the element property representing a
- * formatted element value.
+ * formatted element value.
+ *
+ * @deprecated Replaced by {@link #getFormatFromProperty(String, String)}
*/
public static String getFormatFromProperty(String property) {
- return property.substring(IDebugVMConstants.PROP_FORMATTED_VALUE_BASE.length() + 1);
+ return getFormatFromProperty(property, ""); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a format ID based on the element property representing a
+ * formatted element value. This method has an additional prefix parameter
+ * which is used when multiple number formats are stored in a single
+ * property map.
+ *
+ * @param property The property to extract the format from.
+ * @param prefix The prefix for the property that is used to distinguish
+ * it from other number format values in a given property map. May be
+ * <code>null</code> or an empty string if no prefix is used.
+ * @return The format ID.
+ *
+ * @throws IllegalArgumentException if the property is not a formatted value
+ * property.
+ *
+ * @since 2.2
+ */
+ public static String getFormatFromProperty(String property, String prefix) {
+ if (prefix == null) {
+ prefix = ""; //$NON-NLS-1$
+ }
+
+ synchronized(fFormatProperties) {
+ Map<String, String> formatsMap = getFormatsMap(prefix);
+ for (Map.Entry<String, String> entry : formatsMap.entrySet()) {
+ if (entry.getValue().equals(property)) {
+ return entry.getKey();
+ }
+ }
+ if ( !property.startsWith(prefix) ||
+ !property.startsWith(IDebugVMConstants.PROP_FORMATTED_VALUE_BASE, prefix.length()) )
+ {
+ throw new IllegalArgumentException("Property " + property + " is not a valid formatted value format property."); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ String formatId = property.substring(
+ prefix.length() + IDebugVMConstants.PROP_FORMATTED_VALUE_BASE.length() + 1).intern();
+ formatsMap.put(formatId, property);
+ return formatId;
+ }
}
@@ -116,6 +205,7 @@ public class FormattedValueVMUtil {
return IFormattedValues.NATURAL_FORMAT;
}
+
/**
* This method fills in the formatted value properties in the given array
* of property update objects using data retrieved from the given
@@ -131,6 +221,9 @@ public class FormattedValueVMUtil {
* method assures that there is no ambiguity in which context should be
* used.
* @param monitor Request monitor used to signal completion of work
+ *
+ * @deprecated This method has been replaced by the {@link FormattedValueRetriever}
+ * utility.
*/
@ConfinedToDsfExecutor("service.getExecutor()")
public static void updateFormattedValues(
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java
index 45b39fb01c0..2cab98e7505 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java
@@ -22,8 +22,8 @@ import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
-import org.eclipse.cdt.dsf.debug.service.IRegisters;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMData;
@@ -33,11 +33,12 @@ import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelForeground;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelText;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueLabelText;
-import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueRetriever;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableLabelFont;
@@ -56,6 +57,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelForeground;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.VMDelegatingPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelBackground;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelForeground;
@@ -83,7 +85,6 @@ import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
@@ -173,12 +174,25 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
*/
private IElementLabelProvider fLabelProvider;
+ /**
+ * Retriever for formatted values configured for this VM node.
+ * @since 2.2
+ */
+ private final FormattedValueRetriever fFormattedValueRetriever;
+
public RegisterBitFieldVMNode(AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess access) {
super(provider, session, IBitFieldDMContext.class);
fSyncRegisterDataAccess = access;
fLabelProvider = createLabelProvider();
+ fFormattedValueRetriever =
+ new FormattedValueRetriever(this, session, IRegisters.class, IBitFieldDMContext.class);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ fFormattedValueRetriever.dispose();
}
-
@Override
public String toString() {
@@ -284,15 +298,7 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
IRegisterVMConstants.PROP_CURRENT_MNEMONIC_LONG_NAME}),
new FormattedValueLabelText(),
new ErrorLabelText(),
- new LabelForeground(new RGB(255, 0, 0)) // TODO: replace with preference error color
- {
- { setPropertyNames(new String[] { PROP_NAME }); }
-
- @Override
- public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
- return !status.isOK();
- }
- },
+ new ErrorLabelForeground(),
new LabelBackground(
DebugUITools.getPreferenceColor(IDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB())
{
@@ -493,23 +499,51 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
}
/**
+ * Update the variable view properties. The formatted values need to be
+ * updated in the VM executor thread while the rest of the properties is
+ * updated in the service session's executor thread. The implementation
+ * splits the handling of the updates to accomplish that.
+ *
* @see IElementPropertiesProvider#update(IPropertiesUpdate[])
*
* @since 2.0
*/
public void update(final IPropertiesUpdate[] updates) {
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ for (int i = 0; i < updates.length; i++) {
+ updates[i].done();
+ }
+ };
+ };
+ int count = 0;
+
+ fFormattedValueRetriever.update(updates, countingRm);
+ count++;
+
+ final IPropertiesUpdate[] subUpdates = new IPropertiesUpdate[updates.length];
+ for (int i = 0; i < updates.length; i++) {
+ final IPropertiesUpdate update = updates[i];
+ subUpdates[i] = new VMDelegatingPropertiesUpdate(update, countingRm);
+ count++;
+ }
+ countingRm.setDoneCount(count);
+
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
- updatePropertiesInSessionThread(updates);
+ updatePropertiesInSessionThread(subUpdates);
}});
} catch (RejectedExecutionException e) {
- for (IPropertiesUpdate update : updates) {
- handleFailedUpdate(update);
+ for (IPropertiesUpdate subUpdate : subUpdates) {
+ subUpdate.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Session executor shut down " + getSession().getExecutor(), e)); //$NON-NLS-1$
+ subUpdate.done();
}
}
}
+
//
// @param return-value Boolean.TRUE --> Show Types ICON is selected/depressed
// @param return-value Boolean.FALSE --> Show Types ICON is not selected/depressed
@@ -541,11 +575,6 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
};
int count = 0;
- if (service != null) {
- FormattedValueVMUtil.updateFormattedValues(updates, service, IBitFieldDMContext.class, countingRm);
- count++;
- }
-
for (final IPropertiesUpdate update : updates) {
IExpression expression = (IExpression)DebugPlugin.getAdapter(update.getElement(), IExpression.class);
if (expression != null) {
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java
index 56379ffb872..82ac014133e 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java
@@ -22,19 +22,20 @@ import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
-import org.eclipse.cdt.dsf.debug.service.IRegisters;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegistersChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelForeground;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelText;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueLabelText;
-import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueRetriever;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableLabelFont;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
@@ -52,6 +53,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelForeground;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.VMDelegatingPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelBackground;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelForeground;
@@ -80,7 +82,6 @@ import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
/**
@@ -171,10 +172,18 @@ public class RegisterVMNode extends AbstractExpressionVMNode
*/
private IElementLabelProvider fLabelProvider;
+ /**
+ * Retriever for formatted values configured for this VM node.
+ * @since 2.2
+ */
+ private final FormattedValueRetriever fFormattedValueRetriever;
+
public RegisterVMNode(AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
super(provider, session, IRegisterDMContext.class);
fSyncRegisterDataAccess = syncDataAccess;
fLabelProvider = createLabelProvider();
+ fFormattedValueRetriever =
+ new FormattedValueRetriever(this, session, IRegisters.class, IRegisterDMContext.class);
}
private Object[] constructTypeObjects( Map<String, Object> properties ) {
@@ -218,7 +227,9 @@ public class RegisterVMNode extends AbstractExpressionVMNode
DebugUITools.getPreferenceStore().removePropertyChangeListener(fPreferenceChangeListener);
}
- super.dispose();
+ super.dispose();
+
+ fFormattedValueRetriever.dispose();
}
protected IElementLabelProvider createLabelProvider() {
@@ -325,15 +336,7 @@ public class RegisterVMNode extends AbstractExpressionVMNode
new LabelColumnInfo(new LabelAttribute[] {
new FormattedValueLabelText(),
new ErrorLabelText(),
- new LabelForeground(new RGB(255, 0, 0)) // TODO: replace with preference error color
- {
- { setPropertyNames(new String[] { PROP_NAME }); }
-
- @Override
- public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
- return !status.isOK();
- }
- },
+ new ErrorLabelForeground(),
columnIdValueBackground,
new StaleDataLabelForeground(),
new VariableLabelFont(),
@@ -460,19 +463,46 @@ public class RegisterVMNode extends AbstractExpressionVMNode
}
/**
+ * Update the variable view properties. The formatted values need to be
+ * updated in the VM executor thread while the rest of the properties is
+ * updated in the service session's executor thread. The implementation
+ * splits the handling of the updates to accomplish that.
+ *
* @see IElementPropertiesProvider#update(IPropertiesUpdate[])
*
* @since 2.0
*/
public void update(final IPropertiesUpdate[] updates) {
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ for (int i = 0; i < updates.length; i++) {
+ updates[i].done();
+ }
+ };
+ };
+ int count = 0;
+
+ fFormattedValueRetriever.update(updates, countingRm);
+ count++;
+
+ final IPropertiesUpdate[] subUpdates = new IPropertiesUpdate[updates.length];
+ for (int i = 0; i < updates.length; i++) {
+ final IPropertiesUpdate update = updates[i];
+ subUpdates[i] = new VMDelegatingPropertiesUpdate(update, countingRm);
+ count++;
+ }
+ countingRm.setDoneCount(count);
+
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
- updatePropertiesInSessionThread(updates);
+ updatePropertiesInSessionThread(subUpdates);
}});
} catch (RejectedExecutionException e) {
- for (IPropertiesUpdate update : updates) {
- handleFailedUpdate(update);
+ for (IPropertiesUpdate subUpdate : subUpdates) {
+ subUpdate.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Session executor shut down " + getSession().getExecutor(), e)); //$NON-NLS-1$
+ subUpdate.done();
}
}
}
@@ -513,11 +543,6 @@ public class RegisterVMNode extends AbstractExpressionVMNode
};
int count = 0;
- if (service != null) {
- FormattedValueVMUtil.updateFormattedValues(updates, service, IRegisterDMContext.class, countingRm);
- count++;
- }
-
for (final IPropertiesUpdate update : updates) {
IExpression expression = (IExpression)DebugPlugin.getAdapter(update.getElement(), IExpression.class);
if (expression != null) {
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/DebugManualUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/DebugManualUpdatePolicy.java
index 107d4519119..ef16720e353 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/DebugManualUpdatePolicy.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/DebugManualUpdatePolicy.java
@@ -10,13 +10,17 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.ui.viewmodel.update;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueRetriever;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICacheEntry;
import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTesterExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicyExtension;
import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.TreePath;
@@ -24,17 +28,54 @@ import org.eclipse.jface.viewers.TreePath;
/**
* Manual update policy with extensions specific for the debugger views. It
* properly handles the changes in active number format values in debug view.
+ * This requires clearing of cached properties related to the active format
+ * preference, but not clearing the formatted value data retrieved from the
+ * service.
*
* @since 2.1
*/
-public class DebugManualUpdatePolicy extends ManualUpdatePolicy {
+public class DebugManualUpdatePolicy extends ManualUpdatePolicy implements IVMUpdatePolicyExtension {
- public static String DEBUG_MANUAL_UPDATE_POLICY_ID = "org.eclipse.cdt.dsf.debug.ui.viewmodel.update.debugManualUpdatePolicy"; //$NON-NLS-1$
+ private final Set<String> fActiveNumberFormatPropertiesWithPrefixes;
- private static final List<String> ACTIVE_NUMBER_FORMAT_PROPERTIES = new ArrayList<String>(1);
+ /**
+ * Creates a manual update policy for debug views.
+ */
+ public DebugManualUpdatePolicy() {
+ this(new String[0]);
+ }
+
+ /**
+ * Creates a manual update policy for debug views for models that retrieve
+ * multiple formatted values for each view entry. The given prefixes
+ * distinguish the formatted values properties from each other.
+ *
+ * @see FormattedValueRetriever
+ * @see FormattedValueVMUtil#getPropertyForFormatId(String, String)
+ *
+ * @param prefixes Prefixes to use when flushing the active formatted value
+ * from VM cache.
+ */
+ public DebugManualUpdatePolicy(String[] prefixes) {
+ if (prefixes.length == 0) {
+ fActiveNumberFormatPropertiesWithPrefixes = ACTIVE_NUMBER_FORMAT_PROPERTIES;
+ } else {
+ fActiveNumberFormatPropertiesWithPrefixes = new TreeSet<String>(ACTIVE_NUMBER_FORMAT_PROPERTIES);
+ for (String prefix : prefixes) {
+ fActiveNumberFormatPropertiesWithPrefixes.add(
+ (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT).intern());
+ fActiveNumberFormatPropertiesWithPrefixes.add(
+ (prefix + IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).intern());
+ }
+ }
+
+ }
+ private static final Set<String> ACTIVE_NUMBER_FORMAT_PROPERTIES = new TreeSet<String>();
static {
ACTIVE_NUMBER_FORMAT_PROPERTIES.add(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT);
+ ACTIVE_NUMBER_FORMAT_PROPERTIES.add(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE);
+ ACTIVE_NUMBER_FORMAT_PROPERTIES.add(IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE);
}
/**
@@ -42,17 +83,14 @@ public class DebugManualUpdatePolicy extends ManualUpdatePolicy {
* property of the elemetn under consideration. The partial property flush
* is performed only if the cache entry is not yet dirty.
*/
- private static IElementUpdateTester fgNumberFormatPropertyEventUpdateTester = new IElementUpdateTesterExtension() {
+ private IElementUpdateTester fNumberFormatPropertyEventUpdateTester = new IElementUpdateTesterExtension() {
public int getUpdateFlags(Object viewerInput, TreePath path) {
return FLUSH_PARTIAL_PROPERTIES;
}
public Collection<String> getPropertiesToFlush(Object viewerInput, TreePath path, boolean isDirty) {
- if (!isDirty) {
- return ACTIVE_NUMBER_FORMAT_PROPERTIES;
- }
- return null;
+ return fActiveNumberFormatPropertiesWithPrefixes;
}
public boolean includes(IElementUpdateTester tester) {
@@ -66,17 +104,16 @@ public class DebugManualUpdatePolicy extends ManualUpdatePolicy {
};
@Override
- public String getID() {
- return DEBUG_MANUAL_UPDATE_POLICY_ID;
- }
-
- @Override
public IElementUpdateTester getElementUpdateTester(Object event) {
- if ((event instanceof PropertyChangeEvent &&
- ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE))
+ if ( event instanceof PropertyChangeEvent &&
+ IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE.equals( ((PropertyChangeEvent)event).getProperty()) )
{
- return fgNumberFormatPropertyEventUpdateTester;
+ return fNumberFormatPropertyEventUpdateTester;
}
return super.getElementUpdateTester(event);
}
+
+ public boolean canUpdateDirtyProperty(ICacheEntry entry, String property) {
+ return fActiveNumberFormatPropertiesWithPrefixes.contains(property);
+ }
}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
index af5da3bb96c..fb4b5339867 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
@@ -47,11 +47,13 @@ import org.eclipse.cdt.dsf.debug.service.IStack;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelForeground;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.ErrorLabelText;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionUpdate;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueLabelText;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueRetriever;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
@@ -70,6 +72,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelForeground;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.VMDelegatingPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelBackground;
import org.eclipse.cdt.dsf.ui.viewmodel.update.StaleDataLabelForeground;
@@ -100,7 +103,6 @@ import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IMemento;
@@ -143,6 +145,12 @@ public class VariableVMNode extends AbstractExpressionVMNode
*/
private final IElementLabelProvider fLabelProvider;
+ /**
+ * Retriever for formatted values configured for this VM node.
+ * @since 2.2
+ */
+ private final FormattedValueRetriever fFormattedValueRetriever;
+
public class VariableExpressionVMC extends DMVMContext implements IFormattedValueVMContext {
private IExpression fExpression;
@@ -227,6 +235,8 @@ public class VariableVMNode extends AbstractExpressionVMNode
super(provider, session, IExpressions.IExpressionDMContext.class);
fSyncVariableDataAccess = syncVariableDataAccess;
fLabelProvider = createLabelProvider();
+ fFormattedValueRetriever =
+ new FormattedValueRetriever(this, session, IExpressions.class, IExpressionDMContext.class);
}
/**
@@ -263,7 +273,10 @@ public class VariableVMNode extends AbstractExpressionVMNode
DebugUITools.getPreferenceStore().removePropertyChangeListener(fPreferenceChangeListener);
}
- super.dispose();
+
+ super.dispose();
+
+ fFormattedValueRetriever.dispose();
}
/**
@@ -459,16 +472,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
},
new FormattedValueLabelText(),
new ErrorLabelText(),
- new LabelForeground(new RGB(255, 0, 0)) // TODO: replace with preference error color
- {
- { setPropertyNames(new String[] { PROP_NAME }); }
-
- @Override
- public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
- return !status.isOK();
- }
- },
- //
+ new ErrorLabelForeground(),
columnIdValueBackground,
new StaleDataLabelForeground(),
new VariableLabelFont(),
@@ -607,15 +611,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
POINTER_LABEL_IMAGE,
AGGREGATE_LABEL_IMAGE,
SIMPLE_LABEL_IMAGE,
- new LabelForeground(new RGB(255, 0, 0)) // TODO: replace with preference error color
- {
- { setPropertyNames(new String[] { PROP_NAME }); }
-
- @Override
- public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
- return !status.isOK();
- }
- },
+ new ErrorLabelForeground(),
new LabelForeground(
DebugUITools.getPreferenceColor(IDebugUIConstants.PREF_CHANGED_DEBUG_ELEMENT_COLOR).getRGB())
{
@@ -659,19 +655,46 @@ public class VariableVMNode extends AbstractExpressionVMNode
}
/**
+ * Update the variable view properties. The formatted values need to be
+ * updated in the VM executor thread while the rest of the properties is
+ * updated in the service session's executor thread. The implementation
+ * splits the handling of the updates to accomplish that.
+ *
* @see IElementPropertiesProvider#update(IPropertiesUpdate[])
*
* @since 2.0
*/
public void update(final IPropertiesUpdate[] updates) {
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ for (int i = 0; i < updates.length; i++) {
+ updates[i].done();
+ }
+ };
+ };
+ int count = 0;
+
+ fFormattedValueRetriever.update(updates, countingRm);
+ count++;
+
+ final IPropertiesUpdate[] subUpdates = new IPropertiesUpdate[updates.length];
+ for (int i = 0; i < updates.length; i++) {
+ final IPropertiesUpdate update = updates[i];
+ subUpdates[i] = new VMDelegatingPropertiesUpdate(update, countingRm);
+ count++;
+ }
+ countingRm.setDoneCount(count);
+
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
- updatePropertiesInSessionThread(updates);
+ updatePropertiesInSessionThread(subUpdates);
}});
} catch (RejectedExecutionException e) {
- for (IPropertiesUpdate update : updates) {
- handleFailedUpdate(update);
+ for (IPropertiesUpdate subUpdate : subUpdates) {
+ subUpdate.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Session executor shut down " + getSession().getExecutor(), e)); //$NON-NLS-1$
+ subUpdate.done();
}
}
}
@@ -707,11 +730,6 @@ public class VariableVMNode extends AbstractExpressionVMNode
};
int count = 0;
- if (service != null) {
- FormattedValueVMUtil.updateFormattedValues(updates, service, IExpressionDMContext.class, countingRm);
- count++;
- }
-
for (final IPropertiesUpdate update : updates) {
IExpression expression = (IExpression)DebugPlugin.getAdapter(update.getElement(), IExpression.class);
if (expression != null) {
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java
index 84a966e882d..24220703169 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java
@@ -36,6 +36,9 @@ public interface IPropertiesUpdate extends IViewerUpdate {
/**
* Sets the given map as the complete property map for this update.
+ * If other properties were already set to this update, the properties
+ * given here will be added. If properties are added later, the properties
+ * map given here will not be modified, instead it will be copied.
*
* @param properties Full properties map.
*/
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdateListener.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdateListener.java
new file mode 100644
index 00000000000..13f5a02f83f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdateListener.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.viewmodel.properties;
+
+/**
+ * Listener for properties updates requested by a property based label provider.
+ *
+ * @since 2.2
+ */
+public interface IPropertiesUpdateListener {
+
+ /**
+ * Indicates that the given updates were requested from a properties provider.
+ */
+ public void propertiesUpdatesStarted(IPropertiesUpdate[] updates);
+
+ /**
+ * Indicates that the given update has been completed.
+ */
+ public void propertiesUpdateCompleted(IPropertiesUpdate update);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java
index 7d6c400dcbf..0527b3f487e 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java
@@ -17,6 +17,7 @@ import org.eclipse.osgi.util.NLS;
*/
class MessagesForProperties extends NLS {
public static String DefaultLabelMessage_label;
+ public static String PropertiesUpdateStatus_message;
static {
// initialize resource bundle
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.properties
index cdf03432bfc..a00405819bf 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.properties
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2006, 2009 Wind River Systems and others.
+# Copyright (c) 2006, 2010 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
@@ -9,3 +9,4 @@
# Wind River Systems - initial API and implementation
###############################################################################
DefaultLabelMessage_label=<unknown>
+PropertiesUpdateStatus_message=Multiple errors reported. \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesBasedLabelProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesBasedLabelProvider.java
index 8a720ee7609..d0bb2df7bc3 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesBasedLabelProvider.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesBasedLabelProvider.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.ui.viewmodel.properties;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -49,6 +50,8 @@ public class PropertiesBasedLabelProvider
*/
private Map<String, LabelColumnInfo> fColumnInfos = Collections.synchronizedMap(new HashMap<String,LabelColumnInfo>());
+ private IPropertiesUpdateListener[] fListeners = new IPropertiesUpdateListener[0];
+
/**
* Standard constructor. A property based label constructor does not
* initialize column attribute information {@link #setColumnInfo(String, LabelColumnInfo)}
@@ -81,6 +84,40 @@ public class PropertiesBasedLabelProvider
return fColumnInfos.get(columnId);
}
+ /**
+ * Adds a listener for properties updates generated by this label provider.
+ *
+ * @since 2.2
+ */
+ public void addPropertiesUpdateListener(IPropertiesUpdateListener listener) {
+ synchronized(this) {
+ if (!Arrays.asList(fListeners).contains(listener)) {
+ IPropertiesUpdateListener[] newListeners = new IPropertiesUpdateListener[fListeners.length + 1];
+ System.arraycopy(fListeners, 0, newListeners, 0, fListeners.length);
+ newListeners[fListeners.length] = listener;
+ fListeners = newListeners;
+ }
+ }
+ }
+
+ /**
+ * Removes a listener for properties updates generated by this label provider.
+ *
+ * @since 2.2
+ */
+ public void removePropertiesUpdateListener(IPropertiesUpdateListener listener) {
+ synchronized(this) {
+ int listenerIdx = Arrays.asList(fListeners).indexOf(listener);
+
+ if (listenerIdx != -1) {
+ IPropertiesUpdateListener[] newListeners = new IPropertiesUpdateListener[fListeners.length - 1];
+ System.arraycopy(fListeners, 0, newListeners, 0, listenerIdx);
+ System.arraycopy(fListeners, listenerIdx + 1, newListeners, listenerIdx, newListeners.length - listenerIdx);
+ fListeners = newListeners;
+ }
+ }
+ }
+
/**
* In addition to guarantees on [labelUpdates] declared by
* {@link IElementLabelProvider}, we further require/assume that all the
@@ -89,7 +126,7 @@ public class PropertiesBasedLabelProvider
*
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
- public void update(ILabelUpdate[] labelUpdates) {
+ public void update(final ILabelUpdate[] labelUpdates) {
IElementPropertiesProvider propertiesProvider = getElementPropertiesProvider(labelUpdates[0].getElement());
if (propertiesProvider == null) {
for (ILabelUpdate update : labelUpdates) {
@@ -109,19 +146,41 @@ public class PropertiesBasedLabelProvider
// Call the properties provider. Create a request monitor for each label update.
// We can use an immediate executor for the request monitor because the label provider
// is thread safe.
- IPropertiesUpdate[] propertiesUpdates = new IPropertiesUpdate[labelUpdates.length];
+ final IPropertiesUpdate[] propertiesUpdates = new IPropertiesUpdate[labelUpdates.length];
for (int i = 0; i < labelUpdates.length; i++) {
- final ILabelUpdate labelUpdate = labelUpdates[i];
- propertiesUpdates[i] = new VMPropertiesUpdate(
- propertyNames, labelUpdate,
- new ViewerDataRequestMonitor<Map<String, Object>>(ImmediateExecutor.getInstance(), labelUpdate) {
+ final int idx = i;
+ propertiesUpdates[idx] = new VMPropertiesUpdate(
+ propertyNames, labelUpdates[idx],
+ new ViewerDataRequestMonitor<Map<String, Object>>(ImmediateExecutor.getInstance(), labelUpdates[idx]) {
@Override
protected void handleCompleted() {
- updateLabel(labelUpdate, getStatus(), getData());
+ notifyPropertiesUpdateCompleted(propertiesUpdates[idx]);
+ updateLabel(labelUpdates[idx], getStatus(), getData());
}
});
}
- propertiesProvider.update(propertiesUpdates);
+ notifyPropertiesUpdatesStarted(propertiesUpdates);
+ propertiesProvider.update(propertiesUpdates);
+ }
+
+ private void notifyPropertiesUpdatesStarted(IPropertiesUpdate[] updates) {
+ IPropertiesUpdateListener[] listeners = null;
+ synchronized(this) {
+ listeners = fListeners;
+ }
+ for (IPropertiesUpdateListener listener : listeners) {
+ listener.propertiesUpdatesStarted(updates);
+ }
+ }
+
+ private void notifyPropertiesUpdateCompleted(IPropertiesUpdate update) {
+ IPropertiesUpdateListener[] listeners = null;
+ synchronized(this) {
+ listeners = fListeners;
+ }
+ for (IPropertiesUpdateListener listener : listeners) {
+ listener.propertiesUpdateCompleted(update);
+ }
}
/**
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesUpdateStatus.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesUpdateStatus.java
new file mode 100644
index 00000000000..5ff39b4c9da
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertiesUpdateStatus.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.viewmodel.properties;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DsfMultiStatus;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Status object for use with the IPropertiesUpdate. This status class
+ * allows setting a different status result for each property. This allows
+ * for better interpretation of status by the client of the update.
+ * <p>
+ * This status class derives from MultiStatus class such that the status
+ * objects for each property can be accessed through the standard
+ * {@link #getChildren()} method. Also, multiple properties can reference
+ * the same status object, meaning that the number of properties returned
+ * by {@link #getProperties()} may be greater than the status objects
+ * returned by <code>getChildren()</code>.
+ * <p>
+ * The properties status object does not have its own message, severity,
+ * error status or exception. All these attributes are calculated from
+ * the child status objects. If the status has more than one status child,
+ * the String returned by {@link #getMessage()} is: "Multiple errors reported".
+ *
+ * @since 2.2
+ */
+public class PropertiesUpdateStatus extends DsfMultiStatus {
+
+ final private Map<String,IStatus> fPropertiesStatus = new HashMap<String, IStatus>(1);
+ private boolean fFirstStatusSet;
+
+ public PropertiesUpdateStatus() {
+ super(DsfUIPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns set of properties that have an additional status specified.
+ */
+ public Set<String> getProperties() {
+ return fPropertiesStatus.keySet();
+ }
+
+ /**
+ * Returns an additional status for the given property in a property
+ * update. Returned value may be <code>null</code> if no additional
+ * status is given.
+ */
+ public IStatus getStatus(String property) {
+ return fPropertiesStatus.get(property);
+ }
+
+ /**
+ * Sets the given status for the given property.
+ */
+ public void setStatus(String property, IStatus status) {
+ IStatus child = findEquivalentChild(status);
+ if (child != null) {
+ status = child;
+ } else {
+ add(status);
+ }
+
+ fPropertiesStatus.put(property, status);
+ }
+
+ /**
+ * Sets the given status for the properties array.
+ */
+ public void setStatus(String[] properties, IStatus status) {
+ IStatus child = findEquivalentChild(status);
+ if (child != null) {
+ status = child;
+ } else {
+ add(status);
+ }
+
+ for (String property : properties) {
+ fPropertiesStatus.put(property, status);
+ }
+ }
+
+ /**
+ * Merges data in the new status into the base status data, and returns the
+ * resulting status. Only properties specified in the given set are merged.
+ * <p>
+ * The new status is considered to be more up to date than the base
+ * status and its data overrides the base status . If the base status
+ * holds an error for a given property, which is found in the
+ * given set, and the new status does not, then the base error status is
+ * removed.
+ *
+ * @param baseStatus Properties into which the new status properties will
+ * be merged.
+ * @param newStatus Properties status to merge.
+ * @param properties The properties to consider in the new status.
+ * @return Resulting merged status object.
+ */
+ public static PropertiesUpdateStatus mergePropertiesStatus(PropertiesUpdateStatus baseStatus,
+ PropertiesUpdateStatus newStatus, Set<String> properties)
+ {
+ PropertiesUpdateStatus mergedStatus = new PropertiesUpdateStatus();
+ mergedStatus.fPropertiesStatus.putAll(baseStatus.fPropertiesStatus);
+
+ for (String property : properties) {
+ IStatus propertyStatus = newStatus.getStatus(property);
+ if (propertyStatus != null) {
+ mergedStatus.fPropertiesStatus.put(property, propertyStatus);
+ } else {
+ mergedStatus.fPropertiesStatus.remove(property);
+ }
+ }
+ Set<IStatus> children = new HashSet<IStatus>((baseStatus.getChildren().length + newStatus.getChildren().length) * 4/3);
+
+ children.addAll(mergedStatus.fPropertiesStatus.values());
+ for (IStatus child : children) {
+ mergedStatus.add(child);
+ }
+
+ return mergedStatus;
+ }
+
+ /**
+ * Adds the given status object as a child of this status. If there's an
+ * equivalent child status already, the new status is ignored.
+ */
+ @Override
+ public void add(IStatus status) {
+ if (findEquivalentChild(status) != null) {
+ return;
+ }
+
+ super.add(status);
+
+ boolean firstSet;
+ synchronized(this) {
+ firstSet = fFirstStatusSet;
+ fFirstStatusSet = true;
+ }
+
+ if (!firstSet) {
+ setMessage(status.getMessage());
+ } else {
+ setMessage(MessagesForProperties.PropertiesUpdateStatus_message);
+ }
+ }
+
+ /**
+ * Finds a child status that is equivalent to the given status.
+ */
+ private IStatus findEquivalentChild(IStatus status) {
+ if (getChildren().length != 0) {
+ for (IStatus child : getChildren()) {
+ if (areEquivalent(child, status)) {
+ return child;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compares two status objects to determine if they are equivalent.
+ */
+ private boolean areEquivalent(IStatus s1, IStatus s2) {
+ if ( (s1 == null && s2 != null) || (s1 != null && s2 == null) )
+ {
+ return false;
+ }
+ if (s1 == null) {
+ return true;
+ }
+ if ( (s1.getSeverity() != s2.getSeverity()) ||
+ !s1.getPlugin().equals(s2.getPlugin()) ||
+ (s1.getCode() != s2.getCode()) )
+ {
+ return false;
+ }
+ if ( (s1.getException() == null && s1.getException() != null) ||
+ (s1.getException() != null && s1.getException() == null) ||
+ (s1.getException() != null && !s1.getException().equals(s2.getException())) )
+ {
+ return false;
+ }
+ return s1.getMessage().equals(s2.getMessage());
+ };
+
+
+ /**
+ * Convenience method that returns and optionally creates a properties
+ * update status object for the given update.
+ */
+ public static PropertiesUpdateStatus getPropertiesStatus(IPropertiesUpdate update) {
+ IStatus updateStatus = update.getStatus();
+ if (updateStatus instanceof PropertiesUpdateStatus) {
+ return (PropertiesUpdateStatus)updateStatus;
+ } else {
+ PropertiesUpdateStatus propertiesStatus = new PropertiesUpdateStatus();
+ if (!updateStatus.isOK()) {
+ propertiesStatus.add(updateStatus);
+ }
+ return propertiesStatus;
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMDelegatingPropertiesUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMDelegatingPropertiesUpdate.java
index 296adcfe8f4..97638aa411e 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMDelegatingPropertiesUpdate.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMDelegatingPropertiesUpdate.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009 Wind River Systems and others.
+ * Copyright (c) 2009, 2010 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
@@ -15,6 +15,7 @@ import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.ui.viewmodel.VMViewerUpdate;
+import org.eclipse.core.runtime.IStatus;
/**
* Properties update used as to collect property data from the provider.
@@ -45,6 +46,22 @@ public class VMDelegatingPropertiesUpdate extends VMViewerUpdate implements IPro
fParentUpdate.setAllProperties(properties);
}
+ /**
+ * @since 2.2
+ */
+ @Override
+ public IStatus getStatus() {
+ return fParentUpdate.getStatus();
+ }
+
+ /**
+ * @since 2.2
+ */
+ @Override
+ public void setStatus(IStatus status) {
+ fParentUpdate.setStatus(status);
+ }
+
@Override
public String toString() {
return "VMDelegatingPropertiesUpdate -> " + fParentUpdate; //$NON-NLS-1$
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMPropertiesUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMPropertiesUpdate.java
index a645c34d6fc..d02f3cbff86 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMPropertiesUpdate.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/VMPropertiesUpdate.java
@@ -22,12 +22,20 @@ import org.eclipse.cdt.dsf.internal.DsfPlugin;
import org.eclipse.cdt.dsf.internal.LoggingUtils;
import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
import org.eclipse.cdt.dsf.ui.viewmodel.VMViewerUpdate;
+import org.eclipse.core.runtime.IStatus;
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;
/**
- * Properties update used as to collect property data from the provider.
+ * Properties update used as to collect property data from the provider.
+ * <p>
+ * The status returned by the VMPropertiesUpdate is always going to be of type
+ * PropertiesUpdateStatus, which allows for setting status for individual
+ * properties.
+ * </p>
+ *
+ * @see PropertiesUpdateStatus
*
* @since 2.0
*/
@@ -51,11 +59,13 @@ public class VMPropertiesUpdate extends VMViewerUpdate implements IPropertiesUpd
public VMPropertiesUpdate(Set<String> properties, IViewerUpdate parentUpdate, DataRequestMonitor<Map<String,Object>> rm) {
super(parentUpdate, rm);
+ super.setStatus(new PropertiesUpdateStatus());
fProperties = properties;
}
public VMPropertiesUpdate(Set<String> properties, TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, DataRequestMonitor<Map<String,Object>> rm) {
super(elementPath, viewerInput, presentationContext, rm);
+ super.setStatus(new PropertiesUpdateStatus());
fProperties = properties;
}
@@ -64,6 +74,13 @@ public class VMPropertiesUpdate extends VMViewerUpdate implements IPropertiesUpd
return fProperties;
}
+ /**
+ * @since 2.2
+ */
+ public Map<String, Object> getValues() {
+ return fValues;
+ }
+
public synchronized void setProperty(String property, Object value) {
if (!fCreatedOwnMap) {
fCreatedOwnMap = true;
@@ -86,6 +103,25 @@ public class VMPropertiesUpdate extends VMViewerUpdate implements IPropertiesUpd
}
/**
+ * Overrides the base class to implement special handling of
+ * {@link PropertiesUpdateStatus}. If the given status is an instance of
+ * properties status, this new status will be set to the update. Otherwise, the
+ * given status will be merged into the updates existing properties status.
+ * This way {@link #getStatus()} should always return an instance of
+ * <code>PropertiesUpdateStatus</code>.
+ */
+ @Override
+ public void setStatus(IStatus status) {
+ if (status instanceof PropertiesUpdateStatus) {
+ super.setStatus(status);
+ } else if ((getStatus() instanceof PropertiesUpdateStatus)) {
+ ((PropertiesUpdateStatus)getStatus()).add(status);
+ } else {
+ assert false : "VMPropertiesUpdate status should always be a PropertiesUpdateStatus"; //$NON-NLS-1$
+ }
+ }
+
+ /**
* Overrides the standard done in order to store the retrieved values
* in the client's request monitor.
*/
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java
index 0340def2021..ad244d76c7c 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java
@@ -14,10 +14,12 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
@@ -40,6 +42,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.VMHasChildrenUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesUpdateStatus;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.VMPropertiesUpdate;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
@@ -62,7 +65,7 @@ import org.eclipse.swt.widgets.TreeItem;
* @since 1.0
*/
public class AbstractCachingVMProvider extends AbstractVMProvider
- implements ICachingVMProvider, IElementPropertiesProvider, ICachingVMProviderExtension
+ implements ICachingVMProvider, IElementPropertiesProvider, ICachingVMProviderExtension, ICachingVMProviderExtension2
{
/**
* @since 2.0
@@ -175,7 +178,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
/**
* Entry with cached element data.
*/
- private static class ElementDataEntry extends Entry {
+ private static class ElementDataEntry extends Entry implements ICacheEntry {
ElementDataEntry(ElementDataKey key) {
super(key);
}
@@ -254,6 +257,16 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
", properties=" + fProperties + //$NON-NLS-1$
", oldProperties=" + fArchiveProperties + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
+
+ public IVMNode getNode() { return ((ElementDataKey)fKey).fNode; }
+ public Object getViewerInput() { return ((ElementDataKey)fKey).fViewerInput; }
+ public TreePath getElementPath() { return ((ElementDataKey)fKey).fPath; }
+ public boolean isDirty() { return fDirty; }
+ public Boolean getHasChildren() { return fHasChildren; }
+ public Integer getChildCount() { return fChildrenCount; }
+ public Map<Integer, Object> getChildren() { return fChildren; }
+ public Map<String, Object> getProperties() { return fProperties; }
+ public java.util.Map<String,Object> getArchiveProperties() { return fArchiveProperties; }
}
/**
@@ -294,7 +307,6 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
public String toString() {
return fElementTester.toString() + " " + fRootElement.toString(); //$NON-NLS-1$
}
-
}
/**
@@ -443,13 +455,18 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
}
}
+ public ICacheEntry getCacheEntry(IVMNode node, Object viewerInput, TreePath path) {
+ ElementDataKey key = makeEntryKey(node, viewerInput, path);
+ return getElementDataEntry(key, false);
+ }
+
@Override
public void updateNode(final IVMNode node, IHasChildrenUpdate[] updates) {
LinkedList <IHasChildrenUpdate> missUpdates = new LinkedList<IHasChildrenUpdate>();
for(final IHasChildrenUpdate update : updates) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update);
- final ElementDataEntry entry = getElementDataEntry(key);
+ final ElementDataEntry entry = getElementDataEntry(key, true);
updateRootElementMarker(key.fRootElement, node, update);
// Check if the cache entry has this request result cached.
@@ -498,7 +515,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
public void updateNode(final IVMNode node, final IChildrenCountUpdate update) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update);
- final ElementDataEntry entry = getElementDataEntry(key);
+ final ElementDataEntry entry = getElementDataEntry(key, true);
updateRootElementMarker(key.fRootElement, node, update);
// Check if the cache entry has this request result cached.
@@ -541,7 +558,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
public void updateNode(final IVMNode node, final IChildrenUpdate update) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update);
- final ElementDataEntry entry = getElementDataEntry(key);
+ final ElementDataEntry entry = getElementDataEntry(key, true);
updateRootElementMarker(key.fRootElement, node, update);
final int flushCounter = entry.fFlushCounter;
@@ -928,14 +945,21 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
* update and creates an element cache entry key.
*/
private ElementDataKey makeEntryKey(IVMNode node, IViewerUpdate update) {
- Object rootElement = update.getViewerInput(); // Default
+ return makeEntryKey(node, update.getViewerInput(), update.getElementPath());
+ }
+
+ /**
+ * Convenience class that searches for the root element for the given
+ * update and creates an element cache entry key.
+ */
+ private ElementDataKey makeEntryKey(IVMNode node, Object viewerInput, TreePath path) {
+ Object rootElement = viewerInput; // Default
outer: for (IVMModelProxy proxy : getActiveModelProxies()) {
Object proxyRoot = proxy.getRootElement();
- if (proxyRoot.equals(update.getViewerInput())) {
+ if (proxyRoot.equals(viewerInput)) {
rootElement = proxyRoot;
break;
}
- TreePath path = update.getElementPath();
for (int i = 0; i < path.getSegmentCount(); i++) {
if (proxyRoot.equals(path.getSegment(i))) {
rootElement = proxyRoot;
@@ -944,27 +968,29 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
}
}
- return new ElementDataKey(rootElement, node, update.getViewerInput(), update.getElementPath());
+ return new ElementDataKey(rootElement, node, viewerInput, path);
}
+
/**
* This is the only method that should be used to access a cache entry.
* It creates a new entry if needed and it maintains the ordering in
* the least-recently-used linked list.
+ * @param create Create the entry if needed.
+ * @return cache element entry, may be <code>null</code> if entry does
+ * not exist and the create parameter is <code>false</code>
*/
- private ElementDataEntry getElementDataEntry(ElementDataKey key) {
+ private ElementDataEntry getElementDataEntry(ElementDataKey key, boolean create) {
assert key != null;
ElementDataEntry entry = (ElementDataEntry)fCacheData.get(key);
- if (entry == null) {
+ if (entry != null) {
+ // Entry exists, move it to the end of the list.
+ entry.reinsert(fCacheListHead);
+ } else if (create) {
// Create a new entry and add it to the end of the list.
entry = new ElementDataEntry(key);
addEntry(key, entry);
- } else {
- // Entry exists, move it to the end of the list.
- entry.reinsert(fCacheListHead);
}
-
-
return entry;
}
@@ -991,7 +1017,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
if (created) {
ElementDataKey rootElementDataKey =
new ElementDataKey(rootElement, node, update.getViewerInput(), update.getElementPath());
- ElementDataEntry entry = getElementDataEntry(rootElementDataKey);
+ ElementDataEntry entry = getElementDataEntry(rootElementDataKey, false);
Object[] rootElementChildren = getActiveUpdatePolicy().getInitialRootElementChildren(rootElement);
if (rootElementChildren != null) {
@@ -1104,7 +1130,7 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
for(final IPropertiesUpdate update : updates) {
// Find or create the cache entry for the element of this update.
ElementDataKey key = makeEntryKey(node, update);
- final ElementDataEntry entry = getElementDataEntry(key);
+ final ElementDataEntry entry = getElementDataEntry(key, true);
updateRootElementMarker(key.fRootElement, node, update);
// The request can be retrieved from cache if all the properties that were requested in the update are
@@ -1120,28 +1146,59 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
update.setAllProperties(entry.fProperties);
update.setStatus((IStatus)entry.fProperties.get(PROP_UPDATE_STATUS));
update.done();
- } else if (entry.fProperties != null && entry.fDirty) {
- // Cache miss, BUT the entry is dirty already. Rather then fetch new data from model, return
- // incomplete data to user. User can refresh the view to get the complete data set.
- if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
- DsfUIPlugin.debug("cacheHitPropertiesPartialStaleData(node = " + node + ", update = " + update + ", " + entry.fProperties + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
- }
- if (entry.fProperties.containsKey(PROP_UPDATE_POLICY_ID)) {
- entry.fProperties.put(PROP_UPDATE_POLICY_ID, getActiveUpdatePolicy().getID());
- }
- update.setAllProperties(entry.fProperties);
- update.setStatus(DsfUIPlugin.newErrorStatus(IDsfStatusConstants.INVALID_STATE, "Cache contains partial stale data for this request.", null)); //$NON-NLS-1$
- update.done();
} else {
- // Cache miss! Save the flush counter of the entry and create a proxy update.
+ // Cache miss! Check if already cached properties can be re-used.
+ Set<String> missingProperties = null;
+ if (entry.fProperties != null) {
+ missingProperties = new HashSet<String>(update.getProperties().size() * 4/3);
+ missingProperties.addAll(update.getProperties());
+ missingProperties.removeAll(entry.fProperties.keySet());
+
+ if (entry.fDirty) {
+ // Cache miss, BUT the entry is dirty already. Determine which properties can still be updated
+ // (if any), then request the missing properties from node, or return an error.
+ if (getActiveUpdatePolicy() instanceof IVMUpdatePolicyExtension) {
+ IVMUpdatePolicyExtension updatePolicyExt = (IVMUpdatePolicyExtension)getActiveUpdatePolicy();
+ for (Iterator<String> itr = missingProperties.iterator(); itr.hasNext();) {
+ String missingProperty = itr.next();
+ if ( !updatePolicyExt.canUpdateDirtyProperty(entry, missingProperty) ) {
+ itr.remove();
+ PropertiesUpdateStatus.getPropertiesStatus(update).setStatus(
+ missingProperty,
+ DsfUIPlugin.newErrorStatus(IDsfStatusConstants.INVALID_STATE, "Cache contains stale data. Refresh view.", null ));//$NON-NLS-1$
+ }
+ }
+ } else {
+ PropertiesUpdateStatus.getPropertiesStatus(update).setStatus(
+ missingProperties.toArray(new String[missingProperties.size()]),
+ DsfUIPlugin.newErrorStatus(IDsfStatusConstants.INVALID_STATE, "Cache contains stale data. Refresh view.", null ));//$NON-NLS-1$
+ missingProperties.clear();
+ }
+ if (missingProperties.isEmpty()) {
+ if (entry.fProperties.containsKey(PROP_UPDATE_POLICY_ID)) {
+ entry.fProperties.put(PROP_UPDATE_POLICY_ID, getActiveUpdatePolicy().getID());
+ }
+ update.setAllProperties(entry.fProperties);
+ update.done();
+ return;
+ }
+ }
+ } else {
+ missingProperties = update.getProperties();
+ }
+
+ final Set<String> _missingProperties = missingProperties;
+ // Save the flush counter of the entry and create a proxy update.
final int flushCounter = entry.fFlushCounter;
missUpdates.add(new VMPropertiesUpdate(
- update.getProperties(),
+ missingProperties,
update,
new ViewerDataRequestMonitor<Map<String, Object>>(getExecutor(), update) {
@Override
protected void handleCompleted() {
- Map<String, Object> properties;
+ PropertiesUpdateStatus missUpdateStatus = (PropertiesUpdateStatus)getStatus();
+ Map<String, Object> cachedProperties;
+ PropertiesUpdateStatus cachedStatus;
if (!isCanceled() && flushCounter == entry.fFlushCounter) {
// We are caching the result of this update. Copy the properties from the update
// to the cached properties map.
@@ -1150,56 +1207,67 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
if (update.getProperties().contains(PROP_CACHE_ENTRY_DIRTY)) {
entry.fProperties.put(PROP_CACHE_ENTRY_DIRTY, entry.fDirty);
}
+ entry.fProperties.put(PROP_UPDATE_STATUS, new PropertiesUpdateStatus());
}
- properties = entry.fProperties;
- properties.putAll(getData());
+ cachedProperties = entry.fProperties;
+ cachedProperties.putAll(getData());
- // Make sure that all the properties that were
- // requested by the update object are in the
- // cache entry's properties map. It's possible the
- // ViewerDataRequestMonitor was able to provide
- // us only a subset of the requested ones. We
- // want to prevent that from causing future
- // cache misses, since a cache hit requires the
- // cache entry to contain all requested
- // properties. Use a null value for the missing
- // items.
- for (String updateProperty : update.getProperties()) {
- if (!properties.containsKey(updateProperty)) {
- properties.put(updateProperty, null);
+ // Make sure that all the properties that were requested by the update object are in
+ // the cache entry's properties map. It's possible he ViewerDataRequestMonitor was able
+ // to provide us only a subset of the requested ones. We want to prevent that from
+ // causing future cache misses, since a cache hit requires the cache entry to contain
+ // all requested properties. Use a null value for the missing items.
+ for (String property : _missingProperties) {
+ if (!getData().containsKey(property)) {
+ cachedProperties.put(property, null);
}
}
+
+ // Merge status from properties that came back from the node into the status that's in
+ // the cache.
+ cachedStatus = (PropertiesUpdateStatus)cachedProperties.get(PROP_UPDATE_STATUS);
+ cachedStatus = PropertiesUpdateStatus.mergePropertiesStatus(
+ cachedStatus, missUpdateStatus, _missingProperties);
+ cachedProperties.put(PROP_UPDATE_STATUS, cachedStatus);
} else {
- // We are not caching the result of this update, but we should still
- // return valid data to the client. In case the update was canceled
- // we can also return valid data to the client even if the client
- // is likely to ignore it since the cost of doing so is relatively low.
- properties = new HashMap<String, Object>((getData().size() + 3) * 4/3);
+ // We are not caching the result of this update, but we should still return valid data
+ // to the client. In case the update was canceled we can also return valid data to the
+ // client even if the client is likely to ignore it since the cost of doing so is
+ // relatively low.
+ // Create a temporary cached properties map and add existing cache and node update
+ // properties to it.
+ if (entry.fProperties != null) {
+ cachedProperties = new HashMap<String, Object>((entry.fProperties.size() + getData().size() + 3) * 4/3);
+ cachedProperties.putAll(entry.fProperties);
+ cachedStatus = PropertiesUpdateStatus.mergePropertiesStatus(
+ (PropertiesUpdateStatus)cachedProperties.get(PROP_UPDATE_STATUS),
+ missUpdateStatus, _missingProperties);
+ } else {
+ cachedProperties = new HashMap<String, Object>((getData().size() + 3) * 4/3);
+ cachedStatus = missUpdateStatus;
+ }
+ cachedProperties.putAll(getData());
+ cachedProperties.put(PROP_UPDATE_STATUS, missUpdateStatus);
if (update.getProperties().contains(PROP_CACHE_ENTRY_DIRTY)) {
- properties.put(PROP_CACHE_ENTRY_DIRTY, Boolean.TRUE);
+ cachedProperties.put(PROP_CACHE_ENTRY_DIRTY, Boolean.TRUE);
}
- properties.putAll(getData());
}
+ // Refresh the update policy property.
if (update.getProperties().contains(PROP_UPDATE_POLICY_ID)) {
- properties.put(PROP_UPDATE_POLICY_ID, getActiveUpdatePolicy().getID());
+ cachedProperties.put(PROP_UPDATE_POLICY_ID, getActiveUpdatePolicy().getID());
}
- // Save the update status result in the properties as well, it will be
- // written to the client update when client updates are completed from
- // cache.
- properties.put(PROP_UPDATE_STATUS, getStatus());
-
// If there is archive data available, calculate the requested changed value properties.
// Do not calculate the changed flags if the entry has been flushed.
if (entry.fArchiveProperties != null && flushCounter == entry.fFlushCounter) {
for (String updateProperty : update.getProperties()) {
if (updateProperty.startsWith(PROP_IS_CHANGED_PREFIX)) {
String changedPropertyName = updateProperty.substring(LENGTH_PROP_IS_CHANGED_PREFIX);
- Object newValue = properties.get(changedPropertyName);
+ Object newValue = cachedProperties.get(changedPropertyName);
Object oldValue = entry.fArchiveProperties.get(changedPropertyName);
if (oldValue != null) {
- properties.put(updateProperty, !oldValue.equals(newValue));
+ cachedProperties.put(updateProperty, !oldValue.equals(newValue));
}
}
}
@@ -1209,8 +1277,14 @@ public class AbstractCachingVMProvider extends AbstractVMProvider
DsfUIPlugin.debug("cacheSavedProperties(node = " + node + ", update = " + update + ", " + getData() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
- update.setAllProperties(properties);
- update.setStatus(getStatus());
+ // Fill in requested properties and status into the update.
+ for (String property : update.getProperties()) {
+ update.setProperty(property, cachedProperties.get(property));
+ }
+ PropertiesUpdateStatus updateStatus = PropertiesUpdateStatus.getPropertiesStatus(update);
+ updateStatus = PropertiesUpdateStatus.mergePropertiesStatus(
+ updateStatus, cachedStatus, update.getProperties());
+ update.setStatus(updateStatus);
update.done();
}
}));
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICacheEntry.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICacheEntry.java
new file mode 100644
index 00000000000..6e6d71e4e8e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICacheEntry.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.viewmodel.update;
+
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Cache entry in a caching VM provider.
+ *
+ * @see ICachingVMProvider
+ * @see ICachingVMProviderExtension2
+ *
+ * @since 2.2
+ */
+@ConfinedToDsfExecutor("")
+public interface ICacheEntry {
+
+ /**
+ * The VM node that this cache entry is for. This parameter is part of the
+ * key to finding the cache entry.
+ */
+ public IVMNode getNode();
+
+ /**
+ * The viewer input object that this cache entry is for. This parameter
+ * is part of the key to finding the cache entry.
+ */
+ public Object getViewerInput();
+
+ /**
+ * The element path that this cache entry is for. This parameter is part
+ * of the key to finding the cache entry.
+ */
+ public TreePath getElementPath();
+
+ /**
+ * Says whether this cache entry is currently marked as dirty. If a cache
+ * entry is dirty, it means that it contains stale data which has not been
+ * flushed as indicated by the cache's update policy.
+ * @return
+ */
+ public boolean isDirty();
+
+ /**
+ * Returns the a flag indicating whether the element pointing to this entry
+ * has children. Returns <code>null</code> if this value is not known by
+ * cache.
+ */
+ public Boolean getHasChildren();
+
+ /**
+ * Returns the count of children for the element belonging to this entry.
+ * Returns <code>null</code> if this value is not known by cache.
+ */
+ public Integer getChildCount();
+
+ /**
+ * Returns a map of children of the element belonging to this entry.
+ * The returned map contains integer keys which are indexes of the
+ * element's children. The values in the map are the child element.
+ * Returns <code>null</code> if this value is not known by cache.
+ */
+ public Map<Integer, Object> getChildren();
+
+ /**
+ * Returns map of properties of the element belonging to this entry.
+ * Returns <code>null</code> if this value is not known by cache.
+ */
+ public Map<String, Object> getProperties();
+
+ /**
+ * Returns the archived map of properties of the element belong to this
+ * entry. The archived properties are properties which were saved when
+ * the cache was last flushed, as indicated by the cache's active update
+ * policy. Returns <code>null</code> if this value is not known by cache.
+ */
+ public Map<String, Object> getArchiveProperties();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension2.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension2.java
new file mode 100644
index 00000000000..594ad6a7fe9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension2.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.viewmodel.update;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.jface.viewers.TreePath;
+
+
+/**
+ * Extension allowing access to the caching VM provider cache entries.
+ *
+ * @since 2.2
+ */
+public interface ICachingVMProviderExtension2 extends ICachingVMProvider {
+
+ /**
+ * Returns the cache entry for the given parameters. May return <code>null</code>
+ * if the cache entry does not exist in the cache.
+ */
+ public ICacheEntry getCacheEntry(IVMNode node, Object viewerInput, TreePath path);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicyExtension.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicyExtension.java
new file mode 100644
index 00000000000..30b386b5a84
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicyExtension.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.viewmodel.update;
+
+
+/**
+ * Extension to the VM Update policy which allows the policy to control how to
+ * update missing property values in a dirty cache entry.
+ *
+ * @since 2.2
+ */
+public interface IVMUpdatePolicyExtension extends IVMUpdatePolicy {
+
+ /**
+ * Determines whether the given dirty cache entry should have the given
+ * missing property updated.
+ *
+ * @param entry The dirty cache entry that is missing the given requested
+ * property.
+ * @param property Property missing from cache.
+ * @return If <code>true</code> cache can update the given missing property
+ * in the dirty cache entry with data from the VM node.
+ */
+ public boolean canUpdateDirtyProperty(ICacheEntry entry, String property);
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/IViewerUpdatesListenerConstants.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/IViewerUpdatesListenerConstants.java
new file mode 100644
index 00000000000..eca8593d9b4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/IViewerUpdatesListenerConstants.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.tests.dsf;
+
+/**
+ * Convenience interface with constants used by the test model update listener.
+ * @since 2.2
+ */
+public interface IViewerUpdatesListenerConstants {
+
+ public static final int LABEL_SEQUENCE_COMPLETE = 0X00000001;
+ public static final int CONTENT_SEQUENCE_COMPLETE = 0X00000002;
+ public static final int CONTENT_SEQUENCE_STARTED = 0X00020000;
+ public static final int LABEL_UPDATES = 0X00000004;
+ public static final int LABEL_SEQUENCE_STARTED = 0X00040000;
+ public static final int HAS_CHILDREN_UPDATES = 0X00000008;
+ public static final int HAS_CHILDREN_UPDATES_STARTED = 0X00080000;
+ public static final int CHILD_COUNT_UPDATES = 0X00000010;
+ public static final int CHILD_COUNT_UPDATES_STARTED = 0X00100000;
+ public static final int CHILDREN_UPDATES = 0X00000020;
+ public static final int CHILDREN_UPDATES_STARTED = 0X00200000;
+ public static final int MODEL_CHANGED_COMPLETE = 0X00000040;
+ public static final int MODEL_PROXIES_INSTALLED = 0X00000080;
+ public static final int STATE_SAVE_COMPLETE = 0X00000100;
+ public static final int STATE_SAVE_STARTED = 0X01000000;
+ public static final int STATE_RESTORE_COMPLETE = 0X00000200;
+ public static final int STATE_RESTORE_STARTED = 0X02000000;
+ public static final int STATE_UPDATES = 0X00000400;
+ public static final int STATE_UPDATES_STARTED = 0X04000000;
+ public static final int PROPERTY_UPDATES = 0X00000800;
+ public static final int PROPERTY_UPDATES_STARTED = 0X08000000;
+
+ public static final int VIEWER_UPDATES_RUNNING = 0X00001000;
+ public static final int LABEL_UPDATES_RUNNING = 0X00002000;
+
+ public static final int VIEWER_UPDATES_STARTED = HAS_CHILDREN_UPDATES_STARTED | CHILD_COUNT_UPDATES_STARTED | CHILDREN_UPDATES_STARTED;
+
+ public static final int LABEL_COMPLETE = LABEL_SEQUENCE_COMPLETE | LABEL_UPDATES | LABEL_UPDATES_RUNNING;
+ public static final int CONTENT_UPDATES = HAS_CHILDREN_UPDATES | CHILD_COUNT_UPDATES | CHILDREN_UPDATES;
+ public static final int CONTENT_COMPLETE = CONTENT_UPDATES | CONTENT_SEQUENCE_COMPLETE | VIEWER_UPDATES_RUNNING;
+
+ public static final int ALL_UPDATES_COMPLETE = LABEL_COMPLETE | CONTENT_COMPLETE | MODEL_PROXIES_INSTALLED | LABEL_UPDATES_RUNNING | VIEWER_UPDATES_RUNNING;
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ServiceEventWaitor.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ServiceEventWaitor.java
index 6b28f74b10d..9e25b8924bd 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ServiceEventWaitor.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ServiceEventWaitor.java
@@ -12,6 +12,7 @@ package org.eclipse.cdt.tests.dsf;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.swt.widgets.Display;
/*
* This class provides a way to wait for an asynchronous ServerEvent
@@ -34,14 +35,16 @@ public class ServiceEventWaitor<V> {
/* The type of event to wait for */
private Class<V> fEventTypeClass;
- private DsfSession fSession;
+ private final DsfSession fSession;
private V fEvent;
+ private final Display fDisplay;
/* Empty contructor. registerForEvent() should be called when
* this constructor is used.
*/
public ServiceEventWaitor(DsfSession session) {
+ fDisplay = Display.getDefault();
fSession = session;
}
@@ -62,10 +65,12 @@ public class ServiceEventWaitor<V> {
fSession.addServiceEventListener(this, null);
}
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- if (fEventTypeClass != null) fSession.removeServiceEventListener(this);
+ public DsfSession getSession() {
+ return fSession;
+ }
+
+ public void dispose() {
+ if (fEventTypeClass != null) fSession.removeServiceEventListener(this);
}
/* Block until 'timeout' or the previously specified event has been
@@ -80,7 +85,15 @@ public class ServiceEventWaitor<V> {
// The event might have already been received
if (fEvent != null) return fEvent;
- wait(timeout);
+ long timeoutTime = System.currentTimeMillis() + timeout;
+ while (timeoutTime > System.currentTimeMillis()) {
+ if (fEvent != null) {
+ break;
+ }
+ if (!fDisplay.readAndDispatch()) {
+ Thread.sleep(0);
+ }
+ }
if (fEvent == null) {
throw new Exception("Timed out waiting for ServiceEvent: " + fEventTypeClass.getName());
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ViewerUpdatesListener.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ViewerUpdatesListener.java
new file mode 100644
index 00000000000..33985c1d252
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ViewerUpdatesListener.java
@@ -0,0 +1,644 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.tests.dsf;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import junit.framework.Assert;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+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.ILabelUpdate;
+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.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * @since 2.2
+ */
+public class ViewerUpdatesListener
+ implements IViewerUpdateListener, ILabelUpdateListener, IModelChangedListener, IViewerUpdatesListenerConstants,
+ IStateUpdateListener, IPropertiesUpdateListener
+{
+ private ITreeModelViewer fViewer;
+
+ private boolean fFailOnRedundantUpdates;
+ private Set<IViewerUpdate> fRedundantUpdates = new HashSet<IViewerUpdate>();
+
+ private boolean fFailOnMultipleModelUpdateSequences;
+ private boolean fMultipleModelUpdateSequencesObserved;
+ private boolean fFailOnMultipleLabelUpdateSequences;
+ private boolean fMultipleLabelUpdateSequencesObserved;
+
+ private Set<TreePath> fHasChildrenUpdatesScheduled = makeTreePathSet();
+ private Set<IViewerUpdate> fHasChildrenUpdatesRunning = new HashSet<IViewerUpdate>();
+ private Set<IViewerUpdate> fHasChildrenUpdatesCompleted = new HashSet<IViewerUpdate>();
+ private Map<TreePath, Set<Integer>> fChildrenUpdatesScheduled = makeTreePathMap();
+ private Set<IViewerUpdate> fChildrenUpdatesRunning = new HashSet<IViewerUpdate>();
+ private Set<IViewerUpdate> fChildrenUpdatesCompleted = new HashSet<IViewerUpdate>();
+ private Set<TreePath> fChildCountUpdatesScheduled = makeTreePathSet();
+ private Set<IViewerUpdate> fChildCountUpdatesRunning = new HashSet<IViewerUpdate>();
+ private Set<IViewerUpdate> fChildCountUpdatesCompleted = new HashSet<IViewerUpdate>();
+ private Set<TreePath> fLabelUpdates = makeTreePathSet();
+ private Set<IViewerUpdate> fLabelUpdatesRunning = new HashSet<IViewerUpdate>();
+ private Set<IViewerUpdate> fLabelUpdatesCompleted = new HashSet<IViewerUpdate>();
+ private Set<TreePath> fPropertiesUpdates = makeTreePathSet();
+ private Set<IViewerUpdate> fPropertiesUpdatesRunning = new HashSet<IViewerUpdate>();
+ private Set<IViewerUpdate> fPropertiesUpdatesCompleted = new HashSet<IViewerUpdate>();
+// private Set<TreePath> fProxyModels = new HashSet<TreePath>();
+ private Set<TreePath> fStateUpdates = makeTreePathSet();
+ private boolean fContentSequenceStarted;
+ private boolean fContentSequenceComplete;
+ private boolean fLabelUpdatesStarted;
+ private boolean fLabelSequenceComplete;
+ private boolean fModelChangedComplete;
+ private boolean fStateSaveStarted;
+ private boolean fStateSaveComplete;
+ private boolean fStateRestoreStarted;
+ private boolean fStateRestoreComplete;
+ private int fContentUpdatesCounter;
+ private int fLabelUpdatesCounter;
+ private int fPropertiesUpdatesCounter;
+ private int fTimeoutInterval = 60000;
+ private long fTimeoutTime;
+
+ protected Set<TreePath> makeTreePathSet() {
+ return new HashSet<TreePath>();
+ }
+
+ protected <V> Map<TreePath, V> makeTreePathMap() {
+ return new HashMap<TreePath, V>();
+ }
+
+
+ public ViewerUpdatesListener(ITreeModelViewer viewer, boolean failOnRedundantUpdates, boolean failOnMultipleModelUpdateSequences) {
+ this(viewer);
+ setFailOnRedundantUpdates(failOnRedundantUpdates);
+ setFailOnMultipleModelUpdateSequences(failOnMultipleModelUpdateSequences);
+ }
+
+ public ViewerUpdatesListener() {
+ // No viewer to register with. Client will have to register the listener manually.
+ }
+
+ public ViewerUpdatesListener(ITreeModelViewer viewer) {
+ fViewer = viewer;
+ fViewer.addLabelUpdateListener(this);
+ fViewer.addModelChangedListener(this);
+ fViewer.addStateUpdateListener(this);
+ fViewer.addViewerUpdateListener(this);
+ }
+
+ public void dispose() {
+ if (fViewer != null) {
+ fViewer.removeLabelUpdateListener(this);
+ fViewer.removeModelChangedListener(this);
+ fViewer.removeStateUpdateListener(this);
+ fViewer.removeViewerUpdateListener(this);
+ fViewer = null;
+ }
+ }
+
+
+ public void setFailOnRedundantUpdates(boolean failOnRedundantUpdates) {
+ fFailOnRedundantUpdates = failOnRedundantUpdates;
+ }
+
+ public void setFailOnMultipleModelUpdateSequences(boolean failOnMultipleLabelUpdateSequences) {
+ fFailOnMultipleModelUpdateSequences = failOnMultipleLabelUpdateSequences;
+ }
+
+ public void setFailOnMultipleLabelUpdateSequences(boolean failOnMultipleLabelUpdateSequences) {
+ fFailOnMultipleLabelUpdateSequences = failOnMultipleLabelUpdateSequences;
+ }
+
+ /**
+ * Sets the the maximum amount of time (in milliseconds) that the update listener
+ * is going to wait. If set to -1, the listener will wait indefinitely.
+ */
+ public void setTimeoutInterval(int milis) {
+ fTimeoutInterval = milis;
+ }
+
+ public void reset() {
+ fRedundantUpdates.clear();
+ fMultipleLabelUpdateSequencesObserved = false;
+ fMultipleModelUpdateSequencesObserved = false;
+ fHasChildrenUpdatesScheduled.clear();
+ fHasChildrenUpdatesRunning.clear();
+ fHasChildrenUpdatesCompleted.clear();
+ fChildrenUpdatesScheduled.clear();
+ fChildrenUpdatesRunning.clear();
+ fChildrenUpdatesCompleted.clear();
+ fChildCountUpdatesScheduled.clear();
+ fChildCountUpdatesRunning.clear();
+ fChildCountUpdatesCompleted.clear();
+ fLabelUpdates.clear();
+ fLabelUpdatesRunning.clear();
+ fLabelUpdatesCompleted.clear();
+// fProxyModels.clear();
+ fContentSequenceStarted = false;
+ fContentSequenceComplete = false;
+ fLabelUpdatesStarted = false;
+ fLabelSequenceComplete = false;
+ fStateSaveStarted = false;
+ fStateSaveComplete = false;
+ fStateRestoreStarted = false;
+ fStateRestoreComplete = false;
+ fTimeoutTime = System.currentTimeMillis() + fTimeoutInterval;
+ resetModelChanged();
+ }
+
+ public void resetModelChanged() {
+ fModelChangedComplete = false;
+ }
+
+ public void addHasChildrenUpdate(TreePath path) {
+ fHasChildrenUpdatesScheduled.add(path);
+ }
+
+ public void removeHasChildrenUpdate(TreePath path) {
+ fHasChildrenUpdatesScheduled.remove(path);
+ }
+
+ public void addChildCountUpdate(TreePath path) {
+ fChildCountUpdatesScheduled.add(path);
+ }
+
+ public void removeChildreCountUpdate(TreePath path) {
+ fChildCountUpdatesScheduled.remove(path);
+ }
+
+ public void addChildreUpdate(TreePath path, int index) {
+ Set<Integer> childrenIndexes = fChildrenUpdatesScheduled.get(path);
+ if (childrenIndexes == null) {
+ childrenIndexes = new TreeSet<Integer>();
+ fChildrenUpdatesScheduled.put(path, childrenIndexes);
+ }
+ childrenIndexes.add(new Integer(index));
+ }
+
+ public void removeChildrenUpdate(TreePath path, int index) {
+ Set<Integer> childrenIndexes = fChildrenUpdatesScheduled.get(path);
+ if (childrenIndexes != null) {
+ childrenIndexes.remove(new Integer(index));
+ if (childrenIndexes.isEmpty()) {
+ fChildrenUpdatesScheduled.remove(path);
+ }
+ }
+ }
+
+ public void addLabelUpdate(TreePath path) {
+ fLabelUpdates.add(path);
+ }
+
+ public void addPropertiesUpdate(TreePath path) {
+ fPropertiesUpdates.add(path);
+ }
+
+ public void removeLabelUpdate(TreePath path) {
+ fLabelUpdates.remove(path);
+ }
+
+ public void addStateUpdate(TreePath path) {
+ fStateUpdates.add(path);
+ }
+
+ public void removeStateUpdate(TreePath path) {
+ fStateUpdates.remove(path);
+ }
+
+
+ public boolean isFinished() {
+ return isFinished(ALL_UPDATES_COMPLETE);
+ }
+
+ public boolean isTimedOut() {
+ return fTimeoutInterval > 0 && fTimeoutTime < System.currentTimeMillis();
+ }
+
+ public boolean isFinished(int flags) {
+ if (isTimedOut()) {
+ throw new RuntimeException("Timed Out: " + toString(flags));
+ }
+
+ if (fFailOnRedundantUpdates && !fRedundantUpdates.isEmpty()) {
+ Assert.fail("Redundant Updates: " + fRedundantUpdates.toString());
+ }
+ if (fFailOnMultipleLabelUpdateSequences && !fMultipleLabelUpdateSequencesObserved) {
+ Assert.fail("Multiple label update sequences detected");
+ }
+ if (fFailOnMultipleModelUpdateSequences && fMultipleModelUpdateSequencesObserved) {
+ Assert.fail("Multiple viewer update sequences detected");
+ }
+
+ if ( (flags & LABEL_SEQUENCE_COMPLETE) != 0) {
+ if (!fLabelSequenceComplete) return false;
+ }
+ if ( (flags & LABEL_SEQUENCE_STARTED) != 0) {
+ if (!fLabelUpdatesStarted) return false;
+ }
+ if ( (flags & LABEL_UPDATES) != 0) {
+ if (!fLabelUpdates.isEmpty()) return false;
+ }
+ if ( (flags & CONTENT_SEQUENCE_STARTED) != 0) {
+ if (!fContentSequenceStarted) return false;
+ }
+ if ( (flags & CONTENT_SEQUENCE_COMPLETE) != 0) {
+ if (!fContentSequenceComplete) return false;
+ }
+ if ( (flags & HAS_CHILDREN_UPDATES_STARTED) != 0) {
+ if (fHasChildrenUpdatesRunning.isEmpty() && fHasChildrenUpdatesCompleted.isEmpty()) return false;
+ }
+ if ( (flags & HAS_CHILDREN_UPDATES) != 0) {
+ if (!fHasChildrenUpdatesScheduled.isEmpty()) return false;
+ }
+ if ( (flags & CHILD_COUNT_UPDATES_STARTED) != 0) {
+ if (fChildCountUpdatesRunning.isEmpty() && fChildCountUpdatesCompleted.isEmpty()) return false;
+ }
+ if ( (flags & CHILD_COUNT_UPDATES) != 0) {
+ if (!fChildCountUpdatesScheduled.isEmpty()) return false;
+ }
+ if ( (flags & CHILDREN_UPDATES_STARTED) != 0) {
+ if (fChildrenUpdatesRunning.isEmpty() && fChildrenUpdatesCompleted.isEmpty()) return false;
+ }
+ if ( (flags & CHILDREN_UPDATES) != 0) {
+ if (!fChildrenUpdatesScheduled.isEmpty()) return false;
+ }
+ if ( (flags & MODEL_CHANGED_COMPLETE) != 0) {
+ if (!fModelChangedComplete) return false;
+ }
+ if ( (flags & STATE_SAVE_COMPLETE) != 0) {
+ if (!fStateSaveComplete) return false;
+ }
+ if ( (flags & STATE_SAVE_STARTED) != 0) {
+ if (!fStateSaveStarted) return false;
+ }
+ if ( (flags & STATE_RESTORE_COMPLETE) != 0) {
+ if (!fStateRestoreComplete) return false;
+ }
+ if ( (flags & STATE_RESTORE_STARTED) != 0) {
+ if (!fStateRestoreStarted) return false;
+ }
+// if ( (flags & MODEL_PROXIES_INSTALLED) != 0) {
+// if (fProxyModels.size() != 0) return false;
+// }
+ if ( (flags & VIEWER_UPDATES_RUNNING) != 0) {
+ if (fContentUpdatesCounter != 0) {
+ return false;
+ }
+ }
+ if ( (flags & LABEL_UPDATES_RUNNING) != 0) {
+ if (fLabelUpdatesCounter != 0) {
+ return false;
+ }
+ }
+ if ( (flags & PROPERTY_UPDATES) != 0) {
+ if (!fPropertiesUpdates.isEmpty()) return false;
+ }
+ if ( (flags & PROPERTY_UPDATES_STARTED) != 0) {
+ if (fPropertiesUpdatesRunning.isEmpty() && fPropertiesUpdatesCompleted.isEmpty()) return false;
+ }
+
+ return true;
+ }
+
+ public void updateStarted(IViewerUpdate update) {
+ synchronized (this) {
+ fContentUpdatesCounter++;
+ if (update instanceof IHasChildrenUpdate) {
+ fHasChildrenUpdatesRunning.add(update);
+ } if (update instanceof IChildrenCountUpdate) {
+ fChildCountUpdatesRunning.add(update);
+ } else if (update instanceof IChildrenUpdate) {
+ fChildCountUpdatesRunning.add(update);
+ }
+ }
+ }
+
+ public void updateComplete(IViewerUpdate update) {
+ synchronized (this) {
+ fContentUpdatesCounter--;
+ }
+
+ if (!update.isCanceled()) {
+ if (update instanceof IHasChildrenUpdate) {
+ fHasChildrenUpdatesRunning.remove(update);
+ fHasChildrenUpdatesCompleted.add(update);
+ if (!fHasChildrenUpdatesScheduled.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
+ fRedundantUpdates.add(update);
+ }
+ } if (update instanceof IChildrenCountUpdate) {
+ fChildCountUpdatesRunning.remove(update);
+ fChildCountUpdatesCompleted.add(update);
+ if (!fChildCountUpdatesScheduled.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
+ fRedundantUpdates.add(update);
+ }
+ } else if (update instanceof IChildrenUpdate) {
+ fChildrenUpdatesRunning.remove(update);
+ fChildrenUpdatesCompleted.add(update);
+
+ int start = ((IChildrenUpdate)update).getOffset();
+ int end = start + ((IChildrenUpdate)update).getLength();
+
+ Set<Integer> childrenIndexes = fChildrenUpdatesScheduled.get(update.getElementPath());
+ if (childrenIndexes != null) {
+ for (int i = start; i < end; i++) {
+ childrenIndexes.remove(new Integer(i));
+ }
+ if (childrenIndexes.isEmpty()) {
+ fChildrenUpdatesScheduled.remove(update.getElementPath());
+ }
+ } else if (fFailOnRedundantUpdates) {
+ fRedundantUpdates.add(update);
+ }
+ }
+ }
+ }
+
+ public void viewerUpdatesBegin() {
+ if (fFailOnMultipleModelUpdateSequences && fContentSequenceComplete) {
+ fMultipleModelUpdateSequencesObserved = true;
+ }
+ fContentSequenceStarted = true;
+ }
+
+ public void viewerUpdatesComplete() {
+ fContentSequenceComplete = true;
+ }
+
+ public void labelUpdateComplete(ILabelUpdate update) {
+ synchronized (this) {
+ fLabelUpdatesRunning.remove(update);
+ fLabelUpdatesCompleted.add(update);
+ fLabelUpdatesCounter--;
+ }
+ if (!fLabelUpdates.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
+ fRedundantUpdates.add(update);
+ }
+ }
+
+ public void labelUpdateStarted(ILabelUpdate update) {
+ synchronized (this) {
+ fLabelUpdatesRunning.add(update);
+ fLabelUpdatesCounter++;
+ }
+ }
+
+ public void labelUpdatesBegin() {
+ if (fFailOnMultipleLabelUpdateSequences && fLabelSequenceComplete) {
+ fMultipleLabelUpdateSequencesObserved = true;
+ }
+ fLabelUpdatesStarted = true;
+ }
+
+ public void labelUpdatesComplete() {
+ fLabelSequenceComplete = true;
+ }
+
+ public void propertiesUpdatesStarted(IPropertiesUpdate[] updates) {
+ for (IPropertiesUpdate update : updates) {
+ fPropertiesUpdatesRunning.add(update);
+ fPropertiesUpdatesCounter++;
+ }
+ }
+
+ public void propertiesUpdateCompleted(IPropertiesUpdate update) {
+ synchronized (this) {
+ fPropertiesUpdatesRunning.remove(update);
+ fPropertiesUpdatesCompleted.add(update);
+ fPropertiesUpdatesCounter--;
+ }
+ if (!fPropertiesUpdates.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
+ fRedundantUpdates.add(update);
+ }
+
+ }
+
+ public void modelChanged(IModelDelta delta, IModelProxy proxy) {
+ fModelChangedComplete = true;
+ }
+
+ public void stateRestoreUpdatesBegin(Object input) {
+ fStateRestoreStarted = true;
+ }
+
+ public void stateRestoreUpdatesComplete(Object input) {
+ fStateRestoreComplete = true;
+ }
+
+ public void stateSaveUpdatesBegin(Object input) {
+ fStateSaveStarted = true;
+ }
+
+ public void stateSaveUpdatesComplete(Object input) {
+ fStateSaveComplete = true;
+ }
+
+ public void stateUpdateComplete(Object input, IViewerUpdate update) {
+ }
+
+ public void stateUpdateStarted(Object input, IViewerUpdate update) {
+ }
+
+ private String toString(int flags) {
+ StringBuffer buf = new StringBuffer("Viewer Update Listener");
+
+ if (fFailOnRedundantUpdates) {
+ buf.append("\n\t");
+ buf.append("fRedundantUpdates = ");
+ buf.append( toStringViewerUpdatesSet(fRedundantUpdates) );
+ }
+ if (fFailOnMultipleLabelUpdateSequences) {
+ buf.append("\n\t");
+ buf.append("fMultipleLabelUpdateSequencesObserved = " + fMultipleLabelUpdateSequencesObserved);
+ }
+ if (fFailOnMultipleModelUpdateSequences) {
+ buf.append("\n\t");
+ buf.append("fMultipleModelUpdateSequencesObserved = " + fMultipleModelUpdateSequencesObserved);
+ }
+ if ( (flags & LABEL_SEQUENCE_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fLabelSequenceComplete = " + fLabelSequenceComplete);
+ }
+ if ( (flags & LABEL_UPDATES_RUNNING) != 0) {
+ buf.append("\n\t");
+ buf.append("fLabelUpdatesRunning = " + fLabelUpdatesCounter);
+ }
+ if ( (flags & LABEL_SEQUENCE_STARTED) != 0) {
+ buf.append("\n\t");
+ buf.append("fLabelUpdatesRunning = ");
+ buf.append( toStringViewerUpdatesSet(fLabelUpdatesRunning) );
+ buf.append("\n\t");
+ buf.append("fLabelUpdatesCompleted = ");
+ buf.append( toStringViewerUpdatesSet(fLabelUpdatesCompleted) );
+ }
+ if ( (flags & LABEL_UPDATES) != 0) {
+ buf.append("\n\t");
+ buf.append("fLabelUpdates = ");
+ buf.append( toString(fLabelUpdates) );
+ }
+ if ( (flags & CONTENT_SEQUENCE_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fContentSequenceComplete = " + fContentSequenceComplete);
+ }
+ if ( (flags & VIEWER_UPDATES_RUNNING) != 0) {
+ buf.append("\n\t");
+ buf.append("fContentUpdatesCounter = " + fContentUpdatesCounter);
+ }
+ if ( (flags & HAS_CHILDREN_UPDATES_STARTED) != 0) {
+ buf.append("\n\t");
+ buf.append("fHasChildrenUpdatesRunning = ");
+ buf.append( toStringViewerUpdatesSet(fHasChildrenUpdatesRunning) );
+ buf.append("\n\t");
+ buf.append("fHasChildrenUpdatesCompleted = ");
+ buf.append( toStringViewerUpdatesSet(fHasChildrenUpdatesCompleted) );
+ }
+ if ( (flags & HAS_CHILDREN_UPDATES) != 0) {
+ buf.append("\n\t");
+ buf.append("fHasChildrenUpdates = ");
+ buf.append( toString(fHasChildrenUpdatesScheduled) );
+ }
+ if ( (flags & CHILD_COUNT_UPDATES_STARTED) != 0) {
+ buf.append("\n\t");
+ buf.append("fChildCountUpdatesRunning = ");
+ buf.append( toStringViewerUpdatesSet(fChildCountUpdatesRunning) );
+ buf.append("\n\t");
+ buf.append("fChildCountUpdatesCompleted = ");
+ buf.append( toStringViewerUpdatesSet(fChildCountUpdatesCompleted) );
+ }
+ if ( (flags & CHILD_COUNT_UPDATES) != 0) {
+ buf.append("\n\t");
+ buf.append("fChildCountUpdates = ");
+ buf.append( toString(fChildCountUpdatesScheduled) );
+ }
+ if ( (flags & CHILDREN_UPDATES_STARTED) != 0) {
+ buf.append("\n\t");
+ buf.append("fChildrenUpdatesRunning = ");
+ buf.append( fChildrenUpdatesRunning );
+ buf.append("\n\t");
+ buf.append("fChildrenUpdatesCompleted = ");
+ buf.append( toStringViewerUpdatesSet(fChildrenUpdatesCompleted) );
+ }
+ if ( (flags & CHILDREN_UPDATES) != 0) {
+ buf.append("\n\t");
+ buf.append("fChildrenUpdates = ");
+ buf.append( toStringTreePathMap(fChildrenUpdatesScheduled) );
+ }
+ if ( (flags & MODEL_CHANGED_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fModelChangedComplete = " + fModelChangedComplete);
+ }
+ if ( (flags & STATE_SAVE_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fStateSaveComplete = " + fStateSaveComplete);
+ }
+ if ( (flags & STATE_RESTORE_COMPLETE) != 0) {
+ buf.append("\n\t");
+ buf.append("fStateRestoreComplete = " + fStateRestoreComplete);
+ }
+// if ( (flags & MODEL_PROXIES_INSTALLED) != 0) {
+// buf.append("\n\t");
+// buf.append("fProxyModels = " + fProxyModels);
+// }
+ if ( (flags & PROPERTY_UPDATES_STARTED) != 0) {
+ buf.append("\n\t");
+ buf.append("fPropertiesUpdatesRunning = ");
+ buf.append(toStringViewerUpdatesSet(fPropertiesUpdatesRunning));
+ buf.append("\n\t");
+ buf.append("fPropertiesUpdatesCompleted = " + fPropertiesUpdatesCompleted);
+ }
+ if ( (flags & PROPERTY_UPDATES) != 0) {
+ buf.append("\n\t");
+ buf.append("fPropertiesUpdates = ");
+ buf.append( toString(fPropertiesUpdates) );
+ }
+ if (fTimeoutInterval > 0) {
+ buf.append("\n\t");
+ buf.append("fTimeoutInterval = " + fTimeoutInterval);
+ }
+ return buf.toString();
+ }
+
+ private String toString(Set<TreePath> set) {
+ if (set.isEmpty()) {
+ return "(EMPTY)";
+ }
+ StringBuffer buf = new StringBuffer();
+ for (Iterator<TreePath> itr = set.iterator(); itr.hasNext(); ) {
+ buf.append("\n\t\t");
+ buf.append(toStringTreePath(itr.next()));
+ }
+ return buf.toString();
+ }
+
+ private String toStringViewerUpdatesSet(Set<IViewerUpdate> set) {
+ if (set.isEmpty()) {
+ return "(EMPTY)";
+ }
+ StringBuffer buf = new StringBuffer();
+ for (Iterator<IViewerUpdate> itr = set.iterator(); itr.hasNext(); ) {
+ buf.append("\n\t\t");
+ buf.append(toStringTreePath((itr.next()).getElementPath()));
+ }
+ return buf.toString();
+ }
+
+ private String toStringTreePathMap(Map<TreePath, Set<Integer>> map) {
+ if (map.isEmpty()) {
+ return "(EMPTY)";
+ }
+ StringBuffer buf = new StringBuffer();
+ for (Iterator<TreePath> itr = map.keySet().iterator(); itr.hasNext(); ) {
+ buf.append("\n\t\t");
+ TreePath path = itr.next();
+ buf.append(toStringTreePath(path));
+ Set<?> updates = map.get(path);
+ buf.append(" = ");
+ buf.append(updates.toString());
+ }
+ return buf.toString();
+ }
+
+ private String toStringTreePath(TreePath path) {
+ if (path.getSegmentCount() == 0) {
+ return "/";
+ }
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ buf.append("/");
+ buf.append(path.getSegment(i));
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toString(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE | STATE_RESTORE_COMPLETE |
+ VIEWER_UPDATES_STARTED | LABEL_SEQUENCE_STARTED | PROPERTY_UPDATES | PROPERTY_UPDATES_STARTED);
+ }
+}
+
+
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTest1.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTest1.java
new file mode 100644
index 00000000000..fb2aa034d40
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTest1.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.tests.dsf.debug.vm.launch;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.ILaunchVMConstants;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.VMPropertiesUpdate;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.tests.dsf.IViewerUpdatesListenerConstants;
+import org.eclipse.cdt.tests.dsf.vm.TestModelUpdatesListener;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.DebugPlugin;
+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.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.widgets.Display;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class VMTest1 extends VMTestBase implements IViewerUpdatesListenerConstants {
+
+ @Override
+ protected String getProgramPath() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("samples/example.pda"));
+ return programFile.getPath();
+ }
+
+ @Test
+ public void testRun() throws Throwable {
+
+ Display display = Display.getDefault();
+
+ final VirtualTreeModelViewer dv = new VirtualTreeModelViewer(
+ display, 0, new PresentationContext(IDebugUIConstants.ID_DEBUG_VIEW));
+
+ TestModelUpdatesListener listener = new TestModelUpdatesListener(dv, false, false);
+
+ // Wait for container expand delta, sent by the model upon DV install event.
+ final boolean[] containerExpandReceived = new boolean[1];
+ containerExpandReceived[0] = false;
+ dv.addModelChangedListener(new IModelChangedListener() {
+ public void modelChanged(IModelDelta delta, IModelProxy proxy) {
+ delta.accept(new IModelDeltaVisitor() {
+ public boolean visit(IModelDelta delta, int depth) {
+ if (delta.getElement() instanceof IDMVMContext &&
+ ((IDMVMContext)delta.getElement()).getDMContext() instanceof IContainerDMContext &&
+ (delta.getFlags() & IModelDelta.EXPAND) != 0)
+ {
+ containerExpandReceived[0] = true;
+ return false;
+ }
+ return true;
+ }
+ });
+ }
+ });
+
+ dv.setInput(DebugPlugin.getDefault().getLaunchManager());
+
+ while(!containerExpandReceived[0]) {
+ if (!display.readAndDispatch()) display.sleep();
+ }
+
+ listener.reset();
+
+ // TODO: need to wait for the install delta for the launch to be processed
+ while (!listener.isFinished(CONTENT_SEQUENCE_COMPLETE)) {
+ if (!display.readAndDispatch()) display.sleep();
+ }
+
+ // Find our launch
+ int launchIdx = dv.findElementIndex(TreePath.EMPTY, getLaunch());
+ Assert.assertTrue(-1 != launchIdx);
+
+ // Find the debug container
+ TreePath launchPath = TreePath.EMPTY.createChildPath(getLaunch());
+ int launchChildCount = dv.getChildCount(launchPath);
+ IDMVMContext _containerVMC = null;
+ for (int i = 0; i < launchChildCount; i++) {
+ Object launchChild = dv.getChildElement(launchPath, i);
+ if (launchChild instanceof IDMVMContext &&
+ ((IDMVMContext)launchChild).getDMContext() instanceof IContainerDMContext)
+ {
+ _containerVMC = (IDMVMContext)launchChild;
+ }
+ }
+ Assert.assertNotNull(_containerVMC);
+ final IDMVMContext containerVMC = _containerVMC;
+ final TreePath containerPath = launchPath.createChildPath(containerVMC);
+ final IElementPropertiesProvider containerPropProvider =
+ (IElementPropertiesProvider)containerVMC.getAdapter(IElementPropertiesProvider.class);
+ Assert.assertNotNull(containerPropProvider);
+
+ // Check if container is suspended.
+ Query<Map<String,Object>> suspendedQuery = new Query<Map<String,Object>>() {
+ @Override
+ protected void execute(DataRequestMonitor<Map<String, Object>> rm) {
+ Set<String> properties = new HashSet<String>();
+ properties.add(ILaunchVMConstants.PROP_IS_SUSPENDED);
+
+ containerPropProvider.update( new VMPropertiesUpdate[] {
+ new VMPropertiesUpdate(properties, containerPath, dv.getInput(), dv.getPresentationContext(), rm) });
+ }
+ };
+ suspendedQuery.run();
+
+ // Wait for the properties update to complete
+ while (!suspendedQuery.isDone()) {
+ if (!display.readAndDispatch()) display.sleep();
+ }
+
+ Map<String,Object> properties = suspendedQuery.get();
+ Assert.assertEquals(Boolean.TRUE, properties.get(ILaunchVMConstants.PROP_IS_SUSPENDED));
+
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTestBase.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTestBase.java
new file mode 100644
index 00000000000..8bb546446fc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/debug/vm/launch/VMTestBase.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Ericsson 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:
+ * Ericsson - Initial Implementation
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.debug.vm.launch;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.DsfSession.SessionStartedListener;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch;
+import org.eclipse.cdt.tests.dsf.ServiceEventWaitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+/**
+ * This is the base class for the GDB/MI Unit tests.
+ * It provides the @Before and @After methods which setup
+ * and teardown the launch, for each test.
+ * If these methods are overwridden by a subclass, the new method
+ * must call super.baseSetup or super.baseTeardown itself, if this
+ * code is to be run.
+ */
+public class VMTestBase {
+
+ private PDALaunch fLaunch;
+ public PDALaunch getPDALaunch() { return fLaunch; }
+
+ @BeforeClass
+ public static void baseBeforeClassMethod() {
+ DebugUIPlugin.getDefault().getPreferenceStore().setValue(
+ IInternalDebugUIConstants.PREF_SWITCH_TO_PERSPECTIVE, MessageDialogWithToggle.NEVER);
+ DebugUIPlugin.getDefault().getPreferenceStore().setValue(
+ IInternalDebugUIConstants.PREF_SWITCH_PERSPECTIVE_ON_SUSPEND, MessageDialogWithToggle.NEVER);
+ }
+
+ @Before
+ public void baseBeforeMethod() throws Exception {
+ Map<String, Object> attrs = new HashMap<String, Object>();
+
+ initLaunchAttributes(attrs);
+
+ System.out.println("====================================================================");
+ System.out.println("Launching test application: " + attrs.get(PDAPlugin.ATTR_PDA_PROGRAM));
+ System.out.println("====================================================================");
+
+ ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
+ ILaunchConfigurationType lcType = launchMgr.getLaunchConfigurationType("org.eclipse.cdt.examples.dsf.pda.launchType");
+ assert lcType != null;
+
+ ILaunchConfigurationWorkingCopy lcWorkingCopy = lcType.newInstance(
+ null,
+ launchMgr.generateUniqueLaunchConfigurationNameFrom("Test Launch")); //$NON-NLS-1$
+ assert lcWorkingCopy != null;
+ lcWorkingCopy.setAttributes(attrs);
+
+ final ILaunchConfiguration lc = lcWorkingCopy.doSave();
+ assert lc != null;
+
+ final ServiceEventWaitor<?> eventWaitor[] = new ServiceEventWaitor<?>[1];
+
+ SessionStartedListener newSessionListener = new SessionStartedListener() {
+ public void sessionStarted(DsfSession session) {
+ eventWaitor[0] = new ServiceEventWaitor<IStartedDMEvent>(session, IStartedDMEvent.class);
+ }
+ };
+
+ DsfSession.addSessionStartedListener(newSessionListener);
+ try {
+ fLaunch = (PDALaunch)lc.launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor());
+ Assert.assertNotNull(fLaunch);
+ Assert.assertNotNull(eventWaitor[0]);
+ Assert.assertSame(fLaunch.getSession(), eventWaitor[0].getSession());
+ eventWaitor[0].waitForEvent(60000);
+ } finally {
+ DsfSession.removeSessionStartedListener(newSessionListener);
+ if (eventWaitor[0] != null) {
+ eventWaitor[0].dispose();
+ }
+ }
+ }
+
+ protected void initLaunchAttributes(Map<String, Object> attrs) {
+ attrs.put(PDAPlugin.ATTR_PDA_PROGRAM, getProgramPath());
+ }
+
+ protected String getProgramPath() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("samples/example.pda"));
+ return programFile.getPath();
+ }
+
+ protected ILaunch getLaunch() {
+ return fLaunch;
+ }
+
+ @After
+ public void baseAfterMethod() throws Exception {
+ if (fLaunch != null) {
+ fLaunch.terminate();
+ fLaunch = null;
+ }
+
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/DummyFormattedValueService.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/DummyFormattedValueService.java
new file mode 100644
index 00000000000..ae105165c4f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/DummyFormattedValueService.java
@@ -0,0 +1,58 @@
+package org.eclipse.cdt.tests.dsf.vm;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.osgi.framework.BundleContext;
+
+public class DummyFormattedValueService extends AbstractDsfService implements IFormattedValues {
+
+ public static String DUMMY_FORMAT = "dummy";
+ public static String[] AVAILABLE_FORMATS = new String[] { DUMMY_FORMAT, HEX_FORMAT, OCTAL_FORMAT, BINARY_FORMAT, NATURAL_FORMAT, DECIMAL_FORMAT, STRING_FORMAT };
+
+ public DummyFormattedValueService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ public void initialize(RequestMonitor rm) {
+ super.initialize(new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ register(new String[0], new Hashtable<String, String>() );
+ super.handleSuccess();
+ }
+ });
+ }
+
+ @Override
+ public void shutdown(RequestMonitor rm) {
+ unregister();
+ super.shutdown(rm);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {
+ rm.setData(AVAILABLE_FORMATS);
+ rm.done();
+ }
+
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) {
+ return new FormattedValueDMContext(this, dmc, formatId);
+ }
+
+ public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) {
+ rm.setData(new FormattedValueDMData(dmc.getFormatID()));
+ rm.done();
+ }
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValueTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValueTests.java
new file mode 100644
index 00000000000..60d127311a7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValueTests.java
@@ -0,0 +1,372 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.tests.dsf.vm;
+
+import java.util.concurrent.ExecutionException;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesUpdateStatus;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+import org.eclipse.cdt.tests.dsf.IViewerUpdatesListenerConstants;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElementValidator;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestEvent;
+import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.ViewerLabel;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Tests to verify the operation of FormattedValuesVMUtil
+ * @since 2.2
+ */
+abstract public class FormattedValueTests extends TestCase implements IViewerUpdatesListenerConstants, IDebugVMConstants {
+
+ Display fDisplay;
+ Shell fShell;
+ DsfExecutor fDsfExecutor;
+ DsfSession fDsfSession;
+ ITreeModelViewer fViewer;
+ TestModelUpdatesListener fViewerListener;
+ TestModelUpdatesListener fVMListener;
+ FormattedValuesListener fFormattedValuesListener;
+ TestModel fModel;
+ DummyFormattedValueService fDummyValuesService;
+ AbstractVMAdapter fVMAdapter;
+ TestModelCachingVMProvider fVMProvider;
+
+ public FormattedValueTests(String name) {
+ super(name);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Override
+ protected void setUp() throws Exception {
+ fDsfExecutor = new DefaultDsfExecutor();
+ fDsfSession = DsfSession.startSession(fDsfExecutor, getClass().getName());
+
+ fDisplay = PlatformUI.getWorkbench().getDisplay();
+ fShell = new Shell(fDisplay/*, SWT.ON_TOP | SWT.SHELL_TRIM*/);
+ fShell.setMaximized(true);
+ fShell.setLayout(new FillLayout());
+
+ fViewer = createViewer(fDisplay, fShell);
+
+ fModel = new TestModel(fDsfSession);
+ initializeService(fModel);
+ fDummyValuesService = new DummyFormattedValueService(fDsfSession);
+ initializeService(fDummyValuesService);
+
+ fViewerListener = new TestModelUpdatesListener(fViewer, true, false);
+
+ fModel.setRoot( new TestElement(fModel, "root", new TestElement[0] ) );
+ fModel.setElementChildren(TreePath.EMPTY, makeModelElements(fModel, getTestModelDepth(), "model"));
+
+ fVMAdapter = new AbstractVMAdapter() {
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ return fVMProvider;
+ }
+ };
+ fVMProvider = new TestModelCachingVMProvider(fVMAdapter, fViewer.getPresentationContext(), fDsfSession);
+
+ fVMListener = new TestModelUpdatesListener();
+ fVMProvider.getNode().setVMUpdateListener(fVMListener);
+ fVMProvider.getNode().getLabelProvider().addPropertiesUpdateListener(fViewerListener);
+
+ fFormattedValuesListener = new FormattedValuesListener(fModel);
+ fVMProvider.getNode().setFormattedValuesListener(fFormattedValuesListener);
+ fModel.setTestModelListener(fFormattedValuesListener);
+
+ fShell.open ();
+ }
+
+ private void initializeService(final IDsfService service) throws InterruptedException, ExecutionException {
+ Query<Object> initQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ rm.setData(new Object());
+ service.initialize(rm);
+ }
+ };
+ fDsfExecutor.execute(initQuery);
+ initQuery.get();
+ }
+
+ abstract protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell);
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Override
+ protected void tearDown() throws Exception {
+ fVMProvider.getNode().setFormattedValuesListener(null);
+ fModel.setTestModelListener(null);
+
+ fVMProvider.getNode().getLabelProvider().removePropertiesUpdateListener(fViewerListener);
+ fVMProvider.getNode().setVMUpdateListener(null);
+
+ fVMAdapter.dispose();
+
+ fVMListener.dispose();
+ fViewerListener.dispose();
+
+ shutdownService(fDummyValuesService);
+ shutdownService(fModel);
+ fViewer.getPresentationContext().dispose();
+ // Close the shell and exit.
+ fShell.close();
+ while (!fShell.isDisposed()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+ DsfSession.endSession(fDsfSession);
+ fDsfExecutor.shutdown();
+ }
+
+ private void shutdownService(final IDsfService service) throws InterruptedException, ExecutionException {
+ Query<Object> shutdownQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ rm.setData(new Object());
+ service.shutdown(rm);
+ }
+ };
+ fDsfExecutor.execute(shutdownQuery);
+ shutdownQuery.get();
+ }
+
+ /**
+ * Depth (size) of the test model to be used in the tests. This number allows
+ * the jface based tests to use a small enough model to fit on the screen, and
+ * for the virtual viewer to exercise the content provider to a greater extent.
+ */
+ abstract protected int getTestModelDepth();
+
+ public void testValidate() {
+ setInput(IFormattedValues.NATURAL_FORMAT);
+ setFormatAndValidate(IFormattedValues.HEX_FORMAT, false, false, false);
+ }
+
+ public void testChangeFormat() {
+ setInput(IFormattedValues.NATURAL_FORMAT);
+ setFormatAndValidate(IFormattedValues.HEX_FORMAT, false, false, false);
+ setFormatAndValidate(IFormattedValues.NATURAL_FORMAT, false, false, false);
+ }
+
+ public void testChangeFormatManualUpdateMode() {
+ setInput(IFormattedValues.NATURAL_FORMAT);
+ setUpdatePolicy(ManualUpdatePolicy.MANUAL_UPDATE_POLICY_ID);
+
+ // Chenge to a new format, this does not cause the cache entries to be
+ // set to dirty. Retrieving new format values should happen from the service.
+ setFormatAndValidate(IFormattedValues.HEX_FORMAT, true, false, false);
+
+ // Change _back_ to natural format. Values should be retrieved from cache.
+ setFormatAndValidate(IFormattedValues.NATURAL_FORMAT, true, true, false);
+
+ // Generate an event which will cause all cache entries to be marked dirty.
+ postEventInManualUpdateMode();
+
+ // Change back again to hex format. Values should be retrieved from cache.
+ setFormatAndValidate(IFormattedValues.HEX_FORMAT, true, true, false);
+
+ // Change to a decimal, which is not cached, values should come with an error.
+ setFormatAndValidate(IFormattedValues.DECIMAL_FORMAT, true, true, true);
+
+ }
+
+ private void postEventInManualUpdateMode() {
+ // Generate an event which will cause all cache entries to be marked dirty.
+ fViewerListener.reset();
+ fViewerListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+ fVMListener.reset();
+ fFormattedValuesListener.reset();
+ fVMProvider.postEvent(new TestEvent(fModel.getRootElement(), IModelDelta.CONTENT));
+ while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+ Assert.assertTrue(fFormattedValuesListener.getFormattedValuesCompleted().isEmpty());
+ }
+
+ public void testInvalidFormat() {
+ setInput(IFormattedValues.NATURAL_FORMAT);
+
+ fViewerListener.reset();
+ fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext)fViewer.getInput()).getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+
+ fVMListener.reset();
+ fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+
+ // Set the new number format to the viewer.
+ fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, "invalid format");
+
+ while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES) || !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ validateModel(IFormattedValues.HEX_FORMAT, " (" + FormattedValueVMUtil.getFormatLabel(IFormattedValues.HEX_FORMAT) + ")");
+ }
+
+ /**
+ * Initial format is NATURAL.
+ */
+ private void setInput(String formatId) {
+ // Set the new number format to the viewer.
+ fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, formatId);
+
+ fViewer.setAutoExpandLevel(-1);
+ TestElementVMContext rootVMC = fVMProvider.getElementVMContext(fViewer.getPresentationContext(), fModel.getRootElement());
+
+ // Create the listener
+ fViewerListener.reset();
+ fViewerListener.addUpdates(TreePath.EMPTY, rootVMC.getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+ fVMListener.reset();
+ fVMListener.addUpdates(TreePath.EMPTY, rootVMC.getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+ fFormattedValuesListener.reset();
+
+ fViewer.setInput(rootVMC);
+ while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES) || !fVMListener.isFinished(CONTENT_COMPLETE | PROPERTY_UPDATES))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ Assert.assertTrue(fFormattedValuesListener.isFinished());
+ }
+
+ private void setUpdatePolicy(String policyId) {
+ IVMUpdatePolicy[] policies = fVMProvider.getAvailableUpdatePolicies();
+ IVMUpdatePolicy newPolicy = null;
+ for (IVMUpdatePolicy policy : policies) {
+ if (policyId.equals(policy.getID())) {
+ newPolicy = policy;
+ break;
+ }
+ }
+ if (newPolicy != null) {
+ fVMProvider.setActiveUpdatePolicy(newPolicy);
+ } else {
+ throw new RuntimeException("Update policy " + policyId + " not available");
+ }
+ fViewerListener.reset();
+ fViewerListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+ fVMListener.setFailOnRedundantUpdates(false);
+ while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ fVMListener.setFailOnRedundantUpdates(true);
+ }
+
+ private void setFormatAndValidate(
+ String formatId,
+ boolean expectContentCached,
+ boolean expectFormattedValuesCached,
+ boolean expectCacheMissError)
+ {
+ fViewerListener.reset();
+ fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext)fViewer.getInput()).getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
+
+ fVMListener.reset();
+ int vmUpdateFlags = PROPERTY_UPDATES;
+ if (!expectContentCached) {
+ vmUpdateFlags |= ALL_UPDATES_COMPLETE;
+ }
+ fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, vmUpdateFlags);
+
+ fFormattedValuesListener.reset();
+ if (expectFormattedValuesCached && !expectCacheMissError) {
+ fFormattedValuesListener.setCachedFormats(new String[] {formatId} );
+ }
+
+ // Set the new number format to the viewer.
+ fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, formatId);
+
+ while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES) || !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES))
+ if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+
+ if (expectCacheMissError) {
+ try {
+ validateModel(formatId, "");
+ throw new RuntimeException("Expected validateModel to fail");
+ }
+ catch(AssertionFailedError e) {
+ // expected
+ }
+ } else {
+ validateModel(formatId, "");
+ }
+
+ if (expectCacheMissError) {
+ String formatProperty = FormattedValueVMUtil.getPropertyForFormatId(formatId);
+
+ Assert.assertTrue(fFormattedValuesListener.getFormattedValuesCompleted().isEmpty());
+ Assert.assertFalse(fFormattedValuesListener.getPropertiesUpdates().isEmpty());
+ for (IPropertiesUpdate update : fFormattedValuesListener.getPropertiesUpdates()) {
+ PropertiesUpdateStatus status = (PropertiesUpdateStatus)update.getStatus();
+ assertEquals(IDsfStatusConstants.INVALID_STATE, status.getCode());
+ assertEquals("Cache contains stale data. Refresh view.", status.getStatus(formatProperty).getMessage());
+ assertEquals(
+ "Cache contains stale data. Refresh view.",
+ status.getStatus(PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).getMessage());
+ assertEquals(1, status.getChildren().length);
+
+ }
+
+ } else {
+ Assert.assertTrue(fFormattedValuesListener.isFinished());
+ }
+
+ }
+
+ private void validateModel(final String formatId, final String suffix) {
+ fModel.validateData(
+ fViewer, TreePath.EMPTY,
+ new TestElementValidator() {
+ public void validate(TestElement modelElement, TestElement viewerElement, TreePath viewerPath) {
+ ViewerLabel label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_ID);
+ assertEquals(modelElement.getID(), label.getText());
+
+ label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_FORMATTED_VALUE);
+ assertEquals(fModel.getFormattedValueText(modelElement, formatId) + suffix, label.getText());
+
+ label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_DUMMY_VALUE);
+ assertEquals(formatId, label.getText());
+ }
+ });
+ }
+
+ private TestElement[] makeModelElements(TestModel model, int depth, String prefix) {
+ TestElement[] elements = new TestElement[depth];
+ for (int i = 0; i < depth; i++) {
+ String name = prefix + "." + i;
+ elements[i] = new TestElement(model, name, makeModelElements(model, i, name));
+ }
+ return elements;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValuesListener.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValuesListener.java
new file mode 100644
index 00000000000..cb87bde7334
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/FormattedValuesListener.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.tests.dsf.vm;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdateListener;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
+import org.junit.Assert;
+
+/**
+ *
+ */
+public class FormattedValuesListener implements IFormattedValuesListener, IPropertiesUpdateListener {
+
+ private static final String ANY_FORMAT = "ANY_FORMAT";
+
+ private final TestModel fModel;
+
+ private List<IPropertiesUpdate> fPropertiesUpdates = new ArrayList<IPropertiesUpdate>();
+ private List<List<FormattedValueDMContext>> fFormattedValuesInPending = new ArrayList<List<FormattedValueDMContext>>();
+ private List<FormattedValueDMContext> fFormattedValuesInProgress = new LinkedList<FormattedValueDMContext>();
+ private List<FormattedValueDMContext> fFormattedValuesCompleted = new ArrayList<FormattedValueDMContext>();
+
+ private DsfRunnable fProcessUpdatedFormattedValuesRunnable = null;
+
+ private Set<String> fCachedFormats = new HashSet<String>();
+
+ public FormattedValuesListener(TestModel model) {
+ fModel = model;
+ }
+
+ public void setCachedFormats(String[] cachedFormats) {
+ fCachedFormats.clear();
+ fCachedFormats.addAll(Arrays.asList(cachedFormats));
+ }
+
+ public void propertiesUpdatesStarted(IPropertiesUpdate[] updates) {
+ fPropertiesUpdates.addAll(Arrays.asList(updates));
+ List<FormattedValueDMContext> pending = new ArrayList<FormattedValueDMContext>(updates.length);
+ for (IPropertiesUpdate update : updates) {
+ List<String> formatIds = getRequestedFormatIDs(update);
+ for (String formatId : formatIds) {
+ TestElement te = getPropertyUpdateTestElement(update);
+ pending.add(new FormattedValueDMContext(fModel, te, formatId));
+ }
+ }
+ if (!pending.isEmpty()) {
+ fFormattedValuesInPending.add(pending);
+ }
+ }
+
+ private List<String> getRequestedFormatIDs(IPropertiesUpdate update) {
+ List<String> formatIds = new ArrayList<String>(1);
+ for (String property : update.getProperties()) {
+ if (property.equals(IDebugVMConstants.PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE)) {
+ formatIds.add(ANY_FORMAT);
+ }
+ if (property.startsWith(IDebugVMConstants.PROP_FORMATTED_VALUE_BASE)) {
+ formatIds.add(FormattedValueVMUtil.getFormatFromProperty(property, null));
+ }
+ }
+ return formatIds;
+ }
+
+ public void reset() {
+ reset(new String[0]);
+ }
+
+ public void reset(String[] cachedFormats) {
+ fPropertiesUpdates.clear();
+ fFormattedValuesInPending.clear();
+ fFormattedValuesInProgress.clear();
+ fFormattedValuesCompleted.clear();
+ setCachedFormats(cachedFormats);
+ }
+
+ public List<FormattedValueDMContext> getFormattedValuesCompleted() {
+ return fFormattedValuesCompleted;
+ }
+
+ public List<IPropertiesUpdate> getPropertiesUpdates() {
+ return fPropertiesUpdates;
+ }
+
+ public boolean isFinished() {
+ if ( !fFormattedValuesInProgress.isEmpty() ) {
+ return false;
+ }
+
+ if (!fFormattedValuesInPending.isEmpty() && fCachedFormats.isEmpty()) {
+ return false;
+ }
+
+ for (List<FormattedValueDMContext> pendingList : fFormattedValuesInPending) {
+ for (FormattedValueDMContext pending : pendingList) {
+ String pendingFormat = pending.getFormatID();
+ if (!pendingFormat.equals(ANY_FORMAT) && !fCachedFormats.contains(pendingFormat)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void propertiesUpdateCompleted(IPropertiesUpdate update) {}
+
+ public void formattedValueUpdated(FormattedValueDMContext formattedValueDmc) {
+ Assert.assertFalse("Expected values with formats " + fCachedFormats + " to be cached.",
+ fCachedFormats.contains(formattedValueDmc.getFormatID()));
+
+ if (fProcessUpdatedFormattedValuesRunnable == null) {
+ fProcessUpdatedFormattedValuesRunnable = new DsfRunnable() {
+ public void run() {
+ fProcessUpdatedFormattedValuesRunnable = null;
+ processFormattedValuesInProgress();
+ }
+ };
+ fModel.getExecutor().execute(fProcessUpdatedFormattedValuesRunnable);
+ }
+ fFormattedValuesInProgress.add(formattedValueDmc);
+ }
+
+ private void processFormattedValuesInProgress() {
+ while (!fFormattedValuesInProgress.isEmpty()) {
+ List<FormattedValueDMContext> pendingList = findPendingList(fFormattedValuesInProgress.get(0));
+
+ for (FormattedValueDMContext pending : pendingList) {
+ int progressIdx = indexOfFormattedValueDMContext(fFormattedValuesInProgress, pending);
+
+ if (progressIdx != -1) {
+ // The pending DMC may contain the ANY_FORMAT format ID.
+ // The progress DMC must contain the exact format retrieved.
+ // To have a more accurate record, add the progress DMC to
+ // the completed updates list.
+ FormattedValueDMContext progress = fFormattedValuesInProgress.remove(progressIdx);
+ fFormattedValuesCompleted.add(progress);
+ } else {
+ Assert.fail("Pending Updates not processed in bulk \n " + pendingList);
+ }
+ }
+ }
+ }
+
+ private List<FormattedValueDMContext> findPendingList(FormattedValueDMContext dmc) {
+ for (Iterator<List<FormattedValueDMContext>> itr = fFormattedValuesInPending.iterator(); itr.hasNext();) {
+ List<FormattedValueDMContext> pendingList = itr.next();
+ int pendingIdx = indexOfFormattedValueDMContext(pendingList, dmc);
+ if (pendingIdx != -1) {
+ itr.remove();
+ return pendingList;
+ }
+ }
+ throw new RuntimeException("Pending update not found for element: " + dmc);
+ }
+
+ private int indexOfFormattedValueDMContext(List<FormattedValueDMContext> list, FormattedValueDMContext dmc) {
+ for (int i = 0; i < list.size(); i++) {
+ if (dmc.getParentValueDMContext().equals(list.get(i).getParentValueDMContext())) {
+ if ( ANY_FORMAT.equals(dmc.getFormatID()) ||
+ ANY_FORMAT.equals(list.get(i).getFormatID()) ||
+ dmc.getFormatID().equals(list.get(i).getFormatID()) )
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ private TestElement getPropertyUpdateTestElement(IPropertiesUpdate update) {
+ Object element = update.getElement();
+ if (element instanceof TestElement) {
+ return (TestElement)element;
+ } else if (element instanceof TestElementVMContext) {
+ return ((TestElementVMContext)element).getElement();
+ }
+ throw new RuntimeException("Invalid element in properties update: " + update.getElement());
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/IFormattedValuesListener.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/IFormattedValuesListener.java
new file mode 100644
index 00000000000..ce919f87603
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/IFormattedValuesListener.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.tests.dsf.vm;
+
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+
+/**
+ * @since 2.2
+ */
+public interface IFormattedValuesListener {
+
+ public void formattedValueUpdated(FormattedValueDMContext formattedValueDmc);
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/ITestModelUpdatesListenerConstants.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/ITestModelUpdatesListenerConstants.java
deleted file mode 100644
index 162d955e681..00000000000
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/ITestModelUpdatesListenerConstants.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2010 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.tests.dsf.vm;
-
-/**
- * Convenience interface with constants used by the test model update listener.
- *
- * @since 3.6
- */
-public interface ITestModelUpdatesListenerConstants {
-
- public static final int LABEL_UPDATES_COMPLETE = 0X0001;
- public static final int CONTENT_UPDATES_COMPLETE = 0X0002;
- public static final int LABEL_UPDATES = 0X0004;
- public static final int HAS_CHILDREN_UPDATES = 0X0008;
- public static final int CHILDREN_COUNT_UPDATES = 0X0010;
- public static final int CHILDREN_UPDATES = 0X0020;
- public static final int MODEL_CHANGED_COMPLETE = 0X0040;
- public static final int MODEL_PROXIES_INSTALLED = 0X0080;
- public static final int STATE_SAVE_COMPLETE = 0X0100;
- public static final int STATE_RESTORE_COMPLETE = 0X0200;
- public static final int STATE_UPDATES = 0X0400;
-
- public static final int VIEWER_UPDATES_RUNNING = 0X0800;
- public static final int LABEL_UPDATES_RUNNING = 0X1000;
-
- public static final int LABEL_COMPLETE = LABEL_UPDATES_COMPLETE | LABEL_UPDATES;
- public static final int CONTENT_COMPLETE =
- CONTENT_UPDATES_COMPLETE | HAS_CHILDREN_UPDATES | CHILDREN_COUNT_UPDATES | CHILDREN_UPDATES;
-
- public static final int ALL_UPDATES_COMPLETE = LABEL_COMPLETE | CONTENT_COMPLETE | LABEL_UPDATES_RUNNING | VIEWER_UPDATES_RUNNING;
-}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/JFaceViewerFormattedValueTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/JFaceViewerFormattedValueTests.java
new file mode 100644
index 00000000000..c28a1b2d0be
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/JFaceViewerFormattedValueTests.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 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.tests.dsf.vm;
+
+import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 2.2
+ */
+public class JFaceViewerFormattedValueTests extends FormattedValueTests {
+
+ public JFaceViewerFormattedValueTests(String name) {
+ super(name);
+ }
+
+ @Override
+ protected ITreeModelContentProviderTarget createViewer(Display display, Shell shell) {
+ return new TreeModelViewer(fShell, SWT.VIRTUAL, new PresentationContext("TestViewer"));
+ }
+
+ @Override
+ protected int getTestModelDepth() {
+ return 5;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/PerformanceTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/PerformanceTests.java
index 73c1cf543ec..3438d076bcb 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/PerformanceTests.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/PerformanceTests.java
@@ -12,6 +12,10 @@ package org.eclipse.cdt.tests.dsf.vm;
import junit.framework.TestCase;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.IViewerUpdatesListenerConstants;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
@@ -28,9 +32,11 @@ import org.eclipse.ui.PlatformUI;
/**
* Tests to measure the performance of the viewer updates.
*/
-abstract public class PerformanceTests extends TestCase implements ITestModelUpdatesListenerConstants {
+abstract public class PerformanceTests extends TestCase implements IViewerUpdatesListenerConstants {
Display fDisplay;
Shell fShell;
+ DsfExecutor fDsfExecutor;
+ DsfSession fDsfSession;
ITreeModelViewer fViewer;
TestModelUpdatesListener fListener;
TestModel fModel;
@@ -46,6 +52,9 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
*/
@Override
protected void setUp() throws Exception {
+ fDsfExecutor = new DefaultDsfExecutor();
+ fDsfSession = DsfSession.startSession(fDsfExecutor, getClass().getName());
+
fDisplay = PlatformUI.getWorkbench().getDisplay();
fShell = new Shell(fDisplay/*, SWT.ON_TOP | SWT.SHELL_TRIM*/);
fShell.setMaximized(true);
@@ -55,7 +64,7 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
fListener = new TestModelUpdatesListener(fViewer, false, false);
- fModel = new TestModel();
+ fModel = new TestModel(fDsfSession);
fModel.setRoot( new TestElement(fModel, "root", new TestElement[0] ) );
fModel.setElementChildren(TreePath.EMPTY, makeModelElements(fModel, getTestModelDepth(), "model"));
fVMAdapter = new TestModelVMAdapter();
@@ -78,6 +87,8 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
// Close the shell and exit.
fShell.close();
while (!fShell.isDisposed()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
+ DsfSession.endSession(fDsfSession);
+ fDsfExecutor.shutdown();
}
/**
@@ -166,32 +177,31 @@ abstract public class PerformanceTests extends TestCase implements ITestModelUpd
}
public void _x_testRefreshStructReplaceElements() {
- TestModel model = new TestModel();
- model.setRoot( new TestElement(model, "root", new TestElement[0] ) );
- model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "model"));
+ fModel.setRoot( new TestElement(fModel, "root", new TestElement[0] ) );
+ fModel.setElementChildren(TreePath.EMPTY, makeModelElements(fModel, getTestModelDepth(), "model"));
fViewer.setAutoExpandLevel(-1);
// Create the listener
- fListener.reset(TreePath.EMPTY, model.getRootElement(), -1, true, false);
+ fListener.reset(TreePath.EMPTY, fModel.getRootElement(), -1, true, false);
// Set the input into the view and update the view.
- fViewer.setInput(model.getRootElement());
+ fViewer.setInput(fModel.getRootElement());
while (!fListener.isFinished()) if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
- model.validateData(fViewer, TreePath.EMPTY);
+ fModel.validateData(fViewer, TreePath.EMPTY);
Performance perf = Performance.getDefault();
PerformanceMeter meter = perf.createPerformanceMeter(perf.getDefaultScenarioId(this));
try {
for (int i = 0; i < 2000; i++) {
// Update the model
- model.setElementChildren(TreePath.EMPTY, makeModelElements(model, getTestModelDepth(), "pass " + i));
+ fModel.setElementChildren(TreePath.EMPTY, makeModelElements(fModel, getTestModelDepth(), "pass " + i));
- TestElement element = model.getRootElement();
+ TestElement element = fModel.getRootElement();
fListener.reset(TreePath.EMPTY, element, -1, false, false);
meter.start();
- model.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
+ //fModel.postDelta(new ModelDelta(element, IModelDelta.CONTENT));
while (!fListener.isFinished(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE))
if (!fDisplay.readAndDispatch ()) fDisplay.sleep ();
//model.validateData(fViewer, TreePath.EMPTY);
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestElementVMContext.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestElementVMContext.java
index 3d7360975df..e6ec468cc85 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestElementVMContext.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestElementVMContext.java
@@ -10,17 +10,20 @@
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.vm;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
/**
- *
+ * @since 2.2
*/
-public class TestElementVMContext extends AbstractVMContext {
+public class TestElementVMContext extends AbstractVMContext implements IDMVMContext {
final private TestElement fElement;
- public TestElementVMContext(TestModelVMNode node, TestElement element) {
+ public TestElementVMContext(IVMNode node, TestElement element) {
super(node);
fElement = element;
}
@@ -38,5 +41,13 @@ public class TestElementVMContext extends AbstractVMContext {
public TestElement getElement() {
return fElement;
}
+
+ public IDMContext getDMContext() {
+ return getElement();
+ }
+ @Override
+ public String toString() {
+ return getDMContext().toString();
+ }
}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModel.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModel.java
index cbae0a9d6f7..da475627ad1 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModel.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModel.java
@@ -11,38 +11,45 @@
package org.eclipse.cdt.tests.dsf.vm;
import java.util.Arrays;
+import java.util.Hashtable;
import junit.framework.Assert;
-import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelCheckProviderTarget;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
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.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.IModelProxy;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
-import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.jface.viewers.Viewer;
+import org.osgi.framework.BundleContext;
/**
* Test model for the use in unit tests. This test model contains a set of
* elements in a tree structure. It contains utility methods for modifying the
* model and for verifying that the viewer content matches the model.
*
- * @since 3.6
+ * @since 2.2
*/
-public class TestModel {
+public class TestModel extends AbstractDsfService implements IFormattedValues {
- public static class TestElement extends PlatformObject {
+ public interface TestElementValidator {
+ public void validate(TestElement modelElement, TestElement viewerElement, TreePath viewerPath);
+ }
+
+ public static class TestElement extends AbstractDMContext implements IFormattedDataDMContext {
private final TestModel fModel;
private final String fID;
TestElement[] fChildren;
@@ -51,18 +58,37 @@ public class TestModel {
boolean fChecked;
boolean fGrayed;
+ private TestElement[] fParents = new TestElement[1];
+
public TestElement(TestModel model, String text, TestElement[] children) {
this (model, text, false, false, children);
}
public TestElement(TestModel model, String text, boolean checked, boolean grayed, TestElement[] children) {
+ super(model, EMPTY_PARENTS_ARRAY);
fModel = model;
fID = text;
fChildren = children;
+ for (TestElement child : children) {
+ child.setParent(this);
+ }
fChecked = checked;
fGrayed = grayed;
}
+ public void setParent(TestElement parent) {
+ fParents[0] = parent;
+ }
+
+ public TestElement getParent() {
+ return fParents[0];
+ }
+
+ @Override
+ public IDMContext[] getParents() {
+ return fParents;
+ }
+
public TestModel getModel() {
return fModel;
}
@@ -129,39 +155,72 @@ public class TestModel {
}
}
- private class ModelProxy extends AbstractModelProxy {
- @Override
- public void installed(Viewer viewer) {
- super.installed(viewer);
- ModelDelta rootDelta = TestModel.this.getBaseDelta(new ModelDelta(fInput, IModelDelta.NO_CHANGE));
- installSubModelProxies(fRootPath, rootDelta);
- fireModelChanged(rootDelta);
- }
-
- private void installSubModelProxies(TreePath path, ModelDelta delta) {
- TestElement element = getElement(path);
- if (element.fModel != TestModel.this) {
- // Found an element from a different model. Install its proxy and return.
- delta.setFlags(delta.getFlags() | IModelDelta.INSTALL);
- } else {
- TestElement[] children = element.getChildren();
-
- for (int i = 0; i < children.length; i++) {
- installSubModelProxies(path.createChildPath(children[i]), delta.addNode(children[i], IModelDelta.NO_CHANGE));
- }
- }
+ public static final class TestEvent {
+ private final TestElement fElement;
+ private final int fType;
+
+ public TestEvent(TestElement element, int type) {
+ fElement = element;
+ fType = type;
+ }
+
+ public TestElement getElement() {
+ return fElement;
+ }
+
+ /**
+ * @see IModelDelta#getFlags()
+ */
+ public int getType() {
+ return fType;
}
}
-
+
+ private static final IFormattedValuesListener NULL_LISTENER = new IFormattedValuesListener() {
+ public void formattedValueUpdated(FormattedValueDMContext formattedValueDmc) {}
+ };
+
private TestElement fRoot;
private Object fInput = null;
private TreePath fRootPath = TreePath.EMPTY;
- private ModelProxy fModelProxy;
+ private IFormattedValuesListener fListener = NULL_LISTENER;
/**
* Constructor private. Use static factory methods instead.
*/
- public TestModel() {}
+ public TestModel(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(RequestMonitor rm) {
+ super.initialize(new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ register(new String[0], new Hashtable<String, String>() );
+ super.handleSuccess();
+ }
+ });
+ }
+
+ @Override
+ public void shutdown(RequestMonitor rm) {
+ unregister();
+ super.shutdown(rm);
+ }
+
+ public void setTestModelListener(IFormattedValuesListener listener) {
+ if (listener != null) {
+ fListener = listener;
+ } else {
+ fListener = NULL_LISTENER;
+ }
+ }
public TestElement getRootElement() {
return fRoot;
@@ -197,48 +256,6 @@ public class TestModel {
return depth;
}
- public void update(IHasChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setHasChilren(element.getChildren().length > 0);
- updates[i].done();
- }
- }
-
- public void update(IChildrenCountUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setChildCount(element.getChildren().length);
- updates[i].done();
- }
- }
-
- public void update(IChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- int endOffset = updates[i].getOffset() + updates[i].getLength();
- for (int j = updates[i].getOffset(); j < endOffset; j++) {
- if (j < element.getChildren().length) {
- updates[i].setChild(element.getChildren()[j], j);
- }
- }
- updates[i].done();
- }
- }
-
- public void update(ILabelUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- TestElement element = (TestElement)updates[i].getElement();
- updates[i].setLabel(element.fID, 0);
- if (updates[i] instanceof ICheckUpdate &&
- Boolean.TRUE.equals(updates[i].getPresentationContext().getProperty(ICheckUpdate.PROP_CHECK)))
- {
- ((ICheckUpdate)updates[i]).setChecked(element.getChecked(), element.getGrayed());
- }
- updates[i].done();
- }
- }
-
public final static String ELEMENT_MEMENTO_ID = "id";
public void compareElements(IElementCompareRequest[] updates) {
@@ -259,24 +276,12 @@ public class TestModel {
}
}
-
public void elementChecked(IPresentationContext context, Object viewerInput, TreePath path, boolean checked) {
TestElement element = getElement(path);
Assert.assertFalse(element.getGrayed());
element.setChecked(checked, false);
}
- public IModelProxy createTreeModelProxy(Object input, TreePath path, IPresentationContext context) {
- fModelProxy = new ModelProxy();
- fInput = input;
- fRootPath = path;
- return fModelProxy;
- }
-
- public IModelProxy getModelProxy() {
- return fModelProxy;
- }
-
public TestElement getElement(TreePath path) {
if (path.getSegmentCount() == 0) {
return getRootElement();
@@ -289,6 +294,14 @@ public class TestModel {
return null;
}
}
+
+ public TestElement getElementFromViewer(ITreeModelContentProviderTarget viewer, TreePath parentPath, int index) {
+ Object element = viewer.getChildElement(parentPath, index);
+ if (element instanceof TestElementVMContext) {
+ return ((TestElementVMContext)element).getElement();
+ }
+ return null;
+ }
public void setAllExpanded() {
doSetExpanded(fRoot);
@@ -314,10 +327,16 @@ public class TestModel {
public void validateData(ITreeModelViewer viewer, TreePath path) {
- validateData(viewer, path, false);
+ validateData(viewer, path, null, false);
}
- public void validateData(ITreeModelViewer _viewer, TreePath path, boolean expandedElementsOnly) {
+ public void validateData(ITreeModelViewer viewer, TreePath path, TestElementValidator validator) {
+
+ validateData(viewer, path, validator, false);
+ }
+
+ public void validateData(ITreeModelViewer _viewer, TreePath path, TestElementValidator validator, boolean expandedElementsOnly) {
+
ITreeModelContentProviderTarget viewer = (ITreeModelContentProviderTarget)_viewer;
TestElement element = getElement(path);
if ( Boolean.TRUE.equals(_viewer.getPresentationContext().getProperty(ICheckUpdate.PROP_CHECK)) ) {
@@ -331,8 +350,17 @@ public class TestModel {
Assert.assertEquals(children.length, viewer.getChildCount(path));
for (int i = 0; i < children.length; i++) {
- Assert.assertEquals(children[i], viewer.getChildElement(path, i));
- validateData(viewer, path.createChildPath(children[i]), expandedElementsOnly);
+ Object viewerObject = viewer.getChildElement(path, i);
+ if (viewerObject instanceof TestElementVMContext) {
+ TreePath childPath = path.createChildPath(viewerObject);
+ TestElement viewerElement = ((TestElementVMContext)viewerObject).getElement();
+ Assert.assertEquals(children[i], viewerElement);
+ if (validator != null) {
+ validator.validate(children[i], viewerElement, childPath);
+ }
+
+ validateData(viewer, childPath, validator, expandedElementsOnly);
+ }
}
} else if (!viewer.getExpandedState(path)) {
// If element not expanded, verify the plus sign.
@@ -344,10 +372,6 @@ public class TestModel {
fRoot = root;
}
- public void postDelta(IModelDelta delta) {
- fModelProxy.fireModelChanged(delta);
- }
-
/** Create or retrieve delta for given path
* @param combine if then new deltas for the given path are created. If false existing ones are reused.
*/
@@ -560,6 +584,27 @@ public class TestModel {
return null;
}
+ public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {
+ rm.setData(new String[] { HEX_FORMAT, DECIMAL_FORMAT, OCTAL_FORMAT, BINARY_FORMAT, NATURAL_FORMAT });
+ rm.done();
+ }
+
+ public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) {
+ TestElement te = DMContexts.getAncestorOfType(dmc, TestElement.class);
+ rm.setData(new FormattedValueDMData( getFormattedValueText(te, dmc.getFormatID())));
+ rm.done();
+ fListener.formattedValueUpdated(dmc);
+ }
+
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) {
+ // Creates a context that can be used to retrieve a formatted value.
+ return new FormattedValueDMContext(this, dmc, formatId);
+ }
+
+ public String getFormattedValueText(TestElement te, String formatId) {
+ return te.getLabel() + " (" + formatId + ")";
+ }
+
@Override
public String toString() {
return getElementString(fRoot, "");
@@ -577,8 +622,7 @@ public class TestModel {
return builder.toString();
}
- public static TestModel simpleSingleLevel() {
- TestModel model = new TestModel();
+ public static void simpleSingleLevel(TestModel model) {
model.setRoot( new TestElement(model, "root", new TestElement[] {
new TestElement(model, "1", true, true, new TestElement[0]),
new TestElement(model, "2", true, false, new TestElement[0]),
@@ -587,11 +631,9 @@ public class TestModel {
new TestElement(model, "5", new TestElement[0]),
new TestElement(model, "6", new TestElement[0])
}) );
- return model;
}
- public static TestModel simpleMultiLevel() {
- TestModel model = new TestModel();
+ public static void simpleMultiLevel(TestModel model) {
model.setRoot( new TestElement(model, "root", new TestElement[] {
new TestElement(model, "1", new TestElement[0]),
new TestElement(model, "2", true, false, new TestElement[] {
@@ -617,53 +659,6 @@ public class TestModel {
}),
})
}) );
- return model;
}
-
- public static TestModel compositeMultiLevel() {
- TestModel m2 = new TestModel();
- m2.setRoot( new TestElement(m2, "m2.root", new TestElement[] {
- new TestElement(m2, "m2.1", new TestElement[0]),
- new TestElement(m2, "m2.2", true, false, new TestElement[] {
- new TestElement(m2, "m2.2.1", true, true, new TestElement[0]),
- new TestElement(m2, "m2.2.2", false, true, new TestElement[0]),
- new TestElement(m2, "m2.2.3", true, false, new TestElement[0]),
- }),
- }) );
-
- TestModel m3 = new TestModel();
- m3.setRoot( new TestElement(m3, "m3.root", new TestElement[] {
- new TestElement(m3, "m3.1", new TestElement[0]),
- new TestElement(m3, "m3.2", true, false, new TestElement[] {
- new TestElement(m3, "m3.2.1", true, true, new TestElement[0]),
- new TestElement(m3, "m3.2.2", false, true, new TestElement[0]),
- new TestElement(m3, "m3.2.3", true, false, new TestElement[0]),
- }),
- }) );
-
- TestModel m4 = new TestModel();
- m4.setRoot( new TestElement(m4, "m4.root", new TestElement[] {
- new TestElement(m4, "m4.1", new TestElement[0]),
- new TestElement(m4, "m4.2", true, false, new TestElement[] {
- new TestElement(m4, "m4.2.1", true, true, new TestElement[0]),
- new TestElement(m4, "m4.2.2", false, true, new TestElement[0]),
- new TestElement(m4, "m4.2.3", true, false, new TestElement[0]),
- }),
- }) );
-
- TestModel m1 = new TestModel();
- m1.setRoot( new TestElement(m1, "m1.root", new TestElement[] {
- new TestElement(m1, "m1.1", new TestElement[0]),
- new TestElement(m1, "m1.2", true, false, new TestElement[] {
- m2.fRoot,
- m3.fRoot,
- m4.fRoot,
- }),
- }) );
-
-
- return m1;
- }
-
}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelCachingVMProvider.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelCachingVMProvider.java
new file mode 100644
index 00000000000..5279e4afb79
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelCachingVMProvider.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.tests.dsf.vm;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.update.DebugManualUpdatePolicy;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+/**
+ * @since 2.2
+ */
+public class TestModelCachingVMProvider extends AbstractDMVMProvider {
+
+ public static final String COLUMN_ID = "COLUMN_ID";
+ public static final String COLUMN_FORMATTED_VALUE = "COLUMN_FORMATTED_VALUE";
+ public static final String COLUMN_DUMMY_VALUE = "COLUMN_DUMMY_VALUE";
+ private static final String[] COLUMNS = new String[] { COLUMN_ID, COLUMN_FORMATTED_VALUE, COLUMN_DUMMY_VALUE };
+
+ private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ handleEvent(event);
+ }
+ };
+
+ private static IColumnPresentation COLUMN_PRESENTATION = new IColumnPresentation() {
+ public void init(IPresentationContext context) {}
+ public void dispose() {};
+
+ public String[] getAvailableColumns() {
+ return COLUMNS;
+ };
+
+ public String getHeader(String id) {
+ return id;
+ };
+
+ public String getId() { return "ID"; }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+ public String[] getInitialColumns() {
+ return COLUMNS;
+ }
+ public boolean isOptional() {
+ return false;
+ }
+ };
+
+ public TestModelCachingVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
+ super(adapter, context, session);
+
+ setRootNode(new TestModelDMVMNode(this, session));
+ addChildNodes(getRootVMNode(), new IVMNode[] { getRootVMNode() });
+
+ context.addPropertyChangeListener(fPresentationContextListener);
+ }
+
+ @Override
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] {
+ new AutomaticUpdatePolicy(),
+ new DebugManualUpdatePolicy(new String[] { TestModelDMVMNode.PROP_PREFIX_DUMMY }),
+ new BreakpointHitUpdatePolicy() };
+ }
+
+ public TestModelDMVMNode getNode() {
+ return (TestModelDMVMNode)getRootVMNode();
+ }
+
+ @Override
+ public void dispose() {
+ getPresentationContext().removePropertyChangeListener(fPresentationContextListener);
+ super.dispose();
+ }
+
+ public void postEvent(Object event) {
+ super.handleEvent(event);
+ }
+
+ public TestElementVMContext getElementVMContext(IPresentationContext context, TestElement element) {
+ return ((TestModelDMVMNode)getRootVMNode()).createVMContext(element);
+ }
+
+ @Override
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return COLUMN_PRESENTATION.getId();
+ }
+
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return COLUMN_PRESENTATION;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelDMVMNode.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelDMVMNode.java
new file mode 100644
index 00000000000..19f15555ec8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelDMVMNode.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 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.tests.dsf.vm;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueLabelText;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueRetriever;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelAttribute;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelColumnInfo;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
+import org.eclipse.cdt.tests.dsf.ViewerUpdatesListener;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
+import org.eclipse.cdt.tests.dsf.vm.TestModel.TestEvent;
+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.IElementLabelProvider;
+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.jface.util.PropertyChangeEvent;
+
+/**
+ * @since 2.2
+ */
+public class TestModelDMVMNode extends AbstractDMVMNode implements IRootVMNode, IElementLabelProvider, IElementPropertiesProvider {
+
+ final public static String PROP_PREFIX_DUMMY = "dummy.";
+
+ final private static String PROP_TEST_ELEMENT_LABEL = "PROP_TEST_ELEMENT_LABEL";
+
+ private ViewerUpdatesListener fViewerUpdateListener = NULL_VIEWER_UPDATE_LISTENER;
+ private FormattedValuesListener fFormattedValuesListener;
+
+ private static final ViewerUpdatesListener NULL_VIEWER_UPDATE_LISTENER = new ViewerUpdatesListener();
+
+ final private static PropertiesBasedLabelProvider fLabelProvider = new PropertiesBasedLabelProvider();
+ {
+ LabelColumnInfo idLabelInfo = new LabelColumnInfo(new LabelAttribute[] {
+ new LabelText("{0}", new String[] { PROP_TEST_ELEMENT_LABEL })
+ });
+
+ fLabelProvider.setColumnInfo(PropertiesBasedLabelProvider.ID_COLUMN_NO_COLUMNS, idLabelInfo);
+ fLabelProvider.setColumnInfo(TestModelCachingVMProvider.COLUMN_ID, idLabelInfo);
+ fLabelProvider.setColumnInfo(
+ TestModelCachingVMProvider.COLUMN_FORMATTED_VALUE,
+ new LabelColumnInfo(new LabelAttribute[] {
+ new FormattedValueLabelText()
+ }));
+ fLabelProvider.setColumnInfo(
+ TestModelCachingVMProvider.COLUMN_DUMMY_VALUE,
+ new LabelColumnInfo(new LabelAttribute[] {
+ new FormattedValueLabelText(PROP_PREFIX_DUMMY)
+ }));
+ }
+
+ private final FormattedValueRetriever fFormattedValueRetriever;
+ private final FormattedValueRetriever fDummyFormattedValueRetriever;
+
+ public TestModelDMVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, TestElement.class);
+ fFormattedValueRetriever = new FormattedValueRetriever(this, getSession(), TestModel.class, TestElement.class);
+ fDummyFormattedValueRetriever = new FormattedValueRetriever(this, getSession(), DummyFormattedValueService.class, TestElement.class, PROP_PREFIX_DUMMY);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ fFormattedValueRetriever.dispose();
+ fDummyFormattedValueRetriever.dispose();
+ }
+
+ public void setVMUpdateListener(ViewerUpdatesListener viewerUpdateListener) {
+ if (viewerUpdateListener != null) {
+ fViewerUpdateListener = viewerUpdateListener;
+ } else {
+ fViewerUpdateListener = NULL_VIEWER_UPDATE_LISTENER;
+ }
+ }
+
+ public void setFormattedValuesListener(FormattedValuesListener formattedValuesListener) {
+ fFormattedValuesListener = formattedValuesListener;
+ }
+
+ public PropertiesBasedLabelProvider getLabelProvider() {
+ return fLabelProvider;
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ fLabelProvider.update(updates);
+ }
+
+ @Override
+ public void update(IHasChildrenUpdate[] updates) {
+ fViewerUpdateListener.viewerUpdatesBegin();
+ for (IHasChildrenUpdate update : updates) {
+ fViewerUpdateListener.updateStarted(update);
+ if (update.getElement() instanceof TestElementVMContext) {
+ TestElement element = ((TestElementVMContext)update.getElement()).getElement();
+ update.setHasChilren(element.getChildren().length != 0);
+ }
+ update.done();
+ fViewerUpdateListener.updateComplete(update);
+ }
+ fViewerUpdateListener.viewerUpdatesComplete();
+ }
+
+ @Override
+ public void update(IChildrenCountUpdate[] updates) {
+ fViewerUpdateListener.viewerUpdatesBegin();
+ for (IChildrenCountUpdate update : updates) {
+ fViewerUpdateListener.updateStarted(update);
+ if (update.getElement() instanceof TestElementVMContext) {
+ TestElement element = ((TestElementVMContext)update.getElement()).getElement();
+ update.setChildCount(element.getChildren().length);
+ }
+ update.done();
+ fViewerUpdateListener.updateComplete(update);
+ }
+ fViewerUpdateListener.viewerUpdatesComplete();
+ }
+
+ @Override
+ public void update(IChildrenUpdate[] updates) {
+ fViewerUpdateListener.viewerUpdatesBegin();
+ for (IChildrenUpdate update : updates) {
+ fViewerUpdateListener.updateStarted(update);
+ if (update.getElement() instanceof TestElementVMContext) {
+ TestElement element = ((TestElementVMContext)update.getElement()).getElement();
+ fillUpdateWithTestElements(update, element.getChildren());
+ }
+ update.done();
+ fViewerUpdateListener.updateComplete(update);
+ }
+ fViewerUpdateListener.viewerUpdatesComplete();
+ }
+
+
+ @Override
+ protected void updateElementsInSessionThread(IChildrenUpdate update) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void update(final IPropertiesUpdate[] updates) {
+ fViewerUpdateListener.propertiesUpdatesStarted(updates);
+ if (fFormattedValuesListener != null) fFormattedValuesListener.propertiesUpdatesStarted(updates);
+
+ CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleSuccess() {
+ for (IPropertiesUpdate update : updates) {
+ if (update.getElement() instanceof TestElementVMContext) {
+ TestElement element = ((TestElementVMContext)update.getElement()).getElement();
+ update.setProperty(PROP_TEST_ELEMENT_LABEL, element.getLabel());
+ }
+ update.done();
+ fViewerUpdateListener.propertiesUpdateCompleted(update);
+ if (fFormattedValuesListener != null) fFormattedValuesListener.propertiesUpdateCompleted(update);
+ }
+ }
+ };
+ int count = 0;
+
+ fFormattedValueRetriever.update(updates, crm);
+ count++;
+ fDummyFormattedValueRetriever.update(updates, crm);
+ count++;
+ crm.setDoneCount(count);
+ }
+
+ private void fillUpdateWithTestElements(IChildrenUpdate update, TestElement[] modelElements) {
+ int updateIdx = update.getOffset() != -1 ? update.getOffset() : 0;
+ int endIdx = updateIdx + (update.getLength() != -1 ? update.getLength() : modelElements.length);
+ while (updateIdx < endIdx && updateIdx < modelElements.length) {
+ update.setChild(createVMContext(modelElements[updateIdx]), updateIdx);
+ updateIdx++;
+ }
+ }
+
+ public TestElementVMContext createVMContext(TestElement element) {
+ return new TestElementVMContext(this, element);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
+ */
+ public int getDeltaFlags(Object e) {
+ if ( e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE)
+ {
+ return IModelDelta.CONTENT;
+ }
+ if (e instanceof TestEvent) {
+ return ((TestEvent)e).getType();
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, VMDelta parent, int nodeOffset, RequestMonitor rm) {
+ if ( e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE)
+ {
+ parent.setFlags(parent.getFlags() | IModelDelta.CONTENT);
+ }
+ rm.done();
+ }
+
+
+ public boolean isDeltaEvent(Object rootObject, Object event) {
+ return getDeltaFlags(event) != IModelDelta.NO_CHANGE;
+ }
+
+ public void createRootDelta(Object rootObject, Object event, DataRequestMonitor<VMDelta> rm) {
+ int flags = IModelDelta.NO_CHANGE;
+ if ( event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.PROP_FORMATTED_VALUE_FORMAT_PREFERENCE)
+ {
+ flags |= IModelDelta.CONTENT;
+ }
+
+ // TODO: make more sophisticated to update specific elements.
+ if (event instanceof TestEvent) {
+ flags|= ((TestEvent)event).getType();
+ }
+
+ rm.setData( new VMDelta(rootObject, 0, flags) );
+ rm.done();
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelUpdatesListener.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelUpdatesListener.java
index 8684a81d038..a98d0a4f97f 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelUpdatesListener.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelUpdatesListener.java
@@ -11,34 +11,21 @@
package org.eclipse.cdt.tests.dsf.vm;
import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
-import junit.framework.Assert;
-
+import org.eclipse.cdt.tests.dsf.ViewerUpdatesListener;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
-import org.eclipse.debug.internal.ui.viewers.model.ILabelUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelContentProviderTarget;
import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
-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.ILabelUpdate;
-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.IModelProxy;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.jface.viewers.TreePath;
-public class TestModelUpdatesListener
- implements IViewerUpdateListener, ILabelUpdateListener, IModelChangedListener, ITestModelUpdatesListenerConstants,
- IStateUpdateListener
+/**
+ * @since 2.2
+ */
+public class TestModelUpdatesListener extends ViewerUpdatesListener
{
private final static Comparator<String> fStringComparator = new Comparator<String>() {
@@ -116,74 +103,28 @@ public class TestModelUpdatesListener
};
- private final ITreeModelViewer fViewer;
-
- private boolean fFailOnRedundantUpdates;
- private boolean fFailOnMultipleModelUpdateSequences;
- private boolean fFailOnMultipleLabelUpdateSequences;
-
- private Set<TreePath> fHasChildrenUpdates = new TreeSet<TreePath>(fTestElementVMCComparator);
- private Map<TreePath, Set<Integer>> fChildrenUpdates = new TreeMap<TreePath, Set<Integer>>(fTestElementVMCComparator);
- private Set<TreePath> fChildCountUpdates = new TreeSet<TreePath>(fTestElementVMCComparator);
- private Set<TreePath> fLabelUpdates = new TreeSet<TreePath>(fTestElementVMCComparator);
- private Set<TestModel> fProxyModels = new HashSet<TestModel>();
- private Set<TreePath> fStateUpdates = new TreeSet<TreePath>(fTestElementVMCComparator);
- private boolean fViewerUpdatesComplete;
- private boolean fLabelUpdatesComplete;
- private boolean fModelChangedComplete;
- private boolean fStateSaveComplete;
- private boolean fStateRestoreComplete;
- private int fViewerUpdatesRunning;
- private int fLabelUpdatesRunning;
- private int fTimeoutInterval = 60000;
- private long fTimeoutTime;
+ @Override
+ protected Set<TreePath> makeTreePathSet() {
+ return new TreeSet<TreePath>(fTestElementVMCComparator);
+ }
-
- public TestModelUpdatesListener(ITreeModelViewer viewer, boolean failOnRedundantUpdates, boolean failOnMultipleModelUpdateSequences) {
- setFailOnRedundantUpdates(failOnRedundantUpdates);
- setFailOnMultipleModelUpdateSequences(failOnMultipleModelUpdateSequences);
- fViewer = viewer;
- fViewer.addLabelUpdateListener(this);
- fViewer.addModelChangedListener(this);
- fViewer.addStateUpdateListener(this);
- fViewer.addViewerUpdateListener(this);
- }
-
- public void dispose() {
- fViewer.removeLabelUpdateListener(this);
- fViewer.removeModelChangedListener(this);
- fViewer.removeStateUpdateListener(this);
- fViewer.removeViewerUpdateListener(this);
- }
-
-
- public void setFailOnRedundantUpdates(boolean failOnRedundantUpdates) {
- fFailOnRedundantUpdates = failOnRedundantUpdates;
- }
-
- public void setFailOnMultipleModelUpdateSequences(boolean failOnMultipleLabelUpdateSequences) {
- fFailOnMultipleModelUpdateSequences = failOnMultipleLabelUpdateSequences;
+ @Override
+ protected <V> Map<TreePath, V> makeTreePathMap() {
+ return new TreeMap<TreePath, V>(fTestElementVMCComparator);
}
+
- public void setFailOnMultipleLabelUpdateSequences(boolean failOnMultipleLabelUpdateSequences) {
- fFailOnMultipleLabelUpdateSequences = failOnMultipleLabelUpdateSequences;
+ public TestModelUpdatesListener() {
+ super();
}
- /**
- * Sets the the maximum amount of time (in milliseconds) that the update listener
- * is going to wait. If set to -1, the listener will wait indefinitely.
- */
- public void setTimeoutInterval(int milis) {
- fTimeoutInterval = milis;
+ public TestModelUpdatesListener(ITreeModelViewer viewer, boolean failOnRedundantUpdates, boolean failOnMultipleModelUpdateSequences) {
+ super(viewer, failOnRedundantUpdates, failOnMultipleModelUpdateSequences);
}
public void reset(TreePath path, TestElement element, int levels, boolean failOnRedundantUpdates, boolean failOnMultipleUpdateSequences) {
- reset();
+ reset(failOnRedundantUpdates, failOnMultipleUpdateSequences);
addUpdates(path, element, levels);
- addProxies(element);
- setFailOnRedundantUpdates(failOnRedundantUpdates);
- setFailOnMultipleModelUpdateSequences(failOnMultipleUpdateSequences);
- setFailOnMultipleLabelUpdateSequences(false);
}
public void reset(boolean failOnRedundantUpdates, boolean failOnMultipleUpdateSequences) {
@@ -193,67 +134,6 @@ public class TestModelUpdatesListener
setFailOnMultipleLabelUpdateSequences(false);
}
- public void reset() {
- fHasChildrenUpdates.clear();
- fChildrenUpdates.clear();
- fChildCountUpdates.clear();
- fLabelUpdates.clear();
- fProxyModels.clear();
- fViewerUpdatesComplete = false;
- fLabelUpdatesComplete = false;
- fStateSaveComplete = false;
- fStateRestoreComplete = false;
- fTimeoutTime = System.currentTimeMillis() + fTimeoutInterval;
- resetModelChanged();
- }
-
- public void resetModelChanged() {
- fModelChangedComplete = false;
- }
-
- public void addHasChildrenUpdate(TreePath path) {
- fHasChildrenUpdates.add(path);
- }
-
- public void removeHasChildrenUpdate(TreePath path) {
- fHasChildrenUpdates.remove(path);
- }
-
- public void addChildreCountUpdate(TreePath path) {
- fChildCountUpdates.add(path);
- }
-
- public void removeChildreCountUpdate(TreePath path) {
- fChildCountUpdates.remove(path);
- }
-
- public void addChildreUpdate(TreePath path, int index) {
- Set<Integer> childrenIndexes = fChildrenUpdates.get(path);
- if (childrenIndexes == null) {
- childrenIndexes = new TreeSet<Integer>();
- fChildrenUpdates.put(path, childrenIndexes);
- }
- childrenIndexes.add(new Integer(index));
- }
-
- public void removeChildrenUpdate(TreePath path, int index) {
- Set<Integer> childrenIndexes = fChildrenUpdates.get(path);
- if (childrenIndexes != null) {
- childrenIndexes.remove(new Integer(index));
- if (childrenIndexes.isEmpty()) {
- fChildrenUpdates.remove(path);
- }
- }
- }
-
- public void addLabelUpdate(TreePath path) {
- fLabelUpdates.add(path);
- }
-
- public void removeLabelUpdate(TreePath path) {
- fLabelUpdates.remove(path);
- }
-
public void addUpdates(TreePath path, TestElement element, int levels) {
addUpdates(path, element, levels, ALL_UPDATES_COMPLETE);
}
@@ -269,29 +149,30 @@ public class TestModelUpdatesListener
public void addUpdates(ITreeModelContentProviderTarget viewer, TreePath path, TestElement element, int levels, int flags) {
if (!path.equals(TreePath.EMPTY)) {
if ((flags & LABEL_UPDATES) != 0) {
- fLabelUpdates.add(path);
+ addLabelUpdate(path);
+ }
+ if ((flags & PROPERTY_UPDATES) != 0) {
+ addPropertiesUpdate(path);
}
if ((flags & HAS_CHILDREN_UPDATES) != 0) {
- fHasChildrenUpdates.add(path);
+ addHasChildrenUpdate(path);
}
}
if (levels-- != 0) {
TestElement[] children = element.getChildren();
if (children.length > 0 && (viewer == null || path.getSegmentCount() == 0 || viewer.getExpandedState(path))) {
- if ((flags & CHILDREN_COUNT_UPDATES) != 0) {
- fChildCountUpdates.add(path);
+ if ((flags & CHILD_COUNT_UPDATES) != 0) {
+ addChildCountUpdate(path);
}
if ((flags & CHILDREN_UPDATES) != 0) {
- Set<Integer> childrenIndexes = new HashSet<Integer>();
for (int i = 0; i < children.length; i++) {
- childrenIndexes.add(new Integer(i));
+ addChildreUpdate(path, i);
}
- fChildrenUpdates.put(path, childrenIndexes);
}
if ((flags & STATE_UPDATES) != 0 && viewer != null) {
- fStateUpdates.add(path);
+ addStateUpdate(path);
}
for (int i = 0; i < children.length; i++) {
@@ -301,284 +182,6 @@ public class TestModelUpdatesListener
}
}
-
- private void addProxies(TestElement element) {
- TestModel model = element.getModel();
- if (model.getModelProxy() == null) {
- fProxyModels.add(element.getModel());
- }
- TestElement[] children = element.getChildren();
- for (int i = 0; i < children.length; i++) {
- addProxies(children[i]);
- }
- }
-
- public boolean isFinished() {
- return isFinished(ALL_UPDATES_COMPLETE);
- }
-
- public boolean isFinished(int flags) {
- if (fTimeoutInterval > 0 && fTimeoutTime < System.currentTimeMillis()) {
- throw new RuntimeException("Timed Out: " + toString(flags));
- }
-
- if ( (flags & LABEL_UPDATES_COMPLETE) != 0) {
- if (!fLabelUpdatesComplete) return false;
- }
- if ( (flags & LABEL_UPDATES) != 0) {
- if (!fLabelUpdates.isEmpty()) return false;
- }
- if ( (flags & CONTENT_UPDATES_COMPLETE) != 0) {
- if (!fViewerUpdatesComplete) return false;
- }
- if ( (flags & HAS_CHILDREN_UPDATES) != 0) {
- if (!fHasChildrenUpdates.isEmpty()) return false;
- }
- if ( (flags & CHILDREN_COUNT_UPDATES) != 0) {
- if (!fChildCountUpdates.isEmpty()) return false;
- }
- if ( (flags & CHILDREN_UPDATES) != 0) {
- if (!fChildrenUpdates.isEmpty()) return false;
- }
- if ( (flags & MODEL_CHANGED_COMPLETE) != 0) {
- if (!fModelChangedComplete) return false;
- }
- if ( (flags & STATE_SAVE_COMPLETE) != 0) {
- if (!fStateSaveComplete) return false;
- }
- if ( (flags & STATE_RESTORE_COMPLETE) != 0) {
- if (!fStateRestoreComplete) return false;
- }
- if ( (flags & MODEL_PROXIES_INSTALLED) != 0) {
- if (fProxyModels.size() != 0) return false;
- }
- if ( (flags & VIEWER_UPDATES_RUNNING) != 0) {
- if (fViewerUpdatesRunning != 0) {
- return false;
- }
- }
- if ( (flags & LABEL_UPDATES_RUNNING) != 0) {
- if (fLabelUpdatesRunning != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- public void updateStarted(IViewerUpdate update) {
- synchronized (this) {
- fViewerUpdatesRunning++;
- }
- }
-
- public void updateComplete(IViewerUpdate update) {
- synchronized (this) {
- fViewerUpdatesRunning--;
- }
-
- if (!update.isCanceled()) {
- if (update instanceof IHasChildrenUpdate) {
- if (!fHasChildrenUpdates.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
- Assert.fail("Redundant update: " + update);
- }
- } if (update instanceof IChildrenCountUpdate) {
- if (!fChildCountUpdates.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
- Assert.fail("Redundant update: " + update);
- }
- } else if (update instanceof IChildrenUpdate) {
- int start = ((IChildrenUpdate)update).getOffset();
- int end = start + ((IChildrenUpdate)update).getLength();
-
- Set<Integer> childrenIndexes = fChildrenUpdates.get(update.getElementPath());
- if (childrenIndexes != null) {
- for (int i = start; i < end; i++) {
- childrenIndexes.remove(new Integer(i));
- }
- if (childrenIndexes.isEmpty()) {
- fChildrenUpdates.remove(update.getElementPath());
- }
- } else if (fFailOnRedundantUpdates) {
- Assert.fail("Redundant update: " + update);
- }
- }
- }
- }
-
- public void viewerUpdatesBegin() {
-
- }
-
- public void viewerUpdatesComplete() {
- if (fFailOnMultipleModelUpdateSequences && fViewerUpdatesComplete) {
- Assert.fail("Multiple viewer update sequences detected");
- }
- fViewerUpdatesComplete = true;
- }
-
- public void labelUpdateComplete(ILabelUpdate update) {
- synchronized (this) {
- fLabelUpdatesRunning--;
- }
- if (!fLabelUpdates.remove(update.getElementPath()) && fFailOnRedundantUpdates) {
- Assert.fail("Redundant update: " + update);
- }
- }
-
- public void labelUpdateStarted(ILabelUpdate update) {
- synchronized (this) {
- fLabelUpdatesRunning++;
- }
- }
-
- public void labelUpdatesBegin() {
- }
-
- public void labelUpdatesComplete() {
- if (fFailOnMultipleLabelUpdateSequences && fLabelUpdatesComplete) {
- Assert.fail("Multiple label update sequences detected");
- }
- fLabelUpdatesComplete = true;
- }
-
- public void modelChanged(IModelDelta delta, IModelProxy proxy) {
- fModelChangedComplete = true;
-
- for (Iterator<TestModel> itr = fProxyModels.iterator(); itr.hasNext();) {
- TestModel model = itr.next();
- if (model.getModelProxy() == proxy) {
- itr.remove();
- break;
- }
- }
- }
-
- public void stateRestoreUpdatesBegin(Object input) {
- }
-
- public void stateRestoreUpdatesComplete(Object input) {
- fStateRestoreComplete = true;
- }
-
- public void stateSaveUpdatesBegin(Object input) {
- }
-
- public void stateSaveUpdatesComplete(Object input) {
- fStateSaveComplete = true;
- }
-
- public void stateUpdateComplete(Object input, IViewerUpdate update) {
- }
-
- public void stateUpdateStarted(Object input, IViewerUpdate update) {
- }
-
- private String toString(int flags) {
- StringBuffer buf = new StringBuffer("Viewer Update Listener");
-
- if ( (flags & LABEL_UPDATES_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fLabelUpdatesComplete = " + fLabelUpdatesComplete);
- }
- if ( (flags & LABEL_UPDATES_RUNNING) != 0) {
- buf.append("\n\t");
- buf.append("fLabelUpdatesRunning = " + fLabelUpdatesRunning);
- }
- if ( (flags & LABEL_UPDATES) != 0) {
- buf.append("\n\t");
- buf.append("fLabelUpdates = ");
- buf.append( toString(fLabelUpdates) );
- }
- if ( (flags & CONTENT_UPDATES_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fViewerUpdatesComplete = " + fViewerUpdatesComplete);
- }
- if ( (flags & VIEWER_UPDATES_RUNNING) != 0) {
- buf.append("\n\t");
- buf.append("fViewerUpdatesRunning = " + fViewerUpdatesRunning);
- }
- if ( (flags & HAS_CHILDREN_UPDATES) != 0) {
- buf.append("\n\t");
- buf.append("fHasChildrenUpdates = ");
- buf.append( toString(fHasChildrenUpdates) );
- }
- if ( (flags & CHILDREN_COUNT_UPDATES) != 0) {
- buf.append("\n\t");
- buf.append("fChildCountUpdates = ");
- buf.append( toString(fChildCountUpdates) );
- }
- if ( (flags & CHILDREN_UPDATES) != 0) {
- buf.append("\n\t");
- buf.append("fChildrenUpdates = ");
- buf.append( toString(fChildrenUpdates) );
- }
- if ( (flags & MODEL_CHANGED_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fModelChangedComplete = " + fModelChangedComplete);
- }
- if ( (flags & STATE_SAVE_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fStateSaveComplete = " + fStateSaveComplete);
- }
- if ( (flags & STATE_RESTORE_COMPLETE) != 0) {
- buf.append("\n\t");
- buf.append("fStateRestoreComplete = " + fStateRestoreComplete);
- }
- if ( (flags & MODEL_PROXIES_INSTALLED) != 0) {
- buf.append("\n\t");
- buf.append("fProxyModels = " + fProxyModels);
- }
- if (fTimeoutInterval > 0) {
- buf.append("\n\t");
- buf.append("fTimeoutInterval = " + fTimeoutInterval);
- }
- return buf.toString();
- }
-
- private String toString(Set<TreePath> set) {
- if (set.isEmpty()) {
- return "(EMPTY)";
- }
- StringBuffer buf = new StringBuffer();
- for (Iterator<TreePath> itr = set.iterator(); itr.hasNext(); ) {
- buf.append("\n\t\t");
- buf.append(toString(itr.next()));
- }
- return buf.toString();
- }
-
- private String toString(Map<TreePath, Set<Integer>> map) {
- if (map.isEmpty()) {
- return "(EMPTY)";
- }
- StringBuffer buf = new StringBuffer();
- for (Iterator<TreePath> itr = map.keySet().iterator(); itr.hasNext(); ) {
- buf.append("\n\t\t");
- TreePath path = itr.next();
- buf.append(toString(path));
- Set<?> updates = map.get(path);
- buf.append(" = ");
- buf.append(updates.toString());
- }
- return buf.toString();
- }
-
- private String toString(TreePath path) {
- if (path.getSegmentCount() == 0) {
- return "/";
- }
- StringBuffer buf = new StringBuffer();
- for (int i = 0; i < path.getSegmentCount(); i++) {
- buf.append("/");
- buf.append(path.getSegment(i));
- }
- return buf.toString();
- }
-
- @Override
- public String toString() {
- return toString(ALL_UPDATES_COMPLETE | MODEL_CHANGED_COMPLETE | STATE_RESTORE_COMPLETE);
- }
}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMAdapter.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMAdapter.java
index 2e610714c79..90d37eb6dfb 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMAdapter.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMAdapter.java
@@ -15,7 +15,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
- *
+ * @since 2.2
*/
public class TestModelVMAdapter extends AbstractVMAdapter {
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMNode.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMNode.java
index 959dd2d5b4b..c7f11ac9988 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMNode.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMNode.java
@@ -13,9 +13,10 @@ package org.eclipse.cdt.tests.dsf.vm;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueLabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
-import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
@@ -23,6 +24,7 @@ import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelAttribute;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelColumnInfo;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -33,7 +35,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdat
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
/**
- *
+ * @since 2.2
*/
public class TestModelVMNode extends AbstractVMNode implements IRootVMNode, IElementLabelProvider, IElementPropertiesProvider {
@@ -41,10 +43,16 @@ public class TestModelVMNode extends AbstractVMNode implements IRootVMNode, IEle
final private static PropertiesBasedLabelProvider fLabelProvider = new PropertiesBasedLabelProvider();
{
+ LabelColumnInfo idLabelInfo = new LabelColumnInfo(new LabelAttribute[] {
+ new LabelText("{0}", new String[] { PROP_TEST_ELEMENT_LABEL })
+ });
+
+ fLabelProvider.setColumnInfo(PropertiesBasedLabelProvider.ID_COLUMN_NO_COLUMNS, idLabelInfo);
+ fLabelProvider.setColumnInfo(TestModelCachingVMProvider.COLUMN_ID, idLabelInfo);
fLabelProvider.setColumnInfo(
- PropertiesBasedLabelProvider.ID_COLUMN_NO_COLUMNS,
- new LabelColumnInfo(new LabelAttribute[] {
- new LabelText("{0}", new String[] { PROP_TEST_ELEMENT_LABEL })
+ TestModelCachingVMProvider.COLUMN_FORMATTED_VALUE,
+ new LabelColumnInfo(new LabelAttribute[] {
+ new FormattedValueLabelText()
}));
}
@@ -52,7 +60,7 @@ public class TestModelVMNode extends AbstractVMNode implements IRootVMNode, IEle
fLabelProvider.update(updates);
}
- public TestModelVMNode(IVMProvider provider) {
+ public TestModelVMNode(AbstractVMProvider provider) {
super(provider);
}
@@ -123,7 +131,7 @@ public class TestModelVMNode extends AbstractVMNode implements IRootVMNode, IEle
}
public void createRootDelta(Object rootObject, Object event, DataRequestMonitor<VMDelta> rm) {
- rm.setStatus(new Status(IStatus.ERROR, TestDsfVMPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Not implemented", null));
+ rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Not implemented", null));
rm.done();
}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMProvider.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMProvider.java
index b8265593367..a53186d1b8e 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMProvider.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/TestModelVMProvider.java
@@ -19,9 +19,10 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
- *
+ * @since 2.2
*/
public class TestModelVMProvider extends AbstractVMProvider {
+
public TestModelVMProvider(AbstractVMAdapter adapter, IPresentationContext context) {
super(adapter, context);
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/VirtualViewerPerformanceTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/VirtualViewerPerformanceTests.java
index 072fa267240..91cca156730 100644
--- a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/VirtualViewerPerformanceTests.java
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/vm/VirtualViewerPerformanceTests.java
@@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
- * @since 3.6
+ * @since 2.2
*/
public class VirtualViewerPerformanceTests extends PerformanceTests {

Back to the top