From 452f108ac744c69b42bc2565f608338bdb8fffbc Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Mon, 31 Aug 2009 09:14:04 +0200
Subject: [PATCH] debugger: fixes and improvements related to the Locals
 display

Split the concepts 'enabled' and 'editable' in the dumper output
Disable "<not in scope>" entries, also fix their type.
Fix glitch in type beautification for display
Find reason for failing bulk updates.
---
 share/qtcreator/gdbmacros/gdbmacros.cpp   | 130 ++++++++--------
 src/plugins/debugger/debuggermanager.cpp  |  10 +-
 src/plugins/debugger/gdb/gdbengine.cpp    |  52 +++++--
 src/plugins/debugger/gdb/gdbengine.h      |   2 +-
 src/plugins/debugger/idebuggerengine.h    |   1 -
 src/plugins/debugger/shared/backtrace.cpp |  87 +++++++++++
 src/plugins/debugger/shared/backtrace.h   |  43 +++++
 src/plugins/debugger/shared/shared.pri    |   4 +
 src/plugins/debugger/watchhandler.cpp     | 181 ++++++++++++++++------
 src/plugins/debugger/watchhandler.h       |  13 +-
 src/plugins/debugger/watchutils.cpp       |  34 ++--
 src/plugins/debugger/watchutils.h         |   4 +-
 src/plugins/debugger/watchwindow.cpp      |  11 +-
 src/plugins/debugger/watchwindow.h        |   1 +
 tests/manual/gdbdebugger/simple/app.cpp   |  14 ++
 15 files changed, 428 insertions(+), 159 deletions(-)
 create mode 100644 src/plugins/debugger/shared/backtrace.cpp
 create mode 100644 src/plugins/debugger/shared/backtrace.h

diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index b9a658ea42d..92c8f707a3c 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -500,10 +500,10 @@ struct QDumper
     // the dumper arguments
     int protocolVersion;   // dumper protocol version
     int token;             // some token to show on success
-    const char *outertype; // object type
+    const char *outerType; // object type
     const char *iname;     // object name used for display
     const char *exp;       // object expression
-    const char *innertype; // 'inner type' for class templates
+    const char *innerType; // 'inner type' for class templates
     const void *data;      // pointer to raw data
     bool dumpChildren;     // do we want to see children?
 
@@ -543,7 +543,7 @@ QDumper::~QDumper()
 
 void QDumper::setupTemplateParameters()
 {
-    char *s = const_cast<char *>(innertype);
+    char *s = const_cast<char *>(innerType);
 
     int templateParametersCount = 1;
     templateParameters[0] = s;
@@ -734,7 +734,7 @@ void QDumper::endHash()
 void QDumper::putEllipsis()
 {
     putCommaIfNeeded();
-    put("{name=\"<incomplete>\",value=\"\",type=\"").put(innertype).put("\"}");
+    put("{name=\"<incomplete>\",value=\"\",type=\"").put(innerType).put("\"}");
 }
 
 void QDumper::putItemCount(const char *name, int count)
@@ -875,13 +875,11 @@ void QDumper::putHash(const char *name, QChar value)
 #define DUMPUNKNOWN_MESSAGE "<not in scope>"
 static void qDumpUnknown(QDumper &d, const char *why = 0)
 {
-    //d.putItem("iname", d.iname);
-    //d.putItem("addr", d.data);
     if (!why)
         why = DUMPUNKNOWN_MESSAGE;
     d.putItem("value", why);
-    d.putItem("type", d.outertype);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
+    d.putItem("valueenabled", "false");
     d.putItem("numchild", "0", d.currentChildNumChild);
     d.disarm();
 }
@@ -983,7 +981,7 @@ void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
             if (startsWith(type, "QList<")) {
                 const QListData *ldata = reinterpret_cast<const QListData*>(addr);
                 d.putItemCount("value", ldata->size());
-                d.putItem("valuedisabled", "true");
+                d.putItem("valueeditable", "false");
                 d.putItem("numchild", ldata->size());
             }
             break;
@@ -1638,12 +1636,12 @@ static void qDumpQList(QDumper &d)
 
     int n = nn;
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
         unsigned innerSize = d.extraInt[0];
-        bool innerTypeIsPointer = isPointerType(d.innertype);
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        bool innerTypeIsPointer = isPointerType(d.innerType);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
 
         // The exact condition here is:
         //  QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
@@ -1651,11 +1649,11 @@ static void qDumpQList(QDumper &d)
         // in the frontend.
         // So as first approximation only do the 'isLarge' check:
         bool isInternal = innerSize <= int(sizeof(void*))
-            && isMovableType(d.innertype);
+            && isMovableType(d.innerType);
         d.putItem("internal", (int)isInternal);
         if (n > 1000)
             n = 1000;
-        d.beginChildren(n ? d.innertype : 0);
+        d.beginChildren(n ? d.innerType : 0);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
             if (innerTypeIsPointer) {
@@ -1671,13 +1669,13 @@ static void qDumpQList(QDumper &d)
             } else {
                 void *p = ldata.d->array + i + pdata->begin;
                 if (isInternal) {
-                    //qDumpInnerValue(d, d.innertype, p);
+                    //qDumpInnerValue(d, d.innerType, p);
                     d.putItem("addr", p);
-                    qDumpInnerValueHelper(d, d.innertype, p);
+                    qDumpInnerValueHelper(d, d.innerType, p);
                 } else {
-                    //qDumpInnerValue(d, d.innertype, deref(p));
+                    //qDumpInnerValue(d, d.innerType, deref(p));
                     d.putItem("addr", deref(p));
-                    qDumpInnerValueHelper(d, d.innertype, deref(p));
+                    qDumpInnerValueHelper(d, d.innerType, deref(p));
                 }
             }
             d.endHash();
@@ -1702,23 +1700,23 @@ static void qDumpQLinkedList(QDumper &d)
 
     int n = nn;
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
         //unsigned innerSize = d.extraInt[0];
-        //bool innerTypeIsPointer = isPointerType(d.innertype);
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        //bool innerTypeIsPointer = isPointerType(d.innerType);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
         const char *stripped =
-            isPointerType(d.innertype) ? strippedInnerType.data() : 0;
+            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
 
         if (n > 1000)
             n = 1000;
-        d.beginChildren(d.innertype);
+        d.beginChildren(d.innerType);
         const void *p = deref(ldata);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
             const void *addr = addOffset(p, 2 * sizeof(void*));
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
+            qDumpInnerValueOrPointer(d, d.innerType, stripped, addr);
             p = deref(p);
             d.endHash();
         }
