Debugger: Use primitive internal widget instead of matplotview

This practically removes any functionality beyond plain plot display,
but does that at least reliably, cross-platform, without dependency
on 3rd party python packages.

Change-Id: Iaff2f78595394522f32264c642df20dd48b83f8b
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2015-04-01 17:19:43 +02:00
parent 3e82dcad44
commit 3658bdac89
10 changed files with 356 additions and 296 deletions

View File

@@ -53,11 +53,13 @@
#include <QDebug>
#include <QFile>
#include <QPainter>
#include <QProcess>
#include <QTabWidget>
#include <QTextEdit>
#include <QTimer>
#include <algorithm>
#include <cstring>
#include <ctype.h>
@@ -109,6 +111,52 @@ static void saveWatchers()
setSessionValue("Watchers", WatchHandler::watchedExpressions());
}
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);
}
///////////////////////////////////////////////////////////////////////
//
// SeparatedView
@@ -126,17 +174,29 @@ public:
setWindowTitle(WatchHandler::tr("Debugger - Qt Creator"));
QVariant geometry = sessionValue("DebuggerSeparateWidgetGeometry");
if (geometry.isValid())
setGeometry(geometry.toRect());
if (geometry.isValid()) {
QRect rc = geometry.toRect();
if (rc.width() < 200)
rc.setWidth(200);
if (rc.height() < 200)
rc.setHeight(200);
setGeometry(rc);
}
}
~SeparatedView()
void saveGeometry()
{
setSessionValue("DebuggerSeparateWidgetGeometry", geometry());
}
~SeparatedView()
{
saveGeometry();
}
void removeObject(const QByteArray &key)
{
saveGeometry();
if (QWidget *w = findWidget(key)) {
removeTab(indexOf(w));
sanitize();
@@ -145,9 +205,11 @@ public:
void closeTab(int index)
{
saveGeometry();
if (QObject *o = widget(index)) {
QByteArray iname = o->property(INameProperty).toByteArray();
theIndividualFormats.remove(iname);
saveFormats();
}
removeTab(index);
sanitize();
@@ -170,7 +232,7 @@ public:
return 0;
}
template <class T> T *prepareObject(const QByteArray &key, const QString &title)
template <class T> T *prepareObject(const QByteArray &key, const QString &tabName)
{
T *t = 0;
if (QWidget *w = findWidget(key)) {
@@ -181,7 +243,7 @@ public:
if (!t) {
t = new T;
t->setProperty(KeyProperty, key);
addTab(t, title);
addTab(t, tabName);
}
setCurrentWidget(t);
@@ -218,8 +280,9 @@ public:
void insertItem(WatchItem *item);
void reexpandItems();
void showEditValue(const WatchData &data);
void setFormat(const QByteArray &type, int format);
void showEditValue(const WatchItem *item);
void setTypeFormat(const QByteArray &type, int format);
void setIndividualFormat(const QByteArray &iname, int format);
QString removeNamespaces(QString str) const;
@@ -884,16 +947,12 @@ bool WatchModel::setData(const QModelIndex &idx, const QVariant &value, int role
break;
case LocalsTypeFormatRole:
setFormat(item->type, value.toInt());
setTypeFormat(item->type, value.toInt());
m_engine->updateWatchItem(item);
break;
case LocalsIndividualFormatRole: {
const int format = value.toInt();
if (format == AutomaticFormat)
theIndividualFormats.remove(item->iname);
else
theIndividualFormats[item->iname] = format;
setIndividualFormat(item->iname, value.toInt());
m_engine->updateWatchItem(item);
break;
}
@@ -1010,7 +1069,7 @@ DisplayFormats WatchItem::typeFormatList() const
formats << watchModel()->m_reportedTypeFormats.value(t);
if (t.contains(QLatin1Char(']')))
formats << watchModel()->m_reportedTypeFormats.value(QLatin1String("[]"));
formats.append(ArrayPlotFormat);
// Fixed artificial string and pointer types.
if (origaddr || isPointerType(type)) {
@@ -1132,7 +1191,7 @@ void WatchModel::reinsertAllData()
emit inameIsExpanded(parent->iname);
emit itemIsExpanded(indexFromItem(parent));
}
showEditValue(data);
showEditValue(newItem); // FIXME: Needed?
}
}
@@ -1192,7 +1251,7 @@ void WatchModel::insertItem(WatchItem *item)
const int row = findInsertPosition(parent->children(), item);
parent->insertChild(row, item);
item->walkTree([this](TreeItem *sub) { showEditValue(*static_cast<WatchItem *>(sub)); });
item->walkTree([this](TreeItem *sub) { showEditValue(static_cast<WatchItem *>(sub)); });
}
void WatchModel::reexpandItems()
@@ -1326,20 +1385,20 @@ static void swapEndian(char *d, int nchar)
}
}
void WatchModel::showEditValue(const WatchData &data)
void WatchModel::showEditValue(const WatchItem *item)
{
const QByteArray key = data.address ? data.hexAddress() : data.iname;
switch (data.editformat) {
const QByteArray key = item->address ? item->hexAddress() : item->iname;
switch (item->editformat) {
case StopDisplay:
m_separatedView->removeObject(data.iname);
m_separatedView->removeObject(key);
break;
case DisplayImageData:
case DisplayImageFile: { // QImage
int width = 0, height = 0, nbytes = 0, format = 0;
QByteArray ba;
uchar *bits = 0;
if (data.editformat == DisplayImageData) {
ba = QByteArray::fromHex(data.editvalue);
if (item->editformat == DisplayImageData) {
ba = QByteArray::fromHex(item->editvalue);
QTC_ASSERT(ba.size() > 16, return);
const int *header = (int *)(ba.data());
if (!ba.at(0) && !ba.at(1)) // Check on 'width' for Python dumpers returning 4-byte swapped-data.
@@ -1349,8 +1408,8 @@ void WatchModel::showEditValue(const WatchData &data)
height = header[1];
nbytes = header[2];
format = header[3];
} else if (data.editformat == DisplayImageFile) {
QTextStream ts(data.editvalue);
} else if (item->editformat == DisplayImageFile) {
QTextStream ts(item->editvalue);
QString fileName;
ts >> width >> height >> nbytes >> format >> fileName;
QFile f(fileName);
@@ -1365,33 +1424,45 @@ void WatchModel::showEditValue(const WatchData &data)
QTC_ASSERT(0 < format && format < 32, return);
QImage im(width, height, QImage::Format(format));
std::memcpy(im.bits(), bits, nbytes);
const QString title = data.address ?
tr("%1 Object at %2").arg(QLatin1String(data.type),
QLatin1String(data.hexAddress())) :
tr("%1 Object at Unknown Address").arg(QLatin1String(data.type));
ImageViewer *v = m_separatedView->prepareObject<ImageViewer>(key, title);
v->setProperty(INameProperty, data.iname);
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())
);
v->setImage(im);
break;
}
case DisplayUtf16String:
case DisplayLatin1String:
case DisplayUtf8String: { // String data.
QByteArray ba = QByteArray::fromHex(data.editvalue);
QByteArray ba = QByteArray::fromHex(item->editvalue);
QString str;
if (data.editformat == DisplayUtf16String)
if (item->editformat == DisplayUtf16String)
str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2);
else if (data.editformat == DisplayLatin1String)
else if (item->editformat == DisplayLatin1String)
str = QString::fromLatin1(ba.constData(), ba.size());
else if (data.editformat == DisplayUtf8String)
else if (item->editformat == DisplayUtf8String)
str = QString::fromUtf8(ba.constData(), ba.size());
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, data.name);
t->setProperty(INameProperty, data.iname);
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, item->name);
t->setProperty(INameProperty, item->iname);
t->setText(str);
break;
}
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;
}
default:
QTC_ASSERT(false, qDebug() << "Display format: " << data.editformat);
QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat);
break;
}
}
@@ -1439,52 +1510,6 @@ QStringList WatchHandler::watchedExpressions()
return watcherNames;
}
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);
}
void WatchHandler::saveSessionData()
{
saveWatchers();
@@ -1537,7 +1562,7 @@ const WatchItem *WatchHandler::findCppLocalVariable(const QString &name) const
return 0;
}
void WatchModel::setFormat(const QByteArray &type0, int format)
void WatchModel::setTypeFormat(const QByteArray &type0, int format)
{
const QByteArray type = stripForFormat(type0);
if (format == AutomaticFormat)
@@ -1548,6 +1573,15 @@ void WatchModel::setFormat(const QByteArray &type0, int format)
reinsertAllData();
}
void WatchModel::setIndividualFormat(const QByteArray &iname, int format)
{
if (format == AutomaticFormat)
theIndividualFormats.remove(iname);
else
theIndividualFormats[iname] = format;
saveFormats();
}
int WatchHandler::format(const QByteArray &iname) const
{
int result = AutomaticFormat;