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 ¶ms0); 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';