@@ -2750,7 +2748,7 @@ static void qDumpQSet(QDumper &d)
     }
 
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", 2 * n);
     if (d.dumpChildren) {
         if (n > 100)
@@ -2760,9 +2758,9 @@ static void qDumpQSet(QDumper &d)
         for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) {
             for (node = hd->buckets[bucket]; node->next; node = node->next) {
                 d.beginHash();
-                d.putItem("type", d.innertype);
+                d.putItem("type", d.innerType);
                 d.beginItem("exp");
-                    d.put("(('"NS"QHashNode<").put(d.innertype
+                    d.put("(('"NS"QHashNode<").put(d.innerType
                    ).put(","NS"QHashDummyValue>'*)"
                    ).put(static_cast<const void*>(node)).put(")->key");
                 d.endItem();
@@ -2788,23 +2786,23 @@ static void qDumpQSharedPointer(QDumper &d)
 
     if (ptr.isNull()) { 
         d.putItem("value", "<null>");
-        d.putItem("valuedisabled", "true");
+        d.putItem("valueeditable", "false");
         d.putItem("numchild", 0);
         d.disarm();
         return;
     }
 
-    if (isSimpleType(d.innertype))
-        qDumpInnerValueHelper(d, d.innertype, ptr.data());
+    if (isSimpleType(d.innerType))
+        qDumpInnerValueHelper(d, d.innerType, ptr.data());
     else
         d.putItem("value", "");
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", 1);
     if (d.dumpChildren) {
         d.beginChildren();
         d.beginHash();
             d.putItem("name", "data");
-            qDumpInnerValue(d, d.innertype, ptr.data());
+            qDumpInnerValue(d, d.innerType, ptr.data());
         d.endHash();
         const int v = sizeof(void *);
         d.beginHash();
@@ -2868,7 +2866,7 @@ static void qDumpQStringList(QDumper &d)
     }
 
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
         if (n > 1000)
@@ -2926,18 +2924,18 @@ static void qDumpQVector(QDumper &d)
 
     int n = nn;
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
         const char *stripped =
-            isPointerType(d.innertype) ? strippedInnerType.data() : 0;
+            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
         if (n > 1000)
             n = 1000;
-        d.beginChildren(d.innertype);
+        d.beginChildren(d.innerType);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
-            qDumpInnerValueOrPointer(d, d.innertype, stripped,
+            qDumpInnerValueOrPointer(d, d.innerType, stripped,
                 addOffset(v, i * innersize + typeddatasize));
             d.endHash();
         }
@@ -2958,23 +2956,23 @@ static void qDumpQWeakPointer(QDumper &d)
 
     if (value == 0 || data == 0) {
         d.putItem("value", "<null>");
-        d.putItem("valuedisabled", "true");
+        d.putItem("valueeditable", "false");
         d.putItem("numchild", 0);
         d.disarm();
         return;
     }
 
-    if (isSimpleType(d.innertype))
-        qDumpInnerValueHelper(d, d.innertype, value);
+    if (isSimpleType(d.innerType))
+        qDumpInnerValueHelper(d, d.innerType, value);
     else
         d.putItem("value", "");
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", 1);
     if (d.dumpChildren) {
         d.beginChildren();
         d.beginHash();
             d.putItem("name", "data");
-            qDumpInnerValue(d, d.innertype, value);
+            qDumpInnerValue(d, d.innerType, value);
         d.endHash();
         d.beginHash();
             const void *weak = addOffset(deref(d.data), v);
@@ -3034,16 +3032,16 @@ static void qDumpStdList(QDumper &d)
         d.putItemCount("value", nn);
     d.putItem("numchild", nn);
 
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     if (d.dumpChildren) {
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
         const char *stripped =
-            isPointerType(d.innertype) ? strippedInnerType.data() : 0;
-        d.beginChildren(d.innertype);
+            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
+        d.beginChildren(d.innerType);
         it = list.begin();
         for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
             d.beginHash();
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
+            qDumpInnerValueOrPointer(d, d.innerType, stripped, it.operator->());
             d.endHash();
         }
         if (it != list.end())
@@ -3078,10 +3076,10 @@ static void qDumpStdMapHelper(QDumper &d)
     for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
         qCheckAccess(it.operator->());
 
-    const QByteArray strippedInnerType = stripPointerType(d.innertype);
+    const QByteArray strippedInnerType = stripPointerType(d.innerType);
     d.putItem("numchild", nn);
     d.putItemCount("value", nn);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("valueoffset", d.extraInt[2]);
 
     // HACK: we need a properly const qualified version of the
@@ -3105,7 +3103,7 @@ static void qDumpStdMapHelper(QDumper &d)
             d.put(" valueOffset: ").put(valueOffset);
         d.endItem();
 
-        d.beginChildren(d.innertype);
+        d.beginChildren(d.innerType);
         it = map.begin();
         for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
             d.beginHash();
@@ -3185,26 +3183,26 @@ static void qDumpStdSetHelper(QDumper &d)
         qCheckAccess(it.operator->());
 
     d.putItemCount("value", nn);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", nn);
     d.putItem("valueoffset", d.extraInt[0]);
 
     if (d.dumpChildren) {
         int valueOffset = 0; // d.extraInt[0];
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
         const char *stripped =
-            isPointerType(d.innertype) ? strippedInnerType.data() : 0;
+            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
 
         d.beginItem("extra");
             d.put("valueOffset: ").put(valueOffset);
         d.endItem();
 
-        d.beginChildren(d.innertype);
+        d.beginChildren(d.innerType);
         it = set.begin();
         for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
             const void *node = it.operator->();
             d.beginHash();
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, node);
+            qDumpInnerValueOrPointer(d, d.innerType, stripped, node);
             d.endHash();
         }
         if (it != set.end())
@@ -3295,19 +3293,19 @@ static void qDumpStdVector(QDumper &d)
 
     int n = nn;
     d.putItemCount("value", n);
-    d.putItem("valuedisabled", "true");
+    d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
         unsigned innersize = d.extraInt[0];
-        QByteArray strippedInnerType = stripPointerType(d.innertype);
+        QByteArray strippedInnerType = stripPointerType(d.innerType);
         const char *stripped =
-            isPointerType(d.innertype) ? strippedInnerType.data() : 0;
+            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
         if (n > 1000)
             n = 1000;
-        d.beginChildren(n ? d.innertype : 0);
+        d.beginChildren(n ? d.innerType : 0);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
-            qDumpInnerValueOrPointer(d, d.innertype, stripped,
+            qDumpInnerValueOrPointer(d, d.innerType, stripped,
                 addOffset(v->start, i * innersize));
             d.endHash();
         }
@@ -3326,7 +3324,7 @@ static void qDumpStdVectorBool(QDumper &d)
 
 static void handleProtocolVersion2and3(QDumper &d)
 {
-    if (!d.outertype[0]) {
+    if (!d.outerType[0]) {
         qDumpUnknown(d);
         return;
     }
@@ -3341,7 +3339,7 @@ static void handleProtocolVersion2and3(QDumper &d)
 
 #ifdef QT_NO_QDATASTREAM
     if (d.protocolVersion == 3) {
-        QVariant::Type type = QVariant::nameToType(d.outertype);
+        QVariant::Type type = QVariant::nameToType(d.outerType);
         if (type != QVariant::Invalid) {
             QVariant v(type, d.data);
             QByteArray ba;
@@ -3352,7 +3350,7 @@ static void handleProtocolVersion2and3(QDumper &d)
     }
 #endif
 
-    const char *type = stripNamespace(d.outertype);
+    const char *type = stripNamespace(d.outerType);
     // type[0] is usally 'Q', so don't use it
     switch (type[1]) {
         case 'a':
@@ -3774,10 +3772,10 @@ void *qDumpObjectData440(
         d.extraInt[3]     = extraInt3;
 
         const char *inbuffer = inBuffer;
-        d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+        d.outerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
         d.iname     = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
         d.exp       = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
-        d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
+        d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
         d.iname     = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
 
         handleProtocolVersion2and3(d);
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index f1dbc7b71dc..844ba750b4d 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -319,9 +319,7 @@ void DebuggerManager::init()
     //qRegisterMetaType<WatchData>("Debugger::Internal::WatchData");
     qRegisterMetaType<WatchData>("WatchData");
     connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
-        this, SLOT(updateWatchDataAnnounce()));
-    connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
-        this, SLOT(updateWatchData(WatchData)), Qt::QueuedConnection);
+        this, SLOT(updateWatchData(WatchData)));
 
     m_continueAction = new QAction(this);
     m_continueAction->setText(tr("Continue"));
@@ -695,12 +693,6 @@ void DebuggerManager::updateWatchData(const WatchData &data)
         m_engine->updateWatchData(data);
 }
 
-void DebuggerManager::updateWatchDataAnnounce()
-{
-    if (m_engine)
-        m_engine->updateWatchDataAnnounce();
-}
-
 static inline QString msgEngineNotAvailable(const char *engine)
 {
     return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine));
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index c12a4a1b1c8..89669c9df5e 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -57,6 +57,7 @@
 #include <QtCore/QDebug>
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
+#include <QtCore/QMetaObject>
 #include <QtCore/QTime>
 #include <QtCore/QTimer>
 #include <QtCore/QTextStream>
@@ -2814,12 +2815,20 @@ static void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
         data.setHasChildren(mi.data().toInt() > 0);
 }
 
-static void setWatchDataValueDisabled(WatchData &data, const GdbMi &mi)
+static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
 {
     if (mi.data() == "true")
-        data.valuedisabled = true;
+        data.valueEnabled = true;
     else if (mi.data() == "false")
-        data.valuedisabled = false;
+        data.valueEnabled = false;
+}
+
+static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
+{
+    if (mi.data() == "true")
+        data.valueEditable = true;
+    else if (mi.data() == "false")
+        data.valueEditable = false;
 }
 
 static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
@@ -3127,20 +3136,26 @@ void GdbEngine::updateSubItem(const WatchData &data0)
     QTC_ASSERT(false, return);
 }
 
-void GdbEngine::updateWatchDataAnnounce()
+void GdbEngine::updateWatchData(const WatchData &data)
 {
     // Bump requests to avoid model rebuilding during the nested
     // updateWatchModel runs.
     ++m_pendingRequests;
+#if 1
+    QMetaObject::invokeMethod(this, "updateWatchDataHelper",
+        Qt::QueuedConnection, Q_ARG(WatchData, data));
+#else
+    updateWatchDataHelper(data);
+#endif
 }
 
-void GdbEngine::updateWatchData(const WatchData &data)
+void GdbEngine::updateWatchDataHelper(const WatchData &data)
 {
     //m_pendingRequests = 0;
     PENDING_DEBUG("UPDATE WATCH DATA");
     #if DEBUG_PENDING
     //qDebug() << "##############################################";
-    //qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
+    qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
     //qDebug() << data.toString();
     #endif
 
@@ -3153,9 +3168,11 @@ void GdbEngine::updateWatchData(const WatchData &data)
 
 void GdbEngine::rebuildModel()
 {
+    static int count = 0;
+    ++count;
     m_processedNames.clear();
-    PENDING_DEBUG("REBUILDING MODEL");
-    emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>"));
+    PENDING_DEBUG("REBUILDING MODEL" << count);
+    emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel %1>").arg(count));
     q->showStatusMessage(tr("Finished retrieving data."), 400);
     qq->watchHandler()->endCycle();
     showToolTip();
@@ -3330,7 +3347,8 @@ void GdbEngine::handleVarCreate(const GdbResultRecord &record,
             data.type = _(" ");
             data.setAllUnneeded();
             data.setHasChildren(false);
-            data.valuedisabled = true;
+            data.valueEnabled = false;
+            data.valueEditable = false;
             insertData(data);
         }
     }
@@ -3445,7 +3463,8 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
     setWatchDataSAddress(data, item.findChild("saddr"));
     setWatchDataValueToolTip(data, item.findChild("valuetooltip"),
         item.findChild("valuetooltipencoded").data().toInt());
-    setWatchDataValueDisabled(data, item.findChild("valuedisabled"));
+    setWatchDataValueEnabled(data, item.findChild("valueenabled"));
+    setWatchDataValueEditable(data, item.findChild("valueeditable"));
     //qDebug() << "HANDLE CHILDREN: " << data.toString();
     list->append(data);
 
@@ -3495,7 +3514,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record,
         //    <<  " STREAM:" << out;
         if (list.isEmpty()) {
             //: Value for variable
-            data.setValue(strNotInScope);
+            data.setError(strNotInScope);
             data.setAllUnneeded();
             insertData(data);
         } else if (data.type == __("QString")
@@ -3540,13 +3559,13 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record,
             }
         } else {
             //: Value for variable
-            data.setValue(strNotInScope);
+            data.setError(strNotInScope);
             data.setAllUnneeded();
             insertData(data);
         }
     } else if (record.resultClass == GdbResultError) {
         WatchData data = cookie.value<WatchData>();
-        data.setValue(strNotInScope);
+        data.setError(strNotInScope);
         data.setAllUnneeded();
         insertData(data);
     }
