Debugger: Add special widgets for editing watch values.

Create delegate widgets with validation for bool/int/float
types, using a QVariant-type modelData property.
Also fix register editing to be validated for quint64 values
and editing longer values as hex bigints. Anything else is not
editable.
This commit is contained in:
Friedemann Kleint
2010-09-22 17:30:22 +02:00
parent 596e60305a
commit ca808cc7b4
12 changed files with 630 additions and 64 deletions
+4 -2
View File
@@ -52,7 +52,8 @@ HEADERS += breakhandler.h \
watchhandler.h \ watchhandler.h \
watchutils.h \ watchutils.h \
watchwindow.h \ watchwindow.h \
threadshandler.h threadshandler.h \
watchdelegatewidgets.h
SOURCES += breakhandler.cpp \ SOURCES += breakhandler.cpp \
breakpoint.cpp \ breakpoint.cpp \
@@ -88,7 +89,8 @@ SOURCES += breakhandler.cpp \
watchhandler.cpp \ watchhandler.cpp \
watchutils.cpp \ watchutils.cpp \
watchwindow.cpp \ watchwindow.cpp \
stackframe.cpp stackframe.cpp \
watchdelegatewidgets.cpp
FORMS += attachexternaldialog.ui \ FORMS += attachexternaldialog.ui \
attachcoredialog.ui \ attachcoredialog.ui \
+3
View File
@@ -223,6 +223,8 @@ enum ModelRoles
// Locals and Watchers // Locals and Watchers
LocalsINameRole, LocalsINameRole,
LocalsEditTypeRole, // A QVariant::type describing the item
LocalsIntegerBaseRole, // Number base 16, 10, 8, 2
LocalsExpressionRole, LocalsExpressionRole,
LocalsExpandedRole, // The preferred expanded state to the view LocalsExpandedRole, // The preferred expanded state to the view
LocalsTypeFormatListRole, LocalsTypeFormatListRole,
@@ -265,6 +267,7 @@ enum ModelRoles
RegisterNumberBaseRole, // Currently used number base RegisterNumberBaseRole, // Currently used number base
RegisterAddressRole, // Start value for opening memory view RegisterAddressRole, // Start value for opening memory view
RegisterChangedRole, // Used for painting changed values RegisterChangedRole, // Used for painting changed values
RegisterBigNumberRole, // Register is a big integer that cannot be handled as quint64.
RequestSetRegisterRole, RequestSetRegisterRole,
RequestReloadRegistersRole, RequestReloadRegistersRole,
+31 -29
View File
@@ -33,6 +33,7 @@
#include "debuggeragents.h" #include "debuggeragents.h"
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include "debuggerengine.h" #include "debuggerengine.h"
#include "watchdelegatewidgets.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -68,17 +69,27 @@ int RegisterHandler::columnCount(const QModelIndex &parent) const
return parent.isValid() ? 0 : 2; return parent.isValid() ? 0 : 2;
} }
inline QString RegisterHandler::value(const Register &reg, bool padded) const // Editor value: Preferably number, else string.
QVariant RegisterHandler::editValue(const Register &reg)
{ {
bool ok = true; bool ok = true;
// Try to convert to number? // Try to convert to number?
const qulonglong value = reg.value.toULongLong(&ok, 0); // Autodetect format const qulonglong value = reg.value.toULongLong(&ok, 0); // Autodetect format
if (ok) if (ok)
return QString::fromAscii("%1").arg(value, (padded ? m_strlen : 0), m_base); return QVariant(value);
// Cannot convert, return raw string. return QVariant(reg.value);
if (padded && reg.value.size() < m_strlen) }
return QString(m_strlen - reg.value.size(), QLatin1Char(' ')) + reg.value;
return reg.value; // Editor value: Preferably padded number, else padded string.
inline QString RegisterHandler::displayValue(const Register &reg) const
{
const QVariant editV = RegisterHandler::editValue(reg);
if (editV.type() == QVariant::ULongLong)
return QString::fromAscii("%1").arg(editV.toULongLong(), m_strlen, m_base);
const QString stringValue = editV.toString();
if (stringValue.size() < m_strlen)
return QString(m_strlen - stringValue.size(), QLatin1Char(' ')) + reg.value;
return stringValue;
} }
QVariant RegisterHandler::data(const QModelIndex &index, int role) const QVariant RegisterHandler::data(const QModelIndex &index, int role) const
@@ -92,9 +103,6 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
case EngineActionsEnabledRole: case EngineActionsEnabledRole:
return m_engine->debuggerActionsEnabled(); return m_engine->debuggerActionsEnabled();
case RegisterNumberBaseRole:
return m_base;
} }
if (!index.isValid() || index.row() >= m_registers.size()) if (!index.isValid() || index.row() >= m_registers.size())
@@ -105,11 +113,9 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
switch (role) { switch (role) {
case RegisterAddressRole: { case RegisterAddressRole: {
// Return some address associated with the register. Autodetect format // Return some address associated with the register. Autodetect format
bool ok = true; const QVariant editV = RegisterHandler::editValue(reg);
qulonglong value = reg.value.toULongLong(&ok, 0); return editV.type() == QVariant::ULongLong ? editV : QVariant();
return ok ? QVariant(QString::fromLatin1("0x") + QString::number(value, 16)) : QVariant();
} }
break;
case Qt::DisplayRole: case Qt::DisplayRole:
switch (index.column()) { switch (index.column()) {
@@ -118,14 +124,18 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
return QVariant(padding + reg.name + padding); return QVariant(padding + reg.name + padding);
} }
case 1: // Display: Pad value for alignment case 1: // Display: Pad value for alignment
return value(reg, true); return displayValue(reg);
} // switch column } // switch column
case Qt::EditRole: // Edit: Unpadded for editing case Qt::EditRole: // Edit: Unpadded for editing
return value(reg, false); return RegisterHandler::editValue(reg);
case Qt::TextAlignmentRole: case Qt::TextAlignmentRole:
return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant(); return index.column() == 1 ? QVariant(Qt::AlignRight) : QVariant();
case RegisterChangedRole: case RegisterChangedRole:
return QVariant(reg.changed); return QVariant(reg.changed);
case RegisterBigNumberRole: // Editor: Can it be handled as quint64?
return editValue(reg).type() != QVariant::ULongLong;
case RegisterNumberBaseRole: // Big integers are assumed to be hexadecimal
return editValue(reg).type() == QVariant::ULongLong ? m_base : 16;
default: default:
break; break;
} }
@@ -146,22 +156,14 @@ QVariant RegisterHandler::headerData(int section, Qt::Orientation orientation,
Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const Qt::ItemFlags RegisterHandler::flags(const QModelIndex &idx) const
{ {
using namespace Qt;
if (!idx.isValid()) if (!idx.isValid())
return ItemFlags(); return Qt::ItemFlags();
static const ItemFlags notEditable = const Qt::ItemFlags notEditable = Qt::ItemIsSelectable|Qt::ItemIsEnabled;
ItemIsSelectable // Can edit registers if they are hex numbers and not arrays.
// | ItemIsDragEnabled if (idx.column() == 1 && IntegerWatchLineEdit::isUnsignedHexNumber(m_registers.at(idx.row()).value))
// | ItemIsDropEnabled return notEditable | Qt::ItemIsEditable;
| ItemIsEnabled; return notEditable;
static const ItemFlags editable = notEditable | ItemIsEditable;
if (idx.column() == 1)
return editable; // locals and watcher values are editable
return notEditable;
} }
bool RegisterHandler::setData(const QModelIndex &index, const QVariant &value, int role) bool RegisterHandler::setData(const QModelIndex &index, const QVariant &value, int role)
+2 -1
View File
@@ -73,7 +73,8 @@ public:
private: private:
void calculateWidth(); void calculateWidth();
inline QString value(const Register &reg, bool padded) const; inline QString displayValue(const Register &reg) const;
static QVariant editValue(const Register &reg);
int rowCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+15 -13
View File
@@ -32,6 +32,8 @@
#include "debuggeractions.h" #include "debuggeractions.h"
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include "watchdelegatewidgets.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/savedaction.h> #include <utils/savedaction.h>
@@ -66,31 +68,31 @@ public:
{} {}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
const QModelIndex &) const const QModelIndex &index) const
{ {
QLineEdit *lineEdit = new QLineEdit(parent); IntegerWatchLineEdit *lineEdit = new IntegerWatchLineEdit(parent);
lineEdit->setBase(index.data(RegisterNumberBaseRole).toInt());
lineEdit->setBigInt(index.data(RegisterBigNumberRole).toBool());
lineEdit->setSigned(false);
lineEdit->setAlignment(Qt::AlignRight); lineEdit->setAlignment(Qt::AlignRight);
return lineEdit; return lineEdit;
} }
void setEditorData(QWidget *editor, const QModelIndex &index) const void setEditorData(QWidget *editor, const QModelIndex &index) const
{ {
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor); IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit *>(editor);
QTC_ASSERT(lineEdit, return); QTC_ASSERT(lineEdit, return);
lineEdit->setText(index.data(Qt::EditRole).toString()); lineEdit->setModelData(index.data(Qt::EditRole));
} }
void setModelData(QWidget *editor, QAbstractItemModel *model, void setModelData(QWidget *editor, QAbstractItemModel *, const QModelIndex &index) const
const QModelIndex &index) const
{ {
Q_UNUSED(model); if (index.column() != 1)
//qDebug() << "SET MODEL DATA"; return;
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(editor); IntegerWatchLineEdit *lineEdit = qobject_cast<IntegerWatchLineEdit*>(editor);
QTC_ASSERT(lineEdit, return); QTC_ASSERT(lineEdit, return);
QString value = lineEdit->text(); m_owner->model()->setData(index, lineEdit->modelData(), RequestSetRegisterRole);
//model->setData(index, value, Qt::EditRole);
if (index.column() == 1)
m_owner->model()->setData(index, value, RequestSetRegisterRole);
} }
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
@@ -0,0 +1,346 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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://qt.nokia.com/contact.
**
**************************************************************************/
#include "watchdelegatewidgets.h"
#include <QtGui/QDoubleValidator>
#include <QtCore/QDebug>
#include <utils/qtcassert.h>
enum { debug = 0 };
namespace Debugger {
namespace Internal {
// Basic watch line edit.
WatchLineEdit::WatchLineEdit(QWidget *parent) : QLineEdit(parent)
{
}
QVariant WatchLineEdit::modelData() const
{
return QVariant(text());
}
void WatchLineEdit::setModelData(const QVariant &v)
{
if (debug)
qDebug("WatchLineEdit::setModelData(%s, '%s')", v.typeName(), qPrintable(v.toString()));
setText(v.toString());
}
/* ------ IntegerWatchLineEdit helpers:
* Integer validator using different number bases. */
class IntegerValidator : public QValidator {
public:
explicit IntegerValidator(QObject *parent);
virtual State validate(QString &, int &) const;
int base() const { return m_base; }
void setBase(int b) { m_base = b; }
bool isSigned() const { return m_signed; }
void setSigned(bool s) { m_signed = s; }
bool isBigInt() const { return m_bigInt; }
void setBigInt(bool b) { m_bigInt = b; }
static State validateEntry(const QString &s, int base, bool signedV, bool bigInt);
private:
static inline bool isCharAcceptable(const QChar &c, int base);
int m_base;
bool m_signed;
bool m_bigInt;
};
IntegerValidator::IntegerValidator(QObject *parent) :
QValidator(parent), m_base(10), m_signed(true), m_bigInt(false)
{
}
// Check valid digits depending on base.
bool IntegerValidator::isCharAcceptable(const QChar &c, int base)
{
if (c.isLetter())
return base == 16 && c.toLower().toAscii() <= 'f';
if (!c.isDigit())
return false;
const int digit = c.toAscii() - '0';
if (base == 8 && digit > 7)
return false;
if (base == 2 && digit > 1)
return false;
return true;
}
QValidator::State IntegerValidator::validate(QString &s, int &) const
{
return IntegerValidator::validateEntry(s, m_base, m_signed, m_bigInt);
}
QValidator::State IntegerValidator::validateEntry(const QString &s, int base, bool signedV, bool bigInt)
{
const int size = s.size();
if (!size)
return QValidator::Intermediate;
int pos = 0;
// Skip sign.
if (signedV && s.at(pos) == '-') {
pos++;
if (pos == size)
return QValidator::Intermediate;
}
// Hexadecimal: '0x'?
if (base == 16 && pos + 2 <= size
&& s.at(pos) == QLatin1Char('0') && s.at(pos + 1) == QLatin1Char('x')) {
pos+= 2;
if (pos == size)
return QValidator::Intermediate;
}
// Check characters past sign.
for (; pos < size; pos++)
if (!isCharAcceptable(s.at(pos), base))
return QValidator::Invalid;
// Check conversion unless big integer
if (bigInt)
return QValidator::Acceptable;
bool ok;
if (signedV) {
s.toLongLong(&ok, base);
} else {
s.toULongLong(&ok, base);
}
return ok ? QValidator::Acceptable : QValidator::Intermediate;
}
IntegerWatchLineEdit::IntegerWatchLineEdit(QWidget *parent) :
WatchLineEdit(parent),
m_validator(new IntegerValidator(this))
{
setValidator(m_validator);
}
bool IntegerWatchLineEdit::isUnsignedHexNumber(const QString &v)
{
return IntegerValidator::validateEntry(v, 16, false, true) == QValidator::Acceptable;
}
int IntegerWatchLineEdit::base() const
{
return m_validator->base();
}
void IntegerWatchLineEdit::setBase(int b)
{
QTC_ASSERT(b, return; )
m_validator->setBase(b);
}
bool IntegerWatchLineEdit::isSigned() const
{
return m_validator->isSigned();
}
void IntegerWatchLineEdit::setSigned(bool s)
{
m_validator->setSigned(s);
}
bool IntegerWatchLineEdit::isBigInt() const
{
return m_validator->isBigInt();
}
void IntegerWatchLineEdit::setBigInt(bool b)
{
m_validator->setBigInt(b);
}
QVariant IntegerWatchLineEdit::modelDataI() const
{
if (isBigInt()) // Big integer: Plain text
return QVariant(text());
bool ok;
if (isSigned()) {
const qint64 value = text().toLongLong(&ok, base());
if (ok)
return QVariant(value);
} else {
const quint64 value = text().toULongLong(&ok, base());
if (ok)
return QVariant(value);
}
return QVariant();
}
QVariant IntegerWatchLineEdit::modelData() const
{
const QVariant data = modelDataI();
if (debug)
qDebug("IntegerLineEdit::modelData(): base=%d, signed=%d, bigint=%d returns %s '%s'",
base(), isSigned(), isBigInt(), data.typeName(), qPrintable(data.toString()));
return data;
}
void IntegerWatchLineEdit::setModelData(const QVariant &v)
{
if (debug)
qDebug(">IntegerLineEdit::setModelData(%s, '%s'): base=%d, signed=%d, bigint=%d",
v.typeName(), qPrintable(v.toString()),
base(), isSigned(), isBigInt());
switch (v.type()) {
case QVariant::Int:
case QVariant::LongLong: {
const qint64 iv = v.toLongLong();
setSigned(true);
setText(QString::number(iv, base()));
}
break;
case QVariant::UInt:
case QVariant::ULongLong: {
const quint64 iv = v.toULongLong();
setSigned(false);
setText(QString::number(iv, base()));
}
break;
case QVariant::ByteArray:
setNumberText(QString::fromAscii(v.toByteArray()));
break;
case QVariant::String:
setNumberText(v.toString());
break;
default:
qWarning("Invalid value (%s) passed to IntegerLineEdit::setModelData",
v.typeName());
setText(QString(QLatin1Char('0')));
break;
}
if (debug)
qDebug("<IntegerLineEdit::setModelData(): base=%d, signed=%d, bigint=%d",
base(), isSigned(), isBigInt());
}
void IntegerWatchLineEdit::setNumberText(const QString &t)
{
setText(t);
}
// ------------- FloatWatchLineEdit
FloatWatchLineEdit::FloatWatchLineEdit(QWidget *parent) :
WatchLineEdit(parent)
{
setValidator(new QDoubleValidator(this));
}
QVariant FloatWatchLineEdit::modelData() const
{
return QVariant(text().toDouble());
}
void FloatWatchLineEdit::setModelData(const QVariant &v)
{
if (debug)
qDebug("FloatWatchLineEdit::setModelData(%s, '%s')",
v.typeName(), qPrintable(v.toString()));
switch (v.type()) {
break;
case QVariant::Double:
case QVariant::String:
setText(v.toString());
break;
case QVariant::ByteArray:
setText(QString::fromAscii(v.toByteArray()));
break;
default:
qWarning("Invalid value (%s) passed to FloatWatchLineEdit::setModelData",
v.typeName());
setText(QString::number(0.0));
break;
}
}
WatchLineEdit *WatchLineEdit::create(QVariant::Type t, QWidget *parent)
{
switch (t) {
case QVariant::Bool:
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
return new IntegerWatchLineEdit(parent);
break;
case QVariant::Double:
return new FloatWatchLineEdit(parent);
default:
break;
}
return new WatchLineEdit(parent);
}
BooleanComboBox::BooleanComboBox(QWidget *parent) : QComboBox(parent)
{
QStringList items;
items << QLatin1String("false") << QLatin1String("true");
addItems(items);
}
QVariant BooleanComboBox::modelData() const
{
// As not to confuse debuggers with 'true', 'false', we return integers 1,0.
const int rc = currentIndex() == 1 ? 1 : 0;
return QVariant(rc);
}
void BooleanComboBox::setModelData(const QVariant &v)
{
if (debug)
qDebug("BooleanComboBox::setModelData(%s, '%s')", v.typeName(), qPrintable(v.toString()));
bool value = false;
switch (v.type()) {
case QVariant::Bool:
value = v.toBool();
break;
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
value = v.toInt() != 0;
break;
default:
qWarning("Invalid value (%s) passed to BooleanComboBox::setModelData", v.typeName());
break;
}
setCurrentIndex(value ? 1 : 0);
}
} // namespace Internal
} // namespace Debugger
+118
View File
@@ -0,0 +1,118 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef WATCHDELEGATEEDITS_H
#define WATCHDELEGATEEDITS_H
#include <QtGui/QLineEdit>
#include <QtGui/QComboBox>
#include <QtCore/QVariant>
namespace Debugger {
namespace Internal {
class IntegerValidator;
/* Watch edit widgets. The logic is based on the QVariant 'modelData' property,
* which is accessed by the WatchDelegate. */
/* WatchLineEdit: Base class for Watch delegate line edits with
* ready-made accessors for the model's QVariants for QString-text use. */
class WatchLineEdit : public QLineEdit
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText USER false)
Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData DESIGNABLE false USER true)
public:
explicit WatchLineEdit(QWidget *parent = 0);
// Ready-made accessors for item views passing QVariants around
virtual QVariant modelData() const;
virtual void setModelData(const QVariant &);
static WatchLineEdit *create(QVariant::Type t, QWidget *parent = 0);
};
/* Watch delegate line edit for integer numbers based on quint64/qint64.
* Does validation using the given number base (10, 16, 8, 2) and signedness.
* isBigInt() indicates that no checking for number conversion is to be performed
* (that is, value cannot be handled as quint64/qint64, for 128bit registers, etc). */
class IntegerWatchLineEdit : public WatchLineEdit
{
Q_OBJECT
Q_PROPERTY(int base READ base WRITE setBase DESIGNABLE true)
Q_PROPERTY(bool Signed READ isSigned WRITE setSigned DESIGNABLE true)
Q_PROPERTY(bool bigInt READ isBigInt WRITE setBigInt DESIGNABLE true)
public:
explicit IntegerWatchLineEdit(QWidget *parent = 0);
// Ready-made accessors for item views passing QVariants around
virtual QVariant modelData() const;
virtual void setModelData(const QVariant &);
int base() const;
void setBase(int b);
bool isSigned() const;
void setSigned(bool s);
bool isBigInt() const;
void setBigInt(bool b);
static bool isUnsignedHexNumber(const QString &v);
private:
void setNumberText(const QString &);
inline QVariant modelDataI() const;
IntegerValidator *m_validator;
};
/* Float line edit */
class FloatWatchLineEdit : public WatchLineEdit
{
public:
explicit FloatWatchLineEdit(QWidget *parent = 0);
virtual QVariant modelData() const;
virtual void setModelData(const QVariant &);
};
/* Combo box for booleans */
class BooleanComboBox : public QComboBox
{
Q_OBJECT
Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData DESIGNABLE false USER true)
public:
explicit BooleanComboBox(QWidget *parent = 0);
virtual QVariant modelData() const;
virtual void setModelData(const QVariant &);
};
} // namespace Internal
} // namespace Debugger
#endif // WATCHDELEGATEEDITS_H
+70 -7
View File
@@ -392,6 +392,23 @@ QByteArray WatchModel::niceType(const QByteArray &typeIn) const
return type; return type;
} }
static inline int formatToIntegerBase(int format)
{
switch (format) {
case Debugger::Internal::HexadecimalFormat:
return 16;
break;
case Debugger::Internal::BinaryFormat:
return 2;
break;
case Debugger::Internal::OctalFormat:
return 8;
default:
break;
}
return 10;
}
template <class IntType> QString reformatInteger(IntType value, int format) template <class IntType> QString reformatInteger(IntType value, int format)
{ {
switch (format) { switch (format) {
@@ -470,6 +487,41 @@ static inline QString formattedValue(const WatchData &data, int format)
return result; return result;
} }
// Return the type used for editing
static inline int editType(const WatchData &d)
{
if (d.type == "bool")
return QVariant::Bool;
if (isIntType(d.type))
return d.type.contains('u') ? QVariant::ULongLong : QVariant::LongLong;
if (isFloatType(d.type))
return QVariant::Double;
return QVariant::String;
}
// Convert to editable (see above)
static inline QVariant editValue(const WatchData &d)
{
switch (editType(d)) {
case QVariant::Bool:
return d.value != QLatin1String("0") && d.value != QLatin1String("false");
case QVariant::ULongLong:
return QVariant(d.value.toULongLong());
break;
case QVariant::LongLong:
return QVariant(d.value.toLongLong());
break;
case QVariant::Double:
return QVariant(d.value.toDouble());
default:
break;
}
// Replace newlines, which will cause line edit troubles.
QString stringValue;
stringValue.replace(QLatin1String("\n"), QLatin1String("\\n"));
return QVariant(stringValue);
}
bool WatchModel::canFetchMore(const QModelIndex &index) const bool WatchModel::canFetchMore(const QModelIndex &index) const
{ {
WatchItem *item = watchItem(index); WatchItem *item = watchItem(index);
@@ -612,6 +664,14 @@ static inline quint64 pointerValue(QString data)
return ok ? address : quint64(0); return ok ? address : quint64(0);
} }
int WatchModel::itemFormat(const WatchData &data) const
{
const int individualFormat = m_handler->m_individualFormats.value(data.iname, -1);
if (individualFormat != -1)
return individualFormat;
return m_handler->m_typeFormats.value(data.type, -1);
}
QVariant WatchModel::data(const QModelIndex &idx, int role) const QVariant WatchModel::data(const QModelIndex &idx, int role) const
{ {
switch (role) { switch (role) {
@@ -626,6 +686,10 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
const WatchItem &data = *item; const WatchItem &data = *item;
switch (role) { switch (role) {
case LocalsEditTypeRole:
return QVariant(editType(data));
case LocalsIntegerBaseRole:
return QVariant(formatToIntegerBase(itemFormat(data)));
case Qt::EditRole: case Qt::EditRole:
case Qt::DisplayRole: { case Qt::DisplayRole: {
switch (idx.column()) { switch (idx.column()) {
@@ -635,13 +699,12 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
if (data.name == QLatin1String("*") && item->parent) if (data.name == QLatin1String("*") && item->parent)
return QVariant(QLatin1Char('*') + item->parent->name); return QVariant(QLatin1Char('*') + item->parent->name);
return data.name; return data.name;
case 1: { case 1:
int format = if (role == Qt::DisplayRole) {
m_handler->m_individualFormats.value(data.iname, -1); return truncateValue(formattedValue(data, itemFormat(data)));
if (format == -1) } else {
format = m_handler->m_typeFormats.value(data.type, -1); return editValue(data);
return truncateValue(formattedValue(data, format)); }
}
case 2: { case 2: {
if (!data.displayedType.isEmpty()) if (!data.displayedType.isEmpty())
return data.displayedType; return data.displayedType;
+1
View File
@@ -122,6 +122,7 @@ private:
QByteArray niceType(const QByteArray &typeIn) const; QByteArray niceType(const QByteArray &typeIn) const;
void formatRequests(QByteArray *out, const WatchItem *item) const; void formatRequests(QByteArray *out, const WatchItem *item) const;
DebuggerEngine *engine() const; DebuggerEngine *engine() const;
int itemFormat(const WatchData &data) const;
WatchHandler *m_handler; WatchHandler *m_handler;
WatchType m_type; WatchType m_type;
+6 -1
View File
@@ -580,9 +580,14 @@ bool isSymbianIntType(const QByteArray &type)
return type == "TInt" || type == "TBool"; return type == "TInt" || type == "TBool";
} }
bool isFloatType(const QByteArray &type)
{
return type == "float" || type == "double" || type == "qreal";
}
bool isIntOrFloatType(const QByteArray &type) bool isIntOrFloatType(const QByteArray &type)
{ {
return isIntType(type) || type == "float" || type == "double"; return isIntType(type) || isFloatType(type);
} }
GuessChildrenResult guessChildren(const QByteArray &type) GuessChildrenResult guessChildren(const QByteArray &type)
+1
View File
@@ -77,6 +77,7 @@ QByteArray stripPointerType(QByteArray type);
QByteArray gdbQuoteTypes(const QByteArray &type); QByteArray gdbQuoteTypes(const QByteArray &type);
bool extractTemplate(const QString &type, QString *tmplate, QString *inner); bool extractTemplate(const QString &type, QString *tmplate, QString *inner);
QString extractTypeFromPTypeOutput(const QString &str); QString extractTypeFromPTypeOutput(const QString &str);
bool isFloatType(const QByteArray &type);
bool isIntOrFloatType(const QByteArray &type); bool isIntOrFloatType(const QByteArray &type);
bool isIntType(const QByteArray &type); bool isIntType(const QByteArray &type);
bool isSymbianIntType(const QByteArray &type); bool isSymbianIntType(const QByteArray &type);
+33 -11
View File
@@ -34,12 +34,14 @@
#include "debuggerengine.h" #include "debuggerengine.h"
#include "debuggerdialogs.h" #include "debuggerdialogs.h"
#include "watchhandler.h" #include "watchhandler.h"
#include "watchdelegatewidgets.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/savedaction.h> #include <utils/savedaction.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <QtCore/QVariant>
#include <QtGui/QAction> #include <QtGui/QAction>
#include <QtGui/QContextMenuEvent> #include <QtGui/QContextMenuEvent>
@@ -67,34 +69,54 @@ public:
WatchDelegate(QObject *parent) : QItemDelegate(parent) {} WatchDelegate(QObject *parent) : QItemDelegate(parent) {}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
const QModelIndex &) const const QModelIndex &index) const
{ {
// Value column: Custom editor. Apply integer-specific settings.
if (index.column() == 1) {
const QVariant::Type type = static_cast<QVariant::Type>(index.data(LocalsEditTypeRole).toInt());
switch (type) {
case QVariant::Bool:
return new BooleanComboBox(parent);
default:
break;
}
WatchLineEdit *edit = WatchLineEdit::create(type, parent);
if (IntegerWatchLineEdit *intEdit = qobject_cast<IntegerWatchLineEdit *>(edit))
intEdit->setBase(index.data(LocalsIntegerBaseRole).toInt());
return edit;
}
// Standard line edits for the rest
return new QLineEdit(parent); return new QLineEdit(parent);
} }
void setEditorData(QWidget *editor, const QModelIndex &index) const void setEditorData(QWidget *editor, const QModelIndex &index) const
{ {
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor); if (index.column() == 1) {
QTC_ASSERT(lineEdit, return); editor->setProperty("modelData", index.data(Qt::EditRole));
if (index.column() == 1) } else {
lineEdit->setText(index.data(Qt::DisplayRole).toString()); QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor);
else QTC_ASSERT(lineEdit, return);
lineEdit->setText(index.data(LocalsExpressionRole).toString()); lineEdit->setText(index.data(LocalsExpressionRole).toString());
}
} }
void setModelData(QWidget *editor, QAbstractItemModel *model, void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const const QModelIndex &index) const
{ {
const QString exp = index.data(LocalsExpressionRole).toString();
if (index.column() == 1) { // The value column.
const QVariant value = editor->property("modelData");
QTC_ASSERT(value.isValid(), return);
const QString command = exp + QLatin1Char('=') + value.toString();
model->setData(index, QVariant(command), RequestAssignValueRole);
return;
}
//qDebug() << "SET MODEL DATA"; //qDebug() << "SET MODEL DATA";
QLineEdit *lineEdit = qobject_cast<QLineEdit*>(editor); QLineEdit *lineEdit = qobject_cast<QLineEdit*>(editor);
QTC_ASSERT(lineEdit, return); QTC_ASSERT(lineEdit, return);
const QString value = lineEdit->text(); const QString value = lineEdit->text();
const QString exp = index.data(LocalsExpressionRole).toString();
model->setData(index, value, Qt::EditRole); model->setData(index, value, Qt::EditRole);
if (index.column() == 1) { if (index.column() == 2) {
// The value column.
model->setData(index, QString(exp + '=' + value), RequestAssignValueRole);
} else if (index.column() == 2) {
// The type column. // The type column.
model->setData(index, QString(exp + '=' + value), RequestAssignTypeRole); model->setData(index, QString(exp + '=' + value), RequestAssignTypeRole);
} else if (index.column() == 0) { } else if (index.column() == 0) {