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