blob: 6625dbc19663a4828e5d446ea989746385c070a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.examples.dsf.timers;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelAttribute;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelColumnInfo;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelForeground;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesBasedLabelProvider;
import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
import org.eclipse.cdt.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.graphics.RGB;
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 PropertiesBasedLabelProvider fgLabelProvider;
static {
fgLabelProvider = new PropertiesBasedLabelProvider();
LabelColumnInfo idCol = new LabelColumnInfo(
new LabelAttribute[] { new LabelText("Trigger #{0}", new String[] { PROP_TRIGGER_NUMBER }),
new LabelForeground(new RGB(255, 0, 0)), new LabelImage(DsfExamplesPlugin.getDefault()
.getImageRegistry().getDescriptor(DsfExamplesPlugin.IMG_ALARM)) });
fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
LabelColumnInfo valueCol = new LabelColumnInfo(
new LabelAttribute[] { new LabelText("{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
public String toString() {
return "TriggersVMNode(" + getSession().getId() + ")";
}
@Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) {
AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
if (alarmService == null) {
handleFailedUpdate(update);
return;
}
TriggerDMContext[] triggers = alarmService.getTriggers();
fillUpdateWithVMCs(update, triggers);
update.done();
}
@Override
public void update(ILabelUpdate[] updates) {
fgLabelProvider.update(updates);
}
@Override
public void update(final IPropertiesUpdate[] updates) {
// Switch to the session thread before processing the updates.
try {
getSession().getExecutor().execute(new DsfRunnable() {
@Override
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);
AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
// If either update or service are not valid, fail the update and return.
if (triggerCtx == null || alarmService == null) {
handleFailedUpdate(update);
return;
}
// Calculate and set the update properties.
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();
}
@Override
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.
@Override
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
// Create the cell modifier if needed.
if (fAlarmCellModifier == null) {
fAlarmCellModifier = new TriggerCellModifier(getSession());
}
return fAlarmCellModifier;
}
@Override
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;
}
@Override
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();
}
}