From e8936ad9d21cf08d854b36cb6a0610aab0194179 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Mon, 15 Mar 2010 17:44:56 +0100
Subject: [PATCH] debugger: code cosmetics for custom displays

---
 share/qtcreator/gdbmacros/dumper.py     | 36 +++++++++++++++++++++++++
 share/qtcreator/gdbmacros/gdbmacros.py  | 32 +++++++++++++++++-----
 src/plugins/debugger/watchhandler.cpp   | 36 +++++++++++++++++--------
 src/plugins/debugger/watchhandler.h     |  9 ++++---
 tests/manual/gdbdebugger/simple/app.cpp | 23 ++++++++++++++++
 5 files changed, 116 insertions(+), 20 deletions(-)

diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py
index e5c5a6a4a85..e4e534d6a38 100644
--- a/share/qtcreator/gdbmacros/dumper.py
+++ b/share/qtcreator/gdbmacros/dumper.py
@@ -439,6 +439,32 @@ def findFirstZero(p, max):
         p = p + 1
     return -1
 
+
+def extractCharArray(p, maxsize):
+    t = gdb.lookup_type("unsigned char").pointer()
+    p = p.cast(t)
+    i = findFirstZero(p, maxsize)
+    limit = select(i < 0, maxsize, i)
+    s = ""
+    for i in xrange(limit):
+        s += "%c" % int(p.dereference())
+        p += 1
+    if i == maxsize:
+        s += "..."
+    return s
+
+def extractByteArray(value):
+    d_ptr = value['d'].dereference()
+    data = d_ptr['data']
+    size = d_ptr['size']
+    alloc = d_ptr['alloc']
+    check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
+    checkRef(d_ptr["ref"])
+    if size > 0:
+        checkAccess(data, 4)
+        checkAccess(data + size) == 0
+    return extractCharArray(data, 100)
+
 def encodeCharArray(p, maxsize, size = -1):
     t = gdb.lookup_type("unsigned char").pointer()
     p = p.cast(t)
@@ -803,6 +829,8 @@ SalCommand()
 #
 #######################################################################
 
+StopDisplay, DisplayImage1, DisplayString, DisplayImage, DisplayProcess = range(5)
+
 class Dumper:
     def __init__(self):
         self.output = ""
@@ -907,6 +935,14 @@ class Dumper:
             str = encodeString(value)
             self.put('valueencoded="%d",value="%s",' % (7, str))
 
+    def putDisplay(self, format, value = None, cmd = None):
+        self.put('editformat="%s",' % format)
+        if cmd is None:
+            if not value is None:
+                self.put('editvalue="%s",' % value)
+        else:
+            self.put('editvalue="%s|%s",' % (cmd, value))
+
     def putByteArrayValue(self, value):
         str = encodeByteArray(value)
         self.put('valueencoded="%d",value="%s",' % (6, str))
diff --git a/share/qtcreator/gdbmacros/gdbmacros.py b/share/qtcreator/gdbmacros/gdbmacros.py
index 7255fed290e..b7769c3c930 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.py
+++ b/share/qtcreator/gdbmacros/gdbmacros.py
@@ -406,7 +406,7 @@ def qdump__QImage(d, item):
         d.endChildren()
     format = d.itemFormat(item)
     if format == 0:
-        d.putField("editformat", 0)  # Magic marker for "delete widget"
+        d.putDisplay(StopDisplay)
     elif format == 1:
         if False:
             # Take four bytes at a time, this is critical for performance.
@@ -428,11 +428,8 @@ def qdump__QImage(d, item):
             p = bits.cast(gdb.lookup_type("unsigned char").pointer())
             gdb.execute("dump binary memory %s %s %s" %
                 (filename, cleanAddress(p), cleanAddress(p + nbytes)))
-            d.putField("editformat", 3)  # Magic marker for external "QImage" data.
-            d.beginItem("editvalue")
-            d.put(" %d %d %d %s" % (d_ptr["width"], d_ptr["height"],
-                d_ptr["format"], filename))
-            d.endItem()
+            d.putDisplay(DisplayImage, " %d %d %d %s"
+                % (d_ptr["width"], d_ptr["height"], d_ptr["format"], filename))
 
 
 def qdump__QLinkedList(d, item):
@@ -1979,3 +1976,26 @@ def qdump__TLitC(d, item):
     d.putNumChild(0)
     d.putValue(encodeSymbianString(base, size), "7")
 
+
+#######################################################################
+#
+# Display Test
+#
+#######################################################################
+
+if False:
+    def qdump__Function(d, item):
+        min = item.value["min"]
+        max = item.value["max"]
+        var = extractByteArray(item.value["var"])
+        f = extractByteArray(item.value["f"])
+        d.putValue("%s, %s=%f..%f" % (f, var, min, max))
+        d.putNumChild(0)
+        d.putField("typeformats", "Normal,Displayed");
+        format = d.itemFormat(item)
+        if format == 0:
+            d.putDisplay(StopDisplay)
+        elif format == 1:
+            input = "plot [%s=%f:%f] %s" % (var, min, max, f)
+            d.putDisplay(DisplayProcess, input, "gnuplot")
+
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index b8c0f1e64fc..d046c9fcedf 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -42,6 +42,7 @@
 #include <QtCore/QDebug>
 #include <QtCore/QEvent>
 #include <QtCore/QFile>
+#include <QtCore/QProcess>
 #include <QtCore/QTextStream>
 #include <QtCore/QTimer>
 #include <QtCore/QtAlgorithms>