@@ -3628,6 +3647,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
     //qDebug() << m_varToType;
     QMap<QByteArray, int> seen;
 
+    QList<WatchData> list;
     foreach (const GdbMi &item, locals) {
         // Local variables of inlined code are reported as
         // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this",
@@ -3657,7 +3677,7 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
             //variable of the same name in a nested block
             data.setType(tr("<shadowed>"));
             data.setHasChildren(false);
-            insertData(data);
+            list.append(data);
         } else {
             seen[name] = 1;
             WatchData data;
@@ -3679,9 +3699,10 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
                 qDebug() << "RE-USING" << m_varToType.value(data.framekey);
                 data.setType(m_varToType.value(data.framekey));
             }
-            insertData(data);
+            list.append(data);
         }
     }
+    qq->watchHandler()->insertBulkData(list);
 }
 
 void GdbEngine::insertData(const WatchData &data0)
@@ -3698,7 +3719,6 @@ void GdbEngine::insertData(const WatchData &data0)
 void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
     const WatchData &parent)
 {
-    //qDebug() <<  "VAR_LIST_CHILDREN: PARENT 2" << parent.toString();
     //qDebug() <<  "VAR_LIST_CHILDREN: APPENDEE" << data.toString();
     QByteArray exp = item.findChild("exp").data();
     QByteArray name = item.findChild("name").data();
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index fdf67f15b8e..2694ec01fbd 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -332,7 +332,7 @@ private:
     void updateSubItem(const WatchData &data);
 
     void updateWatchData(const WatchData &data);
-    void updateWatchDataAnnounce();
+    Q_SLOT void updateWatchDataHelper(const WatchData &data);
     void rebuildModel();
 
     void insertData(const WatchData &data);
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index 327b1866c01..89ff3029319 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -63,7 +63,6 @@ public:
     virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
     virtual void exitDebugger() = 0;
     virtual void detachDebugger() {}
-    virtual void updateWatchDataAnnounce() {}
     virtual void updateWatchData(const WatchData &data) = 0;
 
     virtual void stepExec() = 0;
diff --git a/src/plugins/debugger/shared/backtrace.cpp b/src/plugins/debugger/shared/backtrace.cpp
new file mode 100644
index 00000000000..6b81e9339e5
--- /dev/null
+++ b/src/plugins/debugger/shared/backtrace.cpp
@@ -0,0 +1,87 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QProcess>
+
+#if defined(Q_OS_LINUX)
+#include <stdio.h>
+#include <signal.h>
+#include <execinfo.h>
+#endif 
+
+namespace Debugger {
+namespace Internal {
+
+void dumpBacktrace(int maxdepth)
+{
+    if (maxdepth == -1)
+        maxdepth = 200;
+#if defined(Q_OS_LINUX)
+    void *bt[200] = {0};
+    qDebug() << "BACKTRACE:";
+    int size = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
+    for (int i = 0; i < qMin(size, maxdepth); i++)
+        qDebug() << "0x" + QByteArray::number(quintptr(bt[i]), 16);
+    QProcess proc;
+    QStringList args;
+    args.append("-e");
+    args.append(QCoreApplication::arguments().at(0));
+    proc.start("addr2line", args);
+    proc.waitForStarted();
+    for (int i = 0; i < qMin(size, maxdepth); i++)
+        proc.write("0x" + QByteArray::number(quintptr(bt[i]), 16) + "\n");
+    proc.closeWriteChannel();
+    QByteArray out = proc.readAllStandardOutput();
+    qDebug() << QCoreApplication::arguments().at(0);
+    qDebug() << out;
+    proc.waitForFinished();
+    out = proc.readAllStandardOutput();
+    qDebug() << out;
+#endif
+}
+
+/*
+void installSignalHandlers()
+{
+#if defined(Q_OS_LINUX)
+    struct sigaction SignalAction;
+
+    SignalAction.sa_sigaction = handler;
+    sigemptyset(&SignalAction.sa_mask);
+    SignalAction.sa_flags = SA_SIGINFO;
+    sigaction(SIGSEGV, &SignalAction, NULL);
+    sigaction(SIGABRT, &SignalAction, NULL);
+#endif
+}
+*/
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/shared/backtrace.h b/src/plugins/debugger/shared/backtrace.h
new file mode 100644
index 00000000000..771ec2a3d17
--- /dev/null
+++ b/src/plugins/debugger/shared/backtrace.h
@@ -0,0 +1,43 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_BACKTRACE_H
+#define DEBUGGER_BACKTRACE_H
+
+#include <QtCore/qglobal.h>
+
+namespace Debugger {
+namespace Internal {
+
+void dumpBacktrace(int maxdepth = -1);
+
+} // namespace Internal 
+} // namespace Debugger
+
+#endif // DEBUGGER_BACKTRACE_H
diff --git a/src/plugins/debugger/shared/shared.pri b/src/plugins/debugger/shared/shared.pri
index a3dc29a6b39..bd69e956ce0 100644
--- a/src/plugins/debugger/shared/shared.pri
+++ b/src/plugins/debugger/shared/shared.pri
@@ -1,4 +1,8 @@
 
+
+SOURCES += $$PWD/backtrace.cpp
+HEADERS += $$PWD/backtrace.h 
+
 win32 {
 
 INCLUDEPATH+=$$PWD
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 13bf8698b30..d8e6cca6007 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -102,19 +102,40 @@ public:
 WatchData::WatchData() :
     hasChildren(false),
     generation(-1),
-    valuedisabled(false),
+    valueEnabled(true),
+    valueEditable(true),
     source(0),
     state(InitialState),
     changed(false)
 {
 }
 
+bool WatchData::isEqual(const WatchData &other) const
+{
+    return iname == other.iname
+      && exp == other.exp
+      && name == other.name
+      && value == other.value
+      && editvalue == other.editvalue
+      && valuetooltip == other.valuetooltip
+      && type == other.type
+      && displayedType == other.displayedType
+      && variable == other.variable
+      && addr == other.addr
+      && saddr == other.saddr
+      && framekey == other.framekey
+      && hasChildren == other.hasChildren
+      && valueEnabled == other.valueEnabled
+      && valueEditable == other.valueEditable;
+}
+
 void WatchData::setError(const QString &msg)
 {
     setAllUnneeded();
     value = msg;
     setHasChildren(false);
-    valuedisabled = true;
+    valueEnabled = false;
+    valueEditable = false;
 }
 
 void WatchData::setValue(const QString &value0)
@@ -276,6 +297,8 @@ QString WatchData::toToolTip() const
     formatToolTipRow(str, WatchHandler::tr("Object Address"), addr);
     formatToolTipRow(str, WatchHandler::tr("Stored Address"), saddr);
     formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname);
+    formatToolTipRow(str, WatchHandler::tr("Generation"),
+        QString::number(generation));
     str << "</table></body></html>";
     return res;
 }
@@ -330,6 +353,33 @@ void WatchModel::reinitialize()
     endRemoveRows();
 }
 
+void WatchModel::beginCycle()
+{
+    emit enableUpdates(false);
+}
+
+void WatchModel::endCycle()
+{
+    removeOutdated();
+    emit enableUpdates(true);
+}
+
+void WatchModel::dump()
+{
+    qDebug() << "\n";
+    foreach (WatchItem *child, m_root->children)
+        dumpHelper(child);
+}
+
+void WatchModel::dumpHelper(WatchItem *item)
+{
+    qDebug() << "ITEM: " << item->iname
+        << (item->parent ? item->parent->iname : "<none>")
+        << item->generation;
+    foreach (WatchItem *child, item->children)
+        dumpHelper(child);
+}
+
 void WatchModel::removeOutdated()
 {
     foreach (WatchItem *child, m_root->children)
@@ -343,9 +393,9 @@ void WatchModel::removeOutdated()
 
 void WatchModel::removeOutdatedHelper(WatchItem *item)
 {
-    if (item->generation < generationCounter)
+    if (item->generation < generationCounter) {
         removeItem(item);
-    else {
+    } else {
         foreach (WatchItem *child, item->children)
             removeOutdatedHelper(child);
         item->fetchTriggered = false;
@@ -407,9 +457,9 @@ QString niceType(const QString typeIn)
 {
     static QMap<QString, QString> cache;
     const QMap<QString, QString>::const_iterator it = cache.constFind(typeIn);
-    if (it != cache.constEnd()) {
+    if (it != cache.constEnd())
         return it.value();
-    }
+
     QString type = typeIn;
     type.replace(QLatin1Char('*'), QLatin1Char('@'));
 
@@ -434,23 +484,23 @@ QString niceType(const QString typeIn)
         QString inner = alloc.mid(15, alloc.size() - 16).trimmed();
 
         if (inner == QLatin1String("char")) { // std::string
-            static const QRegExp stringRegexp = stdStringRegExp(inner);
+            const QRegExp stringRegexp = stdStringRegExp(inner);
             type.replace(stringRegexp, QLatin1String("string"));
         } else if (inner == QLatin1String("wchar_t")) { // std::wstring
-            static const QRegExp wchartStringRegexp = stdStringRegExp(inner);
+            const QRegExp wchartStringRegexp = stdStringRegExp(inner);
             type.replace(wchartStringRegexp, QLatin1String("wstring"));
         } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC
-            static const QRegExp usStringRegexp = stdStringRegExp(inner);
+            const QRegExp usStringRegexp = stdStringRegExp(inner);
             type.replace(usStringRegexp, QLatin1String("wstring"));
         }
         // std::vector, std::deque, std::list
-        static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc));
+        const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(inner, alloc));
         Q_ASSERT(re1.isValid());
         if (re1.indexIn(type) != -1)
             type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner));
 
         // std::stack
-        static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner));
+        QRegExp re6(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(inner, inner));
         if (!re6.isMinimal())
             re6.setMinimal(true);
         Q_ASSERT(re6.isValid());
@@ -458,7 +508,7 @@ QString niceType(const QString typeIn)
             type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner));
 
         // std::set
-        static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc));
+        QRegExp re4(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*>").arg(inner, inner, alloc));
         if (!re4.isMinimal())
             re4.setMinimal(true);
         Q_ASSERT(re4.isValid());
@@ -481,17 +531,16 @@ QString niceType(const QString typeIn)
             }
             QString ckey = inner.mid(10, pos - 10);
             QString key = chopConst(ckey);
-            QString value = inner.mid(pos + 2, inner.size() - 3 - pos);
-
-            static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>")
+            QString value = inner.mid(pos + 2, inner.size() - 3 - pos).trimmed();
+            QRegExp re5(QString("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>")
                 .arg(key, value, key, alloc));
             if (!re5.isMinimal())
                 re5.setMinimal(true);
             Q_ASSERT(re5.isValid());
-            if (re5.indexIn(type) != -1)
+            if (re5.indexIn(type) != -1) {
                 type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value));
-            else {
-                static QRegExp re7(QString("map<const %1,[ ]?%2,[ ]?std::less<const %3>,[ ]?%4\\s*>")
+            } else {
+                QRegExp re7(QString("map<const %1, ?%2, ?std::less<const %3>, ?%4\\s*>")
                     .arg(key, value, key, alloc));
                 if (!re7.isMinimal())
                     re7.setMinimal(true);
@@ -657,7 +706,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
             static const QVariant red(QColor(200, 0, 0));
             static const QVariant gray(QColor(140, 140, 140));
             switch (idx.column()) {
-                case 1: return data.valuedisabled ? gray : data.changed ? red : QVariant();
+                case 1: return !data.valueEnabled ? gray : data.changed ? red : QVariant();
             }
             break;
         }
@@ -751,9 +800,9 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
         return editable; // watcher names are editable
     if (data.isWatcher() && idx.column() == 2)
         return editable; // watcher types are
-    if (idx.column() == 1)
-        return editable; // locals and watcher values are editable
-    return  notEditable;
+    if (idx.column() == 1 && data.valueEditable)
+        return editable; // locals and watcher values are sometimes editable
+    return notEditable;
 }
 
 QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -775,7 +824,7 @@ struct IName : public QString
     IName(const QString &iname) : QString(iname) {}
 };
 
