diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp
index 53f2f2c147aa0a4c4b9d8b0261e585017b942cd5..399d5bda3c29d177c50f21fd6b2847435b6f6585 100644
--- a/src/plugins/debugger/breakwindow.cpp
+++ b/src/plugins/debugger/breakwindow.cpp
@@ -147,7 +147,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
 
     QAction *act4 = new QAction(tr("Synchronize breakpoints"), &menu);
 
-    QModelIndex idx0 = si.front();
+    QModelIndex idx0 = (si.size() ? si.front() : QModelIndex());
     QModelIndex idx2 = idx0.sibling(idx0.row(), 2);
     bool enabled = si.isEmpty() || model()->data(idx0, Qt::UserRole).toBool();
     QString str5 = enabled ? tr("Disable breakpoint") : tr("Enable breakpoint");
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h
index 7868f2c9fc73ce92e3ebac0ea965f58720285779..09f8850d4f896ed483ad963b4f78540fd5feecca 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine.h
@@ -64,7 +64,7 @@ public:
     virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters);
     virtual void exitDebugger();
     virtual void detachDebugger();
-    virtual void updateWatchModel();
+    virtual void updateWatchData(const WatchData &data);
 
     virtual void stepExec();
     virtual void stepOutExec();
diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp
index e958841be7bca4a649f03ff225748ca701508ded..285d9b5bfc208cceefa8d0104b43cffdccba1549 100644
--- a/src/plugins/debugger/debuggeractions.cpp
+++ b/src/plugins/debugger/debuggeractions.cpp
@@ -151,14 +151,6 @@ DebuggerSettings *DebuggerSettings::instance()
     item = new SavedAction(instance);
     instance->insertItem(AssignType, item);
 
-    item = new SavedAction(instance);
-    item->setText(tr("Expand item"));
-    instance->insertItem(ExpandItem, item);
-
-    item = new SavedAction(instance);
-    item->setText(tr("Collapse item"));
-    instance->insertItem(CollapseItem, item);
-
     //
     // DebuggingHelper
     //
diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h
index de42fe1dfd6bdfa50d7d55c7c7d16e7e05e3e115..79225e61f89d8db99b4061e4f1812ad9f31ebe88 100644
--- a/src/plugins/debugger/debuggeractions.h
+++ b/src/plugins/debugger/debuggeractions.h
@@ -97,8 +97,6 @@ enum DebuggerActionCode
     UseToolTips,
     AssignValue,
     AssignType,
-    ExpandItem,
-    CollapseItem,
 
     RecheckDebuggingHelpers,
     UseDebuggingHelpers,
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 2c48205ff6a6a6667c2cab65b5df5030895b2746..b3dc85212f240915a9915b1ed975ccc8b8bba931 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -317,11 +317,11 @@ void DebuggerManager::init()
     // Locals
     m_watchHandler = new WatchHandler;
     QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
-    localsView->setModel(m_watchHandler->model());
+    localsView->setModel(m_watchHandler->model(LocalsWatch));
 
     // Watchers
     QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
-    watchersView->setModel(m_watchHandler->model());
+    watchersView->setModel(m_watchHandler->model(WatchersWatch));
     connect(m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
         this, SIGNAL(sessionValueRequested(QString,QVariant*)));
     connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
@@ -331,10 +331,10 @@ void DebuggerManager::init()
 
     // Tooltip
     QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
-    tooltipView->setModel(m_watchHandler->model());
+    tooltipView->setModel(m_watchHandler->model(TooltipsWatch));
 
-    connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
-        this, SLOT(updateWatchModel()));
+    connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)),
+        this, SLOT(updateWatchData(WatchData)));
 
     m_continueAction = new QAction(this);
     m_continueAction->setText(tr("Continue"));
@@ -792,10 +792,10 @@ void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::I
         m_engine->setToolTipExpression(mousePos, editor, cursorPos);
 }
 
-void DebuggerManager::updateWatchModel()
+void DebuggerManager::updateWatchData(const WatchData &data)
 {
     if (m_engine)
-        m_engine->updateWatchModel();
+        m_engine->updateWatchData(data);
 }
 
 QVariant DebuggerManager::sessionValue(const QString &name)
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 2beb059921fb249e751cd9692e066745fd3d0887..87f506020097e7e827f43d0f207fe87fb5b53766 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -293,7 +293,7 @@ public slots:
     void detachDebugger();
 
     void addToWatchWindow();
-    void updateWatchModel();
+    void updateWatchData(const WatchData &data);
 
     void sessionLoaded();
     void sessionUnloaded();
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 85c0c7671ba9ce07c53f0512c100592b9cf9600f..0974b09c9b7d3b9471814345963044e34b49836c 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -715,7 +715,7 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
 
 #if 0
     qDebug() << "# handleOutput,"
-        << "cmd type:" << cmd.type
+        << "cmd name:" << cmd.callbackName
         << " cmd synchronized:" << cmd.synchronized
         << "\n record: " << record.toString();
 #endif
@@ -727,14 +727,14 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record)
 
     if (cmd.flags & RebuildModel) {
         --m_pendingRequests;
-        PENDING_DEBUG("   TYPE " << cmd.type << " DECREMENTS PENDING TO: "
+        PENDING_DEBUG("   TYPE " << cmd.callbackName << " DECREMENTS PENDING TO: "
             << m_pendingRequests << cmd.command);
         if (m_pendingRequests <= 0) {
-            PENDING_DEBUG(" ....  AND TRIGGERS MODEL UPDATE");
-            updateWatchModel2();
+            PENDING_DEBUG("\n\n ....  AND TRIGGERS MODEL UPDATE\n");
+            rebuildModel();
         }
     } else {
-        PENDING_DEBUG("   UNKNOWN TYPE " << cmd.type << " LEAVES PENDING AT: "
+        PENDING_DEBUG("   UNKNOWN TYPE " << cmd.callbackName << " LEAVES PENDING AT: "
             << m_pendingRequests << cmd.command);
     }
 
@@ -1968,7 +1968,6 @@ void GdbEngine::handleBreakList(const GdbMi &table)
     handler->updateMarkers();
 }
 
-
 void GdbEngine::handleBreakIgnore(const GdbResultRecord &record, const QVariant &cookie)
 {
     int index = cookie.toInt();
@@ -2724,7 +2723,7 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEd
     m_toolTip.name = exp;
     m_toolTip.iname = tooltipIName;
     insertData(m_toolTip);
-    updateWatchModel2();
+    //updateWatchModel2();
 }
 
 
@@ -3062,55 +3061,40 @@ void GdbEngine::updateSubItem(const WatchData &data0)
     QTC_ASSERT(false, return);
 }
 
-void GdbEngine::updateWatchModel()
+void GdbEngine::updateWatchData(const WatchData &data)
 {
-    m_pendingRequests = 0;
-    PENDING_DEBUG("EXTERNAL TRIGGERING UPDATE WATCH MODEL");
-    updateWatchModel2();
+    //m_pendingRequests = 0;
+    PENDING_DEBUG("UPDATE WATCH DATA");
+    #if DEBUG_PENDING
+    //qDebug() << "##############################################";
+    //qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:";
+    //qDebug() << data.toString();
+    #endif
+
+    // Bump requests to avoid model rebuilding during the nested
+    // updateWatchModel runs.
+    ++m_pendingRequests;
+    updateSubItem(data);
+    //PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
+    --m_pendingRequests;
+    if (m_pendingRequests <= 0)
+        rebuildModel();
 }
 
