From eb75f40a9883b437f1e1ce722a769a450a905d39 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Fri, 25 Jun 2010 09:07:14 +0200
Subject: [PATCH] debugger: allow per item selection of display method in
 Locals&Watchers

---
 share/qtcreator/gdbmacros/dumper.py    | 135 +++++++++++++++----------
 share/qtcreator/gdbmacros/gdbmacros.py |  16 +--
 src/plugins/debugger/gdb/gdbengine.cpp |  12 ++-
 src/plugins/debugger/watchhandler.cpp  |  30 ++++--
 src/plugins/debugger/watchhandler.h    |  12 +--
 src/plugins/debugger/watchwindow.cpp   |  15 +--
 6 files changed, 135 insertions(+), 85 deletions(-)

diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py
index 3657b3e03cd..2be8128bd95 100644
--- a/share/qtcreator/gdbmacros/dumper.py
+++ b/share/qtcreator/gdbmacros/dumper.py
@@ -771,6 +771,49 @@ class Item:
         self.name = name
 
 
+#######################################################################
+#
+# SetupCommand
+#
+#######################################################################
+
+# This is a mapping from 'type name' to 'display alternatives'.
+
+qqDumpers = {}
+qqFormats = {}
+
+
+class SetupCommand(gdb.Command):
+    """Setup Creator Pretty Printing"""
+
+    def __init__(self):
+        super(SetupCommand, self).__init__("bbsetup", gdb.COMMAND_OBSCURE)
+
+    def invoke(self, args, from_tty):
+        module = sys.modules[__name__]
+        for key, value in module.__dict__.items():
+            if key.startswith("qdump__"):
+                name = key[7:]
+                qqDumpers[name] = value
+            elif key.startswith("qform__"):
+                name = key[7:]
+                formats = ""
+                try:
+                    formats = value()
+                except:
+                    pass
+                qqFormats[name] = formats
+        result = "dumpers=["
+        # Too early: ns = qtNamespace()
+        for key, value in qqFormats.items():
+            result += '{type="%s",formats="%s"},' % (key, value)
+        result += ']'
+        #result += '],namespace="%s"' % ns
+        print(result)
+
+SetupCommand()
+
+
 #######################################################################
 #
 # FrameCommand
@@ -778,7 +821,7 @@ class Item:
 #######################################################################
 
 class FrameCommand(gdb.Command):
-    """Do fancy stuff. Usage bb --verbose expandedINames"""
+    """Do fancy stuff."""
 
     def __init__(self):
         super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE)
@@ -846,7 +889,6 @@ class Dumper:
         self.currentValueEncoding = None
         self.currentType = None
         self.currentTypePriority = -100
-        self.dumpers = ""
         self.typeformats = {}
         self.formats = {}
         self.expandedINames = ""
@@ -890,28 +932,6 @@ class Dumper:
         #warn("VARIABLES: %s" % varList)
         #warn("EXPANDED INAMES: %s" % self.expandedINames)
         module = sys.modules[__name__]
-        self.dumpers = {}
-
-        if False:
-            for key, value in module.__dict__.items():
-                if key.startswith("qdump__"):
-                    self.dumpers += '"' + key[7:] + '",'
-            output = "dumpers=[%s]," % self.dumpers
-            #output += "qtversion=[%d,%d,%d]"
-            #output += "qtversion=[4,6,0],"
-            output += "namespace=\"%s\"," % qtNamespace()
-            output += "dumperversion=\"2.0\","
-            output += "sizes=[],"
-            output += "expressions=[]"
-            output += "]"
-            print output
-            return
-
-
-        if self.useFancy:
-            for key, value in module.__dict__.items():
-                if key.startswith("qdump__"):
-                    self.dumpers[key[7:]] = value
 
         #
         # Locals
@@ -1184,7 +1204,7 @@ class Dumper:
             self.putNumChild(0)
 
     def itemFormat(self, item):
-        format = self.formats.get(str(cleanAddress(item.value.address)))
+        format = self.formats.get(item.iname)
         if format is None:
             format = self.typeformats.get(stripClassTag(str(item.value.type)))
         return format
@@ -1224,6 +1244,7 @@ class Dumper:
 
         value = item.value
         type = value.type
+        format = self.itemFormat(item)
 
         if type.code == gdb.TYPE_CODE_REF:
             try:
@@ -1243,62 +1264,66 @@ class Dumper:
             type.strip_typedefs().unqualified()).replace("::", "__")
 
         #warn(" STRIPPED: %s" % strippedType)