-bool operator<(const IName &iname1, const IName &iname2)
+bool iNameLess(const QString &iname1, const QString &iname2)
 {
     QString name1 = iname1.section('.', -1);
     QString name2 = iname2.section('.', -1);
@@ -790,10 +839,14 @@ bool operator<(const IName &iname1, const IName &iname2)
     return name1 < name2; 
 }
 
+bool operator<(const IName &iname1, const IName &iname2)
+{
+    return iNameLess(iname1, iname2);
+}
 
 static bool iNameSorter(const WatchItem *item1, const WatchItem *item2)
 {
-    return IName(item1->iname) < IName(item2->iname);
+    return iNameLess(item1->iname, item2->iname);
 }
 
 static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item)
@@ -806,7 +859,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
 void WatchModel::insertData(const WatchData &data)
 {
     // qDebug() << "WMI:" << data.toString();
-    static int bulk = 0;
+    //static int bulk = 0;
     //qDebug() << "SINGLE: " << ++bulk << data.toString();
     QTC_ASSERT(!data.iname.isEmpty(), return);
     WatchItem *parent = findItem(parentName(data.iname), m_root);
@@ -845,8 +898,16 @@ void WatchModel::insertData(const WatchData &data)
 
 void WatchModel::insertBulkData(const QList<WatchData> &list)
 {
+#if 1
+    for (int i = 0; i != list.size(); ++i) 
+        insertData(list.at(i));
+    return;
+#endif
+    // This method does not properly insert items in proper "iname sort
+    // order", leading to random removal of items in removeOutDated();
+
     //qDebug() << "WMI:" << list.toString();
-    static int bulk = 0;
+    //static int bulk = 0;
     //foreach (const WatchItem &data, list)
     //    qDebug() << "BULK: " << ++bulk << data.toString();
     QTC_ASSERT(!list.isEmpty(), return);
@@ -885,22 +946,39 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
     foreach (WatchItem *oldItem, parent->children) {
         Iterator it = newList.find(oldItem->iname);
         if (it == newList.end()) {
-            newList[oldItem->iname] = *oldItem;
+            WatchData data = *oldItem;
+            data.generation = generationCounter;
+            newList[oldItem->iname] = data;
         } else {
             bool changed = !it->value.isEmpty()
                 && it->value != oldItem->value
                 && it->value != strNotInScope;
             it->changed = changed;
-            it->generation = generationCounter;
+            if (it->generation == -1)
+                it->generation = generationCounter;
         }
     }
 
+    for (Iterator it = newList.begin(); it != newList.end(); ++it) {
+        qDebug() << "  NEW: " << it->iname;
+    }
+
     // overwrite existing items
     Iterator it = newList.begin();
-    const int oldCount = parent->children.size();
-    for (int i = 0; i < oldCount; ++i, ++it)
-        parent->children[i]->setData(*it);
     QModelIndex idx = watchIndex(parent);
+    const int oldCount = parent->children.size();
+    for (int i = 0; i < oldCount; ++i, ++it) {
+        if (!parent->children[i]->isEqual(*it)) {
+            qDebug() << "REPLACING" << parent->children.at(i)->iname
+                << " WITH " << it->iname << it->generation;
+            parent->children[i]->setData(*it);
+            if (parent->children[i]->generation == -1)
+                parent->children[i]->generation = generationCounter;
+            //emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2));
+        } else {
+            //qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname;
+        }
+    }
     emit dataChanged(idx.sibling(0, 0), idx.sibling(oldCount - 1, 2));
 
     // add new items
@@ -909,13 +987,17 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
         //MODEL_DEBUG("INSERT : " << data.iname << data.value);
         for (int i = oldCount; i < newList.size(); ++i, ++it) {
             WatchItem *item = new WatchItem(*it);
+            qDebug() << "ADDING" << it->iname;
             item->parent = parent;
-            item->generation = generationCounter;
+            if (item->generation == -1)
+                item->generation = generationCounter;
             item->changed = true;
             parent->children.append(item);
         }
         endInsertRows();
     }
+    //qDebug() << "ITEMS: " << parent->children.size();
+    dump();
 }
 
 WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const
