diff options
author | eutarass | 2010-02-22 18:19:02 +0000 |
---|---|---|
committer | eutarass | 2010-02-22 18:19:02 +0000 |
commit | 4964b236049b5d07a21c1cf2ce1b20a0c624d567 (patch) | |
tree | af60be954c90030d73c4bf1cb703d064824d11aa /plugins/org.eclipse.tm.tcf.debug.ui | |
parent | e85adcdb0929eebd3adc3a75795acc850034325f (diff) | |
download | org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.tar.gz org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.tar.xz org.eclipse.tcf-4964b236049b5d07a21c1cf2ce1b20a0c624d567.zip |
Work in progress: more TCF value-add support - all tests have passed when connecting to a target through TCF symbols server value-add.
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.debug.ui')
19 files changed, 378 insertions, 227 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java index c3e18cc16..c38e27406 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/Activator.java @@ -35,7 +35,9 @@ public class Activator extends AbstractUIPlugin { private static final BundleListener bundle_listener = new BundleListener() { public void bundleChanged(BundleEvent event) { - if (plugin != null && event.getBundle() == plugin.getBundle() && + if (plugin != null && event != null && + plugin.getBundle() != null && + event.getBundle() == plugin.getBundle() && plugin.getBundle().getState() != Bundle.ACTIVE) { Protocol.invokeAndWait(new Runnable() { public void run() { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java index 8d8199911..9c2417abf 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToArrayCommand.java @@ -18,6 +18,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.ISymbols; import org.eclipse.tm.tcf.util.TCFDataCache; import org.eclipse.tm.tcf.util.TCFTask; @@ -63,12 +64,16 @@ public class CastToArrayCommand extends AbstractActionDelegate { if (node == null) return; IWorkbenchWindow window = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow(); if (window == null) return; - String base_type_name = getBaseTypeName(); + final String base_type_name = getBaseTypeName(); if (base_type_name == null) return; CastToTypeDialog dialog = new CastToTypeDialog(window.getShell(), node.getModel().getCastToType(node.getID())); if (dialog.open() != Window.OK) return; - String new_type = dialog.getValue().trim(); - node.getModel().setCastToType(node.getID(), base_type_name + "[" + new_type + "]"); + final String new_type = dialog.getValue().trim(); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), base_type_name + "[" + new_type + "]"); + } + }); } private String getBaseTypeName() { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java index 34cdc8997..e953ed920 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/CastToTypeCommand.java @@ -18,6 +18,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.ui.IWorkbenchWindow; public class CastToTypeCommand extends AbstractActionDelegate { @@ -48,14 +49,18 @@ public class CastToTypeCommand extends AbstractActionDelegate { @Override protected void run() { - TCFNode node = getCastToTypeNode(); + final TCFNode node = getCastToTypeNode(); if (node == null) return; IWorkbenchWindow window = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow(); if (window == null) return; CastToTypeDialog dialog = new CastToTypeDialog(window.getShell(), node.getModel().getCastToType(node.getID())); if (dialog.open() != Window.OK) return; - String new_type = dialog.getValue().trim(); - node.getModel().setCastToType(node.getID(), new_type); + final String new_type = dialog.getValue().trim(); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), new_type); + } + }); } @Override diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java index 1e02cc19b..8bc9bd915 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/RestoreDefaultTypeCommand.java @@ -12,14 +12,19 @@ package org.eclipse.tm.internal.tcf.debug.ui.commands; import org.eclipse.tm.internal.tcf.debug.ui.model.ICastToType; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; +import org.eclipse.tm.tcf.protocol.Protocol; public class RestoreDefaultTypeCommand extends AbstractActionDelegate { @Override protected void run() { - TCFNode node = getCastToTypeNode(); + final TCFNode node = getCastToTypeNode(); if (node == null) return; - node.getModel().setCastToType(node.getID(), null); + Protocol.invokeLater(new Runnable() { + public void run() { + node.getModel().setCastToType(node.getID(), null); + } + }); } @Override diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java index 4a6face7f..4b840b82d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SignalsDialog.java @@ -246,7 +246,7 @@ class SignalsDialog extends Dialog { new TCFTask<Boolean>() { public void run() { - signal_list.reset(null); + signal_list.dispose(); done(Boolean.TRUE); } }.getE(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java index f2194f6c1..0b37d9bcd 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFPathMapTab.java @@ -11,8 +11,10 @@ package org.eclipse.tm.internal.tcf.debug.ui.launch; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; @@ -219,6 +221,12 @@ public class TCFPathMapTab extends AbstractLaunchConfigurationTab { }); } + List<IPathMap.PathMapRule> getPathMap() { + List<IPathMap.PathMapRule> l = new ArrayList<IPathMap.PathMapRule>(); + for (PathMapRule r : map) l.add(r); + return Collections.unmodifiableList(l); + } + public void initializeFrom(ILaunchConfiguration config) { setErrorMessage(null); setMessage(null); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java index 59886fc00..5f4e4c54d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFTargetTab.java @@ -13,12 +13,14 @@ package org.eclipse.tm.internal.tcf.debug.ui.launch; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; @@ -59,6 +61,7 @@ import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; import org.eclipse.tm.tcf.services.ILocator; +import org.eclipse.tm.tcf.services.IPathMap.PathMapRule; /** @@ -602,7 +605,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { } else if (parent == peer_info) { peer_info.locator = Protocol.getLocator(); - createLocatorListener(peer_info); + doneLoadChildren(parent, null, createLocatorListener(peer_info)); } else { final IChannel channel = parent.peer.openChannel(); @@ -615,9 +618,21 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { public void onChannelClosed(final Throwable error) { assert !closed; if (parent.channel != channel) return; - if (parent.children_error == null) { + if (!opened) { doneLoadChildren(parent, error, null); } + else { + if (display != null) { + display.asyncExec(new Runnable() { + public void run() { + if (parent.children_pending) return; + parent.children = null; + parent.children_error = error; + updateItems(parent); + } + }); + } + } closed = true; parent.channel = null; parent.locator = null; @@ -634,7 +649,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { parent.channel.close(); } else { - createLocatorListener(parent); + doneLoadChildren(parent, null, createLocatorListener(parent)); } } }); @@ -643,7 +658,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { }); } - private void createLocatorListener(PeerInfo peer) { + private PeerInfo[] createLocatorListener(PeerInfo peer) { assert Protocol.isDispatchThread(); Map<String,IPeer> map = peer.locator.getPeers(); PeerInfo[] buf = new PeerInfo[map.size()]; @@ -659,7 +674,7 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { } peer.listener = new LocatorListener(peer); peer.locator.addListener(peer.listener); - doneLoadChildren(peer, null, buf); + return buf; } private void doneLoadChildren(final PeerInfo parent, final Throwable error, final PeerInfo[] children) { @@ -917,7 +932,11 @@ public class TCFTargetTab extends AbstractLaunchConfigurationTab { Protocol.invokeLater(new Runnable() { public void run() { try { - test[0] = new TCFTestSuite(info.peer, done); + List<PathMapRule> map = null; + for (ILaunchConfigurationTab t : getLaunchConfigurationDialog().getTabs()) { + if (t instanceof TCFPathMapTab) map = ((TCFPathMapTab)t).getPathMap(); + } + test[0] = new TCFTestSuite(info.peer, done, map); } catch (Throwable x) { ArrayList<Throwable> errors = new ArrayList<Throwable>(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java index 6b249c266..b3528c6e6 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildren.java @@ -27,7 +27,6 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { private final int pool_margin; private final Map<String,TCFNode> node_pool = new LinkedHashMap<String,TCFNode>(32, 0.75f, true); - private boolean disposed; private static final TCFNode[] EMPTY_NODE_ARRAY = new TCFNode[0]; @@ -46,15 +45,15 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { /** * Dispose the cache and all nodes in the nodes pool. */ - void dispose() { - assert !disposed; + @Override + public void dispose() { + assert !isDisposed(); if (!node_pool.isEmpty()) { TCFNode a[] = node_pool.values().toArray(new TCFNode[node_pool.size()]); for (int i = 0; i < a.length; i++) a[i].dispose(); assert node_pool.isEmpty(); } - disposed = true; - super.reset(null); + super.dispose(); } /** @@ -71,16 +70,8 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { } } - /** - * Check if the cache is disposed. - * @return true if disposed. - */ - boolean isDisposed() { - return disposed; - } - private void addToPool(Map<String,TCFNode> data) { - assert !disposed; + assert !isDisposed(); for (TCFNode n : data.values()) { assert data.get(n.id) == n; node_pool.put(n.id, n); @@ -105,7 +96,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { @Override public void set(IToken token, Throwable error, Map<String,TCFNode> data) { array = null; - if (disposed) { + if (isDisposed()) { // A command can return data after the cache element has been disposed. // Just ignore the data in such case. super.set(token, null, null); @@ -126,7 +117,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { */ @Override public void reset(Map<String,TCFNode> data) { - assert !disposed; + assert !isDisposed(); array = null; if (data != null) { super.reset(data); @@ -160,7 +151,7 @@ public abstract class TCFChildren extends TCFDataCache<Map<String,TCFNode>> { * @param n - a node. */ void add(TCFNode n) { - assert !disposed; + assert !isDisposed(); assert node_pool.get(n.id) == null; node_pool.put(n.id, n); if (isValid()) { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java index f5e00cf92..639a8abc6 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java @@ -90,7 +90,7 @@ public class TCFChildrenExecContext extends TCFChildren { } @Override - protected void dispose() { + public void dispose() { super.dispose(); mem_children.dispose(); run_children.dispose(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java index 67496ab4c..3c86e724a 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java @@ -57,7 +57,7 @@ public class TCFChildrenExpressions extends TCFChildren { } @Override - void dispose() { + public void dispose() { exp_manager.removeExpressionListener(listener); super.dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java index 3b3768dd5..4b36d9417 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java @@ -40,7 +40,7 @@ public class TCFChildrenSubExpressions extends TCFChildren { } void onCastToTypeChanged() { - reset(); + cancel(); TCFNode a[] = getNodes().toArray(new TCFNode[getNodes().size()]); for (int i = 0; i < a.length; i++) a[i].dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java index c61901322..24c2c6d34 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java @@ -138,8 +138,8 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { new TCFDebugTask<Boolean>() { public void run() { disposed = true; - expression_value.reset(null); - expression_type.reset(null); + expression_value.dispose(); + expression_type.dispose(); if (remote_expression.isValid() && remote_expression.getData() != null) { final IChannel channel = exec_ctx.getModel().getLaunch().getChannel(); if (channel.getState() == IChannel.STATE_OPEN) { 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 67b7b1930..70755ec66 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 @@ -40,6 +40,7 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru private final Map<TCFNode,TCFNode[]> node2children = new HashMap<TCFNode,TCFNode[]>(); private final Map<TCFNode,ModelDelta> node2delta = new HashMap<TCFNode,ModelDelta>(); + private int all_flags; private TCFNode selection; private boolean posted; private boolean disposed; @@ -157,16 +158,18 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru else { node2flags.put(node, flags); } + all_flags |= flags; post(); } } void setSelection(TCFNode node) { selection = node; - addDelta(node, IModelDelta.REVEAL); + post(); } void post() { + assert Protocol.isDispatchThread(); if (!posted) { Protocol.invokeLater(this); posted = true; @@ -223,7 +226,13 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru if (parent_flags_obj != null) parent_flags = parent_flags_obj; ModelDelta parent = makeDelta(root, node.parent, parent_flags); if (parent == null) return null; - delta = parent.addNode(node, getNodeIndex(node), flags, getNodeChildren(node).length); + int index = -1; + int children = 0; + if ((all_flags & ~(IModelDelta.STATE | IModelDelta.CONTENT)) != 0) { + index = getNodeIndex(node); + children = getNodeChildren(node).length; + } + delta = parent.addNode(node, index, flags, children); } node2delta.put(node, delta); } @@ -235,26 +244,40 @@ public class TCFModelProxy extends AbstractModelProxy implements IModelProxy, Ru posted = false; assert Protocol.isDispatchThread(); if (disposed) return; - if (node2flags.isEmpty()) return; + if (node2flags.isEmpty() && selection == null) return; pending_node = null; node2children.clear(); node2delta.clear(); ModelDelta root = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); for (TCFNode node : node2flags.keySet()) makeDelta(root, node, node2flags.get(node)); if (pending_node == null) { + all_flags = 0; node2flags.clear(); if (!node2delta.isEmpty()) { fireModelChanged(root); node2delta.clear(); } if (selection != null) { - root = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); - makeDelta(root, selection, IModelDelta.SELECT); - fireModelChanged(root); + all_flags = IModelDelta.REVEAL; + ModelDelta root1 = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); + makeDelta(root1, selection, IModelDelta.REVEAL); + node2delta.clear(); + all_flags = IModelDelta.SELECT; + ModelDelta root2 = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); + makeDelta(root2, selection, IModelDelta.SELECT); node2delta.clear(); - selection = null; + if (pending_node == null) { + fireModelChanged(root1); + fireModelChanged(root2); + selection = null; + } + all_flags = 0; } } + + if (pending_node == null) { + // OK + } else if (pending_node.getData(children_count_update, this)) { assert false; post(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java index adaf843ce..07e98d1dc 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeArrayPartition.java @@ -33,7 +33,6 @@ public class TCFNodeArrayPartition extends TCFNode { @Override void dispose() { - children.reset(null); children.dispose(); super.dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java index df5cb65e2..5b5fc27cd 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java @@ -45,7 +45,7 @@ public class TCFNodeExecContext extends TCFNode { private final TCFDataCache<IRunControl.RunControlContext> run_context; private final TCFDataCache<IProcesses.ProcessContext> prs_context; private final TCFDataCache<TCFContextState> state; - private final TCFDataCache<BigInteger> address; + private final TCFDataCache<BigInteger> address; // Current PC as BigInteger private final Map<BigInteger,TCFSourceRef> line_info_cache; @@ -166,11 +166,11 @@ public class TCFNodeExecContext extends TCFNode { @Override void dispose() { - run_context.reset(null); - prs_context.reset(null); - mem_context.reset(null); - state.reset(null); - address.reset(null); + run_context.dispose(); + prs_context.dispose(); + mem_context.dispose(); + state.dispose(); + address.dispose(); children_exec.dispose(); children_stack.dispose(); super.dispose(); @@ -359,6 +359,8 @@ public class TCFNodeExecContext extends TCFNode { void onContextChanged(IRunControl.RunControlContext context) { assert !disposed; run_context.reset(context); + state.reset(); + children_stack.reset(); children_stack.onSourceMappingChange(); addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); } @@ -466,8 +468,8 @@ public class TCFNodeExecContext extends TCFNode { addModelDelta(IModelDelta.CONTENT); } - // Return true if at least one child is suspended - // The method will fail if node is not validated, see validateChildrenState() + // Return true if at least one child is suspended. + // Return null if waiting for a cache element. private Boolean hasSuspendedChildren(Runnable done) { if (!children_exec.validate(done)) return null; Map<String,TCFNode> m = children_exec.getData(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java index d63cf0bb7..c83970c23 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java @@ -210,12 +210,22 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT e = new Expression(context); e.must_be_disposed = true; } - set(token, error, e); - if (isDisposed()) disposeExpression(); + if (!isDisposed()) set(token, error, e); + else if (e != null) e.dispose(); } }); return false; } + @Override + public void cancel() { + if (isValid() && getData() != null) getData().dispose(); + super.cancel(); + } + @Override + public void dispose() { + if (isValid() && getData() != null) getData().dispose(); + super.dispose(); + } }; value = new TCFDataCache<IExpressions.Value>(channel) { @Override @@ -380,108 +390,95 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT } }; type_name = new TCFDataCache<String>(channel) { - String name; - TCFDataCache<ISymbols.Symbol> type_cache; @Override protected boolean startDataRetrieval() { - if (name == null) type_cache = type; - if (!type_cache.validate(this)) return false; - String s = null; - boolean get_base_type = false; - ISymbols.Symbol t = type_cache.getData(); - if (t != null) { - s = t.getName(); - if (s != null && t.getTypeClass() == ISymbols.TypeClass.composite) { - s = "struct " + s; - } - if (s == null && t.getSize() == 0) s = "void"; - if (s == null) { - switch (t.getTypeClass()) { - case integer: - switch (t.getSize()) { - case 1: s = "char"; break; - case 2: s = "short"; break; - case 4: s = "int"; break; - case 8: s = "long long"; break; - default: s = "<Integer>"; break; - } - break; - case cardinal: - switch (t.getSize()) { - case 1: s = "unsigned char"; break; - case 2: s = "unsigned short"; break; - case 4: s = "unsigned"; break; - case 8: s = "unsigned long long"; break; - default: s = "<Unsigned>"; break; - } - break; - case real: - switch (t.getSize()) { - case 4: s = "float"; break; - case 8: s = "double"; break; - default: s = "<Float>"; break; + String name = null; + TCFDataCache<ISymbols.Symbol> type_cache = type; + for (;;) { + String s = null; + boolean get_base_type = false; + if (!type_cache.validate(this)) return false; + ISymbols.Symbol type_symbol = type_cache.getData(); + if (type_symbol != null) { + s = type_symbol.getName(); + if (s != null && type_symbol.getTypeClass() == ISymbols.TypeClass.composite) s = "struct " + s; + if (s == null && type_symbol.getSize() == 0) s = "void"; + if (s == null) { + switch (type_symbol.getTypeClass()) { + case integer: + switch (type_symbol.getSize()) { + case 1: s = "char"; break; + case 2: s = "short"; break; + case 4: s = "int"; break; + case 8: s = "long long"; break; + default: s = "<Integer>"; break; + } + break; + case cardinal: + switch (type_symbol.getSize()) { + case 1: s = "unsigned char"; break; + case 2: s = "unsigned short"; break; + case 4: s = "unsigned"; break; + case 8: s = "unsigned long long"; break; + default: s = "<Unsigned>"; break; + } + break; + case real: + switch (type_symbol.getSize()) { + case 4: s = "float"; break; + case 8: s = "double"; break; + default: s = "<Float>"; break; + } + break; + case pointer: + s = "*"; + get_base_type = true; + break; + case array: + s = "[]"; + get_base_type = true; + break; + case composite: + s = "<Structure>"; + break; + case function: + s = "<Function>"; + break; } - break; - case pointer: - s = "*"; - get_base_type = true; - break; - case array: - s = "[]"; - get_base_type = true; - break; - case composite: - s = "<Structure>"; - break; - case function: - s = "<Function>"; - break; } } - } - if (s == null) name = "N/A"; - else if (name == null) name = s; - else if (!get_base_type) name = s + " " + name; - else name = s + name; - if (get_base_type) { - type_cache = model.getSymbolInfoCache(t.getBaseTypeID()); - if (type_cache == null) { + if (s == null) { name = "N/A"; + break; } - else { - Protocol.invokeLater(this); - return false; + if (name == null) name = s; + else if (!get_base_type) name = s + " " + name; + else name = s + name; + + if (!get_base_type) break; + + type_cache = model.getSymbolInfoCache(type_symbol.getBaseTypeID()); + if (type_cache == null) { + name = "N/A"; + break; } } set(null, null, name); return true; } - @Override - public void reset() { - super.reset(); - name = null; - } }; children = new TCFChildrenSubExpressions(this, 0, 0, 0); } - private void disposeExpression() { - if (expression.isValid() && expression.getData() != null) { - expression.getData().dispose(); - } - expression.cancel(); - } - @Override void dispose() { - var_expression.reset(null); - value.reset(null); - type.reset(null); - type_name.reset(null); - string.reset(null); - children.reset(null); + var_expression.dispose(); + value.dispose(); + type.dispose(); + type_name.dispose(); + string.dispose(); children.dispose(); - disposeExpression(); + expression.dispose(); super.dispose(); } @@ -506,11 +503,11 @@ public class TCFNodeExpression extends TCFNode implements IElementEditor, ICastT public void onCastToTypeChanged() { - disposeExpression(); - value.reset(); - type.reset(); - type_name.reset(); - string.reset(); + expression.cancel(); + value.cancel(); + type.cancel(); + type_name.cancel(); + string.cancel(); children.onCastToTypeChanged(); addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java index 4f4ab22f6..9413e9934 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java @@ -82,8 +82,8 @@ public class TCFNodeRegister extends TCFNode implements IElementEditor { @Override public void dispose() { - context.reset(null); - value.reset(null); + context.dispose(); + value.dispose(); super.dispose(); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java index 9c685522b..6d219f875 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java @@ -176,15 +176,11 @@ public class TCFNodeStackFrame extends TCFNode { this.frame_no = frame_no; } - public TCFDataCache<TCFSourceRef> getLineInfo() { - return line_info; - } - @Override void dispose() { - stack_trace_context.reset(null); - line_info.reset(null); - address.reset(null); + stack_trace_context.dispose(); + line_info.dispose(); + address.dispose(); children_regs.dispose(); children_vars.dispose(); children_exps.dispose(); @@ -198,6 +194,10 @@ public class TCFNodeStackFrame extends TCFNode { children_exps.dispose(id); } + public TCFDataCache<TCFSourceRef> getLineInfo() { + return line_info; + } + public TCFDataCache<IStackTrace.StackTraceContext> getStackTraceContext() { return stack_trace_context; } @@ -224,19 +224,33 @@ public class TCFNodeStackFrame extends TCFNode { return super.getRelevantModelDeltaFlags(p); } + private TCFChildren getChildren(IPresentationContext ctx) { + String id = ctx.getId(); + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(id)) return children_regs; + if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(id)) return children_vars; + if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(id)) return children_exps; + return null; + } + @Override - protected boolean getData(IChildrenCountUpdate result, Runnable done) { - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - result.setChildCount(children_regs.size()); + protected boolean getData(IHasChildrenUpdate result, Runnable done) { + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + result.setHasChilren(c.size() > 0); } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - result.setChildCount(children_vars.size()); + else { + result.setHasChilren(false); } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - result.setChildCount(children_exps.size()); + return true; + } + + @Override + protected boolean getData(IChildrenCountUpdate result, Runnable done) { + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + result.setChildCount(c.size()); } else { result.setChildCount(0); @@ -247,20 +261,13 @@ public class TCFNodeStackFrame extends TCFNode { @Override protected boolean getData(IChildrenUpdate result, Runnable done) { TCFNode[] arr = null; - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - arr = children_regs.toArray(); - } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - arr = children_vars.toArray(); - } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - arr = children_exps.toArray(); + TCFChildren c = getChildren(result.getPresentationContext()); + if (c != null) { + if (!c.validate(done)) return false; + arr = c.toArray(); } else { - arr = new TCFNode[0]; + return true; } int offset = 0; int r_offset = result.getOffset(); @@ -275,28 +282,7 @@ public class TCFNodeStackFrame extends TCFNode { } @Override - protected boolean getData(IHasChildrenUpdate result, Runnable done) { - if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_regs.validate(done)) return false; - result.setHasChilren(children_regs.size() > 0); - } - else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_vars.validate(done)) return false; - result.setHasChilren(children_vars.size() > 0); - } - else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(result.getPresentationContext().getId())) { - if (!children_exps.validate(done)) return false; - result.setHasChilren(children_exps.size() > 0); - } - else { - result.setHasChilren(false); - } - return true; - } - - @Override protected boolean getData(ILabelUpdate result, Runnable done) { - String image_name = null; TCFChildrenStackTrace stack_trace_cache = ((TCFNodeExecContext)parent).getStackTrace(); if (!stack_trace_cache.validate(done)) return false; if (stack_trace_cache.getData().get(id) == null) { @@ -304,14 +290,21 @@ public class TCFNodeStackFrame extends TCFNode { } else { TCFDataCache<TCFContextState> state_cache = ((TCFNodeExecContext)parent).getState(); - if (!state_cache.validate(done)) return false; - TCFContextState state_data = state_cache.getData(); - if (state_data != null && state_data.is_suspended) image_name = ImageCache.IMG_STACK_FRAME_SUSPENDED; - else image_name = ImageCache.IMG_STACK_FRAME_RUNNING; - if (!stack_trace_context.validate(done)) return false; - if (!line_info.validate(done)) return false; - Throwable error = stack_trace_context.getError(); + TCFDataCache<?> pending = null; + if (!state_cache.validate()) pending = state_cache; + if (!stack_trace_context.validate()) pending = stack_trace_context; + if (!line_info.validate()) pending = line_info; + if (pending != null) { + pending.wait(done); + return false; + } + Throwable error = state_cache.getError(); + if (error == null) error = stack_trace_context.getError(); if (error == null) error = line_info.getError(); + TCFContextState state_data = state_cache.getData(); + String image_name = state_data != null && state_data.is_suspended ? + ImageCache.IMG_STACK_FRAME_SUSPENDED : + ImageCache.IMG_STACK_FRAME_RUNNING; if (error != null && state_data != null && state_data.is_suspended) { result.setForeground(new RGB(255, 0, 0), 0); result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0); @@ -329,8 +322,8 @@ public class TCFNodeStackFrame extends TCFNode { result.setLabel(label, 0); } } + result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0); } - result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0); return true; } @@ -352,9 +345,9 @@ public class TCFNodeStackFrame extends TCFNode { } void onSuspended() { - stack_trace_context.reset(); - line_info.reset(); - address.reset(); + stack_trace_context.cancel(); + line_info.cancel(); + address.cancel(); children_regs.onSuspended(); children_vars.onSuspended(); children_exps.onSuspended(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java index 58c4d7479..48fefb008 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/trace/TraceView.java @@ -11,18 +11,24 @@ package org.eclipse.tm.internal.tcf.debug.ui.trace; import java.io.UnsupportedEncodingException; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Text; import org.eclipse.tm.tcf.core.AbstractChannel; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.JSON; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.ui.part.ViewPart; @@ -93,10 +99,17 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener Page(AbstractChannel channel) { this.channel = channel; + update_thread.setName("TCF Trace View"); update_thread.start(); } public void dispose() { + if (closed) return; + Protocol.invokeAndWait(new Runnable() { + public void run() { + channel.removeTraceListener(Page.this); + } + }); synchronized (this) { closed = true; update_thread.interrupt(); @@ -116,7 +129,6 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener public synchronized void onChannelClosed(Throwable error) { if (error == null) { - channel.removeTraceListener(this); getSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { dispose(); @@ -148,15 +160,7 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener bf.append(name); } if (data != null) { - int i = 0; - while (i < data.length) { - int j = i; - while (j < data.length && data[j] != 0) j++; - bf.append(' '); - bf.append(new String(data, i, j - i, "UTF8")); - if (j < data.length && data[j] == 0) j++; - i = j; - } + appendData(bf, data); } bf.append('\n'); bf_line_cnt++; @@ -185,15 +189,7 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener bf.append(name); } if (data != null) { - int i = 0; - while (i < data.length) { - int j = i; - while (j < data.length && data[j] != 0) j++; - bf.append(' '); - bf.append(new String(data, i, j - i, "UTF8")); - if (j < data.length && data[j] == 0) j++; - i = j; - } + appendData(bf, data); } bf.append('\n'); bf_line_cnt++; @@ -228,7 +224,6 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener Protocol.invokeAndWait(new Runnable() { public void run() { Protocol.removeChannelOpenListener(TraceView.this); - for (Page p : pages) p.channel.removeTraceListener(p); } }); for (Page p : pages) p.dispose(); @@ -274,6 +269,81 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener }); } + private void appendData(StringBuffer bf, byte[] data) throws UnsupportedEncodingException { + int pos = bf.length(); + try { + Object[] o = JSON.parseSequence(data); + for (int i = 0; i < o.length; i++) { + bf.append(' '); + appendJSON(bf, o[i]); + } + } + catch (Throwable z) { + bf.setLength(pos); + for (int i = 0; i < data.length; i++) { + bf.append(' '); + int x = (data[i] >> 4) & 0xf; + int y = data[i] & 0xf; + bf.append((char)(x < 10 ? '0' + x : 'a' + x - 10)); + bf.append((char)(y < 10 ? '0' + y : 'a' + y - 10)); + } + } + } + + private void appendJSON(StringBuffer bf, Object o) { + if (o instanceof byte[]) { + int l = ((byte[])o).length; + bf.append('('); + bf.append(l); + bf.append(')'); + } + else if (o instanceof Collection) { + int cnt = 0; + bf.append('['); + for (Object i : (Collection<?>)o) { + if (cnt > 0) bf.append(','); + appendJSON(bf, i); + cnt++; + } + bf.append(']'); + } + else if (o instanceof Map) { + int cnt = 0; + bf.append('{'); + for (Object k : ((Map<?,?>)o).keySet()) { + if (cnt > 0) bf.append(','); + bf.append(k.toString()); + bf.append(':'); + appendJSON(bf, ((Map<?,?>)o).get(k)); + cnt++; + } + bf.append('}'); + } + else if (o instanceof String) { + bf.append('"'); + String s = (String)o; + int l = s.length(); + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + if (ch < ' ') { + bf.append('\\'); + bf.append('u'); + for (int j = 0; j < 4; j++) { + int x = (ch >> (4 * (3 - j))) & 0xf; + bf.append((char)(x < 10 ? '0' + x : 'a' + x - 10)); + } + } + else { + bf.append(ch); + } + } + bf.append('"'); + } + else { + bf.append(o); + } + } + private void showTabs() { boolean b = false; if (no_data != null) { @@ -283,6 +353,38 @@ public class TraceView extends ViewPart implements Protocol.ChannelOpenListener } if (tabs == null) { tabs = new TabFolder(parent, SWT.NONE); + Menu menu = new Menu(tabs); + MenuItem mi_close = new MenuItem(menu, SWT.NONE); + mi_close.setText("Close"); + mi_close.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + public void widgetSelected(SelectionEvent e) { + if (tabs == null) return; + TabItem[] s = tabs.getSelection(); + for (TabItem i : s) { + Page p = tab2page.get(i); + if (p != null) p.dispose(); + else i.dispose(); + } + } + }); + MenuItem mi_close_all = new MenuItem(menu, SWT.NONE); + mi_close_all.setText("Close All"); + mi_close_all.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + public void widgetSelected(SelectionEvent e) { + if (tabs == null) return; + TabItem[] s = tabs.getItems(); + for (TabItem i : s) { + Page p = tab2page.get(i); + if (p != null) p.dispose(); + else i.dispose(); + } + } + }); + tabs.setMenu(menu); b = true; } if (b) parent.layout(); |