diff options
author | Aaron Barany <akb825@gmail.com> | 2018-12-11 23:09:39 -0800 |
---|---|---|
committer | Aaron Barany <akb825@gmail.com> | 2019-01-08 18:43:44 +0000 |
commit | 21c0f5395ed163a122cc11de5f1ba8eb0805e25f (patch) | |
tree | 183db79686d0130fe557ce543bb3f08f24067b49 | |
parent | 6c40d9570cd0eb14f8e0651c51c730b8d19ebf14 (diff) |
Debugger: Fix sizing of debugger columns
Added span column property to BaseTreeView. This takes an index to a column
that will span remaining space not explicitly taken by the other columns.
This listens to resizing of the tree view and columns that are manually
resized to keep the sizes consistent.
The stack view now once again uses the StackView class, which now sets the
function column as the span column. This will adjust the column size the
first time stack frame contents are encountered. It will not resize
automatically until it's re-created (the next debug session) so it doesn't
undo custom resizing. This also restores the ability to toggle stack
addresses. Some obsolete parts of this class were removed as part of
retrofitting it for the current state of the debugger.
Stack, breakpoint, and thread views now resize remaining space for the
function column rather than empty space at the end. This is generally the
most important field when debugging and can get very long, especially in
C++.
Task-number: QTCREATORBUG-21763
Change-Id: I821c83d1d951f3311d7fa9fcddcbdeedfeed1573
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
-rw-r--r-- | src/libs/utils/basetreeview.cpp | 129 | ||||
-rw-r--r-- | src/libs/utils/basetreeview.h | 8 | ||||
-rw-r--r-- | src/plugins/debugger/debuggerengine.cpp | 4 | ||||
-rw-r--r-- | src/plugins/debugger/debuggerplugin.cpp | 1 | ||||
-rw-r--r-- | src/plugins/debugger/stackwindow.cpp | 41 | ||||
-rw-r--r-- | src/plugins/debugger/stackwindow.h | 9 |
6 files changed, 177 insertions, 15 deletions
diff --git a/src/libs/utils/basetreeview.cpp b/src/libs/utils/basetreeview.cpp index bae4c16fef..03139a4154 100644 --- a/src/libs/utils/basetreeview.cpp +++ b/src/libs/utils/basetreeview.cpp @@ -55,6 +55,40 @@ public: m_settingsTimer.setSingleShot(true); connect(&m_settingsTimer, &QTimer::timeout, this, &BaseTreeViewPrivate::doSaveState); + connect(q->header(), &QHeaderView::sectionResized, this, [this](int logicalIndex, int oldSize, int newSize) { + if (m_processingSpans || m_spanColumn < 0) + return; + + QHeaderView *h = q->header(); + QTC_ASSERT(h, return); + + // Last non-hidden column. + int count = h->count(); + while (count > 0 && h->isSectionHidden(count - 1)) + --count; + + if (count == 0) + return; + + int column = logicalIndex; + if (oldSize < newSize) + { + // Protect against sizing past the next section. + while (column + 1 < count && h->sectionSize(column + 1) == h->minimumSectionSize()) + ++column; + } + + if (logicalIndex >= m_spanColumn) { + // Resize after the span column. + column = column + 1; + } else { + // Resize the span column or before it. + column = m_spanColumn; + } + + rebalanceColumns(column, false); + }); + connect(q->header(), &QHeaderView::geometriesChanged, this, QOverload<>::of(&BaseTreeViewPrivate::rebalanceColumns)); } bool eventFilter(QObject *, QEvent *event) override @@ -197,6 +231,17 @@ public: } } + void setSpanColumn(int column) + { + if (column == m_spanColumn) + return; + + m_spanColumn = column; + if (m_spanColumn >= 0) + q->header()->setStretchLastSection(false); + rebalanceColumns(); + } + void toggleColumnWidth(int logicalIndex) { QHeaderView *h = q->header(); @@ -211,11 +256,72 @@ public: int minSize = 10 * fm.width(QLatin1Char('x')); targetSize = qMax(minSize, headerSize); } + + // Prevent rebalance as part of this resize. + m_processingSpans = true; h->resizeSection(logicalIndex, targetSize); + m_processingSpans = false; + + // Now trigger a rebalance so it resizes the span column. (if set) + rebalanceColumns(); + m_userHandled.remove(logicalIndex); // Reset. saveState(); } + void rebalanceColumns() + { + rebalanceColumns(m_spanColumn, true); + } + + void rebalanceColumns(int column, bool allowResizePrevious) + { + if (m_spanColumn < 0 || column < 0 || m_processingSpans) + return; + + QHeaderView *h = q->header(); + QTC_ASSERT(h, return); + + int count = h->count(); + if (column >= count) + return; + + // Start with the target column, and resize other columns as necessary. + int totalSize = q->viewport()->width(); + if (tryRebalanceColumns(column, totalSize)) + return; + + for (int i = allowResizePrevious ? 0 : column + 1; i < count; ++i) { + if (i != column && tryRebalanceColumns(i, totalSize)) + return; + } + } + + bool tryRebalanceColumns(int column, int totalSize) + { + QHeaderView *h = q->header(); + + int count = h->count(); + int otherColumnTotal = 0; + for (int i = 0; i < count; ++i) { + if (i != column) + otherColumnTotal += h->sectionSize(i); + } + + if (otherColumnTotal < totalSize) { + m_processingSpans = true; + h->resizeSection(column, totalSize - otherColumnTotal); + m_processingSpans = false; + } else + return false; + + // Make sure this didn't go over the total size. + int totalColumnSize = 0; + for (int i = 0; i < count; ++i) + totalColumnSize += h->sectionSize(i); + return totalColumnSize == totalSize; + } + public: BaseTreeView *q; QMap<int, int> m_userHandled; // column -> width, "not present" means "automatic" @@ -224,6 +330,8 @@ public: QString m_settingsKey; bool m_expectUserChanges = false; ProgressIndicator *m_progressIndicator = nullptr; + int m_spanColumn = -1; + bool m_processingSpans = false; }; class BaseTreeViewDelegate : public QItemDelegate @@ -369,6 +477,12 @@ void BaseTreeView::mouseDoubleClickEvent(QMouseEvent *ev) TreeView::mouseDoubleClickEvent(ev); } +void BaseTreeView::resizeEvent(QResizeEvent *ev) +{ + TreeView::resizeEvent(ev); + d->rebalanceColumns(); +} + void BaseTreeView::showEvent(QShowEvent *ev) { emit aboutToShow(); @@ -416,6 +530,21 @@ void BaseTreeView::resizeColumns() d->resizeColumns(); } +int BaseTreeView::spanColumn() const +{ + return d->m_spanColumn; +} + +void BaseTreeView::setSpanColumn(int column) +{ + d->setSpanColumn(column); +} + +void BaseTreeView::refreshSpanColumn() +{ + d->rebalanceColumns(); +} + void BaseTreeView::setSettings(QSettings *settings, const QByteArray &key) { QTC_ASSERT(!d->m_settings, qDebug() << "DUPLICATED setSettings" << key); diff --git a/src/libs/utils/basetreeview.h b/src/libs/utils/basetreeview.h index 923c69b042..36da658913 100644 --- a/src/libs/utils/basetreeview.h +++ b/src/libs/utils/basetreeview.h @@ -68,11 +68,19 @@ public: void dropEvent(QDropEvent *ev) override; void dragMoveEvent(QDragMoveEvent *ev) override; void mouseDoubleClickEvent(QMouseEvent *ev) override; + void resizeEvent(QResizeEvent *event) override; void showProgressIndicator(); void hideProgressIndicator(); void resizeColumns(); + int spanColumn() const; + void setSpanColumn(int column); + + // In some situations this needs to be called when manually resizing columns when the span + // column is set. + void refreshSpanColumn(); + signals: void aboutToShow(); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 6594e7d00c..1f06fef2af 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -642,7 +642,7 @@ void DebuggerEnginePrivate::setupViews() m_registerWindow->setObjectName(DOCKWIDGET_REGISTER); m_registerWindow->setWindowTitle(tr("Reg&isters")); - m_stackView = new BaseTreeView; + m_stackView = new StackTreeView; m_stackView->setModel(m_stackHandler.model()); m_stackView->setSettings(settings, "Debugger.StackView"); m_stackView->setIconSize(QSize(10, 10)); @@ -666,6 +666,7 @@ void DebuggerEnginePrivate::setupViews() m_threadsView->setSortingEnabled(true); m_threadsView->setSettings(settings, "Debugger.ThreadsView"); m_threadsView->setIconSize(QSize(10, 10)); + m_threadsView->setSpanColumn(ThreadData::FunctionColumn); m_threadsWindow = addSearch(m_threadsView); m_threadsWindow->setObjectName(DOCKWIDGET_THREADS); m_threadsWindow->setWindowTitle(tr("&Threads")); @@ -711,6 +712,7 @@ void DebuggerEnginePrivate::setupViews() m_breakView->setIconSize(QSize(10, 10)); m_breakView->setWindowIcon(Icons::BREAKPOINTS.icon()); m_breakView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_breakView->setSpanColumn(BreakpointFunctionColumn); connect(action(UseAddressInBreakpointsView), &QAction::toggled, this, [this](bool on) { m_breakView->setColumnHidden(BreakpointAddressColumn, !on); }); m_breakView->setSettings(settings, "Debugger.BreakWindow"); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 04b1b8d341..042a7f4368 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1038,6 +1038,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, m_breakpointManagerView->setSettings(settings, "Debugger.BreakWindow"); m_breakpointManagerView->setRootIsDecorated(true); m_breakpointManagerView->setModel(BreakpointManager::model()); + m_breakpointManagerView->setSpanColumn(BreakpointFunctionColumn); m_breakpointManagerWindow = addSearch(m_breakpointManagerView); m_breakpointManagerWindow->setWindowTitle(tr("Breakpoint Preset")); m_breakpointManagerWindow->setObjectName(DOCKWIDGET_BREAKPOINTMANAGER); diff --git a/src/plugins/debugger/stackwindow.cpp b/src/plugins/debugger/stackwindow.cpp index 83e6af2829..e25f6aa72b 100644 --- a/src/plugins/debugger/stackwindow.cpp +++ b/src/plugins/debugger/stackwindow.cpp @@ -32,33 +32,56 @@ #include <utils/savedaction.h> #include <QAction> +#include <QHeaderView> namespace Debugger { namespace Internal { -StackTreeView::StackTreeView() +StackTreeView::StackTreeView(QWidget *parent) + : BaseTreeView(parent) { - setWindowTitle(tr("Stack")); - connect(action(UseAddressInStackView), &QAction::toggled, this, &StackTreeView::showAddressColumn); + setSpanColumn(StackFunctionNameColumn); showAddressColumn(false); } +void StackTreeView::setModel(QAbstractItemModel *model) +{ + BaseTreeView::setModel(model); + connect(static_cast<StackHandler*>(model), &StackHandler::stackChanged, + this, [this]() { + if (!m_contentsAdjusted) + adjustForContents(); + }); + + // Resize for the current contents if any are available. + showAddressColumn(action(UseAddressInStackView)->isChecked()); +} + void StackTreeView::showAddressColumn(bool on) { setColumnHidden(StackAddressColumn, !on); - resizeColumnToContents(StackLevelColumn); - resizeColumnToContents(StackLineNumberColumn); - resizeColumnToContents(StackAddressColumn); + adjustForContents(true); } -void StackTreeView::setModel(QAbstractItemModel *model) +void StackTreeView::adjustForContents(bool refreshSpan) { - BaseTreeView::setModel(model); + // Skip resizing if no contents. This will be called again once contents are available. + if (!model() || model()->rowCount() == 0) { + if (refreshSpan) + refreshSpanColumn(); + return; + } + + // Resize without attempting to fix up the columns. + setSpanColumn(-1); resizeColumnToContents(StackLevelColumn); + resizeColumnToContents(StackFileNameColumn); resizeColumnToContents(StackLineNumberColumn); - showAddressColumn(action(UseAddressInStackView)->isChecked()); + resizeColumnToContents(StackAddressColumn); + setSpanColumn(StackFunctionNameColumn); + m_contentsAdjusted = true; } } // namespace Internal diff --git a/src/plugins/debugger/stackwindow.h b/src/plugins/debugger/stackwindow.h index 5439ead73f..79f2974e82 100644 --- a/src/plugins/debugger/stackwindow.h +++ b/src/plugins/debugger/stackwindow.h @@ -34,17 +34,16 @@ namespace Internal { class StackTreeView : public Utils::BaseTreeView { - Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::StackTreeView) - public: - StackTreeView(); + explicit StackTreeView(QWidget *parent = nullptr); private: void setModel(QAbstractItemModel *model) override; void showAddressColumn(bool on); - void reloadFullStack(); - void copyContentsToClipboard(); + void adjustForContents(bool refreshSpan = false); + + bool m_contentsAdjusted = false; }; } // namespace Internal |