@@ -965,11 +1047,20 @@ WatchHandler::WatchHandler()
         SIGNAL(triggered()), this, SLOT(removeWatchExpression()));
 }
 
+void WatchHandler::beginCycle()
+{
+    ++generationCounter;
+    m_locals->beginCycle();
+    m_watchers->beginCycle();
+    m_tooltips->beginCycle();
+}
+
 void WatchHandler::endCycle()
 {
-    m_locals->removeOutdated();
-    m_watchers->removeOutdated();
-    m_tooltips->removeOutdated();
+    //qDebug() << "END CYCLE";
+    m_locals->endCycle();
+    m_watchers->endCycle();
+    m_tooltips->endCycle();
 }
 
 void WatchHandler::cleanup()
@@ -1004,7 +1095,7 @@ void WatchHandler::insertData(const WatchData &data)
 // bulk-insertion
 void WatchHandler::insertBulkData(const QList<WatchData> &list)
 {
-#if 1
+#if 0
     foreach (const WatchItem &data, list)
         insertData(data);
     return;
@@ -1015,16 +1106,20 @@ void WatchHandler::insertBulkData(const QList<WatchData> &list)
     QMap<QString, QList<WatchData> > hash;
 
     foreach (const WatchData &data, list) {
-        if (data.isSomethingNeeded())
-            emit watchDataUpdateNeeded(data);
-        else
-            hash[parentName(data.iname)].append(data);
+        // we insert everything, including incomplete stuff
+        // to reduce the number of row add operations in the model.
+        hash[parentName(data.iname)].append(data);
     }
     foreach (const QString &parentIName, hash.keys()) {
         WatchModel *model = modelForIName(parentIName);
         QTC_ASSERT(model, return);
         model->insertBulkData(hash[parentIName]);
     }
+
+    foreach (const WatchData &data, list) {
+        if (data.isSomethingNeeded())
+            emit watchDataUpdateNeeded(data);
+    }
 }
 
 void WatchHandler::removeData(const QString &iname)
