Commit ad46f128 authored by hjk's avatar hjk
Browse files

Revert "Enabled the use of Debugger-specific watch/locals models."

This reverts commit abf5e3dd.
parent d29bdf71
/**************************************************************************
**
** 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
/**************************************************************************
**
** 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
/**************************************************************************
**
** 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
......@@ -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
......
......@@ -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;