diff --git a/share/qtcreator/dumper/qttypes.py b/share/qtcreator/dumper/qttypes.py
index 085f746fa4ef206f72e275f9ebee48fd559c652d..9d00282fbc8ddb15d0ee250ea6a6a0e42a2f4a28 100644
--- a/share/qtcreator/dumper/qttypes.py
+++ b/share/qtcreator/dumper/qttypes.py
@@ -2397,6 +2397,14 @@ def qdump__Debugger__Internal__GdbMi(d, value):
     d.putByteArrayValue(value["m_data"])
     d.putPlainChildren(value)
 
+def qdump__Debugger__Internal__WatchData(d, value):
+    d.putByteArrayValue(value["iname"])
+    d.putPlainChildren(value)
+
+def qdump__Debugger__Internal__WatchItem(d, value):
+    d.putByteArrayValue(value["iname"])
+    d.putPlainChildren(value)
+
 def qdump__CPlusPlus__ByteArrayRef(d, value):
     d.putValue(encodeCharArray(value["m_start"], 100, value["m_length"]),
         Hex2EncodedLatin1)
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 4b2864633a3de7843043ab87e4ce25662ef06590..112ed2524c2bc3e0015b86646b8414d79fc6b6dc 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -98,6 +98,12 @@ enum { debugSourceMapping = 0 };
 enum { debugWatches = 0 };
 enum { debugBreakpoints = 0 };
 
+enum HandleLocalsFlags
+{
+    PartialLocalsUpdate = 0x1,
+    LocalsUpdateForNewFrame = 0x2
+};
+
 #if 0
 #  define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
 #else
@@ -550,18 +556,16 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
     // Can this be found as a local variable?
     const QByteArray localsPrefix(localsPrefixC);
     QByteArray iname = localsPrefix + exp.toAscii();
-    QModelIndex index = watchHandler()->itemIndex(iname);
-    if (!index.isValid()) {
+    if (!watchHandler()->hasItem(iname)) {
         // Nope, try a 'local.this.m_foo'.
         exp.prepend(QLatin1String("this."));
         iname.insert(localsPrefix.size(), "this.");
-        index = watchHandler()->itemIndex(iname);
-        if (!index.isValid())
+        if (!watchHandler()->hasItem(iname))
             return false;
     }
     DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
     tw->setContext(context);
-    tw->setDebuggerModel(LocalsWatch);
+    tw->setDebuggerModel(LocalsType);
     tw->setExpression(exp);
     tw->acquireEngine(this);
     DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
@@ -1048,7 +1052,7 @@ void CdbEngine::handleAddWatch(const CdbExtensionCommandPtr &reply)
         updateLocalVariable(item.iname);
     } else {
         item.setError(tr("Unable to add expression"));
-        watchHandler()->insertData(item);
+        watchHandler()->insertIncompleteData(item);
         showMessage(QString::fromLatin1("Unable to add watch item '%1'/'%2': %3").
                     arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
                         QString::fromLocal8Bit(reply->errorMessage)), LogError);
@@ -1086,7 +1090,10 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
         str << blankSeparator << stackFrame;
     }
     str << blankSeparator << iname;
-    postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, &CdbEngine::handleLocals);
+    postExtensionCommand(isWatch ? "watches" : "locals",
+                         localsArguments, 0,
+                         &CdbEngine::handleLocals,
+                         0, QVariant(int(PartialLocalsUpdate)));
 }
 
 bool CdbEngine::hasCapability(unsigned cap) const
@@ -1465,8 +1472,7 @@ void CdbEngine::activateFrame(int index)
     stackHandler()->setCurrentIndex(index);
     const bool showAssembler = !frames.at(index).isUsable();
     if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
-        watchHandler()->beginCycle();
-        watchHandler()->endCycle();
+        watchHandler()->removeAllData();
         QAction *assemblerAction = theAssemblerAction();
         if (assemblerAction->isChecked()) {
             gotoLocation(frame);
@@ -1485,14 +1491,12 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
 
     const int frameIndex = stackHandler()->currentIndex();
     if (frameIndex < 0) {
-        watchHandler()->beginCycle();
-        watchHandler()->endCycle();
+        watchHandler()->removeAllData();
         return;
     }
     const StackFrame frame = stackHandler()->currentFrame();
     if (!frame.isUsable()) {
-        watchHandler()->beginCycle();
-        watchHandler()->endCycle();
+        watchHandler()->removeAllData();
         return;
     }
     /* Watchers: Forcibly discard old symbol group as switching from
@@ -1542,9 +1546,11 @@ void CdbEngine::updateLocals(bool forNewStackFrame)
     }
 
     // Required arguments: frame
+    const int flags = forNewStackFrame ? LocalsUpdateForNewFrame : 0;
     str << blankSeparator << frameIndex;
-    watchHandler()->beginCycle();
-    postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals, 0, QVariant(forNewStackFrame));
+    postExtensionCommand("locals", arguments, 0,
+                         &CdbEngine::handleLocals, 0,
+                         QVariant(flags));
 }
 
 void CdbEngine::selectThread(int index)
@@ -1925,6 +1931,9 @@ void CdbEngine::handleRegisters(const CdbExtensionCommandPtr &reply)
 
 void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
 {
+    const int flags = reply->cookie.toInt();
+    if (!(flags & PartialLocalsUpdate))
+        watchHandler()->removeAllData();
     if (reply->success) {
         QList<WatchData> watchData;
         GdbMi root;
@@ -1940,16 +1949,14 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply)
             dummy.name = QLatin1String(child.findChild("name").data());
             parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData);
         }
-        watchHandler()->insertBulkData(watchData);
-        watchHandler()->endCycle();
+        watchHandler()->insertData(watchData);
         if (debugLocals) {
             QDebug nsp = qDebug().nospace();
             nsp << "Obtained " << watchData.size() << " items:\n";
             foreach (const WatchData &wd, watchData)
                 nsp << wd.toString() <<'\n';
         }
-        const bool forNewStackFrame = reply->cookie.toBool();
-        if (forNewStackFrame)
+        if (flags & LocalsUpdateForNewFrame)
             emit stackFrameCompleted();
     } else {
         showMessage(QString::fromLatin1(reply->errorMessage), LogWarning);
diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h
index 897bfd677c0518776fa1032b5c8e10d7b12e5225..57d18dcd403a009c73df564e303c71ef521e7f17 100644
--- a/src/plugins/debugger/debuggercore.h
+++ b/src/plugins/debugger/debuggercore.h
@@ -85,7 +85,7 @@ public:
     virtual QVariant configValue(const QString &name) const = 0;
     virtual void setConfigValue(const QString &name, const QVariant &value) = 0;
     virtual void updateState(DebuggerEngine *engine) = 0;
-    virtual void updateWatchersWindow() = 0;
+    virtual void updateWatchersWindow(bool showWatch, bool showReturn) = 0;
     virtual void showQtDumperLibraryWarning(const QString &details) = 0;
     virtual QIcon locationMarkIcon() const = 0;
     virtual const CPlusPlus::Snapshot &cppCodeModelSnapshot() const = 0;
diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp
index 017aa11f57329a17495ff52a7224fa4a9f624a1d..4db5bc134c95d6c63ea7447a8269850c3464a32c 100644
--- a/src/plugins/debugger/debuggerengine.cpp
+++ b/src/plugins/debugger/debuggerengine.cpp
@@ -491,42 +491,32 @@ QAbstractItemModel *DebuggerEngine::threadsModel() const
 
 QAbstractItemModel *DebuggerEngine::localsModel() const
 {
-    QAbstractItemModel *model = watchHandler()->model(LocalsWatch);
-    if (model->objectName().isEmpty()) // Make debugging easier.
-        model->setObjectName(objectName() + QLatin1String("LocalsModel"));
-    return model;
+    return watchHandler()->model();
 }
 
 QAbstractItemModel *DebuggerEngine::watchersModel() const
 {
-    QAbstractItemModel *model = watchHandler()->model(WatchersWatch);
-    if (model->objectName().isEmpty()) // Make debugging easier.
-        model->setObjectName(objectName() + QLatin1String("WatchersModel"));
-    return model;
+    return watchHandler()->model();
 }
 
 QAbstractItemModel *DebuggerEngine::returnModel() const
 {
-    QAbstractItemModel *model = watchHandler()->model(ReturnWatch);
-    if (model->objectName().isEmpty()) // Make debugging easier.
-        model->setObjectName(objectName() + QLatin1String("ReturnModel"));
-    return model;
+    return watchHandler()->model();
 }
 
 QAbstractItemModel *DebuggerEngine::inspectorModel() const
 {
-    QAbstractItemModel *model = watchHandler()->model(InspectWatch);
-    if (model->objectName().isEmpty()) // Make debugging easier.
-        model->setObjectName(objectName() + QLatin1String("InspectorModel"));
-    return model;
+    return watchHandler()->model();
 }
 
 QAbstractItemModel *DebuggerEngine::toolTipsModel() const
 {
-    QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
-    if (model->objectName().isEmpty()) // Make debugging easier.
-        model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
-    return model;
+    return watchHandler()->model();
+}
+
+QAbstractItemModel *DebuggerEngine::watchModel() const
+{
+    return watchHandler()->model();
 }
 
 QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h
index 76089e425bed4a3c9e9e58980124d85259a3e258..c8ff90586a230b578765f4b77721adcd0f68806f 100644
--- a/src/plugins/debugger/debuggerengine.h
+++ b/src/plugins/debugger/debuggerengine.h
@@ -229,11 +229,12 @@ public:
     virtual QAbstractItemModel *registerModel() const;
     virtual QAbstractItemModel *stackModel() const;
     virtual QAbstractItemModel *threadsModel() const;
-    virtual QAbstractItemModel *localsModel() const;
-    virtual QAbstractItemModel *watchersModel() const;
-    virtual QAbstractItemModel *returnModel() const;
-    virtual QAbstractItemModel *inspectorModel() const;
-    virtual QAbstractItemModel *toolTipsModel() const;
+    virtual QAbstractItemModel *localsModel() const; // Deprecated, FIXME: use watchModel
+    virtual QAbstractItemModel *watchersModel() const; // Deprecated, FIXME: use watchModel
+    virtual QAbstractItemModel *returnModel() const; // Deprecated, FIXME: use watchModel
+    virtual QAbstractItemModel *inspectorModel() const; // Deprecated, FIXME: use watchModel
+    virtual QAbstractItemModel *toolTipsModel() const; // Deprecated, FIXME: use watchModel
+    virtual QAbstractItemModel *watchModel() const;
     virtual QAbstractItemModel *sourceFilesModel() const;
     virtual QAbstractItemModel *qtMessageLogModel() const;
 
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index bc841121981b6f29c51ee37faa3342840d1dcf35..3efe927e5d4f0c587cd33c32972d4e6db4cc799b 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -815,7 +815,7 @@ public slots:
     void fontSettingsChanged(const TextEditor::FontSettings &settings);
 
     void updateState(DebuggerEngine *engine);
-    void updateWatchersWindow();
+    void updateWatchersWindow(bool showWatch, bool showReturn);
     void onCurrentProjectChanged(ProjectExplorer::Project *project);
 
     void sessionLoaded();
@@ -2238,12 +2238,10 @@ void DebuggerPluginPrivate::setInitialState()
     m_qtMessageLogWindow->setEnabled(true);
 }
 
-void DebuggerPluginPrivate::updateWatchersWindow()
+void DebuggerPluginPrivate::updateWatchersWindow(bool showWatch, bool showReturn)
 {
-    m_watchersWindow->setVisible(
-        m_watchersWindow->model()->rowCount(QModelIndex()) > 0);
-    m_returnWindow->setVisible(
-                m_returnWindow->model()->rowCount(QModelIndex()) > 0);
+    m_watchersWindow->setVisible(showWatch);
+    m_returnWindow->setVisible(showReturn);
 }
 
 void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
@@ -2254,8 +2252,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
     QTC_ASSERT(!engine->isSlaveEngine(), return);
 
     m_threadBox->setCurrentIndex(engine->threadsHandler()->currentThread());
-
-    updateWatchersWindow();
+    engine->watchHandler()->updateWatchersWindow();
 
     const DebuggerState state = engine->state();
     //showMessage(QString("PLUGIN SET STATE: ")
diff --git a/src/plugins/debugger/debuggerstreamops.cpp b/src/plugins/debugger/debuggerstreamops.cpp
index cada0ea9d3038226e3f78238187ac765f875de54..fae28bb69c0f28defeeebf4fc79309c310e72b72 100644
--- a/src/plugins/debugger/debuggerstreamops.cpp
+++ b/src/plugins/debugger/debuggerstreamops.cpp
@@ -230,7 +230,6 @@ QDataStream &operator<<(QDataStream &stream, const WatchData &wd)
     stream << wd.address;
     stream << wd.size;
     stream << wd.hasChildren;
-    stream << wd.generation;
     stream << wd.valueEnabled;
     stream << wd.valueEditable;
     stream << wd.error;
@@ -256,7 +255,6 @@ QDataStream &operator>>(QDataStream &stream, WatchData &wd)
     stream >> wd.address;
     stream >> wd.size;
     stream >> wd.hasChildren;
-    stream >> wd.generation;
     stream >> wd.valueEnabled;
     stream >> wd.valueEditable;
     stream >> wd.error;
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index ccbd610ea3af7759aa3ab6ce605dc218eae21e78..2094d2972397cecbf98e9bab16c47267cab40317 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -31,6 +31,7 @@
 **************************************************************************/
 
 #include "debuggertooltipmanager.h"
+#include "debuggerinternalconstants.h"
 #include "watchutils.h"
 #include "debuggerengine.h"
 #include "debuggeractions.h"
@@ -617,7 +618,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) :
     m_titleLabel(new DraggableLabel),
     m_engineAcquired(false),
     m_creationDate(QDate::currentDate()),
-    m_debuggerModel(TooltipsWatch),
+    m_debuggerModel(TooltipType),
     m_treeView(new DebuggerToolTipTreeView),
     m_defaultModel(new QStandardItemModel(this))
 {
@@ -664,7 +665,7 @@ bool DebuggerToolTipWidget::matches(const QString &fileName,
     return function == m_context.function;
 }
 
-void DebuggerToolTipWidget::acquireEngine(Debugger::DebuggerEngine *engine)
+void DebuggerToolTipWidget::acquireEngine(DebuggerEngine *engine)
 {
     QTC_ASSERT(engine, return);
 
@@ -836,7 +837,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
 }
 
 /*!
-    \class Debugger::Internal::DebuggerToolTipExpressionFilterModel
+    \class Debugger::Internal::TooltipFilterModel
 
     \brief Model for tooltips filtering a local variable using the locals or tooltip model,
     matching on the name.
@@ -847,50 +848,46 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
     In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip.
 */
 
-class DebuggerToolTipExpressionFilterModel : public QSortFilterProxyModel
+class TooltipFilterModel : public QSortFilterProxyModel
 {
 public:
-    explicit DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model, const QString &exp, QObject *parent = 0);
-    virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+    TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) :
+        m_expressions(exp.split(QLatin1Char('.'))),
+        m_debuggerModel(debuggerModel)
+    {
+        setSourceModel(model);
+    }
+
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+    {
+        return role == Qt::ToolTipRole
+            ? QVariant() : QSortFilterProxyModel::data(index, role);
+    }
 
-    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
 
 private:
     const QStringList m_expressions;
+    int m_debuggerModel;
 };
 