-void GdbEngine::updateWatchModel2()
+void GdbEngine::rebuildModel()
 {
-    PENDING_DEBUG("UPDATE WATCH MODEL");
-    QList<WatchData> incomplete = qq->watchHandler()->takeCurrentIncompletes();
-    //QTC_ASSERT(incomplete.isEmpty(), /**/);
-    if (!incomplete.isEmpty()) {
-        #if DEBUG_PENDING
-        qDebug() << "##############################################";
-        qDebug() << "UPDATE MODEL, FOUND INCOMPLETES:";
-        foreach (const WatchData &data, incomplete)
-            qDebug() << data.toString();
-        #endif
-
-        // Bump requests to avoid model rebuilding during the nested
-        // updateWatchModel runs.
-        ++m_pendingRequests;
-        foreach (const WatchData &data, incomplete)
-            updateSubItem(data);
-        PENDING_DEBUG("INTERNAL TRIGGERING UPDATE WATCH MODEL");
-        updateWatchModel2();
-        --m_pendingRequests;
-
-        return;
-    }
-
-    if (m_pendingRequests > 0) {
-        PENDING_DEBUG("UPDATE MODEL, PENDING: " << m_pendingRequests);
-        return;
-    }
-
     PENDING_DEBUG("REBUILDING MODEL");
     emit gdbInputAvailable(QString(),
         _c('[') + currentTime() + _("]    <Rebuild Watchmodel>"));
     q->showStatusMessage(tr("Finished retrieving data."), 400);
-    qq->watchHandler()->rebuildModel();
+    qq->watchHandler()->endCycle();
 
     if (!m_toolTipExpression.isEmpty()) {
-        WatchData *data = qq->watchHandler()->findData(tooltipIName);
-        if (data) {
+        WatchData *item = qq->watchHandler()->findItem(tooltipIName);
+        if (item) {
             //m_toolTipCache[data->exp] = *data;
             QToolTip::showText(m_toolTipPos,
-                    _c('(') + data->type + _(") ") + data->exp + _(" = ") + data->value);
+               _c('(') + item->type + _(") ") + item->exp + _(" = ") + item->value);
         } else {
             QToolTip::showText(m_toolTipPos,
                 tr("Cannot evaluate expression: %1").arg(m_toolTipExpression));
@@ -3498,7 +3482,7 @@ void GdbEngine::updateLocals()
     PENDING_DEBUG("\nRESET PENDING");
     m_toolTipCache.clear();
     m_toolTipExpression.clear();
-    qq->watchHandler()->reinitializeWatchers();
+    qq->watchHandler()->beginCycle();
 
     QString level = QString::number(currentFrame());
     // '2' is 'list with type and value'
@@ -3552,6 +3536,7 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record, const QVari
     locals += m_currentFunctionArgs;
 
     setLocals(locals);
+    qq->watchHandler()->updateWatchers();
 }
 
 void GdbEngine::setLocals(const QList<GdbMi> &locals)
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 212ec2dc2d9099bf115a473d81da81facd2ece16..77a4f5935779fd7e3abc92f4bc0a300a0cd4b413 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -320,8 +320,8 @@ private:
     // FIXME: BaseClass. called to improve situation for a watch item
     void updateSubItem(const WatchData &data);
 
-    void updateWatchModel();
-    Q_SLOT void updateWatchModel2();
+    void updateWatchData(const WatchData &data);
+    void rebuildModel();
 
     void insertData(const WatchData &data);
     void sendWatchParameters(const QByteArray &params0);
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index 015dde00509ecd6dbd10cb09e89dc91b769ff71d..8a7187b77f281181092fb48d11c535e41f791bbf 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -40,13 +40,14 @@ class QString;
 QT_END_NAMESPACE
 
 namespace TextEditor {
-    class ITextEditor;
+class ITextEditor;
 }
 
 namespace Debugger {
 namespace Internal {
 
 class Symbol;
+class WatchData;
 struct DebuggerStartParameters;
 
 class IDebuggerEngine : public QObject
@@ -59,7 +60,7 @@ public:
     virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
     virtual void exitDebugger() = 0;
     virtual void detachDebugger() {}
-    virtual void updateWatchModel() = 0;
+    virtual void updateWatchData(const WatchData &data) = 0;
 
     virtual void stepExec() = 0;
     virtual void stepOutExec() = 0;
diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp
index 8517cd7c3422455c9975655e2830493fc72aac51..c8e35886fcd14b11f7a2755d85640c0891a1b7ac 100644
--- a/src/plugins/debugger/script/scriptengine.cpp
+++ b/src/plugins/debugger/script/scriptengine.cpp
@@ -572,7 +572,7 @@ void ScriptEngine::maybeBreakNow(bool byFunction)
 void ScriptEngine::updateLocals()
 {
     QScriptContext *context = m_scriptEngine->currentContext();
-    qq->watchHandler()->reinitializeWatchers();
+    qq->watchHandler()->beginCycle();
     //SDEBUG("UPDATE LOCALS");
 
     //
@@ -605,7 +605,6 @@ void ScriptEngine::updateLocals()
     data.name = "local";
     data.scriptValue = context->activationObject();
     qq->watchHandler()->insertData(data);
-    updateWatchModel();
 
     // FIXME: Use an extra thread. This here is evil
     m_stopped = true;
@@ -616,16 +615,10 @@ void ScriptEngine::updateLocals()
     //SDEBUG("RUNNING AGAIN");
 }
 
-void ScriptEngine::updateWatchModel()
+void ScriptEngine::updateWatchData(const WatchData &data)
 {
-    while (true) {
-        QList<WatchData> list = qq->watchHandler()->takeCurrentIncompletes();
-        if (list.isEmpty())
-            break;
-        foreach (const WatchData &data, list)
-            updateSubItem(data);
-    }
-    qq->watchHandler()->rebuildModel();
+    updateSubItem(data);
+    //qq->watchHandler()->rebuildModel();
     q->showStatusMessage(tr("Stopped."), 5000);
 }
 
diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h
index d6fac03a37ca3f63f0767b8c1a1dd74cce8e7ad2..ae4a434efc007c71a1d6f0107917de3a6c7bf2f4 100644
--- a/src/plugins/debugger/script/scriptengine.h
+++ b/src/plugins/debugger/script/scriptengine.h
@@ -107,9 +107,9 @@ private:
 
     bool supportsThreads() const { return true; }
     void maybeBreakNow(bool byFunction);
-    void updateWatchModel();
+    void updateWatchData(const WatchData &data);
     void updateLocals();
-    void updateSubItem(const WatchData &data0);
+    void updateSubItem(const WatchData &data);
 
 private:
     friend class ScriptAgent;
diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp
index 5efc64ade1065d6cc20eb652284eca46ce4f9ff6..94585085d93195f151c91197997ac1cf7185d8ff 100644
--- a/src/plugins/debugger/tcf/tcfengine.cpp
+++ b/src/plugins/debugger/tcf/tcfengine.cpp
@@ -564,9 +564,9 @@ void TcfEngine::updateLocals()
 {
 }
 
-void TcfEngine::updateWatchModel()
+void TcfEngine::updateWatchData(const WatchData &)
 {
-    qq->watchHandler()->rebuildModel();
+    //qq->watchHandler()->rebuildModel();
     q->showStatusMessage(tr("Stopped."), 5000);
 }
 
diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h
index 0dffedae11c66adb9528de380e1b659de1e6876c..b76ce123cf3b328ec73df458509585a5a28b3cd5 100644
--- a/src/plugins/debugger/tcf/tcfengine.h
+++ b/src/plugins/debugger/tcf/tcfengine.h
@@ -112,9 +112,9 @@ private:
 
     bool supportsThreads() const { return true; }
     void maybeBreakNow(bool byFunction);
-    void updateWatchModel();
+    void updateWatchData(const WatchData &data);
     void updateLocals();
-    void updateSubItem(const WatchData &data0);
+    void updateSubItem(const WatchData &data);
 
     Q_SLOT void socketConnected();
     Q_SLOT void socketDisconnected();
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 104aecea44549abafbbf45c60b7d6116273b30ac..b6b0d68f3c1215fa95091f417d36fc6c2347dfd8 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -40,6 +40,7 @@
 #include <QtCore/QDebug>
 #include <QtCore/QEvent>
 #include <QtCore/QTextStream>
+#include <QtCore/QTimer>
 
 #include <QtGui/QAction>
 #include <QtGui/QApplication>
@@ -51,9 +52,9 @@
 
 
 // creates debug output regarding pending watch data results
-#define DEBUG_PENDING 1
-// creates debug output for accesses to the itemmodel
-//#define DEBUG_MODEL 1
+//#define DEBUG_PENDING 1
+//// creates debug output for accesses to the itemmodel
+#define DEBUG_MODEL 1
 
 #if DEBUG_MODEL
 #   define MODEL_DEBUG(s) qDebug() << s
@@ -62,12 +63,37 @@
 #endif
 #define MODEL_DEBUGX(s) qDebug() << s
 
-using namespace Debugger::Internal;
+namespace Debugger {
+namespace Internal {
 
 static const QString strNotInScope =
         QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>");
 
 static int watcherCounter = 0;
+static int generationCounter = 0;
+
+////////////////////////////////////////////////////////////////////
+//
+// WatchItem
+//
+////////////////////////////////////////////////////////////////////
+
+class WatchItem : public WatchData
+{
+public:
+    WatchItem() { parent = 0; fetched = 0; }
+
+    WatchItem(const WatchData &data) : WatchData(data)
+        { parent = 0; fetched = 0; }
+
+    void setData(const WatchData &data)
+        { static_cast<WatchData &>(*this) = data; }
+
+    WatchItem *parent;
+    bool fetched;      // children fetch has been triggered
+    QList<WatchItem *> children;  // fetched children
+};
+
 
 ////////////////////////////////////////////////////////////////////
 //
@@ -75,16 +101,14 @@ static int watcherCounter = 0;
 //
 ////////////////////////////////////////////////////////////////////
 
-WatchData::WatchData() :
-    childCount(-1),
-    valuedisabled(false),
-    source(0),
-    state(InitialState),
-    parentIndex(-1),
-    row(-1),
-    level(-1),
-    changed(false)
+WatchData::WatchData()
 {
+    childCount = -1;
+    valuedisabled = false;
+    source = 0;
+    state = InitialState;
+    changed = false;
+    generation = -1; 
 }
 
 void WatchData::setError(const QString &msg)
@@ -183,24 +207,8 @@ QString WatchData::toString() const
     const char *doubleQuoteComma = "\",";
     QString res;
     QTextStream str(&res);
-    str  <<"{state=\"0x" << QString::number(state, 16) << doubleQuoteComma;
-    if (level != -1)
-         str << "level=\"" << level << doubleQuoteComma;
-    if (parentIndex != -1)
-         str << "parent=\"" << parentIndex << doubleQuoteComma;
-    if (row != -1)
-         str << "row=\"" << row << doubleQuoteComma;
     if (childCount)
          str << "childCount=\"" << childCount << doubleQuoteComma;
-    if (const int childCount = childIndex.size()) {
-        str << "child=\"";
-        for (int i = 0; i < childCount; i++) {
-            if (i)
-                str << ',';
-            str << childIndex.at(i);
-        }
-        str << doubleQuoteComma;
-    }
 
     if (!iname.isEmpty())
         str << "iname=\"" << iname << doubleQuoteComma;
@@ -267,6 +275,100 @@ QString WatchData::toToolTip() const
     return res;
 }
 
+
+///////////////////////////////////////////////////////////////////////
+//
+// WatchModel
+//
+///////////////////////////////////////////////////////////////////////
+
+WatchModel::WatchModel(WatchHandler *handler, WatchType type)
+    : QAbstractItemModel(handler), m_handler(handler), m_type(type)
+{
+    m_root = new WatchItem;
+    m_root->childCount = 1;
+    m_root->state = 0;
+    m_root->name = WatchHandler::tr("Root");
+
+    WatchItem *item = new WatchItem;
+
+    switch (m_type) {
+        case LocalsWatch:
+            item->iname = QLatin1String("local");
+            item->name = WatchHandler::tr("Locals");
+            break;
+        case WatchersWatch:
+            item->iname = QLatin1String("watch");
+            item->name = WatchHandler::tr("Watchers");
+            break;
+        case TooltipsWatch:
+            item->iname = QLatin1String("tooltip");
+            item->name = WatchHandler::tr("Tooltip");
+            break;
+    }
+    item->childCount = 1;
+    item->state = 0;
+    item->parent = m_root;
+    item->fetched = true;
+
+    m_root->children.append(item);
+}
+
+WatchItem *WatchModel::dummyRoot() const
+{
+    QTC_ASSERT(!m_root->children.isEmpty(), return 0);
+    return m_root->children.front();
+}
+
+void WatchModel::reinitialize()
+{
+    WatchItem *item = dummyRoot();
+    QTC_ASSERT(item, return);
+    QModelIndex index = watchIndex(item);
+    int n = item->children.size();
+    if (n == 0)
+        return;
+    //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << item->iname);
+    beginRemoveRows(index, 0, n - 1);
+    qDeleteAll(item->children);
+    item->children.clear();
+    endRemoveRows();
+}
+
+void WatchModel::removeOutdated()
+{
+    WatchItem *item = dummyRoot();
+    QTC_ASSERT(item, return);
+    foreach (WatchItem *child, item->children)
+        removeOutdatedHelper(child);
+#if DEBUG_MODEL
+#if USE_MODEL_TEST
+    //(void) new ModelTest(this, this);
+#endif
+#endif
+}
+
+void WatchModel::removeOutdatedHelper(WatchItem *item)
+{
+    if (item->generation < generationCounter)
+        removeItem(item);
+    else
+        foreach (WatchItem *child, item->children)
+            removeOutdatedHelper(child);
+}
+
+void WatchModel::removeItem(WatchItem *item)
+{
+    WatchItem *parent = item->parent;
+    QModelIndex index = watchIndex(parent);
+    int n = parent->children.indexOf(item);
+    //MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n);
+    beginRemoveRows(index, n, n);
+    parent->children.removeAt(n);
+    endRemoveRows();
+}
+
+/*
 static bool iNameSorter(const WatchData &d1, const WatchData &d2)
 {
     if (d1.level != d2.level)
@@ -284,6 +386,7 @@ static bool iNameSorter(const WatchData &d1, const WatchData &d2)
     }
     return false; 
 }
+*/
 
 static QString parentName(const QString &iname)
 {
@@ -294,103 +397,6 @@ static QString parentName(const QString &iname)
 }
 
 
-static void insertDataHelper(QList<WatchData> &list, const WatchData &data)
-{
-    // FIXME: Quadratic algorithm
-    for (int i = list.size(); --i >= 0; ) {
-        if (list.at(i).iname == data.iname) {
-            list[i] = data;
-            return;
-        }
-    }
-    list.append(data);
-}
-
-static WatchData take(const QString &iname, QList<WatchData> *list)
-{
-    for (int i = list->size(); --i >= 0;) {
-        if (list->at(i).iname == iname) {
-            WatchData res = list->at(i);
-            (*list)[i] = list->back();
-            (void) list->takeLast();
-            return res;
-            //return list->takeAt(i);
-        }
-    }
-    return WatchData();
-}
-
-static QList<WatchData> initialSet()
-{
-    QList<WatchData> result;
-
-    WatchData root;
-    root.state = 0;
-    root.level = 0;
-    root.row = 0;
-    root.name = WatchHandler::tr("Root");
-    root.parentIndex = -1;
-    root.childIndex.append(1);
-    root.childIndex.append(2);
-    root.childIndex.append(3);
-    result.append(root);
-
-    WatchData local;
-    local.iname = QLatin1String("local");
-    local.name = WatchHandler::tr("Locals");
-    local.state = 0;
-    local.level = 1;
-    local.row = 0;
-    local.parentIndex = 0;
-    result.append(local);
-
-    WatchData tooltip;
-    tooltip.iname = QLatin1String("tooltip");
-    tooltip.name = WatchHandler::tr("Tooltip");
-    tooltip.state = 0;
-    tooltip.level = 1;
-    tooltip.row = 1;
-    tooltip.parentIndex = 0;
-    result.append(tooltip);
-
-    WatchData watch;
-    watch.iname = QLatin1String("watch");
-    watch.name = WatchHandler::tr("Watchers");
-    watch.state = 0;
-    watch.level = 1;
-    watch.row = 2;
-    watch.parentIndex = 0;
-    result.append(watch);
-
-    return result;
-}
-
-///////////////////////////////////////////////////////////////////////
-//
-// WatchHandler
-//
-///////////////////////////////////////////////////////////////////////
-
-WatchHandler::WatchHandler()
-{
-    m_expandPointers = true;
-    m_inFetchMore = false;
-    m_inChange = false;
-
-    m_completeSet = initialSet();
-    m_incompleteSet.clear();
-    m_displaySet = m_completeSet;
-
-    connect(theDebuggerAction(WatchExpression),
-        SIGNAL(triggered()), this, SLOT(watchExpression()));
-    connect(theDebuggerAction(RemoveWatchExpression),
-        SIGNAL(triggered()), this, SLOT(removeWatchExpression()));
-    connect(theDebuggerAction(ExpandItem),
-        SIGNAL(triggered()), this, SLOT(expandChildren()));
-    connect(theDebuggerAction(CollapseItem),
-        SIGNAL(triggered()), this, SLOT(collapseChildren()));
-}
-
 static QString chopConst(QString type)
 {
    while (1) {
@@ -493,14 +499,102 @@ static QString niceType(QString type)
     return type;
 }
 
-QVariant WatchHandler::data(const QModelIndex &idx, int role) const
+bool WatchModel::canFetchMore(const QModelIndex &index) const
 {
-    int node = idx.internalId();
-    if (node < 0)
-        return QVariant();
-    QTC_ASSERT(node < m_displaySet.size(), return QVariant());
+    return index.isValid() && !watchItem(index)->fetched;
+}
+
+void WatchModel::fetchMore(const QModelIndex &index)
+{
+    QTC_ASSERT(index.isValid(), return);
+    QTC_ASSERT(!watchItem(index)->fetched, return);
+    if (WatchItem *item = watchItem(index)) {
+        WatchData data = *item;
+        data.setChildrenNeeded();
+        emit m_handler->watchDataUpdateNeeded(data);
+    }
+}
+
+QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) const
+{
+    if (!hasIndex(row, column, parent))
+        return QModelIndex();
+
+    const WatchItem *item = watchItem(parent);
+    QTC_ASSERT(item, return QModelIndex());
+    return createIndex(row, column, (void*)(item->children.at(row)));
+}
+
+QModelIndex WatchModel::parent(const QModelIndex &idx) const
+{
+    if (!idx.isValid())
+        return QModelIndex();
+
+    const WatchItem *item = watchItem(idx);
+    if (!item->parent || item->parent == m_root)
+        return QModelIndex();
+
+    const WatchItem *grandparent = item->parent->parent;
+    if (!grandparent)
+        return QModelIndex();
+
+    for (int i = 0; i < grandparent->children.size(); ++i)
+        if (grandparent->children.at(i) == item->parent)
+            return createIndex(i, 0, (void*) item->parent);
 
-    const WatchData &data = m_displaySet.at(node);
+    return QModelIndex();
+}
+
+int WatchModel::rowCount(const QModelIndex &idx) const
+{
+    if (!idx.isValid())
+        return 1;
+    if (idx.column() > 0)
+        return 0;
+    return watchItem(idx)->children.size();
+}
+
+int WatchModel::columnCount(const QModelIndex &idx) const
+{
+    Q_UNUSED(idx);
+    return 3;
+}
+
+bool WatchModel::hasChildren(const QModelIndex &parent) const
+{
+    WatchItem *item = watchItem(parent);
+    return !item || item->childCount > 0;
+}
+
+WatchItem *WatchModel::watchItem(const QModelIndex &idx) const
+{
+    return idx.isValid() 
+        ? static_cast<WatchItem*>(idx.internalPointer()) : m_root;
+}
+
+QModelIndex WatchModel::watchIndex(const WatchItem *item) const
+{
+    return watchIndexHelper(item, m_root, QModelIndex());
+}
+
+QModelIndex WatchModel::watchIndexHelper(const WatchItem *needle, 
+    const WatchItem *parentItem, const QModelIndex &parentIndex) const
+{
+    if (needle == parentItem)
+        return parentIndex;
+    for (int i = parentItem->children.size(); --i >= 0; ) {
+        const WatchItem *childItem = parentItem->children.at(i);
+        QModelIndex childIndex = index(i, 0, parentIndex);
+        QModelIndex idx = watchIndexHelper(needle, childItem, childIndex);
+        if (idx.isValid())
+            return idx;
+    }
+    return QModelIndex();
+}
+
+QVariant WatchModel::data(const QModelIndex &idx, int role) const
+{
+    const WatchItem &data = *watchItem(idx);
 
     switch (role) {
         case Qt::DisplayRole: {
@@ -535,11 +629,8 @@ QVariant WatchHandler::data(const QModelIndex &idx, int role) const
             return data.iname;
 
         case ExpandedRole:
-            //qDebug() << " FETCHING: " << data.iname
-            //    << m_expandedINames.contains(data.iname)
-            //    << m_expandedINames;
-            // Level 0 and 1 are always expanded
-            return node < 4 || m_expandedINames.contains(data.iname);
+            return m_handler->m_expandedINames.contains(data.iname);
+            //FIXME return node < 4 || m_expandedINames.contains(data.iname);
     
         default:
             break; 
@@ -547,25 +638,26 @@ QVariant WatchHandler::data(const QModelIndex &idx, int role) const
     return QVariant();
 }
 
-bool WatchHandler::setData(const QModelIndex &index, const QVariant &value, int role)
+bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
 {
-    Q_UNUSED(role);
-    Q_UNUSED(value);
+    if (role == ExpandedRole) {
+        QString iname = data(index, INameRole).toString();
+        if (value.toBool())
+            m_handler->m_expandedINames.insert(iname);
+        else
+            m_handler->m_expandedINames.remove(iname);
+    }
     emit dataChanged(index, index);
     return true;
 }
 
-Qt::ItemFlags WatchHandler::flags(const QModelIndex &idx) const
+Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
 {
     using namespace Qt;
 
     if (!idx.isValid())
         return ItemFlags();
 
-    int node = idx.internalId();
-    if (node < 0)
-        return ItemFlags();
-
     // enabled, editable, selectable, checkable, and can be used both as the
     // source of a drag and drop operation and as a drop target.
 
@@ -579,7 +671,7 @@ Qt::ItemFlags WatchHandler::flags(const QModelIndex &idx) const
 
     static const ItemFlags editable = notEditable | ItemIsEditable;
 
-    const WatchData &data = m_displaySet.at(node);
+    const WatchData &data = *watchItem(idx);
 
     if (data.isWatcher() && idx.column() == 0)
         return editable; // watcher names are editable
@@ -590,8 +682,7 @@ Qt::ItemFlags WatchHandler::flags(const QModelIndex &idx) const
     return  notEditable;
 }
 
-QVariant WatchHandler::headerData(int section, Qt::Orientation orientation,
-    int role) const
+QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const
 {
     if (orientation == Qt::Vertical)
         return QVariant();
@@ -605,54 +696,82 @@ QVariant WatchHandler::headerData(int section, Qt::Orientation orientation,
     return QVariant(); 
 }
 
-QString WatchHandler::toString() const
+void WatchModel::insertData(const WatchData &data)
 {
-    QString res;
-    QTextStream str(&res);
-    str << "\nIncomplete:\n";
-    for (int i = 0, n = m_incompleteSet.size(); i != n; ++i)
-        str << i << ' ' << m_incompleteSet.at(i).toString() << '\n';
-    str << "\nComplete:\n";
-    for (int i = 0, n = m_completeSet.size(); i != n; ++i)
-        str << i << ' ' << m_completeSet.at(i).toString() << '\n';
-    str << "\nDisplay:\n";
-    for (int i = 0, n = m_displaySet.size(); i != n; ++i)
-        str << i << ' ' << m_displaySet.at(i).toString() << '\n';
-
-#if 0
-    str << "\nOld:\n";
-    for (int i = 0, n = m_oldSet.size(); i != n; ++i)
-        str << m_oldSet.at(i).toString() <<  '\n';
-#endif
-    return res;
+    QTC_ASSERT(!data.iname.isEmpty(), return);
+    WatchItem *parent = findItem(parentName(data.iname), m_root);
+    if (!parent) {
+        WatchData parent;
+        parent.iname = parentName(data.iname);
+        insertData(parent);
+        //MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
+        return;
+    }
+    QModelIndex index = watchIndex(parent);
+    if (WatchItem *oldItem = findItem(data.iname, parent)) {
+        // overwrite old entry
+        //MODEL_DEBUG("OVERWRITE : " << data.iname << data.value);
+        bool changed = !data.value.isEmpty()
+            && data.value != oldItem->value
+            && data.value != strNotInScope;
+        oldItem->setData(data);
+        oldItem->changed = changed;
+        oldItem->generation = generationCounter;
+        QModelIndex idx = watchIndex(oldItem);
+        emit dataChanged(idx, idx.sibling(idx.row(), 2));
+    } else {
+        // add new entry
+        //MODEL_DEBUG("INSERT : " << data.iname << data.value);
+        WatchItem *item = new WatchItem(data);
+        item->parent = parent;
+        item->generation = generationCounter;
+        item->changed = true;
+        int n = parent->children.size();
+        beginInsertRows(index, n, n);
+        parent->children.append(item);
+        endInsertRows();
+    }
 }
 
-WatchData *WatchHandler::findData(const QString &iname)
+WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const
 {
-    for (int i = m_completeSet.size(); --i >= 0; )
-        if (m_completeSet.at(i).iname == iname)
-            return &m_completeSet[i];
+    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;
 }
 
-WatchData WatchHandler::takeData(const QString &iname)
-{
-    WatchData data = take(iname, &m_incompleteSet);
-    if (data.isValid())
-        return data;
-    return take(iname, &m_completeSet);
-}
 
-QList<WatchData> WatchHandler::takeCurrentIncompletes()
+///////////////////////////////////////////////////////////////////////
+//
+// WatchHandler
+//
+///////////////////////////////////////////////////////////////////////
+
+WatchHandler::WatchHandler()
 {
-    QList<WatchData> res = m_incompleteSet;
-    //MODEL_DEBUG("TAKING INCOMPLETES" << toString());
-    m_incompleteSet.clear();
-    return res;
+    m_expandPointers = true;
+    m_inChange = false;
+
+    m_locals = new WatchModel(this, LocalsWatch);
+    m_watchers = new WatchModel(this, WatchersWatch);
+    m_tooltips = new WatchModel(this, TooltipsWatch);
+
+    connect(theDebuggerAction(WatchExpression),
+        SIGNAL(triggered()), this, SLOT(watchExpression()));
+    connect(theDebuggerAction(RemoveWatchExpression),
+        SIGNAL(triggered()), this, SLOT(removeWatchExpression()));
 }
 
-void WatchHandler::rebuildModel()
+void WatchHandler::endCycle()
 {
+    m_locals->removeOutdated();
+    m_watchers->removeOutdated();
+    m_tooltips->removeOutdated();
+
+/*
     if (m_inChange) {
         MODEL_DEBUG("RECREATE MODEL IGNORED, CURRENT SET:\n" << toString());
         return;
@@ -682,80 +801,9 @@ void WatchHandler::rebuildModel()
 
     qSort(m_completeSet.begin(), m_completeSet.end(), &iNameSorter);
 
-    // This helps to decide whether the view has completely changed or not.
-    QHash<QString, int> topINames;
-
-    QHash<QString, int> iname2idx;
-
-    for (int i = m_completeSet.size(); --i > 0; ) {
-        WatchData &data = m_completeSet[i];
-        data.parentIndex = 0;
-        data.childIndex.clear();
-        iname2idx[data.iname] = i;
-        if (data.level == 2)
-            ++topINames[data.iname];
-    }
-    //qDebug() << "TOPINAMES: " << topINames << "\nOLD: " << oldTopINames;
-
-    for (int i = 1; i < m_completeSet.size(); ++i) {
-        WatchData &data = m_completeSet[i];
-        QString parentIName = parentName(data.iname);
-        data.parentIndex = iname2idx.value(parentIName, 0);
-        WatchData &parent = m_completeSet[data.parentIndex];
-        data.row = parent.childIndex.size();
-        parent.childIndex.append(i);
-    }
-
-    m_oldSet = m_completeSet;
-    m_oldSet += m_incompleteSet;
-
-    for (int i = 0, n = m_completeSet.size(); i != n; ++i) {
-        WatchData &data = m_completeSet[i];
-        data.changed = !data.value.isEmpty()
-            && data.value != oldValues[data.iname]
-            && data.value != strNotInScope;
-    }
-
-    emit layoutAboutToBeChanged();
-
-    if (0 && oldTopINames != topINames) {
-        m_displaySet = initialSet();
-        m_expandedINames.clear();
-        emit reset();
-    }
-
-    m_displaySet = m_completeSet;
-
-    #ifdef DEBUG_PENDING
-    MODEL_DEBUG("SET  " << toString());
-    #endif
-
-#if 1
-    // Append dummy item to get the [+] effect
-    for (int i = 0, n = m_displaySet.size(); i != n; ++i) {
-        WatchData &data = m_displaySet[i];
-        if (data.childCount > 0 && data.childIndex.size() == 0) {
-            WatchData dummy;
-            dummy.state = 0;
-            dummy.row = 0;
-            dummy.iname = data.iname + QLatin1String(".dummy");
-            //dummy.name = data.iname + ".dummy";
-            //dummy.name  = "<loading>";
-            dummy.level = data.level + 1;
-            dummy.parentIndex = i;
-            dummy.childCount = 0;
-            data.childIndex.append(m_displaySet.size());
-            m_displaySet.append(dummy); 
-        }
-    }
-#endif
-
     // Possibly append dummy items to prevent empty views
     bool ok = true;
-    QTC_ASSERT(m_displaySet.size() >= 2, ok = false);
-    QTC_ASSERT(m_displaySet.at(1).iname == QLatin1String("local"), ok = false);
-    QTC_ASSERT(m_displaySet.at(2).iname == QLatin1String("tooltip"), ok = false);
-    QTC_ASSERT(m_displaySet.at(3).iname == QLatin1String("watch"), ok = false);
+
     if (ok) {
         for (int i = 1; i <= 3; ++i) {
             WatchData &data = m_displaySet[i];
@@ -781,38 +829,15 @@ void WatchHandler::rebuildModel()
             }
         }
     }
-
-    m_inChange = true;
-    //qDebug() << "WATCHHANDLER: RESET ABOUT TO EMIT";
-    //emit reset();
-    emit layoutChanged();
-    //qDebug() << "WATCHHANDLER: RESET EMITTED";
-    m_inChange = false;
-
-    #if DEBUG_MODEL
-    #if USE_MODEL_TEST
-    //(void) new ModelTest(this, this);
-    #endif
-    #endif
-    
-    #ifdef DEBUG_PENDING
-    MODEL_DEBUG("SORTED: " << toString());
-    MODEL_DEBUG("EXPANDED INAMES: " << m_expandedINames);
-    #endif
+*/
 }
 
 void WatchHandler::cleanup()
 {
-    m_oldSet.clear();
     m_expandedINames.clear();
     m_displayedINames.clear();
-
-    m_incompleteSet.clear();
-    m_completeSet = initialSet();
-    m_displaySet = m_completeSet;
-
-    rebuildModel(); // to get the dummy entries back
-
+    m_locals->reinitialize();
+    m_tooltips->reinitialize();
 #if 0
     for (EditWindows::ConstIterator it = m_editWindows.begin();
             it != m_editWindows.end(); ++it) {
@@ -821,108 +846,19 @@ void WatchHandler::cleanup()
     }
     m_editWindows.clear();
 #endif
-    emit reset();
-}
-
-void WatchHandler::collapseChildren()
-{
-    if (QAction *act = qobject_cast<QAction *>(sender()))
-        collapseChildren(act->data().toString());
-}
-
-void WatchHandler::collapseChildren(const QString &iname)
-{
-    if (m_inChange || m_completeSet.isEmpty()) {
-        qDebug() << "WATCHHANDLER: COLLAPSE IGNORED" << iname;
-        return;
-    }
-    MODEL_DEBUG("COLLAPSE NODE" << iname);
-#if 0
-    QString iname1 = iname0 + '.';
-    for (int i = m_completeSet.size(); --i >= 0; ) {
-        QString iname = m_completeSet.at(i).iname;
-        if (iname.startsWith(iname1)) {
-            // Better leave it in in case the user re-enters the branch?
-            (void) m_completeSet.takeAt(i);
-            MODEL_DEBUG(" REMOVING " << iname);
-            m_expandedINames.remove(iname);
-        }
-    }
-#endif
-    m_expandedINames.remove(iname);
-    //MODEL_DEBUG(toString());
-    //rebuildModel();
-}
-
-void WatchHandler::expandChildren()
-{
-    if (QAction *act = qobject_cast<QAction *>(sender()))
-        expandChildren(act->data().toString());
-}
-
-void WatchHandler::expandChildren(const QString &iname)
-{
-    if (m_inChange || m_completeSet.isEmpty()) {
-        //qDebug() << "WATCHHANDLER: EXPAND IGNORED" << iname;
-        return;
-    }
-    int index = -1;
-    for (int i = 0; i != m_displaySet.size(); ++i) {
-        if (m_displaySet.at(i).iname == iname) {
-            index = i;
-            break;
-        }
-    }
-
-    if (index == -1)
-        return;
-    QTC_ASSERT(index >= 0, qDebug() << toString() << index; return);
-    QTC_ASSERT(index < m_completeSet.size(), qDebug() << toString() << index; return);
-    const WatchData &display = m_displaySet.at(index);
-    QTC_ASSERT(index >= 0, qDebug() << toString() << index; return);
-    QTC_ASSERT(index < m_completeSet.size(), qDebug() << toString() << index; return);
-    const WatchData &complete = m_completeSet.at(index);
-    MODEL_DEBUG("\n\nEXPAND" << display.iname);
-    if (display.iname.isEmpty()) {
-        // This should not happen but the view seems to send spurious
-        // "expand()" signals folr the root item from time to time.
-        // Try to handle that gracfully.
-        //MODEL_DEBUG(toString());
-        qDebug() << "FIXME: expandChildren, no data " << display.iname << "found";
-        //rebuildModel();
-        return;
-    }
-
-    //qDebug() << "   ... NODE: " << display.toString()
-    //         << complete.childIndex.size() << complete.childCount;
-
-    if (m_expandedINames.contains(display.iname))
-        return;
-
-    // This is a performance hack and not strictly necessary.
-    // Remove it if there are troubles when expanding nodes.
-    if (0 && complete.childCount > 0 && complete.childIndex.size() > 0) {
-        MODEL_DEBUG("SKIP FETCHING CHILDREN");
-        return;
-    }
-
-    WatchData data = takeData(display.iname); // remove previous data
-    m_expandedINames.insert(data.iname);
-    if (data.iname.contains('.')) // not for top-level items
-        data.setChildrenNeeded();
-    insertData(data);
-    emit watchModelUpdateRequested();
 }
 
 void WatchHandler::insertData(const WatchData &data)
 {
     //MODEL_DEBUG("INSERTDATA: " << data.toString());
     QTC_ASSERT(data.isValid(), return);
-    if (data.isSomethingNeeded())
-        insertDataHelper(m_incompleteSet, data);
-    else
-        insertDataHelper(m_completeSet, data);
-    //MODEL_DEBUG("INSERT RESULT" << toString());
+    if (data.isSomethingNeeded()) {
+        emit watchDataUpdateNeeded(data);
+    } else {
+        WatchModel *model = modelForIName(data.iname);
+        QTC_ASSERT(model, return);
+        model->insertData(data);
+    }
 }
 
 void WatchHandler::watchExpression()
@@ -933,24 +869,27 @@ void WatchHandler::watchExpression()
 
 QString WatchHandler::watcherName(const QString &exp)
 {
-    return QLatin1String("watch.") + QString::number(m_watchers[exp]);
+    return QLatin1String("watch.") + QString::number(m_watcherNames[exp]);
 }
 
 void WatchHandler::watchExpression(const QString &exp)
 {
     // FIXME: 'exp' can contain illegal characters
-    m_watchers[exp] = watcherCounter++;
+    m_watcherNames[exp] = watcherCounter++;
     WatchData data;
     data.exp = exp;
     data.name = exp;
     data.iname = watcherName(exp);
     insertData(data);
     saveWatchers();
-    emit watchModelUpdateRequested();
+    //emit watchModelUpdateRequested();
 }
 
 void WatchHandler::setDisplayedIName(const QString &iname, bool on)
 {
+    Q_UNUSED(iname);
+    Q_UNUSED(on);
+/*
     WatchData *d = findData(iname);
     if (!on || !d) {
         delete m_editWindows.take(iname);
@@ -964,6 +903,7 @@ void WatchHandler::setDisplayedIName(const QString &iname, bool on)
     d->setValueNeeded();
     m_displayedINames.insert(iname);
     insertData(*d);
+*/
 }
 
 void WatchHandler::showEditValue(const WatchData &data)
@@ -1029,236 +969,34 @@ void WatchHandler::removeWatchExpression()
 void WatchHandler::removeWatchExpression(const QString &exp)
 {
     MODEL_DEBUG("REMOVE WATCH: " << exp);
-    m_watchers.remove(exp);
-    for (int i = m_completeSet.size(); --i >= 0;) {
-        const WatchData & data = m_completeSet.at(i);
-        if (data.iname.startsWith(QLatin1String("watch.")) && data.exp == exp) {
-            m_completeSet.takeAt(i);
+    m_watcherNames.remove(exp);
+    foreach (WatchItem *item, m_watchers->dummyRoot()->children) {
+        if (item->exp == exp) {
+            m_watchers->removeItem(item);
+            saveWatchers();
             break;
         }
     }
-    saveWatchers();
-    rebuildModel();
-    emit watchModelUpdateRequested();
 }
 
-void WatchHandler::reinitializeWatchers()
+void WatchHandler::beginCycle()
 {
-    m_completeSet = initialSet();
-    m_incompleteSet.clear();
-    reinitializeWatchersHelper();
+    ++generationCounter;
+    //m_locals->beginCycle();
 }
 
-void WatchHandler::reinitializeWatchersHelper()
+void WatchHandler::updateWatchers()
 {
+    //qDebug() << "UPDATE WATCHERS";
     // copy over all watchers and mark all watchers as incomplete
-    int i = 0;
-    foreach (const QString &exp, m_watchers.keys()) {
+    foreach (const QString &exp, m_watcherNames.keys()) {
         WatchData data;
         data.iname = watcherName(exp);
-        data.level = -1;
-        data.row = -1;
-        data.parentIndex = -1;
-        data.variable.clear();
         data.setAllNeeded();
-        data.valuedisabled = false;
         data.name = exp;
         data.exp = exp;
         insertData(data);
-        ++i;
-    }
-}
-
-bool WatchHandler::canFetchMore(const QModelIndex &parent) const
-{
-    MODEL_DEBUG("CAN FETCH MORE: " << parent << "false");
-#if 1
-    Q_UNUSED(parent);
-    return false;
-#else
-    // FIXME: not robust enough. Problem is that fetchMore
-    // needs to be made synchronous to be useful. Busy loop is no good.
-    if (!parent.isValid())
-        return false;
-    QTC_ASSERT(checkIndex(parent.internalId()), return false);
-    const WatchData &data = m_displaySet.at(parent.internalId());
-    MODEL_DEBUG("CAN FETCH MORE: " << parent << " children: " << data.childCount
-        << data.iname);
-    return data.childCount > 0;
-#endif
-}
-
-void WatchHandler::fetchMore(const QModelIndex &parent)
-{
-    MODEL_DEBUG("FETCH MORE: " << parent);
-    return;
-
-    QTC_ASSERT(checkIndex(parent.internalId()), return);
-    QString iname = m_displaySet.at(parent.internalId()).iname;
-
-    if (m_inFetchMore) {
-        MODEL_DEBUG("LOOP IN FETCH MORE" << iname);
-        return;
     }
-    m_inFetchMore = true;
-
-    WatchData data = takeData(iname);
-    MODEL_DEBUG("FETCH MORE: " << parent << ':' << iname << data.name);
-
-    if (!data.isValid()) {
-        MODEL_DEBUG("FIXME: FETCH MORE, no data " << iname << "found");
-        return;
-    }
-
-    m_expandedINames.insert(data.iname);
-    if (data.iname.contains('.')) // not for top-level items
-        data.setChildrenNeeded();
-
-    MODEL_DEBUG("FETCH MORE: data:" << data.toString());
-    insertData(data);
-    //emit watchUpdateRequested();
-
-    while (m_inFetchMore) {
-        QApplication::processEvents();
-    }
-    m_inFetchMore = false;
-    MODEL_DEBUG("BUSY LOOP FINISHED, data:" << data.toString());
-}
-
-QModelIndex WatchHandler::index(int row, int col, const QModelIndex &parent) const
-{
-    #ifdef DEBUG_MODEL
-    MODEL_DEBUG("INDEX " << row << col << parent);
-    #endif
-    //if (col != 0) {
-    //    MODEL_DEBUG(" -> " << QModelIndex() << " (3) ");
-    //    return QModelIndex();
-    //}
-    if (row < 0) {
-        MODEL_DEBUG(" -> " << QModelIndex() << " (4) ");
-        return QModelIndex();
-    }
-    if (!parent.isValid()) {
-        if (row == 0 && col >= 0 && col < 3 && parent.row() == -1) {
-            MODEL_DEBUG(" ->  " << createIndex(0, 0, 0) << " (B) ");
-            return createIndex(0, col, 0);
-        }
-        MODEL_DEBUG(" -> " << QModelIndex() << " (1) ");
-        return QModelIndex();
-    }
-    int parentIndex = parent.internalId();
-    if (parentIndex < 0) {
-        //MODEL_DEBUG("INDEX " << row << col << parentIndex << "INVALID");
-        MODEL_DEBUG(" -> " << QModelIndex() << " (2) ");
-        return QModelIndex(); 
-    }
-    QTC_ASSERT(checkIndex(parentIndex), return QModelIndex());
-    const WatchData &data = m_displaySet.at(parentIndex);
-    QTC_ASSERT(row >= 0, qDebug() << "ROW: " << row  << "PARENT: " << parent
-        << data.toString() << toString(); return QModelIndex());
-    QTC_ASSERT(row < data.childIndex.size(),
-        MODEL_DEBUG("ROW: " << row << data.toString() << toString());
-        return QModelIndex());
-    QModelIndex idx = createIndex(row, col, data.childIndex.at(row));
-    QTC_ASSERT(idx.row() == m_displaySet.at(idx.internalId()).row,
-        return QModelIndex());
-    MODEL_DEBUG(" -> " << idx << " (A) ");
-    return idx;
-}
-
-QModelIndex WatchHandler::parent(const QModelIndex &idx) const
-{
-    if (!idx.isValid()) {
-        MODEL_DEBUG(" -> " << QModelIndex() << " (1) ");
-        return QModelIndex();
-    }
-    MODEL_DEBUG("PARENT " << idx);
-    int currentIndex = idx.internalId();
-    QTC_ASSERT(checkIndex(currentIndex), return QModelIndex());
-    QTC_ASSERT(idx.row() == m_displaySet.at(currentIndex).row,
-        MODEL_DEBUG("IDX: " << idx << toString(); return QModelIndex()));
-    int parentIndex = m_displaySet.at(currentIndex).parentIndex;
-    if (parentIndex < 0) {
-        MODEL_DEBUG(" -> " << QModelIndex() << " (2) ");
-        return QModelIndex();
-    }
-    QTC_ASSERT(checkIndex(parentIndex), return QModelIndex());
-    QModelIndex parent = 
-        createIndex(m_displaySet.at(parentIndex).row, 0, parentIndex);
-    MODEL_DEBUG(" -> " << parent);
-    return parent;
-}
-
-int WatchHandler::rowCount(const QModelIndex &idx) const
-{
-    MODEL_DEBUG("ROW COUNT " << idx);
-    if (idx.column() > 0) {
-        MODEL_DEBUG(" -> " << 0 << " (A) ");
-        return 0;
-    }
-    int thisIndex = idx.internalId();
-    QTC_ASSERT(checkIndex(thisIndex), return 0);
-    if (idx.row() == -1 && idx.column() == -1) {
-        MODEL_DEBUG(" -> " << 3 << " (B) ");
-        return 1;
-    }
-    if (thisIndex < 0) {
-        MODEL_DEBUG(" -> " << 0 << " (C) ");
-        return 0;
-    }
-    if (thisIndex == 0) {
-        MODEL_DEBUG(" -> " << 3 << " (D) ");
-        return 3;
-    }
-    const WatchData &data = m_displaySet.at(thisIndex);
-    int rows = data.childIndex.size();
-    MODEL_DEBUG(" -> " << rows << " (E) ");
-    return rows;
-	// Try lazy evaluation
-    //if (rows > 0)
-    //    return rows;
-    //return data.childCount;
-}
-
-int WatchHandler::columnCount(const QModelIndex &idx) const
-{
-    MODEL_DEBUG("COLUMN COUNT " << idx);
-    if (idx == QModelIndex()) {
-        MODEL_DEBUG(" -> " << 3 << " (C) ");
-        return 3;
-    }
-    if (idx.column() != 0) {
-        MODEL_DEBUG(" -> " << 0 << " (A) ");
-        return 0;
-    }
-    MODEL_DEBUG(" -> " << 3 << " (B) ");
-    QTC_ASSERT(checkIndex(idx.internalId()), return 3);
-    return 3;
-}
-
-bool WatchHandler::hasChildren(const QModelIndex &idx) const
-{
-    // that's the base implementation:
-    bool base = rowCount(idx) > 0 && columnCount(idx) > 0;
-    MODEL_DEBUG("HAS CHILDREN: " << idx << base);
-    return base;
-    QTC_ASSERT(checkIndex(idx.internalId()), return false);
-    const WatchData &data = m_displaySet.at(idx.internalId());
-    MODEL_DEBUG("HAS CHILDREN: " << idx << data.toString());
-    return data.childCount > 0; // || data.childIndex.size() > 0;
-}
-
-bool WatchHandler::checkIndex(int id) const
-{
-    if (id < 0) {
-        MODEL_DEBUG("CHECK INDEX FAILED" << id);
-        return false;
-    }
-    if (id >= m_displaySet.size()) {
-        MODEL_DEBUG("CHECK INDEX FAILED" << id << toString());
-        return false;
-    }
-    return true;
 }
 
 void WatchHandler::loadWatchers()
@@ -1266,15 +1004,15 @@ void WatchHandler::loadWatchers()
     QVariant value;
     sessionValueRequested("Watchers", &value);
     foreach (const QString &exp, value.toStringList())
-        m_watchers[exp] = watcherCounter++;
+        m_watcherNames[exp] = watcherCounter++;
     //qDebug() << "LOAD WATCHERS: " << m_watchers;
-    reinitializeWatchersHelper();
+    //reinitializeWatchersHelper();
 }
 
 void WatchHandler::saveWatchers()
 {
     //qDebug() << "SAVE WATCHERS: " << m_watchers.keys();
-    setSessionValueRequested("Watchers", QVariant(m_watchers.keys()));
+    setSessionValueRequested("Watchers", QVariant(m_watcherNames.keys()));
 }
 
 void WatchHandler::saveSessionData()
@@ -1285,5 +1023,45 @@ void WatchHandler::saveSessionData()
 void WatchHandler::loadSessionData()
 {
     loadWatchers();
-    rebuildModel();
+    foreach (const QString &exp, m_watcherNames.keys()) {
+        WatchData data;
+        data.iname = watcherName(exp);
+        data.setAllUnneeded();
+        data.name = exp;
+        data.exp = exp;
+        insertData(data);
+    }
+}
+
+WatchModel *WatchHandler::model(WatchType type) const
+{
+    switch (type) {
+        case LocalsWatch: return m_locals;
+        case WatchersWatch: return m_watchers;
+        case TooltipsWatch: return m_tooltips;
+    }
+    QTC_ASSERT(false, /**/);
+    return 0;
+}
+    
+WatchModel *WatchHandler::modelForIName(const QString &iname) const
+{
+    if (iname.startsWith(QLatin1String("local.")))
+        return m_locals;
+    if (iname.startsWith(QLatin1String("watch.")))
+        return m_watchers;
+    if (iname.startsWith(QLatin1String("tooltip.")))
+        return m_tooltips;
+    QTC_ASSERT(false, /**/);
+    return 0;
 }
+
+WatchData *WatchHandler::findItem(const QString &iname) const
+{
+    const WatchModel *model = modelForIName(iname);
+    QTC_ASSERT(model, return 0);
+    return model->findItem(iname, model->m_root);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index 5152eccfe95eded243b648dbf3feaf8779a0fd94..9fcf4956261b5a0c72ba4098cc59b10d4448ba1a 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -42,6 +42,10 @@
 namespace Debugger {
 namespace Internal {
 
+class WatchItem;
+class WatchHandler;
+enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
+
 class WatchData
 {
 public:
@@ -120,6 +124,7 @@ public:
     QString framekey;     // key for type cache
     QScriptValue scriptValue; // if needed...
     int childCount;
+    int generation;       // when updated?
     bool valuedisabled;   // value will be greyed out
 
 private:
@@ -127,29 +132,18 @@ private:
 public:
     int source;  // Used by some debuggers (CDB) to tell where it originates from (dumper or symbol evaluation)
     int state;
-
-    // Model
-    int parentIndex;
-    int row;
-    int level;
-    QList<int> childIndex;
     bool changed;
 };
 
 enum { INameRole = Qt::UserRole, ExpressionRole, ExpandedRole };
 
-
-class WatchHandler : public QAbstractItemModel
+class WatchModel : public QAbstractItemModel
 {
     Q_OBJECT
 
-public:
-    WatchHandler();
-    QAbstractItemModel *model() { return this; }
+private:
+    explicit WatchModel(WatchHandler *handler, WatchType type);
 
-    //
-    //  QAbstractItemModel
-    //
     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;
@@ -160,23 +154,54 @@ public:
     Qt::ItemFlags flags(const QModelIndex &idx) const;
     QVariant headerData(int section, Qt::Orientation orientation,
         int role = Qt::DisplayRole) const;
-    bool checkIndex(int id) const;
-    
+    bool canFetchMore(const QModelIndex &parent) const;
+    void fetchMore(const QModelIndex &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 insertData(const WatchData &data);
+    WatchItem *findItem(const QString &iname, WatchItem *root) const;
+    void reinitialize();
+    void removeOutdated();
+    void removeOutdatedHelper(WatchItem *item);
+    WatchItem *dummyRoot() const;
+    void removeItem(WatchItem *item);
+
+private:
+    WatchHandler *m_handler;
+    WatchType m_type;
+    WatchItem *m_root;
+};
+
+class WatchHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    WatchHandler();
+    WatchModel *model(WatchType type) const;
+    WatchModel *modelForIName(const QString &data) const;
+
 //public slots:
     void cleanup();
     Q_SLOT void watchExpression(); // data in action->data().toString()
     Q_SLOT void watchExpression(const QString &exp);
     Q_SLOT void removeWatchExpression();
     Q_SLOT void removeWatchExpression(const QString &exp);
-    void reinitializeWatchers();
+    void beginCycle(); // called at begin of updateLocals() cycle
+    void updateWatchers(); // called after locals are fetched
+    void endCycle(); // called after all results have been received
+    void showEditValue(const WatchData &data);
 
-    Q_SLOT void collapseChildren();
-    Q_SLOT void expandChildren();
-    Q_SLOT void collapseChildren(const QString &iname);
-    Q_SLOT void expandChildren(const QString &iname);
+    void insertData(const WatchData &data);
+    WatchData *findItem(const QString &iname) const;
 
-    void rebuildModel(); // unconditionally version of above
-    void showEditValue(const WatchData &data);
+    void loadSessionData();
+    void saveSessionData();
 
     bool isDisplayedIName(const QString &iname) const
         { return m_displayedINames.contains(iname); }
@@ -185,27 +210,13 @@ public:
     QSet<QString> expandedINames() const
         { return m_expandedINames; }
 
-    void insertData(const WatchData &data);
-    QList<WatchData> takeCurrentIncompletes();
-
-    bool canFetchMore(const QModelIndex &parent) const;
-    void fetchMore(const QModelIndex &parent);
-
-    WatchData *findData(const QString &iname);
-
-    void loadSessionData();
-    void saveSessionData();
-
 signals:
-    void watchModelUpdateRequested();
-
+    void watchDataUpdateNeeded(const WatchData &data);
     void sessionValueRequested(const QString &name, QVariant *value);
     void setSessionValueRequested(const QString &name, const QVariant &value);
 
 private:
-    void reinitializeWatchersHelper();
-    WatchData takeData(const QString &iname);
-    QString toString() const;
+    friend class WatchModel;
 
     void loadWatchers();
     void saveWatchers();
@@ -216,18 +227,16 @@ private:
     typedef QMap<QString, QPointer<QWidget> > EditWindows;
     EditWindows m_editWindows;
 
-    QList<WatchData> m_incompleteSet;
-    QList<WatchData> m_completeSet;
-    QList<WatchData> m_oldSet;
-    QList<WatchData> m_displaySet;
-    QHash<QString, int> m_watchers;
+    QHash<QString, int> m_watcherNames;
     QString watcherName(const QString &exp);
 
     void setDisplayedIName(const QString &iname, bool on);
     QSet<QString> m_expandedINames;  // those expanded in the treeview
     QSet<QString> m_displayedINames; // those with "external" viewers
 
-    bool m_inFetchMore;
+    WatchModel *m_locals;
+    WatchModel *m_watchers;
+    WatchModel *m_tooltips;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index a4cae3a7b043b1abb194a48dd1042042200676fa..c6c07ed7ce3a9b4736dd08650fbc97f796ec22cd 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -127,26 +127,28 @@ WatchWindow::WatchWindow(Type type, QWidget *parent)
     setAcceptDrops(true);
     setDropIndicatorShown(true);
 
-    connect(this, SIGNAL(expanded(QModelIndex)),
-        this, SLOT(expandNode(QModelIndex)));
-    connect(this, SIGNAL(collapsed(QModelIndex)),
-        this, SLOT(collapseNode(QModelIndex)));
     connect(act, SIGNAL(toggled(bool)),
         this, SLOT(setAlternatingRowColorsHelper(bool)));
+    connect(this, SIGNAL(expanded(QModelIndex)), 
+        this, SLOT(expandNode(QModelIndex))); 
+    connect(this, SIGNAL(collapsed(QModelIndex)), 
+        this, SLOT(collapseNode(QModelIndex))); 
+} 
+ 
+void WatchWindow::expandNode(const QModelIndex &idx) 
+{ 
+    model()->setData(idx, true, ExpandedRole);
+} 
+ 
+void WatchWindow::collapseNode(const QModelIndex &idx) 
+{ 
+    model()->setData(idx, false, ExpandedRole);
 }
 
-void WatchWindow::expandNode(const QModelIndex &idx)
-{
-    QModelIndex mi0 = idx.sibling(idx.row(), 0);
-    QVariant iname = model()->data(mi0, INameRole);
-    theDebuggerAction(ExpandItem)->trigger(iname);
-}
-
-void WatchWindow::collapseNode(const QModelIndex &idx)
+void WatchWindow::reset()
 {
-    QModelIndex mi0 = idx.sibling(idx.row(), 0);
-    QVariant iname = model()->data(mi0, INameRole);
-    theDebuggerAction(CollapseItem)->trigger(iname);
+    QTreeView::reset(); 
+    setRootIndex(model()->index(0, 0, QModelIndex()));
 }
 
 void WatchWindow::keyPressEvent(QKeyEvent *ev)
@@ -259,17 +261,6 @@ void WatchWindow::editItem(const QModelIndex &idx)
     Q_UNUSED(idx); // FIXME
 }
 
-void WatchWindow::reset()
-{
-    QTreeView::reset(); 
-    int row = 0;
-    if (m_type == TooltipType)
-        row = 1;
-    else if (m_type == WatchersType)
-        row = 2;
-    setRootIndex(model()->index(row, 0, model()->index(0, 0)));
-}
-
 void WatchWindow::setModel(QAbstractItemModel *model)
 {
     QTreeView::setModel(model);
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index 935096ded092d0ec9f5172710756fc5d7d26fc85..af8cf163f6a15fc6c8fbd94dda447f3c7edfa240 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -59,9 +59,10 @@ public slots:
     void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); }
 
 private:
-    Q_SLOT void expandNode(const QModelIndex &index);
-    Q_SLOT void collapseNode(const QModelIndex &index);
+    void reset();
     Q_SLOT void resetHelper();
+    Q_SLOT void expandNode(const QModelIndex &idx);
+    Q_SLOT void collapseNode(const QModelIndex &idx);
 
     void keyPressEvent(QKeyEvent *ev);
     void contextMenuEvent(QContextMenuEvent *ev);
@@ -70,7 +71,6 @@ private:
     void dragMoveEvent(QDragMoveEvent *ev);
 
     void editItem(const QModelIndex &idx);
-    void reset(); /* reimpl */
 
     void resetHelper(const QModelIndex &idx);
 
diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp
index 2aaeddc1b5109c84cd65fff427701ec9f6bc9efa..f29c633c21048d1374d6f2ecf1aae55e66078725 100644
--- a/tests/manual/gdbdebugger/simple/app.cpp
+++ b/tests/manual/gdbdebugger/simple/app.cpp
@@ -122,8 +122,23 @@ private:
     QHash<QObject *, Map::iterator> h;
 };
 
+class X : virtual public Foo
+{
+public:
+    X() {
+    }
+};
+
+class Y : virtual public Foo
+{
+public:
+    Y() {
+    }
+};
+
 void testArray()
 {
+    X xxx;
     char c[20];
     c[0] = 'a';
     c[1] = 'b';