1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

[220446] Updated the timers example for use with the "DSF Common Patterns" document.

This commit is contained in:
Pawel Piech 2008-03-04 05:20:05 +00:00
parent 8868398cc9
commit abc958a96a
19 changed files with 916 additions and 1049 deletions

View file

@ -13,7 +13,7 @@
icon="icons/timer.gif"
category="org.eclipse.dd.examples.dsf"
class="org.eclipse.dd.examples.dsf.timers.TimersView"
id="org.eclipse.dd.dsf.examples.model.TimersAlarmsView">
id="org.eclipse.dd.examples.dsf.TimersView">
</view>
</extension>
<extension

View file

@ -64,6 +64,7 @@ public class FileBrowserVMProvider extends AbstractVMProvider
addChildNodes(root, new IVMNode[] { fileSystemRoots });
IVMNode files = new FileVMNode(this);
addChildNodes(fileSystemRoots, new IVMNode[] { files });
addChildNodes(files, new IVMNode[] { files });
setRootNode(root);
}

View file

@ -34,4 +34,9 @@ class FileVMContext extends AbstractVMContext {
public int hashCode() {
return fFile.hashCode();
}
@Override
public String toString() {
return fFile.toString();
}
}

View file

@ -190,7 +190,7 @@ class FileVMNode
}
public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm) {
rm.setStatus(new Status(IStatus.OK, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
rm.done();
}

View file

@ -11,163 +11,114 @@
package org.eclipse.dd.examples.dsf.timers;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
import org.eclipse.dd.dsf.datamodel.AbstractDMEvent;
import org.eclipse.dd.dsf.datamodel.DMContexts;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMService;
import org.eclipse.dd.dsf.service.AbstractDsfService;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerData;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerTickEvent;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerTickDMEvent;
import org.osgi.framework.BundleContext;
/**
* Alarm service tracks a set of alarm objects which are occacionally
* triggered by the timers from the TimerService.
* The alarm service tracks triggers and alarms. Triggers have a specified
* value and can be created and removed independently. Alarms are created
* for a specific timer and a trigger, and can indicate whether an alarm is
* triggered.
* <p>
* This service depends on the TimerService, so the TimerService has to be
* running before this service is initialized. However, the alarm objects
* themeselves do not depend on the timers, they can be listed, created,
* removed without any timers present. So a separate context object exists
* to track alarm status, which requires both an alarm and a timer in order
* to exist.
* initialized before this service is initialized.
* </p>
*/
public class AlarmService extends AbstractDsfService
implements IDMService
{
/**
* Event indicating that the list of alarms is changed and the clients
* which display alarms should re-query this list.
*/
public class AlarmsChangedEvent extends AbstractDMEvent<IDMContext> {
AlarmsChangedEvent() { super(fAlarmsContext); }
}
/** Event indicating that the list of triggers is changed. */
@Immutable
public static class TriggersChangedEvent {}
/**
* Context representing an alarm tracked by this service.
*/
public static class AlarmDMC extends AbstractDMContext {
/** Context representing an alarm tracked by this service. */
@Immutable
public static class TriggerDMContext extends AbstractDMContext {
/** Alarm number, also index into alarm map */
final int fAlarm;
final int fNumber;
public AlarmDMC(AlarmService service, int alarm) {
super(service, new IDMContext[] { service.fAlarmsContext });
fAlarm = alarm;
private TriggerDMContext(String sessionId, int number) {
super(sessionId, new IDMContext[0]);
fNumber = number;
}
@Override
public boolean equals(Object other) {
return baseEquals(other) && ((AlarmDMC)other).fAlarm == fAlarm;
return baseEquals(other) &&
((TriggerDMContext)other).fNumber == fNumber;
}
public int getTriggerNumber() {
return fNumber;
}
@Override
public int hashCode() { return baseHashCode() + fAlarm; }
public int hashCode() {
return baseHashCode() + fNumber;
}
@Override
public String toString() { return baseToString() + ".alarm[" + fAlarm + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
public String toString() {
return baseToString() + ".trigger[" + fNumber + "]";
}
}
/**
* Data object containing information about the alarm. This object
* references internal service data, so it has to guard agains this data
* being obsolete.
*/
public class AlarmData implements IDMData {
private int fAlarmNumber;
AlarmData(int alarmNumber) { fAlarmNumber = alarmNumber; }
public boolean isValid() { return fAlarms.containsKey(fAlarmNumber); }
public int getAlarmNumber() { return fAlarmNumber; }
public int getTriggeringValue() {
if (!isValid()) return -1;
return fAlarms.get(fAlarmNumber);
}
}
/**
* Context representing the "triggered" status of an alarm with respect to
* a specific timer. Having this object separate from the alarm itself
* allows the alarm object to exist independently of the timers.
* a specific timer.
*/
public class AlarmStatusContext extends AbstractDMContext {
/**
* An alarm status requires both a timer and alarm context, both of which
* become parents of the status context.
*/
public AlarmStatusContext(AbstractDsfService service, TimerDMC timerCtx, AlarmDMC alarmCtx) {
super(service.getSession().getId(), new IDMContext[] { timerCtx, alarmCtx });
@Immutable
public static class AlarmDMContext extends AbstractDMContext {
// An alarm requires both a timer and alarm context, both of which
// become parents of the alarm context.
// Note: beyond the parent contexts this context does not contain
// any other data, because no other data is needed.
private AlarmDMContext(String sessionId,
TimerDMContext timerCtx, TriggerDMContext alarmCtx)
{
super(sessionId, new IDMContext[] { timerCtx, alarmCtx });
}
@Override
public boolean equals(Object other) { return baseEquals(other); }
@Override
public int hashCode() { return baseHashCode(); }
public int hashCode() { return baseHashCode(); }
@Override
public String toString() {
return baseToString() + ":alarm_status"; //$NON-NLS-1$
return baseToString() + ":alarm"; //$NON-NLS-1$
}
}
/**
* Data about alarm status. No surprises here.
*
* Event indicating that an alarm has been triggered by a timer.
*/
public class AlarmStatusData implements IDMData {
private boolean fIsTriggered;
public boolean isValid() { return true; }
AlarmStatusData(boolean triggered) { fIsTriggered = triggered; }
public boolean isTriggered() { return fIsTriggered; }
}
/**
* Event indicating that an alarm has been triggered by a timer. The
* status context object's parents indicate which alarm and timer are
* involved.
*/
public class AlarmTriggeredEvent extends AbstractDMEvent<AlarmStatusContext> {
public AlarmTriggeredEvent(AlarmStatusContext context) {
public class AlarmTriggeredEvent extends AbstractDMEvent<AlarmDMContext> {
public AlarmTriggeredEvent(AlarmDMContext context) {
super(context);
}
}
private int fTriggerNumberCounter = 1;
private Map<TriggerDMContext, Integer> fTriggers =
new LinkedHashMap<TriggerDMContext, Integer>();
/** Parent context for all alarms */
private final IDMContext fAlarmsContext;
/** Counter for generating alarm numbers */
private int fAlarmCounter = 1;
/** Map holding the alarms */
private Map<Integer,Integer> fAlarms = new TreeMap<Integer,Integer>();
/** Constructor requires only the session for this service */
AlarmService(DsfSession session) {
super(session);
fAlarmsContext = new AbstractDMContext(this, new IDMContext[0]) {
private final Object fHashObject = new Object();
@Override
public boolean equals(Object obj) { return (this == obj); };
@Override
public int hashCode() { return fHashObject.hashCode(); }
@Override
public String toString() { return "#alarms"; } //$NON-NLS-1$
};
}
@Override
@ -181,17 +132,20 @@ public class AlarmService extends AbstractDsfService
new RequestMonitor(getExecutor(), requestMonitor) {
@Override
protected void handleOK() {
// After super-class is finished initializing
// perform TimerService initialization.
doInitialize(requestMonitor);
}});
}
/**
* Initialization routine registers the service, and adds it as a listener
* to service events.
*/
private void doInitialize(RequestMonitor requestMonitor) {
// Add this class as a listener for service events, in order to receive
// TimerTickEvent events.
getSession().addServiceEventListener(this, null);
// Register service
register(new String[]{AlarmService.class.getName()}, new Hashtable<String,String>());
requestMonitor.done();
}
@ -204,158 +158,95 @@ public class AlarmService extends AbstractDsfService
public boolean isValid() { return true; }
@SuppressWarnings("unchecked")
public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
if (dmc instanceof AlarmDMC) {
getAlarmData((AlarmDMC)dmc, (DataRequestMonitor<AlarmData>)rm);
return;
} else if (dmc instanceof AlarmStatusContext) {
getAlarmStatusData((AlarmStatusContext)dmc, (DataRequestMonitor<AlarmStatusData>)rm);
return;
} else if (dmc == fAlarmsContext) {
((DataRequestMonitor<AlarmService>)rm).setData(this);
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
}
rm.done();
}
/**
* Listener for timer ticks events. If a timer triggers an alarm, this
* service needs to issue an alarm triggered event.
* @param event
*/
@DsfServiceEventHandler
public void eventDispatched(TimerTickEvent event) {
final TimerDMC timerContext = event.getDMContext();
public void eventDispatched(TimerTickDMEvent event) {
final TimerDMContext timerContext = event.getDMContext();
getServicesTracker().getService(TimerService.class).getTimerData(
event.getDMContext(),
new DataRequestMonitor<TimerData>(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!getStatus().isOK()) return;
checkAlarmsForTimer(timerContext, getData().getTimerValue());
}
@Override public String toString() { return "Got timer data: " + getData(); } //$NON-NLS-1$
});
int timerValue = getServicesTracker().getService(TimerService.class).
getTimerValue(event.getDMContext());
// If a timer triggers an alarm, this service needs to issue an alarm
// triggered event.
checkAlarmsForTimer(timerContext, timerValue);
}
/**
* Checks the existing alarms for whether they are triggered by given timer.
* @param timerContext Context of the timer that is changed.
* @param timerValue Current value of the timer.
*/
private void checkAlarmsForTimer(TimerDMC timerContext, int timerValue) {
for (Map.Entry<Integer,Integer> entry : fAlarms.entrySet()) {
private void checkAlarmsForTimer(TimerDMContext timerContext, int timerValue) {
// Check the existing alarms for whether they are triggered by given
// timer.
for (Map.Entry<TriggerDMContext, Integer> entry : fTriggers.entrySet()) {
if (timerValue == entry.getValue()) {
getSession().dispatchEvent(new AlarmTriggeredEvent(
new AlarmStatusContext(this, timerContext, new AlarmDMC(this, entry.getKey()))),
getProperties());
// Generate the AlarmTriggeredEvent
AlarmDMContext alarmCtx = new AlarmDMContext(
getSession().getId(), timerContext, entry.getKey());
getSession().dispatchEvent(
new AlarmTriggeredEvent(alarmCtx), getProperties());
}
}
}
/**
* Retrieves the list of alarm contexts.
*
* <br>Note: this method doesn't need to be asynchronous, because all the
* data is stored locally. But using an asynchronous method makes this a
* more applicable example.
*
* @param rm Return data token.
*/
public void getAlarms(DataRequestMonitor<AlarmDMC[]> rm) {
AlarmDMC[] alarmContexts = new AlarmDMC[fAlarms.size()];
int i = 0;
for (int alarm : fAlarms.keySet()) {
alarmContexts[i++] = new AlarmDMC(this, alarm);
/** Returns the list of triggers. */
public TriggerDMContext[] getTriggers() {
return fTriggers.keySet().toArray(new TriggerDMContext[fTriggers.size()]);
}
/** Returns the trigger value. */
public int getTriggerValue(TriggerDMContext alarmCtx) {
Integer value = fTriggers.get(alarmCtx);
if (value != null) {
return value;
} else {
return -1;
}
rm.setData(alarmContexts);
rm.done();
}
/**
* Retrieves the data object for given alarm context.
*
* <br>Note: likewise this method doesn't need to be asynchronous.
*/
public void getAlarmData(AlarmDMC alarmCtx, DataRequestMonitor<AlarmData> rm) {
if (!fAlarms.containsKey(alarmCtx.fAlarm)) {
rm.setStatus(new Status(
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Alarm context invalid", null)); //$NON-NLS-1$
rm.done();
return;
/** Returns the alarm context for given timer and trigger contexts. */
public AlarmDMContext getAlarmS(TriggerDMContext alarmCtx, TimerDMContext timerCtx) {
return new AlarmDMContext(getSession().getId(), timerCtx, alarmCtx);
}
/** Returns true if the given alarm is triggered */
public boolean isAlarmTriggered(AlarmDMContext alarmCtx) {
// Extract the timer and trigger contexts. They should always be part
// of the alarm.
TimerService.TimerDMContext timerCtx = DMContexts.getAncestorOfType(
alarmCtx, TimerService.TimerDMContext.class);
TriggerDMContext triggerCtx = DMContexts.getAncestorOfType(
alarmCtx, TriggerDMContext.class);
assert triggerCtx != null && timerCtx != null;
// Find the trigger and check whether the timers value has surpassed it.
if (fTriggers.containsKey(triggerCtx)) {
int timerValue = getServicesTracker().getService(TimerService.class).
getTimerValue(timerCtx);
return timerValue >= fTriggers.get(triggerCtx);
}
rm.setData(new AlarmData(alarmCtx.fAlarm));
rm.done();
}
/**
* Returns the alarm status context object, for given timer and alarms.
*
* <br>Note: this method is synchronous... for variety.
*/
public AlarmStatusContext getAlarmStatus(AlarmDMC alarmCtx, TimerDMC timerCtx) {
return new AlarmStatusContext(this, timerCtx, alarmCtx);
}
/**
* Returns the data object for given alarm status object.
*/
public void getAlarmStatusData(AlarmStatusContext alarmStatusCtx, final DataRequestMonitor<AlarmStatusData> rm) {
final TimerService.TimerDMC timerCtx = DMContexts.getAncestorOfType(
alarmStatusCtx, TimerService.TimerDMC.class);
final AlarmDMC alarmCtx = DMContexts.getAncestorOfType(
alarmStatusCtx, AlarmDMC.class);
assert alarmCtx != null && timerCtx != null;
getServicesTracker().getService(TimerService.class).getTimerData(
timerCtx,
new DataRequestMonitor<TimerData>(getExecutor(), rm) {
@Override
protected void handleOK() {
if (!fAlarms.containsKey(alarmCtx.fAlarm)) {
rm.setStatus(new Status(
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Alarm context invalid", null)); //$NON-NLS-1$
rm.done();
return;
}
boolean isTriggered = getData().getTimerValue() >= fAlarms.get(alarmCtx.fAlarm);
rm.setData(new AlarmStatusData(isTriggered));
rm.done();
}
});
return false;
}
/**
* Creates a new alarm object with given value.
* @return context of the new alarm.
*/
public AlarmDMC createAlarm(int value) {
int newAlarm = fAlarmCounter++;
fAlarms.put(newAlarm, value);
getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties());
return new AlarmDMC(this, newAlarm);
/** Creates a new alarm object with given value. */
public TriggerDMContext createTrigger(int value) {
TriggerDMContext triggerCtx =
new TriggerDMContext(getSession().getId(), fTriggerNumberCounter++);
fTriggers.put(triggerCtx, value);
getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
return triggerCtx;
}
/** Removes given alarm from service. */
public void deleteAlarm(AlarmDMC alarmCtx) {
fAlarms.remove(alarmCtx.fAlarm);
getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties());
public void deleteTrigger(TriggerDMContext alarmCtx) {
fTriggers.remove(alarmCtx);
getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
}
/**
* Changes the value of the given alarm.
* @param dmc Alarm to change
* @param newValue New alarm value.
*/
public void setAlarmValue(AlarmDMC dmc, int newValue) {
if (fAlarms.containsKey(dmc.fAlarm)) {
fAlarms.put(dmc.fAlarm, newValue);
/** Changes the value of the given trigger. */
public void setTriggerValue(TriggerDMContext ctx, int newValue) {
if (fTriggers.containsKey(ctx)) {
fTriggers.put(ctx, newValue);
}
getSession().dispatchEvent(new AlarmsChangedEvent(), getProperties());
getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
}
}

View file

@ -1,112 +0,0 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmStatusContext;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmStatusData;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC;
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.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
* View model node that determines whether an "alarm triggered" indicator is
* shown in the tree. This indicator is only shown if a given alarm is
* triggered for a given timer.
*
* @see AlarmStatusContext
*/
@SuppressWarnings("restriction")
class AlarmStatusVMNode extends AbstractDMVMNode
implements IElementLabelProvider
{
public AlarmStatusVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, AlarmStatusContext.class);
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(AlarmService.class, null, update)) return;
if (!checkService(TimerService.class, null, update)) return;
AlarmDMC alarmDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), AlarmDMC.class);
TimerDMC timerDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMC.class);
if (alarmDmc == null || timerDmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path")); //$NON-NLS-1$
update.done();
return;
}
// Get the alarm status DMC then check the triggered value to make sure it's triggered.
final AlarmStatusContext alarmStatusDmc = getServicesTracker().getService(AlarmService.class).
getAlarmStatus(alarmDmc, timerDmc);
getServicesTracker().getService(AlarmService.class).getAlarmStatusData(
alarmStatusDmc,
new DataRequestMonitor<AlarmStatusData>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
if (isDisposed()) return;
if (!getStatus().isOK()) {
update.setStatus(getStatus());
} else {
if (getData().isTriggered()) {
update.setChild(createVMContext(alarmStatusDmc), 0);
}
}
update.done();
}});
}
public void update(ILabelUpdate[] updates) {
for (ILabelUpdate update : updates) {
update.setLabel("ALARM TRIGGERED", 0); //$NON-NLS-1$
update.setImageDescriptor(
DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_ALARM_TRIGGERED),
0);
update.done();
}
}
public int getDeltaFlags(Object e) {
// This node generates delta if the timers have changed, or if the
// label has changed.
if (e instanceof AlarmService.AlarmTriggeredEvent) {
return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND;
}
return IModelDelta.NO_CHANGE;
}
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
// An element is added when and selected upon a triggered event.
// Parent element is also expanded allow element to be selected.
if (e instanceof AlarmService.AlarmTriggeredEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
parentDelta.addNode(
createVMContext( ((AlarmService.AlarmTriggeredEvent)e).getDMContext() ),
0,
IModelDelta.ADDED | IModelDelta.SELECT);
}
requestMonitor.done();
}
}

View file

@ -10,203 +10,96 @@
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import java.text.MessageFormat;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmData;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMContext;
import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.widgets.Composite;
/**
* View model node that defines how alarm DMContexts are displayed in the view. Alarm
* nodes are fairly static, once they are created their label doesn't change.
* @see AlarmDMC
* View model node that determines whether an "alarm triggered" indicator is
* shown in the tree. This indicator is only shown if a given alarm is
* triggered for a given timer.
*
* @see AlarmDMContext
*/
@SuppressWarnings("restriction")
class AlarmsVMNode extends AbstractDMVMNode
implements IElementEditor, IElementPropertiesProvider, IElementLabelProvider
implements IElementLabelProvider
{
public static final String PROP_ALARM_NUMBER = "alarmNumber"; //$NON-NLS-1$
public static final String PROP_ALARM_TRIGGER_VALUE = "alarmTriggerValue"; //$NON-NLS-1$
private AlarmCellModifier fAlarmCellModifier;
private PropertyBasedLabelProvider fLabelProvider;
public AlarmsVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, AlarmDMC.class);
fLabelProvider = new PropertyBasedLabelProvider();
LabelColumnInfo idCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("Alarm #{0}"), new String[] { PROP_ALARM_NUMBER }), //$NON-NLS-1$
new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(DsfExamplesPlugin.IMG_ALARM))
});
fLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
LabelText valueText = new LabelText(new MessageFormat("{0}"), new String[] { PROP_ALARM_TRIGGER_VALUE }); //$NON-NLS-1$
LabelColumnInfo valueCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("{0}"), new String[] { PROP_ALARM_TRIGGER_VALUE }) //$NON-NLS-1$
});
fLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE, valueCol);
super(provider, session, AlarmDMContext.class);
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
// Check that the services are available
if (!checkService(AlarmService.class, null, update)) return;
if (!checkService(TimerService.class, null, update)) return;
// Retrieve the alarm DMContexts, create the corresponding VMCs array, and
// set them as result.
getServicesTracker().getService(AlarmService.class).getAlarms(
new DataRequestMonitor<AlarmDMC[]>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
if (!getStatus().isOK()) {
update.setStatus(getStatus());
} else {
fillUpdateWithVMCs(update, getData());
}
update.done();
}});
// Find the trigger and timer contexts. If not found, fail.
TriggerDMContext alarmDmc = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
TimerDMContext timerDmc = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
if (alarmDmc == null || timerDmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path"));
update.done();
return;
}
// Get the alarm context then check the triggered value.
final AlarmDMContext alarmStatusDmc = getServicesTracker().getService(AlarmService.class).
getAlarmS(alarmDmc, timerDmc);
boolean triggered = getServicesTracker().getService(AlarmService.class).
isAlarmTriggered(alarmStatusDmc);
// Only return the alarm in list of elements if it is triggered.
if (triggered) {
update.setChild(createVMContext(alarmStatusDmc), 0);
}
update.done();
}
public void update(ILabelUpdate[] updates) {
fLabelProvider.update(updates);
}
public void update(final IPropertiesUpdate[] updates) {
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
for (IPropertiesUpdate update : updates) {
updatePropertiesInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
for (ILabelUpdate update : updates) {
update.setLabel("ALARM TRIGGERED", 0);
update.setImageDescriptor(
DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_ALARM_TRIGGERED),
0);
update.done();
}
}
@ConfinedToDsfExecutor("getSession#getExecutor")
protected void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
final AlarmDMC dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), AlarmDMC.class);
if (!checkDmc(dmc, update) || !checkService(AlarmService.class, null, update)) return;
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(AlarmService.class, null),
dmc,
new DataRequestMonitor<AlarmData>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
/*
* Check that the request was evaluated and data is still
* valid. The request could fail if the state of the
* service changed during the request, but the view model
* has not been updated yet.
*/
if (!getStatus().isOK() || !getData().isValid()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedUpdate(update);
return;
}
update.setProperty(PROP_ALARM_NUMBER, getData().getAlarmNumber());
update.setProperty(PROP_ALARM_TRIGGER_VALUE, getData().getTriggeringValue());
update.done();
}
},
getExecutor());
}
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) {
return new TextCellEditor(parent);
}
return null;
}
// Note: this method is synchronized because IElementEditor.getCellModifier can be called
// on any thread, even though in practice it should be only called on the UI thread.
public synchronized ICellModifier getCellModifier(IPresentationContext context, Object element) {
if (fAlarmCellModifier == null) {
fAlarmCellModifier = new AlarmCellModifier(getSession());
}
return fAlarmCellModifier;
}
public int getDeltaFlags(Object e) {
// Since the label for alarms doesn't change, this node will generate
// delta info only if the list of alarms is changed.
if (e instanceof AlarmService.AlarmsChangedEvent) {
return IModelDelta.CONTENT;
if (e instanceof AlarmService.AlarmTriggeredEvent) {
return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND;
}
return IModelDelta.NO_CHANGE;
}
public void buildDelta(Object event, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
if (event instanceof AlarmService.AlarmsChangedEvent) {
// The list of alarms has changed, which means that the parent
// node needs to refresh its contents, which in turn will re-fetch the
// elements from this node.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
// The alarm element is added when and selected upon a triggered event.
// Parent element is also expanded allow the alarm to be selected.
if (e instanceof AlarmService.AlarmTriggeredEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
parentDelta.addNode(
createVMContext( ((AlarmService.AlarmTriggeredEvent)e).getDMContext() ),
0,
IModelDelta.ADDED | IModelDelta.SELECT);
}
requestMonitor.done();
}
@Override
public synchronized void dispose() {
synchronized(this) {
if (fAlarmCellModifier != null) {
fAlarmCellModifier.dispose();
}
}
super.dispose();
}
public String getPropertyDescription(String property) {
// TODO Auto-generated method stub
return null;
}
public String getPropertyName(String property) {
// TODO Auto-generated method stub
return null;
}
}

View file

@ -20,15 +20,19 @@ import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
/**
* Shutdown sequence that stops the services in the timers session.
*
* Sequence that stops the services in the timers session.
*/
class ServicesShutdownSequence extends Sequence {
public class ServicesShutdownSequence extends Sequence {
DsfSession fSession;
// Session to that the services are running in.
final private DsfSession fSession;
// DSF Services is created as the first step of the sequence. It
// cannot be created by the constructor because it can only be called
// in the session thread.
DsfServicesTracker fTracker;
ServicesShutdownSequence(DsfSession session) {
public ServicesShutdownSequence(DsfSession session) {
super(session.getExecutor());
fSession = session;
}
@ -43,6 +47,8 @@ class ServicesShutdownSequence extends Sequence {
@Override
public void rollBack(RequestMonitor requestMonitor) {
// Dispose the tracker in case shutdown sequence is aborted
// and is rolled back.
fTracker.dispose();
fTracker = null;
requestMonitor.done();
@ -63,6 +69,7 @@ class ServicesShutdownSequence extends Sequence {
new Step() {
@Override
public void execute(RequestMonitor requestMonitor) {
// Dispose the tracker after the services are shut down.
fTracker.dispose();
fTracker = null;
requestMonitor.done();
@ -73,18 +80,18 @@ class ServicesShutdownSequence extends Sequence {
@Override
public Step[] getSteps() { return fSteps; }
/**
* Convenience method that shuts down given service. Only service class
* is used to identify the service.
*/
// A convenience method that shuts down given service. Only service class
// is used to identify the service.
private <V extends IDsfService> void shutdownService(Class<V> clazz, RequestMonitor requestMonitor) {
IDsfService service = fTracker.getService(clazz);
if (service != null) {
service.shutdown(requestMonitor);
}
else {
requestMonitor.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR,
"Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$ //$NON-NLS-2$
requestMonitor.setStatus(new Status(
IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
IDsfService.INTERNAL_ERROR,
"Service '" + clazz.getName() + "' not found.", null));
requestMonitor.done();
}
}

View file

@ -16,16 +16,18 @@ import org.eclipse.dd.dsf.service.DsfSession;
/**
* Startup sequence for the timers session. With only two services, this is
* a very simple sequence. Last step creates the first timer and alarm.
* a very simple sequence.
*/
class ServicesStartupSequence extends Sequence {
public class ServicesStartupSequence extends Sequence {
DsfSession fSession;
final private DsfSession fSession;
// The reference to the services are saved to use in the last step.
private TimerService fTimerService = null;
private AlarmService fAlarmService = null;
ServicesStartupSequence(DsfSession session) {
public ServicesStartupSequence(DsfSession session) {
super(session.getExecutor());
fSession = session;
}
@ -46,8 +48,9 @@ class ServicesStartupSequence extends Sequence {
new Step() {
@Override
public void execute(RequestMonitor requestMonitor) {
// Create the first timer and trigger.
fTimerService.startTimer();
fAlarmService.createAlarm(5);
fAlarmService.createTrigger(5);
requestMonitor.done();
}}
};

View file

@ -10,21 +10,18 @@
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
import org.eclipse.dd.dsf.datamodel.AbstractDMEvent;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMService;
import org.eclipse.dd.dsf.service.AbstractDsfService;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
@ -32,121 +29,73 @@ import org.osgi.framework.BundleContext;
/**
* Timer service tracks a set of timers, which are created per user request.
* The timers and their data are provided by the service using the DSF data
* model interfaces.
* <p>
* When each timer is created, an event is issued that the service contents are
* changed, and clients should re-query the list of timers. The timers
* increment their value at rate of one per second (but they are not synchronous),
* and an event is issued for every tick.
* The timers are represented using a Data Model context object, which
* implements {@link IDMContext}. Each timers value, which can be retrieved
* by calling {@link #getTimerValue(TimerDMContext)}, is incremented every
* second. When a timer value is incremented the TimerService issues a
* {@link TimerTickDMEvent}.
*/
public class TimerService extends AbstractDsfService
implements IDMService
{
/**
* Event indicating that the list of timers is changed and the clients
* which display timers should re-query this list.
*/
public class TimersChangedEvent extends AbstractDMEvent<IDMContext> {
TimersChangedEvent() { super(fTimersContext); }
}
/** Event indicating that the list of timers is changed. */
@Immutable
public static class TimersChangedEvent {}
/**
* Timer context represents a timer in this service. Clients can use this
* context to retrieve timer data. This class implements the <code>Comaparable</code>
* interfaces so that the objects can be stored in a TreeMap, which keeps them sorted.
*/
public static class TimerDMC extends AbstractDMContext
implements Comparable<TimerDMC>
{
/**
* Timer number, which is also index to timers map.
*/
final int fTimer;
/** Data Model context representing a timer. */
@Immutable
public static class TimerDMContext extends AbstractDMContext {
final int fNumber;
public TimerDMC(TimerService service, int timer) {
super(service, new IDMContext[] { service.fTimersContext });
fTimer = timer;
public TimerDMContext(String sessionId, int timer) {
super(sessionId, new IDMContext[0]);
fNumber = timer;
}
/**
* Timer context objects are created as needed and not cached, so the
* equals method implementation is critical.
*/
/** Returns the sequential creation number of this timer. */
public int getTimerNumber() {
return fNumber;
}
// Timer context objects are created as needed and not cached, so the
// equals method implementation is critical.
@Override
public boolean equals(Object other) {
return baseEquals(other) && ((TimerDMC)other).fTimer == fTimer;
return baseEquals(other) &&
((TimerDMContext)other).fNumber == fNumber;
}
@Override
public int hashCode() { return baseHashCode() + fTimer; }
public int hashCode() { return baseHashCode() + fNumber; }
@Override
public String toString() {
return baseToString() + ".timer[" + fTimer + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
public int compareTo(TimerDMC other) {
TimerDMC otherTimer = other;
return (fTimer < otherTimer.fTimer ? -1 : (fTimer == otherTimer.fTimer ? 0 : 1));
return baseToString() + ".timer[" + fNumber + "]";
}
}
/**
* Data about the timer in the service. This object references internal
* service data, so it has to guard agains this data being obsolete.
*/
public class TimerData implements IDMData {
TimerDMC fTimerDMC;
TimerData(TimerDMC timer) { fTimerDMC = timer; }
public boolean isValid() { return fTimers.containsKey(fTimerDMC); }
public int getTimerNumber() { return fTimerDMC.fTimer; }
public int getTimerValue() {
if (!isValid()) return -1;
return fTimers.get(fTimerDMC);
}
@Override public String toString() { return "Timer " + fTimerDMC.fTimer + " = " + getTimerValue(); } //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Event indicating that a timer's value has incremented. The context in
* the event points to the timer that has changed.
*/
public class TimerTickEvent extends AbstractDMEvent<TimerDMC> {
public TimerTickEvent(TimerDMC context) {
public class TimerTickDMEvent extends AbstractDMEvent<TimerDMContext> {
public TimerTickDMEvent(TimerDMContext context) {
super(context);
}
}
/** Parnet context for all timers */
private final IDMContext fTimersContext;
/** Counter for generating timer numbers */
private int fTimerCounter = 1;
private int fTimerNumberCounter = 1;
/** Map holding the timers */
private Map<TimerDMC, Integer> fTimers = new TreeMap<TimerDMC, Integer>();
// Use a linked hash in order to be able to return an ordered list of timers.
private Map<TimerDMContext, Integer> fTimers =
new LinkedHashMap<TimerDMContext, Integer>();
private Map<TimerDMContext, Future<?>> fTimerFutures =
new HashMap<TimerDMContext, Future<?>>();
private Map<TimerDMC, Future<?>> fTimerFutures = new TreeMap<TimerDMC, Future<?>>();
/** Constructor requires only the session for this service */
TimerService(DsfSession session) {
super(session);
fTimersContext = new AbstractDMContext(this, new IDMContext[0]) {
private final Object fHashObject = new Object();
@Override
public boolean equals(Object obj) { return (this == obj); };
@Override
public int hashCode() { return fHashObject.hashCode(); }
@Override
public String toString() { return "#timers"; } //$NON-NLS-1$
};
}
@Override
@ -160,97 +109,72 @@ public class TimerService extends AbstractDsfService
new RequestMonitor(getExecutor(), requestMonitor) {
@Override
public void handleOK() {
// After super-class is finished initializing
// perform TimerService initialization.
doInitialize(requestMonitor);
}});
}
private void doInitialize(RequestMonitor requestMonitor) {
// Register service
register( new String[]{ TimerService.class.getName() },
new Hashtable<String,String>() );
requestMonitor.done();
}
@Override
public void shutdown(RequestMonitor requestMonitor) {
/*
* Go through all the timer futures and cancel them, so that they
* don't fire any more events.
*/
// Cancel timer futures to avoid firing more events.
for (Future<?> future : fTimerFutures.values()) {
future.cancel(false);
}
unregister();
super.shutdown(requestMonitor);
}
/**
* Performs the relevant initialization for this service: registering and
* scheduling the timer.
* @param requestMonitor
*/
private void doInitialize(RequestMonitor requestMonitor) {
register(new String[]{TimerService.class.getName()}, new Hashtable<String,String>());
requestMonitor.done();
/** Retrieves the list of timer contexts. */
public TimerDMContext[] getTimers() {
return fTimers.keySet().toArray(new TimerDMContext[fTimers.size()]);
}
public boolean isValid() { return true; }
@SuppressWarnings("unchecked")
public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
if (dmc instanceof TimerDMC) {
getTimerData((TimerDMC)dmc, (DataRequestMonitor<TimerData>)rm);
return;
} else if (dmc == fTimersContext) {
((DataRequestMonitor<TimerService>)rm).setData(this);
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
}
rm.done();
/** Retrieves the timer value for the given context. */
public int getTimerValue(TimerDMContext context) {
Integer value = fTimers.get(context);
if (value != null) {
return value;
}
return -1;
}
/**
* Retrieves the list of timer contexts.
*
* <br>Note: this method doesn't need to be asynchronous, because all the
* data is stored locally. But using an asynchronous method makes this a
* more applicable example.
*
* @param rm Return data token.
*/
public void getTimers(DataRequestMonitor<TimerDMC[]> rm) {
rm.setData( fTimers.keySet().toArray(new TimerDMC[fTimers.size()]) );
rm.done();
}
/**
* Retrieves the data object for given timer context.
*
* <br>Note: likewise this method doesn't need to be asynchronous.
*/
public void getTimerData(TimerDMC context, DataRequestMonitor<TimerData> rm) {
rm.setData(new TimerData(context));
rm.done();
}
/**
* Creates a new timer and returns its context.
*/
public TimerDMC startTimer() {
final TimerDMC newTimer = new TimerDMC(this, fTimerCounter++);
/** Creates a new timer and returns its context. */
public TimerDMContext startTimer() {
// Create a new timer context and add it to the internal list.
final TimerDMContext newTimer =
new TimerDMContext(getSession().getId(), fTimerNumberCounter++);
fTimers.put(newTimer, 0);
// Create a new runnable that will execute every second and increment
// the timer value. The returned future is the handle that allows
// for canceling the scheduling of the runnable.
Future<?> timerFuture = getExecutor().scheduleAtFixedRate(
new Runnable() {
public void run() {
fTimers.put(newTimer, fTimers.get(newTimer) + 1);
getSession().dispatchEvent(new TimerTickEvent(newTimer), getProperties());
getSession().dispatchEvent(new TimerTickDMEvent(newTimer), getProperties());
}
@Override
public String toString() { return "Scheduled timer runnable for timer " + newTimer; } //$NON-NLS-1$
},
1, 1, TimeUnit.SECONDS);
fTimerFutures.put(newTimer, timerFuture);
fTimerFutures.put(newTimer, timerFuture);
// Issue an event to allow clients to update the list of timers.
getSession().dispatchEvent(new TimersChangedEvent(), getProperties());
return newTimer;
}
/**
* Removes given timer from list of timers.
*/
public void killTimer(TimerDMC timerContext) {
/** Removes given timer from list of timers. */
public void killTimer(TimerDMContext timerContext) {
if (fTimers.containsKey(timerContext)) {
fTimers.remove(timerContext);
fTimerFutures.remove(timerContext).cancel(false);

View file

@ -0,0 +1,58 @@
/*******************************************************************************
* 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.dd.examples.dsf.timers;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.RootDMVMNode;
import org.eclipse.dd.examples.dsf.timers.TimersVMProvider.TimersViewLayoutChanged;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
/**
*
*/
@SuppressWarnings("restriction")
public class TimersRootVMNode extends RootDMVMNode {
public TimersRootVMNode(AbstractVMProvider provider) {
super(provider);
}
@Override
public boolean isDeltaEvent(Object rootObject, Object e) {
if (e instanceof TimersViewLayoutChanged) {
return true;
}
return super.isDeltaEvent(rootObject, e);
}
@Override
public int getDeltaFlags(Object e) {
if (e instanceof TimersViewLayoutChanged) {
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
@Override
public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<VMDelta> rm) {
rm.setData(new VMDelta(rootObject, 0, IModelDelta.NO_CHANGE));
int flags = IModelDelta.NO_CHANGE;
if (event instanceof TimersViewLayoutChanged) {
flags |= IModelDelta.CONTENT;
}
rm.setData( new VMDelta(rootObject, 0, flags) );
rm.done();
}
}

View file

@ -14,49 +14,28 @@ import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
* This is the adapter that implements the flexible hierarchy viewer interfaces
* for providing content, labels, and event proxy-ing for the viewer. This
* for providing content, labels, and event processing for the viewer. This
* adapter is registered with the DSF Session object, and is returned by the
* IDMContext.getAdapter() and IVMContext.getAdapter() methods,
* which both call {@link DsfSession#getModelAdapter(Class)}.
* <p>
* The adapter implementation for this excercise is hard-coded to provide
* contents for only one view. In turn the view contens are determined using
* the configurable ViewModelProvider. For demonstration purposes, this model
* adapter has two different layout configurations that can be used. These
* layout configurations can be set by calling the {@link #setViewLayout} method.
* <p>
* This class is primarily accessed by the flexible hierarchy viewer from a
* non-executor thread. So the class is thread-safe, except for a view methods
* which must be called on the executor thread.
*
* @see AbstractDMVMProvider
*/
@SuppressWarnings("restriction")
@ThreadSafe
public class TimersModelAdapter extends AbstractDMVMAdapter
public class TimersVMAdapter extends AbstractDMVMAdapter
{
TimersVMProvider fViewModelProvider;
@Override
protected IVMProvider createViewModelProvider(IPresentationContext context) {
/*
* In this example there is only one viewer, so there is only one
* VMProvider.
*/
return fViewModelProvider;
if ( TimersView.ID_VIEW_TIMERS.equals(context.getId()) ) {
return new TimersVMProvider(this, context, getSession());
}
return null;
}
public TimersModelAdapter(DsfSession session, IPresentationContext presentationContext) {
public TimersVMAdapter(DsfSession session, IPresentationContext presentationContext) {
super(session);
fViewModelProvider = new TimersVMProvider(this, presentationContext, getSession());
}
TimersVMProvider getTimersVMProvider() {
return fViewModelProvider;
}
}

View file

@ -10,38 +10,76 @@
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import java.text.MessageFormat;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerData;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext;
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.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
* View model node that defines how timer DMContexts are displayed in the view. Timers
* change with every tick of the timer, so the label has to be repained
* upon timer tick events.
* @see TimerDMC
* @see TimerDMContext
*/
@SuppressWarnings("restriction")
class TimersVMNode extends AbstractDMVMNode
implements IElementLabelProvider
implements IElementLabelProvider, IElementPropertiesProvider
{
private static final String PROP_TIMER_NUMBER = "alarmNumber";
private static final String PROP_TIMER_VALUE = "alarmTriggerValue";
// Create and configure the label provider.
private static final PropertyBasedLabelProvider fgLabelProvider;
static {
fgLabelProvider = new PropertyBasedLabelProvider();
LabelColumnInfo idCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("Timer #{0}"),
new String[] { PROP_TIMER_NUMBER }),
new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().
getDescriptor(DsfExamplesPlugin.IMG_ALARM))
});
fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
LabelColumnInfo valueCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("{0}"),
new String[] { PROP_TIMER_VALUE })
});
fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE,
valueCol);
}
public TimersVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, TimerDMC.class);
super(provider, session, TimerDMContext.class);
}
public void update(ILabelUpdate[] updates) {
fgLabelProvider.update(updates);
}
@Override
@ -50,93 +88,60 @@ class TimersVMNode extends AbstractDMVMNode
// Retrieve the timer DMContexts, create the corresponding VMCs array, and
// set them as result.
getServicesTracker().getService(TimerService.class).getTimers(
new DataRequestMonitor<TimerDMC[]>(getSession().getExecutor(), null) {
@Override
public void handleCompleted() {
if (!getStatus().isOK()) {
update.setStatus(getStatus());
} else {
fillUpdateWithVMCs(update, getData());
}
update.done();
}});
TimerDMContext[] timers =
getServicesTracker().getService(TimerService.class).getTimers();
fillUpdateWithVMCs(update, timers);
update.done();
}
public void update(final ILabelUpdate[] updates) {
public void update(final IPropertiesUpdate[] updates) {
// Switch to the session thread before processing the updates.
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
updateLabelInSessionThread(updates);
for (IPropertiesUpdate update : updates) {
updatePropertiesInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (ILabelUpdate update : updates) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) {
final TimerDMC dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMC.class);
if (!checkDmc(dmc, update) || !checkService(TimerService.class, null, update)) continue;
getDMVMProvider().getModelData(
this, update,
getServicesTracker().getService(TimerService.class, null),
dmc,
new DataRequestMonitor<TimerData>(getSession().getExecutor(), null) {
@Override
protected void handleCompleted() {
/*
* Check that the request was evaluated and data is still
* valid. The request could fail if the state of the
* service changed during the request, but the view model
* has not been updated yet.
*/
if (!getStatus().isOK() || !getData().isValid()) {
assert getStatus().isOK() ||
getStatus().getCode() != IDsfService.INTERNAL_ERROR ||
getStatus().getCode() != IDsfService.NOT_SUPPORTED;
handleFailedUpdate(update);
return;
}
/*
* If columns are configured, call the protected methods to
* fill in column values.
*/
String[] localColumns = update.getPresentationContext().getColumns();
if (localColumns == null) localColumns = new String[] { null };
for (int i = 0; i < localColumns.length; i++) {
fillColumnLabel(dmc, getData(), localColumns[i], i, update);
}
update.done();
}
},
getExecutor());
@ConfinedToDsfExecutor("getSession#getExecutor")
private void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
// Find the timer context in the element being updated
final TimerDMContext dmc = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
// If either update or service are not valid, fail the update and exit.
if (!checkDmc(dmc, update) ||
!checkService(TimerService.class, null, update))
{
return;
}
TimerService timerService =
getServicesTracker().getService(TimerService.class, null);
int value = timerService.getTimerValue(dmc);
if (value == -1) {
handleFailedUpdate(update);
return;
}
update.setProperty(PROP_TIMER_NUMBER, dmc.getTimerNumber());
update.setProperty(PROP_TIMER_VALUE, value);
update.done();
}
protected void fillColumnLabel(TimerDMC dmContext, TimerData dmData, String columnId, int idx,
ILabelUpdate update)
{
if (TimersViewColumnPresentation.COL_ID.equals(columnId)) {
update.setLabel( Integer.toString(dmData.getTimerNumber()), idx );
update.setImageDescriptor(
DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(DsfExamplesPlugin.IMG_TIMER), idx);
} else if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) {
update.setLabel( Integer.toString(dmData.getTimerValue()), idx);
}
}
public int getDeltaFlags(Object e) {
// This node generates delta if the timers have changed, or if the
// label has changed.
if (e instanceof TimerService.TimerTickEvent) {
if (e instanceof TimerService.TimerTickDMEvent) {
return IModelDelta.STATE;
} else if (e instanceof TimerService.TimersChangedEvent) {
return IModelDelta.CONTENT;
@ -145,10 +150,9 @@ class TimersVMNode extends AbstractDMVMNode
}
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
if (e instanceof TimerService.TimerTickEvent) {
// Add delta indicating that the VMC for the given timer context
// has changed.
parentDelta.addNode( createVMContext(((TimerService.TimerTickEvent)e).getDMContext()), IModelDelta.STATE );
if (e instanceof TimerService.TimerTickDMEvent) {
// Add delta indicating that the given timer has changed.
parentDelta.addNode( createVMContext(((TimerService.TimerTickDMEvent)e).getDMContext()), IModelDelta.STATE );
} else if (e instanceof TimerService.TimersChangedEvent) {
// The list of timers has changed, which means that the parent
// node needs to refresh its contents, which in turn will re-fetch the
@ -157,4 +161,14 @@ class TimersVMNode extends AbstractDMVMNode
}
requestMonitor.done();
}
public String getPropertyDescription(String property) {
return null;
}
public String getPropertyName(String property) {
return null;
}
}

View file

@ -10,60 +10,42 @@
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import org.eclipse.core.runtime.IAdaptable;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.RootVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMModelProxyStrategy;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggersChangedEvent;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimersChangedEvent;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
/**
*
* The View Model provider for the Timers view. This provider allows for
* switching between two different view layouts:
* <ol>
* <li>Timers -> Triggers -> Alarms</li>
* <li>Triggers -> Timers -> Alarms</li>
* </ol>
* A special event is sent when the layout is changed in order to generate
* a proper delta to refresh the view.
*/
@SuppressWarnings("restriction")
public class TimersVMProvider extends AbstractDMVMProvider {
/**
* The object to be set to the viewer that shows contents supplied by this provider.
* @see org.eclipse.jface.viewers.TreeViewer#setInput(Object)
*/
private final IAdaptable fViewerInputObject =
new IAdaptable() {
/**
* The input object provides the viewer access to the viewer model adapter.
*/
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if ( adapter.isInstance(getVMAdapter()) ) {
return getVMAdapter();
}
return null;
}
@Override
public String toString() {
return "Timers View Root"; //$NON-NLS-1$
}
};
private DefaultVMModelProxyStrategy fModelProxyStrategy;
/** Event indicating that the timers view layout has changed */
public static class TimersViewLayoutChanged {}
/** Enumeration of possible layouts for the timers view model */
public enum ViewLayout { ALARMS_AT_TOP, TIMERS_AT_TOP }
public enum ViewLayout { TRIGGERS_AT_TOP, TIMERS_AT_TOP }
public TimersVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
super(adapter, presentationContext, session);
setViewLayout(ViewLayout.ALARMS_AT_TOP);
}
public Object getViewerInputObject() {
return fViewerInputObject;
// Set the initial view layout.
setViewLayout(ViewLayout.TIMERS_AT_TOP);
}
/**
@ -71,33 +53,30 @@ public class TimersVMProvider extends AbstractDMVMProvider {
* @param layout New layout to use.
*/
public void setViewLayout(ViewLayout layout) {
if (layout == ViewLayout.ALARMS_AT_TOP) {
IRootVMNode root = new RootVMNode(this);
IVMNode alarmsNode = new AlarmsVMNode(this, getSession());
IVMNode timersNode0 = new TimersVMNode(this, getSession());
addChildNodes(root, new IVMNode[] { alarmsNode, timersNode0 });
clearNodes();
if (layout == ViewLayout.TRIGGERS_AT_TOP) {
IRootVMNode root = new TimersRootVMNode(this);
IVMNode alarmsNode = new TriggersVMNode(this, getSession());
addChildNodes(root, new IVMNode[] { alarmsNode });
IVMNode timersNode = new TimersVMNode(this, getSession());
addChildNodes(alarmsNode, new IVMNode[] { timersNode });
IVMNode alarmStatusNode = new AlarmStatusVMNode(this, getSession());
IVMNode alarmStatusNode = new AlarmsVMNode(this, getSession());
addChildNodes(timersNode, new IVMNode[] { alarmStatusNode });
setRootNode(root);
} else if (layout == ViewLayout.TIMERS_AT_TOP) {
IRootVMNode root = new RootVMNode(this);
IRootVMNode root = new TimersRootVMNode(this);
IVMNode timersNode = new TimersVMNode(this, getSession());
addChildNodes(root, new IVMNode[] { timersNode });
IVMNode alarmsNode = new AlarmsVMNode(this, getSession());
IVMNode alarmsNode = new TriggersVMNode(this, getSession());
addChildNodes(timersNode, new IVMNode[] { alarmsNode });
IVMNode alarmStatusNode = new AlarmStatusVMNode(this, getSession());
IVMNode alarmStatusNode = new AlarmsVMNode(this, getSession());
addChildNodes(alarmsNode, new IVMNode[] { alarmStatusNode });
setRootNode(root);
}
/* TODO: replace with an event
fModelProxyStrategy.fireModelChanged(
new ModelDelta(getRootElement(), IModelDelta.CONTENT));
*/
handleEvent(new TimersViewLayoutChanged());
}
@Override
public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
return new TimersViewColumnPresentation();
@ -107,5 +86,36 @@ public class TimersVMProvider extends AbstractDMVMProvider {
public String getColumnPresentationId(IPresentationContext context, Object element) {
return TimersViewColumnPresentation.ID;
}
// Add a handler for the triggers and timers changed events. The
// AbstractDMVMProvider superclass automatically registers this provider
// for all IDMEvent events, however these two events do not implement
// IDMEvent
@DsfServiceEventHandler
public void eventDispatched(final TriggersChangedEvent event) {
if (isDisposed()) return;
try {
getExecutor().execute(new Runnable() {
public void run() {
if (isDisposed()) return;
handleEvent(event);
}
});
} catch (RejectedExecutionException e) {}
}
@DsfServiceEventHandler
public void eventDispatched(final TimersChangedEvent event) {
if (isDisposed()) return;
try {
getExecutor().execute(new Runnable() {
public void run() {
if (isDisposed()) return;
handleEvent(event);
}
});
} catch (RejectedExecutionException e) {}
}
}

View file

@ -12,19 +12,20 @@ package org.eclipse.dd.examples.dsf.timers;
import java.util.concurrent.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.service.DsfServicesTracker;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMC;
import org.eclipse.dd.examples.dsf.timers.TimerService.TimerDMContext;
import org.eclipse.dd.examples.dsf.timers.TimersVMProvider.ViewLayout;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.jface.action.Action;
@ -33,6 +34,7 @@ import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
@ -42,17 +44,23 @@ import org.eclipse.ui.part.ViewPart;
/**
* Example view which displays data from timers and alarms DSF services. This
* starts a new DSF session and configures the services for it. Then it
* configures a data model provider to process the service data and display it
* in a flexible-hierarchy asynchronous viewer.
* Example view which displays data from timers and alarms services. It starts
* a new DSF session and configures the services for it. Then it configures
* a data model provider to process the service data and display it in a
* flexible-hierarchy asynchronous viewer.
*/
@SuppressWarnings("restriction")
public class TimersView extends ViewPart {
/** Timers view ID */
public static final String ID_VIEW_TIMERS = "org.eclipse.dd.examples.dsf.TimersView";
/** Asynchronous tree viewer from the platform debug.ui plugin. */
private TreeModelViewer fViewer;
/** Presentation context of the timers viewer */
private PresentationContext fPresentationContext;
/** DSF executor to use for a new session with timers and alarms services */
private DsfExecutor fExecutor;
@ -63,7 +71,7 @@ public class TimersView extends ViewPart {
private DsfServicesTracker fServices;
/** Adapter used to provide view model for flexible-hierarchy viewer */
private TimersModelAdapter fTimersModelAdapter;
private TimersVMAdapter fTimersVMAdapter;
/** Action which toggles the layout in the viewer */
private Action fToggleLayoutAction;
@ -71,45 +79,41 @@ public class TimersView extends ViewPart {
/** Action that adds a new timer */
private Action fAddTimerAction;
/** Action that adds a new alarm */
private Action fAddAlarmAction;
/** Action that adds a new trigger */
private Action fAddTriggerAction;
/** Action that removes the selected alarm or timer */
/** Action that removes the selected trigger or timer */
private Action fRemoveAction;
public TimersView() {}
/**
* This is a callback that will allow us to create the viewer and
* This is a call-back that will allow us to create the viewer and
* initialize it. For this view, it creates the DSF session, along
* with its services. Then it creates the viewer model adapter and
* registers it with the session.
*/
@Override
public void createPartControl(Composite parent) {
/*
* Create the Flexible Hierarchy viewer. Also create a presentation
* context which will be given to the content/label provider adapters
* to distinguish this view from other flex-hierarchy views.
*/
final IPresentationContext presentationContext = new PresentationContext("org.eclipse.dd.examples.dsf.timers"); //$NON-NLS-1$
fViewer = new TreeModelViewer(parent, SWT.VIRTUAL | SWT.FULL_SELECTION, presentationContext);
// Create the Flexible Hierarchy viewer. Also create a presentation
// context which will be given to the content/label provider adapters
// to distinguish this view from other flexible-hierarchy views.
fPresentationContext = new PresentationContext(ID_VIEW_TIMERS);
fViewer = new TreeModelViewer(
parent, SWT.VIRTUAL | SWT.FULL_SELECTION, fPresentationContext);
/*
* Create the executor, which will be used exclusively with this view,
* as well as a session and a services tracker for managing references
* to services.
*/
// Create the executor, which will be used exclusively with this view,
// as well as a session and a services tracker for managing references
// to services.
fExecutor = new DefaultDsfExecutor();
fSession = DsfSession.startSession(fExecutor, "org.eclipse.dd.examples.dsf.timers"); //$NON-NLS-1$
fServices = new DsfServicesTracker(DsfExamplesPlugin.getBundleContext(), fSession.getId());
fSession = DsfSession.startSession(fExecutor, "Timers(DSF Example)");
fServices = new DsfServicesTracker(
DsfExamplesPlugin.getBundleContext(), fSession.getId());
/*
* Start the services using a sequence. The sequence runs in the
* dispatch thread, so we have to block this thread using Future.get()
* until it completes. The Future.get() will throw an exception if
* the sequence fails.
*/
// Start the services using a sequence. The sequence runs in the
// session executor thread, therefore the thread calling this method
// has to block using Future.get() until the sequence it completes.
// The Future.get() will throw an exception if the sequence fails.
ServicesStartupSequence startupSeq = new ServicesStartupSequence(fSession);
fSession.getExecutor().execute(startupSeq);
try {
@ -118,20 +122,38 @@ public class TimersView extends ViewPart {
} catch (ExecutionException e) { assert false;
}
/*
* Create the flexible hierarchy content/label adapter. Then register
* it with the session.
*/
fTimersModelAdapter = new TimersModelAdapter(fSession, presentationContext);
fSession.registerModelAdapter(IElementContentProvider.class, fTimersModelAdapter);
fSession.registerModelAdapter(IModelProxyFactory.class, fTimersModelAdapter);
fSession.registerModelAdapter(IColumnPresentationFactory.class, fTimersModelAdapter);
// Create the flexible hierarchy content/label adapter. Then register
// it with the session.
fTimersVMAdapter = new TimersVMAdapter(fSession, fPresentationContext);
fSession.registerModelAdapter(
IElementContentProvider.class, fTimersVMAdapter);
fSession.registerModelAdapter(
IModelProxyFactory.class, fTimersVMAdapter);
fSession.registerModelAdapter(
IColumnPresentationFactory.class, fTimersVMAdapter);
/*
* Set the root element for the timers tree viewer. The root element
* comes from the content provider.
*/
fViewer.setInput(fTimersModelAdapter.getTimersVMProvider().getViewerInputObject());
// Create the input object for the view. This object needs to return
// the VM adapter through the IAdaptable interface when queried for the
// flexible hierarchy adapters.
final IAdaptable viewerInputObject =
new IAdaptable() {
/**
* The input object provides the viewer access to the viewer model adapter.
*/
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if ( adapter.isInstance(fTimersVMAdapter) ) {
return fTimersVMAdapter;
}
return null;
}
@Override
public String toString() {
return "Timers View Root"; //$NON-NLS-1$
}
};
fViewer.setInput(viewerInputObject);
makeActions();
contributeToActionBars();
@ -140,21 +162,24 @@ public class TimersView extends ViewPart {
@Override
public void dispose() {
try {
/*
* First dispose the view model, which is the client of services.
* We are not in the dispatch thread
*/
// First dispose the view model, which is the client of services.
// This operation needs to be performed in the session executor
// thread. Block using Future.get() until this call completes.
fSession.getExecutor().submit(new Runnable() {
public void run() {
fSession.unregisterModelAdapter(IElementContentProvider.class);
fSession.unregisterModelAdapter(IModelProxyFactory.class);
fSession.unregisterModelAdapter(IColumnPresentationFactory.class);
fTimersModelAdapter.dispose();
fTimersModelAdapter = null;
}}).get();
// Then invoke the shutdown sequence for the services.
ServicesShutdownSequence shutdownSeq = new ServicesShutdownSequence(fSession);
// Dispose the VM adapter.
fTimersVMAdapter.dispose();
fTimersVMAdapter = null;
// Next invoke the shutdown sequence for the services. Sequence
// class also implements Future.get()...
ServicesShutdownSequence shutdownSeq =
new ServicesShutdownSequence(fSession);
fSession.getExecutor().execute(shutdownSeq);
try {
shutdownSeq.get();
@ -162,7 +187,7 @@ public class TimersView extends ViewPart {
} catch (ExecutionException e) { assert false;
}
// Finally end the session and the executor:
// Finally end the session and the executor.
fSession.getExecutor().submit(new Runnable() {
public void run() {
DsfSession.endSession(fSession);
@ -173,7 +198,6 @@ public class TimersView extends ViewPart {
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
//fViewer.dispose();
super.dispose();
}
@ -185,7 +209,7 @@ public class TimersView extends ViewPart {
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(fToggleLayoutAction);
manager.add(fAddTimerAction);
manager.add(fAddAlarmAction);
manager.add(fAddTriggerAction);
manager.add(fRemoveAction);
manager.add(new Separator());
}
@ -195,97 +219,105 @@ public class TimersView extends ViewPart {
@Override
public void run() {
// Get the toggle state of the action while on UI thread.
final ViewLayout layout = isChecked() ? ViewLayout.ALARMS_AT_TOP : ViewLayout.TIMERS_AT_TOP;
final ViewLayout layout = isChecked() ? ViewLayout.TRIGGERS_AT_TOP : ViewLayout.TIMERS_AT_TOP;
// Switch to executor thread to perform the change in layout.
fExecutor.submit(new Runnable() { public void run() {
fTimersModelAdapter.getTimersVMProvider().setViewLayout(layout);
}});
IVMProvider provider = fTimersVMAdapter.getVMProvider(fPresentationContext);
((TimersVMProvider)provider).setViewLayout(layout);
}
};
fToggleLayoutAction.setToolTipText("Toggle Layout"); //$NON-NLS-1$
fToggleLayoutAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_LAYOUT_TOGGLE));
fAddTimerAction = new Action("Add New Timer") { //$NON-NLS-1$
fAddTimerAction = new Action("Add New Timer") {
@Override
public void run() {
fExecutor.submit(new Runnable() { public void run() {
// Only need to create the new timer, the events will cause
// the view to refresh.
fServices.getService(TimerService.class).startTimer();
}});
fExecutor.execute(new Runnable() {
public void run() {
// Only need to create the new timer, the events will
// cause the view to refresh.
fServices.getService(TimerService.class).startTimer();
}
});
}
};
fAddTimerAction.setToolTipText("Add new timer"); //$NON-NLS-1$
fAddTimerAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_TIMER));
fAddTimerAction.setToolTipText("Add a new timer");
fAddTimerAction.setImageDescriptor(
getImage(DsfExamplesPlugin.IMG_TIMER));
fAddAlarmAction = new Action("Add New Alarm") { //$NON-NLS-1$
fAddTriggerAction = new Action("Add New Trigger") {
@Override
public void run() {
// Ask user for the new alarm value.
// Ask user for the new trigger value.
InputDialog inputDialog = new InputDialog(
fViewer.getControl().getShell(),
"New Alarm", //$NON-NLS-1$
"Please enter alarm time", //$NON-NLS-1$
"", //$NON-NLS-1$
getSite().getShell(),
"New Trigger",
"Please enter trigger value",
"",
new IInputValidator() {
public String isValid(String input) {
try {
int i= Integer.parseInt(input);
if (i <= 0)
return "Please enter a positive integer"; //$NON-NLS-1$
return "Please enter a positive integer";
} catch (NumberFormatException x) {
return "Please enter a positive integer"; //$NON-NLS-1$
return "Please enter a positive integer";
}
return null;
}
}
);
if (inputDialog.open() != Window.OK) return;
int tmpAlarmValue = -1;
int tmpTriggerValue = -1;
try {
tmpAlarmValue = Integer.parseInt(inputDialog.getValue());
tmpTriggerValue = Integer.parseInt(inputDialog.getValue());
} catch (NumberFormatException x) { assert false; }
final int alarmValue = tmpAlarmValue;
fExecutor.submit(new Runnable() { public void run() {
// Create the new alarm.
fServices.getService(AlarmService.class).createAlarm(alarmValue);
}});
final int triggerValue = tmpTriggerValue;
fExecutor.execute(new Runnable() {
public void run() {
// Create the new trigger
fServices.getService(AlarmService.class).
createTrigger(triggerValue);
}
});
}
};
fAddAlarmAction.setToolTipText("Add new alarm"); //$NON-NLS-1$
fAddAlarmAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_ALARM));
fAddTriggerAction.setToolTipText("Add a new trigger");
fAddTriggerAction.setImageDescriptor(
getImage(DsfExamplesPlugin.IMG_ALARM));
fRemoveAction = new Action("Remove") { //$NON-NLS-1$
fRemoveAction = new Action("Remove") {
@Override
public void run() {
final Object selectedElement = ((IStructuredSelection)fViewer.getSelection()).getFirstElement();
final Object selectedElement =
((IStructuredSelection)fViewer.getSelection()).getFirstElement();
if (!(selectedElement instanceof IDMVMContext)) return;
final IDMContext selectedDmc = ((IDMVMContext)selectedElement).getDMContext();
// Based on the DMC from the selection, call the appropriate service to
// remove the item.
if (selectedDmc instanceof TimerDMC) {
fExecutor.submit(new Runnable() { public void run() {
final IDMContext selectedCtx =
((IDMVMContext)selectedElement).getDMContext();
// Based on the context from the selection, call the
// appropriate service to remove the item.
if (selectedCtx instanceof TimerDMContext) {
fExecutor.execute(new Runnable() { public void run() {
fServices.getService(TimerService.class).killTimer(
((TimerDMC)selectedDmc));
((TimerDMContext)selectedCtx));
}});
} else if (selectedDmc instanceof AlarmService.AlarmDMC) {
fExecutor.submit(new Runnable() { public void run() {
fServices.getService(AlarmService.class).deleteAlarm(
(AlarmService.AlarmDMC)selectedDmc);
} else if (selectedCtx instanceof AlarmService.TriggerDMContext) {
fExecutor.execute(new Runnable() { public void run() {
fServices.getService(AlarmService.class).deleteTrigger(
(AlarmService.TriggerDMContext)selectedCtx);
}});
}
}
};
fRemoveAction.setToolTipText("Remove selected item"); //$NON-NLS-1$
fRemoveAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
DsfExamplesPlugin.IMG_REMOVE));
fRemoveAction.setToolTipText("Remove selected item");
fRemoveAction.setImageDescriptor( getImage(DsfExamplesPlugin.IMG_REMOVE) );
}
private ImageDescriptor getImage(String key) {
return DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(key);
}
/**
* Passing the focus request to the viewer's control.
*/

View file

@ -25,18 +25,14 @@ public class TimersViewColumnPresentation implements IColumnPresentation {
public static final String COL_ID = ID + ".COL_ID"; //$NON-NLS-1$
public static final String COL_VALUE = ID + ".COL_VALUE"; //$NON-NLS-1$
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#init(org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
public void init(IPresentationContext context) {}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#dispose()
public void dispose() {}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getAvailableColumns()
public String[] getAvailableColumns() {
return new String[] { COL_ID, COL_VALUE };
}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getHeader(java.lang.String)
public String getHeader(String id) {
if (COL_ID.equals(id)) {
return "ID"; //$NON-NLS-1$
@ -46,22 +42,18 @@ public class TimersViewColumnPresentation implements IColumnPresentation {
return null;
}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getId()
public String getId() {
return ID;
}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getImageDescriptor(java.lang.String)
public ImageDescriptor getImageDescriptor(String id) {
return null;
}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getInitialColumns()
public String[] getInitialColumns() {
return getAvailableColumns();
}
// @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#isOptional()
public boolean isOptional() {
return true;
}

View file

@ -11,6 +11,7 @@
package org.eclipse.dd.examples.dsf.timers;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
@ -23,8 +24,7 @@ import org.eclipse.dd.dsf.service.DsfServices;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.service.IDsfService;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmDMC;
import org.eclipse.dd.examples.dsf.timers.AlarmService.AlarmData;
import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.swt.widgets.Shell;
@ -32,58 +32,56 @@ import org.osgi.framework.InvalidSyntaxException;
import org.osgi.util.tracker.ServiceTracker;
/**
*
* Cell modifier used to edit the trigger value.
*/
@ThreadSafeAndProhibitedFromDsfExecutor("")
public class AlarmCellModifier implements ICellModifier {
@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
public class TriggerCellModifier implements ICellModifier {
private final DsfSession fSession;
/**
* Need to use the OSGi service tracker here (instead of DsfServiceTracker),
* because we're accessing it in non-dispatch thread. DsfServiceTracker is not
* thread-safe.
*/
// Need to use the OSGi service tracker (instead of DsfServiceTracker),
// because it's being accessed on multiple threads.
@ThreadSafe
private ServiceTracker fServiceTracker;
/**
* Constructor for the modifier requires a valid DSF session in order to
* Constructor for the modifier requires a valid session in order to
* initialize the service tracker.
* @param session DSF session this modifier will use.
*/
public AlarmCellModifier(DsfSession session) {
public TriggerCellModifier(DsfSession session) {
fSession = session;
}
public boolean canModify(Object element, String property) {
return TimersViewColumnPresentation.COL_VALUE.equals(property) && getAlarmDMC(element) != null;
return TimersViewColumnPresentation.COL_VALUE.equals(property) &&
getAlarmDMC(element) != null;
}
public Object getValue(Object element, String property) {
if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return ""; //$NON-NLS-1$
if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return "";
// Get the DMC and the session. If element is not an alarm DMC, or
// session is stale, then bail out.
AlarmDMC dmc = getAlarmDMC(element);
if (dmc == null) return ""; //$NON-NLS-1$
DsfSession session = DsfSession.getSession(dmc.getSessionId());
if (session == null) return ""; //$NON-NLS-1$
// Get the context and the session. If element is not an trigger
// context or if the session is stale then bail out.
TriggerDMContext triggerCtx = getAlarmDMC(element);
if (triggerCtx == null) return "";
DsfSession session = DsfSession.getSession(triggerCtx.getSessionId());
if (session == null) return "";
/*
* Create the query to request the value from service.
* Note: no need to guard against RejectedExecutionException, because
* DsfSession.getSession() above would only return an active session.
*/
GetValueQuery query = new GetValueQuery(dmc);
session.getExecutor().execute(query);
// Create the query to request the value from service.
GetValueQuery query = new GetValueQuery(triggerCtx);
try {
session.getExecutor().execute(query);
} catch (RejectedExecutionException e) {
return "";
}
try {
return query.get().toString();
} catch (InterruptedException e) {
assert false;
return ""; //$NON-NLS-1$
return "";
} catch (ExecutionException e) {
return ""; //$NON-NLS-1$
return "";
}
}
@ -91,7 +89,7 @@ public class AlarmCellModifier implements ICellModifier {
public void modify(Object element, String property, Object value) {
if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return;
AlarmDMC dmc = getAlarmDMC(element);
TriggerDMContext dmc = getAlarmDMC(element);
if (dmc == null) return;
DsfSession session = DsfSession.getSession(dmc.getSessionId());
if (session == null) return;
@ -105,31 +103,32 @@ public class AlarmCellModifier implements ICellModifier {
try {
intValue = new Integer(((String)value).trim());
} catch (NumberFormatException e) {
MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); //$NON-NLS-1$ //$NON-NLS-2$
MessageDialog.openError(shell, "Invalid Value",
"Please enter a positive integer");
return;
}
if (intValue.intValue() <= 0) {
MessageDialog.openError(shell, "Invalid Value", "Please enter a positive integer"); //$NON-NLS-1$ //$NON-NLS-2$
MessageDialog.openError(shell, "Invalid Value",
"Please enter a positive integer");
return;
}
}
/*
* Create the query to write the value to the service.
* Note: no need to guard against RejectedExecutionException, because
* DsfSession.getSession() above would only return an active session.
*/
// Create the query to write the value to the service.
SetValueQuery query = new SetValueQuery(dmc, intValue);
session.getExecutor().execute(query);
try {
session.getExecutor().execute(query);
} catch (RejectedExecutionException e) {
// View must be shutting down, no need to show error dialog.
}
try {
// Return value is irrelevant, any error would come through with an exception.
query.get().toString();
} catch (InterruptedException e) {
assert false;
} catch (ExecutionException e) {
// View must be shutting down, no need to show erro dialog.
// View must be shutting down, no need to show error dialog.
}
}
@ -151,15 +150,16 @@ public class AlarmCellModifier implements ICellModifier {
return null;
}
private AlarmDMC getAlarmDMC(Object element) {
private TriggerDMContext getAlarmDMC(Object element) {
if (element instanceof IAdaptable) {
return (AlarmDMC)((IAdaptable)element).getAdapter(AlarmDMC.class);
return (TriggerDMContext)((IAdaptable)element).getAdapter(TriggerDMContext.class);
}
return null;
}
@ThreadSafe
private synchronized AlarmService getService(AlarmDMC dmc) {
private synchronized AlarmService getService(TriggerDMContext dmc) {
// Create and initialize the service tracker if needed.
String serviceId = DsfServices.createServiceFilter( AlarmService.class, fSession.getId() );
if (fServiceTracker == null) {
try {
@ -172,26 +172,25 @@ public class AlarmCellModifier implements ICellModifier {
return null;
}
}
// Get the service.
return (AlarmService)fServiceTracker.getService();
}
private class GetValueQuery extends Query<Integer> {
final TriggerDMContext fDmc;
final AlarmDMC fDmc;
private GetValueQuery(AlarmDMC dmc) {
private GetValueQuery(TriggerDMContext dmc) {
super();
fDmc = dmc;
}
@Override
protected void execute(final DataRequestMonitor<Integer> rm) {
/*
* Guard against the session being disposed. If session is disposed
* it could mean that the executor is shut-down, which in turn
* could mean that we can't execute the "done" argument.
* In that case, cancel to notify waiting thread.
*/
// Guard against the session being disposed. If session is disposed
// it could mean that the executor is shut-down, which in turn
// could mean that we can't execute the "done" argument.
// In that case, cancel to notify waiting thread.
final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
if (session == null) {
cancel(false);
@ -201,34 +200,30 @@ public class AlarmCellModifier implements ICellModifier {
AlarmService service = getService(fDmc);
if (service == null) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"Service not available", null)); //$NON-NLS-1$
"Service not available", null));
rm.done();
return;
}
service.getAlarmData(fDmc, new DataRequestMonitor<AlarmData>(session.getExecutor(), rm) {
@Override
protected void handleCompleted() {
// We're in another dispatch, so we must guard against executor shutdown again.
if (DsfSession.isSessionActive(session.getId())) {
super.handleCompleted();
}
}
@Override
protected void handleOK() {
rm.setData(getData().getTriggeringValue());
rm.done();
}
});
int value = service.getTriggerValue(fDmc);
if (value == -1) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE,
"Invalid context", null));
rm.done();
return;
}
rm.setData(value);
rm.done();
}
}
private class SetValueQuery extends Query<Object> {
AlarmDMC fDmc;
TriggerDMContext fDmc;
int fValue;
SetValueQuery(AlarmDMC dmc, int value) {
SetValueQuery(TriggerDMContext dmc, int value) {
super();
fDmc = dmc;
fValue = value;
@ -247,13 +242,13 @@ public class AlarmCellModifier implements ICellModifier {
AlarmService service = getService(fDmc);
if (service == null) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfService.INVALID_STATE,
"Service not available", null)); //$NON-NLS-1$
"Service not available", null));
rm.done();
return;
}
// Finally set the value and return.
service.setAlarmValue(fDmc, fValue);
service.setTriggerValue(fDmc, fValue);
// Return value is irrelevant.
rm.setData(new Object());

View file

@ -0,0 +1,203 @@
/*******************************************************************************
* Copyright (c) 2006 Wind River Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.dd.examples.dsf.timers;
import java.text.MessageFormat;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.service.DsfSession;
import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.dd.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelAttribute;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelColumnInfo;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.dd.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.dd.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
import org.eclipse.dd.examples.dsf.timers.AlarmService.TriggerDMContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.widgets.Composite;
/**
* View model node that defines how alarm DMContexts are displayed in the view. Alarm
* nodes are fairly static, once they are created their label doesn't change.
* @see TriggerDMContext
*/
@SuppressWarnings("restriction")
class TriggersVMNode extends AbstractDMVMNode
implements IElementEditor, IElementPropertiesProvider, IElementLabelProvider
{
private static final String PROP_TRIGGER_NUMBER = "alarmNumber";
private static final String PROP_TRIGGER_VALUE = "alarmTriggerValue";
// Create and configure the label provider.
private static final PropertyBasedLabelProvider fgLabelProvider;
static {
fgLabelProvider = new PropertyBasedLabelProvider();
LabelColumnInfo idCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("Trigger #{0}"),
new String[] { PROP_TRIGGER_NUMBER }),
new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().
getDescriptor(DsfExamplesPlugin.IMG_ALARM))
});
fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
LabelColumnInfo valueCol = new LabelColumnInfo(
new LabelAttribute[] {
new LabelText(new MessageFormat("{0}"),
new String[] { PROP_TRIGGER_VALUE })
});
fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE,
valueCol);
}
private TriggerCellModifier fAlarmCellModifier;
public TriggersVMNode(AbstractDMVMProvider provider, DsfSession session) {
super(provider, session, TriggerDMContext.class);
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(AlarmService.class, null, update)) return;
TriggerDMContext[] triggers =
getServicesTracker().getService(AlarmService.class).getTriggers();
fillUpdateWithVMCs(update, triggers);
update.done();
}
public void update(ILabelUpdate[] updates) {
fgLabelProvider.update(updates);
}
public void update(final IPropertiesUpdate[] updates) {
// Switch to the session thread before processing the updates.
try {
getSession().getExecutor().execute(new DsfRunnable() {
public void run() {
for (IPropertiesUpdate update : updates) {
updatePropertiesInSessionThread(update);
}
}});
} catch (RejectedExecutionException e) {
for (IViewerUpdate update : updates) {
handleFailedUpdate(update);
}
}
}
@ConfinedToDsfExecutor("getSession#getExecutor")
private void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
// Find the trigger context in the element being updated
TriggerDMContext triggerCtx = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
// If either update or service are not valid, fail the update and exit.
if (!checkDmc(triggerCtx, update) ||
!checkService(AlarmService.class, null, update))
{
return;
}
// Calculate and set the update properties.
AlarmService alarmService =
getServicesTracker().getService(AlarmService.class, null);
int value = alarmService.getTriggerValue(triggerCtx);
if (value == -1) {
handleFailedUpdate(update);
return;
}
update.setProperty(PROP_TRIGGER_NUMBER, triggerCtx.getTriggerNumber());
update.setProperty(PROP_TRIGGER_VALUE, value);
update.done();
}
public CellEditor getCellEditor(IPresentationContext context, String columnId,
Object element, Composite parent)
{
// Create a cell editor to modify the trigger value.
if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) {
return new TextCellEditor(parent);
}
return null;
}
// Note: this method is synchronized because IElementEditor.getCellModifier can be called
// on any thread, even though in practice it should be only called on the UI thread.
public ICellModifier getCellModifier(IPresentationContext context,
Object element)
{
// Create the cell modifier if needed.
if (fAlarmCellModifier == null) {
fAlarmCellModifier = new TriggerCellModifier(getSession());
}
return fAlarmCellModifier;
}
public int getDeltaFlags(Object e) {
// Since the label for triggers doesn't change, this node will generate
// delta info only if the list of alarms is changed.
if (e instanceof AlarmService.TriggersChangedEvent) {
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE;
}
public void buildDelta(Object event, VMDelta parentDelta, int nodeOffset,
RequestMonitor requestMonitor)
{
if (event instanceof AlarmService.TriggersChangedEvent) {
// The list of alarms has changed, which means that the parent
// node needs to refresh its contents, which in turn will re-fetch the
// elements from this node.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
requestMonitor.done();
}
@Override
public void dispose() {
if (fAlarmCellModifier != null) {
fAlarmCellModifier.dispose();
}
super.dispose();
}
public String getPropertyDescription(String property) {
return null;
}
public String getPropertyName(String property) {
return null;
}
}

View file

@ -1,28 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>Eclipse Device Debug - Debugger Services Framework - Data Model</title>
</head>
<body>
Example demostrationg use of Debugger Services Framework (DSF) data
model interfaces.<br>
<h2>Package Specification</h2>
The example consists of two services, one that monitors a set of timers
(TimerService), and another that tracks a set of alarms
(AlarmService).&nbsp; The timers are incremented at a rate of one per
second, although for visual interest, timers are not synchronous as
each timer is incremented at a slightly different moment.&nbsp; There
is also a "Timers" view that displays the timers and alarms, and has
actions for adding and removing new timers and alarms.&nbsp; Most
interestingly, the view has a toggle action, which switches the layout
of the view from having timers at the root level, with alarms listed
below each timer, to having alarms at the root level with timers listed
below each alarm.<br>
<br>
<img alt="" title="Example diagram" src="doc-files%5Cpackage-1.png"
style="width: 1014px; height: 643px;"><br>
<br>
</body>
</html>