-DebuggerToolTipExpressionFilterModel::DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model,
-                                                                           const QString &exp,
-                                                                           QObject *parent) :
-    QSortFilterProxyModel(parent),
-    m_expressions(exp.split(QLatin1Char('.')))
-{
-    setSourceModel(model);
-}
-
-QVariant DebuggerToolTipExpressionFilterModel::data(const QModelIndex &index, int role) const
-{
-    return role != Qt::ToolTipRole ?
-        QSortFilterProxyModel::data(index, role) : QVariant();
-}
-
-// Return depth of a model index, that is, 0 for root index, 1 for level-1 children, etc.
-static inline int indexDepth(QModelIndex index)
-{
-    int depth = 0;
-    for ( ; index.isValid() ; index = index.parent())
-        depth++;
-    return depth;
-}
-
-bool DebuggerToolTipExpressionFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
 {
+    const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
+    QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray();
+    if (m_debuggerModel == LocalsType && !iname.startsWith("local"))
+        return false;
+    if (m_debuggerModel == TooltipType && !iname.startsWith("tooltip"))
+        return false;
     // Match on expression for top level, else pass through.
-    const int depth = indexDepth(sourceParent);
-    if (depth >= m_expressions.size()) // No filters at this level
+    const int depth = iname.count('.');
+    if (depth == 0)
         return true;
-    const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent);
-    return nameIndex.data().toString() == m_expressions.at(depth);
+    if (depth > m_expressions.size())
+        return true;
+    const QString name = nameIndex.data().toString();
+    //const QString exp = nameIndex.data(LocalsExpressionRole).toString();
+    return name == m_expressions.at(depth - 1);
 }
 
 /*!
@@ -924,6 +921,7 @@ QAbstractItemModel *DebuggerToolTipTreeView::swapModel(QAbstractItemModel *newMo
         if (previousModel)
             previousModel->disconnect(SIGNAL(rowsInserted(QModelIndex,int,int)), this);
         setModel(newModel);
+        //setRootIndex(newModel->index(0, 0));
         connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
                 this, SLOT(computeSize()), Qt::QueuedConnection);
         computeSize();
@@ -991,24 +989,12 @@ void DebuggerToolTipTreeView::computeSize()
     setRootIsDecorated(rootDecorated);
 }
 
-void DebuggerToolTipWidget::doAcquireEngine(Debugger::DebuggerEngine *engine)
+void DebuggerToolTipWidget::doAcquireEngine(DebuggerEngine *engine)
 {
     // Create a filter model on the debugger's model and switch to it.
-    QAbstractItemModel *model = 0;
-    switch (m_debuggerModel) {
-    case LocalsWatch:
-        model = engine->localsModel();
-        break;
-    case WatchersWatch:
-        model = engine->watchersModel();
-        break;
-    case TooltipsWatch:
-        model = engine->toolTipsModel();
-        break;
-    }
-    QTC_ASSERT(model, return);
-    DebuggerToolTipExpressionFilterModel *filterModel =
-            new DebuggerToolTipExpressionFilterModel(model, m_expression);
+    QAbstractItemModel *model = engine->watchModel();
+    TooltipFilterModel *filterModel =
+            new TooltipFilterModel(model, m_expression, m_debuggerModel);
     swapModel(filterModel);
 }
 
@@ -1311,7 +1297,7 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
     }
 }
 
-void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState state)
+void DebuggerToolTipManager::slotDebuggerStateChanged(DebuggerState state)
 {
     const QObject *engine = sender();
     QTC_ASSERT(engine, return);
@@ -1319,7 +1305,7 @@ void DebuggerToolTipManager::slotDebuggerStateChanged(Debugger::DebuggerState st
     const QString name = engine->objectName();
     if (debugToolTips)
         qDebug() << "DebuggerToolTipWidget::debuggerStateChanged"
-                 << engine << Debugger::DebuggerEngine::stateName(state);
+                 << engine << DebuggerEngine::stateName(state);
 
     // Release at earliest possible convenience.
     switch (state) {
diff --git a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
index a9dd32c0a471b12699071cec44a7d4d28c7b1016..b23fffc2aaddebd8c540238467ad27881c37250a 100644
--- a/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
+++ b/src/plugins/debugger/gdb/abstractplaingdbadapter.cpp
@@ -63,8 +63,11 @@ void AbstractPlainGdbAdapter::setupInferior()
         QString args = startParameters().processArgs;
         m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
     }
-    m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
-        CB(handleFileExecAndSymbols));
+    if (m_engine->gdbVersion() > 70000)
+        m_engine->postCommand("-file-exec-and-symbols \"" + execFilePath() + '"',
+            CB(handleFileExecAndSymbols));
+    else
+        m_engine->postCommand("file " + execFilePath(), CB(handleFileExecAndSymbols));
 }
 
 void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp
index 3b2f82a34a82aca7f4f9c5a7090bda851ba5d72e..52b97a172b4de071326930b98b78adaf24d2e858 100644
--- a/src/plugins/debugger/gdb/classicgdbengine.cpp
+++ b/src/plugins/debugger/gdb/classicgdbengine.cpp
@@ -716,7 +716,7 @@ static bool parseConsoleStream(const GdbResponse &response, GdbMi *contents)
 void GdbEngine::updateLocalsClassic()
 {
     PRECONDITION;
-    m_pendingWatchRequests = 0;
+    //m_pendingWatchRequests = 0;
     m_pendingBreakpointRequests = 0;
     m_processedNames.clear();
 
@@ -724,15 +724,14 @@ void GdbEngine::updateLocalsClassic()
         qDebug() << "\nRESET PENDING";
     //m_toolTipCache.clear();
     clearToolTip();
-    watchHandler()->beginCycle();
 
     QByteArray level = QByteArray::number(currentFrame());
     // '2' is 'list with type and value'
     QByteArray cmd = "-stack-list-arguments 2 " + level + ' ' + level;
-    postCommand(cmd, WatchUpdate,
+    postCommand(cmd, Discardable,
         CB(handleStackListArgumentsClassic));
     // '2' is 'list with type and value'
-    postCommand("-stack-list-locals 2", WatchUpdate,
+    postCommand("-stack-list-locals 2", Discardable,
         CB(handleStackListLocalsClassic)); // stage 2/2
 }
 
@@ -754,9 +753,9 @@ void GdbEngine::runDirectDebuggingHelperClassic(const WatchData &data, bool dump
 
     QVariant var;
     var.setValue(data);
-    postCommand(cmd, WatchUpdate, CB(handleDebuggingHelperValue3Classic), var);
+    postCommand(cmd, Discardable, CB(handleDebuggingHelperValue3Classic), var);
 
-    showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000);
+    showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
 }
 
 void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChildren)
@@ -811,25 +810,25 @@ void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChild
         cmd += ',' + ex;
     cmd += ')';
 
-    postCommand(cmd, WatchUpdate | NonCriticalResponse);
+    postCommand(cmd, Discardable | NonCriticalResponse);
 
-    showStatusMessage(msgRetrievingWatchData(m_pendingWatchRequests + 1), 10000);
+    showStatusMessage(msgRetrievingWatchData(m_uncompleted.size()), 10000);
 
     // retrieve response
-    postCommand("p (char*)&qDumpOutBuffer", WatchUpdate,
+    postCommand("p (char*)&qDumpOutBuffer", Discardable,
         CB(handleDebuggingHelperValue2Classic), qVariantFromValue(data));
 }
 
 void GdbEngine::createGdbVariableClassic(const WatchData &data)
 {
     PRECONDITION;
-    postCommand("-var-delete \"" + data.iname + '"', WatchUpdate);
+    postCommand("-var-delete \"" + data.iname + '"', Discardable);
     QByteArray exp = data.exp;
     if (exp.isEmpty() && data.address)
         exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
     QVariant val = QVariant::fromValue<WatchData>(data);
     postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"',
-        WatchUpdate, CB(handleVarCreate), val);
+        Discardable, CB(handleVarCreate), val);
 }
 
 void GdbEngine::updateSubItemClassic(const WatchData &data0)
@@ -929,7 +928,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
         if (debugSubItem)
             qDebug() << "UPDATE SUBITEM: VALUE";
         QByteArray cmd = "-var-evaluate-expression \"" + data.iname + '"';
-        postCommand(cmd, WatchUpdate,
+        postCommand(cmd, Discardable,
             CB(handleEvaluateExpressionClassic), QVariant::fromValue(data));
         return;
     }
@@ -953,7 +952,7 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0)
     if (data.isChildrenNeeded()) {
         QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
         QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
-        postCommand(cmd, WatchUpdate,
+        postCommand(cmd, Discardable,
             CB(handleVarListChildrenClassic), QVariant::fromValue(data));
         return;
     }
@@ -999,7 +998,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
     if (m_cookieForToken.contains(response.token - 1)) {
         m_cookieForToken.remove(response.token - 1);
         showMessage(_("DETECTING LOST COMMAND %1").arg(response.token - 1));
-        --m_pendingWatchRequests;
+        // --m_pendingWatchRequests;
         data.setError(WatchData::msgNotInScope());
         insertData(data);
         return;
@@ -1025,7 +1024,7 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
     parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
     //for (int i = 0; i != list.size(); ++i)
     //    qDebug() << "READ: " << list.at(i).toString();
-    watchHandler()->insertBulkData(list);
+    watchHandler()->insertData(list);
 }
 
 void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
@@ -1082,7 +1081,7 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
                     QByteArray cmd = "qdumpqstring (" + data1.exp + ')';
                     QVariant var;
                     var.setValue(data1);
-                    postCommand(cmd, WatchUpdate,
+                    postCommand(cmd, Discardable,
                         CB(handleDebuggingHelperValue3Classic), var);
                 }
             }
@@ -1101,6 +1100,9 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
 
 void GdbEngine::tryLoadDebuggingHelpersClassic()
 {
+    if (m_forceAsyncModel)
+        return;
+
     PRECONDITION;
     if (m_gdbAdapter->dumperHandling() == AbstractGdbAdapter::DumperNotAvailable) {
         // Load at least gdb macro based dumpers.
@@ -1171,12 +1173,12 @@ void GdbEngine::updateAllClassic()
         qDebug() << state());
     tryLoadDebuggingHelpersClassic();
     reloadModulesInternal();
-    postCommand("-stack-list-frames", WatchUpdate,
+    postCommand("-stack-list-frames", Discardable,
         CB(handleStackListFrames),
         QVariant::fromValue<StackCookie>(StackCookie(false, true)));
     stackHandler()->setCurrentIndex(0);
     if (supportsThreads())
-        postCommand("-thread-list-ids", WatchUpdate, CB(handleThreadListIds), 0);
+        postCommand("-thread-list-ids", Discardable, CB(handleThreadListIds), 0);
     reloadRegisters();
     updateLocals();
 }
@@ -1248,11 +1250,10 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
                                       frame.function, frame.file, frame.line,
                                       &uninitializedVariables);
     }
-    QList<WatchData> list;
     foreach (const GdbMi &item, locals) {
         const WatchData data = localVariable(item, uninitializedVariables, &seen);
         if (data.isValid())
-            list.push_back(data);
+            insertData(data);
     }
 
     if (!m_resultVarName.isEmpty()) {
@@ -1260,10 +1261,9 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response)
         rd.iname = "return.0";
         rd.name = QLatin1String("return");
         rd.exp = m_resultVarName;
-        list.append(rd);
+        insertData(rd);
     }
 
-    watchHandler()->insertBulkData(list);
     watchHandler()->updateWatchers();
 }
 
@@ -1371,7 +1371,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
         data.setChildrenUnneeded();
         QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
         //iname += '.' + exp;
-        postCommand(cmd, WatchUpdate,
+        postCommand(cmd, Discardable,
             CB(handleVarListChildrenClassic), QVariant::fromValue(data));
     } else if (!startsWithDigit(QLatin1String(exp))
             && item.findChild("numchild").data() == "0") {
@@ -1390,7 +1390,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
         WatchData data;
         data.iname = name;
         QByteArray cmd = "-var-list-children --all-values \"" + data.variable + '"';
-        postCommand(cmd, WatchUpdate,
+        postCommand(cmd, Discardable,
             CB(handleVarListChildrenClassic), QVariant::fromValue(data));
     } else if (exp == "staticMetaObject") {
         //    && item.findChild("type").data() == "const QMetaObject")
@@ -1464,9 +1464,6 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
         //qDebug() <<  "VAR_LIST_CHILDREN: PARENT" << data.toString();
         QList<GdbMi> children = response.data.findChild("children").children();
 
-        for (int i = 0; i != children.size(); ++i)
-            handleVarListChildrenHelperClassic(children.at(i), data, i);
-
         if (children.isEmpty()) {
             // happens e.g. if no debug information is present or
             // if the class really has no children
@@ -1479,14 +1476,18 @@ void GdbEngine::handleVarListChildrenClassic(const GdbResponse &response)
             insertData(data1);
             data.setAllUnneeded();
             insertData(data);
-        } else if (data.variable.endsWith("private")
+        } else {
+            if (data.variable.endsWith("private")
                 || data.variable.endsWith("protected")
                 || data.variable.endsWith("public")) {
             // this skips the spurious "public", "private" etc levels
             // gdb produces
-        } else {
-            data.setChildrenUnneeded();
-            insertData(data);
+            } else {
+                data.setChildrenUnneeded();
+                insertData(data);
+            }
+            for (int i = 0; i != children.size(); ++i)
+                handleVarListChildrenHelperClassic(children.at(i), data, i);
         }
     } else {
         data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 83ee073d05f2e7108ee2dec064740df8f3612992..1a3e87f409f1dd1a440f1c4b2095e0ef30a53822 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -255,7 +255,6 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
     m_oldestAcceptableToken = -1;
     m_nonDiscardableCount = 0;
     m_outputCodec = QTextCodec::codecForLocale();
-    m_pendingWatchRequests = 0;
     m_pendingBreakpointRequests = 0;
     m_commandsDoneCallback = 0;
     m_stackNeeded = false;
@@ -263,6 +262,7 @@ GdbEngine::GdbEngine(const DebuggerStartParameters &startParameters,
     m_disassembleUsesComma = false;
     m_actingOnExpectedStop = false;
     m_fullStartDone = false;
+    m_forceAsyncModel = false;
 
     invalidateSourcesList();
 
@@ -788,7 +788,8 @@ void GdbEngine::readGdbStandardOutput()
     int newstart = 0;
     int scan = m_inbuffer.size();
 
-    m_inbuffer.append(gdbProc()->readAllStandardOutput());
+    QByteArray out = gdbProc()->readAllStandardOutput();
+    m_inbuffer.append(out);
 
     // This can trigger when a dialog starts a nested event loop.
     if (m_busy)
@@ -811,7 +812,8 @@ void GdbEngine::readGdbStandardOutput()
                 continue;
         }
         m_busy = true;
-        handleResponse(QByteArray::fromRawData(m_inbuffer.constData() + start, end - start));
+        QByteArray ba = QByteArray::fromRawData(m_inbuffer.constData() + start, end - start);
+        handleResponse(ba);
         m_busy = false;
     }
     m_inbuffer.clear();
@@ -903,17 +905,13 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
         return;
     }
 
-    if (cmd.flags & RebuildWatchModel) {
-        ++m_pendingWatchRequests;
-        PENDING_DEBUG("   WATCH MODEL:" << cmd.command << "=>" << cmd.callbackName
-                      << "INCREMENTS PENDING TO" << m_pendingWatchRequests);
-    } else if (cmd.flags & RebuildBreakpointModel) {
+    if (cmd.flags & RebuildBreakpointModel) {
         ++m_pendingBreakpointRequests;
         PENDING_DEBUG("   BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
                       << "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
     } else {
         PENDING_DEBUG("   OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
-                      << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
+                      << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
                       << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
     }
 
@@ -1055,7 +1053,6 @@ void GdbEngine::commandTimeout()
         if (mb->exec() == QMessageBox::Ok) {
             showMessage(_("KILLING DEBUGGER AS REQUESTED BY USER"));
             // This is an undefined state, so we just pull the emergency brake.
-            watchHandler()->endCycle();
             gdbProc()->kill();
         } else {
             showMessage(_("CONTINUE DEBUGGER AS REQUESTED BY USER"));
@@ -1205,25 +1202,17 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
     else if (cmd.adapterCallback)
         (m_gdbAdapter->*cmd.adapterCallback)(*response);
 
-    if (cmd.flags & RebuildWatchModel) {
-        --m_pendingWatchRequests;
-        PENDING_DEBUG("   WATCH" << cmd.command << "=>" << cmd.callbackName
-                      << "DECREMENTS PENDING WATCH TO" << m_pendingWatchRequests);
-        if (m_pendingWatchRequests <= 0) {
-            PENDING_DEBUG("\n\n ... AND TRIGGERS WATCH MODEL UPDATE\n");
-            rebuildWatchModel();
-        }
-    } else if (cmd.flags & RebuildBreakpointModel) {
+    if (cmd.flags & RebuildBreakpointModel) {
         --m_pendingBreakpointRequests;
         PENDING_DEBUG("   BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
-                      << "DECREMENTS PENDING TO" << m_pendingWatchRequests);
+                      << "DECREMENTS PENDING TO" << m_uncompleted.size());
         if (m_pendingBreakpointRequests <= 0) {
             PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
             attemptBreakpointSynchronization();
         }
     } else {
         PENDING_DEBUG("   OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
-                      << "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
+                      << "LEAVES PENDING WATCH AT" << m_uncompleted.size()
                       << "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
     }
 
@@ -3918,10 +3907,10 @@ bool GdbEngine::supportsThreads() const
 //
 //////////////////////////////////////////////////////////////////////
 
-bool GdbEngine::showToolTip()
+void GdbEngine::showToolTip()
 {
     if (m_toolTipContext.isNull())
-        return false;
+        return;
     const QString expression = m_toolTipContext->expression;
     const QByteArray iname = tooltipIName(m_toolTipContext->expression);
     if (DebuggerToolTipManager::debug())
@@ -3929,15 +3918,15 @@ bool GdbEngine::showToolTip()
 
     if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) {
         watchHandler()->removeData(iname);
-        return true;
+        return;
     }
 
     if (!watchHandler()->isValidToolTip(iname)) {
         watchHandler()->removeData(iname);
-        return true;
+        return;
     }
     DebuggerToolTipWidget *tw = new DebuggerToolTipWidget;
-    tw->setDebuggerModel(TooltipsWatch);
+    tw->setDebuggerModel(TooltipType);
     tw->setExpression(expression);
     tw->setContext(*m_toolTipContext);
     tw->acquireEngine(this);
@@ -3945,7 +3934,6 @@ bool GdbEngine::showToolTip()
                                                     m_toolTipContext->editor, tw);
     // Prevent tooltip from re-occurring (classic GDB, QTCREATORBUG-4711).
     m_toolTipContext.reset();
-    return true;
 }
 
 QString GdbEngine::tooltipExpression() const
@@ -4034,7 +4022,6 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
         toolTip.exp = exp.toLatin1();
         toolTip.name = exp;
         toolTip.iname = tooltipIName(exp);
-        watchHandler()->removeData(toolTip.iname);
         watchHandler()->insertData(toolTip);
     }
     return true;
@@ -4071,19 +4058,12 @@ bool GdbEngine::hasDebuggingHelperForType(const QByteArray &type) const
     return m_dumperHelper.type(type) != DumperHelper::UnknownType;
 }
 
-
 void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &flags)
 {
     if (isSynchronous()) {
         // This should only be called for fresh expanded items, not for
         // items that had their children retrieved earlier.
         //qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
-#if 0
-        WatchData data1 = data;
-        data1.setAllUnneeded();
-        insertData(data1);
-        rebuildModel();
-#else
         if (data.iname.endsWith("."))
             return;
 
@@ -4106,53 +4086,26 @@ void GdbEngine::updateWatchData(const WatchData &data, const WatchUpdateFlags &f
         // triggered e.g. by manually entered command in the gdb console?
         //qDebug() << "TRY PARTIAL: " << flags.tryIncremental
         //        << hasPython()
-        //        << (m_pendingWatchRequests == 0)
         //        << (m_pendingBreakpointRequests == 0);
 
         UpdateParameters params;
         params.tooltipOnly = data.iname.startsWith("tooltip");
         params.tryPartial = flags.tryIncremental
                 && hasPython()
-                && m_pendingWatchRequests == 0
                 && m_pendingBreakpointRequests == 0;
         params.varList = data.iname;
 
         updateLocalsPython(params);
-#endif
     } else {
-        // Bump requests to avoid model rebuilding during the nested
-        // updateWatchModel runs.
-        ++m_pendingWatchRequests;
-        PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingWatchRequests);
-#if 1
-        QMetaObject::invokeMethod(this, "updateWatchDataHelper",
-            Qt::QueuedConnection, Q_ARG(WatchData, data));
-#else
-        updateWatchDataHelper(data);
-#endif
+        PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_uncompleted.size());
+        updateSubItemClassic(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() << data.toString();
-#    endif
-
-    updateSubItemClassic(data);
-    //PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
-    --m_pendingWatchRequests;
-    PENDING_DEBUG("UPDATE WATCH DONE BUMPS PENDING DOWN TO " << m_pendingWatchRequests);
-    if (m_pendingWatchRequests <= 0)
-        rebuildWatchModel();
-}
-
 void GdbEngine::rebuildWatchModel()
 {
+    QTC_CHECK(m_completed.isEmpty());
+    QTC_CHECK(m_uncompleted.isEmpty());
     static int count = 0;
     ++count;
     if (!isSynchronous())
@@ -4162,7 +4115,6 @@ void GdbEngine::rebuildWatchModel()
         showMessage(LogWindow::logTimeStamp(), LogMiscInput);
     showMessage(_("<Rebuild Watchmodel %1>").arg(count), LogMiscInput);
     showStatusMessage(tr("Finished retrieving data"), 400);
-    watchHandler()->endCycle();
     showToolTip();
     handleAutoTests();
 }
@@ -4332,15 +4284,23 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
     return data;
 }
 
-void GdbEngine::insertData(const WatchData &data0)
+void GdbEngine::insertData(const WatchData &data)
 {
-    PENDING_DEBUG("INSERT DATA" << data0.toString());
-    WatchData data = data0;
-    if (data.value.startsWith(QLatin1String("mi_cmd_var_create:"))) {
-        qDebug() << "BOGUS VALUE:" << data.toString();
-        return;
+    PENDING_DEBUG("INSERT DATA" << data.toString());
+    if (data.isSomethingNeeded()) {
+        m_uncompleted.insert(data.iname);
+        WatchUpdateFlags flags;
+        flags.tryIncremental = true;
+        updateWatchData(data, flags);
+    } else {
+        m_completed.append(data);
+        m_uncompleted.remove(data.iname);
+        if (m_uncompleted.isEmpty()) {
+            watchHandler()->insertData(m_completed);
+            m_completed.clear();
+            rebuildWatchModel();
+        }
     }
-    watchHandler()->insertData(data);
 }
 
 void GdbEngine::assignValueInDebugger(const WatchData *data,
@@ -4901,12 +4861,6 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &settingsIdHint)
 
     postCommand("disassemble 0 0", ConsoleCommand, CB(handleDisassemblerCheck));
 
-    if (sp.breakOnMain) {
-        QByteArray cmd = "tbreak ";
-        cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
-        postCommand(cmd);
-    }
-
     if (attemptQuickStart()) {
         postCommand("set auto-solib-add off", ConsoleCommand);
     } else {
@@ -4941,6 +4895,9 @@ void GdbEngine::loadInitScript()
 
 void GdbEngine::loadPythonDumpers()
 {
+    if (m_forceAsyncModel)
+        return;
+
     const QByteArray dumperSourcePath =
         Core::ICore::resourcePath().toLocal8Bit() + "/dumper/";
 
@@ -5091,6 +5048,12 @@ void GdbEngine::handleInferiorPrepared()
 
     QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
 
+    if (sp.breakOnMain) {
+        QByteArray cmd = "tbreak ";
+        cmd += sp.toolChainAbi.os() == Abi::WindowsOS ? "qMain" : "main";
+        postCommand(cmd);
+    }
+
     // Initial attempt to set breakpoints.
     if (sp.startMode != AttachCore) {
         showStatusMessage(tr("Setting breakpoints..."));
@@ -5361,6 +5324,9 @@ void GdbEngine::requestDebugInformation(const DebugInfoTask &task)
 
 bool GdbEngine::attemptQuickStart() const
 {
+    if (m_forceAsyncModel)
+        return false;
+
     // Don't try if the user does not ask for it.
     if (!debuggerCore()->boolSetting(AttemptQuickStart))
         return false;
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 93760ec19cde9a3f868f82badffd6e4f78d0089c..772f5a4d3fb43890ab8a6f116163f591cb095072 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -36,6 +36,7 @@
 #include "debuggerengine.h"
 
 #include "stackframe.h"
+#include "watchhandler.h"
 #include "watchutils.h"
 
 #include <QByteArray>
@@ -80,16 +81,6 @@ enum DebuggingHelperState
     DebuggingHelperUnavailable
 };
 
-class UpdateParameters
-{
-public:
-    UpdateParameters() { tryPartial = tooltipOnly = false; }
-
-    bool tryPartial;
-    bool tooltipOnly;
-    QByteArray varList;
-};
-
 /* This is only used with Mac gdb since 2.2
  *
  * "Custom dumper" is a library compiled against the current
@@ -322,9 +313,6 @@ private: ////////// Gdb Command Management //////////
         NeedsStop = 1,
         // No need to wait for the reply before continuing inferior.
         Discardable = 2,
-        // Trigger watch model rebuild when no such commands are pending anymore.
-        RebuildWatchModel = 4,
-        WatchUpdate = Discardable | RebuildWatchModel,
         // We can live without receiving an answer.
         NonCriticalResponse = 8,
         // Callback expects GdbResultRunning instead of GdbResultDone.
@@ -407,7 +395,6 @@ private: ////////// Gdb Command Management //////////
     int m_oldestAcceptableToken;
     int m_nonDiscardableCount;
 
-    int m_pendingWatchRequests; // Watch updating commands in flight
     int m_pendingBreakpointRequests; // Watch updating commands in flight
 
     typedef void (GdbEngine::*CommandsDoneCallback)();
@@ -630,13 +617,11 @@ private: ////////// View & Data Stuff //////////
     virtual void watchPoint(const QPoint &);
     void handleWatchPoint(const GdbResponse &response);
 
-    // FIXME: BaseClass. called to improve situation for a watch item
     void updateSubItemClassic(const WatchData &data);
 
-    void virtual updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
-    Q_SLOT void updateWatchDataHelper(const WatchData &data);
+    void updateWatchData(const WatchData &data, const WatchUpdateFlags &flags);
     void rebuildWatchModel();
-    bool showToolTip();
+    void showToolTip();
 
     void insertData(const WatchData &data);
     void sendWatchParameters(const QByteArray &params0);
@@ -753,6 +738,11 @@ private: ////////// View & Data Stuff //////////
     // debug information.
     bool attemptQuickStart() const;
     bool m_fullStartDone;
+
+    // Test
+    bool m_forceAsyncModel;
+    QList<WatchData> m_completed;
+    QSet<QByteArray> m_uncompleted;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp
index f69ee66055b6584b1a38ed5e5538bac8c70a4b21..b020cc03b05c63fca85075c09653fbe0965d2199 100644
--- a/src/plugins/debugger/gdb/pythongdbengine.cpp
+++ b/src/plugins/debugger/gdb/pythongdbengine.cpp
@@ -54,12 +54,11 @@ namespace Internal {
 void GdbEngine::updateLocalsPython(const UpdateParameters &params)
 {
     PRECONDITION;
-    m_pendingWatchRequests = 0;
+    //m_pendingWatchRequests = 0;
     m_pendingBreakpointRequests = 0;
     m_processedNames.clear();
-    WatchHandler *handler = watchHandler();
-    handler->beginCycle(!params.tryPartial);
 
+    WatchHandler *handler = watchHandler();
     QByteArray expanded = "expanded:" + handler->expansionRequests() + ' ';
     expanded += "typeformats:" + handler->typeFormatRequests() + ' ';
     expanded += "formats:" + handler->individualFormatRequests();
@@ -117,7 +116,7 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
 
     postCommand("bb options:" + options + " vars:" + params.varList + ' '
             + resultVar + expanded + " watchers:" + watchers.toHex(),
-        WatchUpdate, CB(handleStackFramePython), QVariant(params.tryPartial));
+        Discardable, CB(handleStackFramePython), QVariant(params.tryPartial));
 }
 
 void GdbEngine::handleStackFramePython(const GdbResponse &response)
@@ -136,9 +135,11 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
         }
         GdbMi all;
         all.fromStringMultiple(out);
-
         GdbMi data = all.findChild("data");
+
+        WatchHandler *handler = watchHandler();
         QList<WatchData> list;
+
         foreach (const GdbMi &child, data.children()) {
             WatchData dummy;
             dummy.iname = child.findChild("iname").data();
@@ -151,7 +152,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
             } else {
                 dummy.name = _(child.findChild("name").data());
             }
-            parseWatchData(watchHandler()->expandedINames(), dummy, child, &list);
+            parseWatchData(handler->expandedINames(), dummy, child, &list);
         }
         const GdbMi typeInfo = all.findChild("typeinfo");
         if (typeInfo.type() == GdbMi::List) {
@@ -169,15 +170,20 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
                 list[i].size = ti.size;
         }
 
-        watchHandler()->insertBulkData(list);
+        if (!partial) {
+            handler->removeChildren("local");
+            handler->removeChildren("watch");
+        }
+
+        handler->insertData(list);
 
         //PENDING_DEBUG("AFTER handleStackFrame()");
         // FIXME: This should only be used when updateLocals() was
         // triggered by expanding an item in the view.
-        if (m_pendingWatchRequests <= 0) {
+        //if (m_pendingWatchRequests <= 0) {
             //PENDING_DEBUG("\n\n ....  AND TRIGGERS MODEL UPDATE\n");
             rebuildWatchModel();
-        }
+        //}
         if (!partial)
             emit stackFrameCompleted();
     } else {
diff --git a/src/plugins/debugger/lldb/ipcenginehost.cpp b/src/plugins/debugger/lldb/ipcenginehost.cpp
index 73a01839dea3b5540ea10c5d7e32e632074dc7d7..7586920ba454b8c45487225ed979b2b70d913606 100644
--- a/src/plugins/debugger/lldb/ipcenginehost.cpp
+++ b/src/plugins/debugger/lldb/ipcenginehost.cpp
@@ -496,9 +496,7 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload)
                 WatchHandler *wh = watchHandler();
                 if (!wh)
                     break;
-                wh->beginCycle(fullCycle);
-                wh->insertBulkData(wd);
-                wh->endCycle();
+                wh->insertData(wd);
             }
             break;
         case IPCEngineGuest::NotifyAddBreakpointOk:
diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp
index 4c027110975ab689c3aa926555a4244ff83ad7e7..7683cd8bb391fbeb716661cb3ef87fe21c861078 100644
--- a/src/plugins/debugger/pdb/pdbengine.cpp
+++ b/src/plugins/debugger/pdb/pdbengine.cpp
@@ -720,14 +720,12 @@ void PdbEngine::updateAll()
 
 void PdbEngine::updateLocals()
 {
-    WatchHandler *handler = watchHandler();
-    handler->beginCycle(true);
-
     QByteArray watchers;
     //if (!m_toolTipExpression.isEmpty())
     //    watchers += m_toolTipExpression.toLatin1()
     //        + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
 
+    WatchHandler *handler = watchHandler();
     QHash<QByteArray, int> watcherNames = handler->watcherNames();
     QHashIterator<QByteArray, int> it(watcherNames);
     while (it.hasNext()) {
@@ -831,8 +829,7 @@ void PdbEngine::handleListLocals(const PdbResponse &response)
         //qDebug() << "CHILD: " << child.toString();
         parseWatchData(handler->expandedINames(), dummy, child, &list);
     }
-    handler->insertBulkData(list);
-    handler->endCycle();
+    handler->insertData(list);
 }
 
 bool PdbEngine::hasCapability(unsigned cap) const
diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp
index 908770961df243a9c34f7b65f552e92c67a7ac82..67078e9781369683b8a3332e3b338f27277c7e2b 100644
--- a/src/plugins/debugger/qml/qmlengine.cpp
+++ b/src/plugins/debugger/qml/qmlengine.cpp
@@ -1000,7 +1000,6 @@ void QmlEngine::updateWatchData(const WatchData &data,
     const WatchUpdateFlags &)
 {
 //    qDebug() << "UPDATE WATCH DATA" << data.toString();
-    //watchHandler()->rebuildModel();
     //showStatusMessage(tr("Stopped."), 5000);
 
     if (data.isInspect()) {
@@ -1020,7 +1019,7 @@ void QmlEngine::updateWatchData(const WatchData &data,
 
 
     if (!data.isSomethingNeeded())
-        watchHandler()->insertData(data);
+        watchHandler()->insertIncompleteData(data);
 }
 
 void QmlEngine::synchronizeWatchers()
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.cpp b/src/plugins/debugger/qml/qmlinspectoragent.cpp
index 9cb35e0ffd4c840b71788843502c84e0427956d5..d2c2793be25077b97829621291de8ddccd535f22 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.cpp
+++ b/src/plugins/debugger/qml/qmlinspectoragent.cpp
@@ -103,15 +103,11 @@ void QmlInspectorAgent::updateWatchData(const WatchData &data)
     if (debug)
         qDebug() << __FUNCTION__ << "(" << data.id << ")";
 
-    if (data.id) {
+    if (data.id && !m_fetchDataIds.contains(data.id)) {
         // objects
+        m_fetchDataIds << data.id;
         ObjectReference ref(data.id);
         m_fetchCurrentObjectsQueryIds << fetchContextObject(ref);
-        WatchData d = data;
-        d.setAllUnneeded();
-        m_engine->watchHandler()->beginCycle(InspectWatch, false);
-        m_engine->watchHandler()->insertData(d);
-        m_engine->watchHandler()->endCycle(InspectWatch);
     }
 }
 
@@ -126,12 +122,9 @@ void QmlInspectorAgent::selectObjectInTree(int debugId)
     if (m_debugIdToIname.contains(debugId)) {
         QByteArray iname = m_debugIdToIname.value(debugId);
         QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname);
-        QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
-        QTC_ASSERT(itemIndex.isValid(),
-                   qDebug() << "No  for " << debugId << ", iname " << iname; return;);
         if (debug)
             qDebug() << "  selecting" << iname << "in tree";
-        m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
+        m_engine->watchHandler()->setCurrentItem(iname);
         m_objectToSelect = 0;
     } else {
         // we've to fetch it
@@ -370,9 +363,8 @@ void QmlInspectorAgent::updateStatus()
             && debuggerCore()->boolSetting(ShowQmlObjectTree)) {
         reloadEngines();
     } else {
-        // clear view
-        m_engine->watchHandler()->beginCycle(InspectWatch, true);
-        m_engine->watchHandler()->endCycle(InspectWatch);
+        // Clear view.
+        m_engine->watchHandler()->removeChildren("inspect");
     }
 }
 
@@ -588,10 +580,7 @@ void QmlInspectorAgent::objectTreeFetched(const ObjectReference &object)
                      << "entries into watch handler ...";
         }
 
-        WatchHandler *watchHandler = m_engine->watchHandler();
-        watchHandler->beginCycle(InspectWatch, true);
-        watchHandler->insertBulkData(watchData);
-        watchHandler->endCycle(InspectWatch);
+        m_engine->watchHandler()->insertData(watchData);
 
         if (debug)
             qDebug() << "inserting entries took" << t.elapsed() << "ms";
@@ -615,15 +604,16 @@ void QmlInspectorAgent::onCurrentObjectsFetched(const ObjectReference &obj)
 
     ObjectReference last = m_fetchCurrentObjects.last();
     m_fetchCurrentObjects.clear();
+    m_fetchDataIds.clear();
 
     if (m_objectToSelect == last.debugId()) {
         // select item in view
         QByteArray iname = m_debugIdToIname.value(last.debugId());
-        QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
-        QTC_ASSERT(itemIndex.isValid(), return);
+        WatchHandler *handler = m_engine->watchHandler();
+        QTC_ASSERT(handler->hasItem(iname), return);
         if (debug)
             qDebug() << "  selecting" << iname << "in tree";
-        m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
+        handler->setCurrentItem(iname);
         m_objectToSelect = -1;
     }
 
@@ -780,12 +770,11 @@ void QmlInspectorAgent::addObjectToTree(const ObjectReference &obj,
             // find parent
             QTC_ASSERT(m_debugIdToIname.contains(parentId), break);
             QByteArray iname = m_debugIdToIname.value(parentId);
-            const WatchData *parent = m_engine->watchHandler()->findItem(iname);
+            WatchHandler *handler = m_engine->watchHandler();
+            const WatchData *parent = handler->findData(iname);
             if (parent) {
                 QList<WatchData> watches = buildWatchData(obj, *parent);
-                m_engine->watchHandler()->beginCycle(false);
-                m_engine->watchHandler()->insertBulkData(watches);
-                m_engine->watchHandler()->endCycle();
+                handler->insertData(watches);
                 break;
             }
         }
diff --git a/src/plugins/debugger/qml/qmlinspectoragent.h b/src/plugins/debugger/qml/qmlinspectoragent.h
index 0d0eafbe62546ff784d939f3d0af8ae72aec16ea..67bd0b82860b7573ee9fcaa8a219c7d72fe456b8 100644
--- a/src/plugins/debugger/qml/qmlinspectoragent.h
+++ b/src/plugins/debugger/qml/qmlinspectoragent.h
@@ -153,6 +153,7 @@ private:
     DebugIdHash m_debugIdHash;
 
     QList<int> m_objectWatches;
+    QList<int> m_fetchDataIds;
 };
 
 } // Internal
diff --git a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
index 1f97e58a542f4941945def1f91f41f00eb3110fc..8d35db37c62620fd658aa9f6bea3ea9de49e898c 100644
--- a/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
+++ b/src/plugins/debugger/qml/qmlv8debuggerclient.cpp
@@ -272,7 +272,7 @@ void QmlV8DebuggerClientPrivate::evaluate(const QString expr, bool global,
         QScriptValue ctxtList = parser.call(QScriptValue(), QScriptValueList() << _(ARRAY  ));
         while (rowCount) {
             QModelIndex index = localsModel->index(--rowCount, 0);
-            const WatchData *data = engine->watchHandler()->watchData(LocalsWatch, index);
+            const WatchData *data = engine->watchHandler()->watchData(index);
             QScriptValue ctxt = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
             ctxt.setProperty(_(NAME), QScriptValue(data->name));
             ctxt.setProperty(_(HANDLE), QScriptValue(int(data->id)));
@@ -1173,7 +1173,7 @@ void QmlV8DebuggerClient::expandObject(const QByteArray &iname, quint64 objectId
 {
     if (objectId == 0) {
         //We may have got the global object
-        const WatchData *watch = d->engine->watchHandler()->findItem(iname);
+        const WatchData *watch = d->engine->watchHandler()->findData(iname);
         if (watch->value == QLatin1String("global")) {
             StackHandler *stackHandler = d->engine->stackHandler();
             if (stackHandler->isContentsValid() && stackHandler->currentFrame().isUsable()) {
@@ -1706,9 +1706,7 @@ void QmlV8DebuggerClient::setCurrentFrameDetails(const QVariant &bodyVal, const
             data.setHasChildren(true);
             data.id = 0;
         }
-        d->engine->watchHandler()->beginCycle();
         d->engine->watchHandler()->insertData(data);
-        d->engine->watchHandler()->endCycle();
     }
 
     const QVariantList currentFrameScopes = currentFrame.value(_("scopes")).toList();
@@ -1785,11 +1783,8 @@ void QmlV8DebuggerClient::updateScope(const QVariant &bodyVal, const QVariant &r
     if (!handlesToLookup.isEmpty())
         d->lookup(handlesToLookup);
 
-    if (!locals.isEmpty()) {
-        d->engine->watchHandler()->beginCycle(false);
-        d->engine->watchHandler()->insertBulkData(locals);
-        d->engine->watchHandler()->endCycle();
-    }
+    if (!locals.isEmpty())
+        d->engine->watchHandler()->insertData(locals);
 }
 
 void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, const QVariant &bodyVal,
@@ -1810,7 +1805,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
             d->scope(index);
         //Also update "this"
         QByteArray iname("local.this");
-        const WatchData *parent = d->engine->watchHandler()->findItem(iname);
+        const WatchData *parent = d->engine->watchHandler()->findData(iname);
         d->localsAndWatchers.insertMulti(parent->id, iname);
         d->lookup(QList<int>() << parent->id);
 
@@ -1833,7 +1828,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
             WatchData data;
             //Do we have request to evaluate a local?
             if (exp.startsWith("local.")) {
-                const WatchData *watch = d->engine->watchHandler()->findItem(exp.toLatin1());
+                const WatchData *watch = d->engine->watchHandler()->findData(exp.toLatin1());
                 watchDataList << createWatchDataList(watch, body.properties, refsVal);
             } else {
                 QByteArray iname = d->engine->watchHandler()->watcherName(exp.toLatin1());
@@ -1854,9 +1849,7 @@ void QmlV8DebuggerClient::updateEvaluationResult(int sequence, bool success, con
                 watchDataList << data << createWatchDataList(&data, body.properties, refsVal);
             }
             //Insert the newly evaluated expression to the Watchers Window
-            d->engine->watchHandler()->beginCycle(false);
-            d->engine->watchHandler()->insertBulkData(watchDataList);
-            d->engine->watchHandler()->endCycle();
+            d->engine->watchHandler()->insertData(watchDataList);
         }
     }
 }
@@ -1933,7 +1926,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
         if (prepend.startsWith("local.") || prepend.startsWith("watch.")) {
             //Data for expanded local/watch
             //Could be an object or function
-            const WatchData *parent = d->engine->watchHandler()->findItem(prepend);
+            const WatchData *parent = d->engine->watchHandler()->findData(prepend);
             watchDataList << createWatchDataList(parent, bodyObjectData.properties, refsVal);
         } else {
             //rest
@@ -1952,9 +1945,7 @@ void QmlV8DebuggerClient::expandLocalsAndWatchers(const QVariant &bodyVal, const
         }
     }
 
-    d->engine->watchHandler()->beginCycle(false);
-    d->engine->watchHandler()->insertBulkData(watchDataList);
-    d->engine->watchHandler()->endCycle();
+    d->engine->watchHandler()->insertData(watchDataList);
 }
 
 QList<WatchData> QmlV8DebuggerClient::createWatchDataList(const WatchData *parent,
diff --git a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
index e4fe415cdd002ed1ce541040f13d3cd2f60d34b6..4b60edc7cb0ccfe25dd0456f7026e5600aba84a1 100644
--- a/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
+++ b/src/plugins/debugger/qml/qscriptdebuggerclient.cpp
@@ -403,6 +403,8 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
     QByteArray command;
     stream >> command;
 
+    WatchHandler *watchHandler = d->engine->watchHandler();
+
     if (command == "STOPPED") {
         d->engine->inferiorSpontaneousStop();
 
@@ -432,15 +434,13 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
 
         d->engine->stackHandler()->setFrames(ideStackFrames);
 
-        d->engine->watchHandler()->beginCycle();
         bool needPing = false;
 
         foreach (WatchData data, watches) {
-            data.iname = d->engine->watchHandler()->watcherName(data.exp);
-            d->engine->watchHandler()->insertData(data);
+            data.iname = watchHandler->watcherName(data.exp);
+            watchHandler->insertIncompleteData(data);
 
-            if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
-                    qint64(data.id) != -1) {
+            if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
                 needPing = true;
                 expandObject(data.iname,data.id);
             }
@@ -448,20 +448,16 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
 
         foreach (WatchData data, locals) {
             data.iname = "local." + data.exp;
-            d->engine->watchHandler()->insertData(data);
+            watchHandler->insertIncompleteData(data);
 
-            if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
-                    qint64(data.id) != -1) {
+            if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
                 needPing = true;
                 expandObject(data.iname,data.id);
             }
         }
 
-        if (needPing) {
+        if (needPing)
             sendPing();
-        } else {
-            d->engine->watchHandler()->endCycle();
-        }
 
         bool becauseOfException;
         stream >> becauseOfException;
@@ -518,12 +514,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
                              +  QLatin1String(iname) + QLatin1Char(' ') + data.value);
         data.iname = iname;
         if (iname.startsWith("watch.")) {
-            d->engine->watchHandler()->insertData(data);
+            watchHandler->insertIncompleteData(data);
         } else if (iname == "console") {
             d->engine->showMessage(data.value, QtMessageLogOutput);
         } else if (iname.startsWith("local.")) {
             data.name = data.name.left(data.name.indexOf(QLatin1Char(' ')));
-            d->engine->watchHandler()->insertData(data);
+            watchHandler->insertIncompleteData(data);
         } else {
             qWarning() << "QmlEngine: Unexcpected result: " << iname << data.value;
         }
@@ -538,10 +534,9 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
 
         foreach (WatchData data, result) {
             data.iname = iname + '.' + data.exp;
-            d->engine->watchHandler()->insertData(data);
+            watchHandler->insertIncompleteData(data);
 
-            if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
-                    qint64(data.id) != -1) {
+            if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
                 needPing = true;
                 expandObject(data.iname, data.id);
             }
@@ -560,14 +555,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
         d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
                              QLatin1String(command), QString::number(frameId),
                              QString::number(locals.size()), QString::number(watches.size())));
-        d->engine->watchHandler()->beginCycle();
         bool needPing = false;
         foreach (WatchData data, watches) {
-            data.iname = d->engine->watchHandler()->watcherName(data.exp);
-            d->engine->watchHandler()->insertData(data);
+            data.iname = watchHandler->watcherName(data.exp);
+            watchHandler->insertIncompleteData(data);
 
-            if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
-                    qint64(data.id) != -1) {
+            if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
                 needPing = true;
                 expandObject(data.iname, data.id);
             }
@@ -575,26 +568,19 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
 
         foreach (WatchData data, locals) {
             data.iname = "local." + data.exp;
-            d->engine->watchHandler()->insertData(data);
-            if (d->engine->watchHandler()->expandedINames().contains(data.iname) &&
-                    qint64(data.id) != -1) {
+            watchHandler->insertIncompleteData(data);
+            if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
                 needPing = true;
                 expandObject(data.iname, data.id);
             }
         }
         if (needPing)
             sendPing();
-        else
-            d->engine->watchHandler()->endCycle();
 
     } else if (command == "PONG") {
         int ping;
         stream >> ping;
-
         d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ') + QString::number(ping));
-
-        if (ping == d->ping)
-            d->engine->watchHandler()->endCycle();
     } else {
         qDebug() << Q_FUNC_INFO << "Unknown command: " << command;
         d->logReceiveMessage(QLatin1String(command) + QLatin1String(" UNKNOWN COMMAND!!"));
diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp
index 16d758f6c90cf770a672e04f85ff1474ed5656cc..efe52b8d41dd9ed5c0992746a76352460b424a67 100644
--- a/src/plugins/debugger/script/scriptengine.cpp
+++ b/src/plugins/debugger/script/scriptengine.cpp
@@ -651,7 +651,6 @@ bool ScriptEngine::checkForBreakCondition(bool byFunction)
 void ScriptEngine::updateLocals()
 {
     QScriptContext *context = m_scriptEngine->currentContext();
-    watchHandler()->beginCycle();
     SDEBUG(Q_FUNC_INFO);
 
     //
@@ -686,9 +685,7 @@ void ScriptEngine::updateLocals()
     data.iname = "local";
     data.name = _(data.iname);
 
-    watchHandler()->beginCycle();
     updateSubItem(data);
-    watchHandler()->endCycle();
     // FIXME: Use an extra thread. This here is evil.
     m_stopped = true;
     showStatusMessage(tr("Stopped."), 5000);
@@ -809,9 +806,9 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
     }
 
     SDEBUG(msgDebugInsert(data, children));
-    watchHandler()->insertData(data);
+    watchHandler()->insertIncompleteData(data);
     if (!children.isEmpty())
-        watchHandler()->insertBulkData(children);
+        watchHandler()->insertData(children);
 }
 
 DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp)
diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp
index be6efdcaad03469307a727250a0e72b2aa2e89a9..e9d35176266447a46b47f55ec9e7892f4726181e 100644
--- a/src/plugins/debugger/watchdata.cpp
+++ b/src/plugins/debugger/watchdata.cpp
@@ -143,7 +143,6 @@ WatchData::WatchData() :
     size(0),
     bitpos(0),
     bitsize(0),
-    generation(-1),
     hasChildren(false),
     valueEnabled(true),
     valueEditable(true),
@@ -399,8 +398,6 @@ QString WatchData::toToolTip() const
     if (size)
         formatToolTipRow(str, tr("Static Object Size"), tr("%1 bytes").arg(size));
     formatToolTipRow(str, tr("Internal ID"), QLatin1String(iname));
-    formatToolTipRow(str, tr("Generation"),
-        QString::number(generation));
     str << "</table></body></html>";
     return res;
 }
diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h
index 44f9f9762406de5188491590d48cb28004df32aa..2b63c0b71a215fba046f30184cf324b1a5025ad8 100644
--- a/src/plugins/debugger/watchdata.h
+++ b/src/plugins/debugger/watchdata.h
@@ -135,7 +135,6 @@ public:
     uint       size;         // Size
     uint       bitpos;       // Position within bit fields
     uint       bitsize;      // Size in case of bit fields
-    qint32     generation;   // When updated?
     bool hasChildren;
     bool valueEnabled;       // Value will be enabled or not
     bool valueEditable;      // Value will be editable
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index c9ada1d5b36facec9ac7a95ffa974557ca7db649..77bc4f9db5703d456f1c2afae918a2c8a21249f7 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -40,10 +40,6 @@
 #include "debuggerdialogs.h"
 #include "watchutils.h"
 
-#if USE_WATCH_MODEL_TEST
-#include "modeltest.h"
-#endif
-
 #include <utils/qtcassert.h>
 #include <utils/savedaction.h>
 
@@ -52,6 +48,7 @@
 #include <QDebug>
 #include <QEvent>
 #include <QFile>
+#include <QPointer>
 #include <QProcess>
 #include <QTextStream>
 #include <QtAlgorithms>
@@ -62,6 +59,12 @@
 #include <ctype.h>
 #include <utils/qtcassert.h>
 
+//#define USE_WATCH_MODEL_TEST 0
+//#define USE_EXPENSIVE_CHECKS 0
+
+#if USE_WATCH_MODEL_TEST
+#include "modeltest.h"
+#endif
 
 namespace Debugger {
 namespace Internal {
@@ -70,7 +73,13 @@ namespace Internal {
 enum { debugModel = 0 };
 
 #define MODEL_DEBUG(s) do { if (debugModel) qDebug() << s; } while (0)
-#define MODEL_DEBUGX(s) qDebug() << s
+
+#if USE_EXPENSIVE_CHECKS
+#define CHECK(s) s
+#else
+#define CHECK(s)
+#endif
+
 
 static QHash<QByteArray, int> theWatcherNames;
 static QHash<QByteArray, int> theTypeFormats;
@@ -100,126 +109,222 @@ static QByteArray stripForFormat(const QByteArray &ba)
     return res;
 }
 
-void WatchHandler::setUnprintableBase(int base)
-{
-    theUnprintableBase = base;
-    emitAllChanged();
-}
-
-int WatchHandler::unprintableBase()
-{
-    return theUnprintableBase;
-}
-
 ////////////////////////////////////////////////////////////////////
 //
 // WatchItem
 //
 ////////////////////////////////////////////////////////////////////
 
+// Used to make sure the item cache is notified of construction and
+// destruction of items.
+
+class WatchItem;
+WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+void itemDestructor(WatchModel *model, WatchItem *item);
+
 class WatchItem : public WatchData
 {
 public:
-    WatchItem() { parent = 0; }
-
-    ~WatchItem() {
-        if (parent != 0)
-            parent->children.removeOne(this);
-        qDeleteAll(children);
-    }
-
-    WatchItem(const WatchData &data) : WatchData(data)
-        { parent = 0; }
+    WatchItem *parent;
+    QList<WatchItem *> children;
 
-    void setData(const WatchData &data)
-        { static_cast<WatchData &>(*this) = data; }
+private:
+    friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+    friend void itemDestructor(WatchModel *model, WatchItem *item);
 
-    WatchItem *parent;
-    QList<WatchItem *> children;  // fetched children
+    WatchItem() { parent = 0; }
+    ~WatchItem() {}
+    WatchItem(const WatchItem &); // Not implemented.
 };
 
-
 ///////////////////////////////////////////////////////////////////////
 //
 // WatchModel
 //
 ///////////////////////////////////////////////////////////////////////
 
-WatchModel::WatchModel(WatchHandler *handler, WatchType type)
-    : QAbstractItemModel(handler), m_generationCounter(0),
-      m_handler(handler), m_type(type)
+class WatchModel : public QAbstractItemModel
 {
-    m_root = new WatchItem;
-    m_root->hasChildren = 1;
-    m_root->state = 0;
-    m_root->name = WatchHandler::tr("Root");
-    m_root->parent = 0;
+    Q_OBJECT
 
-    switch (m_type) {
-        case ReturnWatch:
-            m_root->iname = "return";
-            m_root->name = WatchHandler::tr("Return Value");
-            break;
-        case LocalsWatch:
-            m_root->iname = "local";
-            m_root->name = WatchHandler::tr("Locals");
-            break;
-        case WatchersWatch:
-            m_root->iname = "watch";
-            m_root->name = WatchHandler::tr("Expressions");
-            break;
-        case TooltipsWatch:
-            m_root->iname = "tooltip";
-            m_root->name = WatchHandler::tr("Tooltip");
-            break;
-        case InspectWatch:
-            m_root->iname = "inspect";
-            m_root->name = WatchHandler::tr("Inspector");
-            break;
-    }
+private:
+    explicit WatchModel(WatchHandler *handler);
+    ~WatchModel();
+
+    friend WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname);
+    friend void itemDestructor(WatchModel *model, WatchItem *item);
+
+public:
+    int rowCount(const QModelIndex &idx = QModelIndex()) const;
+    int columnCount(const QModelIndex &idx) const;
+
+signals:
+    void currentIndexRequested(const QModelIndex &idx);
+    void itemIsExpanded(const QModelIndex &idx);
+
+private:
+    QVariant data(const QModelIndex &idx, int role) const;
+    bool setData(const QModelIndex &idx, const QVariant &value, int role);
+    QModelIndex index(int, int, const QModelIndex &idx) const;
+    QModelIndex parent(const QModelIndex &idx) const;
+    bool hasChildren(const QModelIndex &idx) const;
+    Qt::ItemFlags flags(const QModelIndex &idx) const;
+    QVariant headerData(int section, Qt::Orientation orientation,
+        int role = Qt::DisplayRole) const;
+    bool canFetchMore(const QModelIndex &parent) const;
+    void fetchMore(const QModelIndex &parent);
+
+    void invalidateAll(const QModelIndex &parentIndex = QModelIndex());
+    WatchItem *createItem(const QByteArray &iname, const QString &name, WatchItem *parent);
+
+    friend class WatchHandler;
+
+    WatchItem *watchItem(const QModelIndex &) const;
+    QModelIndex watchIndex(const WatchItem *needle) const;
+    QModelIndex watchIndexHelper(const WatchItem *needle,
+        const WatchItem *parentItem, const QModelIndex &parentIndex) const;
+
+    void insertDataItem(const WatchData &data);
+    Q_SLOT void reinsertAllData();
+    void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data);
+    void insertBulkData(const QList<WatchData> &data);
+    QString displayForAutoTest(const QByteArray &iname) const;
+    void reinitialize();
+    void destroyItem(WatchItem *item); // With model notification.
+    void destroyChildren(WatchItem *item); // With model notification.
+    void destroyHelper(const QList<WatchItem *> &items); // Without model notification.
+    void emitDataChanged(int column,
+        const QModelIndex &parentIndex = QModelIndex());
+
+    friend QDebug operator<<(QDebug d, const WatchModel &m);
+
+    void dump();
+    void dumpHelper(WatchItem *item);
+    Q_SLOT void emitAllChanged();
+
+    void showInEditorHelper(QString *contents, WatchItem *item, int level);
+    void setCurrentItem(const QByteArray &iname);
+
+    QString displayType(const WatchData &typeIn) const;
+    QString formattedValue(const WatchData &data) const;
+    QString removeInitialNamespace(QString str) const;
+    QString removeNamespaces(QString str) const;
+    void formatRequests(QByteArray *out, const WatchItem *item) const;
+    DebuggerEngine *engine() const;
+    QString display(const WatchItem *item, int col) const;
+    int itemFormat(const WatchData &data) const;
+    bool contentIsValid() const;
+
+    WatchHandler *m_handler; // Not owned.
+
+    WatchItem *m_root; // Owned.
+    WatchItem *m_localsRoot; // Not owned.
+    WatchItem *m_inspectorRoot; // Not owned.
+    WatchItem *m_watchRoot; // Not owned.
+    WatchItem *m_returnRoot; // Not owned.
+    WatchItem *m_tooltipRoot; // Not owned.
+
+    QSet<QByteArray> m_expandedINames;
+    QSet<QByteArray> m_fetchTriggered;
+
+    QStringList typeFormatList(const WatchData &data) const;
+    TypeFormats m_reportedTypeFormats;
+
+    // QWidgets and QProcesses taking care of special displays.
+    typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
+    EditHandlers m_editHandlers;
+
+    WatchItem *createItem(const QByteArray &iname);
+    WatchItem *createItem(const WatchData &data);
+    void assignData(WatchItem *item, const WatchData &data);
+    WatchItem *findItem(const QByteArray &iname) const;
+    friend class WatchItem;
+    QHash<QByteArray, WatchItem *> m_cache;
+
+    #if USE_EXPENSIVE_CHECKS
+    QHash<const WatchItem *, QByteArray> m_cache2;
+    void checkTree();
+    void checkItem(const WatchItem *item) const;
+    void checkTree(WatchItem *item, QSet<QByteArray> *inames);
+    #endif
+};
+
+WatchModel::WatchModel(WatchHandler *handler)
+    : m_handler(handler)
+{
+    m_root = createItem(QByteArray(), tr("Root"), 0);
+    // Note: Needs to stay
+    m_localsRoot = createItem("local", tr("Locals"), m_root);
+    m_inspectorRoot = createItem("inspect", tr("Inspector"), m_root);
+    m_watchRoot = createItem("watch", tr("Expressions"), m_root);
+    m_returnRoot = createItem("return", tr("Return Value"), m_root);
+    m_tooltipRoot = createItem("tooltip", tr("Tooltip"), m_root);
+
+    connect(debuggerCore()->action(SortStructMembers), SIGNAL(valueChanged(QVariant)),
+        SLOT(reinsertAllData()));
+    connect(debuggerCore()->action(ShowStdNamespace), SIGNAL(valueChanged(QVariant)),
+        SLOT(reinsertAllData()));
+    connect(debuggerCore()->action(ShowQtNamespace), SIGNAL(valueChanged(QVariant)),
+        SLOT(reinsertAllData()));
 }
 
 WatchModel::~WatchModel()
 {
-    delete m_root;
+    CHECK(checkItem(m_root));
+    destroyChildren(m_root);
+    itemDestructor(this, m_root);
+    QTC_CHECK(m_cache.isEmpty());
 }
 
-WatchItem *WatchModel::rootItem() const
+WatchItem *itemConstructor(WatchModel *model, const QByteArray &iname)
 {
-    return m_root;
+    QTC_CHECK(!model->m_cache.contains(iname));
+    WatchItem *item = new WatchItem();
+    item->iname = iname;
+    model->m_cache[iname] = item;
+    CHECK(model->m_cache2[item] = iname);
+    CHECK(model->checkItem(item));
+    return item;
 }
 
-void WatchModel::reinitialize()
+void itemDestructor(WatchModel *model, WatchItem *item)
 {
-    int n = m_root->children.size();
-    if (n == 0)
-        return;
-    //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << m_root->iname);
-    QModelIndex index = watchIndex(m_root);
-    beginRemoveRows(index, 0, n - 1);
-    qDeleteAll(m_root->children);
-    m_root->children.clear();
-    endRemoveRows();
+    QTC_ASSERT(model->m_cache.value(item->iname) == item, return);
+    CHECK(model->checkItem(item));
+    CHECK(model->m_cache2.remove(item));
+    model->m_cache.remove(item->iname);
+    delete item;
 }
 
-void WatchModel::emitAllChanged()
+WatchItem *WatchModel::createItem(const QByteArray &iname, const QString &name, WatchItem *parent)
 {
-    emit layoutChanged();
+    WatchItem *item = itemConstructor(this, iname);
+    item->name = name;
+    item->hasChildren = true; // parent == 0;
+    item->state = 0;
+    item->parent = parent;
+    if (parent)
+        parent->children.append(item);
+    return item;
 }
 
-void WatchModel::beginCycle(bool fullCycle)
+void WatchModel::reinitialize()
 {
-    if (fullCycle)
-        m_generationCounter++;
-
-    //emit enableUpdates(false);
+    CHECK(checkTree());
+    //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << m_root->iname);
+    QTC_CHECK(m_root->children.size() == 5);
+    destroyChildren(m_localsRoot);
+    destroyChildren(m_watchRoot);
+    destroyChildren(m_returnRoot);
+    destroyChildren(m_tooltipRoot);
+    destroyChildren(m_inspectorRoot);
+    QTC_CHECK(m_cache.size() == 6);
+    CHECK(checkTree());
 }
 
-void WatchModel::endCycle()
+void WatchModel::emitAllChanged()
 {
-    removeOutdated();
-    m_fetchTriggered.clear();
-    //emit enableUpdates(true);
+    emit layoutChanged();
 }
 
 DebuggerEngine *WatchModel::engine() const
@@ -237,43 +342,85 @@ void WatchModel::dump()
 void WatchModel::dumpHelper(WatchItem *item)
 {
     qDebug() << "ITEM: " << item->iname
-        << (item->parent ? item->parent->iname : "<none>")
-        << item->generation;
+        << (item->parent ? item->parent->iname : "<none>");
     foreach (WatchItem *child, item->children)
         dumpHelper(child);
 }
 
-void WatchModel::removeOutdated()
+void WatchModel::destroyHelper(const QList<WatchItem *> &items)
 {
-    foreach (WatchItem *child, m_root->children)
-        removeOutdatedHelper(child);
-#if DEBUG_MODEL
-#if USE_WATCH_MODEL_TEST
-    (void) new ModelTest(this, this);
-#endif
-#endif
-}
-
-void WatchModel::removeOutdatedHelper(WatchItem *item)
-{
-    if (item->generation < m_generationCounter) {
-        destroyItem(item);
-    } else {
-        foreach (WatchItem *child, item->children)
-            removeOutdatedHelper(child);
+    for (int i = items.size(); --i >= 0; ) {
+        WatchItem *item = items.at(i);
+        destroyHelper(item->children);
+        itemDestructor(this, item);
     }
 }
 
 void WatchModel::destroyItem(WatchItem *item)
 {
+    const QByteArray iname = item->iname;
+    CHECK(checkTree());
+    QTC_ASSERT(m_cache.contains(iname), return);
+
+    // Deregister from model and parent.
+    // It's sufficient to do this non-recursively.
     WatchItem *parent = item->parent;
-    QModelIndex index = watchIndex(parent);
-    int n = parent->children.indexOf(item);
+    QTC_ASSERT(parent, return);
+    QModelIndex parentIndex = watchIndex(parent);
+    const int i = parent->children.indexOf(item);
     //MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n);
-    beginRemoveRows(index, n, n);
-    parent->children.removeAt(n);
+    beginRemoveRows(parentIndex, i, i);
+    parent->children.removeAt(i);
     endRemoveRows();
-    delete item;
+
+    // Destroy contents.
+    destroyHelper(item->children);
+    itemDestructor(this, item);
+    QTC_ASSERT(!m_cache.contains(iname), return);
+    CHECK(checkTree());
+}
+
+void WatchModel::destroyChildren(WatchItem *item)
+{
+    CHECK(checkTree());
+    QTC_ASSERT(m_cache.contains(item->iname), return);
+    if (item->children.isEmpty())
+        return;
+
+    QList<WatchItem *> items = item->children;
+
+    // Deregister from model and parent.
+    // It's sufficient to do this non-recursively.
+    QModelIndex idx = watchIndex(item);
+    beginRemoveRows(idx, 0, items.size() - 1);
+    item->children.clear();
+    endRemoveRows();
+
+    // Destroy contents.
+    destroyHelper(items);
+    CHECK(checkTree());
+}
+
+WatchItem *WatchModel::findItem(const QByteArray &iname) const
+{
+    return m_cache.value(iname, 0);
+}
+
+WatchItem *WatchModel::createItem(const WatchData &data)
+{
+    WatchItem *item = itemConstructor(this, data.iname);
+    static_cast<WatchData &>(*item) = data;
+    return item;
+}
+
+void WatchModel::assignData(WatchItem *item, const WatchData &data)
+{
+    CHECK(checkItem(item));
+    QTC_ASSERT(data.iname == item->iname,
+        m_cache.remove(item->iname);
+        m_cache[data.iname] = item);
+    static_cast<WatchData &>(*item) = data;
+    CHECK(checkItem(item));
 }
 
 void WatchModel::reinsertAllData()
@@ -281,26 +428,21 @@ void WatchModel::reinsertAllData()
     QList<WatchData> list;
     reinsertAllDataHelper(m_root, &list);
     reinitialize();
-    foreach (WatchItem data, list) {
-        data.setAllUnneeded();
-        insertData(data);
-    }
-    layoutChanged();
+    insertBulkData(list);
 }
 
 void WatchModel::reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data)
 {
     data->append(*item);
+    data->back().setAllUnneeded();
     foreach (WatchItem *child, item->children)
         reinsertAllDataHelper(child, data);
 }
 
 static QByteArray parentName(const QByteArray &iname)
 {
-    int pos = iname.lastIndexOf('.');
-    if (pos == -1)
-        return QByteArray();
-    return iname.left(pos);
+    const int pos = iname.lastIndexOf('.');
+    return pos == -1 ? QByteArray() : iname.left(pos);
 }
 
 static QString niceTypeHelper(const QByteArray &typeIn)
@@ -576,20 +718,27 @@ static inline QVariant editValue(const WatchData &d)
     return QVariant(translate(stringValue));
 }
 
-bool WatchModel::canFetchMore(const QModelIndex &index) const
+bool WatchModel::canFetchMore(const QModelIndex &idx) const
 {
-    WatchItem *item = watchItem(index);
+    if (!idx.isValid())
+        return false;
+    if (!contentIsValid())
+        return false;
+    WatchItem *item = watchItem(idx);
     QTC_ASSERT(item, return false);
-    return index.isValid() && contentIsValid() && !m_fetchTriggered.contains(item->iname);
+    if (!item->iname.contains('.'))
+        return false;
+    return !m_fetchTriggered.contains(item->iname);
 }
 
-void WatchModel::fetchMore(const QModelIndex &index)
+void WatchModel::fetchMore(const QModelIndex &idx)
 {
-    QTC_ASSERT(index.isValid(), return);
-    WatchItem *item = watchItem(index);
+    if (!idx.isValid())
+        return; // Triggered by ModelTester.
+    WatchItem *item = watchItem(idx);
     QTC_ASSERT(item, return);
     QTC_ASSERT(!m_fetchTriggered.contains(item->iname), return);
-    m_handler->m_expandedINames.insert(item->iname);
+    m_expandedINames.insert(item->iname);
     m_fetchTriggered.insert(item->iname);
     if (item->children.isEmpty()) {
         WatchData data = *item;
@@ -634,6 +783,8 @@ QModelIndex WatchModel::parent(const QModelIndex &idx) const
 
 int WatchModel::rowCount(const QModelIndex &idx) const
 {
+    if (!idx.isValid())
+        return m_root->children.size();
     if (idx.column() > 0)
         return 0;
     return watchItem(idx)->children.size();
@@ -653,12 +804,15 @@ bool WatchModel::hasChildren(const QModelIndex &parent) const
 
 WatchItem *WatchModel::watchItem(const QModelIndex &idx) const
 {
-    return idx.isValid()
+    WatchItem *item = idx.isValid()
         ? static_cast<WatchItem*>(idx.internalPointer()) : m_root;
+    CHECK(checkItem(item));
+    return item;
 }
 
 QModelIndex WatchModel::watchIndex(const WatchItem *item) const
 {
+    CHECK(checkItem(item));
     return watchIndexHelper(item, m_root, QModelIndex());
 }
 
@@ -719,13 +873,40 @@ int WatchModel::itemFormat(const WatchData &data) const
 
 bool WatchModel::contentIsValid() const
 {
+    // FIXME:
     // inspector doesn't follow normal beginCycle()/endCycle()
-    if (m_type == InspectWatch)
-        return true;
+    //if (m_type == InspectWatch)
+    //    return true;
     return m_handler->m_contentsValid;
 }
 
-static inline QString expression(const WatchItem *item)
+#if USE_EXPENSIVE_CHECKS
+void WatchModel::checkTree()
+{
+    QSet<QByteArray> inames;
+    checkTree(m_root, &inames);
+    QSet<QByteArray> current = m_cache.keys().toSet();
+    Q_ASSERT(inames == current);
+}
+
+void WatchModel::checkTree(WatchItem *item, QSet<QByteArray> *inames)
+{
+    checkItem(item);
+    inames->insert(item->iname);
+    for (int i = 0, n = item->children.size(); i != n; ++i)
+        checkTree(item->children.at(i), inames);
+}
+
+void WatchModel::checkItem(const WatchItem *item) const
+{
+    Q_ASSERT(item->children.size() < 1000 * 1000);
+    Q_ASSERT(m_cache2.contains(item));
+    Q_ASSERT(m_cache2.value(item) == item->iname);
+    Q_ASSERT(m_cache.value(item->iname) == item);
+}
+#endif
+
+static QString expression(const WatchItem *item)
 {
     if (!item->exp.isEmpty())
          return QString::fromLatin1(item->exp);
@@ -746,11 +927,11 @@ QString WatchModel::display(const WatchItem *item, int col) const
     QString result;
     switch (col) {
         case 0:
-            if (m_type == WatchersWatch && item->name.isEmpty())
+            if (item->parent == m_watchRoot && item->name.isEmpty())
                 result = tr("<Edit>");
-            else if (m_type == ReturnWatch && item->iname.count('.') == 1)
+            else if (item->parent == m_returnRoot)
                 result = tr("returned value");
-            else if (item->name == QLatin1String("*") && item->parent)
+            else if (item->name == QLatin1String("*"))
                 result = QLatin1Char('*') + item->parent->name;
             else
                 result = removeInitialNamespace(item->name);
@@ -774,7 +955,7 @@ QString WatchModel::display(const WatchItem *item, int col) const
 
 QString WatchModel::displayForAutoTest(const QByteArray &iname) const
 {
-    const WatchItem *item = findItem(iname, m_root);
+    WatchItem *item = findItem(iname);
     if (item)
         return display(item, 1) + QLatin1Char(' ') + display(item, 2);
     return QString();
@@ -782,6 +963,9 @@ QString WatchModel::displayForAutoTest(const QByteArray &iname) const
 
 QVariant WatchModel::data(const QModelIndex &idx, int role) const
 {
+    if (!idx.isValid())
+        return QVariant(); // Triggered by ModelTester.
+
     const WatchItem *item = watchItem(idx);
     const WatchItem &data = *item;
 
@@ -840,10 +1024,10 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
             return data.iname;
 
         case LocalsExpandedRole:
-            return m_handler->m_expandedINames.contains(data.iname);
+            return m_expandedINames.contains(data.iname);
 
         case LocalsTypeFormatListRole:
-            return m_handler->typeFormatList(data);
+            return typeFormatList(data);
 
         case LocalsTypeRole:
             return removeNamespaces(displayType(data));
@@ -890,13 +1074,16 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
     return QVariant();
 }
 
-bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
+bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role)
 {
-    WatchItem &data = *watchItem(index);
+    if (!idx.isValid())
+        return false; // Triggered by ModelTester.
+
+    WatchItem &data = *watchItem(idx);
 
     switch (role) {
         case Qt::EditRole:
-            switch (index.column()) {
+            switch (idx.column()) {
             case 0: // Watch expression: See delegate.
                 break;
             case 1: // Change value
@@ -909,10 +1096,10 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
         case LocalsExpandedRole:
             if (value.toBool()) {
                 // Should already have been triggered by fetchMore()
-                //QTC_CHECK(m_handler->m_expandedINames.contains(data.iname));
-                m_handler->m_expandedINames.insert(data.iname);
+                //QTC_CHECK(m_expandedINames.contains(data.iname));
+                m_expandedINames.insert(data.iname);
             } else {
-                m_handler->m_expandedINames.remove(data.iname);
+                m_expandedINames.remove(data.iname);
             }
             break;
 
@@ -933,7 +1120,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
         }
     }
 
-    emit dataChanged(index, index);
+    //emit dataChanged(idx, idx);
     return true;
 }
 
@@ -990,7 +1177,7 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro
     return QVariant();
 }
 
-QStringList WatchHandler::typeFormatList(const WatchData &data) const
+QStringList WatchModel::typeFormatList(const WatchData &data) const
 {
     if (data.referencingAddress || isPointerType(data.type))
         return QStringList()
@@ -1026,7 +1213,7 @@ QStringList WatchHandler::typeFormatList(const WatchData &data) const
 }
 
 // Determine sort order of watch items by sort order or alphabetical inames
-// according to setting 'SortStructMembers'. We need a map key for bulkInsert
+// according to setting 'SortStructMembers'. We need a map key for insertBulkData
 // and a predicate for finding the insertion position of a single item.
 
 // Set this before using any of the below according to action
@@ -1086,98 +1273,153 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
     return it - list.begin();
 }
 
-void WatchModel::insertData(const WatchData &data)
+void WatchModel::insertDataItem(const WatchData &data)
 {
+#if USE_WATCH_MODEL_TEST
+    (void) new ModelTest(this, this);
+#endif
+    m_fetchTriggered.remove(data.iname);
+    CHECK(checkTree());
+
     QTC_ASSERT(!data.iname.isEmpty(), qDebug() << data.toString(); return);
-    WatchItem *parent = findItem(parentName(data.iname), m_root);
+    WatchItem *parent = findItem(parentName(data.iname));
     if (!parent) {
         WatchData parent;
         parent.iname = parentName(data.iname);
         MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
         if (!parent.iname.isEmpty())
-            insertData(parent);
+            insertDataItem(parent);
         return;
     }
-    QModelIndex index = watchIndex(parent);
-    if (WatchItem *oldItem = findItem(data.iname, parent)) {
-        bool hadChildren = oldItem->hasChildren;
+
+    WatchItem *item = findItem(data.iname);
+#if 0
+    if (item) {
         // Overwrite old entry.
-        bool hasChanged = oldItem->hasChanged(data);
-        oldItem->setData(data);
-        oldItem->changed = hasChanged;
-        oldItem->generation = m_generationCounter;
-        QModelIndex idx = watchIndex(oldItem);
-        emit dataChanged(idx, idx.sibling(idx.row(), 2));
+        bool hasChanged = item->hasChanged(data);
+        assignData(item, data);
+        item->changed = hasChanged;
+        //    QModelIndex idx = watchIndex(oldItem);
+        //    emit dataChanged(idx, idx.sibling(idx.row(), 2));
+    } else {
+        // Add new entry.
+        item = createItem(data);
+        item->parent = parent;
+        item->changed = true;
+    }
+    const int n = findInsertPosition(parent->children, item);
+    QModelIndex idx = watchIndex(parent);
+    beginInsertRows(idx, n, n);
+    parent->children.insert(n, item);
+    endInsertRows();
+#else
+    if (item) {
+        // Remove old children.
+        destroyChildren(item);
 
-        // This works around https://bugreports.qt-project.org/browse/QTBUG-7115
-        // by creating and destroying a dummy child item.
-        if (!hadChildren && oldItem->hasChildren) {
-            WatchData dummy = data;
-            dummy.iname = data.iname + ".x";
-            dummy.hasChildren = false;
-            dummy.setAllUnneeded();
-            insertData(dummy);
-            destroyItem(findItem(dummy.iname, m_root));
-        }
+        // Overwrite old entry.
+        bool hasChanged = item->hasChanged(data);
+        assignData(item, data);
+        item->changed = hasChanged;
+        QModelIndex idx = watchIndex(item);
+        emit dataChanged(idx, idx.sibling(idx.row(), 2));
     } else {
         // Add new entry.
-        WatchItem *item = new WatchItem(data);
+        item = createItem(data);
         item->parent = parent;
-        item->generation = m_generationCounter;
         item->changed = true;
-        const int n = findInsertPosition(parent->children, item);
-        beginInsertRows(index, n, n);
-        parent->children.insert(n, item);
+        const int row = findInsertPosition(parent->children, item);
+        QModelIndex idx = watchIndex(parent);
+        beginInsertRows(idx, row, row);
+        parent->children.insert(row, item);
         endInsertRows();
+        if (m_expandedINames.contains(parentName(data.iname))) {
+            emit itemIsExpanded(idx);
+        }
+//        if (m_expandedINames.contains(data.iname)) {
+//            QModelIndex child = index(row, 0, idx);
+//            emit itemIsExpanded(child);
+//        }
     }
+#endif
 }
 
 void WatchModel::insertBulkData(const QList<WatchData> &list)
 {
+    foreach (const WatchData &data, list)
+        insertDataItem(data);
+    CHECK(checkTree());
+    return;
+
 #if 0
-    for (int i = 0; i != list.size(); ++i)
-        insertData(list.at(i));
+    QMap<QByteArray, QList<WatchData> > hash;
+
+    foreach (const WatchData &data, list) {
+        // we insert everything, including incomplete stuff
+        // to reduce the number of row add operations in the model.
+        if (data.isValid()) {
+            hash[parentName(data.iname)].append(data);
+        } else {
+            qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s",
+                __FILE__, __LINE__, qPrintable(data.toString()));
+        }
+    }
+    foreach (const QByteArray &parentIName, hash.keys()) {
+        // FIXME
+        insertBulkDataX(hash[parentIName]);
+    }
+
+    foreach (const WatchData &data, list) {
+        if (data.isSomethingNeeded())
+            m_engine->updateWatchData(data);
+    }
+    const int n = list.size();
+#if 0
+    for (int i = 0; i != n; ++i)
+        insertData(list.at(i), false);
+    layoutChanged();
     return;
 #endif
     // This method does not properly insert items in proper "iname sort
-    // order", leading to random removal of items in removeOutdated();
+    // order".
 
     //qDebug() << "WMI:" << list.toString();
     //static int bulk = 0;
     //foreach (const WatchItem &data, list)
     //    qDebug() << "BULK: " << ++bulk << data.toString();
-    QTC_ASSERT(!list.isEmpty(), return);
+    QTC_ASSERT(n > 0, return);
     QByteArray parentIName = parentName(list.at(0).iname);
-    WatchItem *parent = findItem(parentIName, m_root);
+    WatchItem *parent = m_handler->findItem(parentIName);
     if (!parent) {
         WatchData parent;
         parent.iname = parentIName;
-        insertData(parent);
+        insertDataItem(parent, true);
         MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << list.at(0).iname);
         return;
     }
-    QModelIndex index = watchIndex(parent);
+    QModelIndex idx = watchIndex(parent);
 
     sortWatchDataAlphabetically = debuggerCore()->boolSetting(SortStructMembers);
     QMap<WatchDataSortKey, WatchData> newList;
     typedef QMap<WatchDataSortKey, WatchData>::iterator Iterator;
-    foreach (const WatchItem &data, list)
-        newList.insert(WatchDataSortKey(data), data);
-    if (newList.size() != list.size()) {
-        qDebug() << "LIST: ";
-        foreach (const WatchItem &data, list)
-            qDebug() << data.toString();
-        qDebug() << "NEW LIST: ";
-        foreach (const WatchItem &data, newList)
-            qDebug() << data.toString();
-        qDebug() << "P->CHILDREN: ";
-        foreach (const WatchItem *item, parent->children)
-            qDebug() << item->toString();
-        qDebug()
-            << "P->CHILDREN.SIZE: " << parent->children.size()
-            << "NEWLIST SIZE: " << newList.size()
-            << "LIST SIZE: " << list.size();
-    }
+    for (int i = 0; i != n; ++i)
+        newList.insert(WatchDataSortKey(list.at(i)), list.at(i));
+
+    //if (newList.size() != n) {
+    //    qDebug() << "LIST: ";
+    //    for (int i = 0; i != n; ++i)
+    //        qDebug() << list.at(i).toString();
+    //    qDebug() << "NEW LIST: ";
+    //    foreach (const WatchData &data, newList)
+    //        qDebug() << data.toString();
+    //    qDebug() << "P->CHILDREN: ";
+    //    foreach (const WatchItem *item, parent->children)
+    //        qDebug() << item->toString();
+    //    qDebug()
+    //        << "P->CHILDREN.SIZE: " << parent->children.size()
+    //        << "NEWLIST SIZE: " << newList.size()
+    //        << "LIST SIZE: " << list.size();
+    //}
     QTC_ASSERT(newList.size() == list.size(), return);
 
     foreach (WatchItem *oldItem, parent->children) {
@@ -1185,12 +1427,9 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
         Iterator it = newList.find(oldSortKey);
         if (it == newList.end()) {
             WatchData data = *oldItem;
-            data.generation = m_generationCounter;
             newList.insert(oldSortKey, data);
         } else {
             it->changed = it->hasChanged(*oldItem);
-            if (it->generation == -1)
-                it->generation = m_generationCounter;
         }
     }
 
@@ -1206,9 +1445,7 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
         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 = m_generationCounter;
+            m_handler->setData(parent->children[i], *it);
             //emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2));
         } else {
             //qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname;
@@ -1218,14 +1455,12 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
 
     // add new items
     if (oldCount < newList.size()) {
-        beginInsertRows(index, oldCount, newList.size() - 1);
+        beginInsertRows(idx, oldCount, newList.size() - 1);
         //MODEL_DEBUG("INSERT : " << data.iname << data.value);
         for (int i = oldCount; i < newList.size(); ++i, ++it) {
-            WatchItem *item = new WatchItem(*it);
+            WatchItem *item = m_handler->createItem(*it);
             qDebug() << "ADDING" << it->iname;
             item->parent = parent;
-            if (item->generation == -1)
-                item->generation = m_generationCounter;
             item->changed = true;
             parent->children.append(item);
         }
@@ -1233,16 +1468,7 @@ void WatchModel::insertBulkData(const QList<WatchData> &list)
     }
     //qDebug() << "ITEMS: " << parent->children.size();
     dump();
-}
-
-WatchItem *WatchModel::findItem(const QByteArray &iname, WatchItem *root) const
-{
-    if (root->iname == iname)
-        return root;
-    for (int i = root->children.size(); --i >= 0; )
-        if (WatchItem *item = findItem(iname, root->children.at(i)))
-            return item;
-    return 0;
+#endif
 }
 
 static void debugRecursion(QDebug &d, const WatchItem *item, int depth)
@@ -1271,6 +1497,29 @@ void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
         formatRequests(out, child);
 }
 
+void WatchModel::showInEditorHelper(QString *contents, WatchItem *item, int depth)
+{
+    const QChar tab = QLatin1Char('\t');
+    const QChar nl = QLatin1Char('\n');
+    contents->append(QString(depth, tab));
+    contents->append(item->name);
+    contents->append(tab);
+    contents->append(item->value);
+    contents->append(tab);
+    contents->append(item->type);
+    contents->append(nl);
+    foreach (WatchItem *child, item->children)
+       showInEditorHelper(contents, child, depth + 1);
+}
+
+void WatchModel::setCurrentItem(const QByteArray &iname)
+{
+    if (WatchItem *item = findItem(iname)) {
+        QModelIndex idx = watchIndex(item);
+        emit currentIndexRequested(idx);
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////
 //
 // WatchHandler
@@ -1280,92 +1529,39 @@ void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
 WatchHandler::WatchHandler(DebuggerEngine *engine)
 {
     m_engine = engine;
-    m_inChange = false;
     m_watcherCounter = debuggerCore()->sessionValue(QLatin1String("Watchers"))
             .toStringList().count();
-
-    m_return = new WatchModel(this, ReturnWatch);
-    m_locals = new WatchModel(this, LocalsWatch);
-    m_watchers = new WatchModel(this, WatchersWatch);
-    m_tooltips = new WatchModel(this, TooltipsWatch);
-    m_inspect = new WatchModel(this, InspectWatch);
-
+    m_model = new WatchModel(this);
     m_contentsValid = false;
+    m_contentsValid = true; // FIXME
     m_resetLocationScheduled = false;
-
-    connect(debuggerCore()->action(SortStructMembers), SIGNAL(valueChanged(QVariant)),
-           SLOT(reinsertAllData()));
-    connect(debuggerCore()->action(ShowStdNamespace), SIGNAL(valueChanged(QVariant)),
-           SLOT(reinsertAllData()));
-    connect(debuggerCore()->action(ShowQtNamespace), SIGNAL(valueChanged(QVariant)),
-           SLOT(reinsertAllData()));
-}
-
-void WatchHandler::beginCycle(bool fullCycle)
-{
-    m_return->beginCycle(fullCycle);
-    m_locals->beginCycle(fullCycle);
-    m_watchers->beginCycle(fullCycle);
-    m_tooltips->beginCycle(fullCycle);
-    // don't sync m_inspect here: It's updated on it's own
-}
-
-void WatchHandler::endCycle()
-{
-    m_return->endCycle();
-    m_locals->endCycle();
-    m_watchers->endCycle();
-    m_tooltips->endCycle();
-
-    m_contentsValid = true;
-    m_resetLocationScheduled = false;
-
-    updateWatchersWindow();
 }
 
-void WatchHandler::beginCycle(WatchType type, bool fullCycle)
+WatchHandler::~WatchHandler()
 {
-    model(type)->beginCycle(fullCycle);
-}
-
-void WatchHandler::endCycle(WatchType type)
-{
-    model(type)->endCycle();
+    // Do it manually to prevent calling back in model destructors
+    // after m_cache is destroyed.
+    delete m_model;
+    m_model = 0;
 }
 
 void WatchHandler::cleanup()
 {
-    m_expandedINames.clear();
+    m_model->m_expandedINames.clear();
     theWatcherNames.remove(QByteArray());
-    m_return->reinitialize();
-    m_locals->reinitialize();
-    m_tooltips->reinitialize();
-    m_inspect->reinitialize();
-    m_return->m_fetchTriggered.clear();
-    m_locals->m_fetchTriggered.clear();
-    m_watchers->m_fetchTriggered.clear();
-    m_tooltips->m_fetchTriggered.clear();
-    m_inspect->m_fetchTriggered.clear();
+    m_model->reinitialize();
+    m_model->m_fetchTriggered.clear();
 #if 1
-    for (EditHandlers::ConstIterator it = m_editHandlers.begin();
-            it != m_editHandlers.end(); ++it) {
+    for (WatchModel::EditHandlers::ConstIterator it = m_model->m_editHandlers.begin();
+            it != m_model->m_editHandlers.end(); ++it) {
         if (!it.value().isNull())
             delete it.value();
     }
-    m_editHandlers.clear();
+    m_model->m_editHandlers.clear();
 #endif
 }
 
-void WatchHandler::emitAllChanged()
-{
-    m_return->emitAllChanged();
-    m_locals->emitAllChanged();
-    m_watchers->emitAllChanged();
-    m_tooltips->emitAllChanged();
-    m_inspect->emitAllChanged();
-}
-
-void WatchHandler::insertData(const WatchData &data)
+void WatchHandler::insertIncompleteData(const WatchData &data)
 {
     MODEL_DEBUG("INSERTDATA: " << data.toString());
     if (!data.isValid()) {
@@ -1374,14 +1570,10 @@ void WatchHandler::insertData(const WatchData &data)
         return;
     }
 
-    if (data.isSomethingNeeded() && data.iname.contains(".")) {
+    if (data.isSomethingNeeded() && data.iname.contains('.')) {
         MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
-        if (!m_engine->isSynchronous()
-                || data.isInspect()) {
-            WatchModel *model = modelForIName(data.iname);
-            QTC_ASSERT(model, return);
-            model->insertData(data);
-
+        if (!m_engine->isSynchronous() || data.isInspect()) {
+            m_model->insertDataItem(data);
             m_engine->updateWatchData(data);
         } else {
             m_engine->showMessage(QLatin1String("ENDLESS LOOP: SOMETHING NEEDED: ")
@@ -1390,71 +1582,47 @@ void WatchHandler::insertData(const WatchData &data)
             data1.setAllUnneeded();
             data1.setValue(QLatin1String("<unavailable synchronous data>"));
             data1.setHasChildren(false);
-            WatchModel *model = modelForIName(data.iname);
-            QTC_ASSERT(model, return);
-            model->insertData(data1);
+            m_model->insertDataItem(data1);
         }
     } else {
-        WatchModel *model = modelForIName(data.iname);
-        QTC_ASSERT(model, return);
         MODEL_DEBUG("NOTHING NEEDED: " << data.toString());
-        model->insertData(data);
+        m_model->insertDataItem(data);
         showEditValue(data);
     }
 }
 
-void WatchHandler::reinsertAllData()
+void WatchHandler::insertData(const WatchData &data)
 {
-    m_locals->reinsertAllData();
-    m_watchers->reinsertAllData();
-    m_tooltips->reinsertAllData();
-    m_return->reinsertAllData();
-    m_inspect->reinsertAllData();
+    QList<WatchData> list;
+    list.append(data);
+    insertData(list);
 }
 
-// Bulk-insertion
-void WatchHandler::insertBulkData(const QList<WatchData> &list)
+void WatchHandler::insertData(const QList<WatchData> &list)
 {
-#if 1
-    foreach (const WatchItem &data, list)
-        insertData(data);
-    return;
-#endif
-
-    if (list.isEmpty())
-        return;
-    QMap<QByteArray, QList<WatchData> > hash;
+    m_model->insertBulkData(list);
 
-    foreach (const WatchData &data, list) {
-        // we insert everything, including incomplete stuff
-        // to reduce the number of row add operations in the model.
-        if (data.isValid()) {
-            hash[parentName(data.iname)].append(data);
-        } else {
-            qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s",
-                __FILE__, __LINE__, qPrintable(data.toString()));
-        }
-    }
-    foreach (const QByteArray &parentIName, hash.keys()) {
-        WatchModel *model = modelForIName(parentIName);
-        QTC_ASSERT(model, return);
-        model->insertBulkData(hash[parentIName]);
-    }
+    m_contentsValid = true;
+    updateWatchersWindow();
+}
 
-    foreach (const WatchData &data, list) {
-        if (data.isSomethingNeeded())
-            m_engine->updateWatchData(data);
-    }
+void WatchHandler::removeAllData()
+{
+    m_model->reinitialize();
 }
 
 void WatchHandler::removeData(const QByteArray &iname)
 {
-    WatchModel *model = modelForIName(iname);
-    if (!model)
-        return;
-    WatchItem *item = model->findItem(iname, model->m_root);
+    WatchItem *item = m_model->findItem(iname);
+    if (item)
+        m_model->destroyItem(item);
+}
+
+void WatchHandler::removeChildren(const QByteArray &iname)
+{
+    WatchItem *item = m_model->findItem(iname);
     if (item)
-        model->destroyItem(item);
+        m_model->destroyChildren(item);
 }
 
 QByteArray WatchHandler::watcherName(const QByteArray &exp)
@@ -1483,14 +1651,13 @@ void WatchHandler::watchExpression(const QString &exp)
         data.setAllUnneeded();
         data.setValue(QString(QLatin1Char(' ')));
         data.setHasChildren(false);
-        insertData(data);
+        insertIncompleteData(data);
     } else if (m_engine->isSynchronous()) {
         m_engine->updateWatchData(data);
     } else {
-        insertData(data);
+        insertIncompleteData(data);
     }
     updateWatchersWindow();
-    emitAllChanged();
 }
 
 static void swapEndian(char *d, int nchar)
@@ -1509,9 +1676,9 @@ static void swapEndian(char *d, int nchar)
 void WatchHandler::showEditValue(const WatchData &data)
 {
     const QByteArray key  = data.address ? data.hexAddress() : data.iname;
-    QObject *w = m_editHandlers.value(key);
+    QObject *w = m_model->m_editHandlers.value(key);
     if (data.editformat == 0x0) {
-        m_editHandlers.remove(data.iname);
+        m_model->m_editHandlers.remove(data.iname);
         delete w;
     } else if (data.editformat == 1 || data.editformat == 3) {
         // QImage
@@ -1524,7 +1691,7 @@ void WatchHandler::showEditValue(const WatchData &data)
                     QLatin1String(data.hexAddress())) :
                 tr("%1 Object at Unknown Address").arg(QLatin1String(data.type));
             l->setWindowTitle(title);
-            m_editHandlers[key] = l;
+            m_model->m_editHandlers[key] = l;
         }
         int width, height, format;
         QByteArray ba;
@@ -1563,7 +1730,7 @@ void WatchHandler::showEditValue(const WatchData &data)
         if (!t) {
             delete w;
             t = new QTextEdit;
-            m_editHandlers[key] = t;
+            m_model->m_editHandlers[key] = t;
         }
         QByteArray ba = QByteArray::fromHex(data.editvalue);
         QString str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
@@ -1580,7 +1747,7 @@ void WatchHandler::showEditValue(const WatchData &data)
             p = new QProcess;
             p->start(QLatin1String(cmd));
             p->waitForStarted();
-            m_editHandlers[key] = p;
+            m_model->m_editHandlers[key] = p;
         }
         p->write(input + '\n');
     } else {
@@ -1592,13 +1759,10 @@ void WatchHandler::clearWatches()
 {
     if (theWatcherNames.isEmpty())
         return;
-    const QList<WatchItem *> watches = m_watchers->rootItem()->children;
-    for (int i = watches.size() - 1; i >= 0; i--)
-        m_watchers->destroyItem(watches.at(i));
+    m_model->destroyChildren(m_model->m_watchRoot);
     theWatcherNames.clear();
     m_watcherCounter = 0;
     updateWatchersWindow();
-    emitAllChanged();
     saveWatchers();
 }
 
@@ -1607,12 +1771,12 @@ void WatchHandler::removeWatchExpression(const QString &exp0)
     QByteArray exp = exp0.toLatin1();
     MODEL_DEBUG("REMOVE WATCH: " << exp);
     theWatcherNames.remove(exp);
-    foreach (WatchItem *item, m_watchers->rootItem()->children) {
+
+    foreach (WatchItem *item, m_model->m_watchRoot->children) {
         if (item->exp == exp) {
-            m_watchers->destroyItem(item);
+            m_model->destroyItem(item);
             saveWatchers();
             updateWatchersWindow();
-            emitAllChanged();
             break;
         }
     }
@@ -1621,7 +1785,15 @@ void WatchHandler::removeWatchExpression(const QString &exp0)
 void WatchHandler::updateWatchersWindow()
 {
     // Force show/hide of watchers and return view.
-    debuggerCore()->updateWatchersWindow();
+    static int previousShowWatch = -1;
+    static int previousShowReturn = -1;
+    int showWatch = !m_model->m_watchRoot->children.isEmpty();
+    int showReturn = !m_model->m_returnRoot->children.isEmpty();
+    if (showWatch == previousShowWatch && showReturn == previousShowReturn)
+        return;
+    previousShowWatch = showWatch;
+    previousShowReturn = showReturn;
+    debuggerCore()->updateWatchersWindow(showWatch, showReturn);
 }
 
 QStringList WatchHandler::watchedExpressions()
@@ -1684,18 +1856,14 @@ void WatchHandler::loadSessionData()
     theWatcherNames.clear();
     m_watcherCounter = 0;
     QVariant value = debuggerCore()->sessionValue(QLatin1String("Watchers"));
-    foreach (WatchItem *item, m_watchers->rootItem()->children)
-        m_watchers->destroyItem(item);
+    m_model->destroyChildren(m_model->m_watchRoot);
     foreach (const QString &exp, value.toStringList())
         watchExpression(exp);
-    updateWatchersWindow();
-    emitAllChanged();
 }
 
 void WatchHandler::updateWatchers()
 {
-    foreach (WatchItem *item, m_watchers->rootItem()->children)
-        m_watchers->destroyItem(item);
+    m_model->destroyChildren(m_model->m_watchRoot);
     // Copy over all watchers and mark all watchers as incomplete.
     foreach (const QByteArray &exp, theWatcherNames.keys()) {
         WatchData data;
@@ -1703,67 +1871,33 @@ void WatchHandler::updateWatchers()
         data.setAllNeeded();
         data.name = QLatin1String(exp);
         data.exp = exp;
-        insertData(data);
+        insertIncompleteData(data);
     }
 }
 
-WatchModel *WatchHandler::model(WatchType type) const
+QAbstractItemModel *WatchHandler::model() const
 {
-    switch (type) {
-        case ReturnWatch: return m_return;
-        case LocalsWatch: return m_locals;
-        case WatchersWatch: return m_watchers;
-        case TooltipsWatch: return m_tooltips;
-        case InspectWatch: return m_inspect;
-    }
-    QTC_CHECK(false);
-    return 0;
+    return m_model;
 }
 
-WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
+const WatchData *WatchHandler::watchData(const QModelIndex &idx) const
 {
-    if (iname.startsWith("return"))
-        return m_return;
-    if (iname.startsWith("local"))
-        return m_locals;
-    if (iname.startsWith("tooltip"))
-        return m_tooltips;
-    if (iname.startsWith("watch"))
-        return m_watchers;
-    if (iname.startsWith("inspect"))
-        return m_inspect;
-    QTC_ASSERT(false, qDebug() << "INAME: " << iname);
-    return 0;
+    return m_model->watchItem(idx);
 }
 
-const WatchData *WatchHandler::watchData(WatchType type, const QModelIndex &index) const
+const WatchData *WatchHandler::findData(const QByteArray &iname) const
 {
-    if (index.isValid())
-        if (const WatchModel *m = model(type))
-            return m->watchItem(index);
-    return 0;
-}
-
-const WatchData *WatchHandler::findItem(const QByteArray &iname) const
-{
-    const WatchModel *model = modelForIName(iname);
-    QTC_ASSERT(model, return 0);
-    return model->findItem(iname, model->m_root);
+    return m_model->findItem(iname);
 }
 
 QString WatchHandler::displayForAutoTest(const QByteArray &iname) const
 {
-    const WatchModel *model = modelForIName(iname);
-    QTC_ASSERT(model, return QString());
-    return model->displayForAutoTest(iname);
+    return m_model->displayForAutoTest(iname);
 }
 
-QModelIndex WatchHandler::itemIndex(const QByteArray &iname) const
+bool WatchHandler::hasItem(const QByteArray &iname) const
 {
-    if (const WatchModel *model = modelForIName(iname))
-        if (WatchItem *item = model->findItem(iname, model->m_root))
-            return model->watchIndex(item);
-    return QModelIndex();
+    return m_model->findItem(iname);
 }
 
 void WatchHandler::setFormat(const QByteArray &type0, int format)
@@ -1774,17 +1908,13 @@ void WatchHandler::setFormat(const QByteArray &type0, int format)
     else
         theTypeFormats[type] = format;
     saveTypeFormats();
-    m_return->emitDataChanged(1);
-    m_locals->emitDataChanged(1);
-    m_watchers->emitDataChanged(1);
-    m_tooltips->emitDataChanged(1);
-    m_inspect->emitDataChanged(1);
+    m_model->emitDataChanged(1);
 }
 
 int WatchHandler::format(const QByteArray &iname) const
 {
     int result = -1;
-    if (const WatchData *item = findItem(iname)) {
+    if (const WatchData *item = m_model->findItem(iname)) {
         int result = theIndividualFormats.value(item->iname, -1);
         if (result == -1)
             result = theTypeFormats.value(stripForFormat(item->type), -1);
@@ -1795,10 +1925,9 @@ int WatchHandler::format(const QByteArray &iname) const
 QByteArray WatchHandler::expansionRequests() const
 {
     QByteArray ba;
-    //m_locals->formatRequests(&ba, m_locals->m_root);
-    //m_watchers->formatRequests(&ba, m_watchers->m_root);
-    if (!m_expandedINames.isEmpty()) {
-        QSetIterator<QByteArray> jt(m_expandedINames);
+    m_model->formatRequests(&ba, m_model->m_root);
+    if (!m_model->m_expandedINames.isEmpty()) {
+        QSetIterator<QByteArray> jt(m_model->m_expandedINames);
         while (jt.hasNext()) {
             QByteArray iname = jt.next();
             ba.append(iname);
@@ -1845,67 +1974,43 @@ QByteArray WatchHandler::individualFormatRequests() const
 
 void WatchHandler::addTypeFormats(const QByteArray &type, const QStringList &formats)
 {
-    m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
+    m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
 }
 
 QString WatchHandler::editorContents()
 {
     QString contents;
-    showInEditorHelper(&contents, m_locals->m_root, 0);
-    showInEditorHelper(&contents, m_watchers->m_root, 0);
+    m_model->showInEditorHelper(&contents, m_model->m_root, 0);
     return contents;
 }
 
-void WatchHandler::showInEditorHelper(QString *contents, WatchItem *item, int depth)
-{
-    const QChar tab = QLatin1Char('\t');
-    const QChar nl = QLatin1Char('\n');
-    contents->append(QString(depth, tab));
-    contents->append(item->name);
-    contents->append(tab);
-    contents->append(item->value);
-    contents->append(tab);
-    contents->append(item->type);
-    contents->append(nl);
-    foreach (WatchItem *child, item->children)
-       showInEditorHelper(contents, child, depth + 1);
-}
-
 void WatchHandler::removeTooltip()
 {
-    m_tooltips->reinitialize();
-    m_tooltips->emitAllChanged();
+    m_model->destroyChildren(m_model->m_tooltipRoot);
 }
 
 void WatchHandler::rebuildModel()
 {
-    beginCycle();
-
-    const QList<WatchItem *> watches = m_watchers->rootItem()->children;
-    for (int i = watches.size() - 1; i >= 0; i--)
-        m_watchers->destroyItem(watches.at(i));
-
-    foreach (const QString &exp, watchedExpressions()) {
-        WatchData data;
-        data.exp = exp.toLatin1();
-        data.name = exp;
-        data.iname = watcherName(data.exp);
-        data.setAllUnneeded();
-
-        insertData(data);
-    }
+//    m_model->destroyChildren(m_model->m_watchRoot);
 
-    endCycle();
+//    foreach (const QString &exp, watchedExpressions()) {
+//        WatchData data;
+//        data.exp = exp.toLatin1();
+//        data.name = exp;
+//        data.iname = watcherName(data.exp);
+//        data.setAllUnneeded();
+//        insertIncompleteData(data);
+//    }
 }
 
 void WatchHandler::setTypeFormats(const TypeFormats &typeFormats)
 {
-    m_reportedTypeFormats = typeFormats;
+    m_model->m_reportedTypeFormats = typeFormats;
 }
 
 TypeFormats WatchHandler::typeFormats() const
 {
-    return m_reportedTypeFormats;
+    return m_model->m_reportedTypeFormats;
 }
 
 void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
@@ -1914,11 +2019,11 @@ void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
     TypeFormatsDialog dlg(0);
 
     //QHashIterator<QString, QStringList> it(m_reportedTypeFormats);
-    QList<QString> l = m_reportedTypeFormats.keys();
+    QList<QString> l = m_model->m_reportedTypeFormats.keys();
     qSort(l.begin(), l.end());
     foreach (const QString &ba, l) {
         int f = iname.isEmpty() ? -1 : format(iname);
-        dlg.addTypeFormats(ba, m_reportedTypeFormats.value(ba), f);
+        dlg.addTypeFormats(ba, m_model->m_reportedTypeFormats.value(ba), f);
     }
     if (dlg.exec())
         setTypeFormats(dlg.typeFormats());
@@ -1927,6 +2032,7 @@ void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
 void WatchHandler::scheduleResetLocation()
 {
     m_contentsValid = false;
+    //m_contentsValid = true; // FIXME
     m_resetLocationScheduled = true;
 }
 
@@ -1934,26 +2040,19 @@ void WatchHandler::resetLocation()
 {
     if (m_resetLocationScheduled) {
         m_resetLocationScheduled = false;
-        m_return->invalidateAll();
-        m_locals->invalidateAll();
-        m_watchers->invalidateAll();
-        m_tooltips->invalidateAll();
-        m_inspect->invalidateAll();
+        //m_model->invalidateAll();  FIXME
     }
 }
 
 bool WatchHandler::isValidToolTip(const QByteArray &iname) const
 {
-    WatchItem *item = m_tooltips->findItem(iname, m_tooltips->m_root);
+    WatchItem *item = m_model->findItem(iname);
     return item && !item->type.trimmed().isEmpty();
 }
 
-void WatchHandler::setCurrentModelIndex(WatchType modelType,
-                                        const QModelIndex &index)
+void WatchHandler::setCurrentItem(const QByteArray &iname)
 {
-    if (WatchModel *m = model(modelType)) {
-        emit m->setCurrentIndex(index);
-    }
+    m_model->setCurrentItem(iname);
 }
 
 QHash<QByteArray, int> WatchHandler::watcherNames()
@@ -1961,5 +2060,28 @@ QHash<QByteArray, int> WatchHandler::watcherNames()
     return theWatcherNames;
 }
 
+void WatchHandler::setUnprintableBase(int base)
+{
+    theUnprintableBase = base;
+    m_model->emitAllChanged();
+}
+
+int WatchHandler::unprintableBase()
+{
+    return theUnprintableBase;
+}
+
+bool WatchHandler::isExpandedIName(const QByteArray &iname) const
+{
+    return m_model->m_expandedINames.contains(iname);
+}
+
+QSet<QByteArray> WatchHandler::expandedINames() const
+{
+    return m_model->m_expandedINames;
+}
+
 } // namespace Internal
 } // namespace Debugger
+
+#include "watchhandler.moc"
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index c99fe88685c4ff78e290794fe8203f947f8ee043..db44eef08cd05522833127acaea14df74ac7d49c 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -35,28 +35,38 @@
 
 #include "watchdata.h"
 
-#include <QPointer>
 #include <QHash>
 #include <QSet>
 #include <QStringList>
 #include <QAbstractItemModel>
 
 namespace Debugger {
+
 class DebuggerEngine;
 
 namespace Internal {
 
-class WatchItem;
-class WatchHandler;
+class WatchModel;
+
+class UpdateParameters
+{
+public:
+    UpdateParameters() { tryPartial = tooltipOnly = false; }
+
+    bool tryPartial;
+    bool tooltipOnly;
+    QByteArray varList;
+};
+
 typedef QHash<QString, QStringList> TypeFormats;
 
 enum WatchType
 {
-    ReturnWatch,
-    LocalsWatch,
-    WatchersWatch,
-    TooltipsWatch,
-    InspectWatch
+    LocalsType,
+    InspectType,
+    WatchersType,
+    ReturnType,
+    TooltipType
 };
 
 enum IntegerFormat
@@ -67,126 +77,38 @@ enum IntegerFormat
     OctalFormat
 };
 
-class WatchModel : public QAbstractItemModel
-{
-    Q_OBJECT
-
-private:
-    explicit WatchModel(WatchHandler *handler, WatchType type);
-    virtual ~WatchModel();
-
-public:
-    virtual int rowCount(const QModelIndex &idx = QModelIndex()) const;
-    virtual int columnCount(const QModelIndex &idx) const;
-
-signals:
-    void setCurrentIndex(const QModelIndex &index);
-
-private:
-    QVariant data(const QModelIndex &index, int role) const;
-    bool setData(const QModelIndex &index, const QVariant &value, int role);
-    QModelIndex index(int, int, const QModelIndex &idx) const;
-    QModelIndex parent(const QModelIndex &idx) const;
-    bool hasChildren(const QModelIndex &idx) const;
-    Qt::ItemFlags flags(const QModelIndex &idx) const;
-    QVariant headerData(int section, Qt::Orientation orientation,
-        int role = Qt::DisplayRole) const;
-    bool canFetchMore(const QModelIndex &parent) const;
-    void fetchMore(const QModelIndex &parent);
-
-    void invalidateAll(const QModelIndex &parentIndex = QModelIndex());
-
-    friend class WatchHandler;
-
-    WatchItem *watchItem(const QModelIndex &) const;
-    QModelIndex watchIndex(const WatchItem *needle) const;
-    QModelIndex watchIndexHelper(const WatchItem *needle,
-        const WatchItem *parentItem, const QModelIndex &parentIndex) const;
-
-    void insertData(const WatchData &data);
-    void reinsertAllData();
-    void reinsertAllDataHelper(WatchItem *item, QList<WatchData> *data);
-    void insertBulkData(const QList<WatchData> &data);
-    WatchItem *findItem(const QByteArray &iname, WatchItem *root) const;
-    QString displayForAutoTest(const QByteArray &iname) const;
-    void reinitialize();
-    void removeOutdated();
-    void removeOutdatedHelper(WatchItem *item);
-    WatchItem *rootItem() const;
-    void destroyItem(WatchItem *item);
-
-    void emitDataChanged(int column,
-        const QModelIndex &parentIndex = QModelIndex());
-    void beginCycle(bool fullCycle); // 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);
-    void emitAllChanged();
-
-private:
-    QString displayType(const WatchData &typeIn) const;
-    QString formattedValue(const WatchData &data) const;
-    QString removeInitialNamespace(QString str) const;
-    QString removeNamespaces(QString str) const;
-    void formatRequests(QByteArray *out, const WatchItem *item) const;
-    DebuggerEngine *engine() const;
-    QString display(const WatchItem *item, int col) const;
-    int itemFormat(const WatchData &data) const;
-    bool contentIsValid() const;
-    int m_generationCounter;
-
-    WatchHandler *m_handler;
-    WatchType m_type;
-    WatchItem *m_root;
-    QSet<QByteArray> m_fetchTriggered;
-};
-
 class WatchHandler : public QObject
 {
     Q_OBJECT
 
 public:
     explicit WatchHandler(DebuggerEngine *engine);
-    WatchModel *model(WatchType type) const;
-    WatchModel *modelForIName(const QByteArray &iname) const;
+    ~WatchHandler();
+
+    QAbstractItemModel *model() const;
 
     void cleanup();
     void watchExpression(const QString &exp);
     void removeWatchExpression(const QString &exp);
     Q_SLOT void clearWatches();
-    Q_SLOT void emitAllChanged();
 
-    void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle
     void updateWatchers(); // Called after locals are fetched
-    void endCycle(); // Called after all results have been received
-
-    void beginCycle(WatchType type, bool fullCycle = true);
-    void endCycle(WatchType type);
 
     void showEditValue(const WatchData &data);
 
-    void insertData(const WatchData &data);
-    void insertBulkData(const QList<WatchData> &data);
-    void removeData(const QByteArray &iname);
-    Q_SLOT void reinsertAllData();
-
-    const WatchData *watchData(WatchType type, const QModelIndex &) const;
-    const WatchData *findItem(const QByteArray &iname) const;
+    const WatchData *watchData(const QModelIndex &) const;
+    const WatchData *findData(const QByteArray &iname) const;
     QString displayForAutoTest(const QByteArray &iname) const;
-    QModelIndex itemIndex(const QByteArray &iname) const;
+    bool hasItem(const QByteArray &iname) const;
 
     void loadSessionData();
     void saveSessionData();
     void removeTooltip();
     void rebuildModel();
 
-    bool isExpandedIName(const QByteArray &iname) const
-        { return m_expandedINames.contains(iname); }
-    QSet<QByteArray> expandedINames() const
-        { return m_expandedINames; }
+    bool isExpandedIName(const QByteArray &iname) const;
+    QSet<QByteArray> expandedINames() const;
+
     static QStringList watchedExpressions();
     static QHash<QByteArray, int> watcherNames();
 
@@ -199,7 +121,6 @@ public:
     void addTypeFormats(const QByteArray &type, const QStringList &formats);
     void setTypeFormats(const TypeFormats &typeFormats);
     TypeFormats typeFormats() const;
-    QStringList typeFormatList(const WatchData &data) const;
 
     void setUnprintableBase(int base);
     static int unprintableBase();
@@ -213,7 +134,15 @@ public:
     void resetLocation();
     bool isValidToolTip(const QByteArray &iname) const;
 
-    void setCurrentModelIndex(WatchType modelType, const QModelIndex &index);
+    void setCurrentItem(const QByteArray &iname);
+    void updateWatchersWindow();
+
+    void insertData(const WatchData &data); // Convenience.
+    void insertData(const QList<WatchData> &list);
+    void insertIncompleteData(const WatchData &data);
+    void removeData(const QByteArray &iname);
+    void removeChildren(const QByteArray &iname);
+    void removeAllData();
 
 private:
     friend class WatchModel;
@@ -223,25 +152,8 @@ private:
     static void saveTypeFormats();
 
     void setFormat(const QByteArray &type, int format);
-    void updateWatchersWindow();
-    void showInEditorHelper(QString *contents, WatchItem *item, int level);
-
-    bool m_inChange;
 
-    // QWidgets and QProcesses taking care of special displays.
-    typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
-    EditHandlers m_editHandlers;
-
-    TypeFormats m_reportedTypeFormats;
-
-    // Items expanded in the Locals & Watchers view.
-    QSet<QByteArray> m_expandedINames;
-
-    WatchModel *m_return;
-    WatchModel *m_locals;
-    WatchModel *m_watchers;
-    WatchModel *m_tooltips;
-    WatchModel *m_inspect;
+    WatchModel *m_model;
     DebuggerEngine *m_engine;
 
     int m_watcherCounter;
@@ -253,4 +165,6 @@ private:
 } // namespace Internal
 } // namespace Debugger
 
+Q_DECLARE_METATYPE(Debugger::Internal::UpdateParameters)
+
 #endif // DEBUGGER_WATCHHANDLER_H
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index 9f5ae276091e99e74736ce6beb362681c8158e29..0cdac8da9cafce37284bcd700492a86f6f909cc4 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -530,12 +530,12 @@ void WatchTreeView::keyPressEvent(QKeyEvent *ev)
         QString exp = model()->data(idx1).toString();
         watchExpression(exp);
     }
-    QTreeView::keyPressEvent(ev);
+    BaseTreeView::keyPressEvent(ev);
 }
 
 void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
 {
-    //QTreeView::dragEnterEvent(ev);
+    //BaseTreeView::dragEnterEvent(ev);
     if (ev->mimeData()->hasText()) {
         ev->setDropAction(Qt::CopyAction);
         ev->accept();
@@ -544,7 +544,7 @@ void WatchTreeView::dragEnterEvent(QDragEnterEvent *ev)
 
 void WatchTreeView::dragMoveEvent(QDragMoveEvent *ev)
 {
-    //QTreeView::dragMoveEvent(ev);
+    //BaseTreeView::dragMoveEvent(ev);
     if (ev->mimeData()->hasText()) {
         ev->setDropAction(Qt::CopyAction);
         ev->accept();
@@ -559,7 +559,7 @@ void WatchTreeView::dropEvent(QDropEvent *ev)
         ev->setDropAction(Qt::CopyAction);
         ev->accept();
     }
-    //QTreeView::dropEvent(ev);
+    //BaseTreeView::dropEvent(ev);
 }
 
 void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
@@ -570,7 +570,7 @@ void WatchTreeView::mouseDoubleClickEvent(QMouseEvent *ev)
         watchExpression(QString());
         return;
     }
-    QTreeView::mouseDoubleClickEvent(ev);
+    BaseTreeView::mouseDoubleClickEvent(ev);
 }
 
 // Text for add watch action with truncated expression.
@@ -971,7 +971,7 @@ bool WatchTreeView::event(QEvent *ev)
         releaseMouse();
         currentEngine()->watchPoint(mapToGlobal(mev->pos()));
     }
-    return QTreeView::event(ev);
+    return BaseTreeView::event(ev);
 }
 
 void WatchTreeView::editItem(const QModelIndex &idx)
@@ -982,6 +982,7 @@ void WatchTreeView::editItem(const QModelIndex &idx)
 void WatchTreeView::setModel(QAbstractItemModel *model)
 {
     BaseTreeView::setModel(model);
+    setRootIndex(model->index(m_type, 0, QModelIndex()));
     setRootIsDecorated(true);
     if (header()) {
         header()->setDefaultAlignment(Qt::AlignLeft);
@@ -990,15 +991,25 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
     }
 
     connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
-
-    QTC_ASSERT(qobject_cast<WatchModel*>(model), return);
-    connect(model, SIGNAL(setCurrentIndex(QModelIndex)),
+    connect(model, SIGNAL(currentIndexRequested(QModelIndex)),
             SLOT(setCurrentIndex(QModelIndex)));
+    connect(model, SIGNAL(itemIsExpanded(QModelIndex)),
+            SLOT(handleItemIsExpanded(QModelIndex)));
+}
+
+void WatchTreeView::handleItemIsExpanded(const QModelIndex &idx)
+{
+    bool on = idx.data(LocalsExpandedRole).toBool();
+    QTC_ASSERT(on, return);
+    if (!isExpanded(idx))
+        expand(idx);
 }
 
 void WatchTreeView::resetHelper()
 {
-    resetHelper(model()->index(0, 0));
+    QModelIndex idx = model()->index(m_type, 0);
+    resetHelper(idx);
+    expand(idx);
 }
 
 void WatchTreeView::resetHelper(const QModelIndex &idx)
@@ -1019,6 +1030,13 @@ void WatchTreeView::resetHelper(const QModelIndex &idx)
     }
 }
 
+void WatchTreeView::reset()
+{
+    BaseTreeView::reset();
+    setRootIndex(model()->index(m_type, 0));
+    resetHelper();
+}
+
 void WatchTreeView::watchExpression(const QString &exp)
 {
     currentEngine()->watchHandler()->watchExpression(exp);
@@ -1063,7 +1081,5 @@ void WatchTreeView::setWatchpointAtExpression(const QString &exp)
     breakHandler()->appendBreakpoint(data);
 }
 
-
 } // namespace Internal
 } // namespace Debugger
-
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index 9a28f6380eb67273c898d63ea26bebe46dc95324..17760dda73bdf94ba4cc7192bde08f0ab800cb3b 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -49,15 +49,17 @@ class WatchTreeView : public BaseTreeView
     Q_OBJECT
 
 public:
-    enum Type { ReturnType, LocalsType, TooltipType, WatchersType, InspectType };
+    enum Type { LocalsType, InspectType, WatchersType, ReturnType, TooltipType };
 
     explicit WatchTreeView(Type type, QWidget *parent = 0);
     Type type() const { return m_type; }
     void setModel(QAbstractItemModel *model);
+    void reset();
 
 public slots:
     void watchExpression(const QString &exp);
     void removeWatchExpression(const QString &exp);
+    void handleItemIsExpanded(const QModelIndex &idx);
 
 private:
     Q_SLOT void resetHelper();