diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
index 642aa5b1d3f..4a343bfaf70 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
@@ -8,6 +8,7 @@
# Contributors:
# Ericsson - initial API and implementation
# IBM Corporation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
pluginName=GDB DSF Debugger Integration UI
providerName=Eclipse CDT
@@ -41,3 +42,11 @@ command.nextTraceRecord.name=Next Trace Record
command.prevTraceRecord.name=Previous Trace Record
command.nextTraceRecord.description=Select Next Trace Record
command.prevTraceRecord.description=Select Previous Trace Record
+
+category.description = C/C++ debugging with the DSF GDB debugger
+category.name = CDT DSF-GDB - GDB Debugging
+activity.description = C/C++ debugging with the DSF GDB debugger
+activity.name = CDT DSF-GDB - GDB Debugging
+
+# Pretty Printing
+action.fetchMoreChildren.label=Fetch More Children
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
index b161b9d1d48..a71b10471e1 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
@@ -459,5 +459,17 @@
-
+
+
+
+
+
+
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java
new file mode 100644
index 00000000000..84842f340c6
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.FetchMoreChildrenEvent;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbExpressionVMProvider;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode.IncompleteChildrenVMC;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * @since 3.0
+ */
+public class FetchMoreChildrenAction extends AbstractVMProviderActionDelegate
+ implements IObjectActionDelegate {
+
+ private ISelection selection;
+
+ public void run(IAction action) {
+ IncompleteChildrenVMC incompleteChildrenVmc = getIncompleteChildrenVMC();
+
+ if (incompleteChildrenVmc != null) {
+ if (selection instanceof ITreeSelection) {
+ ITreeSelection treeSelection = (ITreeSelection) selection;
+ TreePath path = treeSelection.getPaths()[0];
+
+ IVMNode node = incompleteChildrenVmc.getVMNode();
+
+ IExpressionDMContext exprCtx = incompleteChildrenVmc.getParentDMContext();
+ ((GdbVariableVMNode) node).incrementChildCountLimit(exprCtx);
+ final FetchMoreChildrenEvent fetchMoreChildrenEvent = new FetchMoreChildrenEvent(exprCtx, path);
+ final AbstractVMProvider vmProvider = (AbstractVMProvider) getVMProvider();
+ vmProvider.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ vmProvider.handleEvent(fetchMoreChildrenEvent);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void init(IViewPart view) {
+ super.init(view);
+ updateEnablement();
+ }
+
+ @Override
+ public void debugContextChanged(DebugContextEvent event) {
+ super.debugContextChanged(event);
+ updateEnablement();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ this.selection = selection;
+ updateEnablement();
+ }
+
+ private void updateEnablement() {
+ boolean enabled = false;
+ if ((getVMProvider() instanceof GdbExpressionVMProvider)
+ || (getVMProvider() instanceof GdbVariableVMProvider)) {
+ enabled = (getIncompleteChildrenVMC() != null);
+ }
+ getAction().setEnabled(enabled);
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ if (targetPart instanceof IViewPart) {
+ init((IViewPart) targetPart);
+ }
+ }
+
+ private IncompleteChildrenVMC getIncompleteChildrenVMC() {
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss = (IStructuredSelection) selection;
+
+ if (ss.size() == 1) {
+ // Only single selection is supported.
+ Object selectedObject = ss.getFirstElement();
+ if (selectedObject instanceof IncompleteChildrenVMC) {
+ return (IncompleteChildrenVMC) selectedObject;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
index 792640f2593..97090690e8c 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -15,9 +16,13 @@ import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.IWorkbench;
@@ -29,6 +34,26 @@ import org.eclipse.ui.PlatformUI;
*/
public class GdbDebugPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+ /**
+ * A vehicle in order to be able to register a selection listener with
+ * a {@link BooleanFieldEditor}.
+ */
+ private class ListenableBooleanFieldEditor extends BooleanFieldEditor {
+
+ public ListenableBooleanFieldEditor(
+ String name,
+ String labelText,
+ int style,
+ Composite parent) {
+ super(name, labelText, style, parent);
+ }
+
+ @Override
+ public Button getChangeControl(Composite parent) {
+ return super.getChangeControl(parent);
+ }
+ }
+
public GdbDebugPreferencePage() {
super(FLAT);
IPreferenceStore store= GdbUIPlugin.getDefault().getPreferenceStore();
@@ -100,6 +125,55 @@ public class GdbDebugPreferencePage extends FieldEditorPreferencePage implements
// need to set layout again
group.setLayout(groupLayout);
+ group = new Group(parent, SWT.NONE);
+ group.setText(MessagesForPreferences.GdbDebugPreferencePage_prettyPrinting_label);
+ groupLayout = new GridLayout(3, false);
+ group.setLayout(groupLayout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ final ListenableBooleanFieldEditor enablePrettyPrintingField = new ListenableBooleanFieldEditor(
+ IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING,
+ MessagesForPreferences.GdbDebugPreferencePage_enablePrettyPrinting_label1 + "\n" //$NON-NLS-1$
+ + MessagesForPreferences.GdbDebugPreferencePage_enablePrettyPrinting_label2,
+ SWT.NONE, group);
+
+ enablePrettyPrintingField.fillIntoGrid(group, 3);
+ addField(enablePrettyPrintingField);
+
+ final Composite indentHelper = new Composite(group, SWT.NONE);
+ GridLayout helperLayout = new GridLayout(3, false);
+ indentHelper.setLayout(helperLayout);
+ GridData helperData = new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1);
+ helperData.horizontalIndent = 20;
+ indentHelper.setLayoutData(helperData);
+
+ final IntegerFieldEditor childCountLimitField = new IntegerFieldEditor(
+ IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ MessagesForPreferences.GdbDebugPreferencePage_initialChildCountLimitForCollections_label,
+ indentHelper);
+
+ childCountLimitField.setValidRange(1, 10000);
+ childCountLimitField.fillIntoGrid(indentHelper, 3);
+
+ IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+ boolean prettyPrintingEnabled = store
+ .getBoolean(IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING);
+ childCountLimitField.setEnabled(prettyPrintingEnabled, indentHelper);
+
+ addField(childCountLimitField);
+
+ enablePrettyPrintingField.getChangeControl(group).addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean enabled = enablePrettyPrintingField.getBooleanValue();
+ childCountLimitField.setEnabled(enabled, indentHelper);
+ }
+ });
+
+ // need to set layouts again
+ indentHelper.setLayout(helperLayout);
+ group.setLayout(groupLayout);
}
@Override
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
index ed11c079108..2efb43368b9 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -25,5 +26,7 @@ public class GdbPreferenceInitializer extends AbstractPreferenceInitializer {
store.setDefault(IGdbDebugPreferenceConstants.PREF_TRACES_ENABLE, true);
store.setDefault(IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, true);
store.setDefault(IGdbDebugPreferenceConstants.PREF_USE_INSPECTOR_HOVER, true);
+ store.setDefault(IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING, true);
+ store.setDefault(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS, 100);
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
index 74af3e2e94d..1687ac00a6a 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -23,6 +24,14 @@ class MessagesForPreferences extends NLS {
public static String GdbDebugPreferencePage_autoTerminateGdb_label;
public static String GdbDebugPreferencePage_hover_label;
public static String GdbDebugPreferencePage_useInspectorHover_label;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_prettyPrinting_label;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_enablePrettyPrinting_label1;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_enablePrettyPrinting_label2;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_initialChildCountLimitForCollections_label;
static {
// initialize resource bundle
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
index 5718c184ad5..b5995a08afa 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
@@ -7,6 +7,7 @@
#
# Contributors:
# Ericsson - initial API and implementation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
GdbDebugPreferencePage_description=General settings for GDB Debugging
@@ -19,3 +20,8 @@ GdbDebugPreferencePage_autoTerminateGdb_label=Terminate GDB when last process ex
GdbDebugPreferencePage_hover_label=Debug Text Hover
GdbDebugPreferencePage_useInspectorHover_label=Use enhanced debug hover
+
+GdbDebugPreferencePage_prettyPrinting_label=Pretty Printing
+GdbDebugPreferencePage_enablePrettyPrinting_label1=Enable pretty printers in variable/expression tree
+GdbDebugPreferencePage_enablePrettyPrinting_label2=(requires python-enabled GDB)
+GdbDebugPreferencePage_initialChildCountLimitForCollections_label=For collections, initially limit child count to
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java
new file mode 100644
index 00000000000..ac7617eeb21
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Event to fetch additional children for and expression context.
+ *
+ * @since 3.0
+ */
+public class FetchMoreChildrenEvent extends AbstractDMEvent {
+
+ private TreePath path;
+
+ public FetchMoreChildrenEvent(IExpressionDMContext exprCtx, TreePath path) {
+ super(exprCtx);
+ this.path = path;
+ }
+
+ public TreePath getPath() {
+ return path;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
index dbd2caf21ee..424438918f6 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
@@ -8,10 +8,14 @@
* Contributors:
* Freescale Semiconductor - initial API and implementation
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.DsfCastToTypeSupport;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.DisabledExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionManagerVMNode;
@@ -24,12 +28,23 @@ import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
+import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode.IncompleteChildrenVMC;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
/**
* A specialization of ExpressionVMProvider that uses a GDB-specific variable VM
@@ -38,12 +53,35 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
@SuppressWarnings("restriction")
public class GdbExpressionVMProvider extends ExpressionVMProvider {
+ private IPropertyChangeListener fPreferencesListener;
+
/**
* Constructor (passthru)
*/
public GdbExpressionVMProvider(AbstractVMAdapter adapter,
IPresentationContext context, DsfSession session) {
super(adapter, context, session);
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ }
+
+ fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ handlePropertyChanged(store, event);
+ }};
+ store.addPropertyChangeListener(fPreferencesListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+ store.removePropertyChangeListener(fPreferencesListener);
}
/**
@@ -126,4 +164,71 @@ public class GdbExpressionVMProvider extends ExpressionVMProvider {
*/
setRootNode(rootNode);
}
+
+ @Override
+ public void handleEvent(Object event, final RequestMonitor rm) {
+ if (event instanceof DoubleClickEvent && !isDisposed()) {
+
+ final ISelection selection= ((DoubleClickEvent) event).getSelection();
+ if (selection instanceof IStructuredSelection) {
+
+ Object element= ((IStructuredSelection) selection).getFirstElement();
+ if (element instanceof IncompleteChildrenVMC) {
+
+ IncompleteChildrenVMC incompleteChildrenVmc = ((IncompleteChildrenVMC) element);
+ IVMNode node = incompleteChildrenVmc.getVMNode();
+ if (node instanceof GdbVariableVMNode && node.getVMProvider() == this) {
+
+ if (selection instanceof ITreeSelection) {
+ ITreeSelection treeSelection = (ITreeSelection) selection;
+ TreePath path = treeSelection.getPaths()[0];
+
+ IExpressionDMContext exprCtx = incompleteChildrenVmc.getParentDMContext();
+ ((GdbVariableVMNode) node).incrementChildCountLimit(exprCtx);
+
+ // replace double click event with the fetch more children event.
+ final FetchMoreChildrenEvent fetchMoreChildrenEvent = new FetchMoreChildrenEvent(
+ exprCtx, path);
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(fetchMoreChildrenEvent, rm);
+ }
+ });
+
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ super.handleEvent(event, rm);
+ }
+
+ /**
+ * @param store
+ * @param event
+ *
+ * @since 3.0
+ */
+ protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property)) {
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ } else {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ null);
+ }
+
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(event);
+ }
+ });
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
index 45c9fa73075..934a304ac01 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
@@ -7,23 +7,48 @@
*
* Contributors:
* Freescale Semiconductor - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.eclipse.cdt.debug.internal.core.ICWatchpointTarget;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.mi.service.IMIExpressions;
import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.TreePath;
/**
* Specialization of DSF's VariableVMNode. See
@@ -31,6 +56,42 @@ import org.eclipse.core.runtime.Status;
*/
public class GdbVariableVMNode extends VariableVMNode {
+ // Notes on gdb's pretty printer support (bug 302121):
+ // If
+ // - an expression has children
+ // - and those children are provided by a pretty printer
+ // - and the expression is not yet initialized
+ // the expression might have a large number of children. Asking gdb to
+ // provide all children, or even just the number of all children, will
+ // lead to extremely slow response times.
+ // Furthermore, there are C/C++ data structures (e.g. linked lists) that
+ // can lead to endless loops if not correctly initialized and a pretty
+ // printer tries to obtain the number of children. In this case, gdb
+ // will never return.
+ //
+ // In order to address this problem, IMIExpressions deriving from
+ // IExpressions has been introduced.
+ // It lets the client specify a maximum number of children to be considered,
+ // both when asking the number of sub-expression, or the sub-expressions
+ // itself.
+ //
+ // The algorithm how it is used is as following:
+ // - We don't show all children in the UI, but only up to a certain limit.
+ // A special context type IncompleteChildrenVMC is used to show that
+ // there are more children than those currently visible.
+ // The user can fetch more children on demand.
+ // - updateHasElementsInSessionThread asks only for up to one child.
+ // - updateElementCountInSessionThread checks whether the expression
+ // requires a limit on the child count limit. If yes, it asks
+ // the expression service for up to limit + 1 children. The + 1
+ // represent the child for the <...more children...> node. I.e.,
+ // if the returned number of children is limit + 1, then there is
+ // an <...more_children...> node. Otherwise, there is not.
+ // - updateElementsInSessionThread sooner or later delegates to
+ // fillUpdateWithVMCs. fillUpdateWithVMCs checks whether there are
+ // limit + 1 children, and if so, will create an IncompleteChildrenVMC
+ // for the last child, discarding the original expression context.
+
/**
* Specialization of VariableVMNode.VariableExpressionVMC that participates
* in the "Add Watchpoint" object contribution action.
@@ -98,8 +159,7 @@ public class GdbVariableVMNode extends VariableVMNode {
@Override
public void handleCompleted() {
if (isSuccess()) {
- assert getData().getSize() > 0;
- request.setCanCreate(true);
+ request.setCanCreate(getData().getSize() > 0);
}
request.setStatus(getStatus());
request.done();
@@ -122,6 +182,41 @@ public class GdbVariableVMNode extends VariableVMNode {
}
};
+ /**
+ * The special context representing more children to be available.
+ *
+ * @since 3.0
+ */
+ public class IncompleteChildrenVMC extends AbstractVMContext {
+
+ private IExpressionDMContext parentDmc;
+
+ public IncompleteChildrenVMC(IExpressionDMContext exprDmc, int childCountLimit) {
+ super(GdbVariableVMNode.this);
+ this.parentDmc = exprDmc;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof IncompleteChildrenVMC &&
+ ((IncompleteChildrenVMC)obj).parentDmc.equals(parentDmc);
+ }
+
+ @Override
+ public int hashCode() {
+ return parentDmc.hashCode();
+ }
+
+ public IExpressionDMContext getParentDMContext() {
+ return parentDmc;
+ }
+ }
+
+ /**
+ * Maps expressions to their current limit on the maximum number of children.
+ */
+ private Map childCountLimits = new HashMap();
+
/**
* Utility method to create an IStatus object for an internal error
*/
@@ -149,4 +244,331 @@ public class GdbVariableVMNode extends VariableVMNode {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new GdbVariableExpressionVMC(dmc);
}
+
+ @Override
+ protected void updateHasElementsInSessionThread(final IHasChildrenUpdate update) {
+ if (update.getElement() instanceof IncompleteChildrenVMC) {
+ update.setHasChilren(false);
+ update.done();
+ return;
+ }
+
+ super.updateHasElementsInSessionThread(update);
+ }
+
+ @Override
+ protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
+ // Get the data model context object for the current node in the hierarchy.
+
+ final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if ( expressionDMC != null ) {
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+
+ if (expressionService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ if (expressionService instanceof IMIExpressions) {
+ final IMIExpressions miExpressions = (IMIExpressions) expressionService;
+
+ miExpressions.safeToAskForAllSubExpressions(expressionDMC,
+ new ViewerDataRequestMonitor(getSession().getExecutor(), update) {
+
+ @Override
+ protected void handleCompleted() {
+ if (! isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ boolean limitRequired = ! getData().booleanValue();
+ if (limitRequired) {
+
+ final int childCountLimit = getOrInitChildCountLimit(expressionDMC);
+
+ miExpressions.getSubExpressionCount(
+ expressionDMC, childCountLimit + 1,
+ new ViewerDataRequestMonitor(getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ int childCount = getData();
+ if (childCountLimit < childCount) {
+ childCount = childCountLimit + 1;
+ }
+
+ update.setChildCount(childCount);
+ update.done();
+ }
+ });
+ } else {
+ GdbVariableVMNode.super.updateElementCountInSessionThread(update);
+ }
+ }
+ });
+
+ return;
+ }
+ }
+
+ super.updateElementCountInSessionThread(update);
+ }
+
+ @Override
+ protected void fillUpdateWithVMCs(IChildrenUpdate update,
+ IDMContext[] dmcs, int firstIndex) {
+ super.fillUpdateWithVMCs(update, dmcs, firstIndex);
+
+ IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if (expressionDMC != null) {
+ int childCountLimit = getChildCountLimit(expressionDMC);
+ int childCount = firstIndex + update.getLength();
+ if (childCountLimit < childCount) {
+ update.setChild(new IncompleteChildrenVMC(expressionDMC, childCountLimit), childCountLimit);
+ }
+ }
+ }
+
+ @Override
+ public void update(IPropertiesUpdate[] updates) {
+ List realExpressions = new ArrayList();
+
+ for (IPropertiesUpdate update : updates) {
+ if (update.getElement() instanceof IncompleteChildrenVMC) {
+ if (update.getProperties().contains(
+ AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION)) {
+ update.setProperty(
+ AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION,
+ Messages.More_Children);
+
+ }
+
+ if (update.getProperties().contains(PROP_NAME)) {
+ update.setProperty(PROP_NAME, Messages.More_Children);
+ }
+ update.done();
+ } else {
+ realExpressions.add(update);
+ }
+ }
+
+ super.update(realExpressions.toArray(new IPropertiesUpdate[realExpressions.size()]));
+ }
+
+ private int getInitialChildCountLimit() {
+ Object initialLimitProperty = getVMProvider().getPresentationContext().getProperty(
+ IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+
+ return (initialLimitProperty instanceof Integer) ? (Integer) initialLimitProperty
+ : 100;
+ }
+
+ /**
+ * The given expression context requires a child count limit. If a limit
+ * is already available from preceding calls, obtain this limit. Otherwise
+ * calculate the initial value, store it, and return it.
+ *
+ * @param expressionDMC
+ * @return The child count limit to apply for the given expression.
+ *
+ * @since 3.0
+ */
+ protected int getOrInitChildCountLimit(IExpressionDMContext expressionDMC) {
+ if (childCountLimits.containsKey(expressionDMC)) {
+ return childCountLimits.get(expressionDMC);
+ }
+
+ int initialLimit = getInitialChildCountLimit();
+ childCountLimits.put(expressionDMC, initialLimit);
+
+ return initialLimit;
+ }
+
+ /**
+ * @param expressionDMC
+ * @return The currently stored child count limit for the given expression,
+ * or {@link Integer#MAX_VALUE} if no child count limit is currently
+ * stored.
+ *
+ * @since 3.0
+ */
+ protected int getChildCountLimit(IExpressionDMContext expressionDMC) {
+ if (childCountLimits.containsKey(expressionDMC)) {
+ return childCountLimits.get(expressionDMC);
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ private void resetChildCountLimits(IExecutionDMContext execCtx) {
+ int initialLimit = getInitialChildCountLimit();
+ for (IExpressionDMContext limitCtx : childCountLimits.keySet()) {
+ if (DMContexts.isAncestorOf(limitCtx, execCtx)) {
+ childCountLimits.put(limitCtx, initialLimit);
+ }
+ }
+ }
+
+ private void resetAllChildCountLimits() {
+ int initialLimit = getInitialChildCountLimit();
+ for (IExpressionDMContext limitCtx : childCountLimits.keySet()) {
+ childCountLimits.put(limitCtx, initialLimit);
+ }
+ }
+
+ /**
+ * Increment the child count limit by the default increment.
+ * This implementation doubles the current limit.
+ *
+ * @since 3.0
+ */
+ public void incrementChildCountLimit(IExpressionDMContext expressionDMC) {
+ assert(childCountLimits.containsKey(expressionDMC));
+
+ int childCountLimit = getChildCountLimit(expressionDMC);
+ if (childCountLimit < Integer.MAX_VALUE / 2) {
+ childCountLimits.put(expressionDMC, childCountLimit * 2);
+ }
+ }
+
+ @Override
+ public int getDeltaFlags(Object e) {
+ int flags = super.getDeltaFlags(e);
+
+ if (e instanceof FetchMoreChildrenEvent) {
+ flags |= IModelDelta.CONTENT;
+ } else if (e instanceof ISuspendedDMEvent) {
+ // The child count limit must be reset.
+ flags |= IModelDelta.CONTENT;
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ flags |= IModelDelta.CONTENT;
+ }
+ }
+
+ return flags;
+ }
+
+
+ @Override
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ int flags = super.getDeltaFlagsForExpression(expression, event);
+
+ if (event instanceof FetchMoreChildrenEvent) {
+ flags |= IModelDelta.CONTENT;
+ } else if (event instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent) event).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS
+ .equals(property)) {
+ flags |= IModelDelta.CONTENT;
+ }
+ }
+
+ return flags;
+ }
+
+ @Override
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset,
+ RequestMonitor rm) {
+
+ if (e instanceof FetchMoreChildrenEvent) {
+ buildDeltaForFetchMoreChildrenEvent((FetchMoreChildrenEvent) e, parentDelta, rm);
+ return;
+ } else if (e instanceof ISuspendedDMEvent) {
+ resetChildCountLimits(((ISuspendedDMEvent) e).getDMContext());
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ resetAllChildCountLimits();
+ buildDeltaForChildCountLimitPreferenceChangedEvent(parentDelta, rm);
+ return;
+ }
+ }
+
+ super.buildDelta(e, parentDelta, nodeOffset, rm);
+ }
+
+ @Override
+ public void buildDeltaForExpressionElement(Object element, int elementIdx,
+ Object event, VMDelta parentDelta, RequestMonitor rm) {
+
+ if (event instanceof FetchMoreChildrenEvent) {
+ FetchMoreChildrenEvent fetchMoreEvent = (FetchMoreChildrenEvent) event;
+ GdbVariableExpressionVMC topLevelExpressionVMC = (GdbVariableExpressionVMC) element;
+ if (topLevelExpressionVMC.equals(fetchMoreEvent.getPath().getFirstSegment())) {
+ buildDeltaForFetchMoreChildrenEvent(fetchMoreEvent, parentDelta, rm);
+ return;
+ }
+ } else if (event instanceof ISuspendedDMEvent) {
+ resetChildCountLimits(((ISuspendedDMEvent) event).getDMContext());
+ } else if (event instanceof IContainerSuspendedDMEvent) {
+ resetChildCountLimits(((IContainerSuspendedDMEvent) event).getDMContext());
+ } else if (event instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)event).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ resetAllChildCountLimits();
+ buildDeltaForChildCountLimitPreferenceChangedEvent(parentDelta, rm);
+ return;
+ }
+ }
+
+ super.buildDeltaForExpressionElement(element, elementIdx, event, parentDelta,
+ rm);
+ }
+
+ private void buildDeltaForFetchMoreChildrenEvent(
+ FetchMoreChildrenEvent fetchMoreChidrenEvent,
+ VMDelta parentDelta, final RequestMonitor rm) {
+
+ TreePath path = fetchMoreChidrenEvent.getPath();
+
+ // Add all the parents of the expression. Those didn't change, however.
+ for (int i = 0; i < path.getSegmentCount() - 2; ++i) {
+ parentDelta = parentDelta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE);
+ }
+
+ // Add the node for the expression. This one changed, of course.
+ final VMDelta expressionDelta =
+ parentDelta.addNode(path.getSegment(path.getSegmentCount() - 2), IModelDelta.CONTENT);
+
+ // Make sure the element formerly know as <...more_children...> is selected
+ // afterwards.
+
+ final int offset = getChildCountLimit(fetchMoreChidrenEvent.getDMContext()) / 2;
+ // The one trailing element is to see whether there are more children.
+ final int maxLength = offset + 1;
+ getVMProvider().updateNode(
+ this,
+ new VMChildrenUpdate(
+ expressionDelta, getVMProvider().getPresentationContext(), offset, maxLength,
+ new DataRequestMonitor>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+
+ // FIXME if the new child has children they do not appear because of this code.
+// final List