Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Tarassov2011-10-21 18:05:56 +0000
committerEugene Tarassov2011-10-21 18:05:56 +0000
commit092ca5f4882e941dc338d1357e4863abe8e3c9ac (patch)
treedcbf5e26eed6c4b2ab8eb28ffd4d8b8b489d67cd
parentb4e87915c9e9ccc6d05b550557490a9a42b67f08 (diff)
downloadorg.eclipse.tcf-092ca5f4882e941dc338d1357e4863abe8e3c9ac.tar.gz
org.eclipse.tcf-092ca5f4882e941dc338d1357e4863abe8e3c9ac.tar.xz
org.eclipse.tcf-092ca5f4882e941dc338d1357e4863abe8e3c9ac.zip
TCF Debugger: added manual refresh mode in debug views.
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/plugin.properties1
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml13
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ManualRefreshCommand.java78
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RefreshCommand.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java90
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java6
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java71
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSnapshot.java351
8 files changed, 588 insertions, 28 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.properties b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.properties
index eec80514f..719aa1252 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.properties
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.properties
@@ -24,6 +24,7 @@ MemoryMap.label = Symbol Files...
ViewMemory.label = View Memory
WatchInExpressions.label = Watch In Expressions
Refresh.label = Refresh
+ManualRefresh.label = Manual Refresh
CastToType.label=Cast To Type...
CastToType.tooltip=Cast Expression To Type
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml
index 068853b44..20c8c9940 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml
@@ -274,6 +274,19 @@
</pluginState>
</enablement>
</action>
+ <action
+ class="org.eclipse.tm.internal.tcf.debug.ui.commands.ManualRefreshCommand"
+ id="org.eclipse.tm.tcf.debug.ui.actions.ManualRefresh"
+ label="%ManualRefresh.label"
+ menubarPath="additions"
+ style="toggle">
+ <enablement>
+ <pluginState
+ value="activated"
+ id="org.eclipse.tm.tcf.debug.ui">
+ </pluginState>
+ </enablement>
+ </action>
</objectContribution>
<!-- TCFNodeExpression popup menu contributions -->
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ManualRefreshCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ManualRefreshCommand.java
new file mode 100644
index 000000000..6de94ebe3
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ManualRefreshCommand.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.internal.tcf.debug.ui.commands;
+
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode;
+import org.eclipse.tm.tcf.util.TCFTask;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+
+public class ManualRefreshCommand extends AbstractActionDelegate {
+
+ // TODO: Automatic, Manual, Breakpoint Hit
+ // org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/messages.properties
+ // No update policies for current selection
+
+ @Override
+ protected void selectionChanged() {
+ final IAction action = getAction();
+ final TCFNode node = getRootNode();
+ if (node == null) {
+ action.setEnabled(false);
+ action.setChecked(false);
+ }
+ else {
+ new TCFTask<Object>(node.getChannel()) {
+ public void run() {
+ IViewPart part = getView();
+ action.setEnabled(true);
+ action.setChecked(node.getModel().isLocked(part));
+ done(null);
+ }
+ }.getE();
+ }
+ }
+
+ @Override
+ protected void run() {
+ final TCFNode node = getRootNode();
+ if (node == null) return;
+ new TCFTask<Object>(node.getChannel()) {
+ public void run() {
+ IViewPart part = getView();
+ if (getAction().isChecked()) {
+ node.getModel().setLock(part);
+ }
+ else {
+ node.getModel().clearLock(part);
+ }
+ done(null);
+ }
+ }.getE();
+ }
+
+ private TCFNode getRootNode() {
+ IViewPart view = getView();
+ if (view == null) return null;
+ IWorkbenchPartSite site = view.getSite();
+ if (site == null || IDebugUIConstants.ID_DEBUG_VIEW.equals(site.getId())) {
+ return null;
+ }
+ if (view instanceof IDebugView) {
+ Object input = ((IDebugView)view).getViewer().getInput();
+ if (input instanceof TCFNode) return (TCFNode)input;
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RefreshCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RefreshCommand.java
index 87ddb0085..783d660c1 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RefreshCommand.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RefreshCommand.java
@@ -30,7 +30,11 @@ public class RefreshCommand extends AbstractActionDelegate {
if (n == null) return;
new TCFTask<Object>(n.getChannel()) {
public void run() {
- n.refresh(getView());
+ IViewPart part = getView();
+ n.refresh(part);
+ if (n.getModel().clearLock(part)) {
+ n.getModel().setLock(part);
+ }
done(null);
}
}.getE();
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
index a9fd4f572..bc9ff9186 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
@@ -38,6 +38,7 @@ import org.eclipse.debug.core.model.IExpression;
import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.internal.ui.viewers.model.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
@@ -72,6 +73,7 @@ import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.graphics.Device;
@@ -133,6 +135,7 @@ import org.eclipse.ui.texteditor.ITextEditor;
* keeping the cache in a coherent state,
* and feeding UI with up-to-date data.
*/
+@SuppressWarnings("restriction")
public class TCFModel implements IElementContentProvider, IElementLabelProvider, IViewerInputProvider,
IModelProxyFactory, IColumnPresentationFactory, ISourceDisplay, ISuspendTrigger {
@@ -274,6 +277,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
private final Set<String> expanded_nodes = new HashSet<String>();
private final Map<IWorkbenchPart,TCFNode> pins = new HashMap<IWorkbenchPart,TCFNode>();
+ private final Map<IWorkbenchPart,TCFSnapshot> locks = new HashMap<IWorkbenchPart,TCFSnapshot>();
private TCFConsole console;
@@ -723,6 +727,11 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
void onDisconnected() {
assert Protocol.isDispatchThread();
+ if (locks.size() > 0) {
+ TCFSnapshot[] arr = locks.values().toArray(new TCFSnapshot[locks.size()]);
+ locks.clear();
+ for (TCFSnapshot s : arr) s.dispose();
+ }
if (launch_node != null) {
launch_node.dispose();
launch_node = null;
@@ -1206,64 +1215,64 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
public void update(IChildrenCountUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- Object o = updates[i].getElement();
+ for (IChildrenCountUpdate update : updates) {
+ Object o = update.getElement();
if (o instanceof TCFLaunch) {
if (launch_node != null) {
- launch_node.update(updates[i]);
+ launch_node.update(update);
}
else {
- updates[i].setChildCount(0);
- updates[i].done();
+ update.setChildCount(0);
+ update.done();
}
}
else {
- ((TCFNode)o).update(updates[i]);
+ ((TCFNode)o).update(update);
}
}
}
public void update(IChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- Object o = updates[i].getElement();
+ for (IChildrenUpdate update : updates) {
+ Object o = update.getElement();
if (o instanceof TCFLaunch) {
if (launch_node != null) {
- launch_node.update(updates[i]);
+ launch_node.update(update);
}
else {
- updates[i].done();
+ update.done();
}
}
else {
- ((TCFNode)o).update(updates[i]);
+ ((TCFNode)o).update(update);
}
}
}
public void update(IHasChildrenUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- Object o = updates[i].getElement();
+ for (IHasChildrenUpdate update : updates) {
+ Object o = update.getElement();
if (o instanceof TCFLaunch) {
if (launch_node != null) {
- launch_node.update(updates[i]);
+ launch_node.update(update);
}
else {
- updates[i].setHasChilren(false);
- updates[i].done();
+ update.setHasChilren(false);
+ update.done();
}
}
else {
- ((TCFNode)o).update(updates[i]);
+ ((TCFNode)o).update(update);
}
}
}
public void update(ILabelUpdate[] updates) {
- for (int i = 0; i < updates.length; i++) {
- Object o = updates[i].getElement();
+ for (ILabelUpdate update : updates) {
+ Object o = update.getElement();
// Launch label is provided by TCFLaunchLabelProvider class.
assert !(o instanceof TCFLaunch);
- ((TCFNode)o).update(updates[i]);
+ ((TCFNode)o).update(update);
}
}
@@ -1334,6 +1343,47 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
else pins.put(part, node);
}
+ private IPresentationContext getPresentationContext(IWorkbenchPart part) {
+ if (part instanceof IDebugView) {
+ Viewer viewer = ((IDebugView)part).getViewer();
+ if (viewer instanceof ITreeModelViewer) {
+ ITreeModelViewer t = ((ITreeModelViewer)viewer);
+ return t.getPresentationContext();
+ }
+ }
+ return null;
+ }
+
+ public void setLock(IWorkbenchPart part) {
+ if (launch_node == null) return;
+ IPresentationContext ctx = getPresentationContext(part);
+ if (ctx == null) return;
+ locks.put(part, new TCFSnapshot(ctx));
+ TCFModelProxy proxy = model_proxies.get(ctx);
+ if (proxy == null) return;
+ proxy.addDelta((TCFNode)proxy.getInput(), IModelDelta.CONTENT);
+ }
+
+ public boolean isLocked(IWorkbenchPart part) {
+ return locks.get(part) != null;
+ }
+
+ public boolean clearLock(IWorkbenchPart part) {
+ TCFSnapshot snapshot = locks.remove(part);
+ if (snapshot == null) return false;
+ snapshot.dispose();
+ IPresentationContext ctx = getPresentationContext(part);
+ if (ctx != null) {
+ TCFModelProxy proxy = model_proxies.get(ctx);
+ if (proxy != null) proxy.addDelta((TCFNode)proxy.getInput(), IModelDelta.CONTENT);
+ }
+ return true;
+ }
+
+ TCFSnapshot getSnapshot(IPresentationContext ctx) {
+ return locks.get(ctx.getPart());
+ }
+
public void setDebugViewSelection(TCFNode node, String reason) {
assert Protocol.isDispatchThread();
if (node == null) return;
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
index 9a5f09b9f..dcc5d3795 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelProxy.java
@@ -283,13 +283,13 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru
if (node.isDisposed()) {
res = EMPTY_NODE_ARRAY;
}
- else if (!node.getData(children_count_update, null)) {
+ else if (!node.getLockedData(children_count_update, null)) {
pending_node = node;
res = EMPTY_NODE_ARRAY;
}
else {
children_update.setLength(children_count_update.count);
- if (!node.getData(children_update, null)) {
+ if (!node.getLockedData(children_update, null)) {
assert false;
pending_node = node;
res = EMPTY_NODE_ARRAY;
@@ -497,7 +497,7 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru
if (pending_node == null) {
launch.removePendingClient(this);
}
- else if (pending_node.getData(children_count_update, this)) {
+ else if (pending_node.getLockedData(children_count_update, this)) {
assert false;
Protocol.invokeLater(this);
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
index 8fc01c255..cf0f37574 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java
@@ -29,7 +29,6 @@ import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.util.TCFDataCache;
import org.eclipse.ui.IViewPart;
-
/**
* TCFNode is base class for all TCF debug model elements.
*/
@@ -239,7 +238,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
if (!done) {
if (!update.isCanceled()) {
if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!getData(update, this)) return;
+ if (!getLockedData(update, this)) return;
}
update.setStatus(Status.OK_STATUS);
}
@@ -259,7 +258,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
if (!done) {
if (!update.isCanceled()) {
if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!getData(update, this)) return;
+ if (!getLockedData(update, this)) return;
}
else {
update.setHasChilren(false);
@@ -282,7 +281,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
if (!done) {
if (!update.isCanceled()) {
if (!disposed && channel.getState() == IChannel.STATE_OPEN) {
- if (!getData(update, this)) return;
+ if (!getLockedData(update, this)) return;
}
else {
update.setLabel("...", 0);
@@ -321,6 +320,70 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo
/**
* Retrieve children count for a presentation context.
+ * If the context is locked, return snapshot data.
+ * Otherwise return live data from the target.
+ * The method is always called on TCF dispatch thread.
+ * @param update - children count update request.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ final boolean getLockedData(IChildrenCountUpdate update, Runnable done) {
+ TCFSnapshot snapshot = model.getSnapshot(update.getPresentationContext());
+ if (snapshot != null) return snapshot.getData(update, this, done);
+ return getData(update, done);
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * If the context is locked, return snapshot data.
+ * Otherwise return live data from the target.
+ * The method is always called on TCF dispatch thread.
+ * @param update - children update request.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ final boolean getLockedData(IChildrenUpdate update, Runnable done) {
+ TCFSnapshot snapshot = model.getSnapshot(update.getPresentationContext());
+ if (snapshot != null) return snapshot.getData(update, this, done);
+ return getData(update, done);
+ }
+
+ /**
+ * Check if the node has children in a presentation context.
+ * If the context is locked, return snapshot data.
+ * Otherwise return live data from the target.
+ * The method is always called on TCF dispatch thread.
+ * @param update - "has children" update request.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ final boolean getLockedData(IHasChildrenUpdate update, Runnable done) {
+ TCFSnapshot snapshot = model.getSnapshot(update.getPresentationContext());
+ if (snapshot != null) return snapshot.getData(update, this, done);
+ return getData(update, done);
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * If the context is locked, return snapshot data.
+ * Otherwise return live data from the target.
+ * The method is always called on TCF dispatch thread.
+ * @param update - label update request.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ final boolean getLockedData(ILabelUpdate update, Runnable done) {
+ TCFSnapshot snapshot = model.getSnapshot(update.getPresentationContext());
+ if (snapshot != null) return snapshot.getData(update, this, done);
+ return getData(update, done);
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
* The method is always called on TCF dispatch thread.
* @param update - children count update request.
* @param done - client call back interface, during data waiting it is
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSnapshot.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSnapshot.java
new file mode 100644
index 000000000..8ff410544
--- /dev/null
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFSnapshot.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.internal.tcf.debug.ui.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tm.tcf.protocol.Protocol;
+
+/**
+ * TCFSnapshot is used to create snapshots of debug views presentation data.
+ * Such snapshots are used to implement various view update policies.
+ */
+class TCFSnapshot {
+
+ private final IPresentationContext ctx;
+
+ private final HashMap<TCFNode,PresentationData> cache = new HashMap<TCFNode,PresentationData>();
+
+ private final String[] columns;
+ private final RGB rgb_stalled = new RGB(128, 128, 128);
+
+ private class PresentationData implements IChildrenCountUpdate, IChildrenUpdate, ILabelUpdate, Runnable {
+
+ IViewerUpdate update;
+ Runnable done;
+ boolean canceled;
+ IStatus status;
+
+ String[] label;
+ FontData[] font_data;
+ ImageDescriptor[] image_desc;
+ RGB[] fg_color;
+ RGB[] bg_color;
+ boolean label_done;
+
+ TCFNode[] children;
+ boolean children_done;
+
+ boolean stalled;
+
+ private final ArrayList<Runnable> waiting_list = new ArrayList<Runnable>();
+
+ public IPresentationContext getPresentationContext() {
+ return ctx;
+ }
+
+ public Object getElement() {
+ return update.getElement();
+ }
+
+ public TreePath getElementPath() {
+ return update.getElementPath();
+ }
+
+ public Object getViewerInput() {
+ return update.getViewerInput();
+ }
+
+ public void setStatus(IStatus status) {
+ this.status = status;
+ }
+
+ public IStatus getStatus() {
+ return status;
+ }
+
+ public void done() {
+ assert false;
+ }
+
+ public void cancel() {
+ canceled = true;
+ }
+
+ public boolean isCanceled() {
+ return canceled;
+ }
+
+ public String[] getColumnIds() {
+ return columns;
+ }
+
+ public void setLabel(String text, int col) {
+ if (!label_done) {
+ if (label == null) {
+ int cnt = columns == null ? 1 : columns.length;
+ label = new String[cnt];
+ }
+ label[col] = text;
+ }
+ else {
+ if (col >= label.length) stalled = true;
+ else if (label[col] != text) {
+ if (label[col] == null || text == null || !text.equals(label[col])) {
+ stalled = true;
+ }
+ }
+ }
+ }
+
+ public void setFontData(FontData fnt, int col) {
+ if (!label_done) {
+ if (font_data == null) {
+ int cnt = columns == null ? 1 : columns.length;
+ font_data = new FontData[cnt];
+ }
+ font_data[col] = fnt;
+ }
+ }
+
+ public void setImageDescriptor(ImageDescriptor image, int col) {
+ if (!label_done) {
+ if (image_desc == null) {
+ int cnt = columns == null ? 1 : columns.length;
+ image_desc = new ImageDescriptor[cnt];
+ }
+ image_desc[col] = image;
+ }
+ }
+
+ public void setForeground(RGB rgb, int col) {
+ if (!label_done) {
+ if (fg_color == null) {
+ int cnt = columns == null ? 1 : columns.length;
+ fg_color = new RGB[cnt];
+ }
+ fg_color[col] = rgb;
+ }
+ }
+
+ public void setBackground(RGB rgb, int col) {
+ if (!label_done) {
+ if (bg_color == null) {
+ int cnt = columns == null ? 1 : columns.length;
+ bg_color = new RGB[cnt];
+ }
+ bg_color[col] = rgb;
+ }
+ }
+
+ public int getOffset() {
+ return 0;
+ }
+
+ public int getLength() {
+ return children.length;
+ }
+
+ public void setChild(Object child, int offset) {
+ if (!children_done) {
+ children[offset] = (TCFNode)child;
+ }
+ }
+
+ public void setChildCount(int cnt) {
+ if (!children_done) {
+ children = new TCFNode[cnt];
+ }
+ }
+
+ public void run() {
+ Runnable d = done;
+ update = null;
+ done = null;
+ for (Runnable r : waiting_list) Protocol.invokeLater(r);
+ waiting_list.clear();
+ d.run();
+ }
+ }
+
+ private PresentationData data;
+
+ TCFSnapshot(IPresentationContext ctx) {
+ this.ctx = ctx;
+ columns = ctx.getColumns();
+ }
+
+ void dispose() {
+ for (PresentationData d : cache.values()) {
+ for (Runnable r : d.waiting_list) Protocol.invokeLater(r);
+ }
+ cache.clear();
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
+ * The method is always called on TCF dispatch thread.
+ * @param update - children count update request.
+ * @param node - debug model node.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ public boolean getData(IChildrenCountUpdate update, TCFNode node, Runnable done) {
+ if (!getChildren(update, node, done)) return false;
+ update.setChildCount(data.children.length);
+ return true;
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * The method is always called on TCF dispatch thread.
+ * @param update - children update request.
+ * @param node - debug model node.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ public boolean getData(IChildrenUpdate update, TCFNode node, Runnable done) {
+ if (!getChildren(update, node, done)) return false;
+ int offset = 0;
+ int r_offset = update.getOffset();
+ int r_length = update.getLength();
+ for (TCFNode n : data.children) {
+ if (offset >= r_offset && offset < r_offset + r_length) {
+ update.setChild(n, offset);
+ }
+ offset++;
+ }
+ return true;
+ }
+
+ /**
+ * Check if the node has children in a presentation context.
+ * The method is always called on TCF dispatch thread.
+ * @param update - "has children" update request.
+ * @param node - debug model node.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ public boolean getData(IHasChildrenUpdate update, TCFNode node, Runnable done) {
+ if (!getChildren(update, node, done)) return false;
+ update.setHasChilren(data.children.length > 0);
+ return true;
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * The method is always called on TCF dispatch thread.
+ * @param update - label update request.
+ * @param node - debug model node.
+ * @param done - client call back interface, during data waiting it is
+ * called every time new portion of data becomes available.
+ * @return false if waiting data retrieval, true if all done.
+ */
+ public boolean getData(ILabelUpdate update, TCFNode node, Runnable done) {
+ if (!getLabel(update, node, done)) return false;
+ String[] ids_update = update.getColumnIds();
+ String[] ids_data = columns;
+ if (ids_update != ids_data && !Arrays.equals(ids_update, ids_data)) {
+ int n = ids_update == null ? 1 : ids_update.length;
+ for (int i = 0; i < n; i++) update.setBackground(rgb_stalled, i);
+ }
+ else {
+ if (data.label != null) {
+ for (int i = 0; i < data.label.length; i++) {
+ if (data.label[i] != null) update.setLabel(data.label[i], i);
+ }
+ }
+ if (data.font_data != null) {
+ for (int i = 0; i < data.font_data.length; i++) {
+ if (data.font_data[i] != null) update.setFontData(data.font_data[i], i);
+ }
+ }
+ if (data.image_desc != null) {
+ for (int i = 0; i < data.image_desc.length; i++) {
+ if (data.image_desc[i] != null) update.setImageDescriptor(data.image_desc[i], i);
+ }
+ }
+ if (data.stalled) {
+ int n = ids_update == null ? 1 : ids_update.length;
+ for (int i = 0; i < n; i++) update.setForeground(rgb_stalled, i);
+ }
+ else {
+ if (data.fg_color != null) {
+ for (int i = 0; i < data.fg_color.length; i++) {
+ if (data.fg_color[i] != null) update.setForeground(data.fg_color[i], i);
+ }
+ }
+ }
+ if (data.bg_color != null) {
+ for (int i = 0; i < data.bg_color.length; i++) {
+ if (data.bg_color[i] != null) update.setBackground(data.bg_color[i], i);
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean getChildren(IViewerUpdate update, TCFNode node, Runnable done) {
+ data = cache.get(node);
+ if (data == null) cache.put(node, data = new PresentationData());
+ assert data.update != update;
+ if (data.children_done) return true;
+ if (data.update != null) {
+ data.waiting_list.add(done);
+ return false;
+ }
+ data.update = update;
+ data.done = done;
+ if (data.children == null) {
+ if (!node.getData((IChildrenCountUpdate)data, data)) return false;
+ assert data.children != null;
+ }
+ if (!node.getData((IChildrenUpdate)data, data)) return false;
+ data.children_done = true;
+ data.update = null;
+ data.done = null;
+ return true;
+ }
+
+ private boolean getLabel(IViewerUpdate update, TCFNode node, Runnable done) {
+ data = cache.get(node);
+ if (data == null) cache.put(node, data = new PresentationData());
+ assert data.update != update;
+ if (data.label_done && data.stalled) return true;
+ if (data.update != null) {
+ data.waiting_list.add(done);
+ return false;
+ }
+ data.update = update;
+ data.done = done;
+ if (!node.getData((ILabelUpdate)data, data)) return false;
+ data.label_done = true;
+ data.update = null;
+ data.done = null;
+ return true;
+ }
+}

Back to the top