Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Piech2009-01-08 21:08:05 +0000
committerPawel Piech2009-01-08 21:08:05 +0000
commit5b471873662a87a77cfd854c98fca9c9948aa878 (patch)
tree3da8dcf3820bf3c2d4ebd17e4e8f3043e9773676 /dsf/org.eclipse.cdt.examples.dsf/src
parent47093064424981f85335cfdaf25368c54cd840f8 (diff)
parentc1e6da229b8ffcea160498f034bfa6bc8ff6f230 (diff)
downloadorg.eclipse.cdt-5b471873662a87a77cfd854c98fca9c9948aa878.tar.gz
org.eclipse.cdt-5b471873662a87a77cfd854c98fca9c9948aa878.tar.xz
org.eclipse.cdt-5b471873662a87a77cfd854c98fca9c9948aa878.zip
Migrated DSF and DSF-GDB to the CDT project.
Diffstat (limited to 'dsf/org.eclipse.cdt.examples.dsf/src')
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java92
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java113
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java62
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java99
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java41
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java314
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java197
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html127
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java252
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java107
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java100
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java60
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java184
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java58
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java41
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java169
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java121
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java325
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java61
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java258
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java201
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.pngbin0 -> 14399 bytes
23 files changed, 3021 insertions, 0 deletions
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java
new file mode 100644
index 00000000000..8799f748c88
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfExamplesPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.examples.dsf"; //$NON-NLS-1$
+
+ public static final String IMG_LAYOUT_TOGGLE = "icons/layout.gif"; //$NON-NLS-1$
+ public static final String IMG_ALARM = "icons/alarm.gif"; //$NON-NLS-1$
+ public static final String IMG_ALARM_TRIGGERED = "icons/alarm_triggered.gif"; //$NON-NLS-1$
+ public static final String IMG_TIMER = "icons/timer.gif"; //$NON-NLS-1$
+ public static final String IMG_REMOVE = "icons/remove.gif"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfExamplesPlugin fgPlugin;
+
+ private static BundleContext fgBundleContext;
+
+ /**
+ * The constructor
+ */
+ public DsfExamplesPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ getImageRegistry().put(IMG_ALARM, imageDescriptorFromPlugin(PLUGIN_ID, IMG_ALARM));
+ getImageRegistry().put(IMG_ALARM_TRIGGERED, imageDescriptorFromPlugin(PLUGIN_ID, IMG_ALARM_TRIGGERED));
+ getImageRegistry().put(IMG_TIMER, imageDescriptorFromPlugin(PLUGIN_ID, IMG_TIMER));
+ getImageRegistry().put(IMG_REMOVE, imageDescriptorFromPlugin(PLUGIN_ID, IMG_REMOVE));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ fgPlugin = null;
+ fgBundleContext = null;
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfExamplesPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+ /**
+ * Returns an image descriptor for the image file at the given
+ * plug-in relative path
+ *
+ * @param path the path
+ * @return the image descriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java
new file mode 100644
index 00000000000..2e686f5c8d1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.actions.ActionDelegate;
+
+/**
+ * Action that opens the File Browser example dialog.
+ */
+public class FileBrowserAction extends ActionDelegate
+ implements IWorkbenchWindowActionDelegate
+{
+ private IWorkbenchWindow fWindow;
+
+ @Override
+ public void run(IAction action) {
+ if (fWindow != null) {
+ // Create the dialog and open it.
+ Dialog dialog = new FileBrowserDialog(fWindow.getShell());
+ dialog.open();
+ }
+ }
+
+ public void init(IWorkbenchWindow window) {
+ fWindow = window;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java
new file mode 100644
index 00000000000..807913c0216
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+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.dialogs.Dialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * File Browser example dialog. It hold a tree viewer that displays
+ * file system contents and a text box for entering a file path to be
+ * shown in the tree.
+ */
+@SuppressWarnings("restriction")
+public class FileBrowserDialog extends Dialog {
+
+ /**
+ * Tree viewer for showing the filesystem contents.
+ */
+ private TreeModelViewer fViewer;
+
+ /**
+ * The model adapter for the tree viewer.
+ */
+ private FileBrowserModelAdapter fModelAdapter;
+
+ /**
+ * Flag used to disable text-box changed events, when the text
+ * box is updated due to selection change in tree.
+ */
+ private boolean fDisableTextChangeNotifications = false;
+
+ public FileBrowserDialog(Shell parent) {
+ super(parent);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite area = (Composite) super.createDialogArea(parent);
+ IPresentationContext presentationContext = new PresentationContext("org.eclipse.cdt.examples.dsf.filebrowser"); //$NON-NLS-1$
+
+ fViewer = new TreeModelViewer(area, SWT.VIRTUAL, presentationContext);
+ fViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ fModelAdapter = new FileBrowserModelAdapter(presentationContext);
+ fViewer.setInput(fModelAdapter.getVMProvider().getViewerInputObject());
+
+ final Text text = new Text(area, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ /*
+ * Update the file name in the text control, to match the
+ * selection in the tree. Do this only if the user is not
+ * actively typing in the text field (test if text has focus).
+ */
+ if (!text.isFocusControl() &&
+ event.getSelection() instanceof IStructuredSelection &&
+ ((IStructuredSelection)event.getSelection()).getFirstElement() instanceof FileVMContext)
+ {
+ FileVMContext fileVmc = (FileVMContext)((IStructuredSelection)event.getSelection()).getFirstElement();
+
+ fDisableTextChangeNotifications = true;
+ text.setText(fileVmc.getFile().getAbsolutePath());
+ fDisableTextChangeNotifications = false;
+ }
+ }
+ });
+
+ text.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if (!fDisableTextChangeNotifications) {
+ fModelAdapter.getVMProvider().selectionTextChanged(text.getText());
+ }
+ }
+ });
+
+ return area;
+ }
+
+ @Override
+ public boolean close() {
+ if (super.close()) {
+ fModelAdapter.dispose();
+ fModelAdapter = null;
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java
new file mode 100644
index 00000000000..497b31f45c1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.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
+ * 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 exercise is hard-coded to provide
+ * contents for only one view. In turn the view contents 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 FileBrowserModelAdapter extends AbstractVMAdapter
+{
+ FileBrowserVMProvider fViewModelProvider;
+
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ /*
+ * In this example there is only one viewer, so there is only one
+ * VMProvider.
+ */
+ return fViewModelProvider;
+ }
+
+ public FileBrowserModelAdapter(IPresentationContext presentationContext) {
+ super();
+ fViewModelProvider = new FileBrowserVMProvider(this, presentationContext);
+ }
+
+ FileBrowserVMProvider getVMProvider() {
+ return fViewModelProvider;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java
new file mode 100644
index 00000000000..ef3d098bb9c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.RootVMNode;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class FileBrowserVMProvider extends AbstractVMProvider
+{
+ /**
+ * 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 "File Browser Viewer Input"; //$NON-NLS-1$
+ }
+ };
+
+ /**
+ * Constructor creates and configures the layout nodes to display file
+ * system contents.
+ * @param adapter The viewer model adapter that this provider is registered with.
+ * @param presentationContext The presentation context that this provider is
+ * generating contents for.
+ */
+ public FileBrowserVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
+ super(adapter, presentationContext);
+
+ IRootVMNode root = new RootVMNode(this);
+ IVMNode fileSystemRoots = new FilesystemRootsVMNode(this);
+ addChildNodes(root, new IVMNode[] { fileSystemRoots });
+ IVMNode files = new FileVMNode(this);
+ addChildNodes(fileSystemRoots, new IVMNode[] { files });
+ addChildNodes(files, new IVMNode[] { files });
+ setRootNode(root);
+ }
+
+ /**
+ * Returns the input object to be set to the viewer that shows contents
+ * supplied by this provider.
+ */
+ public Object getViewerInputObject() {
+ return fViewerInputObject;
+ }
+
+ /**
+ * Event handler for file selection text changes in the dialog.
+ * @param text New text entered in file selection text box.
+ */
+ void selectionTextChanged(final String text) {
+ if (isDisposed()) return;
+
+ // We're in the UI thread. Re-dispach to VM Adapter executor thread
+ // and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ handleEvent(text);
+ }});
+ } catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java
new file mode 100644
index 00000000000..93b8da64e9e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+
+class FileVMContext extends AbstractVMContext {
+ private File fFile;
+ FileVMContext(IVMNode layoutNode, File file) {
+ super(layoutNode);
+ fFile = file;
+ }
+
+ File getFile() { return fFile; }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FileVMContext && ((FileVMContext)obj).getFile().equals(fFile);
+ }
+
+ @Override
+ public int hashCode() {
+ return fFile.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return fFile.toString();
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java
new file mode 100644
index 00000000000..e137dad245f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+
+
+/**
+ * File view model node which returns file elements that are found in the directory
+ * specified by the parent element. The child nodes of this node are fixed to
+ * reference this element, and therefore this node will recursively populate
+ * the contents of the tree reflecting the underlying filesystem directories.
+ * <br>
+ * Note: this node does NOT sub-class the {@link org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode}
+ */
+@SuppressWarnings("restriction")
+class FileVMNode
+ implements IElementLabelProvider, IVMNode
+{
+ /**
+ * Reference to the viewer model provider. It's mainly used to access the
+ * viewer model adapter and its executor.
+ */
+ private final FileBrowserVMProvider fProvider;
+
+ public FileVMNode(FileBrowserVMProvider provider) {
+ fProvider = provider;
+ }
+
+ @Override
+ public String toString() {
+ return "FileVMNode";
+ }
+
+
+ public void dispose() {
+ // All resources garbage collected.
+ }
+
+ public void setChildNodes(IVMNode[] childNodes) {
+ throw new UnsupportedOperationException("This node does not support children."); //$NON-NLS-1$
+ }
+
+ /**
+ * List of child nodes containing only a reference to this.
+ */
+ private final IVMNode[] fChildNodes = { this };
+
+ public IVMNode[] getChildNodes() {
+ return fChildNodes;
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IHasChildrenUpdate update : updates) {
+ /*
+ * Do not retrieve directory contents just to mark the plus
+ * sign in the tree. If it's a directory, just assume that
+ * it has children.
+ */
+ FileVMContext vmc = (FileVMContext)update.getElement();
+ update.setHasChilren(vmc.getFile().isDirectory());
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenCountUpdate update : updates) {
+ update.setChildCount(getFiles(update).length);
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenUpdate update : updates) {
+ File[] files = getFiles(update);
+ int offset = update.getOffset() != -1 ? update.getOffset() : 0;
+ int length = update.getLength() != -1 ? update.getLength() : files.length;
+ for (int i = offset; (i < files.length) && (i < (offset + length)); i++) {
+ update.setChild(new FileVMContext(FileVMNode.this, files[i]), i);
+ }
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel(getLabel((FileVMContext)update.getElement()), 0);
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ private static final File[] EMPTY_FILE_LIST = new File[0];
+
+ /**
+ * Retrieves the list of files for this node. The list of files is based
+ * on the parent element in the tree, which must be of type FileVMC.
+ *
+ * @param update Update object containing the path (and the parent element)
+ * in the tree viewer.
+ * @return List of files contained in the directory specified in the
+ * update object. An empty list if the parent element is not a directory.
+ * @throws ClassCastException If the parent element contained in the update
+ * is NOT of type FileVMC.
+ */
+ private File[] getFiles(IViewerUpdate update) {
+ FileVMContext vmc = (FileVMContext)update.getElement();
+ File[] files = vmc.getFile().listFiles();
+ return files != null ? files : EMPTY_FILE_LIST;
+ }
+
+ /**
+ * Returs the text label to show in the tree for given element.
+ */
+ private String getLabel(FileVMContext vmc) {
+ return vmc.getFile().getName();
+ }
+
+ public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ }
+
+ public int getDeltaFlags(Object e) {
+ /*
+ * @see buildDelta()
+ */
+ int retVal = IModelDelta.NO_CHANGE;
+ if (e instanceof String) {
+ retVal |= IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+
+ return retVal;
+ }
+
+ public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ /*
+ * The FileLayoutNode is recursive, with itself as the only child. In this
+ * method the delta is calculated for a full path VMContext elements, and the
+ * implementation of this method is not recursive.
+ */
+ if (event instanceof String) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ /*
+ * Requirements for a selection event to be issued is that the file exist, and
+ * that the parentDelta contain a FileVMC of a parent directory as its element.
+ *
+ * The test for first the former requirement could be performed inside getDeltaFlags()
+ * but getDeltaFlags() is synchronous, so it is better to perform this test here using
+ * a background thread (job).
+ *
+ * The latter is requirement is needed because this node does not have the algorithm
+ * calculate the complete list of root nodes. That algorithm is implemented inside the
+ * {@link FileSystemRootsLayoutNode#updateElements} method.
+ */
+
+ final File eventFile = new File((String)event);
+ File parentFile = null;
+ if (parentDelta.getElement() instanceof FileVMContext) {
+ parentFile = ((FileVMContext)parentDelta.getElement()).getFile();
+ }
+
+ // The file has to exist in order for us to be able to select
+ // it in the tree.
+ if (eventFile.exists() && parentFile != null) {
+ // Create a list containing all files in path
+ List<File> filePath = new LinkedList<File>();
+ for (File file = eventFile; file != null && !file.equals(parentFile); file = file.getParentFile()) {
+ filePath.add(0, file);
+ }
+
+ if (filePath.size() != 0) {
+ // Build the delta for all files in path.
+ ModelDelta delta = parentDelta;
+ File[] allFilesInDirectory = parentFile.listFiles();
+ for (File pathSegment : filePath) {
+ // All files in path should be directories, and should therefore
+ // have a valid list of elements.
+ assert allFilesInDirectory != null;
+
+ File[] pathSegmentDirectoryFiles = pathSegment.listFiles();
+ delta = delta.addNode(
+ new FileVMContext(FileVMNode.this, pathSegment),
+ nodeOffset + Arrays.asList(allFilesInDirectory).indexOf(pathSegment),
+ IModelDelta.NO_CHANGE,
+ pathSegmentDirectoryFiles != null ? pathSegmentDirectoryFiles.length : 0);
+ allFilesInDirectory = pathSegmentDirectoryFiles;
+ }
+
+ // The last file in path gets the EXPAND | SELECT flags.
+ delta.setFlags(delta.getFlags() | IModelDelta.SELECT | IModelDelta.EXPAND);
+ }
+ }
+
+ // Invoke the request monitor.
+
+ requestMonitor.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ } else {
+ requestMonitor.done();
+ }
+ }
+
+ /**
+ * Override the behavior which checks for delta flags of all the child nodes,
+ * because we would get stuck in a recursive loop. Instead call only the child
+ * nodes which are not us.
+ */
+ protected Map<IVMNode, Integer> getChildNodesWithDeltas(Object e) {
+ Map<IVMNode, Integer> nodes = new HashMap<IVMNode, Integer>();
+ for (final IVMNode childNode : getChildNodes()) {
+ int delta = childNode.getDeltaFlags(e);
+ if (delta != IModelDelta.NO_CHANGE) {
+ nodes.put(childNode, delta);
+ }
+ }
+ return nodes;
+ }
+
+ public IVMProvider getVMProvider() {
+ return fProvider;
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java
new file mode 100644
index 00000000000..a2eb938da95
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+
+
+/**
+ * Viewer model node that populates the filesystem root elements.
+ */
+@SuppressWarnings("restriction")
+class FilesystemRootsVMNode extends AbstractVMNode
+ implements IElementLabelProvider
+{
+ public FilesystemRootsVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public String toString() {
+ return "FilesystemRootsVMNode";
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ File[] files = File.listRoots();
+ for (IChildrenUpdate update : updates) {
+ int offset = update.getOffset() != -1 ? update.getOffset() : 0;
+ int length = update.getLength() != -1 ? update.getLength() : files.length;
+ for (int i = offset; (i < files.length) && (i < (offset + length)); i++) {
+ update.setChild(new FileVMContext(FilesystemRootsVMNode.this, files[i]), i);
+ }
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ for (IHasChildrenUpdate update : updates) {
+ /*
+ * Assume that all filesystem roots have children. If user attempts
+ * to expand an empty directory, the plus sign will be removed
+ * from the element.
+ */
+ update.setHasChilren(true);
+ update.done();
+ }
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenCountUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ update.setChildCount(File.listRoots().length);
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel(getLabel((FileVMContext)update.getElement()), 0);
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+
+ /**
+ * Returs the text label to show in the tree for given element. Filesystem
+ * roots return an empty string for call to File.getName(), use the abolute path
+ * string instead.
+ */
+ private String getLabel(FileVMContext vmc) {
+ return vmc.getFile().getAbsolutePath();
+ }
+
+ public int getDeltaFlags(Object e) {
+ /*
+ * @see buildDelta()
+ */
+ int retVal = IModelDelta.NO_CHANGE;
+ if (e instanceof String) {
+ retVal |= IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+
+ return retVal;
+ }
+
+ public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ if (event instanceof String) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final File eventFile = new File((String)event);
+
+ if (eventFile.exists()) {
+ // Create a list containing all files in path of the file from the event
+ List<File> filePath = new LinkedList<File>();
+ for (File file = eventFile; file != null; file = file.getParentFile()) {
+ filePath.add(0, file);
+ }
+ File eventRoot = filePath.get(0);
+
+ // Get the index of the file in list of filesystem roots.
+ File[] roots = File.listRoots();
+
+ int index = 0;
+ for (; index < roots.length; index++) {
+ if (eventRoot.equals(roots[index])) break;
+ }
+
+ // Check if the specified file is not one of the roots.
+ if (index < roots.length) {
+ ModelDelta delta = parentDelta.addNode(
+ new FileVMContext(FilesystemRootsVMNode.this, eventRoot),
+ index, IModelDelta.NO_CHANGE);
+
+ if (eventFile.equals(eventRoot)) {
+ // The event is for the root node. Select it and extend parent node.
+ delta.setFlags(delta.getFlags() | IModelDelta.SELECT | IModelDelta.EXPAND);
+ }
+ }
+ }
+
+ // Invoke the request monitor.
+ requestMonitor.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ } else {
+ requestMonitor.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html
new file mode 100644
index 00000000000..865be837a58
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html
@@ -0,0 +1,127 @@
+<!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>DSF Filesystem Browser Example</title>
+</head>
+<body>
+<h2>DSF Filesystem Browser Example</h2>
+<h3>Goals</h3>
+This example demonstrates an implementation of a viewer model with a
+layout node that has itself as a child.&nbsp; Such layout nodes are
+needed to represents elements which themselves have a natural tree
+structures.&nbsp; This example uses filesystem folders as the
+tree-structured data, which is retrieved directly from the java.io.File
+class.&nbsp; This example also demonstrates a viewer model
+implementation which does not retrieve data using DSF services and
+associated data model interfaces.&nbsp; <br>
+<h3><span style="font-weight: bold;">Design</span></h3>
+<span style="text-decoration: underline;">Model Adapter Hookup</span><br>
+A flexible-hierarchy tree viewer {@link
+org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer}
+is created within a model dialog.&nbsp; Corresponding {@link
+FileBrowserModelAdapter} and {@link FileBrowserVMProvider} classes are
+instanciated, and the root element object created by
+FileBrowserVMProvider is set as input to the tree viewer.&nbsp; From
+there FileBrowserModelAdapter is returned as the {@link
+IElementContentProvier} and {@link IModelProxyFactory} for all elements
+in the tree.<br>
+<br>
+<p><span style="text-decoration: underline;">Layout Nodes</span><br>
+There are three layout nodes:<br>
+</p>
+<ul>
+ <li>{@link FileBrowserVMProvider.VMRootLayoutNode} is just a root
+node, which generates the input element for the viewer.</li>
+ <li>{@link FilesystemRootsLayoutNode} retrieves the roots of the
+filesystem hierarchy ("C:\", "D:\", etc on Windows).&nbsp; <br>
+ </li>
+ <li>{@link FileLayoutNode} is a child of <span
+ style="font-family: monospace;">FilesystemRootsLayoutNode</span> and
+it recursively retrieves all folders and files under the given parent
+file element.&nbsp; This layout node does not allow any children nodes
+to be added to it, and it returns only itself as a child node (through
+a call to <span style="font-family: monospace;">IVMLayoutNode.getChildLayoutNodes</span>).<br>
+ </li>
+</ul>
+Both <span style="font-family: monospace;">FilesystemRootsLayoutNode</span>
+and <span style="font-family: monospace;">FileLayoutNode</span> create
+elements of the same type: {@link FileVMContext}.&nbsp; Additionally,
+when populating elements in the tree, the <span
+ style="font-family: monospace;">FileLayoutNode</span> requires that a <span
+ style="font-family: monospace;">FileVMContext</span> element be the
+parent element in order to be able to retrieve its children.&nbsp; <br>
+<span style="font-family: monospace;"></span>
+<p><span style="font-family: monospace;"></span></p>
+<span style="text-decoration: underline;">Event Handling/Generating
+Model Deltas</span><br>
+The view model responds to events generated by a text box in the
+dialog, where the user can type in a filesystem path.&nbsp; If the
+entered path resolves to a file on the filesystem, the view model
+generates a delta to select and reveal the given file in the
+tree.&nbsp; The two file layout nodes handle generating the delta in
+different ways:<br>
+<ul>
+ <li><span style="font-family: monospace;">FilesystemRootsLayoutNode</span>
+is a standard layout node.&nbsp; <br>
+ </li>
+ <ol>
+ <li>In the event handler implementation {@link
+org.eclipse.cdt.dsf.ui.viewermodel.IVMLayoutNode#buildDelta}, the user
+specified file-path is compared to the list of file-system roots.&nbsp;
+ <br>
+ </li>
+ <li>If the user file-path contains one of the filesystem roots, a
+new delta node is added for that root and the child layout node is
+called to continue the delta processing.&nbsp; <br>
+ </li>
+ <li>If the user file-path points to one of the filesystem roots,
+the <span style="font-family: monospace;">IModelDelta.SELECT</span>
+and <span style="font-family: monospace;">IModelDelta.EXPAND</span>
+flags are also added to the delta so that the root will be selected in
+the viewer.<br>
+ </li>
+ </ol>
+ <li><span style="font-family: monospace;">FileLayoutNode</span> is
+the special case, because it is a recusrive node.&nbsp; This node does
+not call any child nodes to process the delta, instead it calculates
+the delta for all file elements in user file-path, starting at the
+parent element. <br>
+ </li>
+ <ol>
+ <li>First the parent <span style="font-family: monospace;">FileVMContext</span>
+element is retrieved from the delta.&nbsp; <br>
+ </li>
+ <li>Then the user file-path is broken down into {@link
+java.io.File} objects representing each segment in the path, starting
+at the parent file element retrieved in step 1.</li>
+ <li>Then a delta node is added for each segment of the calculated
+path.&nbsp; <br>
+ </li>
+ <li><span style="font-family: monospace;">IModelDelta.SELECT</span>
+and <span style="font-family: monospace;">IModelDelta.EXPAND</span>
+flags are added to the last delta.<br>
+ </li>
+ </ol>
+</ul>
+<h3>How to use</h3>
+<ol>
+ <li>Make sure that the DSF examples menu is visible in the perspective</li>
+ <ul>
+ <li>Go to Windows -&gt; Customize Perspective...</li>
+ <li>Select Commands tab</li>
+ <li>Check the "DSF Examples" in the "Available command groups"
+table.</li>
+ </ul>
+ <li>Open the dialog by selecting DSF Examples-&gt;Open File Browser
+Dialog menu item.</li>
+ <li>Expand the items in the tree to see filesystem contents.</li>
+ <li>Select elements in the tree, to fill in text box with selected
+file's path.</li>
+ <li>Type in a file path in text box and have the tree expand to the
+specified element.<br>
+ </li>
+</ol>
+</body>
+</html>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java
new file mode 100644
index 00000000000..3823930faf7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerTickDMEvent;
+import org.osgi.framework.BundleContext;
+
+/**
+ * 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
+ * initialized before this service is initialized.
+ * </p>
+ */
+public class AlarmService extends AbstractDsfService
+{
+ /** Event indicating that the list of triggers is changed. */
+ @Immutable
+ public static class TriggersChangedEvent {}
+
+ /** Context representing an alarm tracked by this service. */
+ @Immutable
+ public static class TriggerDMContext extends AbstractDMContext {
+ /** Alarm number, also index into alarm map */
+ final int fNumber;
+
+ private TriggerDMContext(String sessionId, int number) {
+ super(sessionId, new IDMContext[0]);
+ fNumber = number;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return baseEquals(other) &&
+ ((TriggerDMContext)other).fNumber == fNumber;
+ }
+
+ public int getTriggerNumber() {
+ return fNumber;
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + fNumber;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".trigger[" + fNumber + "]";
+ }
+ }
+
+ /**
+ * Context representing the "triggered" status of an alarm with respect to
+ * a specific timer.
+ */
+ @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(); }
+
+ @Override
+ public String toString() {
+ return baseToString() + ":alarm"; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Event indicating that an alarm has been triggered by a timer.
+ */
+ public class AlarmTriggeredDMEvent extends AbstractDMEvent<AlarmDMContext> {
+ public AlarmTriggeredDMEvent(AlarmDMContext context) {
+ super(context);
+ }
+ }
+
+ private int fTriggerNumberCounter = 1;
+ private Map<TriggerDMContext, Integer> fTriggers =
+ new LinkedHashMap<TriggerDMContext, Integer>();
+
+ AlarmService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfExamplesPlugin.getDefault().getBundle().getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ // After super-class is finished initializing
+ // perform TimerService initialization.
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ 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();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor) {
+ getSession().removeServiceEventListener(this);
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+
+ public boolean isValid() { return true; }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(TimerTickDMEvent event) {
+ final TimerDMContext timerContext = event.getDMContext();
+
+ 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);
+ }
+
+ 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()) {
+ // Generate the AlarmTriggeredEvent
+ AlarmDMContext alarmCtx = new AlarmDMContext(
+ getSession().getId(), timerContext, entry.getKey());
+ getSession().dispatchEvent(
+ new AlarmTriggeredDMEvent(alarmCtx), getProperties());
+ }
+ }
+ }
+
+
+ /** 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;
+ }
+ }
+
+ /** Returns the alarm context for given timer and trigger contexts. */
+ public AlarmDMContext getAlarm(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);
+ }
+
+ return false;
+ }
+
+ /** 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 deleteTrigger(TriggerDMContext alarmCtx) {
+ fTriggers.remove(alarmCtx);
+ getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
+ }
+
+ /** 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 TriggersChangedEvent(), getProperties());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java
new file mode 100644
index 00000000000..be7b22f3b07
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+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.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.AlarmDMContext;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+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 AlarmDMContext
+ */
+@SuppressWarnings("restriction")
+class AlarmsVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider
+{
+ public AlarmsVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, AlarmDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "AlarmsVMNode(" + getSession().getId() + ")";
+ }
+
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ // Check that the service is available and find the trigger and timer contexts.
+ // If not found, fail.
+ AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
+ TriggerDMContext alarmDmc = findDmcInPath(
+ update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
+ TimerDMContext timerDmc = findDmcInPath(
+ update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
+ if (alarmService == null || 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 = alarmService.getAlarm(alarmDmc, timerDmc);
+ boolean triggered = alarmService.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) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel("ALARM TRIGGERED", 0);
+ update.setImageDescriptor(
+ DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
+ DsfExamplesPlugin.IMG_ALARM_TRIGGERED),
+ 0);
+ update.done();
+ }
+ }
+
+
+ public int getDeltaFlags(Object e) {
+ if (e instanceof AlarmService.AlarmTriggeredDMEvent) {
+ return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ 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.AlarmTriggeredDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
+ parentDelta.addNode(
+ createVMContext( ((AlarmService.AlarmTriggeredDMEvent)e).getDMContext() ),
+ 0,
+ IModelDelta.ADDED | IModelDelta.SELECT);
+ }
+ requestMonitor.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java
new file mode 100644
index 00000000000..cb8276c9a13
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Sequence that stops the services in the timers session.
+ */
+public class ServicesShutdownSequence extends Sequence {
+
+ // 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;
+
+ public ServicesShutdownSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fTracker = new DsfServicesTracker(DsfExamplesPlugin.getBundleContext(), fSession.getId());
+ requestMonitor.done();
+ }
+
+ @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();
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(AlarmService.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(TimerService.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Dispose the tracker after the services are shut down.
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ // 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,
+ IDsfStatusConstants.INTERNAL_ERROR,
+ "Service '" + clazz.getName() + "' not found.", null));
+ requestMonitor.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java
new file mode 100644
index 00000000000..c137bc36369
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * Startup sequence for the timers session. With only two services, this is
+ * a very simple sequence.
+ */
+public class ServicesStartupSequence extends Sequence {
+
+ 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;
+
+
+ public ServicesStartupSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fTimerService = new TimerService(fSession);
+ fTimerService.initialize(requestMonitor);
+ }},
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fAlarmService = new AlarmService(fSession);
+ fAlarmService.initialize(requestMonitor);
+ }},
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Create the first timer and trigger.
+ fTimerService.startTimer();
+ fAlarmService.createTrigger(5);
+ requestMonitor.done();
+ }}
+ };
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java
new file mode 100644
index 00000000000..6b05f0a1c5e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Timer service tracks a set of timers, which are created per user request.
+ * 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
+{
+ /** Event indicating that the list of timers is changed. */
+ @Immutable
+ public static class TimersChangedEvent {}
+
+ /** Data Model context representing a timer. */
+ @Immutable
+ public static class TimerDMContext extends AbstractDMContext {
+ final int fNumber;
+
+ public TimerDMContext(String sessionId, int timer) {
+ super(sessionId, new IDMContext[0]);
+ fNumber = timer;
+ }
+
+ /** 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) &&
+ ((TimerDMContext)other).fNumber == fNumber;
+ }
+
+ @Override
+ public int hashCode() { return baseHashCode() + fNumber; }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".timer[" + fNumber + "]";
+ }
+ }
+
+ /**
+ * Event indicating that a timer's value has incremented. The context in
+ * the event points to the timer that has changed.
+ */
+ public class TimerTickDMEvent extends AbstractDMEvent<TimerDMContext> {
+ public TimerTickDMEvent(TimerDMContext context) {
+ super(context);
+ }
+ }
+
+ /** Counter for generating timer numbers */
+ private int fTimerNumberCounter = 1;
+
+ // 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<?>>();
+
+
+ TimerService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfExamplesPlugin.getDefault().getBundle().getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ // 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) {
+ // Cancel timer futures to avoid firing more events.
+ for (Future<?> future : fTimerFutures.values()) {
+ future.cancel(false);
+ }
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+
+ /** Retrieves the list of timer contexts. */
+ public TimerDMContext[] getTimers() {
+ return fTimers.keySet().toArray(new TimerDMContext[fTimers.size()]);
+ }
+
+ /** 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;
+ }
+
+ /** 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 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);
+
+ // 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(TimerDMContext timerContext) {
+ if (fTimers.containsKey(timerContext)) {
+ fTimers.remove(timerContext);
+ fTimerFutures.remove(timerContext).cancel(false);
+ }
+ getSession().dispatchEvent(new TimersChangedEvent(), getProperties());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java
new file mode 100644
index 00000000000..c804f6d2476
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java
@@ -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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.cdt.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();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java
new file mode 100644
index 00000000000..5fae6c32c75
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter;
+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 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)}.
+ */
+@SuppressWarnings("restriction")
+@ThreadSafe
+public class TimersVMAdapter extends AbstractDMVMAdapter
+{
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ if ( TimersView.ID_VIEW_TIMERS.equals(context.getId()) ) {
+ return new TimersVMProvider(this, context, getSession());
+ }
+ return null;
+ }
+
+ public TimersVMAdapter(DsfSession session, IPresentationContext presentationContext) {
+ super(session);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java
new file mode 100644
index 00000000000..bba6d1f1ed3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.text.MessageFormat;
+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.LabelImage;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.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 TimerDMContext
+ */
+@SuppressWarnings("restriction")
+class TimersVMNode extends AbstractDMVMNode
+ 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, TimerDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "TimersVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ fgLabelProvider.update(updates);
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ TimerService timerService = getServicesTracker().getService(TimerService.class, null);
+ if ( timerService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // Retrieve the timer DMContexts, create the corresponding VMCs array, and
+ // set them as result.
+ TimerDMContext[] timers = timerService.getTimers();
+ fillUpdateWithVMCs(update, timers);
+ update.done();
+ }
+
+
+ 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 timer context in the element being updated
+ TimerDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
+ TimerService timerService = getServicesTracker().getService(TimerService.class, null);
+
+ // If either update or service are not valid, fail the update and exit.
+ if ( dmc == null || timerService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ 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();
+ }
+
+ public int getDeltaFlags(Object e) {
+ // This node generates delta if the timers have changed, or if the
+ // label has changed.
+ if (e instanceof TimerService.TimerTickDMEvent) {
+ return IModelDelta.STATE;
+ } else if (e instanceof TimerService.TimersChangedEvent) {
+ return IModelDelta.CONTENT;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
+ 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
+ // elements from this node.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+ requestMonitor.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java
new file mode 100644
index 00000000000..e44c122d7db
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggersChangedEvent;
+import org.eclipse.cdt.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 {
+
+ /** 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 { TRIGGERS_AT_TOP, TIMERS_AT_TOP }
+
+ public TimersVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
+ super(adapter, presentationContext, session);
+ // Set the initial view layout.
+ setViewLayout(ViewLayout.TIMERS_AT_TOP);
+ }
+
+ /**
+ * Configures a new layout for the timers view model.
+ * @param layout New layout to use.
+ */
+ public void setViewLayout(ViewLayout layout) {
+ clearNodes();
+ if (layout == ViewLayout.TRIGGERS_AT_TOP) {
+ IRootVMNode root = new TimersRootVMNode(this);
+ IVMNode triggersNode = new TriggersVMNode(this, getSession());
+ addChildNodes(root, new IVMNode[] { triggersNode });
+ IVMNode timersNode = new TimersVMNode(this, getSession());
+ addChildNodes(triggersNode, new IVMNode[] { timersNode });
+ IVMNode alarmNode = new AlarmsVMNode(this, getSession());
+ addChildNodes(timersNode, new IVMNode[] { alarmNode });
+ setRootNode(root);
+ } else if (layout == ViewLayout.TIMERS_AT_TOP) {
+ IRootVMNode root = new TimersRootVMNode(this);
+ IVMNode timersNode = new TimersVMNode(this, getSession());
+ addChildNodes(root, new IVMNode[] { timersNode });
+ IVMNode triggersNode = new TriggersVMNode(this, getSession());
+ addChildNodes(timersNode, new IVMNode[] { triggersNode });
+ IVMNode alarmNode = new AlarmsVMNode(this, getSession());
+ addChildNodes(triggersNode, new IVMNode[] { alarmNode });
+ setRootNode(root);
+ }
+
+ handleEvent(new TimersViewLayoutChanged());
+ }
+
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return new TimersViewColumnPresentation();
+ }
+
+ @Override
+ 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) {}
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java
new file mode 100644
index 00000000000..d9c4a59dac8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimersVMProvider.ViewLayout;
+import org.eclipse.core.runtime.IAdaptable;
+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.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+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;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.part.ViewPart;
+
+
+/**
+ * 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.cdt.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;
+
+ /** DSF session */
+ private DsfSession fSession;
+
+ /** DSF services tracker used by actions in the viewer. */
+ private DsfServicesTracker fServices;
+
+ /** Adapter used to provide view model for flexible-hierarchy viewer */
+ private TimersVMAdapter fTimersVMAdapter;
+
+ /** Action which toggles the layout in the viewer */
+ private Action fToggleLayoutAction;
+
+ /** Action that adds a new timer */
+ private Action fAddTimerAction;
+
+ /** Action that adds a new trigger */
+ private Action fAddTriggerAction;
+
+ /** Action that removes the selected trigger or timer */
+ private Action fRemoveAction;
+
+ public TimersView() {}
+
+ /**
+ * 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 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.
+ fExecutor = new DefaultDsfExecutor();
+ 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
+ // 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 {
+ startupSeq.get();
+ } catch (InterruptedException e) { assert false;
+ } catch (ExecutionException e) { assert false;
+ }
+
+ // 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);
+
+ // 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();
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ // 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);
+ }}).get();
+
+ // 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();
+ } catch (InterruptedException e) { assert false;
+ } catch (ExecutionException e) { assert false;
+ }
+
+ // Finally end the session and the executor.
+ fSession.getExecutor().submit(new Runnable() {
+ public void run() {
+ DsfSession.endSession(fSession);
+ fSession = null;
+ fExecutor.shutdown();
+ fExecutor = null;
+ }}).get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ super.dispose();
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ fillLocalToolBar(bars.getToolBarManager());
+ }
+
+ private void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(fToggleLayoutAction);
+ manager.add(fAddTimerAction);
+ manager.add(fAddTriggerAction);
+ manager.add(fRemoveAction);
+ manager.add(new Separator());
+ }
+
+ private void makeActions() {
+ fToggleLayoutAction = new Action("Toggle Layout", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
+ @Override
+ public void run() {
+ // Get the toggle state of the action while on UI thread.
+ final ViewLayout layout = isChecked() ? ViewLayout.TRIGGERS_AT_TOP : ViewLayout.TIMERS_AT_TOP;
+
+ 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") {
+ @Override
+ public void run() {
+ 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 a new timer");
+ fAddTimerAction.setImageDescriptor(
+ getImage(DsfExamplesPlugin.IMG_TIMER));
+
+ fAddTriggerAction = new Action("Add New Trigger") {
+ @Override
+ public void run() {
+ // Ask user for the new trigger value.
+ InputDialog inputDialog = new InputDialog(
+ 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";
+
+ } catch (NumberFormatException x) {
+ return "Please enter a positive integer";
+ }
+ return null;
+ }
+ }
+ );
+ if (inputDialog.open() != Window.OK) return;
+ int tmpTriggerValue = -1;
+ try {
+ tmpTriggerValue = Integer.parseInt(inputDialog.getValue());
+ } catch (NumberFormatException x) { assert false; }
+ final int triggerValue = tmpTriggerValue;
+ fExecutor.execute(new Runnable() {
+ public void run() {
+ // Create the new trigger
+ fServices.getService(AlarmService.class).
+ createTrigger(triggerValue);
+ }
+ });
+ }
+ };
+ fAddTriggerAction.setToolTipText("Add a new trigger");
+ fAddTriggerAction.setImageDescriptor(
+ getImage(DsfExamplesPlugin.IMG_ALARM));
+
+ fRemoveAction = new Action("Remove") {
+ @Override
+ public void run() {
+ final Object selectedElement =
+ ((IStructuredSelection)fViewer.getSelection()).getFirstElement();
+ if (!(selectedElement instanceof IDMVMContext)) return;
+ 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(
+ ((TimerDMContext)selectedCtx));
+ }});
+ } 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");
+ 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.
+ */
+ @Override
+ public void setFocus() {
+ fViewer.getControl().setFocus();
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java
new file mode 100644
index 00000000000..a43778a525a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class TimersViewColumnPresentation implements IColumnPresentation {
+
+ public static final String ID = DsfExamplesPlugin.PLUGIN_ID + ".TIMER_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+ public static final String COL_ID = ID + ".COL_ID"; //$NON-NLS-1$
+ public static final String COL_VALUE = ID + ".COL_VALUE"; //$NON-NLS-1$
+
+ public void init(IPresentationContext context) {}
+
+ public void dispose() {}
+
+ public String[] getAvailableColumns() {
+ return new String[] { COL_ID, COL_VALUE };
+ }
+
+ public String getHeader(String id) {
+ if (COL_ID.equals(id)) {
+ return "ID"; //$NON-NLS-1$
+ } else if (COL_VALUE.equals(id)) {
+ return "Value"; //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ public String getId() {
+ return ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ public String[] getInitialColumns() {
+ return getAvailableColumns();
+ }
+
+ public boolean isOptional() {
+ return true;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java
new file mode 100644
index 00000000000..b7de00a0ca4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Cell modifier used to edit the trigger value.
+ */
+@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
+public class TriggerCellModifier implements ICellModifier {
+
+ private final DsfSession fSession;
+
+ // 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 session in order to
+ * initialize the service tracker.
+ * @param session DSF session this modifier will use.
+ */
+ public TriggerCellModifier(DsfSession session) {
+ fSession = session;
+ }
+
+ public boolean canModify(Object element, String property) {
+ return TimersViewColumnPresentation.COL_VALUE.equals(property) &&
+ getAlarmDMC(element) != null;
+ }
+
+ public Object getValue(Object element, String property) {
+ if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return "";
+
+ // 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.
+ 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 "";
+ } catch (ExecutionException e) {
+ return "";
+ }
+ }
+
+
+ public void modify(Object element, String property, Object value) {
+ if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return;
+
+ TriggerDMContext dmc = getAlarmDMC(element);
+ if (dmc == null) return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return;
+
+ // Shell is used in displaying error dialogs.
+ Shell shell = getShell();
+ if (shell == null) return;
+
+ Integer intValue = null;
+ if (value instanceof String) {
+ try {
+ intValue = new Integer(((String)value).trim());
+ } catch (NumberFormatException e) {
+ 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");
+ return;
+ }
+ }
+
+ // Create the query to write the value to the service.
+ SetValueQuery query = new SetValueQuery(dmc, intValue);
+
+ 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 error dialog.
+ }
+ }
+
+ /**
+ * Need to dispose the cell modifier property because of the service
+ * tracker.
+ */
+ @ThreadSafe
+ public synchronized void dispose() {
+ if (fServiceTracker != null) {
+ fServiceTracker.close();
+ }
+ }
+
+ private Shell getShell() {
+ if (DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() != null) {
+ return DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell();
+ }
+ return null;
+ }
+
+ private TriggerDMContext getAlarmDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (TriggerDMContext)((IAdaptable)element).getAdapter(TriggerDMContext.class);
+ }
+ return null;
+ }
+
+ @ThreadSafe
+ 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 {
+ fServiceTracker = new ServiceTracker(
+ DsfExamplesPlugin.getBundleContext(),
+ DsfExamplesPlugin.getBundleContext().createFilter(serviceId),
+ null);
+ fServiceTracker.open();
+ } catch (InvalidSyntaxException e) {
+ return null;
+ }
+ }
+ // Get the service.
+ return (AlarmService)fServiceTracker.getService();
+ }
+
+
+ private class GetValueQuery extends Query<Integer> {
+ final TriggerDMContext fDmc;
+
+ 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.
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ return;
+ }
+
+ AlarmService service = getService(fDmc);
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service not available", null));
+ rm.done();
+ return;
+ }
+
+ int value = service.getTriggerValue(fDmc);
+ if (value == -1) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
+ "Invalid context", null));
+ rm.done();
+ return;
+ }
+
+ rm.setData(value);
+ rm.done();
+ }
+ }
+
+ private class SetValueQuery extends Query<Object> {
+
+ TriggerDMContext fDmc;
+ int fValue;
+
+ SetValueQuery(TriggerDMContext dmc, int value) {
+ super();
+ fDmc = dmc;
+ fValue = value;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ // Guard against terminated session
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ return;
+ }
+
+ // Guard against a disposed service
+ AlarmService service = getService(fDmc);
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service not available", null));
+ rm.done();
+ return;
+ }
+
+ // Finally set the value and return.
+ service.setTriggerValue(fDmc, fValue);
+
+ // Return value is irrelevant.
+ rm.setData(new Object());
+ rm.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java
new file mode 100644
index 00000000000..4b6cef7d88a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.timers;
+
+import java.text.MessageFormat;
+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.LabelImage;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
+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.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
+ 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();
+ }
+
+ 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);
+ 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();
+ }
+
+ 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();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png
new file mode 100644
index 00000000000..0e7c8683d61
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png
Binary files differ

Back to the top