| author | Pawel Piech | 2012-06-08 23:22:58 (EDT) |
|---|---|---|
| committer | Eugene Tarassov | 2012-06-11 20:05:48 (EDT) |
| commit | d4fce15928897a3cb0c9757ea5abf50a93c49051 (patch) (side-by-side diff) | |
| tree | 0de839247ccb3985f9513dc3268b145836e77cc6 | |
| parent | 10793bd1adb4c2e5f52df3d99515b153dce63bfb (diff) | |
| download | org.eclipse.tcf-d4fce15928897a3cb0c9757ea5abf50a93c49051.zip org.eclipse.tcf-d4fce15928897a3cb0c9757ea5abf50a93c49051.tar.gz org.eclipse.tcf-d4fce15928897a3cb0c9757ea5abf50a93c49051.tar.bz2 | |
Bug 381993 - [breakpoints] Add a detail pane in breakpoints view to show breakpoints' scope setting
Completed implementaiton.
11 files changed, 1023 insertions, 58 deletions
diff --git a/plugins/org.eclipse.tcf.cdt.ui/plugin.xml b/plugins/org.eclipse.tcf.cdt.ui/plugin.xml index ac6d4f5..cb2668b 100644 --- a/plugins/org.eclipse.tcf.cdt.ui/plugin.xml +++ b/plugins/org.eclipse.tcf.cdt.ui/plugin.xml @@ -451,5 +451,32 @@ </visibleWhen> </command> </menuContribution> + </extension> + <extension point="org.eclipse.debug.ui.detailPaneFactories"> + <detailFactories + class="org.eclipse.tcf.internal.cdt.ui.breakpoints.TCFBreakpointScopeDetailPaneFactory" + id="org.eclipse.tcf.debug.BreakpointScopeDetailPaneFactory"> + <enablement> + <and> + <with variable="selection"> + <iterate> + <or> + <instanceof value=" org.eclipse.cdt.debug.core.model.ICBreakpoint"/> + </or> + </iterate> + </with> + <with variable="debugContext"> + <iterate + ifEmpty="false"> + <or> + <instanceof value="org.eclipse.tcf.internal.debug.ui.model.TCFNode"/> + </or> + </iterate> + </with> + </and> + </enablement> + </detailFactories> + </extension> + </plugin> diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPane.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPane.java new file mode 100644 index 0000000..6f20109 --- a/dev/null +++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPane.java @@ -0,0 +1,443 @@ +/******************************************************************************* + * Copyright (c) 2008, 2012 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.tcf.internal.cdt.ui.breakpoints; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.internal.ui.SWTFactory; +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.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer; +import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy; +import org.eclipse.debug.ui.IDetailPane; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tcf.debug.ui.ITCFDebugUIConstants; +import org.eclipse.tcf.internal.cdt.ui.ImageCache; +import org.eclipse.tcf.internal.debug.model.ITCFConstants; +import org.eclipse.tcf.internal.debug.model.TCFLaunch; +import org.eclipse.tcf.internal.debug.ui.model.TCFContextQueryDescendants; +import org.eclipse.tcf.internal.debug.ui.model.TCFModel; +import org.eclipse.tcf.internal.debug.ui.model.TCFModelManager; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.ui.IWorkbenchPartSite; + +/** + * This detail pane uses a tree viewer to show which contexts a given breakpoint + * can potentially trigger. + */ +@SuppressWarnings("restriction") +public class TCFBreakpointScopeDetailPane implements IDetailPane { + + public static final String ID = "org.eclipse.tcf.debug.DetailPaneFactory"; + public static final String NAME = "TCF Detail Pane"; + public static final String DESC = "TCF Detail Pane"; + + private Composite fComposite; + private Label fFilterName; + private TreeModelViewer fTreeViewer; + + public static class ScopeDetailInputObject extends PlatformObject implements IElementContentProvider, IModelProxyFactory { + + private final ContextQueryElement fContextQueryElement; + + public ScopeDetailInputObject(ContextQueryElement query) { + fContextQueryElement = query; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ScopeDetailInputObject) { + return fContextQueryElement.equals( ((ScopeDetailInputObject)other).fContextQueryElement ); + } + return false; + } + + @Override + public int hashCode() { + return fContextQueryElement.hashCode(); + } + + public void update(IChildrenCountUpdate[] updates) { + for (IChildrenCountUpdate update : updates) { + update.setChildCount(1); + update.done(); + } + } + + public void update(IChildrenUpdate[] updates) { + for (IChildrenUpdate update : updates) { + if (update.getOffset() == 0) { + update.setChild(fContextQueryElement, 0); + update.done(); + } + } + } + + public void update(IHasChildrenUpdate[] updates) { + for (IHasChildrenUpdate update : updates) { + update.setHasChilren(true); + update.done(); + } + } + + public IModelProxy createModelProxy(Object element, IPresentationContext context) { + return new AbstractModelProxy() { + @Override + public void initialize(ITreeModelViewer viewer) { + super.initialize(viewer); + ModelDelta delta = new ModelDelta(this, IModelDelta.NO_CHANGE); + delta.addNode(fContextQueryElement, 0, IModelDelta.INSTALL); + fireModelChanged(delta); + } + }; + } + } + + public static class ContextQueryElement extends PlatformObject + implements IElementContentProvider, IElementLabelProvider, IModelProxyFactory + { + private final String fQuery; + private Set<String> fContexts; + + public ContextQueryElement(String query, Set<String> contexts) { + fQuery = query; + fContexts = contexts; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ContextQueryElement) { + ContextQueryElement element = (ContextQueryElement)other; + return ((fQuery == null && element.fQuery == null) || + (fQuery != null && fQuery.equals(element.fQuery))) && + ((fContexts == null && element.fContexts == null) || + (fContexts != null && fContexts.equals(element.fContexts))); + } + return false; + } + + @Override + public int hashCode() { + return (fQuery != null ? fQuery.hashCode() : 0) + (fContexts != null ? fContexts.hashCode() : 0); + } + + public void update(IChildrenCountUpdate[] updates) { + for (IViewerUpdate update : updates) { + getFilteredLaunches(update); + } + } + + public void update(IChildrenUpdate[] updates) { + for (IViewerUpdate update : updates) { + getFilteredLaunches(update); + } + } + + public void update(IHasChildrenUpdate[] updates) { + for (IViewerUpdate update : updates) { + getFilteredLaunches(update); + } + } + + public void update(ILabelUpdate[] updates) { + for (ILabelUpdate update : updates) { + getQueryFilteredContexts(update); + } + } + + private List<TCFLaunch> getTCFLaunches() { + List<TCFLaunch> tcfLaunches = new ArrayList<TCFLaunch>(); + for (ILaunch launch : DebugPlugin.getDefault().getLaunchManager().getLaunches()) { + if (launch instanceof TCFLaunch) { + tcfLaunches.add((TCFLaunch)launch); + } + } + return tcfLaunches; + } + + + private void getFilteredLaunches (final IViewerUpdate update) { + Protocol.invokeLater( new Runnable() { + public void run() { + final List<TCFLaunch> filteredLaunches = new ArrayList<TCFLaunch>(); + TCFModelManager modelManager = TCFModelManager.getModelManager(); + for (TCFLaunch launch : getTCFLaunches()) { + TCFModel model = modelManager.getModel(launch); + if (model != null && model.getRootNode() != null) { + TCFContextQueryDescendants query_descendants = model.getRootNode().getContextQueryDescendants(); + if (!query_descendants.setQuery(fQuery, launch.getModelContexts(fContexts), this)) return; + if (!query_descendants.validate(this)) return; + if (query_descendants.getData() != null && !query_descendants.getData().isEmpty()) { + filteredLaunches.add(launch); + } + } + } + + done(filteredLaunches, update); + } + }); + } + + private void getQueryFilteredContexts (final ILabelUpdate update) { + Protocol.invokeLater( new Runnable() { + public void run() { + TCFModelManager modelManager = TCFModelManager.getModelManager(); + Set<String> set = new TreeSet<String>(); + for (TCFLaunch launch : getTCFLaunches()) { + TCFModel model = modelManager.getModel(launch); + if (model != null && model.getRootNode() != null) { + TCFContextQueryDescendants query_descendants = model.getRootNode().getContextQueryDescendants(); + if (!query_descendants.setQuery(fQuery, launch.getModelContexts(fContexts), this)) return; + if (!query_descendants.validate(this)) return; + if (query_descendants.getData() != null) { + set.addAll(query_descendants.getData()); + } + } + } + + StringBuffer label = new StringBuffer(); + label.append("("); + label.append(set.size()); + label.append(") "); + + if (fQuery != null) { + label.append("Filter: "); + label.append(fQuery); + if (fContexts != null) { + label.append(", "); + } + } + if (fContexts != null) { + label.append("Contexts: "); + label.append(fContexts); + } + update.setLabel(label.toString(), 0); + update.setImageDescriptor(ImageCache.getImageDescriptor(ImageCache.IMG_BREAKPOINT_SCOPE), 0); + update.done(); + } + }); + } + + private void done(List<TCFLaunch> launches, IViewerUpdate update) { + if (update instanceof IHasChildrenUpdate) { + ((IHasChildrenUpdate)update).setHasChilren(!launches.isEmpty()); + } else if (update instanceof IChildrenCountUpdate) { + ((IChildrenCountUpdate)update).setChildCount(launches.size()); + } else if (update instanceof IChildrenUpdate) { + IChildrenUpdate childrenUpdate = (IChildrenUpdate)update; + int updateStart = childrenUpdate.getOffset(); + int updateEnd = childrenUpdate.getOffset() + childrenUpdate.getLength(); + for (int i = updateStart; i < updateEnd && i < launches.size(); i++) { + childrenUpdate.setChild(launches.get(i), i); + } + } + update.done(); + } + + public IModelProxy createModelProxy(Object element, IPresentationContext context) { + return new QueryInputObjectProxy(); + } + } + + public static class QueryInputObjectProxy extends AbstractModelProxy implements ILaunchesListener2 { + + private ILaunchManager fLaunchManager; + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.AbstractModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext) + */ + public synchronized void init(IPresentationContext context) { + super.init(context); + fLaunchManager = DebugPlugin.getDefault().getLaunchManager(); + fLaunchManager.addLaunchListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy#installed(org.eclipse.jface.viewers.Viewer) + */ + public void installed(Viewer viewer) { + // expand existing launches + ILaunch[] launches = fLaunchManager.getLaunches(); + if (launches.length > 0) { + launchesAdded(launches); + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.ui.viewers.AbstractModelProxy#dispose() + */ + public synchronized void dispose() { + super.dispose(); + if (fLaunchManager != null) { + fLaunchManager.removeLaunchListener(this); + fLaunchManager = null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener2#launchesTerminated(org.eclipse.debug.core.ILaunch[]) + */ + public void launchesTerminated(ILaunch[] launches) { + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(org.eclipse.debug.core.ILaunch[]) + */ + public void launchesRemoved(ILaunch[] launches) { + fireDelta(launches, IModelDelta.REMOVED); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(org.eclipse.debug.core.ILaunch[]) + */ + public void launchesAdded(ILaunch[] launches) { + fireDelta(launches, IModelDelta.ADDED | IModelDelta.INSTALL); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(org.eclipse.debug.core.ILaunch[]) + */ + public void launchesChanged(ILaunch[] launches) { + } + + /** + * Convenience method for firing a delta + * @param launches the launches to set in the delta + * @param launchFlags the flags for the delta + */ + protected void fireDelta(ILaunch[] launches, int launchFlags) { + ModelDelta delta = new ModelDelta(fLaunchManager, IModelDelta.NO_CHANGE); + for (int i = 0; i < launches.length; i++) { + if (launches[i] instanceof TCFLaunch) { + delta.addNode(launches[i], launchFlags); + } + } + fireModelChanged(delta); + } + +} + + public Control createControl(Composite parent) { + fComposite = SWTFactory.createComposite(parent, 1, 1, GridData.FILL_BOTH); + fFilterName = SWTFactory.createLabel(fComposite, "Scope", 1); + fTreeViewer = new TreeModelViewer(fComposite, SWT.VIRTUAL, new PresentationContext(ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW)); + Control control = fTreeViewer.getControl(); + GridData treeLayoutData = new GridData(GridData.FILL_BOTH); + treeLayoutData.horizontalIndent = 10; + control.setLayoutData(treeLayoutData); + GridData gd = new GridData(GridData.FILL_BOTH); + control.setLayoutData(gd); + + return fComposite; + } + + public void display(IStructuredSelection selection) { + if (fTreeViewer == null) return; + + TCFBreakpointScopeExtension extension = getTCFBreakpointScopeExtension((ICBreakpoint)selection.getFirstElement()); + if (extension != null) { + String filter = extension.getPropertiesFilter(); + if (filter != null && filter.trim().isEmpty()) { + filter = null; + } + String[] contexts = extension.getThreadFilters(); + + if (filter != null || contexts != null) { + fFilterName.setText("Scope"); + Set<String> contextsSet = contexts != null ? new TreeSet<String>(Arrays.asList(contexts)) : null; + fTreeViewer.setInput( new ScopeDetailInputObject( + new ContextQueryElement(filter, contextsSet)) ); + fTreeViewer.getPresentationContext().setProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY, filter); + fTreeViewer.getPresentationContext().setProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS, contextsSet); + fTreeViewer.refresh(); + return; + } + } + fFilterName.setText("No scope specified."); + fTreeViewer.setInput(null); + fTreeViewer.getPresentationContext().setProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY, null); + fTreeViewer.getPresentationContext().setProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS, null); + } + + private TCFBreakpointScopeExtension getTCFBreakpointScopeExtension(ICBreakpoint bp) { + if (bp == null) return null; + try { + return (TCFBreakpointScopeExtension) bp.getExtension( + ITCFConstants.ID_TCF_DEBUG_MODEL, TCFBreakpointScopeExtension.class); + } catch (CoreException e) {} + return null; + } + + public void dispose() { + if (fTreeViewer != null) { + fTreeViewer.getControl().dispose(); + fTreeViewer = null; + } + if (fFilterName != null) { + fFilterName.dispose(); + fFilterName = null; + } + if (fComposite != null) { + fComposite.dispose(); + fComposite = null; + } + } + + public String getDescription() { + return DESC; + } + + public String getID() { + return ID; + } + + public String getName() { + return NAME; + } + + public void init(IWorkbenchPartSite part_site) { + } + + public boolean setFocus() { + if (fTreeViewer == null) return false; + fTreeViewer.getControl().setFocus(); + return true; + } +} diff --git a/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPaneFactory.java b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPaneFactory.java new file mode 100644 index 0000000..6605871 --- a/dev/null +++ b/plugins/org.eclipse.tcf.cdt.ui/src/org/eclipse/tcf/internal/cdt/ui/breakpoints/TCFBreakpointScopeDetailPaneFactory.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2008, 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.tcf.internal.cdt.ui.breakpoints; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.debug.ui.IDetailPane; +import org.eclipse.debug.ui.IDetailPaneFactory; +import org.eclipse.jface.viewers.IStructuredSelection; + +/** + * + */ +public class TCFBreakpointScopeDetailPaneFactory implements IDetailPaneFactory { + + public IDetailPane createDetailPane(String paneID) { + assert paneID.equals(TCFBreakpointScopeDetailPane.ID); + return new TCFBreakpointScopeDetailPane(); + } + + public String getDefaultDetailPane(IStructuredSelection selection) { + return TCFBreakpointScopeDetailPane.ID; + } + + public String getDetailPaneDescription(String paneID) { + return TCFBreakpointScopeDetailPane.NAME; + } + + public String getDetailPaneName(String paneID) { + return TCFBreakpointScopeDetailPane.DESC; + } + + @SuppressWarnings("rawtypes") + public Set getDetailPaneTypes(IStructuredSelection selection) { + HashSet<String> set = new HashSet<String>(); + set.add(TCFBreakpointScopeDetailPane.ID); + return set; + } +} diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/adapters/TCFLaunchLabelProvider.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/adapters/TCFLaunchLabelProvider.java index 047bfc5..4a28eab 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/adapters/TCFLaunchLabelProvider.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/adapters/TCFLaunchLabelProvider.java @@ -12,6 +12,7 @@ package org.eclipse.tcf.internal.debug.ui.adapters; import java.util.Collection; import java.util.Map; +import java.util.Set; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; @@ -19,63 +20,125 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.RGB; +import org.eclipse.tcf.debug.ui.ITCFDebugUIConstants; import org.eclipse.tcf.internal.debug.model.TCFLaunch; import org.eclipse.tcf.internal.debug.ui.ImageCache; +import org.eclipse.tcf.internal.debug.ui.model.TCFContextQueryDescendants; import org.eclipse.tcf.internal.debug.ui.model.TCFModel; +import org.eclipse.tcf.internal.debug.ui.model.TCFModelManager; +import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.services.IProcesses; class TCFLaunchLabelProvider implements IElementLabelProvider { public void update(ILabelUpdate[] updates) { for (int i = 0; i < updates.length; i++) { - ILabelUpdate result = updates[i]; - final TCFLaunch launch = (TCFLaunch)result.getElement(); - ImageDescriptor image = DebugUITools.getDefaultImageDescriptor(launch); - if (image == null) image = ImageCache.getImageDescriptor(ImageCache.IMG_TCF); - result.setImageDescriptor(image, 0); - String status = ""; - if (launch.isConnecting()) { - status = "Connecting"; + String view_id = updates[i].getPresentationContext().getId(); + if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) { + updateContextQueryViewLabel(updates[i]); + } else { + updateDebugViewLabel(updates[i]); } - else if (launch.isDisconnected()) { - status = "Disconnected"; - } - String peer_name = launch.getPeerName(); - if (peer_name != null) { - if (status.length() == 0) status = peer_name; - else status = peer_name + ": " + status; - } - if (status.length() > 0) status = " (" + status + ")"; - Throwable error = launch.getError(); - if (error != null) { - status += ": " + TCFModel.getErrorMessage(error, false); - result.setForeground(new RGB(255, 0, 0), 0); + } + } + + private void updateDebugViewLabel(ILabelUpdate result) { + final TCFLaunch launch = (TCFLaunch)result.getElement(); + ImageDescriptor image = DebugUITools.getDefaultImageDescriptor(launch); + if (image == null) image = ImageCache.getImageDescriptor(ImageCache.IMG_TCF); + result.setImageDescriptor(image, 0); + String status = ""; + if (launch.isConnecting()) { + status = "Connecting"; + } + else if (launch.isDisconnected()) { + status = "Disconnected"; + } + String peer_name = launch.getPeerName(); + if (peer_name != null) { + if (status.length() == 0) status = peer_name; + else status = peer_name + ": " + status; + } + if (status.length() > 0) status = " (" + status + ")"; + Throwable error = launch.getError(); + if (error != null) { + status += ": " + TCFModel.getErrorMessage(error, false); + result.setForeground(new RGB(255, 0, 0), 0); + } + else if (launch.isExited()) { + status += ": All exited or detached"; + int code = launch.getExitCode(); + if (code > 0) status += ", exit code " + code; + if (code < 0) { + status += ", signal " + (-code); + Collection<Map<String,Object>> sigs = launch.getSignalList(); + if (sigs != null) { + for (Map<String,Object> m : sigs) { + Number num = (Number)m.get(IProcesses.SIG_CODE); + if (num == null) continue; + if (num.intValue() != -code) continue; + String s = (String)m.get(IProcesses.SIG_NAME); + if (s == null) continue; + status += " (" + s + ")"; + break; + } + } } - else if (launch.isExited()) { - status += ": All exited or detached"; - int code = launch.getExitCode(); - if (code > 0) status += ", exit code " + code; - if (code < 0) { - status += ", signal " + (-code); - Collection<Map<String,Object>> sigs = launch.getSignalList(); - if (sigs != null) { - for (Map<String,Object> m : sigs) { - Number num = (Number)m.get(IProcesses.SIG_CODE); - if (num == null) continue; - if (num.intValue() != -code) continue; - String s = (String)m.get(IProcesses.SIG_NAME); - if (s == null) continue; - status += " (" + s + ")"; - break; + } + String name = "?"; + ILaunchConfiguration cfg = launch.getLaunchConfiguration(); + if (cfg != null) name = cfg.getName(); + result.setLabel(name + status, 0); + result.done(); + } + + private void updateContextQueryViewLabel(final ILabelUpdate result) { + Protocol.invokeLater(new Runnable() { + public void run() { + TCFLaunch launch = (TCFLaunch)result.getElement(); + ImageDescriptor image = DebugUITools.getDefaultImageDescriptor(launch); + if (image == null) image = ImageCache.getImageDescriptor(ImageCache.IMG_TCF); + result.setImageDescriptor(image, 0); + + StringBuffer label = new StringBuffer(); + TCFModel model = TCFModelManager.getModelManager().getModel(launch); + + if (model != null && model.getRootNode() != null) { + String query = (String)result.getPresentationContext().getProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY); + @SuppressWarnings("unchecked") + Set<String> contexts = (Set<String>)result.getPresentationContext().getProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS); + TCFContextQueryDescendants query_descendents = model.getRootNode().getContextQueryDescendants(); + if (!query_descendents.setQuery(query, model.getLaunch().getModelContexts(contexts), this)) return; + if (!query_descendents.validate(this)) return; + if (query_descendents.getError() == null) { + Set<String> descendants = query_descendents.getData(); + if (descendants != null && !descendants.isEmpty()) { + label.append("("); + label.append(descendants.size()); + label.append(") "); } } + } + + ILaunchConfiguration cfg = launch.getLaunchConfiguration(); + if (cfg != null) { + label.append( cfg.getName() ); + } else { + label.append("?"); } + + String peer_name = launch.getPeerName(); + if (peer_name != null) { + label.append(" ("); + label.append(peer_name); + label.append(")"); + } + + result.setLabel(label.toString(), 0); + result.done(); } - String name = "?"; - ILaunchConfiguration cfg = launch.getLaunchConfiguration(); - if (cfg != null) name = cfg.getName(); - result.setLabel(name + status, 0); - result.done(); - } + }); + } + } diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFChildrenContextQuery.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFChildrenContextQuery.java index 4e3a65e..506266f 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFChildrenContextQuery.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFChildrenContextQuery.java @@ -66,8 +66,8 @@ public class TCFChildrenContextQuery extends TCFChildren { if (isValid()) return true; // error creating a node TCFNode n = model.getNode(id); while (n != null) { - if (n.parent == node) { - set.add(id); + if (n.parent == node || (n.parent == null && !(node instanceof TCFNodeExecContext))) { + set.add(n.getID()); break; } n = n.parent; diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFContextQueryDescendants.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFContextQueryDescendants.java new file mode 100644 index 0000000..6a28389 --- a/dev/null +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFContextQueryDescendants.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2012 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.tcf.internal.debug.ui.model; + +import java.util.Arrays; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.tcf.util.TCFDataCache; + +/** + * Cache item that contains children of the node. + * The list of children is filtered according to the context query and context filter. + * An element in the list either matches both query and filter, + * or it is an ancestor of a matching node. + */ +public class TCFContextQueryDescendants extends TCFDataCache<Set<String>> { + + private final TCFNode node; + + private String[] query_data; + private Set<String> filter; + + TCFContextQueryDescendants(TCFNode node) { + super(node.getChannel()); + this.node = node; + } + + public boolean setQuery(String query, Set<String> filter, Runnable done) { + String[] query_data = null; + TCFDataCache<String[]> query_cache = node.getModel().getLaunch().getContextQuery(query); + if (query_cache != null) { + if (!query_cache.validate(done)) return false; + query_data = query_cache.getData(); + } + if (!Arrays.equals(query_data, this.query_data)) reset(); + this.query_data = query_data; + if (this.filter == filter) return true; + if (filter != null && filter.equals(this.filter)) return true; + this.filter = filter; + reset(); + return true; + } + + private boolean getDescendants(Set<String> descendants, String[] ids) { + TCFModel model = node.getModel(); + for (String id : ids) { + if (!model.createNode(id, this)) return false; + if (isValid()) return true; // error creating a node + TCFNode n = model.getNode(id); + while (n != null) { + if ( n.parent == node || (n.parent == null && !(node instanceof TCFNodeExecContext)) ) { + descendants.add(id); + break; + } + n = n.parent; + } + } + return true; + } + + + @Override + protected boolean startDataRetrieval() { + Set<String> set = new TreeSet<String>(); + if (query_data != null && !getDescendants(set, query_data)) return false; + if (isValid()) return true; // error creating a node + if (filter != null) { + Set<String> filtered = new TreeSet<String>(); + if (!getDescendants(filtered, filter.toArray(new String[filter.size()]))) return false; + set.retainAll(filtered); + } + if (isValid()) return true; // error creating a node + set(null, null, set); + return true; + } +} diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java index 4fc7d41..7afef67 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java @@ -11,6 +11,7 @@ package org.eclipse.tcf.internal.debug.ui.model; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -18,6 +19,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugPlugin; @@ -84,6 +87,8 @@ import org.eclipse.swt.graphics.Device; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; +import org.eclipse.tcf.core.Command; +import org.eclipse.tcf.debug.ui.ITCFSourceDisplay; import org.eclipse.tcf.internal.debug.actions.TCFAction; import org.eclipse.tcf.internal.debug.launch.TCFSourceLookupDirector; import org.eclipse.tcf.internal.debug.launch.TCFSourceLookupParticipant; @@ -106,13 +111,12 @@ import org.eclipse.tcf.internal.debug.ui.commands.StepReturnCommand; import org.eclipse.tcf.internal.debug.ui.commands.SuspendCommand; import org.eclipse.tcf.internal.debug.ui.commands.TerminateCommand; import org.eclipse.tcf.internal.debug.ui.preferences.TCFPreferences; -import org.eclipse.tcf.core.Command; -import org.eclipse.tcf.debug.ui.ITCFSourceDisplay; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IErrorReport; import org.eclipse.tcf.protocol.IService; import org.eclipse.tcf.protocol.IToken; import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.services.IContextQuery; import org.eclipse.tcf.services.IDisassembly; import org.eclipse.tcf.services.ILineNumbers; import org.eclipse.tcf.services.IMemory; @@ -304,7 +308,6 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, new HashMap<ILaunchConfiguration,IEditorInput>(); private final IModelSelectionPolicyFactory model_selection_factory = new IModelSelectionPolicyFactory() { - public IModelSelectionPolicy createModelSelectionPolicyAdapter( Object element, IPresentationContext context) { return selection_policy; @@ -317,6 +320,34 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, private TCFNodeLaunch launch_node; private boolean disposed; + private Map<String, TCFDataCache<Set<String>>> context_queries = new TreeMap<String, TCFDataCache<Set<String>>>(); + + public TCFDataCache<Set<String>> getContextQuery(final String query) { + TCFDataCache<Set<String>> data = context_queries.get(query); + if (data == null) { + data = new TCFDataCache<Set<String>>(channel) { + @Override + protected boolean startDataRetrieval() { + assert command == null; + IContextQuery service = channel.getRemoteService(IContextQuery.class); + if (service == null) { + set(null, null, null); + return true; + } + + command = service.query(query, new IContextQuery.DoneQuery() { + public void doneQuery (IToken token, Exception error, String[] contexts) { + set( token, error, new TreeSet<String>(Arrays.asList(contexts)) ); + } + }); + return false; + } + }; + context_queries.put(query, data); + } + return data; + } + private final IMemory.MemoryListener mem_listener = new IMemory.MemoryListener() { public void contextAdded(IMemory.MemoryContext[] contexts) { @@ -402,6 +433,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, } public void contextAdded(IRunControl.RunControlContext[] contexts) { + onContextAdded(); for (IRunControl.RunControlContext ctx : contexts) { String id = ctx.getParentID(); if (id == null) { @@ -891,6 +923,13 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, model_proxies.remove(ctx); } + private void onContextAdded() { + for (TCFDataCache<?> query : context_queries.values()) { + query.reset(); + } + context_queries.clear(); + } + private void onContextRemoved(String[] context_ids) { for (String id : context_ids) { TCFNode node = getNode(id); @@ -904,6 +943,17 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, expanded_nodes.remove(id); if (mem_blocks_update != null) mem_blocks_update.changeset.remove(id); } + + List<String> context_ids_list = Arrays.asList(context_ids); + for (TCFDataCache<Set<String>> query : context_queries.values()) { + if (query.isValid() && query.getError() == null) { + Set<String> query_contexts = query.getData(); + query_contexts.removeAll(context_ids_list); + query.reset(query_contexts); + } + } + context_queries.clear(); + launch_node.onAnyContextAddedOrRemoved(); // Close debug session if the last context is removed: onContextOrProcessRemoved(); diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java index 257d134..bc3b6c3 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java @@ -12,6 +12,7 @@ package org.eclipse.tcf.internal.debug.ui.model; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -52,6 +53,7 @@ import org.eclipse.ui.IWorkbenchPart; public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { private final TCFChildrenExecContext children_exec; + private final TCFContextQueryDescendants query_descendants; private final TCFChildrenStackTrace children_stack; private final TCFChildrenRegisters children_regs; private final TCFChildrenExpressions children_exps; @@ -240,6 +242,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { children_log_exps = new TCFChildrenLogExpressions(this); children_modules = new TCFChildrenModules(this); children_query = new TCFChildrenContextQuery(this, children_exec); + query_descendants = new TCFContextQueryDescendants(this); mem_context = new TCFData<IMemory.MemoryContext>(channel) { @Override protected boolean startDataRetrieval() { @@ -782,6 +785,44 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { public TCFChildren getChildren() { return children_exec; } + +// public TCFQueryChildrenExecContext getQueryChildren(String query, Set<String> contexts) { +// class QueryChildrenKey { +// private final String fQuery; +// private Set<String> fContexts; +// +// QueryChildrenKey(String query, Set<String> contexts) { +// fQuery = query; +// fContexts = contexts; +// } +// +// @Override +// public boolean equals(Object other) { +// if (other instanceof QueryChildrenKey) { +// QueryChildrenKey element = (QueryChildrenKey)other; +// return ((fQuery == null && element.fQuery == null) || +// (fQuery != null && fQuery.equals(element.fQuery))) && +// ((fContexts == null && element.fContexts == null) || +// (fContexts != null && fContexts.equals(element.fContexts))); +// } +// return false; +// } +// +// @Override +// public int hashCode() { +// return (fQuery != null ? fQuery.hashCode() : 0) + (fContexts != null ? fContexts.hashCode() : 0); +// } +// +// } +// +// QueryChildrenKey key = new QueryChildrenKey(query, contexts); +// TCFQueryChildrenExecContext children = query_children_exec_map.get(key); +// if (children ==null) { +// children = new TCFQueryChildrenExecContext(this, children_exec, query, contexts); +// query_children_exec_map.put(key, children); +// } +// return children; +// } public TCFNodeStackFrame getLastTopFrame() { if (!resume_pending) return null; @@ -842,7 +883,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { IPresentationContext context = result.getPresentationContext(); String query = (String)context.getProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY); Set<String> filter = (Set<String>)context.getProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS); - return children_query.setQuery(query, filter, done); + return children_query.setQuery(query, model.getLaunch().getModelContexts(filter), done); } @Override @@ -1053,7 +1094,14 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { @Override protected boolean getData(ILabelUpdate result, Runnable done) { - result.getViewerInput(); + if ( ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(result.getPresentationContext().getId()) ) { + return getContextQueryViewData(result, done); + } else { + return getDebugViewData(result, done); + } + } + + private boolean getDebugViewData(ILabelUpdate result, Runnable done) { if (!run_context.validate(done)) return false; String image_name = null; boolean suspended_by_bp = false; @@ -1093,7 +1141,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { if (state_data.isReversing()) { image_name = ImageCache.IMG_THREAD_REVERSING; label.append(" (Reversing)"); - } + } else { image_name = ImageCache.IMG_THREAD_RUNNNIG; label.append(" (Running)"); @@ -1187,6 +1235,74 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { return true; } + private boolean getContextQueryViewData(ILabelUpdate result, Runnable done) { + if (!run_context.validate(done)) return false; + String image_name = null; + StringBuffer label = new StringBuffer(); + Throwable error = run_context.getError(); + if (error != null) { + result.setForeground(new RGB(255, 0, 0), 0); + label.append(id); + label.append(": "); + label.append(TCFModel.getErrorMessage(error, false)); + } + else { + String query = (String)result.getPresentationContext().getProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY); + @SuppressWarnings("unchecked") + Set<String> contexts = (Set<String>)result.getPresentationContext().getProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS); + if (contexts != null) contexts = model.getLaunch().getModelContexts(contexts); + if (!query_descendants.setQuery(query, contexts, done)) return false; + if (!query_descendants.validate(done)) return false; + if (query_descendants.getError() == null) { + Set<String> descendants = query_descendants.getData(); + if (descendants != null && !descendants.isEmpty()) { + label.append("("); + label.append(descendants.size()); + label.append(") "); + } + } + + TCFDataCache<String[]> query_data = model.getLaunch().getContextQuery(query); + if (!query_data.validate(done)) return false; + if ( (query_data.getData() != null && !Arrays.asList(query_data.getData()).contains(getID())) || + (contexts != null && !contexts.contains(getID())) ) + { + result.setForeground(new RGB(128, 128, 128), 0); + } + + IRunControl.RunControlContext ctx = run_context.getData(); + if (ctx == null) { + label.append(id); + } + else { + String nm = ctx.getName(); + if (nm == null && !ctx.hasState()) { + String prs = ctx.getProcessID(); + if (prs != null) { + if (!prs_context.validate(done)) return false; + IProcesses.ProcessContext pctx = prs_context.getData(); + if (pctx != null) nm = pctx.getName(); + } + } + label.append(nm != null ? nm : id); + Object info = ctx.getProperties().get("AdditionalInfo"); + if (info != null) label.append(info.toString()); + if (ctx.hasState()) { + image_name = ImageCache.IMG_THREAD_UNKNOWN_STATE; + } + else { + // Thread container (process) + image_name = ImageCache.IMG_PROCESS_RUNNING; + + } + } + } + + result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0); + result.setLabel(label.toString(), 0); + return true; + } + @Override protected boolean getData(IViewerInputUpdate result, Runnable done) { result.setInputElement(this); @@ -1244,9 +1360,12 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { } } for (TCFModelProxy p : model.getModelProxies()) { - if (IDebugUIConstants.ID_DEBUG_VIEW.equals(p.getPresentationContext().getId())) { + String view_id = p.getPresentationContext().getId(); + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) { /* Note: should use IModelDelta.INSERTED but it is broken in Eclipse 3.6 */ p.addDelta(this, IModelDelta.ADDED); + } else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) { + p.addDelta(parent, IModelDelta.CONTENT); } } } @@ -1268,8 +1387,11 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { } } for (TCFModelProxy p : model.getModelProxies()) { - if (IDebugUIConstants.ID_DEBUG_VIEW.equals(p.getPresentationContext().getId())) { + String view_id = p.getPresentationContext().getId(); + if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) { p.addDelta(this, IModelDelta.REMOVED); + } else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) { + p.addDelta(parent, IModelDelta.CONTENT); } } } @@ -1279,9 +1401,10 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { for (TCFModelProxy p : model.getModelProxies()) { int flags = 0; String view_id = p.getPresentationContext().getId(); - if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id) && - (launch.getContextActionsCount(id) == 0 || - !model.getDelayStackUpdateUtilLastStep())) { + if ( (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id) || + ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) && + (launch.getContextActionsCount(id) == 0 || !model.getDelayStackUpdateUtilLastStep())) + { flags |= IModelDelta.CONTENT; } if (IDebugUIConstants.ID_REGISTER_VIEW.equals(view_id) || @@ -1331,6 +1454,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { void onContextAdded(IRunControl.RunControlContext context) { children_exec.onContextAdded(context); + children_query.reset(); } void onContextChanged(IRunControl.RunControlContext context) { @@ -1348,6 +1472,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { children_stack.onSourceMappingChange(); children_regs.reset(); children_exec.onAncestorContextChanged(); + children_query.reset(); for (TCFNodeSymbol s : symbols.values()) s.onMemoryMapChanged(); postAllChangedDelta(); } @@ -1376,6 +1501,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner { dispose(); postContextRemovedDelta(); launch.removeContextActions(id); + children_query.reset(); } void onExpressionAddedOrRemoved() { diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeLaunch.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeLaunch.java index 66448f6..1f7da09 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeLaunch.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeLaunch.java @@ -29,13 +29,16 @@ import org.eclipse.tcf.services.IRunControl; public class TCFNodeLaunch extends TCFNode implements ISymbolOwner { private final TCFChildrenExecContext children; + private final TCFChildren filtered_children; private final TCFChildrenContextQuery children_query; + private final TCFContextQueryDescendants query_descendants_count; private final Map<String,TCFNodeSymbol> symbols = new HashMap<String,TCFNodeSymbol>(); TCFNodeLaunch(final TCFModel model) { super(model); children = new TCFChildrenExecContext(this); + query_descendants_count = new TCFContextQueryDescendants(this); filtered_children = new TCFChildren(this) { @Override protected boolean startDataRetrieval() { @@ -65,7 +68,7 @@ public class TCFNodeLaunch extends TCFNode implements ISymbolOwner { super.dispose(); } }; - children_query = new TCFChildrenContextQuery(this, filtered_children); + children_query = new TCFChildrenContextQuery(this, children); } @Override @@ -81,7 +84,8 @@ public class TCFNodeLaunch extends TCFNode implements ISymbolOwner { IPresentationContext context = result.getPresentationContext(); String query = (String)context.getProperty(ITCFDebugUIConstants.PROP_CONTEXT_QUERY); Set<String> filter = (Set<String>)context.getProperty(ITCFDebugUIConstants.PROP_FILTER_CONTEXTS); - return children_query.setQuery(query, filter, done); + return children_query.setQuery(query, model.getLaunch().getModelContexts(filter), done) && + children_query.validate(done); } @Override @@ -162,6 +166,8 @@ public class TCFNodeLaunch extends TCFNode implements ISymbolOwner { void onAnyContextAddedOrRemoved() { filtered_children.reset(); + children_query.reset(); + query_descendants_count.reset(); } public void addSymbol(TCFNodeSymbol s) { @@ -181,4 +187,9 @@ public class TCFNodeLaunch extends TCFNode implements ISymbolOwner { public TCFChildren getFilteredChildren() { return filtered_children; } + + public TCFContextQueryDescendants getContextQueryDescendants() { + return query_descendants_count; + } + } diff --git a/plugins/org.eclipse.tcf.debug/src/org/eclipse/tcf/internal/debug/model/TCFLaunch.java b/plugins/org.eclipse.tcf.debug/src/org/eclipse/tcf/internal/debug/model/TCFLaunch.java index 958c8fb..31e4e3a 100644 --- a/plugins/org.eclipse.tcf.debug/src/org/eclipse/tcf/internal/debug/model/TCFLaunch.java +++ b/plugins/org.eclipse.tcf.debug/src/org/eclipse/tcf/internal/debug/model/TCFLaunch.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; @@ -1229,6 +1230,27 @@ public class TCFLaunch extends Launch { return cache; } + public Set<String> getModelContexts(Set<String> contexts) { + if (contexts != null) { + ILaunchConfiguration launchConfig = getLaunchConfiguration(); + if (launchConfig != null) { + Set<String> modelContexts = new TreeSet<String>(); + String sessionId = launchConfig.getName(); + for (String context : contexts) { + int slashPos = context.indexOf('/'); + if (slashPos > 0 && context.length() > slashPos + 1) { + if ( sessionId.equals(context.substring(0, slashPos)) ) { + modelContexts.add(context.substring(slashPos + 1)); + } + } + } + return modelContexts; + } + } + return null; + } + + /** * Activate TCF launch: open communication channel and perform all necessary launch steps. * @param mode - on of launch mode constants defined in ILaunchManager. diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/BreakpointDetailPaneTest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/BreakpointDetailPaneTest.java new file mode 100644 index 0000000..b27dd96 --- a/dev/null +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/BreakpointDetailPaneTest.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2012 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.tcf.debug.test; + +import java.util.regex.Pattern; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem; +import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualTreeModelViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tcf.debug.ui.ITCFDebugUIConstants; +import org.eclipse.tcf.internal.cdt.ui.breakpoints.TCFBreakpointScopeDetailPane.ContextQueryElement; +import org.eclipse.tcf.internal.cdt.ui.breakpoints.TCFBreakpointScopeDetailPane.ScopeDetailInputObject; +import org.eclipse.tcf.internal.debug.ui.launch.TCFLaunchContext; +import org.junit.Assert; + +@SuppressWarnings("restriction") +public class BreakpointDetailPaneTest extends AbstractTcfUITest +{ + private BreakpointsListener fBpListener; + + protected VirtualTreeModelViewer fContextQueryViewViewer; + protected VirtualViewerUpdatesListener fContextQueryViewListener; + + + @Override + protected void setUp() throws Exception { + super.setUp(); + fBpListener = new BreakpointsListener(); + + // CDT Breakpoint integration depends on the TCF-CDT breakpoint + // integration to be active. This is normally triggered by selecting + // a stack frame in the UI. Here force activation of the plugin + // artificially. None of the cdt integration packages are exported, so + // use the TCF Launch Context extension point indirectly to force the + // plugin to load. + TCFLaunchContext.getLaunchContext(null); + + final Display display = Display.getDefault(); + display.syncExec(new Runnable() { + public void run() { + fContextQueryViewViewer = new VirtualTreeModelViewer( + display, SWT.NONE, new PresentationContext(ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW)); + fContextQueryViewListener = new VirtualViewerUpdatesListener(fContextQueryViewViewer); + } + }); + + } + + @Override + protected void tearDown() throws Exception { + final Display display = Display.getDefault(); + display.syncExec(new Runnable() { + public void run() { + fContextQueryViewListener.dispose(); + fContextQueryViewViewer.dispose(); + } + }); + fBpListener.dispose(); + super.tearDown(); + } + + public void testContextAddedOnLineBrakpointCreate() throws Exception { + initProcessModel("tcf_test_func0"); + + final String query = "pid="+fProcessId; + + fContextQueryViewListener.reset(); + Display.getDefault().syncExec(new Runnable() { public void run() { + fContextQueryViewViewer.setAutoExpandLevel(-1); + fContextQueryViewViewer.setInput(new ScopeDetailInputObject(new ContextQueryElement(query, null))); + }}); + fContextQueryViewListener.waitTillFinished(CONTENT_SEQUENCE_COMPLETE | LABEL_UPDATES_RUNNING); + + VirtualItem scopeItem = fContextQueryViewListener.findElement(new Pattern[] { Pattern.compile(".*pid\\="+fProcessId+"*.") }); + if (scopeItem == null) { + Assert.fail("Scope item not found. \n\nContext query view dump: \n:" + fContextQueryViewViewer.toString()); + } + + } + +} |

