forked from qt-creator/qt-creator
Revert "Enabled the use of Debugger-specific watch/locals models."
This reverts commit abf5e3ddc3.
This commit is contained in:
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -39,6 +39,7 @@ HEADERS += \
|
|||||||
$$PWD/cdbsymbolgroupcontext.h \
|
$$PWD/cdbsymbolgroupcontext.h \
|
||||||
$$PWD/cdbsymbolgroupcontext_tpl.h \
|
$$PWD/cdbsymbolgroupcontext_tpl.h \
|
||||||
$$PWD/cdbstacktracecontext.h \
|
$$PWD/cdbstacktracecontext.h \
|
||||||
|
$$PWD/cdbstackframecontext.h \
|
||||||
$$PWD/cdbbreakpoint.h \
|
$$PWD/cdbbreakpoint.h \
|
||||||
$$PWD/cdbmodules.h \
|
$$PWD/cdbmodules.h \
|
||||||
$$PWD/cdbassembler.h \
|
$$PWD/cdbassembler.h \
|
||||||
@@ -46,14 +47,14 @@ HEADERS += \
|
|||||||
$$PWD/cdboptionspage.h \
|
$$PWD/cdboptionspage.h \
|
||||||
$$PWD/cdbdumperhelper.h \
|
$$PWD/cdbdumperhelper.h \
|
||||||
$$PWD/cdbsymbolpathlisteditor.h \
|
$$PWD/cdbsymbolpathlisteditor.h \
|
||||||
$$PWD/cdbexceptionutils.h \
|
$$PWD/cdbexceptionutils.h
|
||||||
$$PWD/cdbwatchmodels.h
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/cdbdebugengine.cpp \
|
$$PWD/cdbdebugengine.cpp \
|
||||||
$$PWD/cdbdebugeventcallback.cpp \
|
$$PWD/cdbdebugeventcallback.cpp \
|
||||||
$$PWD/cdbdebugoutput.cpp \
|
$$PWD/cdbdebugoutput.cpp \
|
||||||
$$PWD/cdbsymbolgroupcontext.cpp \
|
$$PWD/cdbsymbolgroupcontext.cpp \
|
||||||
|
$$PWD/cdbstackframecontext.cpp \
|
||||||
$$PWD/cdbstacktracecontext.cpp \
|
$$PWD/cdbstacktracecontext.cpp \
|
||||||
$$PWD/cdbbreakpoint.cpp \
|
$$PWD/cdbbreakpoint.cpp \
|
||||||
$$PWD/cdbmodules.cpp \
|
$$PWD/cdbmodules.cpp \
|
||||||
@@ -62,8 +63,7 @@ SOURCES += \
|
|||||||
$$PWD/cdboptionspage.cpp \
|
$$PWD/cdboptionspage.cpp \
|
||||||
$$PWD/cdbdumperhelper.cpp \
|
$$PWD/cdbdumperhelper.cpp \
|
||||||
$$PWD/cdbsymbolpathlisteditor.cpp \
|
$$PWD/cdbsymbolpathlisteditor.cpp \
|
||||||
$$PWD/cdbexceptionutils.cpp \
|
$$PWD/cdbexceptionutils.cpp
|
||||||
$$PWD/cdbwatchmodels.cpp
|
|
||||||
|
|
||||||
FORMS += $$PWD/cdboptionspagewidget.ui
|
FORMS += $$PWD/cdboptionspagewidget.ui
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "cdbdebugengine.h"
|
#include "cdbdebugengine.h"
|
||||||
#include "cdbdebugengine_p.h"
|
#include "cdbdebugengine_p.h"
|
||||||
#include "cdbstacktracecontext.h"
|
#include "cdbstacktracecontext.h"
|
||||||
|
#include "cdbstackframecontext.h"
|
||||||
#include "cdbsymbolgroupcontext.h"
|
#include "cdbsymbolgroupcontext.h"
|
||||||
#include "cdbbreakpoint.h"
|
#include "cdbbreakpoint.h"
|
||||||
#include "cdbmodules.h"
|
#include "cdbmodules.h"
|
||||||
@@ -46,7 +47,6 @@
|
|||||||
#include "moduleshandler.h"
|
#include "moduleshandler.h"
|
||||||
#include "disassemblerhandler.h"
|
#include "disassemblerhandler.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
#include "cdbwatchmodels.h"
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -301,9 +301,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent,
|
|||||||
m_debuggerManagerAccess(parent->engineInterface()),
|
m_debuggerManagerAccess(parent->engineInterface()),
|
||||||
m_currentStackTrace(0),
|
m_currentStackTrace(0),
|
||||||
m_firstActivatedFrame(true),
|
m_firstActivatedFrame(true),
|
||||||
m_mode(AttachCore),
|
m_mode(AttachCore)
|
||||||
m_localsModel(0),
|
|
||||||
m_watchModel(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,15 +390,6 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
|
|||||||
m_cif.debugDataSpaces->Release();
|
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()
|
void CdbDebugEnginePrivate::clearForRun()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
@@ -414,10 +403,6 @@ void CdbDebugEnginePrivate::clearForRun()
|
|||||||
|
|
||||||
void CdbDebugEnginePrivate::cleanStackTrace()
|
void CdbDebugEnginePrivate::cleanStackTrace()
|
||||||
{
|
{
|
||||||
if (m_localsModel) {
|
|
||||||
saveLocalsViewState();
|
|
||||||
m_localsModel->setSymbolGroupContext(0);
|
|
||||||
}
|
|
||||||
if (m_currentStackTrace) {
|
if (m_currentStackTrace) {
|
||||||
delete m_currentStackTrace;
|
delete m_currentStackTrace;
|
||||||
m_currentStackTrace = 0;
|
m_currentStackTrace = 0;
|
||||||
@@ -480,19 +465,14 @@ QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &functio
|
|||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
QString rc;
|
QString rc;
|
||||||
// Find the frame of the function if there is any
|
// 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()) {
|
if (m_d->m_currentStackTrace && !function.isEmpty()) {
|
||||||
const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
|
const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
|
||||||
if (frameIndex != -1) {
|
if (frameIndex != -1)
|
||||||
// Are we at the current frame?
|
frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
|
||||||
if (frameIndex == m_d->m_debuggerManagerAccess->stackHandler()->currentIndex()) {
|
}
|
||||||
if (const WatchData *wd = m_d->m_localsModel->findItemByIName(iname, m_d->m_localsModel->root()))
|
if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
|
||||||
return wd->toToolTip(); }
|
|
||||||
// Nope, try to retrieve via another symbol group
|
|
||||||
if (m_d->m_currentStackTrace->editorToolTip(frameIndex, iname, &rc, &errorMessage))
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
|
||||||
}
|
|
||||||
// No function/symbol context found, try to evaluate in current context.
|
// 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.
|
// Do not append type as this will mostly be 'long long' for integers, etc.
|
||||||
QString type;
|
QString type;
|
||||||
@@ -790,6 +770,67 @@ void CdbDebugEngine::detachDebugger()
|
|||||||
m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
|
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()
|
void CdbDebugEngine::stepExec()
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
@@ -996,14 +1037,18 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
do {
|
do {
|
||||||
QString newValue;
|
QString newValue;
|
||||||
if (frameIndex < 0 || !m_d->m_currentStackTrace) {
|
CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage);
|
||||||
errorMessage = tr("No current stack trace.");
|
if (!sg)
|
||||||
break;
|
break;
|
||||||
|
if (!sg->assignValue(expr, value, &newValue, &errorMessage))
|
||||||
|
break;
|
||||||
|
// Update view
|
||||||
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
||||||
|
if (WatchData *fwd = watchHandler->findItem(expr)) {
|
||||||
|
fwd->setValue(newValue);
|
||||||
|
watchHandler->insertData(*fwd);
|
||||||
|
watchHandler->updateWatchers();
|
||||||
}
|
}
|
||||||
// Assign in stack and update view
|
|
||||||
if (!m_d->m_currentStackTrace->assignValue(frameIndex, expr, value, &newValue, &errorMessage))
|
|
||||||
break;
|
|
||||||
m_d->m_localsModel->setValueByExpression(expr, newValue);
|
|
||||||
success = true;
|
success = true;
|
||||||
} while (false);
|
} while (false);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -1033,11 +1078,6 @@ bool CdbDebugEnginePrivate::executeDebuggerCommand(CIDebugControl *ctrl, const Q
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdbDebugEngine::isDebuggeeHalted() const
|
|
||||||
{
|
|
||||||
return m_d->m_hDebuggeeProcess && !m_d->isDebuggeeRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CdbDebugEngine::evaluateExpression(const QString &expression,
|
bool CdbDebugEngine::evaluateExpression(const QString &expression,
|
||||||
QString *value,
|
QString *value,
|
||||||
QString *type,
|
QString *type,
|
||||||
@@ -1092,21 +1132,21 @@ void CdbDebugEngine::activateFrame(int frameIndex)
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
do {
|
do {
|
||||||
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
|
StackHandler *stackHandler = m_d->m_debuggerManagerAccess->stackHandler();
|
||||||
|
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
|
||||||
const int oldIndex = stackHandler->currentIndex();
|
const int oldIndex = stackHandler->currentIndex();
|
||||||
if (frameIndex >= stackHandler->stackSize()) {
|
if (frameIndex >= stackHandler->stackSize()) {
|
||||||
errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
|
errorMessage = msgStackIndexOutOfRange(frameIndex, stackHandler->stackSize());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldIndex != frameIndex) {
|
if (oldIndex != frameIndex)
|
||||||
m_d->saveLocalsViewState();
|
|
||||||
stackHandler->setCurrentIndex(frameIndex);
|
stackHandler->setCurrentIndex(frameIndex);
|
||||||
}
|
|
||||||
|
|
||||||
const StackFrame &frame = stackHandler->currentFrame();
|
const StackFrame &frame = stackHandler->currentFrame();
|
||||||
if (!frame.isUsable()) {
|
if (!frame.isUsable()) {
|
||||||
m_d->m_localsModel->setSymbolGroupContext(0);
|
|
||||||
// Clean out model
|
// Clean out model
|
||||||
|
watchHandler->beginCycle();
|
||||||
|
watchHandler->endCycle();
|
||||||
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
|
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
|
||||||
arg(QLatin1String(Q_FUNC_INFO), frame.file);
|
arg(QLatin1String(Q_FUNC_INFO), frame.file);
|
||||||
break;
|
break;
|
||||||
@@ -1115,18 +1155,10 @@ void CdbDebugEngine::activateFrame(int frameIndex)
|
|||||||
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true);
|
||||||
|
|
||||||
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
|
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
|
||||||
m_d->m_localsModel->setUseDumpers(m_d->m_dumper->isEnabled() && theDebuggerBoolSetting(UseDebuggingHelpers));
|
watchHandler->beginCycle();
|
||||||
CdbSymbolGroupContext *ctx = 0;
|
if (CdbStackFrameContext *sgc = m_d->getStackFrameContext(frameIndex, &errorMessage))
|
||||||
if (m_d->m_currentStackTrace) {
|
success = sgc->populateModelInitially(watchHandler, &errorMessage);
|
||||||
ctx = m_d->m_currentStackTrace->symbolGroupAt(frameIndex, &errorMessage);
|
watchHandler->endCycle();
|
||||||
success = ctx != 0;
|
|
||||||
} else {
|
|
||||||
errorMessage = QLatin1String(msgNoStackTraceC);
|
|
||||||
}
|
|
||||||
m_d->m_localsModel->setSymbolGroupContext(ctx);
|
|
||||||
m_d->m_debuggerManagerAccess->watchHandler()->restoreLocalsViewState(frameIndex);
|
|
||||||
} else {
|
|
||||||
success = true;
|
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
if (!success)
|
if (!success)
|
||||||
@@ -1468,8 +1500,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
|
||||||
m_engine->activateFrame(current);
|
m_engine->activateFrame(current);
|
||||||
}
|
}
|
||||||
// Update watchers
|
m_debuggerManagerAccess->watchHandler()->updateWatchers();
|
||||||
m_watchModel->refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::updateModules()
|
void CdbDebugEnginePrivate::updateModules()
|
||||||
@@ -1481,6 +1512,8 @@ void CdbDebugEnginePrivate::updateModules()
|
|||||||
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
|
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *dumperPrefixC = "dumper";
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
|
void CdbDebugEnginePrivate::handleModuleLoad(const QString &name)
|
||||||
{
|
{
|
||||||
if (debugCDB>2)
|
if (debugCDB>2)
|
||||||
@@ -1553,37 +1586,6 @@ bool CdbDebugEnginePrivate::setSymbolPaths(const QStringList &s, QString *errorM
|
|||||||
return true;
|
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 Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public:
|
|||||||
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters);
|
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters);
|
||||||
virtual void exitDebugger();
|
virtual void exitDebugger();
|
||||||
virtual void detachDebugger();
|
virtual void detachDebugger();
|
||||||
|
virtual void updateWatchData(const WatchData &data);
|
||||||
|
|
||||||
virtual void stepExec();
|
virtual void stepExec();
|
||||||
virtual void stepOutExec();
|
virtual void stepOutExec();
|
||||||
@@ -96,11 +97,6 @@ public:
|
|||||||
virtual void reloadSourceFiles();
|
virtual void reloadSourceFiles();
|
||||||
virtual void reloadFullStack() {}
|
virtual void reloadFullStack() {}
|
||||||
|
|
||||||
WatchModel *watchModel(int type) const;
|
|
||||||
|
|
||||||
bool isDebuggeeHalted() const;
|
|
||||||
bool evaluateExpression(const QString &expression, QString *value, QString *type, QString *errorMessage);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void syncDebuggerPaths();
|
void syncDebuggerPaths();
|
||||||
|
|
||||||
@@ -112,7 +108,6 @@ private slots:
|
|||||||
void slotConsoleStubError(const QString &msg);
|
void slotConsoleStubError(const QString &msg);
|
||||||
void slotConsoleStubTerminated();
|
void slotConsoleStubTerminated();
|
||||||
void warning(const QString &w);
|
void warning(const QString &w);
|
||||||
void insertWatcher(const WatchData &);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
|
bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
|
||||||
@@ -121,7 +116,8 @@ private:
|
|||||||
void killWatchTimer();
|
void killWatchTimer();
|
||||||
void processTerminated(unsigned long exitCode);
|
void processTerminated(unsigned long exitCode);
|
||||||
bool executeDebuggerCommand(const QString &command, QString *errorMessage);
|
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);
|
QString editorToolTip(const QString &exp, const QString &function);
|
||||||
|
|
||||||
CdbDebugEnginePrivate *m_d;
|
CdbDebugEnginePrivate *m_d;
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
|
|
||||||
#include <utils/consoleprocess.h>
|
#include <utils/consoleprocess.h>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QPointer>
|
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
@@ -50,8 +49,6 @@ class IDebuggerManagerAccessForEngines;
|
|||||||
class WatchHandler;
|
class WatchHandler;
|
||||||
class CdbStackFrameContext;
|
class CdbStackFrameContext;
|
||||||
class CdbStackTraceContext;
|
class CdbStackTraceContext;
|
||||||
class CdbLocalsModel;
|
|
||||||
class CdbWatchModel;
|
|
||||||
|
|
||||||
// Thin wrapper around the 'DBEng' debugger engine shared library
|
// Thin wrapper around the 'DBEng' debugger engine shared library
|
||||||
// which is loaded at runtime.
|
// which is loaded at runtime.
|
||||||
@@ -126,6 +123,7 @@ struct CdbDebugEnginePrivate
|
|||||||
void cleanStackTrace();
|
void cleanStackTrace();
|
||||||
void clearForRun();
|
void clearForRun();
|
||||||
void handleModuleLoad(const QString &);
|
void handleModuleLoad(const QString &);
|
||||||
|
CdbStackFrameContext *getStackFrameContext(int frameIndex, QString *errorMessage) const;
|
||||||
void clearDisplay();
|
void clearDisplay();
|
||||||
|
|
||||||
bool interruptInterferiorProcess(QString *errorMessage);
|
bool interruptInterferiorProcess(QString *errorMessage);
|
||||||
@@ -139,8 +137,6 @@ struct CdbDebugEnginePrivate
|
|||||||
enum EndDebuggingMode { EndDebuggingDetach, EndDebuggingTerminate, EndDebuggingAuto };
|
enum EndDebuggingMode { EndDebuggingDetach, EndDebuggingTerminate, EndDebuggingAuto };
|
||||||
void endDebugging(EndDebuggingMode em = EndDebuggingAuto);
|
void endDebugging(EndDebuggingMode em = EndDebuggingAuto);
|
||||||
|
|
||||||
void saveLocalsViewState();
|
|
||||||
|
|
||||||
static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage);
|
static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage);
|
||||||
static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage);
|
static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage);
|
||||||
|
|
||||||
@@ -172,9 +168,6 @@ struct CdbDebugEnginePrivate
|
|||||||
|
|
||||||
DebuggerStartMode m_mode;
|
DebuggerStartMode m_mode;
|
||||||
Core::Utils::ConsoleProcess m_consoleStubProc;
|
Core::Utils::ConsoleProcess m_consoleStubProc;
|
||||||
|
|
||||||
QPointer<CdbLocalsModel> m_localsModel;
|
|
||||||
QPointer<CdbWatchModel> m_watchModel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
|
|||||||
@@ -27,49 +27,49 @@
|
|||||||
**
|
**
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#ifndef ABSTRACTSYNCWATCHMODEL_H
|
#ifndef CDBSTACKFRAMECONTEXT_H
|
||||||
#define ABSTRACTSYNCWATCHMODEL_H
|
#define CDBSTACKFRAMECONTEXT_H
|
||||||
|
|
||||||
#include "watchhandler.h"
|
|
||||||
#include <QtCore/QPointer>
|
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QDebug;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
/* AbstractSyncWatchModel: To be used by synchonous debuggers.
|
class WatchData;
|
||||||
* Implements all of WatchModel and provides new virtuals for
|
class WatchHandler;
|
||||||
* the debugger to complete items. */
|
class CdbSymbolGroupContext;
|
||||||
|
class CdbDumperHelper;
|
||||||
|
|
||||||
class AbstractSyncWatchModel : public WatchModel
|
/* 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 CdbStackFrameContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_DISABLE_COPY(CdbStackFrameContext)
|
||||||
public:
|
public:
|
||||||
explicit AbstractSyncWatchModel(WatchHandler *handler, WatchType type, QObject *parent = 0);
|
explicit CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper,
|
||||||
|
CdbSymbolGroupContext *symbolContext);
|
||||||
|
~CdbStackFrameContext();
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
bool assignValue(const QString &iname, const QString &value,
|
||||||
|
QString *newValue /* = 0 */, QString *errorMessage);
|
||||||
|
bool editorToolTip(const QString &iname, QString *value, QString *errorMessage);
|
||||||
|
|
||||||
virtual void fetchMore(const QModelIndex &parent);
|
bool populateModelInitially(WatchHandler *wh, QString *errorMessage);
|
||||||
virtual bool canFetchMore(const QModelIndex &parent) const;
|
|
||||||
|
|
||||||
signals:
|
bool completeData(const WatchData &incompleteLocal,
|
||||||
// Emitted if one of fetchChildren/complete fails.
|
WatchHandler *wh,
|
||||||
void error(const QString &);
|
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;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable QString m_errorMessage;
|
const bool m_useDumpers;
|
||||||
|
const QSharedPointer<CdbDumperHelper> m_dumper;
|
||||||
|
CdbSymbolGroupContext *m_symbolContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
#endif // ABSTRACTSYNCWATCHMODEL_H
|
#endif // CDBSTACKFRAMECONTEXT_H
|
||||||
@@ -28,11 +28,11 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include "cdbstacktracecontext.h"
|
#include "cdbstacktracecontext.h"
|
||||||
|
#include "cdbstackframecontext.h"
|
||||||
#include "cdbbreakpoint.h"
|
#include "cdbbreakpoint.h"
|
||||||
#include "cdbsymbolgroupcontext.h"
|
#include "cdbsymbolgroupcontext.h"
|
||||||
#include "cdbdebugengine_p.h"
|
#include "cdbdebugengine_p.h"
|
||||||
#include "cdbdumperhelper.h"
|
#include "cdbdumperhelper.h"
|
||||||
#include "debuggeractions.h"
|
|
||||||
|
|
||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
@@ -90,7 +90,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
|
|||||||
qDebug() << Q_FUNC_INFO << frameCount;
|
qDebug() << Q_FUNC_INFO << frameCount;
|
||||||
|
|
||||||
m_frameContexts.resize(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
|
// Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
|
||||||
WCHAR wszBuf[MAX_PATH];
|
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);
|
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
|
// Create a frame on demand
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
@@ -158,7 +158,6 @@ CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupAt(int index, QString *e
|
|||||||
}
|
}
|
||||||
if (m_frameContexts.at(index))
|
if (m_frameContexts.at(index))
|
||||||
return m_frameContexts.at(index);
|
return m_frameContexts.at(index);
|
||||||
// Create COM and wrap
|
|
||||||
CIDebugSymbolGroup *sg = createSymbolGroup(index, errorMessage);
|
CIDebugSymbolGroup *sg = createSymbolGroup(index, errorMessage);
|
||||||
if (!sg) {
|
if (!sg) {
|
||||||
*errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
|
*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);
|
*errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
m_frameContexts[index] = sc;
|
CdbStackFrameContext *fr = new CdbStackFrameContext(m_dumper, sc);
|
||||||
return sc;
|
m_frameContexts[index] = fr;
|
||||||
|
return fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
|
CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
|
||||||
@@ -198,49 +198,6 @@ CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *
|
|||||||
return sg;
|
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 CdbStackTraceContext::toString() const
|
||||||
{
|
{
|
||||||
QString rc;
|
QString rc;
|
||||||
|
|||||||
@@ -47,10 +47,11 @@ namespace Internal {
|
|||||||
|
|
||||||
struct CdbComInterfaces;
|
struct CdbComInterfaces;
|
||||||
class CdbSymbolGroupContext;
|
class CdbSymbolGroupContext;
|
||||||
|
class CdbStackFrameContext;
|
||||||
class CdbDumperHelper;
|
class CdbDumperHelper;
|
||||||
|
|
||||||
/* Context representing a break point stack consisting of several frames.
|
/* 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. */
|
* containining the local variables of the stack. */
|
||||||
|
|
||||||
class CdbStackTraceContext
|
class CdbStackTraceContext
|
||||||
@@ -74,17 +75,7 @@ public:
|
|||||||
// Top-Level instruction offset for disassembler
|
// Top-Level instruction offset for disassembler
|
||||||
ULONG64 instructionOffset() const { return m_instructionOffset; }
|
ULONG64 instructionOffset() const { return m_instructionOffset; }
|
||||||
|
|
||||||
CdbSymbolGroupContext *symbolGroupAt(int index, QString *errorMessage);
|
CdbStackFrameContext *frameContextAt(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);
|
|
||||||
|
|
||||||
// Format for logging
|
// Format for logging
|
||||||
void format(QTextStream &str) const;
|
void format(QTextStream &str) const;
|
||||||
@@ -98,7 +89,7 @@ private:
|
|||||||
CdbComInterfaces *m_cif;
|
CdbComInterfaces *m_cif;
|
||||||
|
|
||||||
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
|
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
|
||||||
QVector <CdbSymbolGroupContext*> m_frameContexts;
|
QVector <CdbStackFrameContext*> m_frameContexts;
|
||||||
QList<StackFrame> m_frames;
|
QList<StackFrame> m_frames;
|
||||||
ULONG64 m_instructionOffset;
|
ULONG64 m_instructionOffset;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const
|
|||||||
const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
|
const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
|
||||||
wd.setType(type);
|
wd.setType(type);
|
||||||
wd.setValue(fixValue(value));
|
wd.setValue(fixValue(value));
|
||||||
|
wd.setChildrenNeeded(); // compensate side effects of above setters
|
||||||
// Figure out children. The SubElement is only a guess unless the symbol,
|
// Figure out children. The SubElement is only a guess unless the symbol,
|
||||||
// is expanded, so, we leave this as a guess for later updates.
|
// 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
|
// If the symbol has children (expanded or not), we leave the 'Children' flag
|
||||||
|
|||||||
@@ -81,6 +81,31 @@ public:
|
|||||||
bool assignValue(const QString &iname, const QString &value,
|
bool assignValue(const QString &iname, const QString &value,
|
||||||
QString *newValue /* = 0 */, QString *errorMessage);
|
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.
|
// Retrieve child symbols of prefix as a sequence of WatchData.
|
||||||
template <class OutputIterator>
|
template <class OutputIterator>
|
||||||
bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage);
|
bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage);
|
||||||
|
|||||||
@@ -66,6 +66,105 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato
|
|||||||
return true;
|
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 Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -44,8 +44,6 @@ HEADERS += \
|
|||||||
sourcefileswindow.h \
|
sourcefileswindow.h \
|
||||||
threadswindow.h \
|
threadswindow.h \
|
||||||
watchhandler.h \
|
watchhandler.h \
|
||||||
asyncwatchmodel.h \
|
|
||||||
abstractsyncwatchmodel.h \
|
|
||||||
watchwindow.h \
|
watchwindow.h \
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
@@ -73,8 +71,6 @@ SOURCES += \
|
|||||||
sourcefileswindow.cpp \
|
sourcefileswindow.cpp \
|
||||||
threadswindow.cpp \
|
threadswindow.cpp \
|
||||||
watchhandler.cpp \
|
watchhandler.cpp \
|
||||||
asyncwatchmodel.cpp \
|
|
||||||
abstractsyncwatchmodel.cpp \
|
|
||||||
watchwindow.cpp \
|
watchwindow.cpp \
|
||||||
|
|
||||||
FORMS += attachexternaldialog.ui \
|
FORMS += attachexternaldialog.ui \
|
||||||
|
|||||||
@@ -187,8 +187,7 @@ static IDebuggerEngine *tcfEngine = 0;
|
|||||||
|
|
||||||
DebuggerManager::DebuggerManager()
|
DebuggerManager::DebuggerManager()
|
||||||
: m_startParameters(new DebuggerStartParameters),
|
: m_startParameters(new DebuggerStartParameters),
|
||||||
m_inferiorPid(0),
|
m_inferiorPid(0)
|
||||||
m_watchHandler(new WatchHandler)
|
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -232,8 +231,6 @@ void DebuggerManager::init()
|
|||||||
m_sourceFilesWindow = new SourceFilesWindow;
|
m_sourceFilesWindow = new SourceFilesWindow;
|
||||||
m_threadsWindow = new ThreadsWindow;
|
m_threadsWindow = new ThreadsWindow;
|
||||||
m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
|
m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
|
||||||
m_watchHandler->init(m_localsWindow);
|
|
||||||
|
|
||||||
m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
|
m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
|
||||||
//m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType);
|
//m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType);
|
||||||
m_statusTimer = new QTimer(this);
|
m_statusTimer = new QTimer(this);
|
||||||
@@ -324,7 +321,14 @@ void DebuggerManager::init()
|
|||||||
m_registerHandler = new RegisterHandler;
|
m_registerHandler = new RegisterHandler;
|
||||||
registerView->setModel(m_registerHandler->model());
|
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*)),
|
connect(m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
|
||||||
this, SIGNAL(sessionValueRequested(QString,QVariant*)));
|
this, SIGNAL(sessionValueRequested(QString,QVariant*)));
|
||||||
connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
|
connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
|
||||||
@@ -333,6 +337,12 @@ void DebuggerManager::init()
|
|||||||
this, SLOT(assignValueInDebugger()), Qt::QueuedConnection);
|
this, SLOT(assignValueInDebugger()), Qt::QueuedConnection);
|
||||||
|
|
||||||
// Tooltip
|
// 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 = new QAction(this);
|
||||||
m_continueAction->setText(tr("Continue"));
|
m_continueAction->setText(tr("Continue"));
|
||||||
m_continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png"));
|
m_continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png"));
|
||||||
@@ -461,34 +471,12 @@ void DebuggerManager::init()
|
|||||||
localsAndWatchers->setStretchFactor(2, 1);
|
localsAndWatchers->setStretchFactor(2, 1);
|
||||||
m_watchDock = createDockForWidget(localsAndWatchers);
|
m_watchDock = createDockForWidget(localsAndWatchers);
|
||||||
|
|
||||||
initializeWatchModels(gdbEngine);
|
|
||||||
|
|
||||||
setStatus(DebuggerProcessNotReady);
|
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*> DebuggerManager::initializeEngines(unsigned enabledTypeFlags)
|
||||||
{
|
{
|
||||||
QList<Core::IOptionsPage*> rc;
|
QList<Core::IOptionsPage*> rc;
|
||||||
// Initialize watch models so columns show up initially.
|
|
||||||
if (enabledTypeFlags & GdbEngineType)
|
if (enabledTypeFlags & GdbEngineType)
|
||||||
gdbEngine = createGdbEngine(this, &rc);
|
gdbEngine = createGdbEngine(this, &rc);
|
||||||
winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc);
|
winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc);
|
||||||
@@ -499,12 +487,6 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTy
|
|||||||
m_engine = 0;
|
m_engine = 0;
|
||||||
if (Debugger::Constants::Internal::debug)
|
if (Debugger::Constants::Internal::debug)
|
||||||
qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine << rc.size();
|
qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine << rc.size();
|
||||||
if (gdbEngine) {
|
|
||||||
initializeWatchModels(gdbEngine);
|
|
||||||
} else {
|
|
||||||
if (winEngine)
|
|
||||||
initializeWatchModels(winEngine);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -820,6 +802,12 @@ void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::I
|
|||||||
m_engine->setToolTipExpression(mousePos, editor, cursorPos);
|
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)
|
QVariant DebuggerManager::sessionValue(const QString &name)
|
||||||
{
|
{
|
||||||
// this is answered by the plugin
|
// this is answered by the plugin
|
||||||
@@ -955,7 +943,6 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!m_engine) {
|
if (!m_engine) {
|
||||||
debuggingFinished();
|
debuggingFinished();
|
||||||
// Create Message box with possibility to go to settings
|
// 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);
|
Core::ICore::instance()->showOptionsDialog(_(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initializeWatchModels(m_engine);
|
|
||||||
|
|
||||||
if (Debugger::Constants::Internal::debug)
|
if (Debugger::Constants::Internal::debug)
|
||||||
qDebug() << m_startParameters->executable << m_engine;
|
qDebug() << m_startParameters->executable << m_engine;
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ class QModelIndex;
|
|||||||
class QPoint;
|
class QPoint;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
class QTreeView;
|
|
||||||
class QDebug;
|
class QDebug;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
@@ -308,6 +307,7 @@ public slots:
|
|||||||
void detachDebugger();
|
void detachDebugger();
|
||||||
|
|
||||||
void addToWatchWindow();
|
void addToWatchWindow();
|
||||||
|
void updateWatchData(const WatchData &data);
|
||||||
|
|
||||||
void sessionLoaded();
|
void sessionLoaded();
|
||||||
void sessionUnloaded();
|
void sessionUnloaded();
|
||||||
@@ -418,7 +418,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void runTest(const QString &fileName);
|
void runTest(const QString &fileName);
|
||||||
void initializeWatchModels(IDebuggerEngine *engine);
|
|
||||||
QDockWidget *createDockForWidget(QWidget *widget);
|
QDockWidget *createDockForWidget(QWidget *widget);
|
||||||
Q_SLOT void createNewDock(QWidget *widget);
|
Q_SLOT void createNewDock(QWidget *widget);
|
||||||
void updateDockWidget(QDockWidget *dockWidget);
|
void updateDockWidget(QDockWidget *dockWidget);
|
||||||
@@ -484,12 +483,13 @@ private:
|
|||||||
|
|
||||||
QWidget *m_breakWindow;
|
QWidget *m_breakWindow;
|
||||||
QWidget *m_disassemblerWindow;
|
QWidget *m_disassemblerWindow;
|
||||||
QTreeView *m_localsWindow;
|
QWidget *m_localsWindow;
|
||||||
QWidget *m_registerWindow;
|
QWidget *m_registerWindow;
|
||||||
QWidget *m_modulesWindow;
|
QWidget *m_modulesWindow;
|
||||||
|
//QWidget *m_tooltipWindow;
|
||||||
QWidget *m_stackWindow;
|
QWidget *m_stackWindow;
|
||||||
QWidget *m_threadsWindow;
|
QWidget *m_threadsWindow;
|
||||||
QTreeView *m_watchersWindow;
|
QWidget *m_watchersWindow;
|
||||||
DebuggerOutputWindow *m_outputWindow;
|
DebuggerOutputWindow *m_outputWindow;
|
||||||
|
|
||||||
int m_status;
|
int m_status;
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
#include "registerhandler.h"
|
#include "registerhandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
#include "asyncwatchmodel.h"
|
|
||||||
#include "sourcefileswindow.h"
|
#include "sourcefileswindow.h"
|
||||||
|
|
||||||
#include "debuggerdialogs.h"
|
#include "debuggerdialogs.h"
|
||||||
@@ -153,8 +152,7 @@ GdbEngine::GdbEngine(DebuggerManager *parent) :
|
|||||||
m_dumperInjectionLoad(false),
|
m_dumperInjectionLoad(false),
|
||||||
#endif
|
#endif
|
||||||
q(parent),
|
q(parent),
|
||||||
qq(parent->engineInterface()),
|
qq(parent->engineInterface())
|
||||||
m_models(qq->watchHandler())
|
|
||||||
{
|
{
|
||||||
m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug);
|
m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug);
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
@@ -172,8 +170,6 @@ GdbEngine::~GdbEngine()
|
|||||||
|
|
||||||
void GdbEngine::initializeConnections()
|
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
|
// Gdb Process interaction
|
||||||
connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
|
connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
|
||||||
this, SLOT(gdbProcError(QProcess::ProcessError)));
|
this, SLOT(gdbProcError(QProcess::ProcessError)));
|
||||||
@@ -2700,10 +2696,10 @@ static QString tooltipINameForExpression(const QString &exp)
|
|||||||
bool GdbEngine::showToolTip()
|
bool GdbEngine::showToolTip()
|
||||||
{
|
{
|
||||||
WatchHandler *handler = qq->watchHandler();
|
WatchHandler *handler = qq->watchHandler();
|
||||||
AsyncWatchModel *model = static_cast<AsyncWatchModel *>(handler->model(TooltipsWatch));
|
WatchModel *model = handler->model(TooltipsWatch);
|
||||||
QString iname = tooltipINameForExpression(m_toolTipExpression);
|
QString iname = tooltipINameForExpression(m_toolTipExpression);
|
||||||
model->setActiveData(iname);
|
model->setActiveData(iname);
|
||||||
WatchItem *item = model->findItemByIName(iname, model->dummyRoot());
|
WatchItem *item = model->findItem(iname, model->dummyRoot());
|
||||||
if (!item) {
|
if (!item) {
|
||||||
hideDebuggerToolTip();
|
hideDebuggerToolTip();
|
||||||
return false;
|
return false;
|
||||||
@@ -2792,7 +2788,7 @@ void GdbEngine::setToolTipExpression(const QPoint &mousePos,
|
|||||||
toolTip.name = exp;
|
toolTip.name = exp;
|
||||||
toolTip.iname = tooltipINameForExpression(exp);
|
toolTip.iname = tooltipINameForExpression(exp);
|
||||||
qq->watchHandler()->removeData(toolTip.iname);
|
qq->watchHandler()->removeData(toolTip.iname);
|
||||||
m_models.insertData(toolTip);
|
qq->watchHandler()->insertData(toolTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3150,7 +3146,7 @@ void GdbEngine::rebuildModel()
|
|||||||
PENDING_DEBUG("REBUILDING MODEL");
|
PENDING_DEBUG("REBUILDING MODEL");
|
||||||
emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>"));
|
emit gdbInputAvailable(LogStatus, _("<Rebuild Watchmodel>"));
|
||||||
q->showStatusMessage(tr("Finished retrieving data."), 400);
|
q->showStatusMessage(tr("Finished retrieving data."), 400);
|
||||||
m_models.endCycle();
|
qq->watchHandler()->endCycle();
|
||||||
showToolTip();
|
showToolTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3546,7 +3542,7 @@ void GdbEngine::updateLocals()
|
|||||||
PENDING_DEBUG("\nRESET PENDING");
|
PENDING_DEBUG("\nRESET PENDING");
|
||||||
//m_toolTipCache.clear();
|
//m_toolTipCache.clear();
|
||||||
m_toolTipExpression.clear();
|
m_toolTipExpression.clear();
|
||||||
m_models.beginCycle();
|
qq->watchHandler()->beginCycle();
|
||||||
|
|
||||||
QString level = QString::number(currentFrame());
|
QString level = QString::number(currentFrame());
|
||||||
// '2' is 'list with type and value'
|
// '2' is 'list with type and value'
|
||||||
@@ -3600,7 +3596,7 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record, const QVari
|
|||||||
locals += m_currentFunctionArgs;
|
locals += m_currentFunctionArgs;
|
||||||
|
|
||||||
setLocals(locals);
|
setLocals(locals);
|
||||||
m_models.updateWatchers();
|
qq->watchHandler()->updateWatchers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::setLocals(const QList<GdbMi> &locals)
|
void GdbEngine::setLocals(const QList<GdbMi> &locals)
|
||||||
@@ -3672,7 +3668,7 @@ void GdbEngine::insertData(const WatchData &data0)
|
|||||||
qDebug() << "BOGUS VALUE:" << data.toString();
|
qDebug() << "BOGUS VALUE:" << data.toString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_models.insertData(data);
|
qq->watchHandler()->insertData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
|
void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "gdbmi.h"
|
#include "gdbmi.h"
|
||||||
#include "outputcollector.h"
|
#include "outputcollector.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
#include "asyncwatchmodel.h"
|
|
||||||
|
|
||||||
#include <consoleprocess.h>
|
#include <consoleprocess.h>
|
||||||
|
|
||||||
@@ -123,8 +122,6 @@ private:
|
|||||||
void loadAllSymbols();
|
void loadAllSymbols();
|
||||||
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
|
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 setDebugDebuggingHelpers(const QVariant &on);
|
||||||
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
||||||
|
|
||||||
@@ -200,7 +197,6 @@ private slots:
|
|||||||
void stubStarted();
|
void stubStarted();
|
||||||
void stubError(const QString &msg);
|
void stubError(const QString &msg);
|
||||||
void uploadProcError(QProcess::ProcessError error);
|
void uploadProcError(QProcess::ProcessError error);
|
||||||
void updateWatchData(const WatchData &data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int terminationIndex(const QByteArray &buffer, int &length);
|
int terminationIndex(const QByteArray &buffer, int &length);
|
||||||
@@ -328,6 +324,7 @@ private:
|
|||||||
// FIXME: BaseClass. called to improve situation for a watch item
|
// FIXME: BaseClass. called to improve situation for a watch item
|
||||||
void updateSubItem(const WatchData &data);
|
void updateSubItem(const WatchData &data);
|
||||||
|
|
||||||
|
void updateWatchData(const WatchData &data);
|
||||||
void rebuildModel();
|
void rebuildModel();
|
||||||
|
|
||||||
void insertData(const WatchData &data);
|
void insertData(const WatchData &data);
|
||||||
@@ -387,7 +384,6 @@ private:
|
|||||||
|
|
||||||
DebuggerManager * const q;
|
DebuggerManager * const q;
|
||||||
IDebuggerManagerAccessForEngines * const qq;
|
IDebuggerManagerAccessForEngines * const qq;
|
||||||
AsyncWatchModelMixin m_models;
|
|
||||||
// make sure to re-initialize new members in initializeVariables();
|
// make sure to re-initialize new members in initializeVariables();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ class ITextEditor;
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class WatchModel;
|
|
||||||
|
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class WatchData;
|
class WatchData;
|
||||||
struct DebuggerStartParameters;
|
struct DebuggerStartParameters;
|
||||||
@@ -62,6 +60,7 @@ public:
|
|||||||
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
|
virtual bool startDebugger(const QSharedPointer<DebuggerStartParameters> &startParameters) = 0;
|
||||||
virtual void exitDebugger() = 0;
|
virtual void exitDebugger() = 0;
|
||||||
virtual void detachDebugger() {}
|
virtual void detachDebugger() {}
|
||||||
|
virtual void updateWatchData(const WatchData &data) = 0;
|
||||||
|
|
||||||
virtual void stepExec() = 0;
|
virtual void stepExec() = 0;
|
||||||
virtual void stepOutExec() = 0;
|
virtual void stepOutExec() = 0;
|
||||||
@@ -96,8 +95,6 @@ public:
|
|||||||
virtual void reloadFullStack() = 0;
|
virtual void reloadFullStack() = 0;
|
||||||
|
|
||||||
virtual void watchPoint(const QPoint &) {}
|
virtual void watchPoint(const QPoint &) {}
|
||||||
|
|
||||||
virtual WatchModel *watchModel(int type) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -185,13 +185,10 @@ void ScriptAgent::scriptUnload(qint64 scriptId)
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ScriptEngine::ScriptEngine(DebuggerManager *parent) :
|
ScriptEngine::ScriptEngine(DebuggerManager *parent)
|
||||||
q(parent),
|
|
||||||
qq(parent->engineInterface()),
|
|
||||||
m_models(qq->watchHandler())
|
|
||||||
{
|
{
|
||||||
connect(qq->watchHandler(), SIGNAL(watcherInserted(WatchData)), &m_models, SLOT(insertWatcher(WatchData)));
|
q = parent;
|
||||||
connect(&m_models, SIGNAL(watchDataUpdateNeeded(WatchData)), this, SLOT(updateWatchData(WatchData)));
|
qq = parent->engineInterface();
|
||||||
m_scriptEngine = new QScriptEngine(this);
|
m_scriptEngine = new QScriptEngine(this);
|
||||||
m_scriptAgent = new ScriptAgent(this, m_scriptEngine);
|
m_scriptAgent = new ScriptAgent(this, m_scriptEngine);
|
||||||
m_scriptEngine->setAgent(m_scriptAgent);
|
m_scriptEngine->setAgent(m_scriptAgent);
|
||||||
@@ -575,7 +572,7 @@ void ScriptEngine::maybeBreakNow(bool byFunction)
|
|||||||
void ScriptEngine::updateLocals()
|
void ScriptEngine::updateLocals()
|
||||||
{
|
{
|
||||||
QScriptContext *context = m_scriptEngine->currentContext();
|
QScriptContext *context = m_scriptEngine->currentContext();
|
||||||
m_models.beginCycle();
|
qq->watchHandler()->beginCycle();
|
||||||
//SDEBUG("UPDATE LOCALS");
|
//SDEBUG("UPDATE LOCALS");
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -607,7 +604,7 @@ void ScriptEngine::updateLocals()
|
|||||||
data.iname = "local";
|
data.iname = "local";
|
||||||
data.name = "local";
|
data.name = "local";
|
||||||
data.scriptValue = context->activationObject();
|
data.scriptValue = context->activationObject();
|
||||||
m_models.insertData(data);
|
qq->watchHandler()->insertData(data);
|
||||||
|
|
||||||
// FIXME: Use an extra thread. This here is evil
|
// FIXME: Use an extra thread. This here is evil
|
||||||
m_stopped = true;
|
m_stopped = true;
|
||||||
@@ -682,7 +679,7 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
|
|||||||
data.setType("<unknown>");
|
data.setType("<unknown>");
|
||||||
data.setValue("<unknown>");
|
data.setValue("<unknown>");
|
||||||
}
|
}
|
||||||
m_models.insertData(data);
|
qq->watchHandler()->insertData(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,13 +697,13 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
|
|||||||
data1.setChildrenNeeded();
|
data1.setChildrenNeeded();
|
||||||
else
|
else
|
||||||
data1.setChildrenUnneeded();
|
data1.setChildrenUnneeded();
|
||||||
m_models.insertData(data1);
|
qq->watchHandler()->insertData(data1);
|
||||||
++numChild;
|
++numChild;
|
||||||
}
|
}
|
||||||
//SDEBUG(" ... CHILDREN: " << numChild);
|
//SDEBUG(" ... CHILDREN: " << numChild);
|
||||||
data.setHasChildren(numChild > 0);
|
data.setHasChildren(numChild > 0);
|
||||||
data.setChildrenUnneeded();
|
data.setChildrenUnneeded();
|
||||||
m_models.insertData(data);
|
qq->watchHandler()->insertData(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,7 +716,7 @@ void ScriptEngine::updateSubItem(const WatchData &data0)
|
|||||||
}
|
}
|
||||||
data.setHasChildren(numChild > 0);
|
data.setHasChildren(numChild > 0);
|
||||||
//SDEBUG(" ... CHILDCOUNT: " << numChild);
|
//SDEBUG(" ... CHILDCOUNT: " << numChild);
|
||||||
m_models.insertData(data);
|
qq->watchHandler()->insertData(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ class QScriptValue;
|
|||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "idebuggerengine.h"
|
#include "idebuggerengine.h"
|
||||||
#include "asyncwatchmodel.h"
|
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -108,20 +107,14 @@ private:
|
|||||||
|
|
||||||
bool supportsThreads() const { return true; }
|
bool supportsThreads() const { return true; }
|
||||||
void maybeBreakNow(bool byFunction);
|
void maybeBreakNow(bool byFunction);
|
||||||
|
void updateWatchData(const WatchData &data);
|
||||||
void updateLocals();
|
void updateLocals();
|
||||||
void updateSubItem(const WatchData &data);
|
void updateSubItem(const WatchData &data);
|
||||||
|
|
||||||
WatchModel *watchModel(int type) const { return m_models.model(type); }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void updateWatchData(const WatchData &data);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ScriptAgent;
|
friend class ScriptAgent;
|
||||||
DebuggerManager *q;
|
DebuggerManager *q;
|
||||||
IDebuggerManagerAccessForEngines *qq;
|
IDebuggerManagerAccessForEngines *qq;
|
||||||
AsyncWatchModelMixin m_models;
|
|
||||||
|
|
||||||
QScriptEngine *m_scriptEngine;
|
QScriptEngine *m_scriptEngine;
|
||||||
QString m_scriptContents;
|
QString m_scriptContents;
|
||||||
|
|||||||
@@ -112,13 +112,11 @@ QString TcfEngine::TcfCommand::toString() const
|
|||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TcfEngine::TcfEngine(DebuggerManager *parent) :
|
TcfEngine::TcfEngine(DebuggerManager *parent)
|
||||||
q(parent),
|
|
||||||
qq(parent->engineInterface()),
|
|
||||||
m_models(qq->watchHandler())
|
|
||||||
{
|
{
|
||||||
connect(qq->watchHandler(), SIGNAL(watcherInserted(WatchData)), &m_models, SLOT(insertWatcher(WatchData)));
|
q = parent;
|
||||||
connect(&m_models, SIGNAL(watchDataUpdateNeeded(WatchData)), this, SLOT(updateWatchData(WatchData)));
|
qq = parent->engineInterface();
|
||||||
|
|
||||||
m_congestion = 0;
|
m_congestion = 0;
|
||||||
m_inAir = 0;
|
m_inAir = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
#ifndef DEBUGGER_TCFENGINE_H
|
#ifndef DEBUGGER_TCFENGINE_H
|
||||||
#define DEBUGGER_TCFENGINE_H
|
#define DEBUGGER_TCFENGINE_H
|
||||||
|
|
||||||
#include "asyncwatchmodel.h"
|
|
||||||
|
|
||||||
#include <QtCore/QByteArray>
|
#include <QtCore/QByteArray>
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
@@ -114,11 +112,10 @@ private:
|
|||||||
|
|
||||||
bool supportsThreads() const { return true; }
|
bool supportsThreads() const { return true; }
|
||||||
void maybeBreakNow(bool byFunction);
|
void maybeBreakNow(bool byFunction);
|
||||||
|
void updateWatchData(const WatchData &data);
|
||||||
void updateLocals();
|
void updateLocals();
|
||||||
void updateSubItem(const WatchData &data);
|
void updateSubItem(const WatchData &data);
|
||||||
|
|
||||||
WatchModel *watchModel(int type) const { return m_models.model(type); }
|
|
||||||
|
|
||||||
Q_SLOT void socketConnected();
|
Q_SLOT void socketConnected();
|
||||||
Q_SLOT void socketDisconnected();
|
Q_SLOT void socketDisconnected();
|
||||||
Q_SLOT void socketError(QAbstractSocket::SocketError);
|
Q_SLOT void socketError(QAbstractSocket::SocketError);
|
||||||
@@ -131,7 +128,6 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Q_SLOT void startDebugging();
|
Q_SLOT void startDebugging();
|
||||||
Q_SLOT void updateWatchData(const WatchData &data);
|
|
||||||
|
|
||||||
typedef void (TcfEngine::*TcfCommandCallback)
|
typedef void (TcfEngine::*TcfCommandCallback)
|
||||||
(const JsonValue &record, const QVariant &cookie);
|
(const JsonValue &record, const QVariant &cookie);
|
||||||
@@ -170,7 +166,6 @@ private:
|
|||||||
|
|
||||||
DebuggerManager *q;
|
DebuggerManager *q;
|
||||||
IDebuggerManagerAccessForEngines *qq;
|
IDebuggerManagerAccessForEngines *qq;
|
||||||
AsyncWatchModelMixin m_models;
|
|
||||||
QTcpSocket *m_socket;
|
QTcpSocket *m_socket;
|
||||||
QByteArray m_inbuffer;
|
QByteArray m_inbuffer;
|
||||||
QList<QByteArray> m_services;
|
QList<QByteArray> m_services;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
#include <QtGui/QLabel>
|
#include <QtGui/QLabel>
|
||||||
#include <QtGui/QToolTip>
|
#include <QtGui/QToolTip>
|
||||||
#include <QtGui/QTextEdit>
|
#include <QtGui/QTextEdit>
|
||||||
#include <QtGui/QTreeView>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -68,7 +67,34 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
static const QString strNotInScope =
|
||||||
|
QCoreApplication::translate("Debugger::Internal::WatchData", "<not in scope>");
|
||||||
|
|
||||||
static int watcherCounter = 0;
|
static int watcherCounter = 0;
|
||||||
|
static int generationCounter = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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
|
||||||
@@ -246,125 +272,109 @@ QString WatchData::toToolTip() const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// WatchItem
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
WatchItem::WatchItem() :
|
|
||||||
parent(0),
|
|
||||||
fetchTriggered(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchItem::WatchItem(const WatchData &data) :
|
|
||||||
WatchData(data),
|
|
||||||
parent(0),
|
|
||||||
fetchTriggered(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchItem::setData(const WatchData &data)
|
|
||||||
{
|
|
||||||
static_cast<WatchData &>(*this) = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchItem::~WatchItem()
|
|
||||||
{
|
|
||||||
qDeleteAll(children);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchItem::removeChildren()
|
|
||||||
{
|
|
||||||
if (!children.empty()) {
|
|
||||||
qDeleteAll(children);
|
|
||||||
children.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchItem::addChild(WatchItem *child)
|
|
||||||
{
|
|
||||||
children.push_back(child);
|
|
||||||
child->parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// WatchPredicate
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
WatchPredicate::WatchPredicate(Mode mode, const QString &pattern) :
|
|
||||||
m_pattern(pattern),
|
|
||||||
m_mode(mode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WatchPredicate::operator()(const WatchData &w) const
|
|
||||||
{
|
|
||||||
switch (m_mode) {
|
|
||||||
case INameMatch:
|
|
||||||
return m_pattern == w.iname;
|
|
||||||
case ExpressionMatch:
|
|
||||||
return m_pattern == w.exp;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// WatchModel
|
// WatchModel
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
WatchModel::WatchModel(WatchHandler *handler, WatchType type, QObject *parent) :
|
WatchModel::WatchModel(WatchHandler *handler, WatchType type)
|
||||||
QAbstractItemModel(parent),
|
: QAbstractItemModel(handler), m_handler(handler), m_type(type)
|
||||||
m_root(new WatchItem),
|
|
||||||
m_handler(handler),
|
|
||||||
m_type(type)
|
|
||||||
{
|
{
|
||||||
WatchItem *dummyRoot = new WatchItem;
|
m_root = 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->hasChildren = 1;
|
||||||
m_root->state = 0;
|
m_root->state = 0;
|
||||||
m_root->name = WatchHandler::tr("Root");
|
m_root->name = WatchHandler::tr("Root");
|
||||||
|
|
||||||
|
WatchItem *item = new WatchItem;
|
||||||
|
|
||||||
|
switch (m_type) {
|
||||||
|
case LocalsWatch:
|
||||||
|
item->iname = QLatin1String("local");
|
||||||
|
item->name = WatchHandler::tr("Locals");
|
||||||
|
break;
|
||||||
|
case WatchersWatch:
|
||||||
|
item->iname = QLatin1String("watch");
|
||||||
|
item->name = WatchHandler::tr("Watchers");
|
||||||
|
break;
|
||||||
|
case TooltipsWatch:
|
||||||
|
item->iname = QLatin1String("tooltip");
|
||||||
|
item->name = WatchHandler::tr("Tooltip");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item->hasChildren = true;
|
||||||
|
item->state = 0;
|
||||||
|
item->parent = m_root;
|
||||||
|
item->fetchTriggered = true;
|
||||||
|
|
||||||
|
m_root->children.append(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchModel::~WatchModel()
|
WatchItem *WatchModel::dummyRoot() const
|
||||||
{
|
{
|
||||||
delete m_root;
|
QTC_ASSERT(!m_root->children.isEmpty(), return 0);
|
||||||
|
return m_root->children.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WatchModel::parentName(const QString &iname)
|
void WatchModel::reinitialize()
|
||||||
{
|
{
|
||||||
const int pos = iname.lastIndexOf(QLatin1Char('.'));
|
WatchItem *item = dummyRoot();
|
||||||
|
QTC_ASSERT(item, return);
|
||||||
|
QModelIndex index = watchIndex(item);
|
||||||
|
int n = item->children.size();
|
||||||
|
if (n == 0)
|
||||||
|
return;
|
||||||
|
//MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << item->iname);
|
||||||
|
beginRemoveRows(index, 0, n - 1);
|
||||||
|
qDeleteAll(item->children);
|
||||||
|
item->children.clear();
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchModel::removeOutdated()
|
||||||
|
{
|
||||||
|
WatchItem *item = dummyRoot();
|
||||||
|
QTC_ASSERT(item, return);
|
||||||
|
foreach (WatchItem *child, item->children)
|
||||||
|
removeOutdatedHelper(child);
|
||||||
|
#if DEBUG_MODEL
|
||||||
|
#if USE_MODEL_TEST
|
||||||
|
//(void) new ModelTest(this, this);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchModel::removeOutdatedHelper(WatchItem *item)
|
||||||
|
{
|
||||||
|
if (item->generation < generationCounter)
|
||||||
|
removeItem(item);
|
||||||
|
else {
|
||||||
|
foreach (WatchItem *child, item->children)
|
||||||
|
removeOutdatedHelper(child);
|
||||||
|
item->fetchTriggered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchModel::removeItem(WatchItem *item)
|
||||||
|
{
|
||||||
|
WatchItem *parent = item->parent;
|
||||||
|
QModelIndex index = watchIndex(parent);
|
||||||
|
int n = parent->children.indexOf(item);
|
||||||
|
//MODEL_DEBUG("NEED TO REMOVE: " << item->iname << "AT" << n);
|
||||||
|
beginRemoveRows(index, n, n);
|
||||||
|
parent->children.removeAt(n);
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString parentName(const QString &iname)
|
||||||
|
{
|
||||||
|
int pos = iname.lastIndexOf(QLatin1Char('.'));
|
||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
return QString();
|
return QString();
|
||||||
return iname.left(pos);
|
return iname.left(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static QString chopConst(QString type)
|
static QString chopConst(QString type)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -517,10 +527,51 @@ static QString formattedValue(const WatchData &data,
|
|||||||
return data.value;
|
return data.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WatchModel::columnCount(const QModelIndex &idx) const
|
bool WatchModel::canFetchMore(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(idx);
|
return index.isValid() && !watchItem(index)->fetchTriggered;
|
||||||
return 3;
|
}
|
||||||
|
|
||||||
|
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
|
int WatchModel::rowCount(const QModelIndex &idx) const
|
||||||
@@ -532,15 +583,42 @@ int WatchModel::rowCount(const QModelIndex &idx) const
|
|||||||
return watchItem(idx)->children.size();
|
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)) {
|
Q_UNUSED(idx);
|
||||||
if (!item->children.empty())
|
return 3;
|
||||||
return true;
|
|
||||||
QTC_ASSERT(item->isHasChildrenKnown(), return false);
|
|
||||||
return item->hasChildren;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
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 QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex)
|
void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex)
|
||||||
@@ -557,16 +635,11 @@ void WatchModel::emitDataChanged(int column, const QModelIndex &parentIndex)
|
|||||||
|
|
||||||
QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
||||||
{
|
{
|
||||||
if (const WatchData *wdata = watchItem(idx))
|
const WatchItem &data = *watchItem(idx);
|
||||||
return data(*wdata, idx.column(), role);
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant WatchModel::data(const WatchData &data, int column, int role) const
|
|
||||||
{
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
switch (column) {
|
switch (idx.column()) {
|
||||||
case 0: return data.name;
|
case 0: return data.name;
|
||||||
case 1: return formattedValue(data,
|
case 1: return formattedValue(data,
|
||||||
m_handler->m_individualFormats[data.iname],
|
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 red(QColor(200, 0, 0));
|
||||||
static const QVariant black(QColor(0, 0, 0));
|
static const QVariant black(QColor(0, 0, 0));
|
||||||
static const QVariant gray(QColor(140, 140, 140));
|
static const QVariant gray(QColor(140, 140, 140));
|
||||||
switch (column) {
|
switch (idx.column()) {
|
||||||
case 0: return black;
|
case 0: return black;
|
||||||
case 1: return data.valuedisabled ? gray : data.changed ? red : black;
|
case 1: return data.valuedisabled ? gray : data.changed ? red : black;
|
||||||
case 2: return black;
|
case 2: return black;
|
||||||
@@ -630,7 +703,7 @@ QVariant WatchModel::data(const WatchData &data, int column, int role) const
|
|||||||
|
|
||||||
bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
WatchData &data = *watchItem(index);
|
WatchItem &data = *watchItem(index);
|
||||||
if (role == ExpandedRole) {
|
if (role == ExpandedRole) {
|
||||||
if (value.toBool())
|
if (value.toBool())
|
||||||
m_handler->m_expandedINames.insert(data.iname);
|
m_handler->m_expandedINames.insert(data.iname);
|
||||||
@@ -690,159 +763,72 @@ QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int ro
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::setValueByIName(const QString &iname, const QString &value)
|
static bool iNameSorter(const WatchItem *item1, const WatchItem *item2)
|
||||||
{
|
{
|
||||||
if (WatchItem *wd = findItemByIName(iname, dummyRoot())) {
|
QString name1 = item1->iname.section('.', -1);
|
||||||
if (wd->value != value) {
|
QString name2 = item2->iname.section('.', -1);
|
||||||
wd->setValue(value);
|
if (!name1.isEmpty() && !name2.isEmpty()) {
|
||||||
const QModelIndex index = watchIndex(wd);
|
if (name1.at(0).isDigit() && name2.at(0).isDigit())
|
||||||
emit dataChanged(index.sibling(0, 1), index.sibling(0, 2));
|
return name1.toInt() < name2.toInt();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return name1 < name2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::setValueByExpression(const QString &exp, const QString &value)
|
static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *item)
|
||||||
{
|
{
|
||||||
if (WatchItem *wd = findItemByExpression(exp, dummyRoot())) {
|
QList<WatchItem *>::const_iterator it =
|
||||||
if (wd->value != value) {
|
qLowerBound(list.begin(), list.end(), item, iNameSorter);
|
||||||
wd->setValue(value);
|
return it - list.begin();
|
||||||
const QModelIndex index = watchIndex(wd);
|
|
||||||
emit dataChanged(index.sibling(0, 1), index.sibling(0, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchItem *WatchModel::root() const
|
void WatchModel::insertData(const WatchData &data)
|
||||||
{
|
{
|
||||||
return m_root;
|
// qDebug() << "WMI:" << data.toString();
|
||||||
}
|
QTC_ASSERT(!data.iname.isEmpty(), return);
|
||||||
|
WatchItem *parent = findItem(parentName(data.iname), m_root);
|
||||||
WatchItem *WatchModel::dummyRoot() const
|
if (!parent) {
|
||||||
{
|
WatchData parent;
|
||||||
if (!m_root->children.isEmpty())
|
parent.iname = parentName(data.iname);
|
||||||
return m_root->children.front();
|
insertData(parent);
|
||||||
return 0;
|
//MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
|
||||||
}
|
|
||||||
|
|
||||||
void WatchModel::reinitialize()
|
|
||||||
{
|
|
||||||
WatchItem *item = dummyRoot();
|
|
||||||
QTC_ASSERT(item, return);
|
|
||||||
const QModelIndex index = watchIndex(item);
|
|
||||||
const int n = item->children.size();
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
return;
|
||||||
//MODEL_DEBUG("REMOVING " << n << " CHILDREN OF " << item->iname);
|
}
|
||||||
beginRemoveRows(index, 0, n - 1);
|
QModelIndex index = watchIndex(parent);
|
||||||
item->removeChildren();
|
if (WatchItem *oldItem = findItem(data.iname, parent)) {
|
||||||
endRemoveRows();
|
// 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchModel::removeItem(WatchItem *itemIn)
|
WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const
|
||||||
{
|
{
|
||||||
WatchItem *item = static_cast<WatchItem *>(itemIn);
|
if (root->iname == iname)
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static WatchItem *findRecursion(WatchItem *root, const WatchPredicate &p)
|
|
||||||
{
|
|
||||||
if (p(*root))
|
|
||||||
return root;
|
return root;
|
||||||
for (int i = root->children.size(); --i >= 0; )
|
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 item;
|
||||||
return 0;
|
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() :
|
WatchHandler::WatchHandler()
|
||||||
m_expandPointers(true),
|
|
||||||
m_inChange(false)
|
|
||||||
{
|
{
|
||||||
|
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),
|
connect(theDebuggerAction(WatchExpression),
|
||||||
SIGNAL(triggered()), this, SLOT(watchExpression()));
|
SIGNAL(triggered()), this, SLOT(watchExpression()));
|
||||||
connect(theDebuggerAction(RemoveWatchExpression),
|
connect(theDebuggerAction(RemoveWatchExpression),
|
||||||
SIGNAL(triggered()), this, SLOT(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()
|
void WatchHandler::cleanup()
|
||||||
{
|
{
|
||||||
m_expandedINames.clear();
|
m_expandedINames.clear();
|
||||||
m_displayedINames.clear();
|
m_displayedINames.clear();
|
||||||
if (m_models[LocalsWatch])
|
m_locals->reinitialize();
|
||||||
m_models[LocalsWatch]->reinitialize();
|
m_tooltips->reinitialize();
|
||||||
if (m_models[TooltipsWatch])
|
|
||||||
m_models[TooltipsWatch]->reinitialize();
|
|
||||||
#if 0
|
#if 0
|
||||||
for (EditWindows::ConstIterator it = m_editWindows.begin();
|
for (EditWindows::ConstIterator it = m_editWindows.begin();
|
||||||
it != m_editWindows.end(); ++it) {
|
it != m_editWindows.end(); ++it) {
|
||||||
@@ -879,12 +874,26 @@ void WatchHandler::cleanup()
|
|||||||
#endif
|
#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)
|
void WatchHandler::removeData(const QString &iname)
|
||||||
{
|
{
|
||||||
WatchModel *model = modelForIName(iname);
|
WatchModel *model = modelForIName(iname);
|
||||||
if (!model)
|
if (!model)
|
||||||
return;
|
return;
|
||||||
if (WatchItem *item = model->findItemByIName(iname, model->root()))
|
WatchItem *item = model->findItem(iname, model->m_root);
|
||||||
|
if (item)
|
||||||
model->removeItem(item);
|
model->removeItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,7 +918,7 @@ void WatchHandler::watchExpression(const QString &exp)
|
|||||||
if (exp.isEmpty() || exp == watcherEditPlaceHolder())
|
if (exp.isEmpty() || exp == watcherEditPlaceHolder())
|
||||||
data.setAllUnneeded();
|
data.setAllUnneeded();
|
||||||
data.iname = watcherName(exp);
|
data.iname = watcherName(exp);
|
||||||
emit watcherInserted(data);
|
insertData(data);
|
||||||
saveWatchers();
|
saveWatchers();
|
||||||
//emit watchModelUpdateRequested();
|
//emit watchModelUpdateRequested();
|
||||||
}
|
}
|
||||||
@@ -999,10 +1008,32 @@ void WatchHandler::removeWatchExpression(const QString &exp)
|
|||||||
{
|
{
|
||||||
MODEL_DEBUG("REMOVE WATCH: " << exp);
|
MODEL_DEBUG("REMOVE WATCH: " << exp);
|
||||||
m_watcherNames.remove(exp);
|
m_watcherNames.remove(exp);
|
||||||
if (WatchModel *model = m_models[WatchersWatch])
|
foreach (WatchItem *item, m_watchers->dummyRoot()->children) {
|
||||||
if (WatchItem *item = model->findItemByExpression(exp, model->root())) {
|
if (item->exp == exp) {
|
||||||
model->removeItem(item);
|
m_watchers->removeItem(item);
|
||||||
saveWatchers();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1045,11 +1076,6 @@ void WatchHandler::loadTypeFormats()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList WatchHandler::watcherExpressions() const
|
|
||||||
{
|
|
||||||
return m_watcherNames.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchHandler::saveTypeFormats()
|
void WatchHandler::saveTypeFormats()
|
||||||
{
|
{
|
||||||
QMap<QString, QVariant> typeFormats;
|
QMap<QString, QVariant> typeFormats;
|
||||||
@@ -1073,61 +1099,44 @@ void WatchHandler::loadSessionData()
|
|||||||
{
|
{
|
||||||
loadWatchers();
|
loadWatchers();
|
||||||
loadTypeFormats();
|
loadTypeFormats();
|
||||||
initWatchModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WatchHandler::initWatchModel()
|
|
||||||
{
|
|
||||||
foreach (const QString &exp, m_watcherNames.keys()) {
|
foreach (const QString &exp, m_watcherNames.keys()) {
|
||||||
WatchData data;
|
WatchData data;
|
||||||
data.iname = watcherName(exp);
|
data.iname = watcherName(exp);
|
||||||
data.setAllUnneeded();
|
data.setAllUnneeded();
|
||||||
data.name = exp;
|
data.name = exp;
|
||||||
data.exp = exp;
|
data.exp = exp;
|
||||||
emit watcherInserted(data);
|
insertData(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchModel *WatchHandler::model(WatchType type) const
|
WatchModel *WatchHandler::model(WatchType type) const
|
||||||
{
|
{
|
||||||
return m_models[type];
|
switch (type) {
|
||||||
|
case LocalsWatch: return m_locals;
|
||||||
|
case WatchersWatch: return m_watchers;
|
||||||
|
case TooltipsWatch: return m_tooltips;
|
||||||
}
|
}
|
||||||
|
QTC_ASSERT(false, /**/);
|
||||||
void WatchHandler::setModel(WatchType type, WatchModel *model)
|
return 0;
|
||||||
{
|
|
||||||
if (m_models[type] == model)
|
|
||||||
return;
|
|
||||||
if (type == WatchersWatch && m_models[type])
|
|
||||||
saveWatchers();
|
|
||||||
m_models[type] = model;
|
|
||||||
if (type == WatchersWatch)
|
|
||||||
initWatchModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
WatchType WatchHandler::watchTypeOfIName(const QString &iname)
|
|
||||||
{
|
|
||||||
if (iname.startsWith(QLatin1String("local.")))
|
|
||||||
return LocalsWatch;
|
|
||||||
if (iname.startsWith(QLatin1String("watch.")))
|
|
||||||
return WatchersWatch;
|
|
||||||
if (iname.startsWith(QLatin1String("tooltip")))
|
|
||||||
return TooltipsWatch;
|
|
||||||
return WatchModelCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchModel *WatchHandler::modelForIName(const QString &iname) const
|
WatchModel *WatchHandler::modelForIName(const QString &iname) const
|
||||||
{
|
{
|
||||||
const WatchType t = watchTypeOfIName(iname);
|
if (iname.startsWith(QLatin1String("local.")))
|
||||||
if (t == WatchModelCount)
|
return m_locals;
|
||||||
|
if (iname.startsWith(QLatin1String("watch.")))
|
||||||
|
return m_watchers;
|
||||||
|
if (iname.startsWith(QLatin1String("tooltip")))
|
||||||
|
return m_tooltips;
|
||||||
|
QTC_ASSERT(false, /**/);
|
||||||
return 0;
|
return 0;
|
||||||
return m_models[t];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchData *WatchHandler::findItem(const QString &iname) const
|
WatchData *WatchHandler::findItem(const QString &iname) const
|
||||||
{
|
{
|
||||||
const WatchModel *model = modelForIName(iname);
|
const WatchModel *model = modelForIName(iname);
|
||||||
QTC_ASSERT(model, return 0);
|
QTC_ASSERT(model, return 0);
|
||||||
return model->findItemByIName(iname, model->root());
|
return model->findItem(iname, model->m_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WatchHandler::watcherEditPlaceHolder()
|
QString WatchHandler::watcherEditPlaceHolder()
|
||||||
@@ -1140,55 +1149,9 @@ void WatchHandler::setFormat(const QString &type, int format)
|
|||||||
{
|
{
|
||||||
m_typeFormats[type] = format;
|
m_typeFormats[type] = format;
|
||||||
saveTypeFormats();
|
saveTypeFormats();
|
||||||
for (int m = 0; m < WatchModelCount; m++)
|
m_locals->emitDataChanged(1);
|
||||||
m_models[m]->emitDataChanged(1);
|
m_watchers->emitDataChanged(1);
|
||||||
}
|
m_tooltips->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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -32,21 +32,19 @@
|
|||||||
|
|
||||||
#include <QtCore/QPointer>
|
#include <QtCore/QPointer>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QStringList>
|
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QtCore/QSet>
|
#include <QtCore/QSet>
|
||||||
#include <QtCore/QAbstractItemModel>
|
#include <QtGui/QStandardItem>
|
||||||
|
#include <QtGui/QStandardItemModel>
|
||||||
|
#include <QtGui/QTreeView>
|
||||||
#include <QtScript/QScriptValue>
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QTreeView;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class WatchItem;
|
||||||
class WatchHandler;
|
class WatchHandler;
|
||||||
enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch, WatchModelCount };
|
enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch };
|
||||||
|
|
||||||
class WatchData
|
class WatchData
|
||||||
{
|
{
|
||||||
@@ -162,95 +160,51 @@ enum DumpableFormat
|
|||||||
PlainFomat,
|
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
|
class WatchModel : public QAbstractItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
|
||||||
explicit WatchModel(WatchHandler *handler, WatchType type, QObject *parent = 0);
|
|
||||||
virtual ~WatchModel();
|
|
||||||
|
|
||||||
virtual QModelIndex index(int, int, const QModelIndex &idx = QModelIndex()) const;
|
private:
|
||||||
|
explicit WatchModel(WatchHandler *handler, WatchType type);
|
||||||
|
|
||||||
virtual int columnCount(const QModelIndex &idx= QModelIndex()) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
virtual int rowCount(const QModelIndex &idx) const;
|
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||||
virtual bool hasChildren(const QModelIndex &idx) const;
|
QModelIndex index(int, int, const QModelIndex &idx) const;
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
QModelIndex parent(const QModelIndex &idx) const;
|
||||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
|
int rowCount(const QModelIndex &idx) const;
|
||||||
|
int columnCount(const QModelIndex &idx) const;
|
||||||
virtual Qt::ItemFlags flags(const QModelIndex &idx) const;
|
bool hasChildren(const QModelIndex &idx) const;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
Qt::ItemFlags flags(const QModelIndex &idx) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
|
bool canFetchMore(const QModelIndex &parent) const;
|
||||||
|
void fetchMore(const QModelIndex &parent);
|
||||||
|
|
||||||
virtual QModelIndex parent(const QModelIndex &idx) const;
|
friend class WatchHandler;
|
||||||
|
friend class GdbEngine;
|
||||||
|
|
||||||
WatchItem *watchItem(const QModelIndex &) const;
|
WatchItem *watchItem(const QModelIndex &) const;
|
||||||
QModelIndex watchIndex(const WatchItem *needle) const;
|
QModelIndex watchIndex(const WatchItem *needle) const;
|
||||||
QModelIndex watchIndexHelper(const WatchItem *needle,
|
QModelIndex watchIndexHelper(const WatchItem *needle,
|
||||||
const WatchItem *parentItem, const QModelIndex &parentIndex) const;
|
const WatchItem *parentItem, const QModelIndex &parentIndex) const;
|
||||||
|
|
||||||
WatchItem *findItemByIName(const QString &iname, WatchItem *root) const;
|
void insertData(const WatchData &data);
|
||||||
WatchItem *findItemByExpression(const QString &iname, WatchItem *root) const;
|
WatchItem *findItem(const QString &iname, WatchItem *root) const;
|
||||||
void reinitialize();
|
void reinitialize();
|
||||||
|
void removeOutdated();
|
||||||
void removeItem(WatchItem *item);
|
void removeOutdatedHelper(WatchItem *item);
|
||||||
WatchItem *root() const;
|
|
||||||
|
|
||||||
WatchItem *dummyRoot() const;
|
WatchItem *dummyRoot() const;
|
||||||
|
void removeItem(WatchItem *item);
|
||||||
|
void setActiveData(const QString &data) { m_activeData = data; }
|
||||||
|
|
||||||
void setValueByIName(const QString &iname, const QString &value);
|
void emitDataChanged(int column,
|
||||||
void setValueByExpression(const QString &iname, const QString &value);
|
const QModelIndex &parentIndex = QModelIndex());
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WatchItem *m_root;
|
|
||||||
WatchHandler *m_handler;
|
WatchHandler *m_handler;
|
||||||
const WatchType m_type;
|
WatchType m_type;
|
||||||
};
|
WatchItem *m_root;
|
||||||
|
QString m_activeData;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WatchHandler : public QObject
|
class WatchHandler : public QObject
|
||||||
@@ -259,25 +213,21 @@ class WatchHandler : public QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
WatchHandler();
|
WatchHandler();
|
||||||
void init(QTreeView *localsView);
|
|
||||||
|
|
||||||
WatchModel *model(WatchType type) const;
|
WatchModel *model(WatchType type) const;
|
||||||
static WatchType watchTypeOfIName(const QString &iname);
|
|
||||||
WatchModel *modelForIName(const QString &data) const;
|
WatchModel *modelForIName(const QString &data) const;
|
||||||
|
|
||||||
QStringList watcherExpressions() const;
|
|
||||||
QString watcherName(const QString &exp);
|
|
||||||
|
|
||||||
void setModel(WatchType type, WatchModel *model);
|
|
||||||
|
|
||||||
//public slots:
|
//public slots:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
Q_SLOT void watchExpression(); // data in action->data().toString()
|
Q_SLOT void watchExpression(); // data in action->data().toString()
|
||||||
Q_SLOT void watchExpression(const QString &exp);
|
Q_SLOT void watchExpression(const QString &exp);
|
||||||
Q_SLOT void removeWatchExpression();
|
Q_SLOT void removeWatchExpression();
|
||||||
Q_SLOT void removeWatchExpression(const QString &exp);
|
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 showEditValue(const WatchData &data);
|
||||||
|
|
||||||
|
void insertData(const WatchData &data);
|
||||||
void removeData(const QString &iname);
|
void removeData(const QString &iname);
|
||||||
WatchData *findItem(const QString &iname) const;
|
WatchData *findItem(const QString &iname) const;
|
||||||
|
|
||||||
@@ -291,32 +241,18 @@ public:
|
|||||||
QSet<QString> expandedINames() const
|
QSet<QString> expandedINames() const
|
||||||
{ return m_expandedINames; }
|
{ 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();
|
static QString watcherEditPlaceHolder();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void watcherInserted(const WatchData &data);
|
void watchDataUpdateNeeded(const WatchData &data);
|
||||||
void sessionValueRequested(const QString &name, QVariant *value);
|
void sessionValueRequested(const QString &name, QVariant *value);
|
||||||
void setSessionValueRequested(const QString &name, const QVariant &value);
|
void setSessionValueRequested(const QString &name, const QVariant &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WatchModel; // needs formats, expanded inames
|
friend class WatchModel;
|
||||||
|
|
||||||
// Per stack-frame locals state
|
|
||||||
struct LocalsViewState {
|
|
||||||
LocalsViewState() : firstVisibleRow(0) {}
|
|
||||||
int firstVisibleRow;
|
|
||||||
QSet<QString> expandedINames;
|
|
||||||
};
|
|
||||||
typedef QMap<int, LocalsViewState> LocalsViewStateMap;
|
|
||||||
|
|
||||||
void loadWatchers();
|
void loadWatchers();
|
||||||
void saveWatchers();
|
void saveWatchers();
|
||||||
void initWatchModel();
|
|
||||||
|
|
||||||
void loadTypeFormats();
|
void loadTypeFormats();
|
||||||
void saveTypeFormats();
|
void saveTypeFormats();
|
||||||
@@ -329,16 +265,17 @@ private:
|
|||||||
EditWindows m_editWindows;
|
EditWindows m_editWindows;
|
||||||
|
|
||||||
QHash<QString, int> m_watcherNames;
|
QHash<QString, int> m_watcherNames;
|
||||||
|
QString watcherName(const QString &exp);
|
||||||
QHash<QString, int> m_typeFormats;
|
QHash<QString, int> m_typeFormats;
|
||||||
QHash<QString, int> m_individualFormats;
|
QHash<QString, int> m_individualFormats;
|
||||||
|
|
||||||
void setDisplayedIName(const QString &iname, bool on);
|
void setDisplayedIName(const QString &iname, bool on);
|
||||||
QSet<QString> m_expandedINames; // those expanded in the treeview
|
QSet<QString> m_expandedINames; // those expanded in the treeview
|
||||||
QSet<QString> m_displayedINames; // those with "external" viewers
|
QSet<QString> m_displayedINames; // those with "external" viewers
|
||||||
LocalsViewStateMap m_localsViewState;
|
|
||||||
|
|
||||||
WatchModel *m_models[WatchModelCount];
|
WatchModel *m_locals;
|
||||||
QPointer<QTreeView> m_localsView;
|
WatchModel *m_watchers;
|
||||||
|
WatchModel *m_tooltips;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -554,9 +554,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
|
|||||||
}
|
}
|
||||||
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
||||||
wchild.setAddress(dchild.address);
|
wchild.setAddress(dchild.address);
|
||||||
// Child overrides. Note that WatchData::setType sets
|
// Child overrides.
|
||||||
// childcount = 0 for some known types.
|
|
||||||
if (wchild.isHasChildrenNeeded()) {
|
|
||||||
const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
|
const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
|
||||||
switch (effectiveChildChildCount) {
|
switch (effectiveChildChildCount) {
|
||||||
case -1:
|
case -1:
|
||||||
@@ -572,7 +570,6 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
QDebug nospace = qDebug().nospace();
|
QDebug nospace = qDebug().nospace();
|
||||||
nospace << "QtDumperResult::toWatchData" << *this << '\n';
|
nospace << "QtDumperResult::toWatchData" << *this << '\n';
|
||||||
|
|||||||
@@ -327,11 +327,9 @@ void WatchWindow::editItem(const QModelIndex &idx)
|
|||||||
Q_UNUSED(idx); // FIXME
|
Q_UNUSED(idx); // FIXME
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchWindow::setModel(QAbstractItemModel *newModel)
|
void WatchWindow::setModel(QAbstractItemModel *model)
|
||||||
{
|
{
|
||||||
if (model() == newModel)
|
QTreeView::setModel(model);
|
||||||
return;
|
|
||||||
QTreeView::setModel(newModel);
|
|
||||||
|
|
||||||
setRootIsDecorated(true);
|
setRootIsDecorated(true);
|
||||||
header()->setDefaultAlignment(Qt::AlignLeft);
|
header()->setDefaultAlignment(Qt::AlignLeft);
|
||||||
@@ -339,7 +337,7 @@ void WatchWindow::setModel(QAbstractItemModel *newModel)
|
|||||||
if (m_type != LocalsType)
|
if (m_type != LocalsType)
|
||||||
header()->hide();
|
header()->hide();
|
||||||
|
|
||||||
connect(newModel, SIGNAL(layoutChanged()), this, SLOT(resetHelper()));
|
connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchWindow::resetHelper()
|
void WatchWindow::resetHelper()
|
||||||
|
|||||||
Reference in New Issue
Block a user