-        #warn(" DUMPERS: %s" % self.dumpers)
-        #warn(" DUMPERS: %s" % (strippedType in self.dumpers))
+        #warn(" DUMPERS: %s" % (strippedType in qqDumpers))
 
         if isSimpleType(type.unqualified()):
             #warn("IS SIMPLE: %s " % type)
+            #self.putAddress(value.address)
             self.putType(item.value.type)
             self.putValue(value)
             self.putNumChild(0)
 
-        elif strippedType in self.dumpers:
+        elif ((format is None) or (format >= 1)) and strippedType in qqDumpers:
             #warn("IS DUMPABLE: %s " % type)
+            #self.putAddress(value.address)
             self.putType(item.value.type)
-            self.dumpers[strippedType](self, item)
+            qqDumpers[strippedType](self, item)
             #warn(" RESULT: %s " % self.output)
 
         elif type.code == gdb.TYPE_CODE_ENUM:
             #warn("GENERIC ENUM: %s" % value)
+            #self.putAddress(value.address)
             self.putType(item.value.type)
             self.putValue(value)
             self.putNumChild(0)
 
 
         elif type.code == gdb.TYPE_CODE_PTR:
+            warn("POINTER: %s" % format)
             isHandled = False
 
-            format = self.itemFormat(item)
-
             if not format is None:
                 self.putAddress(value.address)
                 self.putType(item.value.type)
-                self.putNumChild(0)
                 isHandled = True
+                if format == 0:
+                    # Bald pointer.
+                    self.putPointerValue(value.address)
+                    self.putNumChild(1)
+                elif format == 1 or format == 2:
+                    # Latin1 or UTF-8
+                    f = select(format == 1, Hex2EncodedLatin1, Hex2EncodedUtf8)
+                    self.putValue(encodeCharArray(value, 100), f)
+                    self.putNumChild(0)
+                elif format == 3:
+                    # UTF-16.
+                    self.putValue(encodeChar2Array(value, 100), Hex4EncodedBigEndian)
+                    self.putNumChild(0)
+                elif format == 4:
+                    # UCS-4:
+                    self.putValue(encodeChar4Array(value, 100), Hex8EncodedBigEndian)
+                    self.putNumChild(0)
 
-            if format == 0:
-                # Bald pointer.
-                self.putPointerValue(value.address)
-            elif format == 1 or format == 2:
-                # Latin1 or UTF-8
-                f = select(format == 1, Hex2EncodedLatin1, Hex2EncodedUtf8)
-                self.putValue(encodeCharArray(value, 100), f)
-            elif format == 3:
-                # UTF-16.
-                self.putValue(encodeChar2Array(value, 100), Hex4EncodedBigEndian)
-            elif format == 4:
-                # UCS-4:
-                self.putValue(encodeChar4Array(value, 100), Hex8EncodedBigEndian)
-
-            strippedType = str(type.strip_typedefs()) \
-                .replace("(anonymous namespace)", "")
-            if (not isHandled) and strippedType.find("(") != -1:
-                # A function pointer.
-                self.putValue(str(item.value))
-                self.putAddress(value.address)
-                self.putType(item.value.type)
-                self.putNumChild(0)
-                isHandled = True
+            if (not isHandled):
+                strippedType = str(type.strip_typedefs()) \
+                    .replace("(anonymous namespace)", "")
+                if strippedType.find("(") != -1:
+                    # A function pointer.
+                    self.putValue(str(item.value))
+                    self.putAddress(value.address)
+                    self.putType(item.value.type)
+                    self.putNumChild(0)
+                    isHandled = True
 
             if (not isHandled) and self.useFancy:
                 if isNull(value):
diff --git a/share/qtcreator/gdbmacros/gdbmacros.py b/share/qtcreator/gdbmacros/gdbmacros.py
index 8296d8e4da9..d675d9e1db6 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.py
+++ b/share/qtcreator/gdbmacros/gdbmacros.py
@@ -66,7 +66,7 @@ def qdump__QAbstractItem(d, item):
                         rr = call(m, "rowCount(child)")
                         cc = call(m, "columnCount(child)")
                         d.putNumChild(rr * cc)
