forked from qt-creator/qt-creator
Debugger: Rework display type selection
The previous index based way was getting too brittle, use enums instead. Also add a switch between exponential and flat display for floating point types. Task-number: QTCREATORBUG-12050 Change-Id: I86addbac5a80e8b79b176c6107b251b466503fe7 Reviewed-by: David Schulz <david.schulz@digia.com> Reviewed-by: Christian Stenger <christian.stenger@digia.com>
This commit is contained in:
@@ -42,6 +42,19 @@ else:
|
|||||||
verbosity = 0
|
verbosity = 0
|
||||||
verbosity = 1
|
verbosity = 1
|
||||||
|
|
||||||
|
# Known special formats. Keep in sync with DisplayFormat in watchhandler.h
|
||||||
|
KnownDumperFormatBase, \
|
||||||
|
Latin1StringFormat, \
|
||||||
|
Utf8StringFormat, \
|
||||||
|
Local8BitStringFormat, \
|
||||||
|
Utf16StringFormat, \
|
||||||
|
Ucs4StringFormat, \
|
||||||
|
Array10Format, \
|
||||||
|
Array100Format, \
|
||||||
|
Array1000Format, \
|
||||||
|
Array10000Format \
|
||||||
|
= range(100, 110)
|
||||||
|
|
||||||
def hasPlot():
|
def hasPlot():
|
||||||
fileName = "/usr/bin/gnuplot"
|
fileName = "/usr/bin/gnuplot"
|
||||||
return os.path.isfile(fileName) and os.access(fileName, os.X_OK)
|
return os.path.isfile(fileName) and os.access(fileName, os.X_OK)
|
||||||
@@ -805,44 +818,45 @@ class DumperBase:
|
|||||||
self.putItem(value.dereference())
|
self.putItem(value.dereference())
|
||||||
return
|
return
|
||||||
|
|
||||||
if format == 1:
|
if format == Latin1StringFormat:
|
||||||
# Explicitly requested Latin1 formatting.
|
# Explicitly requested Latin1 formatting.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1)
|
self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1)
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
if format == 2:
|
if format == Utf8StringFormat:
|
||||||
# Explicitly requested UTF-8 formatting.
|
# Explicitly requested UTF-8 formatting.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue(self.encodeCharArray(value), Hex2EncodedUtf8)
|
self.putValue(self.encodeCharArray(value), Hex2EncodedUtf8)
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
if format == 3:
|
if format == Local8BitStringFormat:
|
||||||
# Explicitly requested local 8 bit formatting.
|
# Explicitly requested local 8 bit formatting.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue(self.encodeCharArray(value), Hex2EncodedLocal8Bit)
|
self.putValue(self.encodeCharArray(value), Hex2EncodedLocal8Bit)
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
if format == 4:
|
if format == Utf16StringFormat:
|
||||||
# Explicitly requested UTF-16 formatting.
|
# Explicitly requested UTF-16 formatting.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue(self.encodeChar2Array(value), Hex4EncodedLittleEndian)
|
self.putValue(self.encodeChar2Array(value), Hex4EncodedLittleEndian)
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
if format == 5:
|
if format == Ucs4StringFormat:
|
||||||
# Explicitly requested UCS-4 formatting.
|
# Explicitly requested UCS-4 formatting.
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putValue(self.encodeChar4Array(value), Hex8EncodedLittleEndian)
|
self.putValue(self.encodeChar4Array(value), Hex8EncodedLittleEndian)
|
||||||
self.putNumChild(0)
|
self.putNumChild(0)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not format is None and format >= 6 and format <= 9:
|
if not format is None \
|
||||||
|
and format >= Array10Format and format <= Array1000Format:
|
||||||
# Explicitly requested formatting as array of n items.
|
# Explicitly requested formatting as array of n items.
|
||||||
n = (10, 100, 1000, 10000)[format - 6]
|
n = (10, 100, 1000, 10000)[format - Array10Format]
|
||||||
self.putType(typeName)
|
self.putType(typeName)
|
||||||
self.putItemCount(n)
|
self.putItemCount(n)
|
||||||
self.putNumChild(n)
|
self.putNumChild(n)
|
||||||
|
|||||||
@@ -352,13 +352,15 @@ int DumpParameters::format(const std::string &type, const std::string &iname) co
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PointerFormats // Watch data pointer format requests
|
// Watch data pointer format requests. This should match the values
|
||||||
|
// in DisplayFormat in watchhandler.h.
|
||||||
|
enum PointerFormats
|
||||||
{
|
{
|
||||||
FormatAuto = 0,
|
FormatAuto = 0,
|
||||||
FormatLatin1String = 1,
|
FormatLatin1String = 101,
|
||||||
FormatUtf8String = 2,
|
FormatUtf8String = 102,
|
||||||
FormatUtf16String = 3,
|
FormatUtf16String = 104,
|
||||||
FormatUcs4String = 4
|
FormatUcs4String = 105
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DumpEncoding // WatchData encoding of GDBMI values
|
enum DumpEncoding // WatchData encoding of GDBMI values
|
||||||
|
|||||||
@@ -889,9 +889,9 @@ void TypeFormatsDialog::addTypeFormats(const QString &type0,
|
|||||||
m_ui->pages[pos]->addTypeFormats(type, typeFormats, current);
|
m_ui->pages[pos]->addTypeFormats(type, typeFormats, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeFormats TypeFormatsDialog::typeFormats() const
|
DumperTypeFormats TypeFormatsDialog::typeFormats() const
|
||||||
{
|
{
|
||||||
return TypeFormats();
|
return DumperTypeFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ private:
|
|||||||
QDialogButtonBox *m_box;
|
QDialogButtonBox *m_box;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<QString, QStringList> TypeFormats;
|
typedef QHash<QString, QStringList> DumperTypeFormats;
|
||||||
|
|
||||||
class StartRemoteEngineDialog : public QDialog
|
class StartRemoteEngineDialog : public QDialog
|
||||||
{
|
{
|
||||||
@@ -190,7 +190,7 @@ public:
|
|||||||
|
|
||||||
void addTypeFormats(const QString &type, const QStringList &formats,
|
void addTypeFormats(const QString &type, const QStringList &formats,
|
||||||
int currentFormat);
|
int currentFormat);
|
||||||
TypeFormats typeFormats() const;
|
DumperTypeFormats typeFormats() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeFormatsDialogUi *m_ui;
|
TypeFormatsDialogUi *m_ui;
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ static QHash<QByteArray, int> theTypeFormats;
|
|||||||
static QHash<QByteArray, int> theIndividualFormats;
|
static QHash<QByteArray, int> theIndividualFormats;
|
||||||
static int theUnprintableBase = -1;
|
static int theUnprintableBase = -1;
|
||||||
|
|
||||||
|
|
||||||
static QByteArray stripForFormat(const QByteArray &ba)
|
static QByteArray stripForFormat(const QByteArray &ba)
|
||||||
{
|
{
|
||||||
QByteArray res;
|
QByteArray res;
|
||||||
@@ -175,6 +174,9 @@ public:
|
|||||||
int rowCount(const QModelIndex &idx = QModelIndex()) const;
|
int rowCount(const QModelIndex &idx = QModelIndex()) const;
|
||||||
int columnCount(const QModelIndex &idx) const;
|
int columnCount(const QModelIndex &idx) const;
|
||||||
|
|
||||||
|
static QString nameForFormat(int format);
|
||||||
|
TypeFormatList typeFormatList(const WatchData &value) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentIndexRequested(const QModelIndex &idx);
|
void currentIndexRequested(const QModelIndex &idx);
|
||||||
void itemIsExpanded(const QModelIndex &idx);
|
void itemIsExpanded(const QModelIndex &idx);
|
||||||
@@ -247,8 +249,9 @@ private:
|
|||||||
QSet<QByteArray> m_expandedINames;
|
QSet<QByteArray> m_expandedINames;
|
||||||
QSet<QByteArray> m_fetchTriggered;
|
QSet<QByteArray> m_fetchTriggered;
|
||||||
|
|
||||||
QStringList typeFormatList(const WatchData &data) const;
|
TypeFormatList builtinTypeFormatList(const WatchData &data) const;
|
||||||
TypeFormats m_reportedTypeFormats;
|
QStringList dumperTypeFormatList(const WatchData &data) const;
|
||||||
|
DumperTypeFormats m_reportedTypeFormats;
|
||||||
|
|
||||||
// QWidgets and QProcesses taking care of special displays.
|
// QWidgets and QProcesses taking care of special displays.
|
||||||
typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
|
typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
|
||||||
@@ -498,43 +501,24 @@ QString WatchModel::removeNamespaces(QString str) const
|
|||||||
static int formatToIntegerBase(int format)
|
static int formatToIntegerBase(int format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case HexadecimalFormat:
|
case HexadecimalIntegerFormat:
|
||||||
return 16;
|
return 16;
|
||||||
case BinaryFormat:
|
case BinaryIntegerFormat:
|
||||||
return 2;
|
return 2;
|
||||||
case OctalFormat:
|
case OctalIntegerFormat:
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isIntegralValue(const QString &value)
|
|
||||||
{
|
|
||||||
if (value.startsWith(QLatin1Char('-')))
|
|
||||||
return isIntegralValue(value.mid(1));
|
|
||||||
|
|
||||||
bool ok;
|
|
||||||
value.toULongLong(&ok, 10);
|
|
||||||
if (ok)
|
|
||||||
return true;
|
|
||||||
value.toULongLong(&ok, 16);
|
|
||||||
if (ok)
|
|
||||||
return true;
|
|
||||||
value.toULongLong(&ok, 8);
|
|
||||||
if (ok)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class IntType> QString reformatInteger(IntType value, int format)
|
template <class IntType> QString reformatInteger(IntType value, int format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case HexadecimalFormat:
|
case HexadecimalIntegerFormat:
|
||||||
return QLatin1String("(hex) ") + QString::number(value, 16);
|
return QLatin1String("(hex) ") + QString::number(value, 16);
|
||||||
case BinaryFormat:
|
case BinaryIntegerFormat:
|
||||||
return QLatin1String("(bin) ") + QString::number(value, 2);
|
return QLatin1String("(bin) ") + QString::number(value, 2);
|
||||||
case OctalFormat:
|
case OctalIntegerFormat:
|
||||||
return QLatin1String("(oct) ") + QString::number(value, 8);
|
return QLatin1String("(oct) ") + QString::number(value, 8);
|
||||||
}
|
}
|
||||||
return QString::number(value, 10); // not reached
|
return QString::number(value, 10); // not reached
|
||||||
@@ -543,7 +527,7 @@ template <class IntType> QString reformatInteger(IntType value, int format)
|
|||||||
static QString reformatInteger(quint64 value, int format, int size, bool isSigned)
|
static QString reformatInteger(quint64 value, int format, int size, bool isSigned)
|
||||||
{
|
{
|
||||||
// Follow convention and don't show negative non-decimal numbers.
|
// Follow convention and don't show negative non-decimal numbers.
|
||||||
if (format != DecimalFormat)
|
if (format != AutomaticFormat)
|
||||||
isSigned = false;
|
isSigned = false;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@@ -671,23 +655,34 @@ QString WatchModel::formattedValue(const WatchData &data) const
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIntegralValue(value)) {
|
|
||||||
// Append quoted, printable character also for decimal.
|
|
||||||
const int format = itemFormat(data);
|
const int format = itemFormat(data);
|
||||||
|
|
||||||
|
// Append quoted, printable character also for decimal.
|
||||||
if (data.type.endsWith("char") || data.type.endsWith("QChar")) {
|
if (data.type.endsWith("char") || data.type.endsWith("QChar")) {
|
||||||
bool ok;
|
bool ok;
|
||||||
const int code = value.toInt(&ok);
|
const int code = value.toInt(&ok);
|
||||||
return ok ? reformatCharacter(code, format) : value;
|
return ok ? reformatCharacter(code, format) : value;
|
||||||
}
|
}
|
||||||
// Rest: Leave decimal as is
|
|
||||||
if (format <= 0)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
|
if (format == HexadecimalIntegerFormat
|
||||||
|
|| format == DecimalIntegerFormat
|
||||||
|
|| format == OctalIntegerFormat
|
||||||
|
|| format == BinaryIntegerFormat) {
|
||||||
bool isSigned = value.startsWith(QLatin1Char('-'));
|
bool isSigned = value.startsWith(QLatin1Char('-'));
|
||||||
quint64 raw = isSigned ? quint64(value.toLongLong()): value.toULongLong();
|
quint64 raw = isSigned ? quint64(value.toLongLong()): value.toULongLong();
|
||||||
return reformatInteger(raw, format, data.size, isSigned);
|
return reformatInteger(raw, format, data.size, isSigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (format == ScientificFloatFormat) {
|
||||||
|
double d = value.toDouble();
|
||||||
|
return QString::number(d, 'e');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format == CompactFloatFormat) {
|
||||||
|
double d = value.toDouble();
|
||||||
|
return QString::number(d, 'g');
|
||||||
|
}
|
||||||
|
|
||||||
if (data.type == "va_list")
|
if (data.type == "va_list")
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
@@ -918,10 +913,10 @@ static QString truncateValue(QString v)
|
|||||||
|
|
||||||
int WatchModel::itemFormat(const WatchData &data) const
|
int WatchModel::itemFormat(const WatchData &data) const
|
||||||
{
|
{
|
||||||
const int individualFormat = theIndividualFormats.value(data.iname, -1);
|
const int individualFormat = theIndividualFormats.value(data.iname, AutomaticFormat);
|
||||||
if (individualFormat != -1)
|
if (individualFormat != AutomaticFormat)
|
||||||
return individualFormat;
|
return individualFormat;
|
||||||
return theTypeFormats.value(stripForFormat(data.type), -1);
|
return theTypeFormats.value(stripForFormat(data.type), AutomaticFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WatchModel::contentIsValid() const
|
bool WatchModel::contentIsValid() const
|
||||||
@@ -1089,7 +1084,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|||||||
return m_expandedINames.contains(data.iname);
|
return m_expandedINames.contains(data.iname);
|
||||||
|
|
||||||
case LocalsTypeFormatListRole:
|
case LocalsTypeFormatListRole:
|
||||||
return typeFormatList(data);
|
return QVariant::fromValue(typeFormatList(data));
|
||||||
|
|
||||||
case LocalsTypeRole:
|
case LocalsTypeRole:
|
||||||
return removeNamespaces(displayType(data));
|
return removeNamespaces(displayType(data));
|
||||||
@@ -1098,10 +1093,10 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
|||||||
return QString::fromLatin1(data.type);
|
return QString::fromLatin1(data.type);
|
||||||
|
|
||||||
case LocalsTypeFormatRole:
|
case LocalsTypeFormatRole:
|
||||||
return theTypeFormats.value(stripForFormat(data.type), -1);
|
return theTypeFormats.value(stripForFormat(data.type), AutomaticFormat);
|
||||||
|
|
||||||
case LocalsIndividualFormatRole:
|
case LocalsIndividualFormatRole:
|
||||||
return theIndividualFormats.value(data.iname, -1);
|
return theIndividualFormats.value(data.iname, AutomaticFormat);
|
||||||
|
|
||||||
case LocalsRawValueRole:
|
case LocalsRawValueRole:
|
||||||
return data.value;
|
return data.value;
|
||||||
@@ -1171,7 +1166,7 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role
|
|||||||
|
|
||||||
case LocalsIndividualFormatRole: {
|
case LocalsIndividualFormatRole: {
|
||||||
const int format = value.toInt();
|
const int format = value.toInt();
|
||||||
if (format == -1)
|
if (format == AutomaticFormat)
|
||||||
theIndividualFormats.remove(data.iname);
|
theIndividualFormats.remove(data.iname);
|
||||||
else
|
else
|
||||||
theIndividualFormats[data.iname] = format;
|
theIndividualFormats[data.iname] = format;
|
||||||
@@ -1246,31 +1241,36 @@ static inline QString msgArrayFormat(int n)
|
|||||||
return WatchModel::tr("Array of %n items", 0, n);
|
return WatchModel::tr("Array of %n items", 0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList WatchModel::typeFormatList(const WatchData &data) const
|
QString WatchModel::nameForFormat(int format)
|
||||||
{
|
{
|
||||||
if (data.origaddr || isPointerType(data.type))
|
switch (format) {
|
||||||
return QStringList()
|
case RawFormat: return tr("Raw Data");
|
||||||
<< tr("Raw pointer")
|
case Latin1StringFormat: return tr("Latin1 String");
|
||||||
<< tr("Latin1 string")
|
case Utf8StringFormat: return tr("UTF-8 String");
|
||||||
<< tr("UTF8 string")
|
case Local8BitStringFormat: return tr("Local 8-Bit String");
|
||||||
<< tr("Local 8bit string")
|
case Utf16StringFormat: return tr("UTF-16 String");
|
||||||
<< tr("UTF16 string")
|
case Ucs4StringFormat: return tr("UCS-4 String");
|
||||||
<< tr("UCS4 string")
|
case Array10Format: return msgArrayFormat(10);
|
||||||
<< msgArrayFormat(10)
|
case Array100Format: return msgArrayFormat(100);
|
||||||
<< msgArrayFormat(100)
|
case Array1000Format: return msgArrayFormat(1000);
|
||||||
<< msgArrayFormat(1000)
|
case Array10000Format: return msgArrayFormat(10000);
|
||||||
<< msgArrayFormat(10000);
|
case DecimalIntegerFormat: return tr("Decimal Integer");
|
||||||
if (data.type.contains("char[") || data.type.contains("char ["))
|
case HexadecimalIntegerFormat: return tr("Hexadecimal Integer");
|
||||||
return QStringList()
|
case BinaryIntegerFormat: return tr("Binary Integer");
|
||||||
<< tr("Latin1 string")
|
case OctalIntegerFormat: return tr("Octal Integer");
|
||||||
<< tr("UTF8 string")
|
case CompactFloatFormat: return tr("Compact Float");
|
||||||
<< tr("Local 8bit string");
|
case ScientificFloatFormat: return tr("Scientific Float");
|
||||||
if (isIntegralValue(data.value))
|
}
|
||||||
return QStringList()
|
|
||||||
<< tr("Decimal")
|
QTC_CHECK(false);
|
||||||
<< tr("Hexadecimal")
|
return QString();
|
||||||
<< tr("Binary")
|
}
|
||||||
<< tr("Octal");
|
|
||||||
|
TypeFormatList WatchModel::typeFormatList(const WatchData &data) const
|
||||||
|
{
|
||||||
|
TypeFormatList formats;
|
||||||
|
|
||||||
|
// Types supported by dumpers:
|
||||||
// Hack: Compensate for namespaces.
|
// Hack: Compensate for namespaces.
|
||||||
QString type = QLatin1String(stripForFormat(data.type));
|
QString type = QLatin1String(stripForFormat(data.type));
|
||||||
int pos = type.indexOf(QLatin1String("::Q"));
|
int pos = type.indexOf(QLatin1String("::Q"));
|
||||||
@@ -1280,7 +1280,50 @@ QStringList WatchModel::typeFormatList(const WatchData &data) const
|
|||||||
if (pos >= 0)
|
if (pos >= 0)
|
||||||
type.truncate(pos);
|
type.truncate(pos);
|
||||||
type.replace(QLatin1Char(':'), QLatin1Char('_'));
|
type.replace(QLatin1Char(':'), QLatin1Char('_'));
|
||||||
return m_reportedTypeFormats.value(type);
|
QStringList reported = m_reportedTypeFormats.value(type);
|
||||||
|
for (int i = 0, n = reported.size(); i != n; ++i)
|
||||||
|
formats.append(TypeFormatItem(reported.at(i), i));
|
||||||
|
|
||||||
|
// Fixed artificial string and pointer types.
|
||||||
|
if (data.origaddr || isPointerType(data.type)) {
|
||||||
|
formats.append(RawFormat);
|
||||||
|
formats.append(Latin1StringFormat);
|
||||||
|
formats.append(Utf8StringFormat);
|
||||||
|
formats.append(Local8BitStringFormat);
|
||||||
|
formats.append(Utf16StringFormat);
|
||||||
|
formats.append(Ucs4StringFormat);
|
||||||
|
formats.append(Array10Format);
|
||||||
|
formats.append(Array100Format);
|
||||||
|
formats.append(Array1000Format);
|
||||||
|
formats.append(Array10000Format);
|
||||||
|
} else if (data.type.contains("char[") || data.type.contains("char [")) {
|
||||||
|
formats.append(Latin1StringFormat);
|
||||||
|
formats.append(Utf8StringFormat);
|
||||||
|
formats.append(Ucs4StringFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed artificial floating point types.
|
||||||
|
bool ok = false;
|
||||||
|
data.value.toDouble(&ok);
|
||||||
|
if (ok) {
|
||||||
|
formats.append(CompactFloatFormat);
|
||||||
|
formats.append(ScientificFloatFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed artificial integral types.
|
||||||
|
data.value.toULongLong(&ok, 10);
|
||||||
|
if (!ok)
|
||||||
|
data.value.toULongLong(&ok, 16);
|
||||||
|
if (!ok)
|
||||||
|
data.value.toULongLong(&ok, 8);
|
||||||
|
if (ok) {
|
||||||
|
formats.append(DecimalIntegerFormat);
|
||||||
|
formats.append(HexadecimalIntegerFormat);
|
||||||
|
formats.append(BinaryIntegerFormat);
|
||||||
|
formats.append(OctalIntegerFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine sort order of watch items by sort order or alphabetical inames
|
// Determine sort order of watch items by sort order or alphabetical inames
|
||||||
@@ -1439,10 +1482,10 @@ QDebug operator<<(QDebug d, const WatchModel &m)
|
|||||||
|
|
||||||
void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
|
void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const
|
||||||
{
|
{
|
||||||
int format = theIndividualFormats.value(item->iname, -1);
|
int format = theIndividualFormats.value(item->iname, AutomaticFormat);
|
||||||
if (format == -1)
|
if (format == AutomaticFormat)
|
||||||
format = theTypeFormats.value(stripForFormat(item->type), -1);
|
format = theTypeFormats.value(stripForFormat(item->type), AutomaticFormat);
|
||||||
if (format != -1)
|
if (format != AutomaticFormat)
|
||||||
*out += item->iname + ":format=" + QByteArray::number(format) + ',';
|
*out += item->iname + ":format=" + QByteArray::number(format) + ',';
|
||||||
foreach (const WatchItem *child, item->children)
|
foreach (const WatchItem *child, item->children)
|
||||||
formatRequests(out, child);
|
formatRequests(out, child);
|
||||||
@@ -1869,7 +1912,7 @@ void WatchHandler::saveFormats()
|
|||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
const int format = it.value();
|
const int format = it.value();
|
||||||
if (format != DecimalFormat) {
|
if (format != AutomaticFormat) {
|
||||||
const QByteArray key = it.key().trimmed();
|
const QByteArray key = it.key().trimmed();
|
||||||
if (!key.isEmpty())
|
if (!key.isEmpty())
|
||||||
formats.insert(QString::fromLatin1(key), format);
|
formats.insert(QString::fromLatin1(key), format);
|
||||||
@@ -1948,7 +1991,7 @@ bool WatchHandler::hasItem(const QByteArray &iname) const
|
|||||||
void WatchHandler::setFormat(const QByteArray &type0, int format)
|
void WatchHandler::setFormat(const QByteArray &type0, int format)
|
||||||
{
|
{
|
||||||
const QByteArray type = stripForFormat(type0);
|
const QByteArray type = stripForFormat(type0);
|
||||||
if (format == -1)
|
if (format == AutomaticFormat)
|
||||||
theTypeFormats.remove(type);
|
theTypeFormats.remove(type);
|
||||||
else
|
else
|
||||||
theTypeFormats[type] = format;
|
theTypeFormats[type] = format;
|
||||||
@@ -1958,11 +2001,11 @@ void WatchHandler::setFormat(const QByteArray &type0, int format)
|
|||||||
|
|
||||||
int WatchHandler::format(const QByteArray &iname) const
|
int WatchHandler::format(const QByteArray &iname) const
|
||||||
{
|
{
|
||||||
int result = -1;
|
int result = AutomaticFormat;
|
||||||
if (const WatchData *item = m_model->findItem(iname)) {
|
if (const WatchData *item = m_model->findItem(iname)) {
|
||||||
int result = theIndividualFormats.value(item->iname, -1);
|
int result = theIndividualFormats.value(item->iname, AutomaticFormat);
|
||||||
if (result == -1)
|
if (result == AutomaticFormat)
|
||||||
result = theTypeFormats.value(stripForFormat(item->type), -1);
|
result = theTypeFormats.value(stripForFormat(item->type), AutomaticFormat);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1990,11 +2033,14 @@ QByteArray WatchHandler::typeFormatRequests() const
|
|||||||
QHashIterator<QByteArray, int> it(theTypeFormats);
|
QHashIterator<QByteArray, int> it(theTypeFormats);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
|
const int format = it.value();
|
||||||
|
if (format >= RawFormat && format < ArtificialFormatBase) {
|
||||||
ba.append(it.key().toHex());
|
ba.append(it.key().toHex());
|
||||||
ba.append('=');
|
ba.append('=');
|
||||||
ba.append(QByteArray::number(it.value()));
|
ba.append(QByteArray::number(format));
|
||||||
ba.append(',');
|
ba.append(',');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ba.chop(1);
|
ba.chop(1);
|
||||||
}
|
}
|
||||||
return ba;
|
return ba;
|
||||||
@@ -2007,11 +2053,14 @@ QByteArray WatchHandler::individualFormatRequests() const
|
|||||||
QHashIterator<QByteArray, int> it(theIndividualFormats);
|
QHashIterator<QByteArray, int> it(theIndividualFormats);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
|
const int format = it.value();
|
||||||
|
if (format >= RawFormat && format < ArtificialFormatBase) {
|
||||||
ba.append(it.key());
|
ba.append(it.key());
|
||||||
ba.append('=');
|
ba.append('=');
|
||||||
ba.append(QByteArray::number(it.value()));
|
ba.append(QByteArray::number(it.value()));
|
||||||
ba.append(',');
|
ba.append(',');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ba.chop(1);
|
ba.chop(1);
|
||||||
}
|
}
|
||||||
return ba;
|
return ba;
|
||||||
@@ -2029,12 +2078,12 @@ QString WatchHandler::editorContents()
|
|||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchHandler::setTypeFormats(const TypeFormats &typeFormats)
|
void WatchHandler::setTypeFormats(const DumperTypeFormats &typeFormats)
|
||||||
{
|
{
|
||||||
m_model->m_reportedTypeFormats = typeFormats;
|
m_model->m_reportedTypeFormats = typeFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeFormats WatchHandler::typeFormats() const
|
DumperTypeFormats WatchHandler::typeFormats() const
|
||||||
{
|
{
|
||||||
return m_model->m_reportedTypeFormats;
|
return m_model->m_reportedTypeFormats;
|
||||||
}
|
}
|
||||||
@@ -2048,7 +2097,7 @@ void WatchHandler::editTypeFormats(bool includeLocals, const QByteArray &iname)
|
|||||||
QList<QString> l = m_model->m_reportedTypeFormats.keys();
|
QList<QString> l = m_model->m_reportedTypeFormats.keys();
|
||||||
qSort(l.begin(), l.end());
|
qSort(l.begin(), l.end());
|
||||||
foreach (const QString &ba, l) {
|
foreach (const QString &ba, l) {
|
||||||
int f = iname.isEmpty() ? -1 : format(iname);
|
int f = iname.isEmpty() ? AutomaticFormat : format(iname);
|
||||||
dlg.addTypeFormats(ba, m_model->m_reportedTypeFormats.value(ba), f);
|
dlg.addTypeFormats(ba, m_model->m_reportedTypeFormats.value(ba), f);
|
||||||
}
|
}
|
||||||
if (dlg.exec())
|
if (dlg.exec())
|
||||||
@@ -2107,6 +2156,30 @@ QSet<QByteArray> WatchHandler::expandedINames() const
|
|||||||
return m_model->m_expandedINames;
|
return m_model->m_expandedINames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// TypeFormatItem/List
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
TypeFormatItem::TypeFormatItem(const QString &display, int format)
|
||||||
|
: display(display), format(format)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void TypeFormatList::append(int format)
|
||||||
|
{
|
||||||
|
append(TypeFormatItem(WatchModel::nameForFormat(format), format));
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeFormatItem TypeFormatList::find(int format) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i != size(); ++i)
|
||||||
|
if (at(i).format == format)
|
||||||
|
return at(i);
|
||||||
|
return TypeFormatItem();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,76 @@
|
|||||||
|
|
||||||
#include "watchdata.h"
|
#include "watchdata.h"
|
||||||
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QTabWidget)
|
QT_FORWARD_DECLARE_CLASS(QTabWidget)
|
||||||
|
|
||||||
|
namespace Debugger {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
// Special formats. Keep in sync with dumper.py.
|
||||||
|
enum DisplayFormat
|
||||||
|
{
|
||||||
|
AutomaticFormat = -1, // Based on type for individuals, dumper default for types.
|
||||||
|
RawFormat = 0,
|
||||||
|
|
||||||
|
// Values between 1 and 99 refer to dumper provided custom formats.
|
||||||
|
|
||||||
|
// Values between 100 and 199 refer to well-known formats handled in dumpers.
|
||||||
|
KnownDumperFormatBase = 100,
|
||||||
|
Latin1StringFormat,
|
||||||
|
Utf8StringFormat,
|
||||||
|
Local8BitStringFormat,
|
||||||
|
Utf16StringFormat,
|
||||||
|
Ucs4StringFormat,
|
||||||
|
|
||||||
|
Array10Format,
|
||||||
|
Array100Format,
|
||||||
|
Array1000Format,
|
||||||
|
Array10000Format,
|
||||||
|
|
||||||
|
|
||||||
|
// Values above 200 refer to format solely handled in the WatchHandler code
|
||||||
|
ArtificialFormatBase = 200,
|
||||||
|
|
||||||
|
BoolTextFormat,
|
||||||
|
BoolIntegerFormat,
|
||||||
|
|
||||||
|
DecimalIntegerFormat,
|
||||||
|
HexadecimalIntegerFormat,
|
||||||
|
BinaryIntegerFormat,
|
||||||
|
OctalIntegerFormat,
|
||||||
|
|
||||||
|
CompactFloatFormat,
|
||||||
|
ScientificFloatFormat,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TypeFormatItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TypeFormatItem() : format(-1) {}
|
||||||
|
TypeFormatItem(const QString &display, int format);
|
||||||
|
|
||||||
|
QString display;
|
||||||
|
int format;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TypeFormatList : public QVector<TypeFormatItem>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QVector::append;
|
||||||
|
void append(int format);
|
||||||
|
TypeFormatItem find(int format) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace Debugger
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Debugger::Internal::TypeFormatList)
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
|
|
||||||
class DebuggerEngine;
|
class DebuggerEngine;
|
||||||
@@ -55,15 +120,7 @@ public:
|
|||||||
QByteArray varList;
|
QByteArray varList;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<QString, QStringList> TypeFormats;
|
typedef QHash<QString, QStringList> DumperTypeFormats; // Type name -> Dumper Formats
|
||||||
|
|
||||||
enum IntegerFormat
|
|
||||||
{
|
|
||||||
DecimalFormat = 0, // Keep that at 0 as default.
|
|
||||||
HexadecimalFormat,
|
|
||||||
BinaryFormat,
|
|
||||||
OctalFormat
|
|
||||||
};
|
|
||||||
|
|
||||||
class WatchHandler : public QObject
|
class WatchHandler : public QObject
|
||||||
{
|
{
|
||||||
@@ -104,8 +161,8 @@ public:
|
|||||||
int format(const QByteArray &iname) const;
|
int format(const QByteArray &iname) const;
|
||||||
|
|
||||||
void addTypeFormats(const QByteArray &type, const QStringList &formats);
|
void addTypeFormats(const QByteArray &type, const QStringList &formats);
|
||||||
void setTypeFormats(const TypeFormats &typeFormats);
|
void setTypeFormats(const DumperTypeFormats &typeFormats);
|
||||||
TypeFormats typeFormats() const;
|
DumperTypeFormats typeFormats() const;
|
||||||
|
|
||||||
void setUnprintableBase(int base);
|
void setUnprintableBase(int base);
|
||||||
static int unprintableBase();
|
static int unprintableBase();
|
||||||
|
|||||||
@@ -59,6 +59,8 @@
|
|||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QModelIndex)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// WatchDelegate
|
// WatchDelegate
|
||||||
@@ -68,6 +70,8 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
const char CurrentIndex[] = "CurrentIndex";
|
||||||
|
|
||||||
static DebuggerEngine *currentEngine()
|
static DebuggerEngine *currentEngine()
|
||||||
{
|
{
|
||||||
return debuggerCore()->currentEngine();
|
return debuggerCore()->currentEngine();
|
||||||
@@ -584,12 +588,150 @@ static void copyToClipboard(const QString &clipboardText)
|
|||||||
clipboard->setText(clipboardText, QClipboard::Clipboard);
|
clipboard->setText(clipboardText, QClipboard::Clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::fillFormatMenu(QMenu *formatMenu, const QModelIndex &mi)
|
||||||
|
{
|
||||||
|
QTC_CHECK(mi.isValid());
|
||||||
|
|
||||||
|
DebuggerEngine *engine = currentEngine();
|
||||||
|
WatchHandler *handler = engine->watchHandler();
|
||||||
|
|
||||||
|
const QModelIndex mi2 = mi.sibling(mi.row(), 2);
|
||||||
|
const QString type = mi2.data().toString();
|
||||||
|
|
||||||
|
const TypeFormatList alternativeFormats =
|
||||||
|
mi.data(LocalsTypeFormatListRole).value<TypeFormatList>();
|
||||||
|
int typeFormat =
|
||||||
|
mi.data(LocalsTypeFormatRole).toInt();
|
||||||
|
const int individualFormat =
|
||||||
|
mi.data(LocalsIndividualFormatRole).toInt();
|
||||||
|
const int unprintableBase = handler->unprintableBase();
|
||||||
|
|
||||||
|
QAction *showUnprintableUnicode = 0;
|
||||||
|
QAction *showUnprintableEscape = 0;
|
||||||
|
QAction *showUnprintableOctal = 0;
|
||||||
|
QAction *showUnprintableHexadecimal = 0;
|
||||||
|
formatMenu->setTitle(tr("Change Local Display Format..."));
|
||||||
|
showUnprintableUnicode =
|
||||||
|
formatMenu->addAction(tr("Treat All Characters as Printable"));
|
||||||
|
showUnprintableUnicode->setCheckable(true);
|
||||||
|
showUnprintableUnicode->setChecked(unprintableBase == 0);
|
||||||
|
showUnprintableUnicode->setData(0);
|
||||||
|
showUnprintableEscape =
|
||||||
|
formatMenu->addAction(tr("Show Unprintable Characters as Escape Sequences"));
|
||||||
|
showUnprintableEscape->setCheckable(true);
|
||||||
|
showUnprintableEscape->setChecked(unprintableBase == -1);
|
||||||
|
showUnprintableEscape->setData(-1);
|
||||||
|
showUnprintableOctal =
|
||||||
|
formatMenu->addAction(tr("Show Unprintable Characters as Octal"));
|
||||||
|
showUnprintableOctal->setCheckable(true);
|
||||||
|
showUnprintableOctal->setChecked(unprintableBase == 8);
|
||||||
|
showUnprintableOctal->setData(8);
|
||||||
|
showUnprintableHexadecimal =
|
||||||
|
formatMenu->addAction(tr("Show Unprintable Characters as Hexadecimal"));
|
||||||
|
showUnprintableHexadecimal->setCheckable(true);
|
||||||
|
showUnprintableHexadecimal->setChecked(unprintableBase == 16);
|
||||||
|
showUnprintableHexadecimal->setData(16);
|
||||||
|
|
||||||
|
connect(showUnprintableUnicode, SIGNAL(triggered()), SLOT(onShowUnprintable()));
|
||||||
|
connect(showUnprintableEscape, SIGNAL(triggered()), SLOT(onShowUnprintable()));
|
||||||
|
connect(showUnprintableOctal, SIGNAL(triggered()), SLOT(onShowUnprintable()));
|
||||||
|
connect(showUnprintableHexadecimal, SIGNAL(triggered()), SLOT(onShowUnprintable()));
|
||||||
|
|
||||||
|
|
||||||
|
const QString spacer = QLatin1String(" ");
|
||||||
|
formatMenu->addSeparator();
|
||||||
|
QAction *dummy = formatMenu->addAction(
|
||||||
|
tr("Change Display for Object Named \"%1\":").arg(mi.data().toString()));
|
||||||
|
dummy->setEnabled(false);
|
||||||
|
QString msg = (individualFormat == AutomaticFormat && typeFormat != AutomaticFormat)
|
||||||
|
? tr("Use Format for Type (Currently %1)")
|
||||||
|
.arg(alternativeFormats.find(typeFormat).display)
|
||||||
|
: tr("Use Display Format Based on Type") + QLatin1Char(' ');
|
||||||
|
|
||||||
|
QAction *clearIndividualFormatAction = formatMenu->addAction(spacer + msg);
|
||||||
|
clearIndividualFormatAction->setCheckable(true);
|
||||||
|
clearIndividualFormatAction->setChecked(individualFormat == AutomaticFormat);
|
||||||
|
connect(clearIndividualFormatAction, SIGNAL(triggered()),
|
||||||
|
SLOT(onClearIndividualFormat()));
|
||||||
|
|
||||||
|
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
||||||
|
const QString display = spacer + alternativeFormats.at(i).display;
|
||||||
|
const int format = alternativeFormats.at(i).format;
|
||||||
|
QAction *act = new QAction(display, formatMenu);
|
||||||
|
act->setData(format);
|
||||||
|
act->setCheckable(true);
|
||||||
|
act->setChecked(format == individualFormat);
|
||||||
|
act->setProperty(CurrentIndex, QVariant::fromValue(mi));
|
||||||
|
formatMenu->addAction(act);
|
||||||
|
connect(act, SIGNAL(triggered()), SLOT(onIndividualFormatChange()));
|
||||||
|
}
|
||||||
|
|
||||||
|
formatMenu->addSeparator();
|
||||||
|
dummy = formatMenu->addAction(tr("Change Display for Type \"%1\":").arg(type));
|
||||||
|
dummy->setEnabled(false);
|
||||||
|
|
||||||
|
QAction *clearTypeFormatAction = formatMenu->addAction(spacer + tr("Automatic"));
|
||||||
|
clearTypeFormatAction->setCheckable(true);
|
||||||
|
clearTypeFormatAction->setChecked(typeFormat == AutomaticFormat);
|
||||||
|
connect(clearTypeFormatAction, SIGNAL(triggered()), SLOT(onClearTypeFormat()));
|
||||||
|
|
||||||
|
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
||||||
|
const QString display = spacer + alternativeFormats.at(i).display;
|
||||||
|
QAction *act = new QAction(display, formatMenu);
|
||||||
|
const int format = alternativeFormats.at(i).format;
|
||||||
|
act->setData(format);
|
||||||
|
act->setCheckable(true);
|
||||||
|
act->setChecked(format == typeFormat);
|
||||||
|
act->setProperty(CurrentIndex, QVariant::fromValue(mi));
|
||||||
|
formatMenu->addAction(act);
|
||||||
|
connect(act, SIGNAL(triggered()), SLOT(onTypeFormatChange()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::onClearTypeFormat()
|
||||||
|
{
|
||||||
|
const QModelIndexList active = activeRows();
|
||||||
|
foreach (const QModelIndex &idx, active)
|
||||||
|
setModelData(LocalsTypeFormatRole, AutomaticFormat, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::onClearIndividualFormat()
|
||||||
|
{
|
||||||
|
const QModelIndexList active = activeRows();
|
||||||
|
foreach (const QModelIndex &idx, active)
|
||||||
|
setModelData(LocalsIndividualFormatRole, AutomaticFormat, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::onShowUnprintable()
|
||||||
|
{
|
||||||
|
QAction *act = qobject_cast<QAction *>(sender());
|
||||||
|
QTC_ASSERT(act, return);
|
||||||
|
DebuggerEngine *engine = currentEngine();
|
||||||
|
WatchHandler *handler = engine->watchHandler();
|
||||||
|
handler->setUnprintableBase(act->data().toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::onTypeFormatChange()
|
||||||
|
{
|
||||||
|
QAction *act = qobject_cast<QAction *>(sender());
|
||||||
|
QTC_ASSERT(act, return);
|
||||||
|
QModelIndex idx = act->property(CurrentIndex).value<QModelIndex>();
|
||||||
|
setModelData(LocalsTypeFormatRole, act->data(), idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchTreeView::onIndividualFormatChange()
|
||||||
|
{
|
||||||
|
QAction *act = qobject_cast<QAction *>(sender());
|
||||||
|
QTC_ASSERT(act, return);
|
||||||
|
QModelIndex idx = act->property(CurrentIndex).value<QModelIndex>();
|
||||||
|
setModelData(LocalsIndividualFormatRole, act->data(), idx);
|
||||||
|
}
|
||||||
|
|
||||||
void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
||||||
{
|
{
|
||||||
DebuggerEngine *engine = currentEngine();
|
DebuggerEngine *engine = currentEngine();
|
||||||
WatchHandler *handler = engine->watchHandler();
|
WatchHandler *handler = engine->watchHandler();
|
||||||
|
|
||||||
const QModelIndexList active = activeRows();
|
|
||||||
const QModelIndex idx = indexAt(ev->pos());
|
const QModelIndex idx = indexAt(ev->pos());
|
||||||
const QModelIndex mi0 = idx.sibling(idx.row(), 0);
|
const QModelIndex mi0 = idx.sibling(idx.row(), 0);
|
||||||
const QModelIndex mi1 = idx.sibling(idx.row(), 1);
|
const QModelIndex mi1 = idx.sibling(idx.row(), 1);
|
||||||
@@ -604,89 +746,6 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
// Offer to open address pointed to or variable address.
|
// Offer to open address pointed to or variable address.
|
||||||
const bool createPointerActions = pointerAddress && pointerAddress != address;
|
const bool createPointerActions = pointerAddress && pointerAddress != address;
|
||||||
|
|
||||||
const QStringList alternativeFormats =
|
|
||||||
mi0.data(LocalsTypeFormatListRole).toStringList();
|
|
||||||
int typeFormat =
|
|
||||||
mi0.data(LocalsTypeFormatRole).toInt();
|
|
||||||
if (typeFormat >= alternativeFormats.size())
|
|
||||||
typeFormat = -1;
|
|
||||||
const int individualFormat =
|
|
||||||
mi0.data(LocalsIndividualFormatRole).toInt();
|
|
||||||
const int unprintableBase = handler->unprintableBase();
|
|
||||||
|
|
||||||
QMenu formatMenu;
|
|
||||||
QList<QAction *> typeFormatActions;
|
|
||||||
QList<QAction *> individualFormatActions;
|
|
||||||
QAction *clearTypeFormatAction = 0;
|
|
||||||
QAction *clearIndividualFormatAction = 0;
|
|
||||||
QAction *showUnprintableUnicode = 0;
|
|
||||||
QAction *showUnprintableEscape = 0;
|
|
||||||
QAction *showUnprintableOctal = 0;
|
|
||||||
QAction *showUnprintableHexadecimal = 0;
|
|
||||||
formatMenu.setTitle(tr("Change Local Display Format..."));
|
|
||||||
showUnprintableUnicode =
|
|
||||||
formatMenu.addAction(tr("Treat All Characters as Printable"));
|
|
||||||
showUnprintableUnicode->setCheckable(true);
|
|
||||||
showUnprintableUnicode->setChecked(unprintableBase == 0);
|
|
||||||
showUnprintableEscape =
|
|
||||||
formatMenu.addAction(tr("Show Unprintable Characters as Escape Sequences"));
|
|
||||||
showUnprintableEscape->setCheckable(true);
|
|
||||||
showUnprintableEscape->setChecked(unprintableBase == -1);
|
|
||||||
showUnprintableOctal =
|
|
||||||
formatMenu.addAction(tr("Show Unprintable Characters as Octal"));
|
|
||||||
showUnprintableOctal->setCheckable(true);
|
|
||||||
showUnprintableOctal->setChecked(unprintableBase == 8);
|
|
||||||
showUnprintableHexadecimal =
|
|
||||||
formatMenu.addAction(tr("Show Unprintable Characters as Hexadecimal"));
|
|
||||||
showUnprintableHexadecimal->setCheckable(true);
|
|
||||||
showUnprintableHexadecimal->setChecked(unprintableBase == 16);
|
|
||||||
if (idx.isValid() /*&& !alternativeFormats.isEmpty() */) {
|
|
||||||
const QString spacer = QLatin1String(" ");
|
|
||||||
formatMenu.addSeparator();
|
|
||||||
QAction *dummy = formatMenu.addAction(
|
|
||||||
tr("Change Display for Object Named \"%1\":").arg(mi0.data().toString()));
|
|
||||||
dummy->setEnabled(false);
|
|
||||||
QString msg = (individualFormat == -1 && typeFormat != -1)
|
|
||||||
? tr("Use Format for Type (Currently %1)")
|
|
||||||
.arg(alternativeFormats.at(typeFormat))
|
|
||||||
: tr("Use Display Format Based on Type") + QLatin1Char(' ');
|
|
||||||
clearIndividualFormatAction = formatMenu.addAction(spacer + msg);
|
|
||||||
clearIndividualFormatAction->setCheckable(true);
|
|
||||||
clearIndividualFormatAction->setChecked(individualFormat == -1);
|
|
||||||
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
|
||||||
const QString format = spacer + alternativeFormats.at(i);
|
|
||||||
QAction *act = new QAction(format, &formatMenu);
|
|
||||||
act->setCheckable(true);
|
|
||||||
if (i == individualFormat)
|
|
||||||
act->setChecked(true);
|
|
||||||
formatMenu.addAction(act);
|
|
||||||
individualFormatActions.append(act);
|
|
||||||
}
|
|
||||||
formatMenu.addSeparator();
|
|
||||||
dummy = formatMenu.addAction(
|
|
||||||
tr("Change Display for Type \"%1\":").arg(type));
|
|
||||||
dummy->setEnabled(false);
|
|
||||||
clearTypeFormatAction = formatMenu.addAction(spacer + tr("Automatic"));
|
|
||||||
//clearTypeFormatAction->setEnabled(typeFormat != -1);
|
|
||||||
//clearTypeFormatAction->setEnabled(individualFormat != -1);
|
|
||||||
clearTypeFormatAction->setCheckable(true);
|
|
||||||
clearTypeFormatAction->setChecked(typeFormat == -1);
|
|
||||||
for (int i = 0; i != alternativeFormats.size(); ++i) {
|
|
||||||
const QString format = spacer + alternativeFormats.at(i);
|
|
||||||
QAction *act = new QAction(format, &formatMenu);
|
|
||||||
act->setCheckable(true);
|
|
||||||
//act->setEnabled(individualFormat != -1);
|
|
||||||
if (i == typeFormat)
|
|
||||||
act->setChecked(true);
|
|
||||||
formatMenu.addAction(act);
|
|
||||||
typeFormatActions.append(act);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QAction *dummy = formatMenu.addAction(
|
|
||||||
tr("Change Display for Type or Item..."));
|
|
||||||
dummy->setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool actionsEnabled = engine->debuggerActionsEnabled();
|
const bool actionsEnabled = engine->debuggerActionsEnabled();
|
||||||
const bool canHandleWatches = engine->hasCapability(AddWatcherCapability);
|
const bool canHandleWatches = engine->hasCapability(AddWatcherCapability);
|
||||||
const DebuggerState state = engine->state();
|
const DebuggerState state = engine->state();
|
||||||
@@ -782,6 +841,14 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
menu.addAction(actRemoveWatches);
|
menu.addAction(actRemoveWatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMenu formatMenu;
|
||||||
|
if (mi0.isValid()) {
|
||||||
|
fillFormatMenu(&formatMenu, mi0);
|
||||||
|
} else {
|
||||||
|
QAction *dummy = formatMenu.addAction(tr("Change Display for Type or Item..."));
|
||||||
|
dummy->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
QMenu memoryMenu;
|
QMenu memoryMenu;
|
||||||
memoryMenu.setTitle(tr("Open Memory Editor..."));
|
memoryMenu.setTitle(tr("Open Memory Editor..."));
|
||||||
QAction *actOpenMemoryEditAtObjectAddress = new QAction(&memoryMenu);
|
QAction *actOpenMemoryEditAtObjectAddress = new QAction(&memoryMenu);
|
||||||
@@ -839,7 +906,6 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
QAction *actCopyValue = new QAction(tr("Copy Value to Clipboard"), &menu);
|
QAction *actCopyValue = new QAction(tr("Copy Value to Clipboard"), &menu);
|
||||||
actCopyValue->setEnabled(idx.isValid());
|
actCopyValue->setEnabled(idx.isValid());
|
||||||
|
|
||||||
|
|
||||||
menu.addAction(actInsertNewWatchItem);
|
menu.addAction(actInsertNewWatchItem);
|
||||||
menu.addAction(actSelectWidgetToWatch);
|
menu.addAction(actSelectWidgetToWatch);
|
||||||
menu.addMenu(&formatMenu);
|
menu.addMenu(&formatMenu);
|
||||||
@@ -914,43 +980,11 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
copyToClipboard(mi1.data().toString());
|
copyToClipboard(mi1.data().toString());
|
||||||
} else if (act == actRemoveWatches) {
|
} else if (act == actRemoveWatches) {
|
||||||
handler->clearWatches();
|
handler->clearWatches();
|
||||||
} else if (act == clearTypeFormatAction) {
|
|
||||||
foreach (const QModelIndex &idx, active)
|
|
||||||
setModelData(LocalsTypeFormatRole, -1, idx);
|
|
||||||
} else if (act == clearIndividualFormatAction) {
|
|
||||||
foreach (const QModelIndex &idx, active)
|
|
||||||
setModelData(LocalsIndividualFormatRole, -1, idx);
|
|
||||||
} else if (act == actShowInEditor) {
|
} else if (act == actShowInEditor) {
|
||||||
QString contents = handler->editorContents();
|
QString contents = handler->editorContents();
|
||||||
debuggerCore()->openTextEditor(tr("Locals & Expressions"), contents);
|
debuggerCore()->openTextEditor(tr("Locals & Expressions"), contents);
|
||||||
} else if (act == showUnprintableUnicode) {
|
|
||||||
handler->setUnprintableBase(0);
|
|
||||||
} else if (act == showUnprintableEscape) {
|
|
||||||
handler->setUnprintableBase(-1);
|
|
||||||
} else if (act == showUnprintableOctal) {
|
|
||||||
handler->setUnprintableBase(8);
|
|
||||||
} else if (act == showUnprintableHexadecimal) {
|
|
||||||
handler->setUnprintableBase(16);
|
|
||||||
} else if (act == actCloseEditorToolTips) {
|
} else if (act == actCloseEditorToolTips) {
|
||||||
DebuggerToolTipManager::closeAllToolTips();
|
DebuggerToolTipManager::closeAllToolTips();
|
||||||
} else if (handleBaseContextAction(act)) {
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
// Restrict multiple changes to items of the same type
|
|
||||||
// to avoid assigning illegal formats.
|
|
||||||
const QVariant currentType = mi1.data(LocalsTypeRole);
|
|
||||||
for (int i = 0; i != typeFormatActions.size(); ++i) {
|
|
||||||
if (act == typeFormatActions.at(i))
|
|
||||||
foreach (const QModelIndex &idx, active)
|
|
||||||
if (idx.data(LocalsTypeRole) == currentType)
|
|
||||||
setModelData(LocalsTypeFormatRole, i, idx);
|
|
||||||
}
|
|
||||||
for (int i = 0; i != individualFormatActions.size(); ++i) {
|
|
||||||
if (act == individualFormatActions.at(i))
|
|
||||||
foreach (const QModelIndex &idx, active)
|
|
||||||
if (idx.data(LocalsTypeRole) == currentType)
|
|
||||||
setModelData(LocalsIndividualFormatRole, i, idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ public:
|
|||||||
void rowActivated(const QModelIndex &index);
|
void rowActivated(const QModelIndex &index);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void fillFormatMenu(QMenu *, const QModelIndex &mi);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void watchExpression(const QString &exp);
|
void watchExpression(const QString &exp);
|
||||||
void watchExpression(const QString &exp, const QString &name);
|
void watchExpression(const QString &exp, const QString &name);
|
||||||
@@ -62,11 +64,19 @@ public slots:
|
|||||||
signals:
|
signals:
|
||||||
void currentIndexChanged(const QModelIndex ¤tIndex);
|
void currentIndexChanged(const QModelIndex ¤tIndex);
|
||||||
|
|
||||||
private:
|
private slots:
|
||||||
Q_SLOT void resetHelper();
|
void resetHelper();
|
||||||
Q_SLOT void expandNode(const QModelIndex &idx);
|
void expandNode(const QModelIndex &idx);
|
||||||
Q_SLOT void collapseNode(const QModelIndex &idx);
|
void collapseNode(const QModelIndex &idx);
|
||||||
|
|
||||||
|
void onClearIndividualFormat();
|
||||||
|
void onClearTypeFormat();
|
||||||
|
void onShowUnprintable();
|
||||||
|
|
||||||
|
void onTypeFormatChange();
|
||||||
|
void onIndividualFormatChange();
|
||||||
|
|
||||||
|
private:
|
||||||
void keyPressEvent(QKeyEvent *ev);
|
void keyPressEvent(QKeyEvent *ev);
|
||||||
void contextMenuEvent(QContextMenuEvent *ev);
|
void contextMenuEvent(QContextMenuEvent *ev);
|
||||||
void dragEnterEvent(QDragEnterEvent *ev);
|
void dragEnterEvent(QDragEnterEvent *ev);
|
||||||
|
|||||||
Reference in New Issue
Block a user