2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
|
** Contact: http://www.qt.io/licensing
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-14 18:07:15 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms and
|
|
|
|
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
2014-10-01 13:21:18 +02:00
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-10-01 13:21:18 +02:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2015-01-14 18:07:15 +01:00
|
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "watchhandler.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
|
|
|
|
|
#include "breakhandler.h"
|
2009-03-19 09:32:09 +01:00
|
|
|
#include "debuggeractions.h"
|
2010-11-10 11:39:01 +01:00
|
|
|
#include "debuggercore.h"
|
2011-11-07 20:07:14 +01:00
|
|
|
#include "debuggerdialogs.h"
|
2013-01-24 11:19:15 +01:00
|
|
|
#include "debuggerengine.h"
|
|
|
|
|
#include "debuggerinternalconstants.h"
|
|
|
|
|
#include "debuggerprotocol.h"
|
2015-09-14 12:53:35 +02:00
|
|
|
#include "debuggertooltipmanager.h"
|
2014-01-15 12:04:23 +01:00
|
|
|
#include "simplifytype.h"
|
2013-01-08 16:20:26 +01:00
|
|
|
#include "imageviewer.h"
|
2013-01-24 11:19:15 +01:00
|
|
|
#include "watchutils.h"
|
2015-03-20 16:03:59 +01:00
|
|
|
#include "cdb/cdbengine.h" // Remove after string freeze
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-12-02 08:56:33 +01:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2014-07-03 11:01:53 +02:00
|
|
|
#include <utils/basetreeview.h>
|
2008-12-09 16:18:28 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2010-03-18 10:59:06 +01:00
|
|
|
#include <utils/savedaction.h>
|
2014-12-02 08:56:33 +01:00
|
|
|
#include <utils/checkablemessagebox.h>
|
2015-03-19 20:44:18 +01:00
|
|
|
#include <utils/theme/theme.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
2014-01-08 14:10:56 +01:00
|
|
|
#include <QFile>
|
2015-12-16 17:17:38 +01:00
|
|
|
#include <QJsonArray>
|
|
|
|
|
#include <QJsonObject>
|
2015-04-01 17:19:43 +02:00
|
|
|
#include <QPainter>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QProcess>
|
2013-06-07 17:57:25 +02:00
|
|
|
#include <QTabWidget>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QTextEdit>
|
2015-03-16 13:36:35 +01:00
|
|
|
#include <QTimer>
|
2015-12-16 17:17:38 +01:00
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
#include <algorithm>
|
2014-08-28 17:33:47 +02:00
|
|
|
#include <cstring>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <ctype.h>
|
2009-04-02 11:41:36 +02:00
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2009-06-17 16:00:03 +02:00
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-01-25 10:59:45 +01:00
|
|
|
// Creates debug output for accesses to the model.
|
|
|
|
|
enum { debugModel = 0 };
|
|
|
|
|
|
|
|
|
|
#define MODEL_DEBUG(s) do { if (debugModel) qDebug() << s; } while (0)
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2012-03-14 12:26:27 +01:00
|
|
|
static QHash<QByteArray, int> theWatcherNames;
|
2015-03-16 09:10:36 +01:00
|
|
|
static int theWatcherCount = 0;
|
2012-03-14 12:26:27 +01:00
|
|
|
static QHash<QByteArray, int> theTypeFormats;
|
|
|
|
|
static QHash<QByteArray, int> theIndividualFormats;
|
|
|
|
|
static int theUnprintableBase = -1;
|
|
|
|
|
|
2014-05-17 21:00:22 +02:00
|
|
|
const char INameProperty[] = "INameProperty";
|
|
|
|
|
const char KeyProperty[] = "KeyProperty";
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static const WatchModel *watchModel(const WatchItem *item)
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<const WatchModel *>(item->model());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
|
void readNumericVectorHelper(std::vector<double> *v, const QByteArray &ba)
|
|
|
|
|
{
|
|
|
|
|
const T *p = (const T *) ba.data();
|
|
|
|
|
const int n = ba.size() / sizeof(T);
|
|
|
|
|
v->resize(n);
|
|
|
|
|
// Losing precision in case of 64 bit ints is ok here, as the result
|
|
|
|
|
// is only used to plot data.
|
|
|
|
|
for (int i = 0; i != n; ++i)
|
|
|
|
|
(*v)[i] = static_cast<double>(p[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void readNumericVector(std::vector<double> *v, const QByteArray &rawData, DebuggerEncoding encoding)
|
|
|
|
|
{
|
|
|
|
|
switch (encoding.type) {
|
|
|
|
|
case DebuggerEncoding::HexEncodedSignedInteger:
|
|
|
|
|
switch (encoding.size) {
|
|
|
|
|
case 1:
|
|
|
|
|
readNumericVectorHelper<signed char>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 2:
|
|
|
|
|
readNumericVectorHelper<short>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 4:
|
|
|
|
|
readNumericVectorHelper<int>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 8:
|
|
|
|
|
readNumericVectorHelper<qint64>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case DebuggerEncoding::HexEncodedUnsignedInteger:
|
|
|
|
|
switch (encoding.size) {
|
|
|
|
|
case 1:
|
|
|
|
|
readNumericVectorHelper<char>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 2:
|
|
|
|
|
readNumericVectorHelper<unsigned short>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 4:
|
|
|
|
|
readNumericVectorHelper<unsigned int>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 8:
|
|
|
|
|
readNumericVectorHelper<quint64>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case DebuggerEncoding::HexEncodedFloat:
|
|
|
|
|
switch (encoding.size) {
|
|
|
|
|
case 4:
|
|
|
|
|
readNumericVectorHelper<float>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
case 8:
|
|
|
|
|
readNumericVectorHelper<double>(v, rawData);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "ENCODING ERROR: " << encoding.toString();
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-30 11:09:10 +01:00
|
|
|
static QByteArray stripForFormat(const QByteArray &ba)
|
|
|
|
|
{
|
|
|
|
|
QByteArray res;
|
|
|
|
|
res.reserve(ba.size());
|
|
|
|
|
int inArray = 0;
|
|
|
|
|
for (int i = 0; i != ba.size(); ++i) {
|
|
|
|
|
const char c = ba.at(i);
|
|
|
|
|
if (c == '<')
|
|
|
|
|
break;
|
|
|
|
|
if (c == '[')
|
|
|
|
|
++inArray;
|
|
|
|
|
if (c == ']')
|
|
|
|
|
--inArray;
|
|
|
|
|
if (c == ' ')
|
|
|
|
|
continue;
|
2012-07-19 23:35:41 +02:00
|
|
|
if (c == '&') // Treat references like the referenced type.
|
|
|
|
|
continue;
|
2011-11-30 11:09:10 +01:00
|
|
|
if (inArray && c >= '0' && c <= '9')
|
|
|
|
|
continue;
|
|
|
|
|
res.append(c);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
2011-05-17 11:30:44 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 13:18:36 +01:00
|
|
|
static void saveWatchers()
|
|
|
|
|
{
|
|
|
|
|
setSessionValue("Watchers", WatchHandler::watchedExpressions());
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
static void loadFormats()
|
|
|
|
|
{
|
|
|
|
|
QVariant value = sessionValue("DefaultFormats");
|
|
|
|
|
QMapIterator<QString, QVariant> it(value.toMap());
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (!it.key().isEmpty())
|
|
|
|
|
theTypeFormats.insert(it.key().toUtf8(), it.value().toInt());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = sessionValue("IndividualFormats");
|
|
|
|
|
it = QMapIterator<QString, QVariant>(value.toMap());
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (!it.key().isEmpty())
|
|
|
|
|
theIndividualFormats.insert(it.key().toUtf8(), it.value().toInt());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void saveFormats()
|
|
|
|
|
{
|
|
|
|
|
QMap<QString, QVariant> formats;
|
|
|
|
|
QHashIterator<QByteArray, int> it(theTypeFormats);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const int format = it.value();
|
|
|
|
|
if (format != AutomaticFormat) {
|
|
|
|
|
const QByteArray key = it.key().trimmed();
|
|
|
|
|
if (!key.isEmpty())
|
|
|
|
|
formats.insert(QString::fromLatin1(key), format);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setSessionValue("DefaultFormats", formats);
|
|
|
|
|
|
|
|
|
|
formats.clear();
|
|
|
|
|
it = QHashIterator<QByteArray, int>(theIndividualFormats);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const int format = it.value();
|
|
|
|
|
const QByteArray key = it.key().trimmed();
|
|
|
|
|
if (!key.isEmpty())
|
|
|
|
|
formats.insert(QString::fromLatin1(key), format);
|
|
|
|
|
}
|
|
|
|
|
setSessionValue("IndividualFormats", formats);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-13 09:11:07 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
2009-06-17 16:00:03 +02:00
|
|
|
//
|
2014-11-07 13:50:09 +01:00
|
|
|
// SeparatedView
|
2009-06-17 16:00:03 +02:00
|
|
|
//
|
2009-07-13 09:11:07 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
2009-06-17 16:00:03 +02:00
|
|
|
|
2014-05-17 21:00:22 +02:00
|
|
|
class SeparatedView : public QTabWidget
|
2012-12-30 22:35:25 -06:00
|
|
|
{
|
|
|
|
|
public:
|
2014-10-22 13:04:47 +02:00
|
|
|
SeparatedView() : QTabWidget(Internal::mainWindow())
|
2012-12-30 22:35:25 -06:00
|
|
|
{
|
|
|
|
|
setTabsClosable(true);
|
2014-11-07 13:50:09 +01:00
|
|
|
connect(this, &QTabWidget::tabCloseRequested, this, &SeparatedView::closeTab);
|
2012-12-30 22:35:25 -06:00
|
|
|
setWindowFlags(windowFlags() | Qt::Window);
|
|
|
|
|
setWindowTitle(WatchHandler::tr("Debugger - Qt Creator"));
|
2014-05-17 21:00:22 +02:00
|
|
|
|
2014-07-28 14:23:52 +02:00
|
|
|
QVariant geometry = sessionValue("DebuggerSeparateWidgetGeometry");
|
2015-04-01 17:19:43 +02:00
|
|
|
if (geometry.isValid()) {
|
|
|
|
|
QRect rc = geometry.toRect();
|
|
|
|
|
if (rc.width() < 200)
|
|
|
|
|
rc.setWidth(200);
|
|
|
|
|
if (rc.height() < 200)
|
|
|
|
|
rc.setHeight(200);
|
|
|
|
|
setGeometry(rc);
|
|
|
|
|
}
|
2014-05-17 21:00:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
void saveGeometry()
|
2014-05-17 21:00:22 +02:00
|
|
|
{
|
2014-07-28 14:23:52 +02:00
|
|
|
setSessionValue("DebuggerSeparateWidgetGeometry", geometry());
|
2012-12-30 22:35:25 -06:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
~SeparatedView()
|
|
|
|
|
{
|
|
|
|
|
saveGeometry();
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-17 21:00:22 +02:00
|
|
|
void removeObject(const QByteArray &key)
|
2012-12-30 22:35:25 -06:00
|
|
|
{
|
2015-04-01 17:19:43 +02:00
|
|
|
saveGeometry();
|
2014-05-17 21:00:22 +02:00
|
|
|
if (QWidget *w = findWidget(key)) {
|
|
|
|
|
removeTab(indexOf(w));
|
|
|
|
|
sanitize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-07 13:50:09 +01:00
|
|
|
void closeTab(int index)
|
2014-05-17 21:00:22 +02:00
|
|
|
{
|
2015-04-01 17:19:43 +02:00
|
|
|
saveGeometry();
|
2014-05-17 21:00:22 +02:00
|
|
|
if (QObject *o = widget(index)) {
|
|
|
|
|
QByteArray iname = o->property(INameProperty).toByteArray();
|
|
|
|
|
theIndividualFormats.remove(iname);
|
2015-04-01 17:19:43 +02:00
|
|
|
saveFormats();
|
2014-05-17 21:00:22 +02:00
|
|
|
}
|
2012-12-30 22:35:25 -06:00
|
|
|
removeTab(index);
|
2014-05-17 21:00:22 +02:00
|
|
|
sanitize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sanitize()
|
|
|
|
|
{
|
|
|
|
|
if (count() == 0)
|
|
|
|
|
hide();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QWidget *findWidget(const QByteArray &needle)
|
|
|
|
|
{
|
|
|
|
|
for (int i = count(); --i >= 0; ) {
|
|
|
|
|
QWidget *w = widget(i);
|
|
|
|
|
QByteArray key = w->property(KeyProperty).toByteArray();
|
|
|
|
|
if (key == needle)
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
template <class T> T *prepareObject(const QByteArray &key, const QString &tabName)
|
2014-05-17 21:00:22 +02:00
|
|
|
{
|
|
|
|
|
T *t = 0;
|
|
|
|
|
if (QWidget *w = findWidget(key)) {
|
|
|
|
|
t = qobject_cast<T *>(w);
|
|
|
|
|
if (!t)
|
|
|
|
|
removeTab(indexOf(w));
|
|
|
|
|
}
|
|
|
|
|
if (!t) {
|
|
|
|
|
t = new T;
|
|
|
|
|
t->setProperty(KeyProperty, key);
|
2015-04-01 17:19:43 +02:00
|
|
|
addTab(t, tabName);
|
2014-05-17 21:00:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setCurrentWidget(t);
|
|
|
|
|
show();
|
|
|
|
|
raise();
|
|
|
|
|
return t;
|
2012-12-30 22:35:25 -06:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-05-17 21:00:22 +02:00
|
|
|
|
2014-11-07 13:50:09 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// WatchModel
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
2009-06-17 16:00:03 +02:00
|
|
|
|
2014-11-07 13:50:09 +01:00
|
|
|
class WatchModel : public WatchModelBase
|
|
|
|
|
{
|
2015-03-23 12:41:06 +03:00
|
|
|
Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::WatchModel)
|
2012-05-18 02:28:41 +02:00
|
|
|
public:
|
2015-03-20 13:18:36 +01:00
|
|
|
WatchModel(WatchHandler *handler, DebuggerEngine *engine);
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
static QString nameForFormat(int format);
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
QVariant data(const QModelIndex &idx, int role) const override;
|
|
|
|
|
bool setData(const QModelIndex &idx, const QVariant &value, int role) override;
|
|
|
|
|
|
|
|
|
|
Qt::ItemFlags flags(const QModelIndex &idx) const override;
|
|
|
|
|
bool hasChildren(const QModelIndex &idx) const override;
|
|
|
|
|
bool canFetchMore(const QModelIndex &idx) const override;
|
|
|
|
|
void fetchMore(const QModelIndex &idx) override;
|
2012-05-18 02:28:41 +02:00
|
|
|
|
|
|
|
|
QString displayForAutoTest(const QByteArray &iname) const;
|
2012-10-09 16:13:29 +02:00
|
|
|
void reinitialize(bool includeInspectData = false);
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
WatchItem *findItem(const QByteArray &iname) const;
|
2015-12-16 17:17:38 +01:00
|
|
|
const WatchItem *watchItem(const QModelIndex &idx) const;
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
void insertItem(WatchItem *item);
|
|
|
|
|
void reexpandItems();
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
void showEditValue(const WatchItem *item);
|
|
|
|
|
void setTypeFormat(const QByteArray &type, int format);
|
|
|
|
|
void setIndividualFormat(const QByteArray &iname, int format);
|
2012-05-18 02:28:41 +02:00
|
|
|
|
|
|
|
|
QString removeNamespaces(QString str) const;
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
public:
|
2012-05-18 02:28:41 +02:00
|
|
|
WatchHandler *m_handler; // Not owned.
|
2015-03-20 13:18:36 +01:00
|
|
|
DebuggerEngine *m_engine; // Not owned.
|
|
|
|
|
|
|
|
|
|
bool m_contentsValid;
|
|
|
|
|
bool m_resetLocationScheduled;
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
WatchItem *root() const { return static_cast<WatchItem *>(rootItem()); }
|
2012-05-18 02:28:41 +02:00
|
|
|
WatchItem *m_localsRoot; // Not owned.
|
|
|
|
|
WatchItem *m_inspectorRoot; // Not owned.
|
|
|
|
|
WatchItem *m_watchRoot; // Not owned.
|
|
|
|
|
WatchItem *m_returnRoot; // Not owned.
|
|
|
|
|
WatchItem *m_tooltipRoot; // Not owned.
|
|
|
|
|
|
2015-03-20 11:45:08 +01:00
|
|
|
SeparatedView *m_separatedView; // Not owned.
|
2015-03-19 12:42:53 +01:00
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
QSet<QByteArray> m_expandedINames;
|
2015-03-17 13:26:20 +01:00
|
|
|
QTimer m_requestUpdateTimer;
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
QHash<QString, DisplayFormats> m_reportedTypeFormats; // Type name -> Dumper Formats
|
2015-03-19 12:42:53 +01:00
|
|
|
QHash<QByteArray, QString> m_valueCache;
|
2012-05-18 02:28:41 +02:00
|
|
|
};
|
|
|
|
|
|
2015-03-20 13:18:36 +01:00
|
|
|
WatchModel::WatchModel(WatchHandler *handler, DebuggerEngine *engine)
|
|
|
|
|
: m_handler(handler), m_engine(engine), m_separatedView(new SeparatedView)
|
2012-05-18 02:28:41 +02:00
|
|
|
{
|
2013-08-19 13:30:10 +02:00
|
|
|
setObjectName(QLatin1String("WatchModel"));
|
2015-01-29 09:58:23 +01:00
|
|
|
|
2015-03-20 13:18:36 +01:00
|
|
|
m_contentsValid = false;
|
|
|
|
|
m_contentsValid = true; // FIXME
|
|
|
|
|
m_resetLocationScheduled = false;
|
|
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
setHeader(QStringList() << tr("Name") << tr("Value") << tr("Type"));
|
|
|
|
|
auto root = new WatchItem;
|
2015-12-16 17:17:38 +01:00
|
|
|
m_localsRoot = new WatchItem;
|
|
|
|
|
m_localsRoot->iname = "local";
|
|
|
|
|
m_localsRoot->name = tr("Locals");
|
|
|
|
|
m_inspectorRoot = new WatchItem;
|
|
|
|
|
m_inspectorRoot->iname = "inspect";
|
|
|
|
|
m_inspectorRoot->name = tr("Inspector");
|
|
|
|
|
m_watchRoot = new WatchItem;
|
|
|
|
|
m_watchRoot->iname = "watch";
|
|
|
|
|
m_watchRoot->name = tr("Expressions");
|
|
|
|
|
m_returnRoot = new WatchItem;
|
|
|
|
|
m_returnRoot->iname = "return";
|
|
|
|
|
m_returnRoot->name = tr("Return Value");
|
|
|
|
|
m_tooltipRoot = new WatchItem;
|
|
|
|
|
m_tooltipRoot->iname = "tooltip";
|
|
|
|
|
m_tooltipRoot->name = tr("Tooltip");
|
|
|
|
|
root->appendChild(m_localsRoot);
|
|
|
|
|
root->appendChild(m_inspectorRoot);
|
|
|
|
|
root->appendChild(m_watchRoot);
|
|
|
|
|
root->appendChild(m_returnRoot);
|
|
|
|
|
root->appendChild(m_tooltipRoot);
|
2015-01-29 09:58:23 +01:00
|
|
|
setRootItem(root);
|
2012-05-18 02:28:41 +02:00
|
|
|
|
2015-03-17 13:26:20 +01:00
|
|
|
m_requestUpdateTimer.setSingleShot(true);
|
|
|
|
|
connect(&m_requestUpdateTimer, &QTimer::timeout,
|
|
|
|
|
this, &WatchModel::updateStarted);
|
|
|
|
|
|
2015-02-03 23:58:49 +02:00
|
|
|
connect(action(SortStructMembers), &SavedAction::valueChanged,
|
2015-07-16 13:29:05 +02:00
|
|
|
m_engine, &DebuggerEngine::updateLocals);
|
2015-02-03 23:58:49 +02:00
|
|
|
connect(action(ShowStdNamespace), &SavedAction::valueChanged,
|
2015-05-29 09:38:53 +02:00
|
|
|
m_engine, &DebuggerEngine::updateAll);
|
2015-02-03 23:58:49 +02:00
|
|
|
connect(action(ShowQtNamespace), &SavedAction::valueChanged,
|
2015-05-29 09:38:53 +02:00
|
|
|
m_engine, &DebuggerEngine::updateAll);
|
2015-12-16 14:13:44 +01:00
|
|
|
connect(action(ShowQObjectNames), &SavedAction::valueChanged,
|
|
|
|
|
m_engine, &DebuggerEngine::updateAll);
|
2009-06-17 16:00:03 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-09 16:13:29 +02:00
|
|
|
void WatchModel::reinitialize(bool includeInspectData)
|
2009-08-31 09:14:04 +02:00
|
|
|
{
|
2015-01-29 09:58:23 +01:00
|
|
|
m_localsRoot->removeChildren();
|
|
|
|
|
m_watchRoot->removeChildren();
|
|
|
|
|
m_returnRoot->removeChildren();
|
|
|
|
|
m_tooltipRoot->removeChildren();
|
|
|
|
|
if (includeInspectData)
|
|
|
|
|
m_inspectorRoot->removeChildren();
|
2009-08-31 09:14:04 +02:00
|
|
|
}
|
2010-06-23 15:13:51 +02:00
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
WatchItem *WatchModel::findItem(const QByteArray &iname) const
|
2009-08-31 09:14:04 +02:00
|
|
|
{
|
2015-01-29 09:58:23 +01:00
|
|
|
return root()->findItem(iname);
|
2009-08-31 09:14:04 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
const WatchItem *WatchModel::watchItem(const QModelIndex &idx) const
|
2009-06-17 16:00:03 +02:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
return static_cast<WatchItem *>(itemForIndex(idx));
|
2012-05-18 02:28:41 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-05 16:51:55 +01:00
|
|
|
static QByteArray parentName(const QByteArray &iname)
|
2009-07-10 14:36:28 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
const int pos = iname.lastIndexOf('.');
|
|
|
|
|
return pos == -1 ? QByteArray() : iname.left(pos);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2010-09-24 10:35:22 +02:00
|
|
|
static QString niceTypeHelper(const QByteArray &typeIn)
|
2009-07-03 13:56:27 +02:00
|
|
|
{
|
2010-09-24 10:35:22 +02:00
|
|
|
typedef QMap<QByteArray, QString> Cache;
|
|
|
|
|
static Cache cache;
|
|
|
|
|
const Cache::const_iterator it = cache.constFind(typeIn);
|
2009-08-31 09:14:04 +02:00
|
|
|
if (it != cache.constEnd())
|
2009-07-03 13:56:27 +02:00
|
|
|
return it.value();
|
2014-01-15 12:04:23 +01:00
|
|
|
const QString simplified = simplifyType(QLatin1String(typeIn));
|
2010-11-25 13:51:54 +01:00
|
|
|
cache.insert(typeIn, simplified); // For simplicity, also cache unmodified types
|
|
|
|
|
return simplified;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-19 15:47:34 +02:00
|
|
|
QString WatchModel::removeNamespaces(QString str) const
|
2009-11-25 08:35:02 +01:00
|
|
|
{
|
2014-07-28 14:23:52 +02:00
|
|
|
if (!boolSetting(ShowStdNamespace))
|
2011-01-17 15:23:22 +01:00
|
|
|
str.remove(QLatin1String("std::"));
|
2014-07-28 14:23:52 +02:00
|
|
|
if (!boolSetting(ShowQtNamespace)) {
|
2015-03-20 13:18:36 +01:00
|
|
|
const QString qtNamespace = QString::fromLatin1(m_engine->qtNamespace());
|
2010-09-24 10:35:22 +02:00
|
|
|
if (!qtNamespace.isEmpty())
|
2011-01-17 15:23:22 +01:00
|
|
|
str.remove(qtNamespace);
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-22 18:02:29 +01:00
|
|
|
static int formatToIntegerBase(int format)
|
2010-09-22 17:30:22 +02:00
|
|
|
{
|
|
|
|
|
switch (format) {
|
2014-04-15 18:13:03 +02:00
|
|
|
case HexadecimalIntegerFormat:
|
2011-02-22 18:02:29 +01:00
|
|
|
return 16;
|
2014-04-15 18:13:03 +02:00
|
|
|
case BinaryIntegerFormat:
|
2011-02-22 18:02:29 +01:00
|
|
|
return 2;
|
2014-04-15 18:13:03 +02:00
|
|
|
case OctalIntegerFormat:
|
2011-02-22 18:02:29 +01:00
|
|
|
return 8;
|
2010-09-22 17:30:22 +02:00
|
|
|
}
|
|
|
|
|
return 10;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 16:32:44 +01:00
|
|
|
template <class IntType> QString reformatInteger(IntType value, int format)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
2014-04-15 18:13:03 +02:00
|
|
|
case HexadecimalIntegerFormat:
|
2011-12-21 14:02:52 +01:00
|
|
|
return QLatin1String("(hex) ") + QString::number(value, 16);
|
2014-04-15 18:13:03 +02:00
|
|
|
case BinaryIntegerFormat:
|
2011-12-21 14:02:52 +01:00
|
|
|
return QLatin1String("(bin) ") + QString::number(value, 2);
|
2014-04-15 18:13:03 +02:00
|
|
|
case OctalIntegerFormat:
|
2011-12-21 14:02:52 +01:00
|
|
|
return QLatin1String("(oct) ") + QString::number(value, 8);
|
2009-11-25 16:32:44 +01:00
|
|
|
}
|
2014-02-14 00:38:45 +01:00
|
|
|
return QString::number(value, 10); // not reached
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString reformatInteger(quint64 value, int format, int size, bool isSigned)
|
|
|
|
|
{
|
|
|
|
|
// Follow convention and don't show negative non-decimal numbers.
|
2014-05-22 17:41:01 +02:00
|
|
|
if (format != AutomaticFormat && format != DecimalIntegerFormat)
|
2014-02-14 00:38:45 +01:00
|
|
|
isSigned = false;
|
|
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
|
case 1:
|
|
|
|
|
value = value & 0xff;
|
|
|
|
|
return isSigned
|
|
|
|
|
? reformatInteger<qint8>(value, format)
|
|
|
|
|
: reformatInteger<quint8>(value, format);
|
|
|
|
|
case 2:
|
|
|
|
|
value = value & 0xffff;
|
|
|
|
|
return isSigned
|
|
|
|
|
? reformatInteger<qint16>(value, format)
|
|
|
|
|
: reformatInteger<quint16>(value, format);
|
|
|
|
|
case 4:
|
|
|
|
|
value = value & 0xffffffff;
|
|
|
|
|
return isSigned
|
|
|
|
|
? reformatInteger<qint32>(value, format)
|
|
|
|
|
: reformatInteger<quint32>(value, format);
|
|
|
|
|
default:
|
|
|
|
|
case 8: return isSigned
|
|
|
|
|
? reformatInteger<qint64>(value, format)
|
|
|
|
|
: reformatInteger<quint64>(value, format);
|
|
|
|
|
}
|
2009-11-25 16:32:44 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-09 16:39:36 +02:00
|
|
|
// Format printable (char-type) characters
|
2016-01-04 18:25:51 +01:00
|
|
|
static QString reformatCharacter(int code, int size, bool isSigned)
|
2010-04-09 16:39:36 +02:00
|
|
|
{
|
2013-10-13 22:29:22 +02:00
|
|
|
const QChar c = QChar(uint(code));
|
2016-01-04 18:25:51 +01:00
|
|
|
QString out;
|
2012-03-13 10:38:44 +01:00
|
|
|
if (c.isPrint())
|
2016-01-04 18:25:51 +01:00
|
|
|
out = QString::fromLatin1("'") + c + QLatin1String("' ");
|
|
|
|
|
else if (code == 0)
|
|
|
|
|
out = QLatin1String("'\\0'");
|
|
|
|
|
else if (code == '\r')
|
|
|
|
|
out = QLatin1String("'\\r'");
|
|
|
|
|
else if (code == '\n')
|
|
|
|
|
out = QLatin1String("'\\n'");
|
|
|
|
|
else if (code == '\t')
|
|
|
|
|
out = QLatin1String("'\\t'");
|
|
|
|
|
else
|
|
|
|
|
out = QLatin1String(" ");
|
|
|
|
|
|
|
|
|
|
out += QLatin1Char('\t');
|
|
|
|
|
|
|
|
|
|
if (isSigned) {
|
|
|
|
|
out += QString::number(code);
|
|
|
|
|
if (code < 0)
|
|
|
|
|
out += QString::fromLatin1("/%1 ").arg((1 << (8*size)) + code).left(2 + 2 * size);
|
|
|
|
|
else
|
|
|
|
|
out += QString(2 + 2 * size, QLatin1Char(' '));
|
|
|
|
|
} else {
|
|
|
|
|
out += QString::number(unsigned(code));
|
2010-04-09 16:39:36 +02:00
|
|
|
}
|
2016-01-04 18:25:51 +01:00
|
|
|
|
|
|
|
|
out += QLatin1Char('\t');
|
|
|
|
|
|
|
|
|
|
out += QString::fromLatin1("0x%1").arg(uint(code & ((1ULL << (8*size)) - 1)),
|
|
|
|
|
2 * size, 16, QLatin1Char('0'));
|
|
|
|
|
return out;
|
2010-04-09 16:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
2011-08-03 14:36:07 +02:00
|
|
|
static QString quoteUnprintable(const QString &str)
|
|
|
|
|
{
|
|
|
|
|
if (WatchHandler::unprintableBase() == 0)
|
|
|
|
|
return str;
|
2011-08-03 17:04:32 +02:00
|
|
|
|
2011-08-03 14:36:07 +02:00
|
|
|
QString encoded;
|
2011-08-03 17:04:32 +02:00
|
|
|
if (WatchHandler::unprintableBase() == -1) {
|
|
|
|
|
foreach (const QChar c, str) {
|
|
|
|
|
int u = c.unicode();
|
2012-03-13 10:38:44 +01:00
|
|
|
if (c.isPrint())
|
2011-08-03 17:04:32 +02:00
|
|
|
encoded += c;
|
2014-09-29 09:19:25 +03:00
|
|
|
else if (u == '\r')
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QLatin1String("\\r");
|
2014-09-29 09:19:25 +03:00
|
|
|
else if (u == '\t')
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QLatin1String("\\t");
|
2014-09-29 09:19:25 +03:00
|
|
|
else if (u == '\n')
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QLatin1String("\\n");
|
2011-08-03 17:04:32 +02:00
|
|
|
else
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QString::fromLatin1("\\%1")
|
2011-08-03 17:04:32 +02:00
|
|
|
.arg(c.unicode(), 3, 8, QLatin1Char('0'));
|
|
|
|
|
}
|
|
|
|
|
return encoded;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-03 14:36:07 +02:00
|
|
|
foreach (const QChar c, str) {
|
|
|
|
|
if (c.isPrint()) {
|
|
|
|
|
encoded += c;
|
|
|
|
|
} else if (WatchHandler::unprintableBase() == 8) {
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QString::fromLatin1("\\%1")
|
2011-08-03 14:36:07 +02:00
|
|
|
.arg(c.unicode(), 3, 8, QLatin1Char('0'));
|
|
|
|
|
} else {
|
2011-12-21 14:02:52 +01:00
|
|
|
encoded += QString::fromLatin1("\\u%1")
|
2011-08-03 14:36:07 +02:00
|
|
|
.arg(c.unicode(), 4, 16, QLatin1Char('0'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return encoded;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static int itemFormat(const WatchItem *item)
|
2009-07-03 11:20:47 +02:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
const int individualFormat = theIndividualFormats.value(item->iname, AutomaticFormat);
|
|
|
|
|
if (individualFormat != AutomaticFormat)
|
|
|
|
|
return individualFormat;
|
|
|
|
|
return theTypeFormats.value(stripForFormat(item->type), AutomaticFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString formattedValue(const WatchItem *item)
|
|
|
|
|
{
|
|
|
|
|
if (item->type == "bool") {
|
|
|
|
|
if (item->value == QLatin1String("0"))
|
2012-02-08 14:42:28 +01:00
|
|
|
return QLatin1String("false");
|
2015-12-16 17:17:38 +01:00
|
|
|
if (item->value == QLatin1String("1"))
|
2012-02-08 14:42:28 +01:00
|
|
|
return QLatin1String("true");
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->value;
|
2012-02-08 14:42:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
const int format = itemFormat(item);
|
2014-02-14 00:38:45 +01:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
// Append quoted, printable character also for decimal.
|
2015-04-01 10:32:28 +02:00
|
|
|
// FIXME: This is unreliable.
|
2016-01-04 18:25:51 +01:00
|
|
|
if (item->type.endsWith("char")) {
|
2014-04-15 18:13:03 +02:00
|
|
|
bool ok;
|
2015-12-16 17:17:38 +01:00
|
|
|
const int code = item->value.toInt(&ok);
|
|
|
|
|
bool isUnsigned = item->type == "unsigned char" || item->type == "uchar";
|
2016-01-04 18:25:51 +01:00
|
|
|
if (ok)
|
|
|
|
|
return reformatCharacter(code, 1, !isUnsigned);
|
|
|
|
|
} else if (item->type.endsWith("wchar_t")) {
|
|
|
|
|
bool ok;
|
|
|
|
|
const int code = item->value.toInt(&ok);
|
|
|
|
|
if (ok)
|
|
|
|
|
return reformatCharacter(code, 4, false);
|
|
|
|
|
} else if (item->type.endsWith("QChar")) {
|
|
|
|
|
bool ok;
|
|
|
|
|
const int code = item->value.toInt(&ok);
|
|
|
|
|
if (ok)
|
|
|
|
|
return reformatCharacter(code, 2, false);
|
2014-04-15 18:13:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (format == HexadecimalIntegerFormat
|
|
|
|
|
|| format == DecimalIntegerFormat
|
|
|
|
|
|| format == OctalIntegerFormat
|
|
|
|
|
|| format == BinaryIntegerFormat) {
|
2015-12-16 17:17:38 +01:00
|
|
|
bool isSigned = item->value.startsWith(QLatin1Char('-'));
|
|
|
|
|
quint64 raw = isSigned ? quint64(item->value.toLongLong()) : item->value.toULongLong();
|
|
|
|
|
return reformatInteger(raw, format, item->size, isSigned);
|
2009-12-08 16:00:06 +01:00
|
|
|
}
|
2011-05-17 12:58:53 +02:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
if (format == ScientificFloatFormat) {
|
2015-12-16 17:17:38 +01:00
|
|
|
double dd = item->value.toDouble();
|
2015-01-29 09:58:23 +01:00
|
|
|
return QString::number(dd, 'e');
|
2014-04-15 18:13:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (format == CompactFloatFormat) {
|
2015-12-16 17:17:38 +01:00
|
|
|
double dd = item->value.toDouble();
|
2015-01-29 09:58:23 +01:00
|
|
|
return QString::number(dd, 'g');
|
2014-04-15 18:13:03 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
if (item->type == "va_list")
|
|
|
|
|
return item->value;
|
2011-08-04 17:14:22 +02:00
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
if (!isPointerType(item->type) && !item->isVTablePointer()) {
|
2011-07-07 11:27:58 +02:00
|
|
|
bool ok = false;
|
2015-12-16 17:17:38 +01:00
|
|
|
qulonglong integer = item->value.toULongLong(&ok, 0);
|
2012-03-13 10:38:44 +01:00
|
|
|
if (ok) {
|
2015-12-16 17:17:38 +01:00
|
|
|
const int format = itemFormat(item);
|
|
|
|
|
return reformatInteger(integer, format, item->size, false);
|
2012-03-13 10:38:44 +01:00
|
|
|
}
|
2011-07-07 11:27:58 +02:00
|
|
|
}
|
2011-05-17 12:58:53 +02:00
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
if (item->elided) {
|
|
|
|
|
QString v = item->value;
|
2014-05-16 00:18:17 +02:00
|
|
|
v.chop(1);
|
2015-12-16 17:17:38 +01:00
|
|
|
QString len = item->elided > 0 ? QString::number(item->elided) : QLatin1String("unknown length");
|
2015-12-10 15:32:41 +01:00
|
|
|
return quoteUnprintable(v) + QLatin1String("\"... (") + len + QLatin1Char(')');
|
2014-05-16 00:18:17 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
return quoteUnprintable(item->value);
|
2009-07-03 11:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-23 13:22:08 +02:00
|
|
|
// Get a pointer address from pointer values reported by the debugger.
|
|
|
|
|
// Fix CDB formatting of pointers "0x00000000`000003fd class foo *", or
|
|
|
|
|
// "0x00000000`000003fd "Hallo"", or check gdb formatting of characters.
|
|
|
|
|
static inline quint64 pointerValue(QString data)
|
|
|
|
|
{
|
|
|
|
|
const int blankPos = data.indexOf(QLatin1Char(' '));
|
|
|
|
|
if (blankPos != -1)
|
|
|
|
|
data.truncate(blankPos);
|
|
|
|
|
data.remove(QLatin1Char('`'));
|
2011-07-07 15:00:11 +02:00
|
|
|
return data.toULongLong(0, 0);
|
2010-09-23 13:22:08 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-22 17:30:22 +02:00
|
|
|
// Return the type used for editing
|
2015-01-29 09:58:23 +01:00
|
|
|
int WatchItem::editType() const
|
2010-09-22 17:30:22 +02:00
|
|
|
{
|
2015-03-19 12:42:53 +01:00
|
|
|
if (type == "bool")
|
2010-09-22 17:30:22 +02:00
|
|
|
return QVariant::Bool;
|
2015-03-19 12:42:53 +01:00
|
|
|
if (isIntType(type))
|
|
|
|
|
return type.contains('u') ? QVariant::ULongLong : QVariant::LongLong;
|
|
|
|
|
if (isFloatType(type))
|
2010-09-22 17:30:22 +02:00
|
|
|
return QVariant::Double;
|
2010-09-23 13:22:08 +02:00
|
|
|
// Check for pointers using hex values (0xAD00 "Hallo")
|
2015-03-19 12:42:53 +01:00
|
|
|
if (isPointerType(type) && value.startsWith(QLatin1String("0x")))
|
2010-09-23 13:22:08 +02:00
|
|
|
return QVariant::ULongLong;
|
2010-09-22 17:30:22 +02:00
|
|
|
return QVariant::String;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert to editable (see above)
|
2015-01-29 09:58:23 +01:00
|
|
|
QVariant WatchItem::editValue() const
|
2010-09-22 17:30:22 +02:00
|
|
|
{
|
2015-01-29 09:58:23 +01:00
|
|
|
switch (editType()) {
|
2010-09-22 17:30:22 +02:00
|
|
|
case QVariant::Bool:
|
2015-03-19 12:42:53 +01:00
|
|
|
return value != QLatin1String("0") && value != QLatin1String("false");
|
2010-09-22 17:30:22 +02:00
|
|
|
case QVariant::ULongLong:
|
2015-03-19 12:42:53 +01:00
|
|
|
if (isPointerType(type)) // Fix pointer values (0xAD00 "Hallo" -> 0xAD00)
|
|
|
|
|
return QVariant(pointerValue(value));
|
|
|
|
|
return QVariant(value.toULongLong());
|
2010-09-22 17:30:22 +02:00
|
|
|
case QVariant::LongLong:
|
2015-03-19 12:42:53 +01:00
|
|
|
return QVariant(value.toLongLong());
|
2010-09-22 17:30:22 +02:00
|
|
|
case QVariant::Double:
|
2015-03-19 12:42:53 +01:00
|
|
|
return QVariant(value.toDouble());
|
2010-09-22 17:30:22 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-07-18 15:41:56 +02:00
|
|
|
// Some string value: '0x434 "Hallo"':
|
|
|
|
|
// Remove quotes and replace newlines, which will cause line edit troubles.
|
2015-03-19 12:42:53 +01:00
|
|
|
QString stringValue = value;
|
2011-07-18 15:41:56 +02:00
|
|
|
if (stringValue.endsWith(QLatin1Char('"'))) {
|
|
|
|
|
const int leadingDoubleQuote = stringValue.indexOf(QLatin1Char('"'));
|
|
|
|
|
if (leadingDoubleQuote != stringValue.size() - 1) {
|
|
|
|
|
stringValue.truncate(stringValue.size() - 1);
|
|
|
|
|
stringValue.remove(0, leadingDoubleQuote + 1);
|
|
|
|
|
stringValue.replace(QLatin1String("\n"), QLatin1String("\\n"));
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-07-20 14:23:54 +02:00
|
|
|
return QVariant(quoteUnprintable(stringValue));
|
2010-09-22 17:30:22 +02:00
|
|
|
}
|
|
|
|
|
|
2011-08-19 15:47:34 +02:00
|
|
|
// Truncate value for item view, maintaining quotes.
|
|
|
|
|
static QString truncateValue(QString v)
|
2010-01-13 10:36:37 +01:00
|
|
|
{
|
|
|
|
|
enum { maxLength = 512 };
|
|
|
|
|
if (v.size() < maxLength)
|
|
|
|
|
return v;
|
|
|
|
|
const bool isQuoted = v.endsWith(QLatin1Char('"')); // check for 'char* "Hallo"'
|
|
|
|
|
v.truncate(maxLength);
|
|
|
|
|
v += isQuoted ? QLatin1String("...\"") : QLatin1String("...");
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static QString displayName(const WatchItem *item)
|
2011-11-25 18:50:54 +01:00
|
|
|
{
|
|
|
|
|
QString result;
|
2015-12-16 17:17:38 +01:00
|
|
|
|
|
|
|
|
const WatchItem *p = item->parentItem();
|
|
|
|
|
if (!p)
|
|
|
|
|
return result;
|
|
|
|
|
if (item->arrayIndex >= 0) {
|
|
|
|
|
result = QString::fromLatin1("[%1]").arg(item->arrayIndex);
|
2015-01-29 09:58:23 +01:00
|
|
|
return result;
|
2015-12-16 17:17:38 +01:00
|
|
|
}
|
|
|
|
|
if (item->iname.startsWith("return") && item->name.startsWith(QLatin1Char('$')))
|
2015-01-29 09:58:23 +01:00
|
|
|
result = WatchModel::tr("returned value");
|
2015-12-16 17:17:38 +01:00
|
|
|
else if (item->name == QLatin1String("*"))
|
|
|
|
|
result = QLatin1Char('*') + p->name;
|
2013-03-06 10:03:29 +01:00
|
|
|
else
|
2015-12-16 17:17:38 +01:00
|
|
|
result = watchModel(item)->removeNamespaces(item->name);
|
2014-07-03 11:01:53 +02:00
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
// Simplify names that refer to base classes.
|
2014-07-03 11:01:53 +02:00
|
|
|
if (result.startsWith(QLatin1Char('['))) {
|
|
|
|
|
result = simplifyType(result);
|
|
|
|
|
if (result.size() > 30)
|
2014-07-03 13:49:46 +02:00
|
|
|
result = result.left(27) + QLatin1String("...]");
|
2014-07-03 11:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-06 10:03:29 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static QString displayValue(const WatchItem *item)
|
2013-03-06 10:03:29 +01:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
QString result = watchModel(item)->removeNamespaces(truncateValue(formattedValue(item)));
|
|
|
|
|
if (result.isEmpty() && item->address)
|
|
|
|
|
result += QString::fromLatin1("@0x" + QByteArray::number(item->address, 16));
|
2015-03-19 12:42:53 +01:00
|
|
|
// if (origaddr)
|
|
|
|
|
// result += QString::fromLatin1(" (0x" + QByteArray::number(origaddr, 16) + ')');
|
2013-03-06 10:03:29 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static QString displayType(const WatchItem *item)
|
2013-03-06 10:03:29 +01:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
QString result = niceTypeHelper(item->type);
|
|
|
|
|
if (item->bitsize)
|
|
|
|
|
result += QString::fromLatin1(":%1").arg(item->bitsize);
|
2013-03-06 10:03:29 +01:00
|
|
|
result.remove(QLatin1Char('\''));
|
2015-12-16 17:17:38 +01:00
|
|
|
result = watchModel(item)->removeNamespaces(result);
|
2011-11-25 18:50:54 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static QColor valueColor(const WatchItem *item, int column)
|
2015-04-15 18:48:32 +02:00
|
|
|
{
|
|
|
|
|
Theme::Color color = Theme::Debugger_WatchItem_ValueNormal;
|
2015-12-16 17:17:38 +01:00
|
|
|
if (const WatchModel *model = watchModel(item)) {
|
|
|
|
|
if (!model->m_contentsValid && !item->isInspect()) {
|
2015-04-15 18:48:32 +02:00
|
|
|
color = Theme::Debugger_WatchItem_ValueInvalid;
|
|
|
|
|
} else if (column == 1) {
|
2015-12-16 17:17:38 +01:00
|
|
|
if (!item->valueEnabled)
|
2015-04-15 18:48:32 +02:00
|
|
|
color = Theme::Debugger_WatchItem_ValueInvalid;
|
2015-12-16 17:17:38 +01:00
|
|
|
else if (!model->m_contentsValid && !item->isInspect())
|
2015-04-15 18:48:32 +02:00
|
|
|
color = Theme::Debugger_WatchItem_ValueInvalid;
|
2015-12-16 17:17:38 +01:00
|
|
|
else if (column == 1 && item->value.isEmpty()) // This might still show 0x...
|
2015-04-15 18:48:32 +02:00
|
|
|
color = Theme::Debugger_WatchItem_ValueInvalid;
|
2015-12-16 17:17:38 +01:00
|
|
|
else if (column == 1 && item->value != model->m_valueCache.value(item->iname))
|
2015-04-15 18:48:32 +02:00
|
|
|
color = Theme::Debugger_WatchItem_ValueChanged;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return creatorTheme()->color(color);
|
2015-02-09 09:00:21 +01:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
static DisplayFormats typeFormatList(const WatchItem *item)
|
2009-06-17 16:00:03 +02:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
DisplayFormats formats;
|
|
|
|
|
|
|
|
|
|
// Types supported by dumpers:
|
|
|
|
|
// Hack: Compensate for namespaces.
|
|
|
|
|
QString t = QLatin1String(stripForFormat(item->type));
|
|
|
|
|
int pos = t.indexOf(QLatin1String("::Q"));
|
|
|
|
|
if (pos >= 0 && t.count(QLatin1Char(':')) == 2)
|
|
|
|
|
t.remove(0, pos + 2);
|
|
|
|
|
pos = t.indexOf(QLatin1Char('<'));
|
|
|
|
|
if (pos >= 0)
|
|
|
|
|
t.truncate(pos);
|
|
|
|
|
t.replace(QLatin1Char(':'), QLatin1Char('_'));
|
|
|
|
|
formats << watchModel(item)->m_reportedTypeFormats.value(t);
|
|
|
|
|
|
|
|
|
|
if (t.contains(QLatin1Char(']')))
|
|
|
|
|
formats.append(ArrayPlotFormat);
|
|
|
|
|
|
|
|
|
|
// Fixed artificial string and pointer types.
|
|
|
|
|
if (item->origaddr || isPointerType(item->type)) {
|
|
|
|
|
formats.append(RawFormat);
|
|
|
|
|
formats.append(Latin1StringFormat);
|
|
|
|
|
formats.append(SeparateLatin1StringFormat);
|
|
|
|
|
formats.append(Utf8StringFormat);
|
|
|
|
|
formats.append(SeparateUtf8StringFormat);
|
|
|
|
|
formats.append(Local8BitStringFormat);
|
|
|
|
|
formats.append(Utf16StringFormat);
|
|
|
|
|
formats.append(Ucs4StringFormat);
|
|
|
|
|
formats.append(Array10Format);
|
|
|
|
|
formats.append(Array100Format);
|
|
|
|
|
formats.append(Array1000Format);
|
|
|
|
|
formats.append(Array10000Format);
|
|
|
|
|
} else if (item->type.contains("char[") || item->type.contains("char [")) {
|
|
|
|
|
formats.append(RawFormat);
|
|
|
|
|
formats.append(Latin1StringFormat);
|
|
|
|
|
formats.append(SeparateLatin1StringFormat);
|
|
|
|
|
formats.append(Utf8StringFormat);
|
|
|
|
|
formats.append(SeparateUtf8StringFormat);
|
|
|
|
|
formats.append(Local8BitStringFormat);
|
|
|
|
|
formats.append(Utf16StringFormat);
|
|
|
|
|
formats.append(Ucs4StringFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fixed artificial floating point types.
|
|
|
|
|
bool ok = false;
|
|
|
|
|
item->value.toDouble(&ok);
|
|
|
|
|
if (ok) {
|
|
|
|
|
formats.append(CompactFloatFormat);
|
|
|
|
|
formats.append(ScientificFloatFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fixed artificial integral types.
|
|
|
|
|
QString v = item->value;
|
|
|
|
|
if (v.startsWith(QLatin1Char('-')))
|
|
|
|
|
v = v.mid(1);
|
|
|
|
|
v.toULongLong(&ok, 10);
|
|
|
|
|
if (!ok)
|
|
|
|
|
v.toULongLong(&ok, 16);
|
|
|
|
|
if (!ok)
|
|
|
|
|
v.toULongLong(&ok, 8);
|
|
|
|
|
if (ok) {
|
|
|
|
|
formats.append(DecimalIntegerFormat);
|
|
|
|
|
formats.append(HexadecimalIntegerFormat);
|
|
|
|
|
formats.append(BinaryIntegerFormat);
|
|
|
|
|
formats.append(OctalIntegerFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return formats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|
|
|
|
{
|
|
|
|
|
if (role == BaseTreeView::ExtraIndicesForColumnWidth) {
|
|
|
|
|
QModelIndexList l;
|
|
|
|
|
foreach (TreeItem *item, m_watchRoot->children())
|
|
|
|
|
l.append(indexForItem(item));
|
|
|
|
|
foreach (TreeItem *item, m_returnRoot->children())
|
|
|
|
|
l.append(indexForItem(item));
|
|
|
|
|
return QVariant::fromValue(l);
|
|
|
|
|
}
|
|
|
|
|
const WatchItem *item = watchItem(idx);
|
|
|
|
|
if (!item)
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
|
|
|
|
const int column = idx.column();
|
2008-12-02 12:01:29 +01:00
|
|
|
switch (role) {
|
2011-02-14 13:42:01 +01:00
|
|
|
case LocalsEditTypeRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->editType();
|
2011-02-14 13:42:01 +01:00
|
|
|
|
2011-05-10 15:57:33 +02:00
|
|
|
case LocalsNameRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->name;
|
2011-05-10 15:57:33 +02:00
|
|
|
|
2011-02-14 13:42:01 +01:00
|
|
|
case LocalsIntegerBaseRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
if (isPointerType(item->type)) // Pointers using 0x-convention
|
2010-09-23 13:22:08 +02:00
|
|
|
return QVariant(16);
|
2015-12-16 17:17:38 +01:00
|
|
|
return formatToIntegerBase(itemFormat(item));
|
2011-02-14 13:42:01 +01:00
|
|
|
|
|
|
|
|
case Qt::EditRole: {
|
2015-01-29 09:58:23 +01:00
|
|
|
switch (column) {
|
2011-02-14 13:42:01 +01:00
|
|
|
case 0:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->expression();
|
2011-02-14 13:42:01 +01:00
|
|
|
case 1:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->editValue();
|
2011-02-14 13:42:01 +01:00
|
|
|
case 2:
|
2015-12-16 17:17:38 +01:00
|
|
|
return QString::fromUtf8(item->type);
|
2011-02-14 13:42:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-06 10:03:29 +01:00
|
|
|
case Qt::DisplayRole: {
|
2015-01-29 09:58:23 +01:00
|
|
|
switch (column) {
|
2013-03-06 10:03:29 +01:00
|
|
|
case 0:
|
2015-12-16 17:17:38 +01:00
|
|
|
return displayName(item);
|
2013-03-06 10:03:29 +01:00
|
|
|
case 1:
|
2015-12-16 17:17:38 +01:00
|
|
|
return displayValue(item);
|
2013-03-06 10:03:29 +01:00
|
|
|
case 2:
|
2015-12-16 17:17:38 +01:00
|
|
|
return displayType(item);
|
2013-03-06 10:03:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-02-14 13:42:01 +01:00
|
|
|
|
2009-05-13 14:39:55 +02:00
|
|
|
case Qt::ToolTipRole:
|
2014-07-28 14:23:52 +02:00
|
|
|
return boolSetting(UseToolTipsInLocalsView)
|
2015-12-16 17:17:38 +01:00
|
|
|
? item->toToolTip() : QVariant();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-02-09 09:00:21 +01:00
|
|
|
case Qt::ForegroundRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return valueColor(item, column);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-09-23 13:22:08 +02:00
|
|
|
case LocalsExpressionRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->expression();
|
2011-02-14 13:42:01 +01:00
|
|
|
|
2011-03-17 19:37:07 +01:00
|
|
|
case LocalsRawExpressionRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->exp;
|
2011-03-17 19:37:07 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case LocalsINameRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->iname;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case LocalsExpandedRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return m_expandedINames.contains(item->iname);
|
2009-06-24 12:31:09 +02:00
|
|
|
|
2011-11-07 20:07:14 +01:00
|
|
|
case LocalsTypeFormatListRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return QVariant::fromValue(typeFormatList(item));
|
2011-11-07 20:07:14 +01:00
|
|
|
|
2011-04-21 09:10:31 +02:00
|
|
|
case LocalsTypeRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return removeNamespaces(displayType(item));
|
2011-11-07 20:07:14 +01:00
|
|
|
|
2011-04-21 09:10:31 +02:00
|
|
|
case LocalsRawTypeRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return QString::fromLatin1(item->type);
|
2011-11-07 20:07:14 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case LocalsTypeFormatRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return theTypeFormats.value(stripForFormat(item->type), AutomaticFormat);
|
2009-12-08 16:00:06 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case LocalsIndividualFormatRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return theIndividualFormats.value(item->iname, AutomaticFormat);
|
2009-12-08 16:00:06 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
case LocalsRawValueRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->value;
|
2009-07-03 11:20:47 +02:00
|
|
|
|
2013-03-06 10:03:29 +01:00
|
|
|
case LocalsObjectAddressRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->address;
|
2013-03-06 10:03:29 +01:00
|
|
|
|
|
|
|
|
case LocalsPointerAddressRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->origaddr;
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2013-03-06 10:03:29 +01:00
|
|
|
case LocalsIsWatchpointAtObjectAddressRole: {
|
2011-05-09 08:35:58 +02:00
|
|
|
BreakpointParameters bp(WatchpointAtAddress);
|
2015-12-16 17:17:38 +01:00
|
|
|
bp.address = item->address;
|
|
|
|
|
return m_engine->breakHandler()->findWatchpoint(bp) != 0;
|
2011-03-01 19:16:24 +01:00
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2011-04-04 16:15:03 +02:00
|
|
|
case LocalsSizeRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
return item->size;
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2013-03-06 10:03:29 +01:00
|
|
|
case LocalsIsWatchpointAtPointerAddressRole:
|
2015-12-16 17:17:38 +01:00
|
|
|
if (isPointerType(item->type)) {
|
2011-05-09 08:35:58 +02:00
|
|
|
BreakpointParameters bp(WatchpointAtAddress);
|
2015-12-16 17:17:38 +01:00
|
|
|
bp.address = pointerValue(item->value);
|
|
|
|
|
return m_engine->breakHandler()->findWatchpoint(bp) != 0;
|
2011-03-01 19:16:24 +01:00
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
return false;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
default:
|
2010-01-29 21:33:57 +01:00
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
return QVariant();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role)
|
2009-04-07 13:38:19 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
if (!idx.isValid())
|
|
|
|
|
return false; // Triggered by ModelTester.
|
|
|
|
|
|
2015-04-22 12:37:39 +02:00
|
|
|
WatchItem *item = static_cast<WatchItem *>(itemForIndex(idx));
|
2015-01-29 09:58:23 +01:00
|
|
|
QTC_ASSERT(item, return false);
|
2010-06-23 15:13:51 +02:00
|
|
|
|
|
|
|
|
switch (role) {
|
2010-09-24 10:35:22 +02:00
|
|
|
case Qt::EditRole:
|
2012-05-18 02:28:41 +02:00
|
|
|
switch (idx.column()) {
|
2015-03-06 11:32:39 +01:00
|
|
|
case 0: {
|
2015-08-11 14:13:06 +02:00
|
|
|
m_handler->updateWatchExpression(item, value.toString().trimmed().toUtf8());
|
2010-09-24 10:35:22 +02:00
|
|
|
break;
|
2015-03-06 11:32:39 +01:00
|
|
|
}
|
2010-09-24 10:35:22 +02:00
|
|
|
case 1: // Change value
|
2015-03-20 13:18:36 +01:00
|
|
|
m_engine->assignValueInDebugger(item, item->expression(), value);
|
2010-09-24 10:35:22 +02:00
|
|
|
break;
|
|
|
|
|
case 2: // TODO: Implement change type.
|
2015-03-20 13:18:36 +01:00
|
|
|
m_engine->assignValueInDebugger(item, item->expression(), value);
|
2010-09-24 10:35:22 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-06-23 15:13:51 +02:00
|
|
|
case LocalsExpandedRole:
|
|
|
|
|
if (value.toBool()) {
|
|
|
|
|
// Should already have been triggered by fetchMore()
|
2015-03-19 12:42:53 +01:00
|
|
|
//QTC_CHECK(m_expandedINames.contains(item->iname));
|
|
|
|
|
m_expandedINames.insert(item->iname);
|
2010-06-23 15:13:51 +02:00
|
|
|
} else {
|
2015-03-19 12:42:53 +01:00
|
|
|
m_expandedINames.remove(item->iname);
|
2010-06-23 15:13:51 +02:00
|
|
|
}
|
2015-03-26 16:59:51 +01:00
|
|
|
if (item->iname.contains('.'))
|
|
|
|
|
emit columnAdjustmentRequested();
|
2010-06-23 15:13:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LocalsTypeFormatRole:
|
2015-04-01 17:19:43 +02:00
|
|
|
setTypeFormat(item->type, value.toInt());
|
2015-07-15 17:14:29 +02:00
|
|
|
m_engine->updateLocals();
|
2010-06-23 15:13:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case LocalsIndividualFormatRole: {
|
2015-04-01 17:19:43 +02:00
|
|
|
setIndividualFormat(item->iname, value.toInt());
|
2015-07-15 17:14:29 +02:00
|
|
|
m_engine->updateLocals();
|
2010-06-23 15:13:51 +02:00
|
|
|
break;
|
2009-11-25 16:32:44 +01:00
|
|
|
}
|
2009-06-17 16:00:03 +02:00
|
|
|
}
|
2010-09-23 13:22:08 +02:00
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
//emit dataChanged(idx, idx);
|
2009-04-07 13:38:19 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
if (!idx.isValid())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const WatchItem *item = watchItem(idx);
|
|
|
|
|
if (!item)
|
|
|
|
|
return Qt::ItemIsEnabled|Qt::ItemIsSelectable;
|
|
|
|
|
|
|
|
|
|
const int column = idx.column();
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(m_engine, return Qt::ItemFlags());
|
|
|
|
|
const DebuggerState state = m_engine->state();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-02-17 16:31:43 +01:00
|
|
|
// Enabled, editable, selectable, checkable, and can be used both as the
|
2008-12-02 12:01:29 +01:00
|
|
|
// source of a drag and drop operation and as a drop target.
|
|
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
const Qt::ItemFlags notEditable = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
|
|
|
|
const Qt::ItemFlags editable = notEditable | Qt::ItemIsEditable;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
if (item->isWatcher()) {
|
|
|
|
|
if (state == InferiorUnrunnable)
|
|
|
|
|
return (column == 0 && item->iname.count('.') == 1) ? editable : notEditable;
|
2015-08-12 14:30:17 +02:00
|
|
|
|
2015-03-18 13:28:45 +01:00
|
|
|
if (state != InferiorStopOk
|
|
|
|
|
&& state != DebuggerNotReady
|
|
|
|
|
&& state != DebuggerFinished
|
2015-12-16 17:17:38 +01:00
|
|
|
&& !m_engine->hasCapability(AddWatcherWhileRunningCapability))
|
2015-03-18 13:28:45 +01:00
|
|
|
return Qt::ItemFlags();
|
2015-12-16 17:17:38 +01:00
|
|
|
if (column == 0 && item->iname.count('.') == 1)
|
2010-09-23 08:19:49 +02:00
|
|
|
return editable; // Watcher names are editable.
|
2015-12-16 17:17:38 +01:00
|
|
|
if (column == 1 && item->arrayIndex >= 0)
|
|
|
|
|
return editable;
|
2010-09-23 08:19:49 +02:00
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
if (!item->name.isEmpty()) {
|
2010-07-22 15:34:35 +02:00
|
|
|
// FIXME: Forcing types is not implemented yet.
|
|
|
|
|
//if (idx.column() == 2)
|
|
|
|
|
// return editable; // Watcher types can be set by force.
|
2015-12-16 17:17:38 +01:00
|
|
|
if (column == 1 && item->valueEditable && !item->elided)
|
2010-07-22 15:34:35 +02:00
|
|
|
return editable; // Watcher values are sometimes editable.
|
|
|
|
|
}
|
2015-12-16 17:17:38 +01:00
|
|
|
} else if (item->isLocal()) {
|
|
|
|
|
if (state != InferiorStopOk && !m_engine->hasCapability(AddWatcherWhileRunningCapability))
|
2015-03-18 13:28:45 +01:00
|
|
|
return Qt::ItemFlags();
|
2015-12-16 17:17:38 +01:00
|
|
|
if (column == 1 && item->valueEditable && !item->elided)
|
2010-07-22 15:34:35 +02:00
|
|
|
return editable; // Locals values are sometimes editable.
|
2015-12-16 17:17:38 +01:00
|
|
|
if (column == 1 && item->arrayIndex >= 0)
|
|
|
|
|
return editable;
|
|
|
|
|
} else if (item->isInspect()) {
|
|
|
|
|
if (column == 1 && item->valueEditable)
|
2012-05-23 14:55:48 +02:00
|
|
|
return editable; // Inspector values are sometimes editable.
|
2010-07-22 15:34:35 +02:00
|
|
|
}
|
2009-08-31 09:14:04 +02:00
|
|
|
return notEditable;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-12-16 17:17:38 +01:00
|
|
|
bool WatchModel::canFetchMore(const QModelIndex &idx) const
|
|
|
|
|
{
|
|
|
|
|
if (!idx.isValid())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// See "hasChildren" below.
|
|
|
|
|
const WatchItem *item = watchItem(idx);
|
|
|
|
|
if (!item)
|
|
|
|
|
return false;
|
|
|
|
|
if (!item->wantsChildren)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_contentsValid && !item->isInspect())
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchModel::fetchMore(const QModelIndex &idx)
|
|
|
|
|
{
|
|
|
|
|
if (!idx.isValid())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
WatchItem *item = static_cast<WatchItem *>(itemForIndex(idx));
|
|
|
|
|
if (item) {
|
|
|
|
|
m_expandedINames.insert(item->iname);
|
|
|
|
|
if (item->children().isEmpty()) {
|
|
|
|
|
item->setChildrenNeeded();
|
|
|
|
|
m_engine->expandItem(item->iname);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WatchModel::hasChildren(const QModelIndex &idx) const
|
|
|
|
|
{
|
|
|
|
|
const WatchItem *item = watchItem(idx);
|
|
|
|
|
if (!item)
|
|
|
|
|
return true;
|
|
|
|
|
if (item->rowCount() > 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// "Can fetch more", see above.
|
|
|
|
|
if (!item->wantsChildren)
|
|
|
|
|
return false;
|
|
|
|
|
if (!m_contentsValid && !item->isInspect())
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-28 12:51:37 +01:00
|
|
|
static inline QString msgArrayFormat(int n)
|
|
|
|
|
{
|
|
|
|
|
return WatchModel::tr("Array of %n items", 0, n);
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
QString WatchModel::nameForFormat(int format)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
2015-03-31 09:29:34 +02:00
|
|
|
case AutomaticFormat: return tr("Automatic");
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
case RawFormat: return tr("Raw Data");
|
2015-03-20 16:03:59 +01:00
|
|
|
case SimpleFormat: return CdbEngine::tr("Normal"); // FIXME: String
|
2015-03-31 09:29:34 +02:00
|
|
|
case EnhancedFormat: return tr("Enhanced");
|
2015-03-20 16:03:59 +01:00
|
|
|
case SeparateFormat: return CdbEngine::tr("Separate Window"); // FIXME: String
|
|
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
case Latin1StringFormat: return tr("Latin1 String");
|
2015-03-20 16:03:59 +01:00
|
|
|
case SeparateLatin1StringFormat: return tr("Latin1 String in Separate Window");
|
2014-04-15 18:13:03 +02:00
|
|
|
case Utf8StringFormat: return tr("UTF-8 String");
|
2015-03-20 16:03:59 +01:00
|
|
|
case SeparateUtf8StringFormat: return tr("UTF-8 String in Separate Window");
|
2014-04-15 18:13:03 +02:00
|
|
|
case Local8BitStringFormat: return tr("Local 8-Bit String");
|
|
|
|
|
case Utf16StringFormat: return tr("UTF-16 String");
|
|
|
|
|
case Ucs4StringFormat: return tr("UCS-4 String");
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
case Array10Format: return msgArrayFormat(10);
|
|
|
|
|
case Array100Format: return msgArrayFormat(100);
|
|
|
|
|
case Array1000Format: return msgArrayFormat(1000);
|
|
|
|
|
case Array10000Format: return msgArrayFormat(10000);
|
2015-03-31 09:29:34 +02:00
|
|
|
case ArrayPlotFormat: return tr("Plot in Separate Window");
|
|
|
|
|
|
|
|
|
|
case CompactMapFormat: return tr("Display Keys and Values Side by Side");
|
|
|
|
|
case DirectQListStorageFormat: return tr("Force Display as Direct Storage Form");
|
|
|
|
|
case IndirectQListStorageFormat: return tr("Force Display as Indirect Storage Form");
|
|
|
|
|
|
|
|
|
|
case BoolTextFormat: return tr("Display Boolean Values as True or False");
|
|
|
|
|
case BoolIntegerFormat: return tr("Display Boolean Values as 1 or 0");
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
case DecimalIntegerFormat: return tr("Decimal Integer");
|
|
|
|
|
case HexadecimalIntegerFormat: return tr("Hexadecimal Integer");
|
|
|
|
|
case BinaryIntegerFormat: return tr("Binary Integer");
|
|
|
|
|
case OctalIntegerFormat: return tr("Octal Integer");
|
2015-03-20 16:03:59 +01:00
|
|
|
|
2014-04-15 18:13:03 +02:00
|
|
|
case CompactFloatFormat: return tr("Compact Float");
|
|
|
|
|
case ScientificFloatFormat: return tr("Scientific Float");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTC_CHECK(false);
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-17 16:00:03 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// WatchHandler
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
WatchHandler::WatchHandler(DebuggerEngine *engine)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-03-20 13:18:36 +01:00
|
|
|
m_model = new WatchModel(this, engine);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
WatchHandler::~WatchHandler()
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
// Do it manually to prevent calling back in model destructors
|
|
|
|
|
// after m_cache is destroyed.
|
|
|
|
|
delete m_model;
|
|
|
|
|
m_model = 0;
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void WatchHandler::cleanup()
|
|
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
m_model->m_expandedINames.clear();
|
2012-03-14 12:26:27 +01:00
|
|
|
theWatcherNames.remove(QByteArray());
|
2015-03-18 13:28:45 +01:00
|
|
|
saveWatchers();
|
2012-05-18 02:28:41 +02:00
|
|
|
m_model->reinitialize();
|
2015-03-06 09:14:40 +01:00
|
|
|
emit m_model->updateFinished();
|
2015-03-20 11:45:08 +01:00
|
|
|
m_model->m_separatedView->hide();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 15:14:15 +01:00
|
|
|
void WatchHandler::insertItem(WatchItem *item)
|
|
|
|
|
{
|
|
|
|
|
m_model->insertItem(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchModel::insertItem(WatchItem *item)
|
|
|
|
|
{
|
2015-07-03 13:48:00 +02:00
|
|
|
QTC_ASSERT(!item->iname.isEmpty(), return);
|
|
|
|
|
|
2015-05-20 13:57:06 +02:00
|
|
|
WatchItem *parent = findItem(parentName(item->iname));
|
|
|
|
|
QTC_ASSERT(parent, return);
|
|
|
|
|
|
2015-07-03 13:48:00 +02:00
|
|
|
bool found = false;
|
|
|
|
|
const QVector<TreeItem *> siblings = parent->children();
|
|
|
|
|
for (int row = 0, n = siblings.size(); row < n; ++row) {
|
|
|
|
|
if (static_cast<WatchItem *>(siblings.at(row))->iname == item->iname) {
|
|
|
|
|
delete takeItem(parent->children().at(row));
|
|
|
|
|
parent->insertChild(row, item);
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-05-29 09:38:53 +02:00
|
|
|
}
|
2015-07-03 13:48:00 +02:00
|
|
|
if (!found)
|
|
|
|
|
parent->appendChild(item);
|
2015-03-20 14:13:27 +01:00
|
|
|
|
2015-07-17 12:28:00 +02:00
|
|
|
item->update();
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
item->walkTree([this](TreeItem *sub) { showEditValue(static_cast<WatchItem *>(sub)); });
|
2015-01-28 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchModel::reexpandItems()
|
|
|
|
|
{
|
|
|
|
|
foreach (const QByteArray &iname, m_expandedINames) {
|
2015-03-03 10:01:50 +01:00
|
|
|
if (WatchItem *item = findItem(iname)) {
|
2015-04-22 12:37:39 +02:00
|
|
|
emit itemIsExpanded(indexForItem(item));
|
2015-03-03 10:01:50 +01:00
|
|
|
emit inameIsExpanded(iname);
|
|
|
|
|
} else {
|
|
|
|
|
// Can happen. We might have stepped into another frame
|
|
|
|
|
// not containing that iname, but we still like to
|
|
|
|
|
// remember the expanded state of iname in case we step
|
|
|
|
|
// out of the frame again.
|
|
|
|
|
}
|
2015-01-28 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-09 16:13:29 +02:00
|
|
|
void WatchHandler::removeAllData(bool includeInspectData)
|
2012-05-18 02:28:41 +02:00
|
|
|
{
|
2012-10-09 16:13:29 +02:00
|
|
|
m_model->reinitialize(includeInspectData);
|
2009-07-13 12:28:47 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-08 15:50:47 +02:00
|
|
|
/*!
|
|
|
|
|
If a displayed item differs from the cached entry it is considered
|
|
|
|
|
"new", and correspondingly marked in red. Calling \c resetValueCache()
|
|
|
|
|
stores the currently displayed items in the cache, effectively
|
|
|
|
|
marking the value as known, and consequently painted black.
|
|
|
|
|
*/
|
2012-09-21 16:46:06 +02:00
|
|
|
void WatchHandler::resetValueCache()
|
2012-05-31 14:26:08 +02:00
|
|
|
{
|
2012-09-21 16:46:06 +02:00
|
|
|
m_model->m_valueCache.clear();
|
2015-01-29 09:58:23 +01:00
|
|
|
TreeItem *root = m_model->rootItem();
|
|
|
|
|
root->walkTree([this, root](TreeItem *item) {
|
|
|
|
|
auto watchItem = static_cast<WatchItem *>(item);
|
2015-03-19 12:42:53 +01:00
|
|
|
m_model->m_valueCache[watchItem->iname] = watchItem->value;
|
2015-01-29 09:58:23 +01:00
|
|
|
});
|
2012-05-31 14:26:08 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-18 13:28:45 +01:00
|
|
|
void WatchHandler::resetWatchers()
|
|
|
|
|
{
|
|
|
|
|
loadSessionData();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-06 09:46:08 +02:00
|
|
|
void WatchHandler::notifyUpdateStarted(const QList<QByteArray> &inames)
|
2015-03-06 09:14:40 +01:00
|
|
|
{
|
2015-07-06 09:46:08 +02:00
|
|
|
auto marker = [](TreeItem *it) { static_cast<WatchItem *>(it)->outdated = true; };
|
|
|
|
|
|
|
|
|
|
if (inames.isEmpty()) {
|
|
|
|
|
foreach (auto item, m_model->itemsAtLevel<WatchItem *>(2))
|
|
|
|
|
item->walkTree(marker);
|
|
|
|
|
} else {
|
|
|
|
|
foreach (auto iname, inames) {
|
|
|
|
|
if (WatchItem *item = m_model->findItem(iname))
|
|
|
|
|
item->walkTree(marker);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-17 13:26:20 +01:00
|
|
|
m_model->m_requestUpdateTimer.start(80);
|
2015-03-20 13:18:36 +01:00
|
|
|
m_model->m_contentsValid = false;
|
2015-03-18 13:28:45 +01:00
|
|
|
updateWatchersWindow();
|
2015-03-06 09:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-17 13:26:20 +01:00
|
|
|
void WatchHandler::notifyUpdateFinished()
|
2015-03-06 09:14:40 +01:00
|
|
|
{
|
2015-07-06 09:46:08 +02:00
|
|
|
struct OutDatedItemsFinder : public TreeItemVisitor
|
|
|
|
|
{
|
|
|
|
|
bool preVisit(TreeItem *item)
|
|
|
|
|
{
|
|
|
|
|
auto watchItem = static_cast<WatchItem *>(item);
|
|
|
|
|
if (level() <= 1 || !watchItem->outdated)
|
|
|
|
|
return true;
|
|
|
|
|
toRemove.append(watchItem);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-03-06 09:14:40 +01:00
|
|
|
|
2015-07-06 09:46:08 +02:00
|
|
|
QList<WatchItem *> toRemove;
|
|
|
|
|
} finder;
|
|
|
|
|
|
|
|
|
|
m_model->root()->walkTree(&finder);
|
|
|
|
|
|
|
|
|
|
foreach (auto item, finder.toRemove)
|
2015-06-15 15:40:22 +02:00
|
|
|
delete m_model->takeItem(item);
|
2015-01-28 15:14:15 +01:00
|
|
|
|
2015-03-20 13:18:36 +01:00
|
|
|
m_model->m_contentsValid = true;
|
2015-02-09 15:27:18 +01:00
|
|
|
updateWatchersWindow();
|
2015-07-06 09:46:08 +02:00
|
|
|
m_model->reexpandItems();
|
|
|
|
|
m_model->m_requestUpdateTimer.stop();
|
|
|
|
|
emit m_model->updateFinished();
|
2015-01-28 15:14:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-08 10:44:10 +02:00
|
|
|
void WatchHandler::reexpandItems()
|
|
|
|
|
{
|
|
|
|
|
m_model->reexpandItems();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 16:40:22 +01:00
|
|
|
void WatchHandler::removeItemByIName(const QByteArray &iname)
|
2009-06-24 12:31:09 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
WatchItem *item = m_model->findItem(iname);
|
2012-05-24 16:49:18 +02:00
|
|
|
if (!item)
|
|
|
|
|
return;
|
2015-03-19 12:42:53 +01:00
|
|
|
if (item->isWatcher()) {
|
|
|
|
|
theWatcherNames.remove(item->exp);
|
2012-05-24 16:49:18 +02:00
|
|
|
saveWatchers();
|
|
|
|
|
}
|
2015-06-09 09:33:14 +02:00
|
|
|
delete m_model->takeItem(item);
|
2012-05-24 16:24:53 +02:00
|
|
|
updateWatchersWindow();
|
2012-05-18 02:28:41 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-05 16:51:55 +01:00
|
|
|
QByteArray WatchHandler::watcherName(const QByteArray &exp)
|
2009-04-15 10:06:31 +02:00
|
|
|
{
|
2012-03-14 12:26:27 +01:00
|
|
|
return "watch." + QByteArray::number(theWatcherNames[exp]);
|
2009-04-15 10:06:31 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-10 21:22:02 +02:00
|
|
|
void WatchHandler::watchExpression(const QString &exp0, const QString &name)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-11-25 16:32:07 +01:00
|
|
|
// Do not insert the same entry more then once.
|
2015-03-18 13:28:45 +01:00
|
|
|
QByteArray exp = exp0.toLatin1();
|
|
|
|
|
if (exp.isEmpty() || theWatcherNames.contains(exp))
|
2010-07-22 15:34:35 +02:00
|
|
|
return;
|
|
|
|
|
|
2015-03-18 13:28:45 +01:00
|
|
|
theWatcherNames[exp] = theWatcherCount++;
|
2013-08-10 21:22:02 +02:00
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
auto item = new WatchItem;
|
|
|
|
|
item->exp = exp;
|
|
|
|
|
item->name = name.isEmpty() ? exp0 : name;
|
|
|
|
|
item->iname = watcherName(exp);
|
2015-07-15 17:14:29 +02:00
|
|
|
m_model->insertItem(item);
|
2011-02-28 18:55:54 +01:00
|
|
|
saveWatchers();
|
|
|
|
|
|
2015-03-20 13:18:36 +01:00
|
|
|
if (m_model->m_engine->state() == DebuggerNotReady) {
|
2015-03-19 12:42:53 +01:00
|
|
|
item->setAllUnneeded();
|
|
|
|
|
item->setValue(QString(QLatin1Char(' ')));
|
2015-08-11 14:13:06 +02:00
|
|
|
item->update();
|
|
|
|
|
} else {
|
|
|
|
|
m_model->m_engine->updateItem(item->iname);
|
|
|
|
|
}
|
|
|
|
|
updateWatchersWindow();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchHandler::updateWatchExpression(WatchItem *item, const QByteArray &newExp)
|
|
|
|
|
{
|
|
|
|
|
if (newExp.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (item->exp != newExp) {
|
|
|
|
|
theWatcherNames.insert(newExp, theWatcherNames.value(item->exp));
|
|
|
|
|
theWatcherNames.remove(item->exp);
|
|
|
|
|
item->exp = newExp;
|
|
|
|
|
item->name = QString::fromUtf8(item->exp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveWatchers();
|
|
|
|
|
if (m_model->m_engine->state() == DebuggerNotReady) {
|
|
|
|
|
item->setAllUnneeded();
|
|
|
|
|
item->setValue(QString(QLatin1Char(' ')));
|
|
|
|
|
item->update();
|
2010-11-23 13:28:18 +01:00
|
|
|
} else {
|
2015-07-15 17:14:29 +02:00
|
|
|
m_model->m_engine->updateItem(item->iname);
|
2010-11-23 13:28:18 +01:00
|
|
|
}
|
2010-06-16 11:08:54 +02:00
|
|
|
updateWatchersWindow();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-29 12:59:53 +01:00
|
|
|
// Watch something obtained from the editor.
|
|
|
|
|
// Prefer to watch an existing local variable by its expression
|
|
|
|
|
// (address) if it can be found. Default to watchExpression().
|
|
|
|
|
void WatchHandler::watchVariable(const QString &exp)
|
|
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
if (const WatchItem *localVariable = findCppLocalVariable(exp))
|
2012-10-29 12:59:53 +01:00
|
|
|
watchExpression(QLatin1String(localVariable->exp), exp);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2012-10-29 12:59:53 +01:00
|
|
|
watchExpression(exp);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-12 11:14:50 +01:00
|
|
|
static void swapEndian(char *d, int nchar)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-03-12 11:14:50 +01:00
|
|
|
QTC_ASSERT(nchar % 4 == 0, return);
|
|
|
|
|
for (int i = 0; i < nchar; i += 4) {
|
|
|
|
|
char c = d[i];
|
|
|
|
|
d[i] = d[i + 3];
|
|
|
|
|
d[i + 3] = c;
|
|
|
|
|
c = d[i + 1];
|
|
|
|
|
d[i + 1] = d[i + 2];
|
|
|
|
|
d[i + 2] = c;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
void WatchModel::showEditValue(const WatchItem *item)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-04-01 17:19:43 +02:00
|
|
|
const QByteArray key = item->address ? item->hexAddress() : item->iname;
|
|
|
|
|
switch (item->editformat) {
|
2012-12-14 11:50:14 +01:00
|
|
|
case StopDisplay:
|
2015-04-01 17:19:43 +02:00
|
|
|
m_separatedView->removeObject(key);
|
2012-12-14 11:50:14 +01:00
|
|
|
break;
|
|
|
|
|
case DisplayImageData:
|
|
|
|
|
case DisplayImageFile: { // QImage
|
2013-07-01 11:43:56 +02:00
|
|
|
int width = 0, height = 0, nbytes = 0, format = 0;
|
2010-03-17 13:03:34 +01:00
|
|
|
QByteArray ba;
|
2012-10-29 23:35:56 +02:00
|
|
|
uchar *bits = 0;
|
2015-04-01 17:19:43 +02:00
|
|
|
if (item->editformat == DisplayImageData) {
|
|
|
|
|
ba = QByteArray::fromHex(item->editvalue);
|
2013-07-01 11:43:56 +02:00
|
|
|
QTC_ASSERT(ba.size() > 16, return);
|
2010-03-17 13:03:34 +01:00
|
|
|
const int *header = (int *)(ba.data());
|
2012-12-28 18:57:33 +01:00
|
|
|
if (!ba.at(0) && !ba.at(1)) // Check on 'width' for Python dumpers returning 4-byte swapped-data.
|
2013-07-01 11:43:56 +02:00
|
|
|
swapEndian(ba.data(), 16);
|
|
|
|
|
bits = 16 + (uchar *)(ba.data());
|
2010-03-17 13:03:34 +01:00
|
|
|
width = header[0];
|
|
|
|
|
height = header[1];
|
2013-07-01 11:43:56 +02:00
|
|
|
nbytes = header[2];
|
|
|
|
|
format = header[3];
|
2015-04-01 17:19:43 +02:00
|
|
|
} else if (item->editformat == DisplayImageFile) {
|
|
|
|
|
QTextStream ts(item->editvalue);
|
2010-03-17 13:03:34 +01:00
|
|
|
QString fileName;
|
2013-07-01 11:43:56 +02:00
|
|
|
ts >> width >> height >> nbytes >> format >> fileName;
|
2010-03-17 13:03:34 +01:00
|
|
|
QFile f(fileName);
|
|
|
|
|
f.open(QIODevice::ReadOnly);
|
|
|
|
|
ba = f.readAll();
|
|
|
|
|
bits = (uchar*)ba.data();
|
2013-07-01 11:43:56 +02:00
|
|
|
nbytes = width * height;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2013-07-01 11:43:56 +02:00
|
|
|
QTC_ASSERT(0 < width && width < 10000, return);
|
|
|
|
|
QTC_ASSERT(0 < height && height < 10000, return);
|
|
|
|
|
QTC_ASSERT(0 < nbytes && nbytes < 10000 * 10000, return);
|
|
|
|
|
QTC_ASSERT(0 < format && format < 32, return);
|
|
|
|
|
QImage im(width, height, QImage::Format(format));
|
2014-08-28 17:33:47 +02:00
|
|
|
std::memcpy(im.bits(), bits, nbytes);
|
2015-04-01 17:19:43 +02:00
|
|
|
ImageViewer *v = m_separatedView->prepareObject<ImageViewer>(key, item->name);
|
|
|
|
|
v->setProperty(INameProperty, item->iname);
|
|
|
|
|
v->setInfo(item->address ?
|
|
|
|
|
tr("%1 Object at %2").arg(QLatin1String(item->type),
|
|
|
|
|
QLatin1String(item->hexAddress())) :
|
|
|
|
|
tr("%1 Object at Unknown Address").arg(QLatin1String(item->type))
|
|
|
|
|
+ QLatin1String(" ") +
|
|
|
|
|
ImageViewer::tr("Size: %1x%2, %3 byte, format: %4, depth: %5")
|
|
|
|
|
.arg(width).arg(height).arg(nbytes).arg(im.format()).arg(im.depth())
|
|
|
|
|
);
|
2014-05-17 21:00:22 +02:00
|
|
|
v->setImage(im);
|
2012-12-14 11:50:14 +01:00
|
|
|
break;
|
2014-05-17 21:00:22 +02:00
|
|
|
}
|
2012-12-14 11:50:14 +01:00
|
|
|
case DisplayUtf16String:
|
|
|
|
|
case DisplayLatin1String:
|
|
|
|
|
case DisplayUtf8String: { // String data.
|
2015-04-01 17:19:43 +02:00
|
|
|
QByteArray ba = QByteArray::fromHex(item->editvalue);
|
2012-10-04 13:03:01 +02:00
|
|
|
QString str;
|
2015-04-01 17:19:43 +02:00
|
|
|
if (item->editformat == DisplayUtf16String)
|
2012-10-04 13:03:01 +02:00
|
|
|
str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
|
2015-04-01 17:19:43 +02:00
|
|
|
else if (item->editformat == DisplayLatin1String)
|
2012-10-04 13:03:01 +02:00
|
|
|
str = QString::fromLatin1(ba.constData(), ba.size());
|
2015-04-01 17:19:43 +02:00
|
|
|
else if (item->editformat == DisplayUtf8String)
|
2012-10-04 13:03:01 +02:00
|
|
|
str = QString::fromUtf8(ba.constData(), ba.size());
|
2015-04-01 17:19:43 +02:00
|
|
|
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, item->name);
|
|
|
|
|
t->setProperty(INameProperty, item->iname);
|
2010-03-17 13:03:34 +01:00
|
|
|
t->setText(str);
|
2012-12-14 11:50:14 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2015-04-01 17:19:43 +02:00
|
|
|
case DisplayPlotData: { // Plots
|
|
|
|
|
std::vector<double> data;
|
|
|
|
|
readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding);
|
|
|
|
|
PlotViewer *v = m_separatedView->prepareObject<PlotViewer>(key, item->name);
|
|
|
|
|
v->setProperty(INameProperty, item->iname);
|
|
|
|
|
v->setData(data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-12-14 11:50:14 +01:00
|
|
|
default:
|
2015-04-01 17:19:43 +02:00
|
|
|
QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat);
|
2012-12-14 11:50:14 +01:00
|
|
|
break;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-14 17:28:37 +01:00
|
|
|
void WatchHandler::clearWatches()
|
|
|
|
|
{
|
2012-03-14 12:26:27 +01:00
|
|
|
if (theWatcherNames.isEmpty())
|
2011-01-14 17:28:37 +01:00
|
|
|
return;
|
2014-12-02 08:56:33 +01:00
|
|
|
|
2015-02-03 23:58:49 +02:00
|
|
|
const QDialogButtonBox::StandardButton ret = CheckableMessageBox::doNotAskAgainQuestion(
|
2014-12-02 08:56:33 +01:00
|
|
|
Core::ICore::mainWindow(), tr("Remove All Expression Evaluators"),
|
|
|
|
|
tr("Are you sure you want to remove all expression evaluators?"),
|
|
|
|
|
Core::ICore::settings(), QLatin1String("RemoveAllWatchers"));
|
|
|
|
|
if (ret != QDialogButtonBox::Yes)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-29 09:58:23 +01:00
|
|
|
m_model->m_watchRoot->removeChildren();
|
2012-03-14 12:26:27 +01:00
|
|
|
theWatcherNames.clear();
|
2015-03-16 09:10:36 +01:00
|
|
|
theWatcherCount = 0;
|
2011-01-14 17:28:37 +01:00
|
|
|
updateWatchersWindow();
|
|
|
|
|
saveWatchers();
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void WatchHandler::updateWatchersWindow()
|
|
|
|
|
{
|
2015-03-06 14:25:33 +01:00
|
|
|
emit m_model->columnAdjustmentRequested();
|
|
|
|
|
|
2010-06-23 14:11:52 +02:00
|
|
|
// Force show/hide of watchers and return view.
|
2015-03-18 13:28:45 +01:00
|
|
|
int showWatch = !theWatcherNames.isEmpty();
|
2015-04-22 14:49:14 +02:00
|
|
|
int showReturn = m_model->m_returnRoot->childCount() != 0;
|
2014-10-22 13:04:47 +02:00
|
|
|
Internal::updateWatchersWindow(showWatch, showReturn);
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
|
|
|
|
|
2010-11-04 18:11:09 +01:00
|
|
|
QStringList WatchHandler::watchedExpressions()
|
2008-12-17 17:43:01 +01:00
|
|
|
{
|
2009-12-04 13:22:39 +01:00
|
|
|
// Filter out invalid watchers.
|
2009-06-23 13:43:23 +02:00
|
|
|
QStringList watcherNames;
|
2012-03-14 12:26:27 +01:00
|
|
|
QHashIterator<QByteArray, int> it(theWatcherNames);
|
2009-07-03 11:20:47 +02:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2011-12-21 14:02:52 +01:00
|
|
|
const QByteArray &watcherName = it.key();
|
2010-07-23 18:20:13 +02:00
|
|
|
if (!watcherName.isEmpty())
|
2011-12-21 14:02:52 +01:00
|
|
|
watcherNames.push_back(QLatin1String(watcherName));
|
2009-06-23 13:43:23 +02:00
|
|
|
}
|
2009-12-04 13:22:39 +01:00
|
|
|
return watcherNames;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-17 17:43:01 +01:00
|
|
|
void WatchHandler::saveSessionData()
|
|
|
|
|
{
|
|
|
|
|
saveWatchers();
|
2013-11-28 14:28:20 +01:00
|
|
|
saveFormats();
|
2008-12-17 17:43:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchHandler::loadSessionData()
|
|
|
|
|
{
|
2013-11-28 14:28:20 +01:00
|
|
|
loadFormats();
|
2012-03-14 12:26:27 +01:00
|
|
|
theWatcherNames.clear();
|
2015-03-16 09:10:36 +01:00
|
|
|
theWatcherCount = 0;
|
2014-07-28 14:23:52 +02:00
|
|
|
QVariant value = sessionValue("Watchers");
|
2015-01-29 09:58:23 +01:00
|
|
|
m_model->m_watchRoot->removeChildren();
|
2010-11-25 16:32:07 +01:00
|
|
|
foreach (const QString &exp, value.toStringList())
|
2015-03-19 22:35:39 +02:00
|
|
|
watchExpression(exp.trimmed());
|
2010-11-04 18:11:09 +01:00
|
|
|
}
|
2010-06-25 09:53:23 +02:00
|
|
|
|
2014-11-07 13:50:09 +01:00
|
|
|
WatchModelBase *WatchHandler::model() const
|
2009-06-17 16:00:03 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
return m_model;
|
2009-07-10 14:36:28 +02:00
|
|
|
}
|
2010-01-29 21:33:57 +01:00
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
const WatchItem *WatchHandler::watchItem(const QModelIndex &idx) const
|
2009-06-17 16:00:03 +02:00
|
|
|
{
|
2015-04-22 12:37:39 +02:00
|
|
|
return static_cast<WatchItem *>(m_model->itemForIndex(idx));
|
2008-12-17 17:43:01 +01:00
|
|
|
}
|
2009-06-17 16:00:03 +02:00
|
|
|
|
2014-06-02 10:43:26 +02:00
|
|
|
void WatchHandler::fetchMore(const QByteArray &iname) const
|
2012-11-23 17:15:29 +01:00
|
|
|
{
|
2015-12-16 17:17:38 +01:00
|
|
|
if (WatchItem *item = m_model->findItem(iname)) {
|
|
|
|
|
m_model->m_expandedINames.insert(iname);
|
|
|
|
|
if (item->children().isEmpty()) {
|
|
|
|
|
item->setChildrenNeeded();
|
|
|
|
|
m_model->m_engine->expandItem(iname);
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-11-23 17:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-28 15:14:15 +01:00
|
|
|
WatchItem *WatchHandler::findItem(const QByteArray &iname) const
|
|
|
|
|
{
|
|
|
|
|
return m_model->findItem(iname);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
const WatchItem *WatchHandler::findCppLocalVariable(const QString &name) const
|
2012-08-31 11:34:27 +02:00
|
|
|
{
|
|
|
|
|
// Can this be found as a local variable?
|
|
|
|
|
const QByteArray localsPrefix("local.");
|
|
|
|
|
QByteArray iname = localsPrefix + name.toLatin1();
|
2015-03-19 12:42:53 +01:00
|
|
|
if (const WatchItem *item = findItem(iname))
|
|
|
|
|
return item;
|
2014-11-11 11:00:32 +01:00
|
|
|
// // Nope, try a 'local.this.m_foo'.
|
|
|
|
|
// iname.insert(localsPrefix.size(), "this.");
|
|
|
|
|
// if (const WatchData *wd = findData(iname))
|
|
|
|
|
// return wd;
|
2012-08-31 11:34:27 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
void WatchModel::setTypeFormat(const QByteArray &type0, int format)
|
2009-07-03 11:20:47 +02:00
|
|
|
{
|
2011-11-30 11:09:10 +01:00
|
|
|
const QByteArray type = stripForFormat(type0);
|
2014-04-15 18:13:03 +02:00
|
|
|
if (format == AutomaticFormat)
|
2012-03-14 12:26:27 +01:00
|
|
|
theTypeFormats.remove(type);
|
2010-05-19 15:15:56 +02:00
|
|
|
else
|
2012-03-14 12:26:27 +01:00
|
|
|
theTypeFormats[type] = format;
|
2013-11-28 14:28:20 +01:00
|
|
|
saveFormats();
|
2015-05-29 09:38:53 +02:00
|
|
|
m_engine->updateAll();
|
2009-07-03 11:20:47 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-01 17:19:43 +02:00
|
|
|
void WatchModel::setIndividualFormat(const QByteArray &iname, int format)
|
|
|
|
|
{
|
|
|
|
|
if (format == AutomaticFormat)
|
|
|
|
|
theIndividualFormats.remove(iname);
|
|
|
|
|
else
|
|
|
|
|
theIndividualFormats[iname] = format;
|
|
|
|
|
saveFormats();
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-11 18:55:52 +01:00
|
|
|
int WatchHandler::format(const QByteArray &iname) const
|
|
|
|
|
{
|
2014-04-15 18:13:03 +02:00
|
|
|
int result = AutomaticFormat;
|
2015-01-29 09:58:23 +01:00
|
|
|
if (const WatchItem *item = m_model->findItem(iname)) {
|
2015-03-19 12:42:53 +01:00
|
|
|
result = theIndividualFormats.value(item->iname, AutomaticFormat);
|
2014-04-15 18:13:03 +02:00
|
|
|
if (result == AutomaticFormat)
|
2015-03-19 12:42:53 +01:00
|
|
|
result = theTypeFormats.value(stripForFormat(item->type), AutomaticFormat);
|
2010-03-11 18:55:52 +01:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
QString WatchHandler::nameForFormat(int format)
|
|
|
|
|
{
|
|
|
|
|
return WatchModel::nameForFormat(format);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 08:53:18 +02:00
|
|
|
QByteArray WatchHandler::typeFormatRequests() const
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
2012-03-14 12:26:27 +01:00
|
|
|
if (!theTypeFormats.isEmpty()) {
|
|
|
|
|
QHashIterator<QByteArray, int> it(theTypeFormats);
|
2010-03-11 18:55:52 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2014-04-15 18:13:03 +02:00
|
|
|
const int format = it.value();
|
2015-03-20 16:03:59 +01:00
|
|
|
if (format != AutomaticFormat) {
|
2014-04-15 18:13:03 +02:00
|
|
|
ba.append(it.key().toHex());
|
|
|
|
|
ba.append('=');
|
|
|
|
|
ba.append(QByteArray::number(format));
|
|
|
|
|
ba.append(',');
|
|
|
|
|
}
|
2010-03-11 18:55:52 +01:00
|
|
|
}
|
|
|
|
|
ba.chop(1);
|
|
|
|
|
}
|
2010-04-27 08:53:18 +02:00
|
|
|
return ba;
|
|
|
|
|
}
|
2010-03-11 18:55:52 +01:00
|
|
|
|
2010-04-27 08:53:18 +02:00
|
|
|
QByteArray WatchHandler::individualFormatRequests() const
|
|
|
|
|
{
|
|
|
|
|
QByteArray ba;
|
2012-03-14 12:26:27 +01:00
|
|
|
if (!theIndividualFormats.isEmpty()) {
|
|
|
|
|
QHashIterator<QByteArray, int> it(theIndividualFormats);
|
2010-03-11 18:55:52 +01:00
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2014-04-15 18:13:03 +02:00
|
|
|
const int format = it.value();
|
2015-03-20 16:03:59 +01:00
|
|
|
if (format != AutomaticFormat) {
|
2014-04-15 18:13:03 +02:00
|
|
|
ba.append(it.key());
|
|
|
|
|
ba.append('=');
|
|
|
|
|
ba.append(QByteArray::number(it.value()));
|
|
|
|
|
ba.append(',');
|
|
|
|
|
}
|
2010-03-11 18:55:52 +01:00
|
|
|
}
|
|
|
|
|
ba.chop(1);
|
|
|
|
|
}
|
|
|
|
|
return ba;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 11:31:02 +01:00
|
|
|
void WatchHandler::appendFormatRequests(DebuggerCommand *cmd)
|
|
|
|
|
{
|
2015-09-14 13:40:35 +02:00
|
|
|
QJsonArray expanded;
|
2015-02-12 11:31:02 +01:00
|
|
|
QSetIterator<QByteArray> jt(m_model->m_expandedINames);
|
2015-09-14 13:40:35 +02:00
|
|
|
while (jt.hasNext())
|
|
|
|
|
expanded.append(QLatin1String(jt.next()));
|
|
|
|
|
|
|
|
|
|
cmd->arg("expanded", expanded);
|
2015-02-12 11:31:02 +01:00
|
|
|
|
2015-09-14 13:40:35 +02:00
|
|
|
QJsonObject typeformats;
|
2015-02-12 11:31:02 +01:00
|
|
|
QHashIterator<QByteArray, int> it(theTypeFormats);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
const int format = it.value();
|
2015-03-20 16:03:59 +01:00
|
|
|
if (format != AutomaticFormat)
|
2015-09-14 13:40:35 +02:00
|
|
|
typeformats.insert(QLatin1String(it.key()), format);
|
2015-02-12 11:31:02 +01:00
|
|
|
}
|
2015-09-14 13:40:35 +02:00
|
|
|
cmd->arg("typeformats", typeformats);
|
2015-02-12 11:31:02 +01:00
|
|
|
|
2015-09-14 13:40:35 +02:00
|
|
|
QJsonObject formats;
|
2015-02-12 11:31:02 +01:00
|
|
|
QHashIterator<QByteArray, int> it2(theIndividualFormats);
|
|
|
|
|
while (it2.hasNext()) {
|
|
|
|
|
it2.next();
|
|
|
|
|
const int format = it2.value();
|
2015-03-20 16:03:59 +01:00
|
|
|
if (format != AutomaticFormat)
|
2015-09-14 13:40:35 +02:00
|
|
|
formats.insert(QLatin1String(it2.key()), format);
|
2015-02-12 11:31:02 +01:00
|
|
|
}
|
2015-09-14 13:40:35 +02:00
|
|
|
cmd->arg("formats", formats);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QJsonObject watcher(const QByteArray &iname, const QByteArray &exp)
|
|
|
|
|
{
|
|
|
|
|
QJsonObject watcher;
|
|
|
|
|
watcher.insert(QStringLiteral("iname"), QLatin1String(iname));
|
|
|
|
|
watcher.insert(QStringLiteral("exp"), QLatin1String(exp.toHex()));
|
|
|
|
|
return watcher;
|
2015-02-12 11:31:02 +01:00
|
|
|
}
|
|
|
|
|
|
2015-09-14 12:53:35 +02:00
|
|
|
void WatchHandler::appendWatchersAndTooltipRequests(DebuggerCommand *cmd)
|
|
|
|
|
{
|
2015-09-14 13:40:35 +02:00
|
|
|
QJsonArray watchers;
|
2015-09-14 12:53:35 +02:00
|
|
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(m_model->m_engine);
|
2015-09-14 13:40:35 +02:00
|
|
|
foreach (const DebuggerToolTipContext &p, toolTips)
|
|
|
|
|
watchers.append(watcher(p.iname, p.expression.toLatin1()));
|
2015-09-14 12:53:35 +02:00
|
|
|
|
|
|
|
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
2015-09-14 13:40:35 +02:00
|
|
|
watchers.append(watcher("watch." + QByteArray::number(it.value()), it.key()));
|
2015-09-14 12:53:35 +02:00
|
|
|
}
|
2015-09-14 13:40:35 +02:00
|
|
|
cmd->arg("watchers", watchers);
|
2015-09-14 12:53:35 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-23 19:09:08 +01:00
|
|
|
void WatchHandler::addDumpers(const GdbMi &dumpers)
|
|
|
|
|
{
|
|
|
|
|
foreach (const GdbMi &dumper, dumpers.children()) {
|
2015-03-20 16:03:59 +01:00
|
|
|
DisplayFormats formats;
|
|
|
|
|
formats.append(RawFormat);
|
|
|
|
|
QByteArray reportedFormats = dumper["formats"].data();
|
|
|
|
|
foreach (const QByteArray &format, reportedFormats.split(',')) {
|
|
|
|
|
if (int f = format.toInt())
|
|
|
|
|
formats.append(DisplayFormat(f));
|
2015-01-23 19:09:08 +01:00
|
|
|
}
|
|
|
|
|
addTypeFormats(dumper["type"].data(), formats);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:03:59 +01:00
|
|
|
void WatchHandler::addTypeFormats(const QByteArray &type, const DisplayFormats &formats)
|
2010-06-25 09:07:14 +02:00
|
|
|
{
|
2012-05-18 02:28:41 +02:00
|
|
|
m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
|
2010-06-25 09:07:14 +02:00
|
|
|
}
|
|
|
|
|
|
2015-03-19 12:42:53 +01:00
|
|
|
static void showInEditorHelper(const WatchItem *item, QTextStream &ts, int depth)
|
|
|
|
|
{
|
|
|
|
|
const QChar tab = QLatin1Char('\t');
|
|
|
|
|
const QChar nl = QLatin1Char('\n');
|
|
|
|
|
ts << QString(depth, tab) << item->name << tab << item->value << tab
|
|
|
|
|
<< item->type << nl;
|
|
|
|
|
foreach (const TreeItem *child, item->children())
|
|
|
|
|
showInEditorHelper(static_cast<const WatchItem *>(child), ts, depth + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-05 19:38:40 +01:00
|
|
|
QString WatchHandler::editorContents()
|
2010-09-08 09:09:09 +02:00
|
|
|
{
|
|
|
|
|
QString contents;
|
2015-03-19 12:42:53 +01:00
|
|
|
QTextStream ts(&contents);
|
|
|
|
|
showInEditorHelper(m_model->root(), ts, 0);
|
2010-11-05 19:38:40 +01:00
|
|
|
return contents;
|
2010-09-08 09:09:09 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-17 18:44:02 +01:00
|
|
|
void WatchHandler::scheduleResetLocation()
|
|
|
|
|
{
|
2015-03-20 13:18:36 +01:00
|
|
|
m_model->m_contentsValid = false;
|
|
|
|
|
m_model->m_resetLocationScheduled = true;
|
2012-01-17 18:44:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WatchHandler::resetLocation()
|
|
|
|
|
{
|
2015-03-20 13:18:36 +01:00
|
|
|
m_model->m_resetLocationScheduled = false;
|
2012-01-17 18:44:02 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
void WatchHandler::setCurrentItem(const QByteArray &iname)
|
2012-04-18 14:20:54 +02:00
|
|
|
{
|
2015-03-20 13:18:36 +01:00
|
|
|
if (WatchItem *item = m_model->findItem(iname)) {
|
2015-04-22 12:37:39 +02:00
|
|
|
QModelIndex idx = m_model->indexForItem(item);
|
2015-03-20 13:18:36 +01:00
|
|
|
emit m_model->currentIndexRequested(idx);
|
|
|
|
|
}
|
2012-04-18 14:20:54 +02:00
|
|
|
}
|
|
|
|
|
|
2012-03-14 12:26:27 +01:00
|
|
|
QHash<QByteArray, int> WatchHandler::watcherNames()
|
|
|
|
|
{
|
|
|
|
|
return theWatcherNames;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-18 02:28:41 +02:00
|
|
|
void WatchHandler::setUnprintableBase(int base)
|
|
|
|
|
{
|
|
|
|
|
theUnprintableBase = base;
|
2015-01-29 09:58:23 +01:00
|
|
|
m_model->layoutChanged();
|
2012-05-18 02:28:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WatchHandler::unprintableBase()
|
|
|
|
|
{
|
|
|
|
|
return theUnprintableBase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WatchHandler::isExpandedIName(const QByteArray &iname) const
|
|
|
|
|
{
|
|
|
|
|
return m_model->m_expandedINames.contains(iname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSet<QByteArray> WatchHandler::expandedINames() const
|
|
|
|
|
{
|
|
|
|
|
return m_model->m_expandedINames;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-17 16:00:03 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|