Skip to content
Snippets Groups Projects
Commit 29e312f3 authored by hjk's avatar hjk
Browse files

Debugger: Save width of manually resized tree view columns


Task-number: QTCREATORBUG-12670
Change-Id: I5c31ffd6d3bb3060e851df56e9d9a80101df9347
Reviewed-by: default avatarAlessandro Portale <alessandro.portale@digia.com>
parent 2224f847
No related branches found
No related tags found
No related merge requests found
......@@ -29,16 +29,188 @@
#include "basetreeview.h"
#include <utils/qtcassert.h>
#include <QDebug>
#include <QFontMetrics>
#include <QHeaderView>
#include <QItemDelegate>
#include <QLabel>
#include <QMap>
#include <QMenu>
#include <QMouseEvent>
#include <QSettings>
#include <QTimer>
namespace Utils {
namespace Internal {
const char ColumnKey[] = "Columns";
class BaseTreeViewPrivate : public QObject
{
Q_OBJECT
public:
explicit BaseTreeViewPrivate(BaseTreeView *parent)
: q(parent), m_settings(0), m_expectUserChanges(false)
{}
bool eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::MouseMove) {
// At this time we don't know which section will get which size.
// But we know that a resizedSection() will be emitted later.
QMouseEvent *me = static_cast<QMouseEvent *>(event);
if (me->buttons() & Qt::LeftButton)
m_expectUserChanges = true;
}
return false;
}
void readSettings()
{
// This only reads setting, does not restore state.
// Storage format is a flat list of column numbers and width.
// Columns not mentioned are resized to content////
m_userHandled.clear();
if (m_settings && !m_settingsKey.isEmpty()) {
m_settings->beginGroup(m_settingsKey);
QVariantList l = m_settings->value(QLatin1String(ColumnKey)).toList();
QTC_ASSERT(l.size() % 2 == 0, qDebug() << m_settingsKey; l.append(0));
for (int i = 0; i < l.size(); i += 2) {
int column = l.at(i).toInt();
int width = l.at(i + 1).toInt();
QTC_ASSERT(column >= 0 && column < 20, qDebug() << m_settingsKey << column; continue);
QTC_ASSERT(width > 0 && width < 10000, qDebug() << m_settingsKey << width; continue);
m_userHandled[column] = width;
}
m_settings->endGroup();
}
}
void restoreState()
{
if (m_settings && !m_settingsKey.isEmpty()) {
QHeaderView *h = q->header();
for (auto it = m_userHandled.constBegin(), et = m_userHandled.constEnd(); it != et; ++it) {
const int column = it.key();
const int targetSize = it.value();
const int currentSize = h->sectionSize(column);
if (targetSize > 0 && targetSize != currentSize)
h->resizeSection(column, targetSize);
}
}
}
void saveState()
{
if (m_settings && !m_settingsKey.isEmpty()) {
m_settings->beginGroup(m_settingsKey);
QVariantList l;
for (auto it = m_userHandled.constBegin(), et = m_userHandled.constEnd(); it != et; ++it) {
const int column = it.key();
const int width = it.value();
QTC_ASSERT(column >= 0 && column < q->model()->columnCount(), continue);
QTC_ASSERT(width > 0 && width < 10000, continue);
l.append(column);
l.append(width);
}
m_settings->setValue(QLatin1String(ColumnKey), l);
m_settings->endGroup();
}
}
Q_SLOT void handleSectionResized(int logicalIndex, int /*oldSize*/, int newSize)
{
if (m_expectUserChanges) {
m_userHandled[logicalIndex] = newSize;
saveState();
m_expectUserChanges = false;
}
}
int suggestedColumnSize(int column) const
{
QHeaderView *h = q->header();
QTC_ASSERT(h, return -1);
QAbstractItemModel *m = q->model();
QTC_ASSERT(m, return -1);
QModelIndex a = q->indexAt(QPoint(1, 1));
a = a.sibling(a.row(), column);
QFontMetrics fm = q->fontMetrics();
int minimum = fm.width(m->headerData(column, Qt::Horizontal).toString());
const int ind = q->indentation();
for (int i = 0; i < 100 && a.isValid(); ++i) {
const QString s = m->data(a).toString();
int w = fm.width(s) + 10;
if (column == 0) {
for (QModelIndex b = a.parent(); b.isValid(); b = b.parent())
w += ind;
}
if (w > minimum)
minimum = w;
a = q->indexBelow(a);
}
return minimum;
}
Q_SLOT void resizeColumns()
{
QHeaderView *h = q->header();
QTC_ASSERT(h, return);
if (m_settings && !m_settingsKey.isEmpty()) {
for (int i = 0, n = h->count(); i != n; ++i) {
int targetSize;
if (m_userHandled.contains(i))
targetSize = m_userHandled.value(i);
else
targetSize = suggestedColumnSize(i);
const int currentSize = h->sectionSize(i);
if (targetSize > 0 && targetSize != currentSize)
h->resizeSection(i, targetSize);
}
}
}
Q_SLOT void rowActivatedHelper(const QModelIndex &index)
{
q->rowActivated(index);
}
Q_SLOT void rowClickedHelper(const QModelIndex &index)
{
q->rowClicked(index);
}
Q_SLOT void toggleColumnWidth(int logicalIndex)
{
QHeaderView *h = q->header();
const int currentSize = h->sectionSize(logicalIndex);
const int suggestedSize = suggestedColumnSize(logicalIndex);
int targetSize = suggestedSize;
// We switch to the size suggested by the contents, except
// when we have that size already, in that case minimize.
if (currentSize == suggestedSize) {
QFontMetrics fm = q->fontMetrics();
int headerSize = fm.width(q->model()->headerData(logicalIndex, Qt::Horizontal).toString());
int minSize = 10 * fm.width(QLatin1Char('x'));
targetSize = qMax(minSize, headerSize);
}
h->resizeSection(logicalIndex, targetSize);
m_userHandled.remove(logicalIndex); // Reset.
saveState();
}
public:
BaseTreeView *q;
QMap<int, int> m_userHandled; // column -> width, "not present" means "automatic"
QSettings *m_settings;
QString m_settingsKey;
bool m_expectUserChanges;
};
class BaseTreeViewDelegate : public QItemDelegate
{
......@@ -58,8 +230,12 @@ public:
}
};
} // namespace Internal
using namespace Internal;
BaseTreeView::BaseTreeView(QWidget *parent)
: TreeView(parent)
: TreeView(parent), d(new BaseTreeViewPrivate(this))
{
setAttribute(Qt::WA_MacShowFocusRect, false);
setFrameStyle(QFrame::NoFrame);
......@@ -68,30 +244,42 @@ BaseTreeView::BaseTreeView(QWidget *parent)
setSelectionMode(QAbstractItemView::ExtendedSelection);
setUniformRowHeights(true);
setItemDelegate(new BaseTreeViewDelegate(this));
header()->setDefaultAlignment(Qt::AlignLeft);
header()->setClickable(true);
QHeaderView *h = header();
h->setDefaultAlignment(Qt::AlignLeft);
h->setClickable(true);
h->viewport()->installEventFilter(d);
connect(this, SIGNAL(activated(QModelIndex)),
SLOT(rowActivatedHelper(QModelIndex)));
d, SLOT(rowActivatedHelper(QModelIndex)));
connect(this, SIGNAL(clicked(QModelIndex)),
SLOT(rowClickedHelper(QModelIndex)));
connect(header(), SIGNAL(sectionClicked(int)),
SLOT(toggleColumnWidth(int)));
d, SLOT(rowClickedHelper(QModelIndex)));
connect(h, SIGNAL(sectionClicked(int)),
d, SLOT(toggleColumnWidth(int)));
connect(h, SIGNAL(sectionResized(int,int,int)),
d, SLOT(handleSectionResized(int,int,int)));
}
BaseTreeView::~BaseTreeView()
{
delete d;
}
void BaseTreeView::setModel(QAbstractItemModel *m)
{
QAbstractItemModel *oldModel = model();
const char *sig = "columnAdjustmentRequested()";
if (model()) {
if (oldModel) {
int index = model()->metaObject()->indexOfSignal(sig);
if (index != -1)
disconnect(model(), SIGNAL(columnAdjustmentRequested()), this, SLOT(resizeColumns()));
disconnect(model(), SIGNAL(columnAdjustmentRequested()), d, SLOT(resizeColumns()));
}
TreeView::setModel(m);
if (m) {
int index = m->metaObject()->indexOfSignal(sig);
if (index != -1)
connect(m, SIGNAL(columnAdjustmentRequested()), this, SLOT(resizeColumns()));
connect(m, SIGNAL(columnAdjustmentRequested()), d, SLOT(resizeColumns()));
d->restoreState();
}
}
......@@ -100,60 +288,15 @@ void BaseTreeView::mousePressEvent(QMouseEvent *ev)
TreeView::mousePressEvent(ev);
const QModelIndex mi = indexAt(ev->pos());
if (!mi.isValid())
toggleColumnWidth(columnAt(ev->x()));
d->toggleColumnWidth(columnAt(ev->x()));
}
void BaseTreeView::resizeColumns()
void BaseTreeView::setSettings(QSettings *settings, const QByteArray &key)
{
QHeaderView *h = header();
if (!h)
return;
for (int i = 0, n = h->count(); i != n; ++i) {
int targetSize = suggestedColumnSize(i);
if (targetSize > 0)
h->resizeSection(i, targetSize);
}
}
int BaseTreeView::suggestedColumnSize(int column) const
{
QHeaderView *h = header();
if (!h)
return -1;
QModelIndex a = indexAt(QPoint(1, 1));
a = a.sibling(a.row(), column);
QFontMetrics fm(font());
int m = fm.width(model()->headerData(column, Qt::Horizontal).toString());
const int ind = indentation();
for (int i = 0; i < 100 && a.isValid(); ++i) {
const QString s = model()->data(a).toString();
int w = fm.width(s) + 10;
if (column == 0) {
for (QModelIndex b = a.parent(); b.isValid(); b = b.parent())
w += ind;
}
if (w > m)
m = w;
a = indexBelow(a);
}
return m;
}
void BaseTreeView::toggleColumnWidth(int logicalIndex)
{
QHeaderView *h = header();
const int currentSize = h->sectionSize(logicalIndex);
const int suggestedSize = suggestedColumnSize(logicalIndex);
if (currentSize == suggestedSize) {
QFontMetrics fm(font());
int headerSize = fm.width(model()->headerData(logicalIndex, Qt::Horizontal).toString());
int minSize = 10 * fm.width(QLatin1Char('x'));
h->resizeSection(logicalIndex, qMax(minSize, headerSize));
} else {
h->resizeSection(logicalIndex, suggestedSize);
}
QTC_ASSERT(!d->m_settings, qDebug() << "DUPLICATED setSettings" << key);
d->m_settings = settings;
d->m_settingsKey = QString::fromLatin1(key);
d->readSettings();
}
QModelIndexList BaseTreeView::activeRows() const
......@@ -169,3 +312,5 @@ QModelIndexList BaseTreeView::activeRows() const
}
} // namespace Utils
#include "basetreeview.moc"
......@@ -34,15 +34,23 @@
#include "itemviews.h"
QT_BEGIN_NAMESPACE
class QSettings;
QT_END_NAMESPACE
namespace Utils {
namespace Internal { class BaseTreeViewPrivate; }
class QTCREATOR_UTILS_EXPORT BaseTreeView : public TreeView
{
Q_OBJECT
public:
BaseTreeView(QWidget *parent = 0);
~BaseTreeView();
void setSettings(QSettings *settings, const QByteArray &key);
QModelIndexList activeRows() const;
void setModel(QAbstractItemModel *model);
......@@ -51,16 +59,10 @@ public:
void mousePressEvent(QMouseEvent *ev);
public slots:
void resizeColumns();
void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); }
private slots:
void rowActivatedHelper(const QModelIndex &index) { rowActivated(index); }
void rowClickedHelper(const QModelIndex &index) { rowClicked(index); }
void toggleColumnWidth(int logicalIndex);
private:
int suggestedColumnSize(int column) const;
Internal::BaseTreeViewPrivate *d;
};
} // namespace Utils
......
......@@ -834,7 +834,6 @@ public slots:
m_returnView->header()->resizeSection(section, newSize);
}
void sourceFilesDockToggled(bool on)
{
if (on && m_currentEngine->state() == InferiorStopOk)
......@@ -2762,6 +2761,8 @@ void DebuggerPluginPrivate::extensionsInitialized()
{
const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5"));
QSettings *settings = Core::ICore::settings();
m_debuggerSettings = new DebuggerSettings;
m_debuggerSettings->readSettings();
......@@ -2794,39 +2795,48 @@ void DebuggerPluginPrivate::extensionsInitialized()
m_breakHandler = new BreakHandler;
m_breakView = new BreakTreeView;
m_breakView->setSettings(settings, "Debugger.BreakWindow");
m_breakView->setModel(m_breakHandler->model());
m_breakWindow = addSearch(m_breakView, tr("Breakpoints"), DOCKWIDGET_BREAK);
m_modulesView = new ModulesTreeView;
m_modulesView->setSettings(settings, "Debugger.ModulesView");
m_modulesWindow = addSearch(m_modulesView, tr("Modules"), DOCKWIDGET_MODULES);
m_registerView = new RegisterTreeView;
m_registerView->setSettings(settings, "Debugger.RegisterView");
m_registerWindow = addSearch(m_registerView, tr("Registers"), DOCKWIDGET_REGISTER);
m_stackView = new StackTreeView;
m_stackView->setSettings(settings, "Debugger.StackView");
m_stackWindow = addSearch(m_stackView, tr("Stack"), DOCKWIDGET_STACK);
m_sourceFilesView = new SourceFilesTreeView;
m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView");
m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES);
m_threadsView = new ThreadsTreeView;
m_threadsView->setSettings(settings, "Debugger.ThreadsView");
m_threadsWindow = addSearch(m_threadsView, tr("Threads"), DOCKWIDGET_THREADS);
m_returnView = new WatchTreeView(ReturnType);
m_returnView = new WatchTreeView(ReturnType); // No settings.
m_returnWindow = addSearch(m_returnView, tr("Locals and Expressions"), "CppDebugReturn");
m_localsView = new WatchTreeView(LocalsType);
m_localsView->setSettings(settings, "Debugger.LocalsView");
m_localsWindow = addSearch(m_localsView, tr("Locals and Expressions"), "CppDebugLocals");
m_watchersView = new WatchTreeView(WatchersType);
m_watchersView = new WatchTreeView(WatchersType); // No settings.
m_watchersWindow = addSearch(m_watchersView, tr("Locals and Expressions"), "CppDebugWatchers");
m_inspectorView = new WatchTreeView(InspectType);
m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view.
m_inspectorWindow = addSearch(m_inspectorView, tr("Locals and Expressions"), "Inspector");
// Snapshot
m_snapshotHandler = new SnapshotHandler;
m_snapshotView = new SnapshotTreeView(m_snapshotHandler);
m_snapshotView->setSettings(settings, "Debugger.SnapshotView");
m_snapshotView->setModel(m_snapshotHandler->model());
m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS);
......
......@@ -587,6 +587,8 @@ QWidget *CallgrindToolPrivate::createWidgets()
{
QTC_ASSERT(!m_visualisation, return 0);
QSettings *coreSettings = ICore::settings();
//
// DockWidgets
//
......@@ -600,6 +602,7 @@ QWidget *CallgrindToolPrivate::createWidgets()
m_callersView = new CostView(mw);
m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView"));
m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView");
m_callersView->sortByColumn(CallModel::CostColumn);
m_callersView->setFrameStyle(QFrame::NoFrame);
// enable sorting
......@@ -612,6 +615,7 @@ QWidget *CallgrindToolPrivate::createWidgets()
m_calleesView = new CostView(mw);
m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView"));
m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView");
m_calleesView->sortByColumn(CallModel::CostColumn);
m_calleesView->setFrameStyle(QFrame::NoFrame);
// enable sorting
......@@ -624,6 +628,7 @@ QWidget *CallgrindToolPrivate::createWidgets()
m_flatView = new CostView(mw);
m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView"));
m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView");
m_flatView->sortByColumn(DataModel::SelfCostColumn);
m_flatView->setFrameStyle(QFrame::NoFrame);
m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment