From 5439a6af9eef8c9eeddf7ffcfd566ed33c6805b7 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 5 May 2012 12:54:55 +0400 Subject: Bug 360314: OS awareness debug view Change-Id: I96b6df8bd5faa7e1da579d9e45580004170ac1e9 Reviewed-on: https://git.eclipse.org/r/5835 Reviewed-by: Marc Khouzam IP-Clean: Marc Khouzam Tested-by: Marc Khouzam --- .../META-INF/MANIFEST.MF | 3 +- .../icons/full/view16/osresources_view.gif | Bin 0 -> 262 bytes .../org.eclipse.cdt.dsf.gdb.ui/plugin.properties | 6 +- dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml | 7 + dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/pom.xml | 2 +- .../dsf/gdb/internal/ui/osview/ColumnLayout.java | 143 +++++ .../ui/osview/ContentLabelProviderWrapper.java | 88 +++ .../cdt/dsf/gdb/internal/ui/osview/Messages.java | 39 ++ .../dsf/gdb/internal/ui/osview/Messages.properties | 22 + .../cdt/dsf/gdb/internal/ui/osview/OSData.java | 148 +++++ .../gdb/internal/ui/osview/OSResourcesView.java | 641 +++++++++++++++++++++ .../ui/osview/ResourceClassContributionItem.java | 210 +++++++ .../dsf/gdb/internal/ui/osview/SessionOSData.java | 292 ++++++++++ .../cdt/dsf/gdb/service/GDBHardwareAndOS_7_5.java | 95 +++ .../dsf/gdb/service/GdbDebugServicesFactory.java | 6 + .../cdt/dsf/gdb/service/IGDBHardwareAndOS2.java | 67 +++ .../cdt/dsf/mi/service/command/CommandFactory.java | 17 + .../dsf/mi/service/command/commands/MIInfoOs.java | 52 ++ .../mi/service/command/output/MIInfoOsInfo.java | 187 ++++++ 19 files changed, 2022 insertions(+), 3 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/icons/full/view16/osresources_view.gif create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ColumnLayout.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ContentLabelProviderWrapper.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.properties create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSData.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSResourcesView.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ResourceClassContributionItem.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/SessionOSData.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS_7_5.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInfoOs.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIInfoOsInfo.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/META-INF/MANIFEST.MF b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/META-INF/MANIFEST.MF index d4e6cc44ddc..8d3a7df5824 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/META-INF/MANIFEST.MF +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-SymbolicName: org.eclipse.cdt.dsf.gdb.ui;singleton:=true -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Activator: org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, @@ -32,6 +32,7 @@ Export-Package: org.eclipse.cdt.dsf.gdb.internal.ui;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.commands;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.console;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.launching;x-friends:="org.eclipse.cdt.debug.gdbjtag.ui", + org.eclipse.cdt.dsf.gdb.internal.ui.osview;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.preferences;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.tracepointactions;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.ui.tracepoints;x-internal:=true, diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/icons/full/view16/osresources_view.gif b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/icons/full/view16/osresources_view.gif new file mode 100644 index 00000000000..71fc0a4f941 Binary files /dev/null and b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/icons/full/view16/osresources_view.gif differ 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 6248385f21a..219fa516a90 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2008, 2010 Ericsson and others. +# Copyright (c) 2008, 2012 Ericsson 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 @@ -9,6 +9,7 @@ # Ericsson - initial API and implementation # IBM Corporation # Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121) +# Vladimir Prus (Mentor Graphics) - OS Resources view (bug 360314) ############################################################################### pluginName=GDB DSF Debugger Integration UI providerName=Eclipse CDT @@ -47,3 +48,6 @@ activity.name = CDT DSF-GDB - GDB Debugging # Pretty Printing action.fetchMoreChildren.label=Fetch More Children + +# OS view +view.osresources.name=OS Resources 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 b59f15537b5..81593486d9a 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml @@ -263,6 +263,13 @@ id="org.eclipse.cdt.dsf.gdb.ui.tracecontrol.view" name="%view.traceControl.name"> + + diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/pom.xml b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/pom.xml index a418ced7299..16b88d43c30 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/pom.xml +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 2.3.0-SNAPSHOT + 2.4.0-SNAPSHOT org.eclipse.cdt.dsf.gdb.ui eclipse-plugin diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ColumnLayout.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ColumnLayout.java new file mode 100644 index 00000000000..f8727623645 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ColumnLayout.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.jface.dialogs.IDialogSettings; + +/* Hold information about which columns in a table are visible, and what + * width they have. Stores that information inside preferences store. + */ +class ColumnLayout +{ + private String fResourceClass; + private Map fVisible = new HashMap(); + private Map fWidth = new HashMap(); + private Integer fSortColumn = null; + private Integer fSortDirection = null; + + private static IDialogSettings settings; + private static IDialogSettings getDialogSettings() + { + if (settings != null) + return settings; + + IDialogSettings topSettings = GdbUIPlugin.getDefault().getDialogSettings(); + settings = topSettings.getSection(ResourceClassContributionItem.class.getName()); + if (settings == null) { + settings = topSettings.addNewSection(ResourceClassContributionItem.class.getName()); + } + return settings; + } + + private static void setDefaultSetting(String key, boolean value) + { + IDialogSettings s = getDialogSettings(); + if (s.get(key) == null) + s.put(key, value); + } + + private static void setDefaultSetting(String key, int value) + { + IDialogSettings s = getDialogSettings(); + if (s.get(key) == null) + s.put(key, value); + } + + public ColumnLayout(String resourceClass) + { + fResourceClass = resourceClass; + } + + public boolean getVisible(String column) + { + if (fVisible.containsKey(column)) + return fVisible.get(column); + else + { + setDefaultSetting(columnKey(column, "v"), true); //$NON-NLS-1$ + boolean b = getDialogSettings().getBoolean(columnKey(column, "v")); //$NON-NLS-1$ + fVisible.put(column, b); + return b; + } + } + + public void setVisible(String column, boolean visible) + { + fVisible.put(column, visible); + getDialogSettings().put(columnKey(column, "v"), visible); //$NON-NLS-1$ + } + + public int getWidth(String column) + { + if (fWidth.containsKey(column)) + return fWidth.get(column); + else + { + setDefaultSetting(columnKey(column, "w"), -1); //$NON-NLS-1$ + int w = getDialogSettings().getInt(columnKey(column, "w")); //$NON-NLS-1$ + fWidth.put(column, w); + return w; + } + } + + public void setWidth(String column, int width) + { + fWidth.put(column, width); + getDialogSettings().put(columnKey(column, "w"), width); //$NON-NLS-1$ + } + + public int getSortColumn() + { + if (fSortColumn == null) + { + setDefaultSetting(globalKey("sortColumn"), 0); //$NON-NLS-1$ + fSortColumn = getDialogSettings().getInt(globalKey("sortColumn")); //$NON-NLS-1$ + } + return fSortColumn; + } + + public void setSortColumn(int column) + { + fSortColumn = column; + getDialogSettings().put(globalKey("sortColumn"), fSortColumn); //$NON-NLS-1$ + } + + public int getSortDirection() + { + if (fSortDirection == null) + { + setDefaultSetting(globalKey("sortDirection"), 1); //$NON-NLS-1$ + fSortDirection = getDialogSettings().getInt(globalKey("sortDirection")); //$NON-NLS-1$ + } + return fSortDirection; + } + + public void setSortDirection(int direction) + { + fSortDirection = direction; + getDialogSettings().put(globalKey("sortDirection"), fSortDirection); //$NON-NLS-1$ + } + + private String columnKey(String column, String what) + { + return "columnLayout." + fResourceClass + "." + column + "." + what; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + private String globalKey(String what) + { + return "columnLayout." + fResourceClass + "." + what; //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ContentLabelProviderWrapper.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ContentLabelProviderWrapper.java new file mode 100644 index 00000000000..d322b096fd7 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ContentLabelProviderWrapper.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.graphics.Image; + +/** Helper class to change table and label provider of a TreeViewer in an atomic fashion. + * + * Suppose we want to change both content and label provider of existing TreeViewer. Right now, + * if we set either, TreeViewer will try a refresh, using one new provider and one old. This + * is obviously nonsensical -- for example if we set set new content provider, then old label provider + * will be asked to provide labels for elements it has no idea what to do with, or for columns beyond + * its range, etc. + * + * This class is wrapping our real content provider, and can be retargeted in one call -- after which + * refresh of TreeViewer sees consistent data. + * + * @since 2.4 + * */ +public class ContentLabelProviderWrapper +implements ITableLabelProvider, IStructuredContentProvider +{ + + public ContentLabelProviderWrapper(U realProvider) + { + this.realProvider = realProvider; + } + + public void setData(U realProvider) + { + this.realProvider = realProvider; + } + + @Override + public Image getColumnImage(Object obj, int index) { + return realProvider.getColumnImage(obj, index); + } + + @Override + public void addListener(ILabelProviderListener listener) { + realProvider.addListener(listener); + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return realProvider.isLabelProperty(element, property); + } + + @Override + public void removeListener(ILabelProviderListener listener) { + realProvider.removeListener(listener); + } + + @Override + public String getColumnText(Object obj, int index) { + return realProvider.getColumnText(obj, index); + } + + @Override + public void inputChanged(Viewer v, Object oldInput, Object newInput) { + realProvider.inputChanged(v, oldInput, newInput); + } + + @Override + public void dispose() { + realProvider.dispose(); + } + + @Override + public Object[] getElements(Object parent) { + return realProvider.getElements(parent); + } + + private U realProvider; +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.java new file mode 100644 index 00000000000..ae708ab7f14 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import org.eclipse.osgi.util.NLS; + +/** + * @since 2.4 + */ +public class Messages extends NLS { + public static String OSView_3; + public static String OSView_4; + public static String OSView_5; + public static String OSView_6; + public static String OSView_7; + public static String OSView_8; + public static String OSView_9; + public static String OSView_10; + public static String OSView_11; + public static String OSView_12; + public static String OSView_13; + public static String OSView_14; + static { + // initialize resource bundle + NLS.initializeMessages(Messages.class.getName(), Messages.class); + } + + private Messages() { + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.properties new file mode 100644 index 00000000000..f57587aa280 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/Messages.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2011, 2012 Mentor Graphics 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: +# Vladimir Prus (Mentor Graphics) - initial API and implementation +############################################################################### +OSView_3=Refresh +OSView_4=No debug session is selected. +OSView_5=Please select resource class. +OSView_6=Fetching data... +OSView_7=No data has been fetched yet. Fetch now. +OSView_8='Refresh (last fetched on' h:mm:ss ')' +OSView_9=Updating OS resources view +OSView_10=OS resources are not available using your target and GDB. +OSView_11=Determining available OS resource classes... +OSView_12=No data has been fetched yet. Target is busy. +OSView_13=Waiting for the debug session to initialize. +OSView_14=Objects from different debug sessions are selected. diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSData.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSData.java new file mode 100644 index 00000000000..0bbad09af74 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSData.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.IResourcesInformation; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.graphics.Image; + +/* Table data provider that exposes information about OS resources + * of specific class. Constructed from MI output. Once constructed, + * this class is immutable. + */ +class OSData +extends LabelProvider +implements ITableLabelProvider, IStructuredContentProvider +{ + private IResourcesInformation data; + private boolean[] columnIsInteger; + private List remap; + + public OSData(String resourceClass, IResourcesInformation data) { + this.data = data; + determineColumnTypes(); + + remap = new ArrayList(data.getColumnNames().length); + for (int i = 0; i < data.getColumnNames().length; ++i) + remap.add(i); + + if (resourceClass.equals("processes")) //$NON-NLS-1$ + sendToEnd("Command"); //$NON-NLS-1$ + + if (resourceClass.equals("threads")) //$NON-NLS-1$ + sendToEnd("Command"); //$NON-NLS-1$ + + if (resourceClass.equals("modules")) //$NON-NLS-1$ + sendToEnd("Dependencies"); //$NON-NLS-1$ + } + + // Determine column types, for the purpose of proper sorting + private void determineColumnTypes() + { + String[] columnNames = data.getColumnNames(); + String[][] content = data.getContent(); + + columnIsInteger = new boolean[columnNames.length]; + + boolean[] columnHasInteger = new boolean[columnNames.length]; + boolean[] columnHasOther = new boolean[columnNames.length]; + + for (int i = 0; i < content.length; ++i) { + for (int j = 0; j < content[i].length; ++j) { + if (!columnHasOther[j]) + { + try { + Integer.parseInt(content[i][j]); + columnHasInteger[j] = true; + } + catch(NumberFormatException e) { + columnHasOther[j] = true; + } + catch(Throwable e) { + e.printStackTrace(); + } + } + + } + } + + for (int j = 0; j < data.getColumnNames().length; ++j) { + columnIsInteger[j] = columnHasInteger[j] && !columnHasOther[j]; + } + } + + /* Make column named 'column' appear last in UI. */ + private void sendToEnd(String column) + { + // Find index in the remap array (which is equal to index in UI) + // at which column named 'column' is found. + int index = -1; + for (int i = 0; i < remap.size(); ++i) + if (data.getColumnNames()[remap.get(i)].equals(column)) { + index = i; + break; + } + if (index == -1) + return; + + // Move the element to the end of the list + remap.add(remap.remove(index)); + } + + public int getColumnCount() + { + return remap.size(); + } + + public String getColumnName(int i) + { + return data.getColumnNames()[remap.get(i)]; + } + + public boolean getColumnIsInteger(int j) { + return columnIsInteger[remap.get(j)]; + } + + @Override + public String getColumnText(Object obj, int index) { + return ((String[]) obj)[remap.get(index)]; + } + + @Override + public Image getColumnImage(Object obj, int index) { + return getImage(obj); + } + + @Override + public Image getImage(Object obj) { + return null; + } + + @Override + public void inputChanged(Viewer v, Object oldInput, Object newInput) { + } + + @Override + public void dispose() { + } + + @Override + public Object[] getElements(Object parent) { + return data.getContent(); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSResourcesView.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSResourcesView.java new file mode 100644 index 00000000000..5e5f2a7cc5a --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/OSResourcesView.java @@ -0,0 +1,641 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.contexts.DebugContextEvent; +import org.eclipse.debug.ui.contexts.IDebugContextListener; +import org.eclipse.debug.ui.contexts.IDebugContextManager; +import org.eclipse.debug.ui.contexts.IDebugContextService; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.osgi.util.NLS; +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.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.ui.progress.UIJob; +import org.osgi.framework.Bundle; + +/** + * @since 2.4 + */ +public class OSResourcesView extends ViewPart implements DsfSession.SessionEndedListener { + + private final static String FETCH_LINK_TAG = "fetch"; //$NON-NLS-1$ + + // The data model for the selected session, or null if no session is + // selected. + private SessionOSData fSessionData; + private Map fSessionDataCache = new HashMap(); + // The data presently shown by table viewer. + private OSData fTableShownData = null; + // The data which was used to populate column selector menu + private OSData fMenuShownData = null; + private String fResourceClass = null; + + // Indicates that we've selected objects from different debug sessions. + boolean fMultiple = false; + + + // UI objects + private TableViewer fViewer; + private Comparator fComparator; + private Composite fNothingLabelContainer; + private Link fNothingLabel; + private ResourceClassContributionItem fResourceClassEditor; + private Action fRefreshAction; + + // Map from resource class name to table column layout. + private Map fColumnLayouts = new HashMap(); + + private ColumnLayout fColumnLayout = null; + + private IDebugContextListener fDebugContextListener; + + @Override + public void createPartControl(Composite xparent) { + + Composite parent = new Composite(xparent, SWT.NONE); + GridLayout topLayout = new GridLayout(1, false); + topLayout.marginWidth = 0; + topLayout.marginHeight = 0; + parent.setLayout(topLayout); + + fViewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL + | SWT.V_SCROLL); + GridData viewerData = new GridData(GridData.FILL_BOTH); + viewerData.exclude = true; + fViewer.getControl().setLayoutData(viewerData); + + fViewer.setComparator(fComparator = new Comparator()); + + Table table = fViewer.getTable(); + table.setHeaderVisible(true); + table.setVisible(false); + + fNothingLabelContainer = new Composite(parent, SWT.NONE); + + GridData nothingLayout = new GridData(SWT.FILL, SWT.FILL, true, true); + fNothingLabelContainer.setLayoutData(nothingLayout); + + GridLayout containerLayout = new GridLayout(1, false); + fNothingLabelContainer.setLayout(containerLayout); + + fNothingLabel = new Link(fNothingLabelContainer, SWT.BORDER); + fNothingLabel.setText(Messages.OSView_4); + fNothingLabel.setBackground(fNothingLabel.getDisplay().getSystemColor( + SWT.COLOR_LIST_BACKGROUND)); + fNothingLabel.addListener (SWT.Selection, new Listener () { + @Override + public void handleEvent(Event event) { + if (event.text.equals("fetch")) //$NON-NLS-1$ + if (fSessionData != null && fResourceClass != null) + fSessionData.fetchData(fResourceClass); + } + }); + fNothingLabelContainer.setBackground(fNothingLabel.getBackground()); + + GridData nothingLabelLayout = new GridData(SWT.CENTER, SWT.TOP, true, false); + fNothingLabel.setLayoutData(nothingLabelLayout); + + fResourceClassEditor = new ResourceClassContributionItem(); + fResourceClassEditor.setListener(new ResourceClassContributionItem.Listener() { + + @Override + public void resourceClassChanged(String newClass) { + fResourceClass = newClass; + // Since user explicitly changed the class, initiate fetch immediately. + fSessionData.fetchData(fResourceClass); + // Do not call 'update()' here. fetchData call above will notify + // us at necessary moments. + } + }); + IActionBars bars = getViewSite().getActionBars(); + bars.getToolBarManager().add(fResourceClassEditor); + + fRefreshAction = new Action() { + @Override + public void run() { + if (fSessionData != null && fResourceClass != null) + fSessionData.fetchData(fResourceClass); + } + }; + fRefreshAction.setText(Messages.OSView_3); + fRefreshAction.setToolTipText(Messages.OSView_3); + try { + Bundle bundle= Platform.getBundle("org.eclipse.ui"); //$NON-NLS-1$ + URL url = bundle.getEntry("/"); //$NON-NLS-1$ + url = new URL(url, "icons/full/elcl16/refresh_nav.gif"); //$NON-NLS-1$ + ImageDescriptor candidate = ImageDescriptor.createFromURL(url); + if (candidate != null && candidate.getImageData() != null) { + fRefreshAction.setImageDescriptor(candidate); + } + } catch (Exception e) { + } + bars.getToolBarManager().add(fRefreshAction); + bars.updateActionBars(); + + fResourceClass = fResourceClassEditor.getResourceClassId(); + + setupContextListener(); + DsfSession.addSessionEndedListener(this); + } + + private void setupContextListener() { + IDebugContextManager contextManager = DebugUITools.getDebugContextManager(); + IDebugContextService contextService = contextManager + .getContextService(getSite().getWorkbenchWindow()); + + fDebugContextListener = new IDebugContextListener() { + + @Override + public void debugContextChanged(DebugContextEvent event) { + + if ((event.getFlags() & DebugContextEvent.ACTIVATED) != 0) { + ISelection s = event.getContext(); + setDebugContext(s); + } + } + }; + contextService.addDebugContextListener(fDebugContextListener); + setDebugContext(contextService.getActiveContext()); + } + + @Override + public void dispose() { + super.dispose(); + + IDebugContextManager contextManager = DebugUITools.getDebugContextManager(); + IDebugContextService contextService = contextManager + .getContextService(getSite().getWorkbenchWindow()); + contextService.removeDebugContextListener(fDebugContextListener); + + setDebugContext((ICommandControlDMContext)null); + DsfSession.removeSessionEndedListener(this); + } + + private void setDebugContext(ISelection s) { + + ICommandControlDMContext context = null; + fMultiple = false; + if (s instanceof IStructuredSelection) { + IStructuredSelection ss = (IStructuredSelection) s; + if (ss.size() > 0) { + @SuppressWarnings("rawtypes") + Iterator i = ss.iterator(); + context = getCommandControlContext(i.next()); + while (i.hasNext()) { + ICommandControlDMContext nextContext = getCommandControlContext(i.next()); + if (nextContext == null && context != null + || nextContext != null && context == null + || nextContext != null && context != null && !nextContext.equals(context)) + { + context = null; + fMultiple = true; + break; + } + } + } + } + + setDebugContext(context); + } + + private ICommandControlDMContext getCommandControlContext(Object obj) { + IDMContext context = null; + if (obj instanceof IDMVMContext) + context = ((IDMVMContext)obj).getDMContext(); + else if (obj instanceof GdbLaunch) { + GdbLaunch l = (GdbLaunch)obj; + final DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), l.getSession().getId()); + Query contextQuery = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + ICommandControlService commandControl = tracker.getService(ICommandControlService.class); + tracker.dispose(); + if (commandControl != null) + { + rm.setData(commandControl.getContext()); + } + rm.done(); + } + }; + l.getSession().getExecutor().submit(contextQuery); + try { + context = contextQuery.get(); + } catch (Exception e) { + } + } + return DMContexts.getAncestorOfType(context, ICommandControlDMContext.class); + } + + private void setDebugContext(ICommandControlDMContext context) + { + DsfSession newSession = null; + SessionOSData newSessionData = null; + + if (context != null) + { + newSession = DsfSession.getSession(context.getSessionId()); + } + + if (newSession != null) + { + newSessionData = fSessionDataCache.get(newSession.getId()); + if (newSessionData == null) + { + newSessionData = new SessionOSData(newSession, context); + fSessionDataCache.put(newSession.getId(), newSessionData); + + newSessionData.setUIListener(new SessionOSData.Listener() { + + @Override + public void update() { + // Note that fSessionData always calls the listener in + // UI thread, so we can directly call 'update' here. + OSResourcesView.this.update(); + } + }, fViewer.getControl()); + } + } + + + if (newSessionData != fSessionData) + { + fSessionData = newSessionData; + update(); + } + } + + @Override + public void sessionEnded(DsfSession session) { + String id = session.getId(); + SessionOSData data = fSessionDataCache.remove(id); + if (data != null) { + data.dispose(); + } + } + + private void update() { + + if (fViewer == null || fViewer.getControl() == null) + return; + + if (fViewer.getControl().isDisposed()) + return; + + if (fSessionData == null) + { + hideTable(fMultiple ? Messages.OSView_14 : Messages.OSView_4); + fResourceClassEditor.setEnabled(false); + fRefreshAction.setEnabled(false); + return; + } + + boolean enable = fSessionData.canFetchData(); + fRefreshAction.setEnabled(enable); + fResourceClass = fResourceClassEditor.updateClasses(fSessionData.getResourceClasses()); + fResourceClassEditor.setEnabled(enable); + + if (!fSessionData.osResourcesSupported()) { + fRefreshAction.setEnabled(false); + fResourceClassEditor.setEnabled(false); + hideTable(Messages.OSView_10); + return; + } + + if (fSessionData.waitingForSessionInitialization()) { + fRefreshAction.setEnabled(false); + fResourceClassEditor.setEnabled(false); + hideTable(Messages.OSView_13); + return; + } + + if (fSessionData.fetchingClasses()) { + fRefreshAction.setEnabled(false); + fResourceClassEditor.setEnabled(false); + hideTable(Messages.OSView_11); + return; + } + + if (fResourceClass == null) + { + fRefreshAction.setEnabled(false); + fResourceClassEditor.setEnabled(true); + hideTable(Messages.OSView_5); + return; + } + + + final OSData data = fSessionData.existingData(fResourceClass); + + if (fSessionData.fetchingContent()) + { + hideTable(Messages.OSView_6); + } + else if (data == null) + { + if (fSessionData.canFetchData()) + hideTable(NLS.bind(Messages.OSView_7, FETCH_LINK_TAG)); + else + hideTable(Messages.OSView_12); + } + else + { + SimpleDateFormat format = new SimpleDateFormat(Messages.OSView_8); + fRefreshAction.setToolTipText(format.format(fSessionData.timestamp(fResourceClass))); + if (data != fTableShownData) + { + Job job = new UIJob(Messages.OSView_9) { + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + fTableShownData = data; + populateTable(data); + showTable(); + return Status.OK_STATUS; + } + + }; + job.setPriority(Job.INTERACTIVE); + job.schedule(); + } + else + { + assert fViewer.getTable().getColumnCount() == data.getColumnCount(); + showTable(); + } + } + fRefreshAction.setEnabled(fSessionData.canFetchData()); + fResourceClassEditor.setEnabled(fSessionData.canFetchData()); + + } + + /* Hide the table that would show OS awareness data if it were available. Display + * 'message' instead. + */ + private void hideTable(String message) { + setContentDescription(""); //$NON-NLS-1$ + fViewer.getControl().setVisible(false); + ((GridData) fViewer.getControl().getLayoutData()).exclude = true; + fNothingLabelContainer.setVisible(true); + ((GridData) fNothingLabelContainer.getLayoutData()).exclude = false; + fNothingLabelContainer.getParent().layout(); + fNothingLabel.setText(message); + fNothingLabelContainer.layout(); + + // If the table is not shown, we don't want the menu to have stale + // list of columns to select from. + IActionBars bars = getViewSite().getActionBars(); + bars.getMenuManager().removeAll(); + bars.updateActionBars(); + fMenuShownData = null; + } + + private void showTable() { + assert fTableShownData != null; + + fViewer.getControl().setVisible(true); + ((GridData) fViewer.getControl().getLayoutData()).exclude = false; + fNothingLabelContainer.setVisible(false); + ((GridData) fNothingLabelContainer.getLayoutData()).exclude = true; + fNothingLabelContainer.getParent().layout(); + + populateViewMenu(fTableShownData); + } + + private void populateTable(final OSData data) + { + final Table table = fViewer.getTable(); + + while (table.getColumnCount() > 0) + table.getColumns()[0].dispose(); + + fColumnLayout = fColumnLayouts.get(fResourceClass); + if (fColumnLayout == null) + { + fColumnLayout = new ColumnLayout(fResourceClass); + fColumnLayouts.put(fResourceClass, fColumnLayout); + } + + for (int i = 0; i < data.getColumnCount(); ++i) { + final String cn = data.getColumnName(i); + final TableColumn c = new TableColumn(table, SWT.LEFT); + c.setText(cn); + + c.addListener(SWT.Resize, new Listener() { + + @Override + public void handleEvent(Event event) { + fColumnLayout.setWidth(cn, c.getWidth()); + } + }); + + final int final_index = i; + c.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + int dir = table.getSortDirection(); + if (table.getSortColumn() == c) { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } else { + dir = SWT.DOWN; + } + table.setSortDirection(dir); + table.setSortColumn(c); + fComparator.configure(final_index, data); + fComparator.setDirection(dir == SWT.DOWN ? 1 : -1); + fColumnLayout.setSortColumn(final_index); + fColumnLayout.setSortDirection(dir == SWT.DOWN ? 1 : -1); + fViewer.refresh(); + } + }); + } + + populateViewMenu(data); + + int sortColumn = fColumnLayout.getSortColumn(); + if (sortColumn < data.getColumnCount()) + { + fComparator.configure(sortColumn, data); + } + fComparator.setDirection(fColumnLayout.getSortDirection()); + + fViewer.getTable().setEnabled(true); + + + if (fViewer.getContentProvider() == null) + { + ContentLabelProviderWrapper wrapper = + new ContentLabelProviderWrapper(data); + fViewer.setContentProvider(wrapper); + fViewer.setLabelProvider(wrapper); + } + else + { + // Retarget current content/label providers in atomic fashion. See comments + // on ContentLabelProviderWrapper. + @SuppressWarnings("unchecked") + ContentLabelProviderWrapper wrapper = (ContentLabelProviderWrapper)fViewer.getContentProvider(); + wrapper.setData(data); + } + fViewer.setInput(getViewSite()); + fViewer.getControl().setVisible(true); + + for (int i = 0; i < fViewer.getTable().getColumnCount(); ++i) + { + TableColumn col = fViewer.getTable().getColumns()[i]; + String cn = col.getText(); + + if (i == sortColumn) { + table.setSortDirection(fColumnLayout.getSortDirection() == 1 ? SWT.DOWN : SWT.UP); + table.setSortColumn(col); + } + + if (fColumnLayout.getVisible(cn)) + { + int w = fColumnLayout.getWidth(cn); + if (w > 0) + col.setWidth(w); + else + col.pack(); + } + else + { + col.setWidth(0); + col.setResizable(false); + } + } + } + + private void populateViewMenu(final OSData data) { + + assert data.getColumnCount() == fViewer.getTable().getColumnCount(); + + if (data == fMenuShownData) + return; + + IActionBars bars = getViewSite().getActionBars(); + bars.getMenuManager().setVisible(true); + bars.getMenuManager().removeAll(); + + for (int i = 0; i < data.getColumnCount(); ++i) { + final String cn = data.getColumnName(i); + final TableColumn c = fViewer.getTable().getColumns()[i]; + + Action a = new Action(cn, IAction.AS_CHECK_BOX) { + @Override + public void run() { + if (isChecked()) { + int w = fColumnLayout.getWidth(cn); + if (w > 0) + c.setWidth(w); + else + c.pack(); + c.setResizable(true); + } else { + int w = c.getWidth(); + c.setWidth(0); + // Make sure we remember the width the column + // had before hiding. + fColumnLayout.setWidth(cn, w); + c.setResizable(false); + } + fColumnLayout.setVisible(cn, isChecked()); + } + }; + a.setChecked(fColumnLayout.getVisible(cn)); + a.setText(cn); + bars.getMenuManager().add(a); + } + bars.updateActionBars(); + + fMenuShownData = data; + } + + class Comparator extends ViewerComparator + { + private int fColumn = 0; + private OSData fData; + private boolean fInteger = false; + private int fDirection = 1; + + public void configure(int column, OSData data) + { + fColumn = column; + fData = data; + fInteger = data.getColumnIsInteger(column); + } + + public void setDirection(int direction) + { + assert direction == 1 || direction == -1; + fDirection = direction; + } + + @Override + public int compare(Viewer viewer, Object xe1, Object xe2) { + + String v1 = fData.getColumnText(xe1, fColumn); + String v2 = fData.getColumnText(xe2, fColumn); + if (fInteger) { + Integer i1 = Integer.parseInt(v1); + Integer i2 = Integer.parseInt(v2); + return fDirection*(i1 - i2); + } else { + return fDirection*(v1.compareTo(v2)); + } + } + }; + + @Override + public void setFocus() { + fViewer.getControl().setFocus(); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ResourceClassContributionItem.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ResourceClassContributionItem.java new file mode 100644 index 00000000000..68c37dfd91a --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/ResourceClassContributionItem.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.IResourceClass; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** + * @since 2.4 + */ +public class ResourceClassContributionItem extends ContributionItem { + + // In some places below, we are trying to determine size hint for Combo, given the list of + // content. However, while we can determine width of content, we don't know how much width + // the combobox itself is adding. This constant is our guess. + private static final int COMBO_TRIM_WIDTH = 64; + + interface Listener + { + void resourceClassChanged(String newClass); + } + + private Combo fResourceClassCombo; + private IResourceClass[] resourceClasses = new IResourceClass[0]; + private String fResourceClassId = null; + + private Listener fListener; + private boolean blockListener = false; + private ToolItem toolItem; + + private boolean enabled = true; + + private static IDialogSettings settings; + private static IDialogSettings getDialogSettings() + { + if (settings != null) + return settings; + + IDialogSettings topSettings = GdbUIPlugin.getDefault().getDialogSettings(); + settings = topSettings.getSection(ResourceClassContributionItem.class.getName()); + if (settings == null) { + settings = topSettings.addNewSection(ResourceClassContributionItem.class.getName()); + } + return settings; + } + + public void setListener(Listener listener) { + + fListener = listener; + } + + public void setEnabled(boolean enable) { + // It appears that every update of action bars will call 'fill' action below, creating + // combo. So, we want to keep 'enabled' state as member variable, to make sure it is kept + // if combo is recreated. + enabled = enable; + if (fResourceClassCombo != null) + fResourceClassCombo.setEnabled(enable); + } + + public String updateClasses(IResourceClass[] resourceClasses) { + + boolean different = false; + if (this.resourceClasses.length != resourceClasses.length) + different = true; + else for (int i = 0; i < this.resourceClasses.length; ++i) { + if (!this.resourceClasses[i].getId().equals(resourceClasses[i].getId()) + || !this.resourceClasses[i].getHumanDescription().equals(resourceClasses[i].getHumanDescription())) + { + different = true; + break; + } + } + + if (!different) + return fResourceClassId; + + this.resourceClasses = resourceClasses; + + fResourceClassCombo.removeAll(); + final int width = populateCombo(); + // Now change the width. Call to setWidth causes relayout automatically. + // IMPORTANT: the visibility check is critical. Without it, we appear to have hit + // an SWT/Gtk bug whenever a debug session and a previously use OS resources view + // is not shown. The bug manifests by 100% CPU consumption inside event loop, and + // it further blocks asyncExec runnables from ever executing. I suppose it might + // be specific to relayout of invisible toolbar. + + // If we're invisible, we don't arrange for relayout to happen when the view becomes + // available, because it is not exactly trivial (we need to events on the right control) + // and it only matters when we start a new session and it has a different set of + // resource classes and that requires longer combobox. + if (toolItem.getParent().isVisible()) + toolItem.setWidth(width); + + return fResourceClassId; + } + + /** Populate the combobox with resource classes. Return the width the + * combobox must have, including any trim. If there are no resource classes, + * returns some reasonable default width. + */ + private int populateCombo() { + + int width = 0; + String lastResourceClassId = getDialogSettings().get("resourceClass"); //$NON-NLS-1$ + int index = -1; + int i = 0; + GC gc = new GC(fResourceClassCombo); + for (i = 0; i < resourceClasses.length; ++i) { + String description = resourceClasses[i].getHumanDescription(); + width = Math.max(width, gc.textExtent(description).x); + fResourceClassCombo.add(description); + if (resourceClasses[i].getId().equals(lastResourceClassId)) + index = i; + } + + + + if (index != -1) { + fResourceClassId = lastResourceClassId; + blockListener = true; + fResourceClassCombo.select(index); + blockListener = false; + } + + if (width == 0) { + // We have some hints what the longest element in combo will be. Even if it's different + // in new GDB version, no problem -- the combo will be resized when it's populated. + width = gc.textExtent("Shared memory regions").x; //$NON-NLS-1$ + } + + // Because there's no way whatsoever to set the width + // of the combobox list, only complete length, we just add + // random padding. + width = width + COMBO_TRIM_WIDTH; + + return width; + } + + + public String getResourceClassId() { + return fResourceClassId; + } + + @Override + public void fill(ToolBar parent, int toolbarItemIndex) { + + fResourceClassCombo = new Combo(parent, SWT.NONE); + fResourceClassCombo.setEnabled(enabled); + int width = populateCombo(); + + fResourceClassCombo.addSelectionListener(new SelectionListener() { + + @SuppressWarnings({ "null"}) + @Override + public void widgetSelected(SelectionEvent e) { + String description = fResourceClassCombo.getText(); + String id = null; + for (int i = 0; i < resourceClasses.length; ++i) + if (resourceClasses[i].getHumanDescription().equals(description)) { + id = resourceClasses[i].getId(); + break; + } + + // id is never null here, unless we messed up our data structures. + assert id != null; + if (id != null && !id.equals(fResourceClassId)) + { + fResourceClassId = id; + getDialogSettings().put("resourceClass", id); //$NON-NLS-1$ + if (fListener != null && !blockListener) + fListener.resourceClassChanged(fResourceClassId); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + + toolItem = new ToolItem(parent, SWT.SEPARATOR); + toolItem.setControl(fResourceClassCombo); + toolItem.setWidth(width); + } + + @Override + public boolean isDynamic() { + return false; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/SessionOSData.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/SessionOSData.java new file mode 100644 index 00000000000..bfcbed340ea --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/osview/SessionOSData.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.ui.osview; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2; +import org.eclipse.cdt.dsf.mi.service.IMIRunControl; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.statushandlers.StatusManager; +import org.osgi.framework.BundleContext; + +/** Responsible for fetching and storing OS awareness data for a + * specific DSF session. + * + * @since 2.4 + */ +public class SessionOSData { + + private DsfSession fSession; + private DsfServicesTracker fTracker; + private IGDBHardwareAndOS2 fHardwareOs; + private ICommandControlDMContext fContext; + + private IGDBHardwareAndOS2.IResourceClass[] fResourceClasses = new IGDBHardwareAndOS2.IResourceClass[0]; + private Map fExistingData = new HashMap(); + private Map fTimestamp = new HashMap(); + + private Listener fUIListener; + private Control fUIControl; + + private boolean fWaitingForSession = true; + private boolean fSupported = true; + private boolean fAcceptingCommands = false; + private boolean fFetchingClasses = false; + private boolean fFetchingContent = false; + + + public SessionOSData(DsfSession session, final ICommandControlDMContext executionContext) + { + fSession = session; + BundleContext c = GdbUIPlugin.getDefault().getBundle().getBundleContext(); + fTracker = new DsfServicesTracker(c, fSession.getId()); + fContext = executionContext; + + final DsfExecutor executor = fSession.getExecutor(); + executor.submit(new DsfRunnable() { + + @Override + public void run() { + + IMIRunControl runControl = fTracker.getService(IMIRunControl.class); + fAcceptingCommands = runControl.isTargetAcceptingCommands(); + + fSession.addServiceEventListener(SessionOSData.this, null); + + fHardwareOs = fTracker.getService(IGDBHardwareAndOS2.class); + + if (fHardwareOs == null) { + fSupported = false; + notifyUI(); + return; + } + + if (fHardwareOs.isAvailable()) { + fetchClasses(); + } + } + }); + } + + @ConfinedToDsfExecutor("") + private void fetchClasses() + { + fWaitingForSession = false; + fFetchingClasses = true; + fHardwareOs.getResourceClasses(fContext, new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleCompleted() { + + if (isSuccess()) + { + fResourceClasses = getData(); + if (fResourceClasses.length == 0) + fSupported = false; + } + else + { + fSupported = false; + } + fFetchingClasses = false; + notifyUI(); + } + }); + } + + @DsfServiceEventHandler + public void eventDispatched(DataModelInitializedEvent e) { + // If we see this event, it necessary means that by the time we've set event listener, + // isAvailable() was returning false, so we need to fetch classes now. + if (fHardwareOs != null) + fetchClasses(); + } + + public boolean waitingForSessionInitialization() + { + return fWaitingForSession; + } + + public boolean osResourcesSupported() + { + return fSupported; + } + + public void dispose() + { + fSession.removeServiceEventListener(SessionOSData.this); + fTracker.dispose(); + } + + public IGDBHardwareAndOS2.IResourceClass[] getResourceClasses() + { + return fResourceClasses; + } + + /** Returns OS awareness data for given resource class that + * was previously fetched, or null if none was ever fetched. + */ + public OSData existingData(String resourceClass) + { + return fExistingData.get(resourceClass); + } + + /** Returns the timestamp at which data for 'resourceClass' have + * been obtained. + * @pre existingData(resourceClass) != null + */ + public Date timestamp(String resourceClass) + { + return fTimestamp.get(resourceClass); + } + + /** Returns true if fresh data can be fetched at this time. + * Generally, it's possible if we're not fetching data already, + * and if GDB is accepting commands right now. + * + */ + public boolean canFetchData() + { + return fAcceptingCommands && !fFetchingContent; + } + + public boolean fetchingClasses() + { + return fFetchingClasses; + } + + /** Returns true if we're presently fetching data. This can + * be used to provide some feedback to the user. + */ + public boolean fetchingContent() + { + return fFetchingContent; + } + + /** Fetches up-to-date data for resourceClass. Listeners will be + * informed when the new data is available. */ + public void fetchData(final String resourceClass) + { + fFetchingContent = true; + notifyUI(); + + final DsfExecutor executor = fSession.getExecutor(); + executor.submit(new DsfRunnable() { + + @Override + public void run() { + fHardwareOs.getResourcesInformation(fContext, resourceClass, new DataRequestMonitor(executor, null) { + + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleCompleted() { + + fFetchingContent = false; + + if (isSuccess()) + { + OSData data = new OSData(resourceClass, getData()); + fExistingData.put(resourceClass, data); + fTimestamp.put(resourceClass, new Date()); + } + else + { + StatusManager.getManager().handle(getStatus(), StatusManager.BLOCK); + } + notifyUI(); + } + }); + } + }); + + + } + + public interface Listener + { + void update(); + } + + /** Setup the listener that will be notified whenever externally + * visible state changes. The listener will always be invoked + * in the UI thread. 'control' is the control associated with + * the listener. The listener will not be called if the control + * is disposed. + */ + public void setUIListener(Listener listener, Control control) + { + fUIListener = listener; + fUIControl = control; + } + + private void notifyUI() + { + + final Control c = fUIControl; + if (c != null && !c.isDisposed()) + // There be dragons: if you try to use c.getDisplay() below, then this Runnable will not + // run until resource view is actually visible. And it will also block other interesting + // async/job runnables, like perspective switch runnable using during debug launch, + // causing launch to be stuck at random point. + // + Display.getDefault().asyncExec(new Runnable() { + + @Override + public void run() { + + if (!c.isDisposed()) + fUIListener.update(); + } + }); + + } + + @DsfServiceEventHandler + public void eventDispatched(IResumedDMEvent e) { + if (e instanceof IContainerResumedDMEvent) { + // This event is raised only in all-stop. It does not + // seem to be possible to issue -info-os in all-stop, + // regardless of whether target-async is in effect, and + // according to DSF folks, all-stop+target-async will + // not work anyway. So, we assume that no commands + // can be issued right now. + fAcceptingCommands = false; + notifyUI(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent e) { + if (e instanceof IContainerSuspendedDMEvent) { + fAcceptingCommands = true; + notifyUI(); + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS_7_5.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS_7_5.java new file mode 100644 index 00000000000..537c321216a --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBHardwareAndOS_7_5.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.service; + +import java.util.Hashtable; + +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfoOsInfo; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +/** + * @since 4.2 + */ +public class GDBHardwareAndOS_7_5 extends GDBHardwareAndOS implements IGDBHardwareAndOS2 { + + public GDBHardwareAndOS_7_5(DsfSession session) { + super(session); + } + + @Override + public boolean isAvailable() { + return getSessionInitializationComplete(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new RequestMonitor(ImmediateExecutor.getInstance(), requestMonitor) { + @Override + protected void handleSuccess() { + register(new String[] { IGDBHardwareAndOS2.class.getName() }, + new Hashtable()); + + requestMonitor.done(); + } + }); + } + + @Override + public void getResourceClasses(final IDMContext dmc, final DataRequestMonitor rm) { + + IGDBControl control = getServicesTracker().getService(IGDBControl.class); + if (control == null) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Service not available", null)); //$NON-NLS-1$ + return; + } + + CommandFactory factory = control.getCommandFactory(); + control.queueCommand(factory.createMIInfoOS(dmc), new DataRequestMonitor(getExecutor(), rm) { + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleSuccess() { + rm.setData(getData().getResourceClasses()); + rm.done(); + } + }); + } + + @Override + public void getResourcesInformation(final IDMContext dmc, final String resourceClass, final DataRequestMonitor rm) { + + IGDBControl control = getServicesTracker().getService(IGDBControl.class); + if (control == null) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Service not available", null)); //$NON-NLS-1$ + return; + } + + CommandFactory factory = control.getCommandFactory(); + control.queueCommand(factory.createMIInfoOS(dmc, resourceClass), new DataRequestMonitor(getExecutor(), rm) { + + @Override + protected void handleSuccess() { + rm.setData(getData().getResourcesInformation()); + rm.done(); + } + }); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java index 3d33d62131e..27501dff4ee 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java @@ -11,6 +11,7 @@ * Onur Akdemir (TUBITAK BILGEM-ITI) - Multi-process debugging (Bug 237306) * Marc Khouzam (Ericsson) - Support for GDB 7.4 (Bug 367788) * Marc Khouzam (Ericsson) - Include IGDBHardware service for the multicore visualizer (Bug 335027) + * Vladimir Prus (Mentor Graphics) - Support for OS resources. *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -62,6 +63,8 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { public static final String GDB_7_3_VERSION = "7.3"; //$NON-NLS-1$ /** @since 4.1 */ public static final String GDB_7_4_VERSION = "7.4"; //$NON-NLS-1$ + /** @since 4.2*/ + public static final String GDB_7_5_VERSION = "7.5"; //$NON-NLS-1$ private final String fVersion; @@ -229,6 +232,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { /** @since 4.1 */ protected IGDBHardwareAndOS createHardwareAndOSService(DsfSession session, ILaunchConfiguration config) { + if (GDB_7_5_VERSION.compareTo(fVersion) <= 0) { + return new GDBHardwareAndOS_7_5(session); + } return new GDBHardwareAndOS(session); } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java new file mode 100644 index 00000000000..256c67dd93f --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBHardwareAndOS2.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.service; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; + +/** + * Interface for accessing information about OS resources. + * + * EXPERIMENTAL. This class or interface has been added as part + * of a work in progress. There is no guarantee that this API will work or that + * it will remain the same. + * + * @since 4.2 + */ +public interface IGDBHardwareAndOS2 extends IGDBHardwareAndOS { + + /** Returns true if information returned by the other methods is available. + * If false is returned, it means that session initialization is in progress, + * and further request should be made after DataModelInitializedEvent is fired. + */ + public boolean isAvailable(); + + /** Information about OS resource class. */ + public interface IResourceClass + { + /** The id of this resource class, used in GDB requests. */ + public String getId(); + /** Human-friendly description of this class, suitable for direct display in UI. */ + public String getHumanDescription(); + } + + /** + * Return a list of OS resource classes GDB knows about + */ + public void getResourceClasses(IDMContext dmc, DataRequestMonitor rm); + + /** Information about OS resources of specific resource class + * This is conceptually a table. GDB provides column headers, and + * data rows, but does not provide any additional information about + * the meaning + */ + public interface IResourcesInformation + { + /** Return the names of the columns in resource table. */ + public String[] getColumnNames(); + /** Returns rows of the resource table. Each element is an array + * of the size equal to getColumnNames().length + */ + public String[][] getContent(); + } + + /** + * Return table describing resources of specified class. + */ + void getResourcesInformation(IDMContext dmc, String resourceClassId, DataRequestMonitor rm); +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index a706ee91c90..f62b44c1882 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -18,6 +18,7 @@ * Marc Khouzam (Ericsson) - New method for new MIGDBSetPythonPrintStack (Bug 367788) * Mathias Kunter - New methods for handling different charsets (Bug 370462) * Anton Gorenkov - A preference to use RTTI for variable types determination (Bug 377536) + * Vladimir Prus (Mentor Graphics) - Support for -info-os (Bug 360314) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service.command; @@ -118,6 +119,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetTargetCharset; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetTargetWideCharset; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBShowExitCode; import org.eclipse.cdt.dsf.mi.service.command.commands.MIInferiorTTYSet; +import org.eclipse.cdt.dsf.mi.service.command.commands.MIInfoOs; import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExec; import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExecConsole; import org.eclipse.cdt.dsf.mi.service.command.commands.MIInterpreterExecConsoleKill; @@ -181,6 +183,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIDataReadMemoryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIDataWriteMemoryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfoOsInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIStackInfoDepthInfo; @@ -708,6 +711,20 @@ public class CommandFactory { return new MIInferiorTTYSet(dmc, tty); } + /** + * @since 4.2 + */ + public ICommand createMIInfoOS(IDMContext ctx) { + return new MIInfoOs(ctx); + } + + /** + * @since 4.2 + */ + public ICommand createMIInfoOS(IDMContext ctx, String resourceClass) { + return new MIInfoOs(ctx, resourceClass); + } + public ICommand createMIInterpreterExec(IDMContext ctx, String interpreter, String cmd) { return new MIInterpreterExec(ctx, interpreter, cmd); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInfoOs.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInfoOs.java new file mode 100644 index 00000000000..a29a957c0ea --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIInfoOs.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2011 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfoOsInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; + +/** + * MIInfoOS + * + * -info-os [ type ] + * If no argument is supplied, the command returns a table of + * available operating-system-specific information types. If one of these + * types is supplied as an argument type, then the command returns a + * table of data of that type. + * + * The types of information available depend on the target operating system. + * @since 4.2 + */ +public class MIInfoOs extends MICommand { + + public MIInfoOs(IDMContext ctx) + { + super(ctx, "-info-os"); //$NON-NLS-1$ + } + + public MIInfoOs(IDMContext ctx, String resourceClass) + { + super(ctx, "-info-os", new String[]{resourceClass}); //$NON-NLS-1$ + specificResource = true; + } + + @Override + public MIInfoOsInfo getResult(MIOutput out) { + + return new MIInfoOsInfo(out, specificResource); + } + + private boolean specificResource = false; + +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIInfoOsInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIInfoOsInfo.java new file mode 100644 index 00000000000..9c9f5191812 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIInfoOsInfo.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 Mentor Graphics 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: + * Vladimir Prus (Mentor Graphics) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; + +/** + * Example output: + * + * (gdb) -info-os + * ^done,OSDataTable={nr_rows="9",nr_cols="3", + * hdr=[{width="10",alignment="-1",col_name="col0",colhdr="Type"}, + * {width="10",alignment="-1",col_name="col1",colhdr="Description"}, + * {width="10",alignment="-1",col_name="col2",colhdr="Title"}], + * body=[item={col0="processes",col1="Listing of all processes", + * col2="Processes"}, + * item={col0="procgroups",col1="Listing of all process groups", + * col2="Process groups"}, + * item={col0="threads",col1="Listing of all threads", + * col2="Threads"}, + * item={col0="files",col1="Listing of all file descriptors", + * col2="File descriptors"}, + * item={col0="sockets",col1="Listing of all internet-domain sockets", + * col2="Sockets"}, + * item={col0="shm",col1="Listing of all shared-memory regions", + * col2="Shared-memory regions"}, + * item={col0="semaphores",col1="Listing of all semaphores", + * col2="Semaphores"}, + * item={col0="msg",col1="Listing of all message queues", + * col2="Message queues"}, + * item={col0="modules",col1="Listing of all loaded kernel modules", + * col2="Kernel modules"}]} + * (gdb) -info-os processes + * ^done,OSDataTable={nr_rows="190",nr_cols="4", + * hdr=[{width="10",alignment="-1",col_name="col0",colhdr="pid"}, + * {width="10",alignment="-1",col_name="col1",colhdr="user"}, + * {width="10",alignment="-1",col_name="col2",colhdr="command"}, + * {width="10",alignment="-1",col_name="col3",colhdr="cores"}], + * body=[item={col0="1",col1="root",col2="/sbin/init",col3="0"}, + * item={col0="2",col1="root",col2="[kthreadd]",col3="1"}, + * item={col0="3",col1="root",col2="[ksoftirqd/0]",col3="0"}, + * ... + * item={col0="26446",col1="stan",col2="bash",col3="0"}, + * item={col0="28152",col1="stan",col2="bash",col3="1"}]} + * (gdb) + * + * @since 4.2 + */ +public class MIInfoOsInfo extends MIInfo { + + // The fields below are used for response with list of classes. + private IGDBHardwareAndOS2.IResourceClass[] resourceClasses; + + // The below fields are used only for data with specific resource class + private String[] columnNames; + private String[][] content; + + public MIInfoOsInfo(MIOutput record, boolean resourcesInformation) { + super(record); + if (isDone()) { + if (resourcesInformation) + parseResourcesInformation(); + else + parseResourceClasses(); + } + } + + public IGDBHardwareAndOS2.IResourcesInformation getResourcesInformation() + { + return new IGDBHardwareAndOS2.IResourcesInformation() { + + @Override + public String[][] getContent() { return content; } + + @Override + public String[] getColumnNames() { return columnNames; } + }; + } + + public IGDBHardwareAndOS2.IResourceClass[] getResourceClasses() + { + return resourceClasses; + } + + private void parseResourceClasses() + { + List classes = new ArrayList(); + + MITuple table = (MITuple)get(getMIOutput(), "OSDataTable"); //$NON-NLS-1$ + + MIList body = (MIList)get(table, "body"); //$NON-NLS-1$ + for (MIResult r: body.getMIResults()) { + MITuple row = (MITuple)r.getMIValue(); + + final String id = getString(row.getMIResults()[0]); + final String description = getString(row.getMIResults()[2]); + + classes.add(new IGDBHardwareAndOS2.IResourceClass() { + + @Override + public String getId() { return id; } + + @Override + public String getHumanDescription() { return description; } + + }); + } + + resourceClasses = classes.toArray(new IGDBHardwareAndOS2.IResourceClass[classes.size()]); + } + + private void parseResourcesInformation() + { + MITuple table = (MITuple) get(getMIOutput(), "OSDataTable"); //$NON-NLS-1$ + + MIList header = (MIList) get(table, "hdr"); //$NON-NLS-1$ + columnNames = new String[header.getMIValues().length]; + int i = 0; + for (MIValue v : header.getMIValues()) { + MITuple column = (MITuple) v; + String columnName = ((MIConst) get(column, "colhdr")).getString(); //$NON-NLS-1$ + columnNames[i++] = Character.toUpperCase(columnName.charAt(0)) + columnName.substring(1); + } + + + MIList body = (MIList) get(table, "body"); //$NON-NLS-1$ + if (body == null) + { + content = new String[0][]; + return; + } + + content = new String[body.getMIResults().length][]; + i = 0; + for (MIResult r : body.getMIResults()) { + MITuple row = (MITuple) r.getMIValue(); + assert row.getMIResults().length == columnNames.length; + String[] rowStrings = new String[row.getMIResults().length]; + int j = 0; + for (MIResult r2 : row.getMIResults()) + { + rowStrings[j] = ((MIConst) r2.getMIValue()).getString(); + ++j; + } + content[i++] = rowStrings; + } + } + + private MIValue get(MIResult[] results, String name) { + for (MIResult r : results) + if (r.getVariable().equals(name)) + return r.getMIValue(); + return null; + } + + private MIValue get(MIOutput output, String name) { + return get(output.getMIResultRecord().getMIResults(), name); + } + + private MIValue get(MITuple tuple, String name) { + return get(tuple.getMIResults(), name); + } + + private String getString(MIValue value) + { + return ((MIConst)value).getString(); + } + + private String getString(MIResult result) + { + return getString(result.getMIValue()); + } +} -- cgit v1.2.3