diff options
author | Eugene Tarassov | 2011-10-21 18:05:56 +0000 |
---|---|---|
committer | Eugene Tarassov | 2011-10-21 18:05:56 +0000 |
commit | 092ca5f4882e941dc338d1357e4863abe8e3c9ac (patch) | |
tree | dcbf5e26eed6c4b2ab8eb28ffd4d8b8b489d67cd | |
parent | b4e87915c9e9ccc6d05b550557490a9a42b67f08 (diff) | |
download | org.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.
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; + } +} |