@@ -1157,12 +1252,6 @@ void WatchHandler::removeWatchExpression(const QString &exp)
     }
 }
 
-void WatchHandler::beginCycle()
-{
-    ++generationCounter;
-    //m_locals->beginCycle();
-}
-
 void WatchHandler::updateWatchers()
 {
     //qDebug() << "UPDATE WATCHERS";
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index 4c2d2d36fe7..8f6590484b9 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -111,6 +111,8 @@ public:
     bool isLocal() const { return iname.startsWith(QLatin1String("local.")); }
     bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); }
     bool isValid() const { return !iname.isEmpty(); }
+    
+    bool isEqual(const WatchData &other) const;
 
 public:
     QString iname;        // internal name sth like 'local.baz.public.a'
@@ -128,7 +130,8 @@ public:
     QScriptValue scriptValue; // if needed...
     bool hasChildren;
     int generation;       // when updated?
-    bool valuedisabled;   // value will be greyed out
+    bool valueEnabled;    // value will be greyed out or not
+    bool valueEditable;   // value will be editable
 
 private:
 
@@ -204,8 +207,16 @@ private:
 
     void emitDataChanged(int column,
         const QModelIndex &parentIndex = QModelIndex());
+    void beginCycle(); // called at begin of updateLocals() cycle
+    void endCycle(); // called after all results have been received
 
     friend QDebug operator<<(QDebug d, const WatchModel &m);
+
+    void dump();
+    void dumpHelper(WatchItem *item);
+signals:
+    void enableUpdates(bool);
+
 private:
     WatchHandler *m_handler;
     WatchType m_type;
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 6b6a358455e..1663f942668 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -491,7 +491,7 @@ QtDumperResult::Child::Child() :
    keyEncoded(0),
    valueEncoded(0),
    childCount(-1),
-   valuedisabled(false),
+   valueEnabled(true),
    valueEncountered(false)
 {
 }
@@ -499,7 +499,7 @@ QtDumperResult::Child::Child() :
 QtDumperResult::QtDumperResult() :
     valueEncountered(false),
     valueEncoded(0),
-    valuedisabled(false),
+    valueEnabled(true),
     childCount(-1),
     internal(false),
     childChildCount(-1)
@@ -516,7 +516,8 @@ void QtDumperResult::clear()
     extra.clear();
     displayedType.clear();
     valueEncoded = 0;
-    valueEncountered = valuedisabled = false;
+    valueEncountered = false;
+    valueEnabled = false;
     childCount = -1;
     internal = false;
     childType.clear();
@@ -535,7 +536,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
     root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
     if (valueEncountered) {
         root.setValue(decodeData(value, valueEncoded));
-        root.valuedisabled = valuedisabled;
+        root.valueEnabled = valueEnabled;
     }
     root.setType(type);
     if (!displayedType.isEmpty())