-                        d.putField("value",
+                        d.putValue(
                             call(m, "data(child, Qt::DisplayRole).toString())"), 6)
 
             #with SubItem(d):
@@ -424,6 +424,8 @@ def qdump__QList(d, item):
                     d.putItem(Item(pp, item.iname, i))
                 p += 1
 
+def qdump__QImage():
+    return "Normal,Displayed";
 
 def qdump__QImage(d, item):
     painters = item.value["painters"]
@@ -436,7 +438,6 @@ def qdump__QImage(d, item):
         d.putValue("(%dx%d)" % (d_ptr["width"], d_ptr["height"]))
     bits = d_ptr["data"]
     nbytes = d_ptr["nbytes"]
-    d.putField("typeformats", "Normal,Displayed");
     d.putNumChild(0)
     #d.putNumChild(1)
     if d.isExpanded(item):
@@ -447,9 +448,9 @@ def qdump__QImage(d, item):
                 d.putNumChild(0)
                 d.putValue("size: %s bytes" % nbytes);
     format = d.itemFormat(item)
-    if format == 0:
+    if format == 1:
         d.putDisplay(StopDisplay)
-    elif format == 1:
+    elif format == 2:
         if False:
             # Take four bytes at a time, this is critical for performance.
             # In fact, even four at a time is too slow beyond 100x100 or so.
@@ -1458,15 +1459,16 @@ def qdump__QSizeF(d, item):
 def qdump__QStack(d, item):
     qdump__QVector(d, item)
 
+def qform__QString():
+    return "Inline,Separate Window";
 
 def qdump__QString(d, item):
     d.putStringValue(item.value)
     d.putNumChild(0)
-    d.putField("typeformats", "Normal,Displayed");
     format = d.itemFormat(item)
-    if format == 0:
+    if format == 1:
         d.putDisplay(StopDisplay)
-    elif format == 1:
+    elif format == 2:
         d.putField("editformat", 2)
         str = encodeString(item.value)
         d.putField("editvalue", str)
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index d6f75bade4e..b63d3632fb3 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -1525,6 +1525,16 @@ void GdbEngine::handleHasPython(const GdbResponse &response)
 {
     if (response.resultClass == GdbResultDone) {
         m_hasPython = true;
+        GdbMi contents = response.data.findChild("consolestreamoutput");
+        GdbMi data;
+        data.fromStringMultiple(contents.data());
+        const GdbMi dumpers = data.findChild("dumpers");
+        foreach (const GdbMi &dumper, dumpers.children()) {
+            QString type = _(dumper.findChild("type").data());
+            QStringList formats(tr("Raw structure"));
+            formats.append(_(dumper.findChild("formats").data()).split(_(",")));
+            watchHandler()->addTypeFormats(type, formats);
+        }
     } else {
         m_hasPython = false;
         if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperLoadedByGdbPreload
@@ -4125,7 +4135,7 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
             "\"python execfile('" + dumperSourcePath + "gdbmacros.py')\"",
         NonCriticalResponse);
 
-    postCommand("-interpreter-exec console \"help bb\"",
+    postCommand("-interpreter-exec console \"bbsetup\"",
         CB(handleHasPython));
 
     return true;
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 92b71279f61..ddf6f9e0238 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -613,7 +613,8 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
                         return QVariant(QLatin1Char('*') + item->parent->name);
                     return data.name;
                 case 1: {
-                    int format = m_handler->m_individualFormats.value(data.addr, -1);
+                    int format =
+                        m_handler->m_individualFormats.value(data.iname, -1);
                     if (format == -1)
                         format = m_handler->m_typeFormats.value(data.type, -1);
                     return truncateValue(formattedValue(data, format));
@@ -650,26 +651,30 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
         case LocalsExpandedRole:
             return m_handler->m_expandedINames.contains(data.iname);
 
-        case LocalsTypeFormatListRole:
-            if (!data.typeFormats.isEmpty())
-                return data.typeFormats.split(',');
+        case LocalsTypeFormatListRole: {
             if (isIntType(data.type))
                 return QStringList() << tr("decimal") << tr("hexadecimal")
                     << tr("binary") << tr("octal");
             if (data.type.endsWith(QLatin1Char('*')))
                 return QStringList()
-                    << tr("Bald pointer")
+                    << tr("Raw pointer")
                     << tr("Latin1 string")
                     << tr("UTF8 string")
                     << tr("UTF16 string")
                     << tr("UCS4 string");
-            break;
+            // Hack: Compensate for namespaces.
+            QString type = data.type;
+            int pos = type.indexOf("::Q");
+            if (pos >= 0 && type.count(':') == 2)
+                type = type.mid(pos + 2);
+            return m_handler->m_reportedTypeFormats.value(type);
+        }
 
         case LocalsTypeFormatRole:
             return m_handler->m_typeFormats.value(data.type, -1);
 
         case LocalsIndividualFormatRole:
-            return m_handler->m_individualFormats.value(data.addr, -1);
+            return m_handler->m_individualFormats.value(data.iname, -1);
 
         case LocalsRawValueRole:
             return data.value;
@@ -772,9 +777,9 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
         case LocalsIndividualFormatRole: {
             const int format = value.toInt();
             if (format == -1) {
-                m_handler->m_individualFormats.remove(data.addr);
+                m_handler->m_individualFormats.remove(data.iname);
             } else {
-                m_handler->m_individualFormats[data.addr] = format;
+                m_handler->m_individualFormats[data.iname] = format;
             }
             engine()->updateWatchData(data);
             break;
@@ -1503,7 +1508,7 @@ int WatchHandler::format(const QByteArray &iname) const
 {
     int result = -1;
     if (const WatchData *item = findItem(iname)) {
-        int result = m_individualFormats.value(iname, -1);
+        int result = m_individualFormats.value(item->iname, -1);
         if (result == -1)
             result = m_typeFormats.value(item->type, -1);
     }
@@ -1561,5 +1566,10 @@ QByteArray WatchHandler::individualFormatRequests() const
     return ba;
 }
 
+void WatchHandler::addTypeFormats(const QString &type, const QStringList &formats)
+{
+    m_reportedTypeFormats.insert(type, formats);
+}
+
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index a973b884930..0ba82d25d6e 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -36,12 +36,8 @@
 #include <QtCore/QObject>
 #include <QtCore/QHash>
 #include <QtCore/QSet>
+#include <QtCore/QStringList>
 #include <QtCore/QAbstractItemModel>
-#include <QtScript/QScriptValue>
-
-QT_BEGIN_NAMESPACE
-class QDebug;
-QT_END_NAMESPACE
 
 namespace Debugger {
 namespace Internal {
@@ -49,6 +45,7 @@ namespace Internal {
 class DebuggerEngine;
 class WatchItem;
 class WatchHandler;
+class WatchData;
 
 enum WatchType
 {
@@ -174,6 +171,8 @@ public:
     static QString watcherEditPlaceHolder();
     int format(const QByteArray &iname) const;
 
+    void addTypeFormats(const QString &type, const QStringList &formats);
+
 private:
     friend class WatchModel;
 
@@ -195,7 +194,8 @@ private:
     QHash<QByteArray, int> m_watcherNames;
     QByteArray watcherName(const QByteArray &exp);
     QHash<QString, int> m_typeFormats;
-    QHash<QByteArray, int> m_individualFormats;
+    QHash<QByteArray, int> m_individualFormats; // Indexed by iname.
+    QHash<QString, QStringList> m_reportedTypeFormats;
 
     // Items expanded in the Locals & Watchers view.
     QSet<QByteArray> m_expandedINames; 
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index 17783f8ee4a..67357efccd4 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -231,7 +231,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
         if (alternativeFormats.isEmpty()) {
             typeFormatMenu.setEnabled(false);
         } else {
-            clearTypeFormatAction = typeFormatMenu.addAction(tr("Clear"));
+            clearTypeFormatAction = typeFormatMenu.addAction(tr("Automatic"));
             clearTypeFormatAction->setEnabled(typeFormat != -1);
             clearTypeFormatAction->setCheckable(true);
             clearTypeFormatAction->setChecked(typeFormat == -1);
@@ -254,13 +254,14 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     QMenu individualFormatMenu;
     QList<QAction *> individualFormatActions;
     QAction *clearIndividualFormatAction = 0;
-    if (idx.isValid() && address) {
+    if (idx.isValid()) {
         individualFormatMenu.setTitle(
-            tr("Change Format for Object at 0x%1").arg(address, 0, 16));
+            tr("Change Format for Object Named \"%1\"").arg(mi0.data().toString()));
         if (alternativeFormats.isEmpty()) {
             individualFormatMenu.setEnabled(false);
         } else {
-            clearIndividualFormatAction = individualFormatMenu.addAction(tr("Clear"));
+            clearIndividualFormatAction
+                = individualFormatMenu.addAction(tr("Automatic"));
             clearIndividualFormatAction->setEnabled(individualFormat != -1);
             clearIndividualFormatAction->setCheckable(true);
             clearIndividualFormatAction->setChecked(individualFormat == -1);
@@ -302,10 +303,12 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
 
     if (canShowMemory && address)
         actOpenMemoryEditAtVariableAddress =
-            new QAction(tr("Open Memory Editor at Object's Address (0x%1)").arg(address, 0, 16), &menu);
+            new QAction(tr("Open Memory Editor at Object's Address (0x%1)")
+                .arg(address, 0, 16), &menu);
     if (createPointerActions)
         actOpenMemoryEditAtPointerValue =
-            new QAction(tr("Open Memory Editor at Referenced Address (0x%1)").arg(pointerValue, 0, 16), &menu);
+            new QAction(tr("Open Memory Editor at Referenced Address (0x%1)")
+                .arg(pointerValue, 0, 16), &menu);
     menu.addSeparator();
 
     QAction *actSetWatchPointAtVariableAddress = 0;
-- 
GitLab