From ad46f1286fd3242089f8a5a8c20794e433a05645 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Mon, 13 Jul 2009 09:11:07 +0200 Subject: [PATCH] Revert "Enabled the use of Debugger-specific watch/locals models." This reverts commit abf5e3ddc39b8f4971f61fb9f8dccdb1d4635bf5. --- .../debugger/abstractsyncwatchmodel.cpp | 107 --- src/plugins/debugger/asyncwatchmodel.cpp | 232 ------ src/plugins/debugger/asyncwatchmodel.h | 102 --- src/plugins/debugger/cdb/cdb.pri | 8 +- src/plugins/debugger/cdb/cdbdebugengine.cpp | 178 ++--- src/plugins/debugger/cdb/cdbdebugengine.h | 16 +- src/plugins/debugger/cdb/cdbdebugengine_p.h | 13 +- .../cdbstackframecontext.h} | 54 +- .../debugger/cdb/cdbstacktracecontext.cpp | 55 +- .../debugger/cdb/cdbstacktracecontext.h | 17 +- .../debugger/cdb/cdbsymbolgroupcontext.cpp | 1 + .../debugger/cdb/cdbsymbolgroupcontext.h | 25 + .../debugger/cdb/cdbsymbolgroupcontext_tpl.h | 99 +++ src/plugins/debugger/cdb/cdbwatchmodels.cpp | 477 ------------- src/plugins/debugger/cdb/cdbwatchmodels.h | 96 --- src/plugins/debugger/debugger.pro | 4 - src/plugins/debugger/debuggermanager.cpp | 58 +- src/plugins/debugger/debuggermanager.h | 8 +- src/plugins/debugger/gdb/gdbengine.cpp | 20 +- src/plugins/debugger/gdb/gdbengine.h | 6 +- src/plugins/debugger/idebuggerengine.h | 7 +- src/plugins/debugger/script/scriptengine.cpp | 21 +- src/plugins/debugger/script/scriptengine.h | 9 +- src/plugins/debugger/tcf/tcfengine.cpp | 10 +- src/plugins/debugger/tcf/tcfengine.h | 9 +- src/plugins/debugger/watchhandler.cpp | 661 +++++++++--------- src/plugins/debugger/watchhandler.h | 151 ++-- src/plugins/debugger/watchutils.cpp | 23 +- src/plugins/debugger/watchwindow.cpp | 8 +- 29 files changed, 687 insertions(+), 1788 deletions(-) delete mode 100644 src/plugins/debugger/abstractsyncwatchmodel.cpp delete mode 100644 src/plugins/debugger/asyncwatchmodel.cpp delete mode 100644 src/plugins/debugger/asyncwatchmodel.h rename src/plugins/debugger/{abstractsyncwatchmodel.h => cdb/cdbstackframecontext.h} (52%) delete mode 100644 src/plugins/debugger/cdb/cdbwatchmodels.cpp delete mode 100644 src/plugins/debugger/cdb/cdbwatchmodels.h diff --git a/src/plugins/debugger/abstractsyncwatchmodel.cpp b/src/plugins/debugger/abstractsyncwatchmodel.cpp deleted file mode 100644 index 9cf1d8404dd..00000000000 --- a/src/plugins/debugger/abstractsyncwatchmodel.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** -**************************************************************************/ - -#include "abstractsyncwatchmodel.h" - -#include <utils/qtcassert.h> -#include <QtCore/QDebug> - -namespace Debugger { -namespace Internal { - -enum { debug = 0 }; - -AbstractSyncWatchModel::AbstractSyncWatchModel(WatchHandler *handler, WatchType type, QObject *parent) : - WatchModel(handler, type, parent) -{ -} - -void AbstractSyncWatchModel::fetchMore(const QModelIndex &parent) -{ - WatchItem *item = watchItem(parent); - if (!item || item == root()) - return; - if (debug) - qDebug() << ">fetchMore" << item->toString(); - // Figure out children... - if (item->isHasChildrenNeeded()) { - m_errorMessage.clear(); - if (!complete(item, &m_errorMessage)) { - item->setHasChildren(false); - emit error(m_errorMessage); - } - } - if (item->isChildrenNeeded()) { - m_errorMessage.clear(); - if (fetchChildren(item, &m_errorMessage)) { - item->setChildrenUnneeded(); - } else { - item->setHasChildren(false); - emit error(m_errorMessage); - } - } - - if (debug) - qDebug() << "<fetchMore" << item->iname << item->children.size(); -} - -bool AbstractSyncWatchModel::canFetchMore(const QModelIndex &parent) const -{ - WatchItem *item = watchItem(parent); - if (!item || item == root()) - return false; - const bool rc = item->isChildrenNeeded() || item->isHasChildrenNeeded(); - if (debug) - qDebug() << "canFetchMore" << rc << item->iname; - return rc; -} - -QVariant AbstractSyncWatchModel::data(const QModelIndex &idx, int role) const -{ - if (WatchItem *wdata = watchItem(idx)) { - const int column = idx.column(); - // Is any display data (except children) needed? - const bool incomplete = (wdata->state & ~WatchData::ChildrenNeeded); - if ((debug > 1) && incomplete && column == 0 && role == Qt::DisplayRole) - qDebug() << "data()" << "incomplete=" << incomplete << wdata->toString(); - if (incomplete) { - AbstractSyncWatchModel *nonConstThis = const_cast<AbstractSyncWatchModel *>(this); - m_errorMessage.clear(); - if (!nonConstThis->complete(wdata, &m_errorMessage)) { - wdata->setAllUnneeded(); - nonConstThis->emit error(m_errorMessage); - } - } - return WatchModel::data(*wdata, column, role); - } - return QVariant(); -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/asyncwatchmodel.cpp b/src/plugins/debugger/asyncwatchmodel.cpp deleted file mode 100644 index 5b627eb8606..00000000000 --- a/src/plugins/debugger/asyncwatchmodel.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** -**************************************************************************/ - -#include "asyncwatchmodel.h" - -#include <QtCore/QCoreApplication> - -#include <utils/qtcassert.h> - -namespace Debugger { -namespace Internal { - -int AsyncWatchModel::generationCounter = 0; - -static const QString strNotInScope = - QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>"); - -//////////////////////////////////////////////////////////////////// -// -// WatchItem -// -//////////////////////////////////////////////////////////////////// - -AsyncWatchModel::AsyncWatchModel(WatchHandler *handler, WatchType type, QObject *parent) : - WatchModel(handler, type, parent) -{ - dummyRoot()->fetchTriggered = true; -} - -void AsyncWatchModel::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 AsyncWatchModel::removeOutdatedHelper(WatchItem *item) -{ - if (item->generation < generationCounter) - removeItem(item); - else { - foreach (WatchItem *child, item->children) - removeOutdatedHelper(child); - item->fetchTriggered = false; - } -} - -bool AsyncWatchModel::canFetchMore(const QModelIndex &index) const -{ - if (index.isValid()) - if (const WatchItem *item = watchItem(index)) - return !item->fetchTriggered; - return false; -} - -void AsyncWatchModel::fetchMore(const QModelIndex &index) -{ - QTC_ASSERT(index.isValid(), return); - WatchItem *item = watchItem(index); - QTC_ASSERT(item && !item->fetchTriggered, return); - item->fetchTriggered = true; - WatchData data = *item; - data.setChildrenNeeded(); - emit watchDataUpdateNeeded(data); -} - -static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) -{ - QString name1 = item1->iname.section('.', -1); - QString name2 = item2->iname.section('.', -1); - if (!name1.isEmpty() && !name2.isEmpty()) { - if (name1.at(0).isDigit() && name2.at(0).isDigit()) - return name1.toInt() < name2.toInt(); - } - return name1 < name2; -} - -static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) -{ - QList<WatchItem *>::const_iterator it = - qLowerBound(list.begin(), list.end(), item, iNameSorter); - return it - list.begin(); -} - -void AsyncWatchModel::insertData(const WatchData &data) -{ - // qDebug() << "WMI:" << data.toString(); - QTC_ASSERT(!data.iname.isEmpty(), return); - WatchItem *parent = findItemByIName(parentName(data.iname), 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 = findItemByIName(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 = findInsertPosition(parent->children, item); - beginInsertRows(index, n, n); - parent->children.insert(n, item); - endInsertRows(); - } -} - -// ----------------- AsyncWatchModelMixin -AsyncWatchModelMixin::AsyncWatchModelMixin(WatchHandler *wh, - QObject *parent) : - QObject(parent), - m_wh(wh) -{ -} - -AsyncWatchModelMixin::~AsyncWatchModelMixin() -{ -} - -AsyncWatchModel *AsyncWatchModelMixin::model(int wt) const -{ - if (wt < 0 || wt >= WatchModelCount) - return 0; - if (!m_models[wt]) { - m_models[wt] = new AsyncWatchModel(m_wh, static_cast<WatchType>(wt), const_cast<AsyncWatchModelMixin *>(this)); - connect(m_models[wt], SIGNAL(watchDataUpdateNeeded(WatchData)), this, SIGNAL(watchDataUpdateNeeded(WatchData))); - m_models[wt]->setObjectName(QLatin1String("model") + QString::number(wt)); - } - return m_models[wt]; -} - -AsyncWatchModel *AsyncWatchModelMixin::modelForIName(const QString &iname) const -{ - const WatchType wt = WatchHandler::watchTypeOfIName(iname); - QTC_ASSERT(wt != WatchModelCount, return 0); - return model(wt); -} - -void AsyncWatchModelMixin::beginCycle() -{ - ++AsyncWatchModel::generationCounter; -} - -void AsyncWatchModelMixin::updateWatchers() -{ - //qDebug() << "UPDATE WATCHERS"; - // copy over all watchers and mark all watchers as incomplete - foreach (const QString &exp, m_wh->watcherExpressions()) { - WatchData data; - data.iname = m_wh->watcherName(exp); - data.setAllNeeded(); - data.name = exp; - data.exp = exp; - insertData(data); - } -} - -void AsyncWatchModelMixin::endCycle() -{ - for (int m = 0; m < WatchModelCount; m++) - if (m_models[m]) - m_models[m]->removeOutdated(); -} - -void AsyncWatchModelMixin::insertWatcher(const WatchData &data) -{ - // Is the engine active? - if (m_models[WatchersWatch] && m_wh->model(WatchersWatch) == m_models[WatchersWatch]) - insertData(data); -} - -void AsyncWatchModelMixin::insertData(const WatchData &data) -{ - QTC_ASSERT(data.isValid(), return); - if (data.isSomethingNeeded()) { - emit watchDataUpdateNeeded(data); - } else { - AsyncWatchModel *model = modelForIName(data.iname); - QTC_ASSERT(model, return); - model->insertData(data); - } -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/asyncwatchmodel.h b/src/plugins/debugger/asyncwatchmodel.h deleted file mode 100644 index 880f2f83d76..00000000000 --- a/src/plugins/debugger/asyncwatchmodel.h +++ /dev/null @@ -1,102 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** -**************************************************************************/ - -#ifndef ASYNCWATCHMODEL_H -#define ASYNCWATCHMODEL_H - -#include "watchhandler.h" -#include <QtCore/QPointer> - -namespace Debugger { -namespace Internal { - -/* AsyncWatchModel: incrementally populated by asynchronous debuggers via - * fetch. */ - -class AsyncWatchModel : public WatchModel -{ - Q_OBJECT -public: - explicit AsyncWatchModel(WatchHandler *handler, WatchType type, QObject *parent = 0); - - bool canFetchMore(const QModelIndex &parent) const; - void fetchMore(const QModelIndex &parent); - - friend class WatchHandler; - friend class GdbEngine; - - void insertData(const WatchData &data); - - void removeOutdated(); - void removeOutdatedHelper(WatchItem *item); - - void setActiveData(const QString &data) { m_activeData = data; } - - static int generationCounter; - -signals: - void watchDataUpdateNeeded(const WatchData &data); - -private: - QString m_activeData; - WatchItem *m_root; -}; - -/* A Mixin to manage asynchronous models. */ - -class AsyncWatchModelMixin : public QObject { - Q_OBJECT -public: - explicit AsyncWatchModelMixin(WatchHandler *wh, QObject *parent = 0); - virtual ~AsyncWatchModelMixin(); - - AsyncWatchModel *model(int t) const; - AsyncWatchModel *modelForIName(const QString &iname) const; - - void beginCycle(); // called at begin of updateLocals() cycle - void updateWatchers(); // called after locals are fetched - void endCycle(); // called after all results have been received - -public slots: - void insertData(const WatchData &data); - // For watchers, ensures that engine is active - void insertWatcher(const WatchData &data); - -signals: - void watchDataUpdateNeeded(const WatchData &data); - -private: - WatchHandler *m_wh; - mutable QPointer<AsyncWatchModel> m_models[WatchModelCount]; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // ASYNCWATCHMODEL_H diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index 3c7398567b8..06f14409d32 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -39,6 +39,7 @@ HEADERS += \ $$PWD/cdbsymbolgroupcontext.h \ $$PWD/cdbsymbolgroupcontext_tpl.h \ $$PWD/cdbstacktracecontext.h \ + $$PWD/cdbstackframecontext.h \ $$PWD/cdbbreakpoint.h \ $$PWD/cdbmodules.h \ $$PWD/cdbassembler.h \ @@ -46,14 +47,14 @@ HEADERS += \ $$PWD/cdboptionspage.h \ $$PWD/cdbdumperhelper.h \ $$PWD/cdbsymbolpathlisteditor.h \ - $$PWD/cdbexceptionutils.h \ - $$PWD/cdbwatchmodels.h + $$PWD/cdbexceptionutils.h SOURCES += \ $$PWD/cdbdebugengine.cpp \ $$PWD/cdbdebugeventcallback.cpp \ $$PWD/cdbdebugoutput.cpp \ $$PWD/cdbsymbolgroupcontext.cpp \ + $$PWD/cdbstackframecontext.cpp \ $$PWD/cdbstacktracecontext.cpp \ $$PWD/cdbbreakpoint.cpp \ $$PWD/cdbmodules.cpp \ @@ -62,8 +63,7 @@ SOURCES += \ $$PWD/cdboptionspage.cpp \ $$PWD/cdbdumperhelper.cpp \ $$PWD/cdbsymbolpathlisteditor.cpp \ - $$PWD/cdbexceptionutils.cpp \ - $$PWD/cdbwatchmodels.cpp + $$PWD/cdbexceptionutils.cpp FORMS += $$PWD/cdboptionspagewidget.ui diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 867cfb5a91c..798f5234ff4 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -30,6 +30,7 @@ #include "cdbdebugengine.h" #include "cdbdebugengine_p.h" #include "cdbstacktracecontext.h" +#include "cdbstackframecontext.h" #include "cdbsymbolgroupcontext.h" #include "cdbbreakpoint.h" #include "cdbmodules.h" @@ -46,7 +47,6 @@ #include "moduleshandler.h" #include "disassemblerhandler.h" #include "watchutils.h" -#include "cdbwatchmodels.h" #include <coreplugin/icore.h> #include <utils/qtcassert.h> @@ -301,9 +301,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, m_debuggerManagerAccess(parent->engineInterface()), m_currentStackTrace(0), m_firstActivatedFrame(true), - m_mode(AttachCore), - m_localsModel(0), - m_watchModel(0) + m_mode(AttachCore) { } @@ -392,15 +390,6 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate() m_cif.debugDataSpaces->Release(); } -void CdbDebugEnginePrivate::saveLocalsViewState() -{ - if (m_localsModel && m_localsModel->symbolGroupContext()) { - const int oldFrame = m_debuggerManagerAccess->stackHandler()->currentIndex(); - if (oldFrame != -1) - m_debuggerManagerAccess->watchHandler()->saveLocalsViewState(oldFrame); - } -} - void CdbDebugEnginePrivate::clearForRun() { if (debugCDB) @@ -414,10 +403,6 @@ void CdbDebugEnginePrivate::clearForRun() void CdbDebugEnginePrivate::cleanStackTrace() { - if (m_localsModel) { - saveLocalsViewState(); - m_localsModel->setSymbolGroupContext(0); - } if (m_currentStackTrace) { delete m_currentStackTrace; m_currentStackTrace = 0; @@ -480,19 +465,14 @@ QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &functio QString errorMessage; QString rc; // Find the frame of the function if there is any - const QString iname = QLatin1String("local.") + exp; + CdbStackFrameContext *frame = 0; if (m_d->m_currentStackTrace && !function.isEmpty()) { const int frameIndex = m_d->m_currentStackTrace->indexOf(function); - if (frameIndex != -1) { - // Are we at the current frame? - if (frameIndex == m_d->m_debuggerManagerAccess->stackHandler()->currentIndex()) { - if (const WatchData *wd = m_d->m_localsModel->findItemByIName(iname, m_d->m_localsModel->root())) - return wd->toToolTip(); } - // Nope, try to retrieve via another symbol group - if (m_d->m_currentStackTrace->editorToolTip(frameIndex, iname, &rc, &errorMessage)) - return rc; - } + if (frameIndex != -1) + frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage); } + if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage)) + return rc; // No function/symbol context found, try to evaluate in current context. // Do not append type as this will mostly be 'long long' for integers, etc. QString type; @@ -790,6 +770,67 @@ void CdbDebugEngine::detachDebugger() m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach); } +CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const +{ + if (!m_currentStackTrace) { + *errorMessage = QLatin1String(msgNoStackTraceC); + return 0; + } + if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage)) + return sg; + return 0; +} + +void CdbDebugEngine::evaluateWatcher(WatchData *wd) +{ + if (debugCDBWatchHandling) + qDebug() << Q_FUNC_INFO << wd->exp; + QString errorMessage; + QString value; + QString type; + if (evaluateExpression(wd->exp, &value, &type, &errorMessage)) { + wd->setValue(value); + wd->setType(type); + } else { + wd->setValue(errorMessage); + wd->setTypeUnneeded(); + } + wd->setHasChildren(false); +} + +void CdbDebugEngine::updateWatchData(const WatchData &incomplete) +{ + // Watch item was edited while running + if (m_d->isDebuggeeRunning()) + return; + + if (debugCDBWatchHandling) + qDebug() << Q_FUNC_INFO << "\n " << incomplete.toString(); + + WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); + if (incomplete.iname.startsWith(QLatin1String("watch."))) { + WatchData watchData = incomplete; + evaluateWatcher(&watchData); + watchHandler->insertData(watchData); + return; + } + + const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex(); + + bool success = false; + QString errorMessage; + do { + CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage); + if (!sg) + break; + if (!sg->completeData(incomplete, watchHandler, &errorMessage)) + break; + success = true; + } while (false); + if (!success) + warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); +} + void CdbDebugEngine::stepExec() { if (debugCDB) @@ -996,14 +1037,18 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v bool success = false; do { QString newValue; - if (frameIndex < 0 || !m_d->m_currentStackTrace) { - errorMessage = tr("No current stack trace."); + CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage); + if (!sg) break; - } - // Assign in stack and update view - if (!m_d->m_currentStackTrace->assignValue(frameIndex, expr, value, &newValue, &errorMessage)) + if (!sg->assignValue(expr, value, &newValue, &errorMessage)) break; - m_d->m_localsModel->setValueByExpression(expr, newValue); + // Update view + WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); + if (WatchData *fwd = watchHandler->findItem(expr)) { + fwd->setValue(newValue); + watchHandler->insertData(*fwd); + watchHandler->updateWatchers(); + } success = true; } while (false); if (!success) { @@ -1033,11 +1078,6 @@ bool CdbDebugEnginePrivate::executeDebuggerCommand(CIDebugControl *ctrl, const Q return true; } -bool CdbDebugEngine::isDebuggeeHalted() const -{ - return m_d->m_hDebuggeeProcess && !m_d->isDebuggeeRunning(); -} - bool CdbDebugEngine::evaluateExpression(const QString &expression, QString *value, QString *type, @@ -1092,21 +1132,21 @@ void CdbDebugEngine::activateFrame(int frameIndex) bool success = false; do { StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler(); + WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); const int oldIndex = stackHandler->currentIndex(); if (frameIndex >= stackHandler->stackSize()) { errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize()); break; } - if (oldIndex != frameIndex) { - m_d->saveLocalsViewState(); + if (oldIndex != frameIndex) stackHandler->setCurrentIndex(frameIndex); - } const StackFrame &frame = stackHandler->currentFrame(); if (!frame.isUsable()) { - m_d->m_localsModel->setSymbolGroupContext(0); // Clean out model + watchHandler->beginCycle(); + watchHandler->endCycle(); errorMessage = QString::fromLatin1("%1: file %2 unusable."). arg(QLatin1String(Q_FUNC_INFO), frame.file); break; @@ -1115,18 +1155,10 @@ void CdbDebugEngine::activateFrame(int frameIndex) m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true); if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) { - m_d->m_localsModel->setUseDumpers(m_d->m_dumper->isEnabled() && theDebuggerBoolSetting(UseDebuggingHelpers)); - CdbSymbolGroupContext *ctx = 0; - if (m_d->m_currentStackTrace) { - ctx = m_d->m_currentStackTrace->symbolGroupAt(frameIndex, &errorMessage); - success = ctx != 0; - } else { - errorMessage = QLatin1String(msgNoStackTraceC); - } - m_d->m_localsModel->setSymbolGroupContext(ctx); - m_d->m_debuggerManagerAccess->watchHandler()->restoreLocalsViewState(frameIndex); - } else { - success = true; + watchHandler->beginCycle(); + if (CdbStackFrameContext *sgc = m_d->getStackFrameContext(frameIndex, &errorMessage)) + success = sgc->populateModelInitially(watchHandler, &errorMessage); + watchHandler->endCycle(); } } while (false); if (!success) @@ -1190,7 +1222,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa m_cif.debugSymbols, m_debuggerManagerAccess->breakHandler(), errorMessage, &warnings); - if (const int warningsCount = warnings.size()) + if (const int warningsCount = warnings.size()) for (int w = 0; w < warningsCount; w++) m_engine->warning(warnings.at(w)); return ok; @@ -1468,8 +1500,7 @@ void CdbDebugEnginePrivate::updateStackTrace() m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current); m_engine->activateFrame(current); } - // Update watchers - m_watchModel->refresh(); + m_debuggerManagerAccess->watchHandler()->updateWatchers(); } void CdbDebugEnginePrivate::updateModules() @@ -1481,6 +1512,8 @@ void CdbDebugEnginePrivate::updateModules() m_debuggerManagerAccess->modulesHandler()->setModules(modules); } +static const char *dumperPrefixC = "dumper"; + void CdbDebugEnginePrivate::handleModuleLoad(const QString &name) { if (debugCDB>2) @@ -1553,37 +1586,6 @@ bool CdbDebugEnginePrivate::setSymbolPaths(const QStringList &s, QString *errorM return true; } -void CdbDebugEngine::insertWatcher(const WatchData &wd) -{ - // Make sure engine is active - if (m_d->m_watchModel && m_d->m_watchModel == m_d->m_debuggerManagerAccess->watchHandler()->model(WatchersWatch)) - m_d->m_watchModel->addWatcher(wd); -} - -WatchModel *CdbDebugEngine::watchModel(int type) const -{ - switch (type) { - case LocalsWatch: - if (!m_d->m_localsModel) { - m_d->m_localsModel = new CdbLocalsModel(m_d->m_dumper, m_d->m_debuggerManagerAccess->watchHandler(), LocalsWatch, const_cast<CdbDebugEngine*>(this)); - connect(m_d->m_localsModel, SIGNAL(error(QString)), this, SLOT(warning(QString))); - } - return m_d->m_localsModel; - case WatchersWatch: - if (!m_d->m_watchModel) { - CdbDebugEngine* nonConstThis = const_cast<CdbDebugEngine*>(this); - WatchHandler *wh = m_d->m_debuggerManagerAccess->watchHandler(); - m_d->m_watchModel = new CdbWatchModel(nonConstThis, m_d->m_dumper, wh, WatchersWatch, nonConstThis); - connect(m_d->m_watchModel, SIGNAL(error(QString)), this, SLOT(warning(QString))); - connect(wh, SIGNAL(watcherInserted(WatchData)), this, SLOT(insertWatcher(WatchData))); - } - return m_d->m_watchModel; - default: - break; - } - return 0; -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 8c827769709..13725bb97e4 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -64,14 +64,15 @@ public: virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters); virtual void exitDebugger(); virtual void detachDebugger(); + virtual void updateWatchData(const WatchData &data); virtual void stepExec(); virtual void stepOutExec(); virtual void nextExec(); virtual void stepIExec(); virtual void nextIExec(); - - virtual void continueInferior(); + + virtual void continueInferior(); virtual void interruptInferior(); virtual void runToLineExec(const QString &fileName, int lineNumber); @@ -96,11 +97,6 @@ public: virtual void reloadSourceFiles(); virtual void reloadFullStack() {} - WatchModel *watchModel(int type) const; - - bool isDebuggeeHalted() const; - bool evaluateExpression(const QString &expression, QString *value, QString *type, QString *errorMessage); - public slots: void syncDebuggerPaths(); @@ -110,9 +106,8 @@ protected: private slots: void slotConsoleStubStarted(); void slotConsoleStubError(const QString &msg); - void slotConsoleStubTerminated(); + void slotConsoleStubTerminated(); void warning(const QString &w); - void insertWatcher(const WatchData &); private: bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage); @@ -121,7 +116,8 @@ private: void killWatchTimer(); void processTerminated(unsigned long exitCode); bool executeDebuggerCommand(const QString &command, QString *errorMessage); - + bool evaluateExpression(const QString &expression, QString *value, QString *type, QString *errorMessage); + void evaluateWatcher(WatchData *wd); QString editorToolTip(const QString &exp, const QString &function); CdbDebugEnginePrivate *m_d; diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 910486aa8b5..23eb5648275 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -39,7 +39,6 @@ #include <utils/consoleprocess.h> #include <QtCore/QSharedPointer> -#include <QtCore/QPointer> #include <QtCore/QMap> namespace Debugger { @@ -50,8 +49,6 @@ class IDebuggerManagerAccessForEngines; class WatchHandler; class CdbStackFrameContext; class CdbStackTraceContext; -class CdbLocalsModel; -class CdbWatchModel; // Thin wrapper around the 'DBEng' debugger engine shared library // which is loaded at runtime. @@ -118,7 +115,7 @@ struct CdbDebugEnginePrivate bool isDebuggeeRunning() const { return m_watchTimer != -1; } void handleDebugEvent(); - void updateThreadList(); + void updateThreadList(); void updateStackTrace(); void updateModules(); @@ -126,6 +123,7 @@ struct CdbDebugEnginePrivate void cleanStackTrace(); void clearForRun(); void handleModuleLoad(const QString &); + CdbStackFrameContext *getStackFrameContext(int frameIndex, QString *errorMessage) const; void clearDisplay(); bool interruptInterferiorProcess(QString *errorMessage); @@ -139,8 +137,6 @@ struct CdbDebugEnginePrivate enum EndDebuggingMode { EndDebuggingDetach, EndDebuggingTerminate, EndDebuggingAuto }; void endDebugging(EndDebuggingMode em = EndDebuggingAuto); - void saveLocalsViewState(); - static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage); static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage); @@ -159,7 +155,7 @@ struct CdbDebugEnginePrivate int m_watchTimer; CdbComInterfaces m_cif; CdbDebugEventCallback m_debugEventCallBack; - CdbDebugOutput m_debugOutputCallBack; + CdbDebugOutput m_debugOutputCallBack; QSharedPointer<CdbDumperHelper> m_dumper; CdbDebugEngine* m_engine; @@ -172,9 +168,6 @@ struct CdbDebugEnginePrivate DebuggerStartMode m_mode; Core::Utils::ConsoleProcess m_consoleStubProc; - - QPointer<CdbLocalsModel> m_localsModel; - QPointer<CdbWatchModel> m_watchModel; }; // helper functions diff --git a/src/plugins/debugger/abstractsyncwatchmodel.h b/src/plugins/debugger/cdb/cdbstackframecontext.h similarity index 52% rename from src/plugins/debugger/abstractsyncwatchmodel.h rename to src/plugins/debugger/cdb/cdbstackframecontext.h index 91573a0602b..f9ba79c9f83 100644 --- a/src/plugins/debugger/abstractsyncwatchmodel.h +++ b/src/plugins/debugger/cdb/cdbstackframecontext.h @@ -27,49 +27,49 @@ ** **************************************************************************/ -#ifndef ABSTRACTSYNCWATCHMODEL_H -#define ABSTRACTSYNCWATCHMODEL_H +#ifndef CDBSTACKFRAMECONTEXT_H +#define CDBSTACKFRAMECONTEXT_H -#include "watchhandler.h" -#include <QtCore/QPointer> #include <QtCore/QList> - -QT_BEGIN_NAMESPACE -class QDebug; -QT_END_NAMESPACE +#include <QtCore/QSharedPointer> namespace Debugger { namespace Internal { -/* AbstractSyncWatchModel: To be used by synchonous debuggers. - * Implements all of WatchModel and provides new virtuals for - * the debugger to complete items. */ +class WatchData; +class WatchHandler; +class CdbSymbolGroupContext; +class CdbDumperHelper; + +/* CdbStackFrameContext manages a symbol group context and + * a dumper context. It dispatches calls between the local items + * that are handled by the symbol group and those that are handled by the dumpers. */ -class AbstractSyncWatchModel : public WatchModel +class CdbStackFrameContext { - Q_OBJECT + Q_DISABLE_COPY(CdbStackFrameContext) public: - explicit AbstractSyncWatchModel(WatchHandler *handler, WatchType type, QObject *parent = 0); - - virtual QVariant data(const QModelIndex &index, int role) const; + explicit CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper, + CdbSymbolGroupContext *symbolContext); + ~CdbStackFrameContext(); - virtual void fetchMore(const QModelIndex &parent); - virtual bool canFetchMore(const QModelIndex &parent) const; + bool assignValue(const QString &iname, const QString &value, + QString *newValue /* = 0 */, QString *errorMessage); + bool editorToolTip(const QString &iname, QString *value, QString *errorMessage); -signals: - // Emitted if one of fetchChildren/complete fails. - void error(const QString &); + bool populateModelInitially(WatchHandler *wh, QString *errorMessage); -protected: - // Overwrite these virtuals to fetch children of an item and to complete it - virtual bool fetchChildren(WatchItem *wd, QString *errorMessage) = 0; - virtual bool complete(WatchItem *wd, QString *errorMessage) = 0; + bool completeData(const WatchData &incompleteLocal, + WatchHandler *wh, + QString *errorMessage); private: - mutable QString m_errorMessage; + const bool m_useDumpers; + const QSharedPointer<CdbDumperHelper> m_dumper; + CdbSymbolGroupContext *m_symbolContext; }; } // namespace Internal } // namespace Debugger -#endif // ABSTRACTSYNCWATCHMODEL_H +#endif // CDBSTACKFRAMECONTEXT_H diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index d3d927cd49f..7663f315d0a 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -28,11 +28,11 @@ **************************************************************************/ #include "cdbstacktracecontext.h" +#include "cdbstackframecontext.h" #include "cdbbreakpoint.h" #include "cdbsymbolgroupcontext.h" #include "cdbdebugengine_p.h" #include "cdbdumperhelper.h" -#include "debuggeractions.h" #include <QtCore/QDir> #include <QtCore/QTextStream> @@ -90,7 +90,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa qDebug() << Q_FUNC_INFO << frameCount; m_frameContexts.resize(frameCount); - qFill(m_frameContexts, static_cast<CdbSymbolGroupContext*>(0)); + qFill(m_frameContexts, static_cast<CdbStackFrameContext*>(0)); // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames WCHAR wszBuf[MAX_PATH]; @@ -145,7 +145,7 @@ static inline QString msgFrameContextFailed(int index, const StackFrame &f, cons arg(index).arg(f.function).arg(f.line).arg(f.file, why); } -CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupAt(int index, QString *errorMessage) +CdbStackFrameContext *CdbStackTraceContext::frameContextAt(int index, QString *errorMessage) { // Create a frame on demand if (debugCDB) @@ -158,7 +158,6 @@ CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupAt(int index, QString *e } if (m_frameContexts.at(index)) return m_frameContexts.at(index); - // Create COM and wrap CIDebugSymbolGroup *sg = createSymbolGroup(index, errorMessage); if (!sg) { *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); @@ -169,8 +168,9 @@ CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupAt(int index, QString *e *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage); return 0; } - m_frameContexts[index] = sc; - return sc; + CdbStackFrameContext *fr = new CdbStackFrameContext(m_dumper, sc); + m_frameContexts[index] = fr; + return fr; } CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage) @@ -198,49 +198,6 @@ CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString * return sg; } -bool CdbStackTraceContext::editorToolTip(int frameIndex, - const QString &iname, - QString *value, - QString *errorMessage) -{ - value->clear(); - // Look up iname in the frame's symbol group. - CdbSymbolGroupContext *m_symbolContext = symbolGroupAt(frameIndex, errorMessage); - if (!m_symbolContext) - return false; - unsigned long index; - if (!m_symbolContext->lookupPrefix(iname, &index)) { - *errorMessage = QString::fromLatin1("%1 not found.").arg(iname); - return false; - } - const WatchData wd = m_symbolContext->symbolAt(index); - // Check dumpers. Should actually be just one item. - if (theDebuggerBoolSetting(UseDebuggingHelpers) && m_dumper->isEnabled()) { - QList<WatchData> result; - if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, 1, &result, errorMessage)) { - foreach (const WatchData &dwd, result) { - if (!value->isEmpty()) - value->append(QLatin1Char('\n')); - value->append(dwd.toToolTip()); - } - return true; - } // Dumped ok - } // has Dumpers - *value = wd.toToolTip(); - return true; -} - -bool CdbStackTraceContext::assignValue(int frameIndex, - const QString &iname, - const QString &value, - QString *newValue /* = 0 */, QString *errorMessage) -{ - if (CdbSymbolGroupContext *symbolContext = symbolGroupAt(frameIndex, errorMessage)) - return symbolContext->assignValue(iname, value, newValue, errorMessage); - return false; -} - - QString CdbStackTraceContext::toString() const { QString rc; diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index d878472450b..9dfbdf04745 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -47,10 +47,11 @@ namespace Internal { struct CdbComInterfaces; class CdbSymbolGroupContext; +class CdbStackFrameContext; class CdbDumperHelper; /* Context representing a break point stack consisting of several frames. - * Maintains an on-demand constructed list of CdbSymbolGroupContext + * Maintains an on-demand constructed list of CdbStackFrameContext * containining the local variables of the stack. */ class CdbStackTraceContext @@ -74,17 +75,7 @@ public: // Top-Level instruction offset for disassembler ULONG64 instructionOffset() const { return m_instructionOffset; } - CdbSymbolGroupContext *symbolGroupAt(int index, QString *errorMessage); - - // Helper to retrieve an editor tooltip for a frame. Note that - // for the current frame, the LocalsModel should be consulted first. - bool editorToolTip(int frameIndex,const QString &iname, QString *value, QString *errorMessage); - - // Assign value in Debugger - bool assignValue(int frameIndex, - const QString &iname, - const QString &value, - QString *newValue /* = 0 */, QString *errorMessage); + CdbStackFrameContext *frameContextAt(int index, QString *errorMessage); // Format for logging void format(QTextStream &str) const; @@ -98,7 +89,7 @@ private: CdbComInterfaces *m_cif; DEBUG_STACK_FRAME m_cdbFrames[maxFrames]; - QVector <CdbSymbolGroupContext*> m_frameContexts; + QVector <CdbStackFrameContext*> m_frameContexts; QList<StackFrame> m_frames; ULONG64 m_instructionOffset; }; diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index 94bf9814f62..5d82835f53d 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -406,6 +406,7 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); wd.setType(type); wd.setValue(fixValue(value)); + wd.setChildrenNeeded(); // compensate side effects of above setters // Figure out children. The SubElement is only a guess unless the symbol, // is expanded, so, we leave this as a guess for later updates. // If the symbol has children (expanded or not), we leave the 'Children' flag diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index 16b7f5fab61..91ec5fd9240 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -81,6 +81,31 @@ public: bool assignValue(const QString &iname, const QString &value, QString *newValue /* = 0 */, QString *errorMessage); + // Initially populate the locals model for a new stackframe. + // Write a sequence of WatchData to it, recurse down if the + // recursionPredicate agrees. The ignorePredicate can be used + // to terminate processing after insertion of an item (if the calling + // routine wants to insert another subtree). + template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> + static bool populateModelInitially(CdbSymbolGroupContext *sg, + OutputIterator it, + RecursionPredicate recursionPredicate, + IgnorePredicate ignorePredicate, + QString *errorMessage); + + // Complete children of a WatchData item. + // Write a sequence of WatchData to it, recurse if the + // recursionPredicate agrees. The ignorePredicate can be used + // to terminate processing after insertion of an item (if the calling + // routine wants to insert another subtree). + template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> + static bool completeData (CdbSymbolGroupContext *sg, + WatchData incompleteLocal, + OutputIterator it, + RecursionPredicate recursionPredicate, + IgnorePredicate ignorePredicate, + QString *errorMessage); + // Retrieve child symbols of prefix as a sequence of WatchData. template <class OutputIterator> bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage); diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h index 5aa9c35a2fd..ccaba97ee89 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h @@ -66,6 +66,105 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato return true; } +// Insert a symbol (and its first level children depending on forceRecursion) +// The parent symbol is inserted before the children to make dumper handling +// simpler. In theory, it can happen that the symbol context indicates +// children but can expand none, which would lead to invalid parent information +// (expand icon), though (ignore for simplicity). +template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> +bool insertSymbolRecursion(WatchData wd, + CdbSymbolGroupContext *sg, + OutputIterator it, + RecursionPredicate recursionPredicate, + IgnorePredicate ignorePredicate, + QString *errorMessage) +{ + // Find out whether to recurse (has children and predicate agrees) + const bool hasChildren = wd.hasChildren || wd.isChildrenNeeded(); + const bool recurse = hasChildren && recursionPredicate(wd); + if (debugSgRecursion) + qDebug() << "insertSymbolRecursion" << '\n' << wd.iname << "recurse=" << recurse; + if (!recurse) { + // No further recursion at this level, pretend entry is complete + // to the watchmodel for the parent to show (only remaining watchhandler-specific + // part here). + if (wd.isChildrenNeeded()) { + wd.setHasChildren(true); + wd.setChildrenUnneeded(); + } + if (debugSgRecursion) + qDebug() << " INSERTING non-recursive: " << wd.toString(); + *it = wd; + ++it; + return true; + } + // Recursion: Indicate children unneeded + wd.setHasChildren(true); + wd.setChildrenUnneeded(); + if (debugSgRecursion) + qDebug() << " INSERTING recursive: " << wd.toString(); + *it = wd; + ++it; + // Recurse unless the predicate disagrees + if (ignorePredicate(wd)) + return true; + QList<WatchData> watchList; + // This implicitly enforces expansion + if (!sg->getChildSymbols(wd.iname, WatchDataBackInserter(watchList), errorMessage)) + return false; + const int childCount = watchList.size(); + for (int c = 0; c < childCount; c++) { + const WatchData &cwd = watchList.at(c); + if (wd.isValid()) { // We sometimes get empty names for deeply nested data + if (!insertSymbolRecursion(cwd, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + return false; + } else { + const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'."). + arg(QLatin1String(Q_FUNC_INFO)).arg(c).arg(cwd.type, wd.iname); + qWarning("%s\n", qPrintable(msg)); + } + } + return true; +} + +template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> +bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, + OutputIterator it, + RecursionPredicate recursionPredicate, + IgnorePredicate ignorePredicate, + QString *errorMessage) +{ + if (debugSgRecursion) + qDebug() << "### CdbSymbolGroupContext::populateModelInitially"; + + // Insert root items + QList<WatchData> watchList; + if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage)) + return false; + // Insert data + foreach(const WatchData &wd, watchList) + if (!insertSymbolRecursion(wd, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + return false; + return true; +} + +template <class OutputIterator, class RecursionPredicate, class IgnorePredicate> +bool CdbSymbolGroupContext::completeData(CdbSymbolGroupContext *sg, + WatchData incompleteLocal, + OutputIterator it, + RecursionPredicate recursionPredicate, + IgnorePredicate ignorePredicate, + QString *errorMessage) +{ + if (debugSgRecursion) + qDebug().nospace() << "###>CdbSymbolGroupContext::completeData" << ' ' << incompleteLocal.iname << '\n'; + // If the symbols are already expanded in the context, they will be re-inserted, + // which is not handled for simplicity. + if (!insertSymbolRecursion(incompleteLocal, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + return false; + return true; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbwatchmodels.cpp b/src/plugins/debugger/cdb/cdbwatchmodels.cpp deleted file mode 100644 index 0f5bb70846f..00000000000 --- a/src/plugins/debugger/cdb/cdbwatchmodels.cpp +++ /dev/null @@ -1,477 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** -**************************************************************************/ - -#include "cdbwatchmodels.h" -#include "cdbdumperhelper.h" -#include "cdbsymbolgroupcontext.h" -#include "cdbdebugengine.h" -#include "watchutils.h" -#include "debuggeractions.h" - -#include <QtCore/QDebug> -#include <QtCore/QList> -#include <QtCore/QCoreApplication> -#include <QtCore/QRegExp> - -enum { debugCDBWatchHandling = 0 }; - -namespace Debugger { -namespace Internal { - -enum { LocalsOwnerSymbolGroup, LocalsOwnerDumper }; - -static inline QString msgNoStackFrame() -{ - return QCoreApplication::translate("CdbWatchModels", "No active stack frame present."); -} - -static inline QString msgUnknown() -{ - return QCoreApplication::translate("CdbWatchModels", "<Unknown>"); -} - -// Helper to add a sequence of WatchData from the symbol group context to an item -// without using dumpers. - -class SymbolGroupInserter -{ -public: - explicit SymbolGroupInserter(WatchItem *parent) : m_parent(parent) {} - - inline SymbolGroupInserter& operator*() { return *this; } - inline SymbolGroupInserter&operator=(const WatchData &wd) { - WatchItem *item = new WatchItem(wd); - item->source = LocalsOwnerSymbolGroup; - m_parent->addChild(item); - return *this; - } - inline SymbolGroupInserter&operator++() { return *this; } - -private: - WatchItem *m_parent; -}; - -// fixDumperResult: When querying an item, the queried item is sometimes returned in -// incomplete form. Take over values from source, set items with missing addresses to -// "complete". -static inline void fixDumperResult(const WatchData &source, - QList<WatchData> *result) -{ - if (debugCDBWatchHandling > 1) { - qDebug() << "fixDumperResult for : " << source.toString(); - foreach (const WatchData &wd, *result) - qDebug() << " " << wd.toString(); - } - const int size = result->size(); - if (!size) - return; - WatchData &returned = result->front(); - if (returned.iname != source.iname) - return; - if (returned.type.isEmpty()) - returned.setType(source.type); - if (returned.isValueNeeded()) { - if (source.isValueKnown()) { - returned.setValue(source.value); - } else { - // Should not happen - returned.setValue(msgUnknown()); - qWarning("%s: No value for %s\n", Q_FUNC_INFO, qPrintable(returned.toString())); - } - } - if (size == 1) - return; - // Fix the children: If the address is missing, we cannot query any further. - const QList<WatchData>::iterator wend = result->end(); - QList<WatchData>::iterator it = result->begin(); - for (++it; it != wend; ++it) { - WatchData &wd = *it; - if (wd.addr.isEmpty() && wd.isSomethingNeeded()) { - wd.setAllUnneeded(); - } - } -} - -// Dump an item. If *ptrToDumpedItem == 0, allocate a new item and set it. -// If it is non-null, the item pointed to will receive the results -// ("complete" functionality). -static CdbDumperHelper::DumpResult - dumpItem(const QSharedPointer<CdbDumperHelper> dumper, - const WatchData &wd, - WatchItem **ptrToDumpedItem, - int dumperOwnerValue, QString *errorMessage) -{ - QList<WatchData> dumperResult; - WatchItem *dumpedItem = *ptrToDumpedItem; - const CdbDumperHelper::DumpResult rc = dumper->dumpType(wd, true, dumperOwnerValue, &dumperResult, errorMessage); - if (debugCDBWatchHandling > 1) - qDebug() << "dumper for " << wd.type << " returns " << rc; - - switch (rc) { - case CdbDumperHelper::DumpError: - return rc; - case CdbDumperHelper::DumpNotHandled: - errorMessage->clear(); - return rc; - case CdbDumperHelper::DumpOk: - break; - } - // Dumpers omit types for complicated templates - fixDumperResult(wd, &dumperResult); - // Discard the original item and insert the dumper results - if (dumpedItem) { - dumpedItem->setData(dumperResult.front()); - } else { - dumpedItem = new WatchItem(dumperResult.front()); - *ptrToDumpedItem = dumpedItem; - } - dumperResult.pop_front(); - foreach(const WatchData &dwd, dumperResult) - dumpedItem->addChild(new WatchItem(dwd)); - return rc; -} - -// Is this a non-null pointer to a dumpeable item with a value -// "0x4343 class QString *" ? - Insert a fake '*' dereferenced item -// and run dumpers on it. If that succeeds, insert the fake items owned by dumpers, -// Note that the symbol context does not create '*' dereferenced items for -// classes (see note in its header documentation). -static bool expandPointerToDumpable(const QSharedPointer<CdbDumperHelper> dumper, - const WatchData &wd, - WatchItem *parent, - QString *errorMessage) -{ - - - if (debugCDBWatchHandling > 1) - qDebug() << ">expandPointerToDumpable" << wd.iname; - - WatchItem *derefedWdItem = 0; - WatchItem *ptrWd = 0; - bool handled = false; - do { - if (!isPointerType(wd.type)) - break; - const int classPos = wd.value.indexOf(" class "); - if (classPos == -1) - break; - const QString hexAddrS = wd.value.mid(0, classPos); - static const QRegExp hexNullPattern(QLatin1String("0x0+")); - Q_ASSERT(hexNullPattern.isValid()); - if (hexNullPattern.exactMatch(hexAddrS)) - break; - const QString type = stripPointerType(wd.value.mid(classPos + 7)); - WatchData derefedWd; - derefedWd.setType(type); - derefedWd.setAddress(hexAddrS); - derefedWd.name = QString(QLatin1Char('*')); - derefedWd.iname = wd.iname + QLatin1String(".*"); - derefedWd.source = LocalsOwnerDumper; - QList<WatchData> dumperResult; - const CdbDumperHelper::DumpResult dr = dumpItem(dumper, derefedWd, &derefedWdItem, LocalsOwnerDumper, errorMessage); - if (dr != CdbDumperHelper::DumpOk) - break; - // Insert the pointer item with 1 additional child + its dumper results - // Note: formal arguments might already be expanded in the symbol group. - ptrWd = new WatchItem(wd); - ptrWd->source = LocalsOwnerDumper; - ptrWd->setHasChildren(true); - ptrWd->setChildrenUnneeded(); - ptrWd->addChild(derefedWdItem); - parent->addChild(ptrWd); - handled = true; - } while (false); - if (!handled) { - delete derefedWdItem; - delete ptrWd; - } - if (debugCDBWatchHandling > 1) - qDebug() << "<expandPointerToDumpable returns " << handled << *errorMessage; - return handled; -} - -// Main routine for inserting an item from the symbol group using the dumpers -// where applicable. -static inline bool insertDumpedItem(const QSharedPointer<CdbDumperHelper> &dumper, - const WatchData &wd, - WatchItem *parent, - QString *errorMessage) -{ - if (debugCDBWatchHandling > 1) - qDebug() << "insertItem=" << wd.toString(); - // Check pointer to dumpeable, dumpeable, insert accordingly. - if (expandPointerToDumpable(dumper, wd, parent, errorMessage)) - return true; - WatchItem *dumpedItem = 0; - // Add item owned by Dumper or symbol group on failure. - const CdbDumperHelper::DumpResult dr = dumpItem(dumper, wd, &dumpedItem, LocalsOwnerDumper, errorMessage); - switch (dr) { - case CdbDumperHelper::DumpOk: - dumpedItem->parent = parent; - parent->children.push_back(dumpedItem); - break; - case CdbDumperHelper::DumpNotHandled: - case CdbDumperHelper::DumpError: { - WatchItem *symbolItem = new WatchItem(wd); - symbolItem->source = LocalsOwnerSymbolGroup; - parent->addChild(symbolItem); - } - break; - } - return true; -} - -// Helper to add a sequence of WatchData from the symbol group context to an item. -// Checks if the item is dumpable in some way; if so, dump it and use that instead of -// symbol group. -class SymbolGroupDumperInserter -{ -public: - explicit SymbolGroupDumperInserter(const QSharedPointer<CdbDumperHelper> &dumper, - WatchItem *parent, - QString *errorMessage); - - inline SymbolGroupDumperInserter& operator*() { return *this; } - inline SymbolGroupDumperInserter&operator=(const WatchData &wd) { - insertDumpedItem(m_dumper, wd, m_parent, m_errorMessage); - return *this; - } - inline SymbolGroupDumperInserter&operator++() { return *this; } - -private: - const QSharedPointer<CdbDumperHelper> m_dumper; - WatchItem *m_parent; - QString *m_errorMessage; -}; - -SymbolGroupDumperInserter::SymbolGroupDumperInserter(const QSharedPointer<CdbDumperHelper> &dumper, - WatchItem *parent, - QString *errorMessage) : - m_dumper(dumper), - m_parent(parent), - m_errorMessage(errorMessage) -{ -} - -// -------------- CdbLocalsModel - -CdbLocalsModel::CdbLocalsModel(const QSharedPointer<CdbDumperHelper> &dh, - WatchHandler *handler, WatchType type, QObject *parent) : - AbstractSyncWatchModel(handler, type, parent), - m_dumperHelper(dh), - m_symbolGroupContext(0), - m_useDumpers(false) -{ -} - -CdbLocalsModel::~CdbLocalsModel() -{ -} - -bool CdbLocalsModel::fetchChildren(WatchItem *wd, QString *errorMessage) -{ - if (!m_symbolGroupContext) { - *errorMessage = msgNoStackFrame(); - return false; - } - if (debugCDBWatchHandling) - qDebug() << "fetchChildren" << wd->iname; - - // Check the owner and call it to expand the item. - switch (wd->source) { - case LocalsOwnerSymbolGroup: - if (m_useDumpers && m_dumperHelper->isEnabled()) { - SymbolGroupDumperInserter inserter(m_dumperHelper, wd, errorMessage); - return m_symbolGroupContext->getChildSymbols(wd->iname, inserter, errorMessage); - } else { - return m_symbolGroupContext->getChildSymbols(wd->iname, SymbolGroupInserter(wd), errorMessage); - } - break; - case LocalsOwnerDumper: - if (dumpItem(m_dumperHelper, *wd, &wd, LocalsOwnerDumper, errorMessage) == CdbDumperHelper::DumpOk) - return true; - if (wd->isValueNeeded()) - wd->setValue(msgUnknown()); - qWarning("%s: No value for %s\n", Q_FUNC_INFO, qPrintable(wd->toString())); - return false; - } - return false; -} - -bool CdbLocalsModel::complete(WatchItem *wd, QString *errorMessage) -{ - if (!m_symbolGroupContext) { - *errorMessage = msgNoStackFrame(); - return false; - } - if (debugCDBWatchHandling) - qDebug() << "complete" << wd->iname; - // Might as well fetch children when completing a dumped item. - return fetchChildren(wd, errorMessage); -} - -void CdbLocalsModel::setSymbolGroupContext(CdbSymbolGroupContext *s) -{ - if (s == m_symbolGroupContext) - return; - if (debugCDBWatchHandling) - qDebug() << ">setSymbolGroupContext" << s; - m_symbolGroupContext = s; - reinitialize(); - if (!m_symbolGroupContext) - return; - // Populate first row - WatchItem *item = dummyRoot(); - QString errorMessage; - do { - if (m_useDumpers && m_dumperHelper->isEnabled()) { - SymbolGroupDumperInserter inserter(m_dumperHelper, item, &errorMessage); - if (!m_symbolGroupContext->getChildSymbols(m_symbolGroupContext->prefix(), inserter, &errorMessage)) { - break; - } - } else { - if (!m_symbolGroupContext->getChildSymbols(m_symbolGroupContext->prefix(), SymbolGroupInserter(item), &errorMessage)) - break; - } - if (item->children.empty()) - break; - reset(); - } while (false); - if (!errorMessage.isEmpty()) - emit error(errorMessage); - if (debugCDBWatchHandling) - qDebug() << "<setSymbolGroupContext" << item->children.size() << errorMessage; - if (debugCDBWatchHandling > 1) - qDebug() << '\n' << *this; -} - -// ---- CdbWatchModel - -enum { WatchOwnerNewItem, WatchOwnerExpression, WatchOwnerDumper }; - -CdbWatchModel::CdbWatchModel(CdbDebugEngine *engine, - const QSharedPointer<CdbDumperHelper> &dh, - WatchHandler *handler, - WatchType type, QObject *parent) : - AbstractSyncWatchModel(handler, type, parent), - m_dumperHelper(dh), - m_engine(engine) -{ -} - -CdbWatchModel::~CdbWatchModel() -{ -} - -bool CdbWatchModel::evaluateWatchExpression(WatchData *wd, QString *errorMessage) -{ - QString value; - QString type; - - const bool rc = m_engine->evaluateExpression(wd->exp, &value, &type, errorMessage); - if (!rc) { - wd->setValue(msgUnknown()); - return false; - } - wd->setValue(value); - wd->setType(type); - return true; -} - -bool CdbWatchModel::fetchChildren(WatchItem *wd, QString *errorMessage) -{ - if (debugCDBWatchHandling) - qDebug() << "Watch:fetchChildren" << wd->iname << wd->source; - // We need to be halted. - if (!m_engine->isDebuggeeHalted()) { - *errorMessage = QCoreApplication::translate("CdbWatchModels", "Can evaluates watches only in halted state."); - wd->setValue(msgUnknown()); - return false; - } - // New item with address -> dumper. - if (wd->source == WatchOwnerNewItem) - wd->source = wd->addr.isEmpty() ? WatchOwnerExpression : WatchOwnerDumper; - // Expressions - if (wd->source == WatchOwnerExpression) - return evaluateWatchExpression(wd, errorMessage); - // Variables by address - if (!m_dumperHelper->isEnabled() || !theDebuggerBoolSetting(UseDebuggingHelpers)) { - *errorMessage = QCoreApplication::translate("CdbWatchModels", "Cannot evaluate '%1' due to dumpers being disabled.").arg(wd->name); - return false; - } - return dumpItem(m_dumperHelper, *wd, &wd, WatchOwnerDumper, errorMessage) == CdbDumperHelper::DumpOk; -} - -bool CdbWatchModel::complete(WatchItem *wd, QString *errorMessage) -{ - return fetchChildren(wd, errorMessage); -} - -void CdbWatchModel::addWatcher(const WatchData &wd) -{ - WatchItem *root = dummyRoot(); - if (!root) - return; - const QModelIndex rootIndex = watchIndex(root); - beginInsertRows(rootIndex, root->children.size(), root->children.size()); - root->addChild(new WatchItem(wd)); - endInsertRows(); -} - -void CdbWatchModel::refresh() -{ - // Refresh data for a new break - WatchItem *root = dummyRoot(); - if (!root) - return; - const int childCount = root->children.size(); - if (!childCount) - return; - // reset flags, if there children, trigger a reset - bool resetRequired = false; - for (int i = 0; i < childCount; i++) { - WatchItem *topLevel = root->children.at(i); - topLevel->setAllNeeded(); - if (!topLevel->children.empty()) { - topLevel->removeChildren(); - resetRequired = true; - } - } - // notify model - if (resetRequired) { - reset(); - } else { - const QModelIndex topLeft = watchIndex(root->children.front()); - const QModelIndex bottomLeft = root->children.size() == 1 ? topLeft : watchIndex(root->children.back()); - emit dataChanged(topLeft.sibling(0, 1), bottomLeft.sibling(0, columnCount() -1)); - } -} - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbwatchmodels.h b/src/plugins/debugger/cdb/cdbwatchmodels.h deleted file mode 100644 index 29c8be80505..00000000000 --- a/src/plugins/debugger/cdb/cdbwatchmodels.h +++ /dev/null @@ -1,96 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** -**************************************************************************/ - -#ifndef CDBWATCHMODELS_H -#define CDBWATCHMODELS_H - -#include "abstractsyncwatchmodel.h" -#include <QtCore/QSharedPointer> - -namespace Debugger { -namespace Internal { - -class CdbSymbolGroupContext; -class CdbDumperHelper; -class CdbDebugEngine; - -class CdbLocalsModel : public AbstractSyncWatchModel { - Q_DISABLE_COPY(CdbLocalsModel) - Q_OBJECT -public: - explicit CdbLocalsModel(const QSharedPointer<CdbDumperHelper> &dh, - WatchHandler *handler, WatchType type, QObject *parent = 0); - ~CdbLocalsModel(); - - // Set a symbolgroup context, thus activating a stack frame. - // Set 0 to clear out. - void setSymbolGroupContext(CdbSymbolGroupContext *sg = 0); - CdbSymbolGroupContext *symbolGroupContext() const { return m_symbolGroupContext; } - - void setUseDumpers(bool d) { m_useDumpers = d; } - -protected: - virtual bool fetchChildren(WatchItem *wd, QString *errorMessage); - virtual bool complete(WatchItem *wd, QString *errorMessage); - -private: - const QSharedPointer<CdbDumperHelper> m_dumperHelper; - CdbSymbolGroupContext *m_symbolGroupContext; - bool m_useDumpers; -}; - -class CdbWatchModel : public AbstractSyncWatchModel { - Q_DISABLE_COPY(CdbWatchModel) - Q_OBJECT -public: - explicit CdbWatchModel(CdbDebugEngine *engine, - const QSharedPointer<CdbDumperHelper> &dh, - WatchHandler *handler, - WatchType type, QObject *parent = 0); - ~CdbWatchModel(); - -public slots: - void addWatcher(const WatchData &d); - void refresh(); - -protected: - virtual bool fetchChildren(WatchItem *wd, QString *errorMessage); - virtual bool complete(WatchItem *wd, QString *errorMessage); - -private: - bool evaluateWatchExpression(WatchData *wd, QString *errorMessage); - - const QSharedPointer<CdbDumperHelper> m_dumperHelper; - CdbDebugEngine *m_engine; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // CDBWATCHMODELS_H diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index c74dcdd01f4..25b7c355f07 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -44,8 +44,6 @@ HEADERS += \ sourcefileswindow.h \ threadswindow.h \ watchhandler.h \ - asyncwatchmodel.h \ - abstractsyncwatchmodel.h \ watchwindow.h \ SOURCES += \ @@ -73,8 +71,6 @@ SOURCES += \ sourcefileswindow.cpp \ threadswindow.cpp \ watchhandler.cpp \ - asyncwatchmodel.cpp \ - abstractsyncwatchmodel.cpp \ watchwindow.cpp \ FORMS += attachexternaldialog.ui \ diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 67a9d93efbe..15c586b5bba 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -187,8 +187,7 @@ static IDebuggerEngine *tcfEngine = 0; DebuggerManager::DebuggerManager() : m_startParameters(new DebuggerStartParameters), - m_inferiorPid(0), - m_watchHandler(new WatchHandler) + m_inferiorPid(0) { init(); } @@ -232,8 +231,6 @@ void DebuggerManager::init() m_sourceFilesWindow = new SourceFilesWindow; m_threadsWindow = new ThreadsWindow; m_localsWindow = new WatchWindow(WatchWindow::LocalsType); - m_watchHandler->init(m_localsWindow); - m_watchersWindow = new WatchWindow(WatchWindow::WatchersType); //m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType); m_statusTimer = new QTimer(this); @@ -324,7 +321,14 @@ void DebuggerManager::init() m_registerHandler = new RegisterHandler; registerView->setModel(m_registerHandler->model()); - // Locals/Watchers + // Locals + m_watchHandler = new WatchHandler; + QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow); + localsView->setModel(m_watchHandler->model(LocalsWatch)); + + // Watchers + QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow); + 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)), @@ -333,6 +337,12 @@ void DebuggerManager::init() this, SLOT(assignValueInDebugger()), Qt::QueuedConnection); // Tooltip + //QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow); + //tooltipView->setModel(m_watchHandler->model(TooltipsWatch)); + + connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), + this, SLOT(updateWatchData(WatchData))); + m_continueAction = new QAction(this); m_continueAction->setText(tr("Continue")); m_continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png")); @@ -461,34 +471,12 @@ void DebuggerManager::init() localsAndWatchers->setStretchFactor(2, 1); m_watchDock = createDockForWidget(localsAndWatchers); - initializeWatchModels(gdbEngine); - setStatus(DebuggerProcessNotReady); } -void DebuggerManager::initializeWatchModels(IDebuggerEngine *engine) -{ - if (engine == 0) - return; - WatchModel *localsModel = engine->watchModel(LocalsWatch); - m_watchHandler->setModel(LocalsWatch, localsModel); - m_localsWindow->setModel(localsModel); - - WatchModel *watchModel = engine->watchModel(WatchersWatch); - m_watchHandler->setModel(WatchersWatch, watchModel); - m_watchersWindow->setModel(watchModel); - - if (WatchModel *toolTipModel = engine->watchModel(TooltipsWatch)) { - m_watchHandler->setModel(TooltipsWatch, toolTipModel); - } else { - m_watchHandler->setModel(TooltipsWatch, 0); - } -} - QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTypeFlags) { QList<Core::IOptionsPage*> rc; - // Initialize watch models so columns show up initially. if (enabledTypeFlags & GdbEngineType) gdbEngine = createGdbEngine(this, &rc); winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc); @@ -499,12 +487,6 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTy m_engine = 0; if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine << rc.size(); - if (gdbEngine) { - initializeWatchModels(gdbEngine); - } else { - if (winEngine) - initializeWatchModels(winEngine); - } return rc; } @@ -820,6 +802,12 @@ void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::I m_engine->setToolTipExpression(mousePos, editor, cursorPos); } +void DebuggerManager::updateWatchData(const WatchData &data) +{ + if (m_engine) + m_engine->updateWatchData(data); +} + QVariant DebuggerManager::sessionValue(const QString &name) { // this is answered by the plugin @@ -874,7 +862,7 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable, return scriptEngine; } -#ifndef Q_OS_WIN +#ifndef Q_OS_WIN Q_UNUSED(settingsIdHint) if (!gdbEngine) { *errorMessage = msgEngineNotAvailable("Gdb Engine"); @@ -955,7 +943,6 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl, break; } - if (!m_engine) { debuggingFinished(); // Create Message box with possibility to go to settings @@ -969,7 +956,6 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl, Core::ICore::instance()->showOptionsDialog(_(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint); return; } - initializeWatchModels(m_engine); if (Debugger::Constants::Internal::debug) qDebug() << m_startParameters->executable << m_engine; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 3dc8dcb16b9..c153465c884 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -46,7 +46,6 @@ class QModelIndex; class QPoint; class QTimer; class QWidget; -class QTreeView; class QDebug; QT_END_NAMESPACE @@ -308,6 +307,7 @@ public slots: void detachDebugger(); void addToWatchWindow(); + void updateWatchData(const WatchData &data); void sessionLoaded(); void sessionUnloaded(); @@ -418,7 +418,6 @@ public: private: void init(); void runTest(const QString &fileName); - void initializeWatchModels(IDebuggerEngine *engine); QDockWidget *createDockForWidget(QWidget *widget); Q_SLOT void createNewDock(QWidget *widget); void updateDockWidget(QDockWidget *dockWidget); @@ -484,12 +483,13 @@ private: QWidget *m_breakWindow; QWidget *m_disassemblerWindow; - QTreeView *m_localsWindow; + QWidget *m_localsWindow; QWidget *m_registerWindow; QWidget *m_modulesWindow; + //QWidget *m_tooltipWindow; QWidget *m_stackWindow; QWidget *m_threadsWindow; - QTreeView *m_watchersWindow; + QWidget *m_watchersWindow; DebuggerOutputWindow *m_outputWindow; int m_status; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 91fffde641a..e9bbb509566 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -46,7 +46,6 @@ #include "registerhandler.h" #include "stackhandler.h" #include "watchhandler.h" -#include "asyncwatchmodel.h" #include "sourcefileswindow.h" #include "debuggerdialogs.h" @@ -153,8 +152,7 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : m_dumperInjectionLoad(false), #endif q(parent), - qq(parent->engineInterface()), - m_models(qq->watchHandler()) + qq(parent->engineInterface()) { m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug); #ifdef Q_OS_UNIX @@ -172,8 +170,6 @@ GdbEngine::~GdbEngine() void GdbEngine::initializeConnections() { - connect(qq->watchHandler(), SIGNAL(watcherInserted(WatchData)), &m_models, SLOT(insertWatcher(WatchData))); - connect(&m_models, SIGNAL(watchDataUpdateNeeded(WatchData)), this, SLOT(updateWatchData(WatchData))); // Gdb Process interaction connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(gdbProcError(QProcess::ProcessError))); @@ -2700,10 +2696,10 @@ static QString tooltipINameForExpression(const QString &exp) bool GdbEngine::showToolTip() { WatchHandler *handler = qq->watchHandler(); - AsyncWatchModel *model = static_cast<AsyncWatchModel *>(handler->model(TooltipsWatch)); + WatchModel *model = handler->model(TooltipsWatch); QString iname = tooltipINameForExpression(m_toolTipExpression); model->setActiveData(iname); - WatchItem *item = model->findItemByIName(iname, model->dummyRoot()); + WatchItem *item = model->findItem(iname, model->dummyRoot()); if (!item) { hideDebuggerToolTip(); return false; @@ -2792,7 +2788,7 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos, toolTip.name = exp; toolTip.iname = tooltipINameForExpression(exp); qq->watchHandler()->removeData(toolTip.iname); - m_models.insertData(toolTip); + qq->watchHandler()->insertData(toolTip); } @@ -3150,7 +3146,7 @@ void GdbEngine::rebuildModel() PENDING_DEBUG("REBUILDING MODEL"); emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>")); q->showStatusMessage(tr("Finished retrieving data."), 400); - m_models.endCycle(); + qq->watchHandler()->endCycle(); showToolTip(); } @@ -3546,7 +3542,7 @@ void GdbEngine::updateLocals() PENDING_DEBUG("\nRESET PENDING"); //m_toolTipCache.clear(); m_toolTipExpression.clear(); - m_models.beginCycle(); + qq->watchHandler()->beginCycle(); QString level = QString::number(currentFrame()); // '2' is 'list with type and value' @@ -3600,7 +3596,7 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record, const QVari locals += m_currentFunctionArgs; setLocals(locals); - m_models.updateWatchers(); + qq->watchHandler()->updateWatchers(); } void GdbEngine::setLocals(const QList<GdbMi> &locals) @@ -3672,7 +3668,7 @@ void GdbEngine::insertData(const WatchData &data0) qDebug() << "BOGUS VALUE:" << data.toString(); return; } - m_models.insertData(data); + qq->watchHandler()->insertData(data); } void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 0ad6dc2e90b..41137705879 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -34,7 +34,6 @@ #include "gdbmi.h" #include "outputcollector.h" #include "watchutils.h" -#include "asyncwatchmodel.h" #include <consoleprocess.h> @@ -123,8 +122,6 @@ private: void loadAllSymbols(); virtual QList<Symbol> moduleSymbols(const QString &moduleName); - WatchModel *watchModel(int type) const { return m_models.model(type); } - Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on); @@ -200,7 +197,6 @@ private slots: void stubStarted(); void stubError(const QString &msg); void uploadProcError(QProcess::ProcessError error); - void updateWatchData(const WatchData &data); private: int terminationIndex(const QByteArray &buffer, int &length); @@ -328,6 +324,7 @@ private: // FIXME: BaseClass. called to improve situation for a watch item void updateSubItem(const WatchData &data); + void updateWatchData(const WatchData &data); void rebuildModel(); void insertData(const WatchData &data); @@ -387,7 +384,6 @@ private: DebuggerManager * const q; IDebuggerManagerAccessForEngines * const qq; - AsyncWatchModelMixin m_models; // make sure to re-initialize new members in initializeVariables(); }; diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index f99e26bd869..dbbdb143143 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -46,8 +46,6 @@ class ITextEditor; namespace Debugger { namespace Internal { -class WatchModel; - class Symbol; class WatchData; struct DebuggerStartParameters; @@ -62,13 +60,14 @@ public: virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0; virtual void exitDebugger() = 0; virtual void detachDebugger() {} + virtual void updateWatchData(const WatchData &data) = 0; virtual void stepExec() = 0; virtual void stepOutExec() = 0; virtual void nextExec() = 0; virtual void stepIExec() = 0; virtual void nextIExec() = 0; - + virtual void continueInferior() = 0; virtual void interruptInferior() = 0; @@ -96,8 +95,6 @@ public: virtual void reloadFullStack() = 0; virtual void watchPoint(const QPoint &) {} - - virtual WatchModel *watchModel(int type) const = 0; }; } // namespace Internal diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index 0096e3a414d..28d20a24cc2 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -185,13 +185,10 @@ void ScriptAgent::scriptUnload(qint64 scriptId) // /////////////////////////////////////////////////////////////////////// -ScriptEngine::ScriptEngine(DebuggerManager *parent) : - q(parent), - qq(parent->engineInterface()), - m_models(qq->watchHandler()) +ScriptEngine::ScriptEngine(DebuggerManager *parent) { - connect(qq->watchHandler(), SIGNAL(watcherInserted(WatchData)), &m_models, SLOT(insertWatcher(WatchData))); - connect(&m_models, SIGNAL(watchDataUpdateNeeded(WatchData)), this, SLOT(updateWatchData(WatchData))); + q = parent; + qq = parent->engineInterface(); m_scriptEngine = new QScriptEngine(this); m_scriptAgent = new ScriptAgent(this, m_scriptEngine); m_scriptEngine->setAgent(m_scriptAgent); @@ -575,7 +572,7 @@ void ScriptEngine::maybeBreakNow(bool byFunction) void ScriptEngine::updateLocals() { QScriptContext *context = m_scriptEngine->currentContext(); - m_models.beginCycle(); + qq->watchHandler()->beginCycle(); //SDEBUG("UPDATE LOCALS"); // @@ -607,7 +604,7 @@ void ScriptEngine::updateLocals() data.iname = "local"; data.name = "local"; data.scriptValue = context->activationObject(); - m_models.insertData(data); + qq->watchHandler()->insertData(data); // FIXME: Use an extra thread. This here is evil m_stopped = true; @@ -682,7 +679,7 @@ void ScriptEngine::updateSubItem(const WatchData &data0) data.setType("<unknown>"); data.setValue("<unknown>"); } - m_models.insertData(data); + qq->watchHandler()->insertData(data); return; } @@ -700,13 +697,13 @@ void ScriptEngine::updateSubItem(const WatchData &data0) data1.setChildrenNeeded(); else data1.setChildrenUnneeded(); - m_models.insertData(data1); + qq->watchHandler()->insertData(data1); ++numChild; } //SDEBUG(" ... CHILDREN: " << numChild); data.setHasChildren(numChild > 0); data.setChildrenUnneeded(); - m_models.insertData(data); + qq->watchHandler()->insertData(data); return; } @@ -719,7 +716,7 @@ void ScriptEngine::updateSubItem(const WatchData &data0) } data.setHasChildren(numChild > 0); //SDEBUG(" ... CHILDCOUNT: " << numChild); - m_models.insertData(data); + qq->watchHandler()->insertData(data); return; } diff --git a/src/plugins/debugger/script/scriptengine.h b/src/plugins/debugger/script/scriptengine.h index bd49d0e1ef1..ae4a434efc0 100644 --- a/src/plugins/debugger/script/scriptengine.h +++ b/src/plugins/debugger/script/scriptengine.h @@ -49,7 +49,6 @@ class QScriptValue; QT_END_NAMESPACE #include "idebuggerengine.h" -#include "asyncwatchmodel.h" namespace Debugger { namespace Internal { @@ -108,20 +107,14 @@ private: bool supportsThreads() const { return true; } void maybeBreakNow(bool byFunction); - + void updateWatchData(const WatchData &data); void updateLocals(); void updateSubItem(const WatchData &data); - WatchModel *watchModel(int type) const { return m_models.model(type); } - -private slots: - void updateWatchData(const WatchData &data); - private: friend class ScriptAgent; DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; - AsyncWatchModelMixin m_models; QScriptEngine *m_scriptEngine; QString m_scriptContents; diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp index 756f0d80289..b699f40954a 100644 --- a/src/plugins/debugger/tcf/tcfengine.cpp +++ b/src/plugins/debugger/tcf/tcfengine.cpp @@ -112,13 +112,11 @@ QString TcfEngine::TcfCommand::toString() const // /////////////////////////////////////////////////////////////////////// -TcfEngine::TcfEngine(DebuggerManager *parent) : - q(parent), - qq(parent->engineInterface()), - m_models(qq->watchHandler()) +TcfEngine::TcfEngine(DebuggerManager *parent) { - connect(qq->watchHandler(), SIGNAL(watcherInserted(WatchData)), &m_models, SLOT(insertWatcher(WatchData))); - connect(&m_models, SIGNAL(watchDataUpdateNeeded(WatchData)), this, SLOT(updateWatchData(WatchData))); + q = parent; + qq = parent->engineInterface(); + m_congestion = 0; m_inAir = 0; diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h index e09097df959..ff5844c436b 100644 --- a/src/plugins/debugger/tcf/tcfengine.h +++ b/src/plugins/debugger/tcf/tcfengine.h @@ -30,8 +30,6 @@ #ifndef DEBUGGER_TCFENGINE_H #define DEBUGGER_TCFENGINE_H -#include "asyncwatchmodel.h" - #include <QtCore/QByteArray> #include <QtCore/QHash> #include <QtCore/QMap> @@ -114,11 +112,10 @@ private: bool supportsThreads() const { return true; } void maybeBreakNow(bool byFunction); + void updateWatchData(const WatchData &data); void updateLocals(); void updateSubItem(const WatchData &data); - WatchModel *watchModel(int type) const { return m_models.model(type); } - Q_SLOT void socketConnected(); Q_SLOT void socketDisconnected(); Q_SLOT void socketError(QAbstractSocket::SocketError); @@ -131,7 +128,6 @@ private: private: Q_SLOT void startDebugging(); - Q_SLOT void updateWatchData(const WatchData &data); typedef void (TcfEngine::*TcfCommandCallback) (const JsonValue &record, const QVariant &cookie); @@ -157,7 +153,7 @@ private: QHash<int, TcfCommand> m_cookieForToken; QQueue<TcfCommand> m_sendQueue; - + // timer based congestion control. does not seem to work well. void enqueueCommand(const TcfCommand &command); Q_SLOT void handleSendTimer(); @@ -170,7 +166,6 @@ private: DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; - AsyncWatchModelMixin m_models; QTcpSocket *m_socket; QByteArray m_inbuffer; QList<QByteArray> m_services; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index c33f8bcc486..bad769c7dbb 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -48,7 +48,6 @@ #include <QtGui/QLabel> #include <QtGui/QToolTip> #include <QtGui/QTextEdit> -#include <QtGui/QTreeView> #include <ctype.h> @@ -68,13 +67,40 @@ namespace Debugger { namespace Internal { +static const QString strNotInScope = + QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>"); + static int watcherCounter = 0; +static int generationCounter = 0; + //////////////////////////////////////////////////////////////////// // -// WatchData +// WatchItem // //////////////////////////////////////////////////////////////////// +class WatchItem : public WatchData +{ +public: + WatchItem() { parent = 0; fetchTriggered = false; } + + WatchItem(const WatchData &data) : WatchData(data) + { parent = 0; fetchTriggered = false; } + + void setData(const WatchData &data) + { static_cast<WatchData &>(*this) = data; } + + WatchItem *parent; + bool fetchTriggered; // children fetch has been triggered + QList<WatchItem *> children; // fetched children +}; + +//////////////////////////////////////////////////////////////////// +// +// WatchData +// +//////////////////////////////////////////////////////////////////// + WatchData::WatchData() : hasChildren(false), generation(-1), @@ -122,7 +148,7 @@ void WatchData::setValue(const QString &value0) // column. No need to duplicate it here. if (value.startsWith("(" + type + ") 0x")) value = value.section(" ", -1, -1); - + setValueUnneeded(); } @@ -246,125 +272,109 @@ QString WatchData::toToolTip() const return res; } -//////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// // -// WatchItem +// WatchModel // -//////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////// -WatchItem::WatchItem() : - parent(0), - fetchTriggered(false) +WatchModel::WatchModel(WatchHandler *handler, WatchType type) + : QAbstractItemModel(handler), m_handler(handler), m_type(type) { -} + m_root = new WatchItem; + m_root->hasChildren = 1; + m_root->state = 0; + m_root->name = WatchHandler::tr("Root"); -WatchItem::WatchItem(const WatchData &data) : - WatchData(data), - parent(0), - fetchTriggered(false) -{ -} + WatchItem *item = new WatchItem; -void WatchItem::setData(const WatchData &data) -{ - static_cast<WatchData &>(*this) = data; -} + 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->hasChildren = true; + item->state = 0; + item->parent = m_root; + item->fetchTriggered = true; -WatchItem::~WatchItem() -{ - qDeleteAll(children); + m_root->children.append(item); } -void WatchItem::removeChildren() +WatchItem *WatchModel::dummyRoot() const { - if (!children.empty()) { - qDeleteAll(children); - children.clear(); - } + QTC_ASSERT(!m_root->children.isEmpty(), return 0); + return m_root->children.front(); } -void WatchItem::addChild(WatchItem *child) +void WatchModel::reinitialize() { - children.push_back(child); - child->parent = this; + 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(); } -/////////////////////////////////////////////////////////////////////// -// -// WatchPredicate -// -/////////////////////////////////////////////////////////////////////// - -WatchPredicate::WatchPredicate(Mode mode, const QString &pattern) : - m_pattern(pattern), - m_mode(mode) +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 } -bool WatchPredicate::operator()(const WatchData &w) const +void WatchModel::removeOutdatedHelper(WatchItem *item) { - switch (m_mode) { - case INameMatch: - return m_pattern == w.iname; - case ExpressionMatch: - return m_pattern == w.exp; + if (item->generation < generationCounter) + removeItem(item); + else { + foreach (WatchItem *child, item->children) + removeOutdatedHelper(child); + item->fetchTriggered = false; } - return false; -} - -/////////////////////////////////////////////////////////////////////// -// -// WatchModel -// -/////////////////////////////////////////////////////////////////////// - -WatchModel::WatchModel(WatchHandler *handler, WatchType type, QObject *parent) : - QAbstractItemModel(parent), - m_root(new WatchItem), - m_handler(handler), - m_type(type) -{ - WatchItem *dummyRoot = new WatchItem; - - switch (type) { - case LocalsWatch: - dummyRoot->iname = QLatin1String("local"); - dummyRoot->name = WatchHandler::tr("Locals"); - break; - case WatchersWatch: - dummyRoot->iname = QLatin1String("watch"); - dummyRoot->name = WatchHandler::tr("Watchers"); - break; - case TooltipsWatch: - dummyRoot->iname = QLatin1String("tooltip"); - dummyRoot->name = WatchHandler::tr("Tooltip"); - break; - case WatchModelCount: - break; - } - dummyRoot->hasChildren = true; - dummyRoot->state = 0; - - m_root->addChild(dummyRoot); - - m_root->hasChildren = 1; - m_root->state = 0; - m_root->name = WatchHandler::tr("Root"); } -WatchModel::~WatchModel() +void WatchModel::removeItem(WatchItem *item) { - delete m_root; + 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(); } -QString WatchModel::parentName(const QString &iname) +static QString parentName(const QString &iname) { - const int pos = iname.lastIndexOf(QLatin1Char('.')); + int pos = iname.lastIndexOf(QLatin1Char('.')); if (pos == -1) return QString(); return iname.left(pos); } + static QString chopConst(QString type) { while (1) { @@ -409,7 +419,7 @@ QString niceType(const QString typeIn) for (int i = 0; i < 10; ++i) { int start = type.indexOf("std::allocator<"); if (start == -1) - break; + break; // search for matching '>' int pos; int level = 0; @@ -517,10 +527,51 @@ static QString formattedValue(const WatchData &data, return data.value; } -int WatchModel::columnCount(const QModelIndex &idx) const +bool WatchModel::canFetchMore(const QModelIndex &index) const { - Q_UNUSED(idx); - return 3; + return index.isValid() && !watchItem(index)->fetchTriggered; +} + +void WatchModel::fetchMore(const QModelIndex &index) +{ + QTC_ASSERT(index.isValid(), return); + QTC_ASSERT(!watchItem(index)->fetchTriggered, return); + if (WatchItem *item = watchItem(index)) { + item->fetchTriggered = true; + 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); + + return QModelIndex(); } int WatchModel::rowCount(const QModelIndex &idx) const @@ -532,18 +583,45 @@ int WatchModel::rowCount(const QModelIndex &idx) const return watchItem(idx)->children.size(); } -bool WatchModel::hasChildren(const QModelIndex &idx) const +int WatchModel::columnCount(const QModelIndex &idx) const { - if (const WatchItem *item = watchItem(idx)) { - if (!item->children.empty()) - return true; - QTC_ASSERT(item->isHasChildrenKnown(), return false); - return item->hasChildren; + Q_UNUSED(idx); + return 3; +} + +bool WatchModel::hasChildren(const QModelIndex &parent) const +{ + WatchItem *item = watchItem(parent); + return !item || item->hasChildren; +} + +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 false; + return QModelIndex(); } -void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex) +void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex) { QModelIndex idx1 = index(0, column, parentIndex); QModelIndex idx2 = index(rowCount(parentIndex) - 1, column, parentIndex); @@ -557,16 +635,11 @@ void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex) QVariant WatchModel::data(const QModelIndex &idx, int role) const { - if (const WatchData *wdata = watchItem(idx)) - return data(*wdata, idx.column(), role); - return QVariant(); -} + const WatchItem &data = *watchItem(idx); -QVariant WatchModel::data(const WatchData &data, int column, int role) const -{ switch (role) { case Qt::DisplayRole: { - switch (column) { + switch (idx.column()) { case 0: return data.name; case 1: return formattedValue(data, m_handler->m_individualFormats[data.iname], @@ -584,7 +657,7 @@ QVariant WatchModel::data(const WatchData &data, int column, int role) const static const QVariant red(QColor(200, 0, 0)); static const QVariant black(QColor(0, 0, 0)); static const QVariant gray(QColor(140, 140, 140)); - switch (column) { + switch (idx.column()) { case 0: return black; case 1: return data.valuedisabled ? gray : data.changed ? red : black; case 2: return black; @@ -605,7 +678,7 @@ QVariant WatchModel::data(const WatchData &data, int column, int role) const case ActiveDataRole: qDebug() << "ASK FOR" << data.iname; return true; - + case TypeFormatListRole: if (isIntType(data.type)) return QStringList() << tr("decimal") << tr("hexadecimal") @@ -623,14 +696,14 @@ QVariant WatchModel::data(const WatchData &data, int column, int role) const } default: - break; + break; } return QVariant(); } bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role) { - WatchData &data = *watchItem(index); + WatchItem &data = *watchItem(index); if (role == ExpandedRole) { if (value.toBool()) m_handler->m_expandedINames.insert(data.iname); @@ -687,162 +760,75 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro case 2: return QString(tr("Type") + QLatin1String(" ")); } } - return QVariant(); -} - -void WatchModel::setValueByIName(const QString &iname, const QString &value) -{ - if (WatchItem *wd = findItemByIName(iname, dummyRoot())) { - if (wd->value != value) { - wd->setValue(value); - const QModelIndex index = watchIndex(wd); - emit dataChanged(index.sibling(0, 1), index.sibling(0, 2)); - } - } + return QVariant(); } -void WatchModel::setValueByExpression(const QString &exp, const QString &value) +static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) { - if (WatchItem *wd = findItemByExpression(exp, dummyRoot())) { - if (wd->value != value) { - wd->setValue(value); - const QModelIndex index = watchIndex(wd); - emit dataChanged(index.sibling(0, 1), index.sibling(0, 2)); - } + QString name1 = item1->iname.section('.', -1); + QString name2 = item2->iname.section('.', -1); + if (!name1.isEmpty() && !name2.isEmpty()) { + if (name1.at(0).isDigit() && name2.at(0).isDigit()) + return name1.toInt() < name2.toInt(); } + return name1 < name2; } -WatchItem *WatchModel::root() const +static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item) { - return m_root; + QList<WatchItem *>::const_iterator it = + qLowerBound(list.begin(), list.end(), item, iNameSorter); + return it - list.begin(); } -WatchItem *WatchModel::dummyRoot() const -{ - if (!m_root->children.isEmpty()) - return m_root->children.front(); - return 0; -} - -void WatchModel::reinitialize() +void WatchModel::insertData(const WatchData &data) { - WatchItem *item = dummyRoot(); - QTC_ASSERT(item, return); - const QModelIndex index = watchIndex(item); - const int n = item->children.size(); - if (n == 0) + // qDebug() << "WMI:" << data.toString(); + 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; - //MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << item->iname); - beginRemoveRows(index, 0, n - 1); - item->removeChildren(); - endRemoveRows(); -} - -void WatchModel::removeItem(WatchItem *itemIn) -{ - WatchItem *item = static_cast<WatchItem *>(itemIn); - WatchItem *parent = item->parent; - const QModelIndex index = watchIndex(parent); - const int n = parent->children.indexOf(item); - //MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n); - beginRemoveRows(index, n, n); - parent->children.removeAt(n); - endRemoveRows(); -} - -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 = static_cast<WatchItem *>(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); - - return QModelIndex(); -} - -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(); + 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 = findInsertPosition(parent->children, item); + beginInsertRows(index, n, n); + parent->children.insert(n, item); + endInsertRows(); + } } -static WatchItem *findRecursion(WatchItem *root, const WatchPredicate &p) +WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const { - if (p(*root)) + if (root->iname == iname) return root; for (int i = root->children.size(); --i >= 0; ) - if (WatchItem *item = findRecursion(root->children.at(i), p)) + if (WatchItem *item = findItem(iname, root->children.at(i))) return item; return 0; } -WatchItem *WatchModel::findItemByExpression(const QString &exp, WatchItem *root) const -{ - return findRecursion(root, WatchPredicate(WatchPredicate::ExpressionMatch, exp)); -} - -WatchItem *WatchModel::findItemByIName(const QString &iname, WatchItem *root) const -{ - return findRecursion(root, WatchPredicate(WatchPredicate::INameMatch, iname)); -} - -static void debugItemRecursion(QDebug d, WatchItem *item, QString indent = QString()) -{ - qDebug() << (indent + item->toString()); - if (!item->children.isEmpty()) { - indent += QLatin1String(" "); - foreach(WatchItem *c, item->children) - debugItemRecursion(d, c, indent); - } -} - -QDebug operator<<(QDebug d, const WatchModel &wm) -{ - if (WatchItem *root = wm.dummyRoot()) - debugItemRecursion(d.nospace(), root); - return d; -} /////////////////////////////////////////////////////////////////////// // @@ -850,25 +836,34 @@ QDebug operator<<(QDebug d, const WatchModel &wm) // /////////////////////////////////////////////////////////////////////// -WatchHandler::WatchHandler() : - m_expandPointers(true), - m_inChange(false) +WatchHandler::WatchHandler() { + 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())); - qFill(m_models, m_models + WatchModelCount, static_cast<WatchModel*>(0)); +} + +void WatchHandler::endCycle() +{ + m_locals->removeOutdated(); + m_watchers->removeOutdated(); + m_tooltips->removeOutdated(); } void WatchHandler::cleanup() { m_expandedINames.clear(); m_displayedINames.clear(); - if (m_models[LocalsWatch]) - m_models[LocalsWatch]->reinitialize(); - if (m_models[TooltipsWatch]) - m_models[TooltipsWatch]->reinitialize(); + m_locals->reinitialize(); + m_tooltips->reinitialize(); #if 0 for (EditWindows::ConstIterator it = m_editWindows.begin(); it != m_editWindows.end(); ++it) { @@ -879,12 +874,26 @@ void WatchHandler::cleanup() #endif } +void WatchHandler::insertData(const WatchData &data) +{ + MODEL_DEBUG("INSERTDATA: " << data.toString()); + QTC_ASSERT(data.isValid(), return); + if (data.isSomethingNeeded()) { + emit watchDataUpdateNeeded(data); + } else { + WatchModel *model = modelForIName(data.iname); + QTC_ASSERT(model, return); + model->insertData(data); + } +} + void WatchHandler::removeData(const QString &iname) { WatchModel *model = modelForIName(iname); if (!model) return; - if (WatchItem *item = model->findItemByIName(iname, model->root())) + WatchItem *item = model->findItem(iname, model->m_root); + if (item) model->removeItem(item); } @@ -909,7 +918,7 @@ void WatchHandler::watchExpression(const QString &exp) if (exp.isEmpty() || exp == watcherEditPlaceHolder()) data.setAllUnneeded(); data.iname = watcherName(exp); - emit watcherInserted(data); + insertData(data); saveWatchers(); //emit watchModelUpdateRequested(); } @@ -999,11 +1008,33 @@ void WatchHandler::removeWatchExpression(const QString &exp) { MODEL_DEBUG("REMOVE WATCH: " << exp); m_watcherNames.remove(exp); - if (WatchModel *model = m_models[WatchersWatch]) - if (WatchItem *item = model->findItemByExpression(exp, model->root())) { - model->removeItem(item); + foreach (WatchItem *item, m_watchers->dummyRoot()->children) { + if (item->exp == exp) { + m_watchers->removeItem(item); saveWatchers(); + break; } + } +} + +void WatchHandler::beginCycle() +{ + ++generationCounter; + //m_locals->beginCycle(); +} + +void WatchHandler::updateWatchers() +{ + //qDebug() << "UPDATE WATCHERS"; + // copy over all watchers and mark all watchers as incomplete + foreach (const QString &exp, m_watcherNames.keys()) { + WatchData data; + data.iname = watcherName(exp); + data.setAllNeeded(); + data.name = exp; + data.exp = exp; + insertData(data); + } } void WatchHandler::loadWatchers() @@ -1045,11 +1076,6 @@ void WatchHandler::loadTypeFormats() } } -QStringList WatchHandler::watcherExpressions() const -{ - return m_watcherNames.keys(); -} - void WatchHandler::saveTypeFormats() { QMap<QString, QVariant> typeFormats; @@ -1073,61 +1099,44 @@ void WatchHandler::loadSessionData() { loadWatchers(); loadTypeFormats(); - initWatchModel(); -} - -void WatchHandler::initWatchModel() -{ foreach (const QString &exp, m_watcherNames.keys()) { WatchData data; data.iname = watcherName(exp); data.setAllUnneeded(); data.name = exp; data.exp = exp; - emit watcherInserted(data); + insertData(data); } } WatchModel *WatchHandler::model(WatchType type) const { - return m_models[type]; -} - -void WatchHandler::setModel(WatchType type, WatchModel *model) -{ - if (m_models[type] == model) - return; - if (type == WatchersWatch && m_models[type]) - saveWatchers(); - m_models[type] = model; - if (type == WatchersWatch) - initWatchModel(); + switch (type) { + case LocalsWatch: return m_locals; + case WatchersWatch: return m_watchers; + case TooltipsWatch: return m_tooltips; + } + QTC_ASSERT(false, /**/); + return 0; } - -WatchType WatchHandler::watchTypeOfIName(const QString &iname) + +WatchModel *WatchHandler::modelForIName(const QString &iname) const { if (iname.startsWith(QLatin1String("local."))) - return LocalsWatch; + return m_locals; if (iname.startsWith(QLatin1String("watch."))) - return WatchersWatch; + return m_watchers; if (iname.startsWith(QLatin1String("tooltip"))) - return TooltipsWatch; - return WatchModelCount; -} - -WatchModel *WatchHandler::modelForIName(const QString &iname) const -{ - const WatchType t = watchTypeOfIName(iname); - if (t == WatchModelCount) - return 0; - return m_models[t]; + 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->findItemByIName(iname, model->root()); + return model->findItem(iname, model->m_root); } QString WatchHandler::watcherEditPlaceHolder() @@ -1140,55 +1149,9 @@ void WatchHandler::setFormat(const QString &type, int format) { m_typeFormats[type] = format; saveTypeFormats(); - for (int m = 0; m < WatchModelCount; m++) - m_models[m]->emitDataChanged(1); -} - -void WatchHandler::init(QTreeView *localsView) -{ - m_localsView = localsView; -} - -void WatchHandler::saveLocalsViewState(int frame) -{ - WatchModel *model = m_models[LocalsWatch]; - if (!model || !m_localsView) - return; - LocalsViewStateMap::iterator it = m_localsViewState.find(frame); - if (it == m_localsViewState.end()) - it = m_localsViewState.insert(frame, LocalsViewState()); - - const QModelIndex topIndex = m_localsView->indexAt(QPoint(0, 0)); - it.value().firstVisibleRow = topIndex.isValid() ? topIndex.row() : 0; - it.value().expandedINames = m_expandedINames; -} - -void WatchHandler::restoreLocalsViewState(int frame) -{ - WatchModel *model = m_models[LocalsWatch]; - if (!model || !m_localsView) - return; - int firstVisibleRow = 0; - const LocalsViewStateMap::const_iterator it = m_localsViewState.constFind(frame); - if (it != m_localsViewState.constEnd()) { - firstVisibleRow = it.value().firstVisibleRow; - m_expandedINames = it.value().expandedINames; - } - // Loop over and expand valid inames, purge out invalid. - WatchItem *root = model->root(); - for (QSet<QString>::iterator it = m_expandedINames.begin(); it != m_expandedINames.end(); ) { - if (const WatchItem *wd = model->findItemByIName(*it, root)) { - m_localsView->expand(model->watchIndex(wd)); - ++it; - } else { - it = m_expandedINames.erase(it); - } - } - if (firstVisibleRow) { - const QModelIndex index = model->index(0, 0).child(firstVisibleRow, 0); - if (index.isValid()) - m_localsView->scrollTo(index, QAbstractItemView::PositionAtTop); - } + m_locals->emitDataChanged(1); + m_watchers->emitDataChanged(1); + m_tooltips->emitDataChanged(1); } } // namespace Internal diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 4b472fab3f4..86e7dff3b07 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -32,21 +32,19 @@ #include <QtCore/QPointer> #include <QtCore/QObject> -#include <QtCore/QStringList> #include <QtCore/QHash> #include <QtCore/QSet> -#include <QtCore/QAbstractItemModel> +#include <QtGui/QStandardItem> +#include <QtGui/QStandardItemModel> +#include <QtGui/QTreeView> #include <QtScript/QScriptValue> -QT_BEGIN_NAMESPACE -class QTreeView; -QT_END_NAMESPACE - namespace Debugger { namespace Internal { +class WatchItem; class WatchHandler; -enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch, WatchModelCount }; +enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch }; class WatchData { @@ -162,95 +160,51 @@ enum DumpableFormat PlainFomat, }; -class WatchHandler; - -// Item used by the model. -class WatchItem : public WatchData -{ - Q_DISABLE_COPY(WatchItem) -public: - WatchItem(); - explicit WatchItem(const WatchData &data); - - ~WatchItem(); - - void setData(const WatchData &data); - void addChild(WatchItem *child); - void removeChildren(); - - WatchItem *parent; - bool fetchTriggered; - QList<WatchItem*> children; -}; - -/* WatchModel: To be used by synchonous debuggers. - * Implements all of WatchModel and provides new virtuals for - * the debugger to complete items. */ - class WatchModel : public QAbstractItemModel { Q_OBJECT -public: - explicit WatchModel(WatchHandler *handler, WatchType type, QObject *parent = 0); - virtual ~WatchModel(); - - virtual QModelIndex index(int, int, const QModelIndex &idx = QModelIndex()) const; - - virtual int columnCount(const QModelIndex &idx= QModelIndex()) const; - virtual int rowCount(const QModelIndex &idx) const; - virtual bool hasChildren(const QModelIndex &idx) const; - virtual QVariant data(const QModelIndex &index, int role) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role); - - virtual Qt::ItemFlags flags(const QModelIndex &idx) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - virtual QModelIndex parent(const QModelIndex &idx) const; +private: + explicit WatchModel(WatchHandler *handler, WatchType type); + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + QModelIndex index(int, int, const QModelIndex &idx) const; + QModelIndex parent(const QModelIndex &idx) const; + int rowCount(const QModelIndex &idx) const; + int columnCount(const QModelIndex &idx) const; + bool hasChildren(const QModelIndex &idx) const; + Qt::ItemFlags flags(const QModelIndex &idx) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + bool canFetchMore(const QModelIndex &parent) const; + void fetchMore(const QModelIndex &parent); + + friend class WatchHandler; + friend class GdbEngine; WatchItem *watchItem(const QModelIndex &) const; QModelIndex watchIndex(const WatchItem *needle) const; QModelIndex watchIndexHelper(const WatchItem *needle, const WatchItem *parentItem, const QModelIndex &parentIndex) const; - WatchItem *findItemByIName(const QString &iname, WatchItem *root) const; - WatchItem *findItemByExpression(const QString &iname, WatchItem *root) const; + void insertData(const WatchData &data); + WatchItem *findItem(const QString &iname, WatchItem *root) const; void reinitialize(); - - void removeItem(WatchItem *item); - WatchItem *root() const; - + void removeOutdated(); + void removeOutdatedHelper(WatchItem *item); WatchItem *dummyRoot() const; + void removeItem(WatchItem *item); + void setActiveData(const QString &data) { m_activeData = data; } - void setValueByIName(const QString &iname, const QString &value); - void setValueByExpression(const QString &iname, const QString &value); - - void emitDataChanged(int column, const QModelIndex &parentIndex = QModelIndex()); - -protected: - WatchHandler *handler() const { return m_handler; } - QVariant data(const WatchData &data, int column, int role) const; - - static QString parentName(const QString &iname); + void emitDataChanged(int column, + const QModelIndex &parentIndex = QModelIndex()); private: - WatchItem *m_root; WatchHandler *m_handler; - const WatchType m_type; -}; - -QDebug operator<<(QDebug d, const WatchModel &wm); - -/* A helper predicate for implementing model find routines */ -class WatchPredicate { -public: - enum Mode { INameMatch, ExpressionMatch }; - explicit WatchPredicate(Mode m, const QString &pattern); - bool operator()(const WatchData &w) const; - -private: - const QString &m_pattern; - const Mode m_mode; + WatchType m_type; + WatchItem *m_root; + QString m_activeData; }; class WatchHandler : public QObject @@ -259,25 +213,21 @@ class WatchHandler : public QObject public: WatchHandler(); - void init(QTreeView *localsView); - WatchModel *model(WatchType type) const; - static WatchType watchTypeOfIName(const QString &iname); WatchModel *modelForIName(const QString &data) const; - QStringList watcherExpressions() const; - QString watcherName(const QString &exp); - - void setModel(WatchType type, WatchModel *model); - //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 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); + void insertData(const WatchData &data); void removeData(const QString &iname); WatchData *findItem(const QString &iname) const; @@ -291,32 +241,18 @@ public: QSet<QString> expandedINames() const { return m_expandedINames; } - // For debuggers that clean out the locals models between frames: - // save/restore the expansion state. - Q_SLOT void restoreLocalsViewState(int frame = 0); - Q_SLOT void saveLocalsViewState(int frame = 0); - static QString watcherEditPlaceHolder(); signals: - void watcherInserted(const WatchData &data); + void watchDataUpdateNeeded(const WatchData &data); void sessionValueRequested(const QString &name, QVariant *value); void setSessionValueRequested(const QString &name, const QVariant &value); private: - friend class WatchModel; // needs formats, expanded inames - - // Per stack-frame locals state - struct LocalsViewState { - LocalsViewState() : firstVisibleRow(0) {} - int firstVisibleRow; - QSet<QString> expandedINames; - }; - typedef QMap<int, LocalsViewState> LocalsViewStateMap; + friend class WatchModel; void loadWatchers(); void saveWatchers(); - void initWatchModel(); void loadTypeFormats(); void saveTypeFormats(); @@ -329,16 +265,17 @@ private: EditWindows m_editWindows; QHash<QString, int> m_watcherNames; + QString watcherName(const QString &exp); QHash<QString, int> m_typeFormats; QHash<QString, int> m_individualFormats; void setDisplayedIName(const QString &iname, bool on); QSet<QString> m_expandedINames; // those expanded in the treeview QSet<QString> m_displayedINames; // those with "external" viewers - LocalsViewStateMap m_localsViewState; - WatchModel *m_models[WatchModelCount]; - QPointer<QTreeView> m_localsView; + WatchModel *m_locals; + WatchModel *m_watchers; + WatchModel *m_tooltips; }; } // namespace Internal diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 7eccb04cd9e..83486e899e9 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -554,22 +554,19 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const } wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); wchild.setAddress(dchild.address); - // Child overrides. Note that WatchData::setType sets - // childcount = 0 for some known types. - if (wchild.isHasChildrenNeeded()) { - const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; - switch (effectiveChildChildCount) { + // Child overrides. + const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; + switch (effectiveChildChildCount) { case -1: - wchild.setChildrenNeeded(); - wchild.setHasChildrenNeeded(); - break; + wchild.setChildrenNeeded(); + wchild.setHasChildrenNeeded(); + break; case 0: - wchild.setHasChildren(false); - break; + wchild.setHasChildren(false); + break; default: - wchild.setHasChildren(true); - break; - } + wchild.setHasChildren(true); + break; } } } diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 73e9c2bf0b4..0df432ce179 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -327,11 +327,9 @@ void WatchWindow::editItem(const QModelIndex &idx) Q_UNUSED(idx); // FIXME } -void WatchWindow::setModel(QAbstractItemModel *newModel) +void WatchWindow::setModel(QAbstractItemModel *model) { - if (model() == newModel) - return; - QTreeView::setModel(newModel); + QTreeView::setModel(model); setRootIsDecorated(true); header()->setDefaultAlignment(Qt::AlignLeft); @@ -339,7 +337,7 @@ void WatchWindow::setModel(QAbstractItemModel *newModel) if (m_type != LocalsType) header()->hide(); - connect(newModel, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); + connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); } void WatchWindow::resetHelper() -- GitLab