@@ -575,7 +576,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
             wchild.iname += iname;
             wchild.exp = dchild.exp;
             if (dchild.valueEncountered) {
-                wchild.valuedisabled = dchild.valuedisabled;
+                wchild.valueEnabled = dchild.valueEnabled;
                 wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
             }
             wchild.setAddress(dchild.address);
@@ -611,14 +612,15 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
 QDebug operator<<(QDebug in, const QtDumperResult &d)
 {
     QDebug nospace = in.nospace();
-    nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType
+    nospace << " iname=" << d.iname << " type=" << d.type
+            << " displayed=" << d.displayedType
             << " address=" << d.address;
     if (!d.addressInfo.isEmpty())
         nospace << " addressInfo=" << d.addressInfo;
     if (d.valueEncountered) {
         nospace << " encoded=" << d.valueEncoded
                 << " value="  << d.value
-                << " disabled=" << d.valuedisabled;
+                << " enabled=" << d.valueEnabled;
     } else {
         nospace  << " <no value>";
     }
@@ -633,7 +635,7 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
         for (int i = 0; i < realChildCount; i++) {
             const QtDumperResult::Child &c = d.children.at(i);
             nospace << "   #" << i << " addr=" << c.address
-                    << " disabled=" << c.valuedisabled
+                    << " enabled=" << c.valueEnabled
                     << " type=" << c.type << " exp=" << c.exp
                     << " name=" << c.name;
             if (!c.key.isEmpty())
@@ -1518,7 +1520,7 @@ protected:
 private:
     enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue,
                 ExpectingType, ExpectingDisplayedType, ExpectingInternal,
-                ExpectingValueDisabled,  ExpectingValueEncoded,
+                ExpectingValueEnabled,  ExpectingValueEncoded,
                 ExpectingCommonChildType, ExpectingChildCount,
                 ExpectingChildChildOverrideCount,
                 ExpectingExtra,
@@ -1529,7 +1531,7 @@ private:
                 ExpectingChildDisplayedType,
                 ExpectingChildKey, ExpectingChildKeyEncoded,
                 ExpectingChildValue, ExpectingChildValueEncoded,
-                ExpectingChildValueDisabled, ExpectingChildChildCount,
+                ExpectingChildValueEnabled, ExpectingChildChildCount,
                 IgnoreNextChildMode
               };
 
@@ -1593,8 +1595,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
             return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded;
         break;
     case 13:
-        if (!qstrncmp(keyword, "valuedisabled", size))
-            return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled;
+        if (!qstrncmp(keyword, "valueenabled", size))
+            return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled;
         if (!qstrncmp(keyword, "displayedtype", size))
             return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType;
         if (!qstrncmp(keyword, "childnumchild", size))
@@ -1642,8 +1644,8 @@ bool ValueDumperParser::handleValue(const char *k, int size)
         m_result.valueEncountered = true;
         m_result.value = valueBA;
         break;
-    case ExpectingValueDisabled:
-        m_result.valuedisabled = valueBA == "true";
+    case ExpectingValueEnabled:
+        m_result.valueEnabled = valueBA == "true";
         break;
     case ExpectingValueEncoded:
         m_result.valueEncoded = QString::fromLatin1(valueBA).toInt();
@@ -1695,8 +1697,8 @@ bool ValueDumperParser::handleValue(const char *k, int size)
     case ExpectingChildValueEncoded:
         m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt();
         break;
-    case ExpectingChildValueDisabled:
-        m_result.children.back().valuedisabled = valueBA == "true";
+    case ExpectingChildValueEnabled:
+        m_result.children.back().valueEnabled = valueBA == "true";
         break;
     case ExpectingChildType:
         m_result.children.back().type = QString::fromLatin1(valueBA);
diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h
index 7c854009813..f085179d413 100644
--- a/src/plugins/debugger/watchutils.h
+++ b/src/plugins/debugger/watchutils.h
@@ -97,7 +97,7 @@ struct QtDumperResult
         int keyEncoded;
         int valueEncoded;
         int childCount;
-        bool valuedisabled;
+        bool valueEnabled;
         QString name;
         QString address;
         QString exp;
@@ -121,7 +121,7 @@ struct QtDumperResult
     bool valueEncountered;
     QByteArray value;
     int valueEncoded;
-    bool valuedisabled;
+    bool valueEnabled;
     int childCount;
     bool internal;
     QString childType;
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index b8a687c82db..edb3c9bbaf8 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -353,7 +353,16 @@ void WatchWindow::setModel(QAbstractItemModel *model)
     if (m_type != LocalsType)
         header()->hide();
 
-    connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper()));
+    connect(model, SIGNAL(layoutChanged()),
+        this, SLOT(resetHelper()));
+    connect(model, SIGNAL(enableUpdates(bool)),
+        this, SLOT(setUpdatesEnabled(bool)));
+}
+
+void WatchWindow::setUpdatesEnabled(bool enable)
+{
+    //qDebug() << "ENABLING UPDATES: " << enable;
+    QTreeView::setUpdatesEnabled(enable);
 }
 
 void WatchWindow::resetHelper()
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index b2b27a9f062..582ffdcd6fa 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -64,6 +64,7 @@ private:
     Q_SLOT void resetHelper();
     Q_SLOT void expandNode(const QModelIndex &idx);
     Q_SLOT void collapseNode(const QModelIndex &idx);
+    Q_SLOT void setUpdatesEnabled(bool enable);
 
     void keyPressEvent(QKeyEvent *ev);
     void contextMenuEvent(QContextMenuEvent *ev);
diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp
index 3a63d348b8c..0259c0a2e21 100644
--- a/tests/manual/gdbdebugger/simple/app.cpp
+++ b/tests/manual/gdbdebugger/simple/app.cpp
@@ -90,6 +90,20 @@ public:
         int t = 2;
         b = 2 + s + t;
         a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
     }
 
     ~Foo()
-- 
GitLab