@@ -1209,12 +1210,12 @@ void WatchHandler::cleanup()
     m_watchers->m_fetchTriggered.clear();
     m_tooltips->m_fetchTriggered.clear();
 #if 1
-    for (EditWindows::ConstIterator it = m_editWindows.begin();
-            it != m_editWindows.end(); ++it) {
+    for (EditHandlers::ConstIterator it = m_editHandlers.begin();
+            it != m_editHandlers.end(); ++it) {
         if (!it.value().isNull())
             delete it.value();
     }
-    m_editWindows.clear();
+    m_editHandlers.clear();
 #endif
 }
 
@@ -1348,21 +1349,21 @@ static void swapEndian(char *d, int nchar)
 
 void WatchHandler::showEditValue(const WatchData &data)
 {
-    QWidget *w = m_editWindows.value(data.iname);
+    QObject *w = m_editHandlers.value(data.iname);
     if (data.editformat == 0x0) {
-        m_editWindows.remove(data.iname);
+        m_editHandlers.remove(data.iname);
         delete w;
-    } else if (data.editformat == 0x1 || data.editformat == 0x3) {
+    } else if (data.editformat == 1 || data.editformat == 3) {
         // QImage
         if (!w) {
             w = new QLabel;
-            m_editWindows[data.iname] = w;
+            m_editHandlers[data.iname] = w;
         }
         if (QLabel *l = qobject_cast<QLabel *>(w)) {
             int width, height, format;
             QByteArray ba;
             uchar *bits;
-            if (data.editformat == 0x1) {
+            if (data.editformat == 1) {
                 ba = QByteArray::fromHex(data.editvalue);
                 const int *header = (int *)(ba.data());
                 swapEndian(ba.data(), ba.size());
@@ -1370,7 +1371,7 @@ void WatchHandler::showEditValue(const WatchData &data)
                 width = header[0];
                 height = header[1];
                 format = header[2];
-            } else { // data.editformat == 0x3
+            } else { // data.editformat == 3
                 QTextStream ts(data.editvalue);
                 QString fileName;
                 ts >> width >> height >> format >> fileName;
@@ -1384,11 +1385,11 @@ void WatchHandler::showEditValue(const WatchData &data)
             l->resize(width, height);
             l->show();
         }
-    } else if (data.editformat == 0x2) {
+    } else if (data.editformat == 2) {
         // QString
         if (!w) {
             w = new QTextEdit;
-            m_editWindows[data.iname] = w;
+            m_editHandlers[data.iname] = w;
         }
         QByteArray ba = QByteArray::fromHex(data.editvalue);
         QString str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
@@ -1398,6 +1399,19 @@ void WatchHandler::showEditValue(const WatchData &data)
             t->resize(400, 200);
             t->show();
         }
+    } else if (data.editformat == 4) {
+        // Generic Process.
+        int pos = data.editvalue.indexOf('|');
+        QByteArray cmd = data.editvalue.left(pos);
+        QByteArray input = data.editvalue.mid(pos + 1);
+        QProcess *p = qobject_cast<QProcess *>(w);
+        if (!p) {
+            p = new QProcess;
+            p->start(cmd);
+            p->waitForStarted();
+            m_editHandlers[data.iname] = p;
+        }
+        p->write(input + "\n");
     } else {
         QTC_ASSERT(false, qDebug() << "Display format: " << data.editformat);
     }
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index e2f4ddf0f93..d6b26ef6bdf 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -282,14 +282,17 @@ private:
     bool m_expandPointers;
     bool m_inChange;
 
-    typedef QMap<QString, QPointer<QWidget> > EditWindows;
-    EditWindows m_editWindows;
+    // QWidgets and QProcesses taking care of special displays.
+    typedef QMap<QString, QPointer<QObject> > EditHandlers;
+    EditHandlers m_editHandlers;
 
     QHash<QByteArray, int> m_watcherNames;
     QByteArray watcherName(const QByteArray &exp);
     QHash<QString, int> m_typeFormats;
     QHash<QString, int> m_individualFormats;
-    QSet<QByteArray> m_expandedINames;  // Those expanded in the treeview.
+
+    // Items expanded in the Locals & Watchers view.
+    QSet<QByteArray> m_expandedINames; 
 
     WatchModel *m_locals;
     WatchModel *m_watchers;
diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp
index 18540d2cfb3..36b3940701e 100644
--- a/tests/manual/gdbdebugger/simple/app.cpp
+++ b/tests/manual/gdbdebugger/simple/app.cpp
@@ -361,6 +361,28 @@ void testQImage()
     pain.end();
 }
 
+struct Function
+{
+    Function(QByteArray var, QByteArray f, double min, double max)
+      : var(var), f(f), min(min), max(max) {}
+    QByteArray var;
+    QByteArray f;
+    double min;
+    double max;
+};
+
+void testFunction()
+{
+    Function func("x", "sin(x)", 0, 1);
+    func.max = 10;
+    func.f = "cos(x)";
+    func.max = 4;
+    func.max = 5;
+    func.max = 6;
+    func.max = 7;
+    func.max = 8;
+}
+
 void testIO()
 {
     qDebug() << "qDebug() 1";
@@ -1467,6 +1489,7 @@ int main(int argc, char *argv[])
     list2 << 0;
 
     testQStandardItemModel();
+    testFunction();
     testQImage();
     testNoArgumentName(1, 2, 3);
     testIO();
-- 
GitLab