Commit be25be47 authored by hjk's avatar hjk

Debugger: Better handling of the tabbed extra views

Closing with the [x] now resets the Display mode of the associated
iname, and the view hides if there are no visible tabs left.
Also, remove the long-unused DisplayProcess format.

Change-Id: Ibd3308549af75e345c672c07f6714d26e7196e5a
Reviewed-by: default avatarChristian Stenger <christian.stenger@digia.com>
parent 6facb439
...@@ -1515,10 +1515,9 @@ StopDisplay, \ ...@@ -1515,10 +1515,9 @@ StopDisplay, \
DisplayImageData, \ DisplayImageData, \
DisplayUtf16String, \ DisplayUtf16String, \
DisplayImageFile, \ DisplayImageFile, \
DisplayProcess, \
DisplayLatin1String, \ DisplayLatin1String, \
DisplayUtf8String \ DisplayUtf8String \
= range(7) = range(6)
def mapForms(): def mapForms():
......
...@@ -2866,9 +2866,8 @@ bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, ...@@ -2866,9 +2866,8 @@ bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &,
DisplayImageData = 1, DisplayImageData = 1,
DisplayUtf16String = 2, DisplayUtf16String = 2,
DisplayImageFile = 3, DisplayImageFile = 3,
DisplayProcess = 4, DisplayLatin1String = 4,
DisplayLatin1String = 5, DisplayUtf8String = 5
DisplayUtf8String = 6
}; };
enum Formats { enum Formats {
......
...@@ -210,9 +210,8 @@ enum DebuggerDisplay { ...@@ -210,9 +210,8 @@ enum DebuggerDisplay {
DisplayImageData = 1, DisplayImageData = 1,
DisplayUtf16String = 2, DisplayUtf16String = 2,
DisplayImageFile = 3, DisplayImageFile = 3,
DisplayProcess = 4, DisplayLatin1String = 4,
DisplayLatin1String = 5, DisplayUtf8String = 5
DisplayUtf8String = 6
}; };
// Decode string data as returned by the dumper helpers. // Decode string data as returned by the dumper helpers.
QString decodeData(const QByteArray &baIn, int encoding); QString decodeData(const QByteArray &baIn, int encoding);
......
...@@ -79,6 +79,9 @@ static QHash<QByteArray, int> theTypeFormats; ...@@ -79,6 +79,9 @@ static QHash<QByteArray, int> theTypeFormats;
static QHash<QByteArray, int> theIndividualFormats; static QHash<QByteArray, int> theIndividualFormats;
static int theUnprintableBase = -1; static int theUnprintableBase = -1;
const char INameProperty[] = "INameProperty";
const char KeyProperty[] = "KeyProperty";
static QByteArray stripForFormat(const QByteArray &ba) static QByteArray stripForFormat(const QByteArray &ba)
{ {
QByteArray res; QByteArray res;
...@@ -139,26 +142,85 @@ private: ...@@ -139,26 +142,85 @@ private:
// //
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
class SeparateViewWidget : public QTabWidget class SeparatedView : public QTabWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
SeparateViewWidget(QWidget *parent) : QTabWidget(parent) SeparatedView() : QTabWidget(debuggerCore()->mainWindow())
{ {
setTabsClosable(true); setTabsClosable(true);
connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeTab(int))); connect(this, SIGNAL(tabCloseRequested(int)), SLOT(closeTab(int)));
setWindowFlags(windowFlags() | Qt::Window); setWindowFlags(windowFlags() | Qt::Window);
setWindowTitle(WatchHandler::tr("Debugger - Qt Creator")); setWindowTitle(WatchHandler::tr("Debugger - Qt Creator"));
QVariant geometry = DebuggerCore::sessionValue("DebuggerSeparateWidgetGeometry");
if (geometry.isValid())
setGeometry(geometry.toRect());
}
~SeparatedView()
{
DebuggerCore::setSessionValue("DebuggerSeparateWidgetGeometry", geometry());
} }
public slots: void removeObject(const QByteArray &key)
void closeTab(int index)
{ {
if (QWidget *w = findWidget(key)) {
removeTab(indexOf(w));
sanitize();
}
}
Q_SLOT void closeTab(int index)
{
if (QObject *o = widget(index)) {
QByteArray iname = o->property(INameProperty).toByteArray();
theIndividualFormats.remove(iname);
}
removeTab(index); removeTab(index);
sanitize();
}
void sanitize()
{
if (count() == 0)
hide();
}
QWidget *findWidget(const QByteArray &needle)
{
for (int i = count(); --i >= 0; ) {
QWidget *w = widget(i);
QByteArray key = w->property(KeyProperty).toByteArray();
if (key == needle)
return w;
}
return 0;
}
template <class T> T *prepareObject(const QByteArray &key, const QString &title)
{
T *t = 0;
if (QWidget *w = findWidget(key)) {
t = qobject_cast<T *>(w);
if (!t)
removeTab(indexOf(w));
}
if (!t) {
t = new T;
t->setProperty(KeyProperty, key);
addTab(t, title);
}
setCurrentWidget(t);
show();
raise();
return t;
} }
}; };
class WatchModel : public QAbstractItemModel class WatchModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
...@@ -253,10 +315,6 @@ private: ...@@ -253,10 +315,6 @@ private:
QStringList dumperTypeFormatList(const WatchData &data) const; QStringList dumperTypeFormatList(const WatchData &data) const;
DumperTypeFormats m_reportedTypeFormats; DumperTypeFormats m_reportedTypeFormats;
// QWidgets and QProcesses taking care of special displays.
typedef QMap<QByteArray, QPointer<QObject> > EditHandlers;
EditHandlers m_editHandlers;
WatchItem *createItem(const QByteArray &iname); WatchItem *createItem(const QByteArray &iname);
WatchItem *createItem(const WatchData &data); WatchItem *createItem(const WatchData &data);
void assignData(WatchItem *item, const WatchData &data); void assignData(WatchItem *item, const WatchData &data);
...@@ -1537,23 +1595,19 @@ void WatchModel::setCurrentItem(const QByteArray &iname) ...@@ -1537,23 +1595,19 @@ void WatchModel::setCurrentItem(const QByteArray &iname)
WatchHandler::WatchHandler(DebuggerEngine *engine) WatchHandler::WatchHandler(DebuggerEngine *engine)
{ {
m_separateWindow = 0;
m_engine = engine; m_engine = engine;
m_watcherCounter = DebuggerCore::sessionValue("Watchers").toStringList().count(); m_watcherCounter = DebuggerCore::sessionValue("Watchers").toStringList().count();
m_model = new WatchModel(this); m_model = new WatchModel(this);
m_contentsValid = false; m_contentsValid = false;
m_contentsValid = true; // FIXME m_contentsValid = true; // FIXME
m_resetLocationScheduled = false; m_resetLocationScheduled = false;
m_separatedView = new SeparatedView;
} }
WatchHandler::~WatchHandler() WatchHandler::~WatchHandler()
{ {
if (m_separateWindow) { delete m_separatedView;
DebuggerCore::setSessionValue("DebuggerSeparateWidgetGeometry", m_separatedView = 0;
m_separateWindow->geometry());
delete m_separateWindow;
m_separateWindow = 0;
}
// Do it manually to prevent calling back in model destructors // Do it manually to prevent calling back in model destructors
// after m_cache is destroyed. // after m_cache is destroyed.
delete m_model; delete m_model;
...@@ -1566,14 +1620,7 @@ void WatchHandler::cleanup() ...@@ -1566,14 +1620,7 @@ void WatchHandler::cleanup()
theWatcherNames.remove(QByteArray()); theWatcherNames.remove(QByteArray());
m_model->reinitialize(); m_model->reinitialize();
m_model->m_fetchTriggered.clear(); m_model->m_fetchTriggered.clear();
#if 1 m_separatedView->hide();
for (WatchModel::EditHandlers::ConstIterator it = m_model->m_editHandlers.begin();
it != m_model->m_editHandlers.end(); ++it) {
if (!it.value().isNull())
delete it.value();
}
m_model->m_editHandlers.clear();
#endif
} }
void WatchHandler::insertIncompleteData(const WatchData &data) void WatchHandler::insertIncompleteData(const WatchData &data)
...@@ -1717,68 +1764,15 @@ static void swapEndian(char *d, int nchar) ...@@ -1717,68 +1764,15 @@ static void swapEndian(char *d, int nchar)
} }
} }
static int indexOf(const QTabWidget *tw, const QWidget *w)
{
for (int i = 0; i < tw->count(); ++i)
if (tw->widget(i) == w)
return i;
return -1;
}
void WatchHandler::removeSeparateWidget(QObject *o)
{
const int index = o && o->isWidgetType() && !m_separateWindow.isNull() ?
indexOf(m_separateWindow, static_cast<QWidget *>(o)) : -1;
if (index != -1) {
m_separateWindow->removeTab(index);
if (!m_separateWindow->count())
m_separateWindow->hide();
}
}
void WatchHandler::showSeparateWidget(QWidget *w)
{
if (m_separateWindow.isNull()) {
m_separateWindow = new SeparateViewWidget(debuggerCore()->mainWindow());
QVariant geometry = DebuggerCore::sessionValue("DebuggerSeparateWidgetGeometry");
if (geometry.isValid())
m_separateWindow->setGeometry(geometry.toRect());
}
int index = indexOf(m_separateWindow, w);
if (index != -1)
m_separateWindow->setTabText(index, w->windowTitle());
else
index = m_separateWindow->addTab(w, w->windowTitle());
m_separateWindow->setCurrentIndex(index);
m_separateWindow->show();
m_separateWindow->raise();
}
void WatchHandler::showEditValue(const WatchData &data) void WatchHandler::showEditValue(const WatchData &data)
{ {
const QByteArray key = data.address ? data.hexAddress() : data.iname; const QByteArray key = data.address ? data.hexAddress() : data.iname;
QObject *w = m_model->m_editHandlers.value(key);
switch (data.editformat) { switch (data.editformat) {
case StopDisplay: case StopDisplay:
m_model->m_editHandlers.remove(data.iname); m_separatedView->removeObject(data.iname);
delete w;
break; break;
case DisplayImageData: case DisplayImageData:
case DisplayImageFile: { // QImage case DisplayImageFile: { // QImage
ImageViewer *l = qobject_cast<ImageViewer *>(w);
if (!l) {
removeSeparateWidget(w);
delete w;
l = new ImageViewer;
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));
l->setWindowTitle(title);
showSeparateWidget(l);
m_model->m_editHandlers[key] = l;
}
int width = 0, height = 0, nbytes = 0, format = 0; int width = 0, height = 0, nbytes = 0, format = 0;
QByteArray ba; QByteArray ba;
uchar *bits = 0; uchar *bits = 0;
...@@ -1809,20 +1803,18 @@ void WatchHandler::showEditValue(const WatchData &data) ...@@ -1809,20 +1803,18 @@ void WatchHandler::showEditValue(const WatchData &data)
QTC_ASSERT(0 < format && format < 32, return); QTC_ASSERT(0 < format && format < 32, return);
QImage im(width, height, QImage::Format(format)); QImage im(width, height, QImage::Format(format));
qMemCopy(im.bits(), bits, nbytes); qMemCopy(im.bits(), bits, nbytes);
l->setImage(im); const QString title = data.address ?
showSeparateWidget(l); 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);
v->setImage(im);
break; break;
}
case DisplayUtf16String: case DisplayUtf16String:
case DisplayLatin1String: case DisplayLatin1String:
case DisplayUtf8String: { // String data. case DisplayUtf8String: { // String data.
QTextEdit *t = qobject_cast<QTextEdit *>(w);
if (!t) {
removeSeparateWidget(w);
delete w;
t = new QTextEdit;
m_model->m_editHandlers[key] = t;
}
QByteArray ba = QByteArray::fromHex(data.editvalue); QByteArray ba = QByteArray::fromHex(data.editvalue);
QString str; QString str;
if (data.editformat == DisplayUtf16String) if (data.editformat == DisplayUtf16String)
...@@ -1831,26 +1823,11 @@ void WatchHandler::showEditValue(const WatchData &data) ...@@ -1831,26 +1823,11 @@ void WatchHandler::showEditValue(const WatchData &data)
str = QString::fromLatin1(ba.constData(), ba.size()); str = QString::fromLatin1(ba.constData(), ba.size());
else if (data.editformat == DisplayUtf8String) else if (data.editformat == DisplayUtf8String)
str = QString::fromUtf8(ba.constData(), ba.size()); str = QString::fromUtf8(ba.constData(), ba.size());
t->setWindowTitle(data.name); QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, data.name);
t->setProperty(INameProperty, data.iname);
t->setText(str); t->setText(str);
showSeparateWidget(t);
}
break; break;
case DisplayProcess: {
// Generic Process.
int pos = data.editvalue.indexOf('|');
QByteArray cmd = data.editvalue.left(pos);
QByteArray input = data.editvalue.mid(pos + 1);
QProcess *p = qobject_cast<QProcess *>(w);
if (!p) {
p = new QProcess;
p->start(QLatin1String(cmd));
p->waitForStarted();
m_model->m_editHandlers[key] = p;
}
p->write(input + '\n');
} }
break;
default: default:
QTC_ASSERT(false, qDebug() << "Display format: " << data.editformat); QTC_ASSERT(false, qDebug() << "Display format: " << data.editformat);
break; break;
......
...@@ -36,11 +36,11 @@ ...@@ -36,11 +36,11 @@
#include <QPointer> #include <QPointer>
#include <QVector> #include <QVector>
QT_FORWARD_DECLARE_CLASS(QTabWidget)
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class SeparatedView;
// Special formats. Keep in sync with dumper.py. // Special formats. Keep in sync with dumper.py.
enum DisplayFormat enum DisplayFormat
{ {
...@@ -190,9 +190,6 @@ public: ...@@ -190,9 +190,6 @@ public:
void resetValueCache(); void resetValueCache();
private: private:
void removeSeparateWidget(QObject *o);
void showSeparateWidget(QWidget *w);
friend class WatchModel; friend class WatchModel;
void saveWatchers(); void saveWatchers();
...@@ -203,7 +200,7 @@ private: ...@@ -203,7 +200,7 @@ private:
WatchModel *m_model; // Owned. WatchModel *m_model; // Owned.
DebuggerEngine *m_engine; // Not owned. DebuggerEngine *m_engine; // Not owned.
QPointer<QTabWidget> m_separateWindow; // Owned. SeparatedView *m_separatedView; // Owned.
int m_watcherCounter; int m_watcherCounter;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment