1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Bug 321932 - [update policy] When in manual mode, switching number format should still show value in other formats if value is cached.

This commit is contained in:
Pawel Piech 2010-09-24 18:58:49 +00:00
parent de6322ba9c
commit 4d3edd80a2
44 changed files with 3956 additions and 844 deletions

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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)) {

View file

@ -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= \
ErrorLabelText_Error_message__text_page_break_delimiter= \\

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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
@ -47,6 +48,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.
*/
@ -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.
*
* @deprecated Replaced by {@link #getFormatFromProperty(String, String)}
*/
public static String getFormatFromProperty(String property) {
return getFormatFromProperty(property, ""); //$NON-NLS-1$
}
/**
* Returns a format ID based on the element property representing a
* formatted element value.
* 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) {
return property.substring(IDebugVMConstants.PROP_FORMATTED_VALUE_BASE.length() + 1);
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(

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {
@ -65,18 +103,17 @@ 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);
}
}

View file

@ -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) {

View file

@ -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.
*/

View file

@ -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);
}

View file

@ -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

View file

@ -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.

View file

@ -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);
}
}
/**

View file

@ -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;
}
}
}

View file

@ -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$

View file

@ -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;
@ -85,6 +102,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.

View file

@ -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);
if (update.getProperties().contains(PROP_CACHE_ENTRY_DIRTY)) {
properties.put(PROP_CACHE_ENTRY_DIRTY, Boolean.TRUE);
// 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)) {
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();
}
}));

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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());

View file

@ -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);
}
}

View file

@ -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));
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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);
public static final class TestEvent {
private final TestElement fElement;
private final int fType;
public TestEvent(TestElement element, int type) {
fElement = element;
fType = type;
}
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 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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
@Override
protected Set<TreePath> makeTreePathSet() {
return new TreeSet<TreePath>(fTestElementVMCComparator);
}
@Override
protected <V> Map<TreePath, V> makeTreePathMap() {
return new TreeMap<TreePath, V>(fTestElementVMCComparator);
}
public TestModelUpdatesListener() {
super();
}
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;
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;
}
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;
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);
}
}

View file

@ -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 {

View file

@ -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();
}

View file

@ -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);

View file

@ -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 {