[QT] Fixes feel when resizing the last column on tables (issue #2862)

Re-submitting this pull request with a single commit.

This patch introduces a GUIUtil class that is used when setting up the 2 tables we have so far on the Qt-GUI.
In the past you could only resize the last column, which has BTC amounts from the right border of the column header, something that was rather unnatural.

If a new table were ever to be added to the interface, fixing the last columns resizing behavior is rather simple. Just look at how we initialize here a TableViewLastColumnResizingFixer object when setting up the table header's behavior, and then how we override the resize event of the component (can be the table, or the dialog) and we invoke columnResizingFixer->stretchColumnWidth(columnIndex);
This commit is contained in:
gubatron 2014-03-21 01:45:47 -04:00
parent 6539cfc583
commit 8c29273ff0
6 changed files with 217 additions and 27 deletions

View file

@ -379,6 +379,121 @@ bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
return QObject::eventFilter(obj, evt);
}
void TableViewLastColumnResizingFixer::connectViewHeadersSignals()
{
connect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
connect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
}
//we need to disconnect these while handling the resize events, otherwise we can enter infinite loops
void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals()
{
disconnect(tableView->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(on_sectionResized(int,int,int)));
disconnect(tableView->horizontalHeader(), SIGNAL(geometriesChanged()), this, SLOT(on_geometriesChanged()));
}
//setup the resize mode, handles compatibility for QT5 and below as the method signatures changed. (refactored here for readability)
void TableViewLastColumnResizingFixer::setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
{
#if QT_VERSION < 0x050000
tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode);
#else
tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode);
#endif
}
void TableViewLastColumnResizingFixer::resizeColumn(int nColumnIndex, int width) {
tableView->setColumnWidth(nColumnIndex, width);
tableView->horizontalHeader()->resizeSection(nColumnIndex, width);
}
int TableViewLastColumnResizingFixer::getColumnsWidth()
{
int nColumnsWidthSum = 0;
for (int i = 0; i < columnCount; i++)
{
nColumnsWidthSum += tableView->horizontalHeader()->sectionSize(i);
}
return nColumnsWidthSum;
}
int TableViewLastColumnResizingFixer::getAvailableWidthForColumn(int column)
{
int nResult = lastColumnMinimumWidth;
int nTableWidth = tableView->horizontalHeader()->width();
if (nTableWidth > 0)
{
int nOtherColsWidth = getColumnsWidth() - tableView->horizontalHeader()->sectionSize(column);
nResult = std::max(nResult, nTableWidth - nOtherColsWidth);
}
return nResult;
}
//make sure we don't make the columns wider than the table's viewport's width.
void TableViewLastColumnResizingFixer::adjustTableColumnsWidth()
{
disconnectViewHeadersSignals();
resizeColumn(lastColumnIndex, getAvailableWidthForColumn(lastColumnIndex));
connectViewHeadersSignals();
int nTableWidth = tableView->horizontalHeader()->width();
int nColsWidth = getColumnsWidth();
if (nColsWidth > nTableWidth)
{
resizeColumn(secondToLastColumnIndex,getAvailableWidthForColumn(secondToLastColumnIndex));
}
}
//make column use all the space available, useful during window resizing.
void TableViewLastColumnResizingFixer::stretchColumnWidth(int column) {
disconnectViewHeadersSignals();
resizeColumn(column, getAvailableWidthForColumn(column));
connectViewHeadersSignals();
}
//when a section is resized this is a slot-proxy for ajustAmountColumnWidth()
void TableViewLastColumnResizingFixer::on_sectionResized(int logicalIndex, int oldSize, int newSize)
{
adjustTableColumnsWidth();
int remainingWidth = getAvailableWidthForColumn(logicalIndex);
if (newSize > remainingWidth)
{
resizeColumn(logicalIndex, remainingWidth);
}
}
//when the table's geometry is ready, we manually perform the Stretch of the "Message" column
//as the "Stretch" resize mode does not allow for interactive resizing.
void TableViewLastColumnResizingFixer::on_geometriesChanged()
{
if ((getColumnsWidth() - this->tableView->horizontalHeader()->width()) != 0)
{
disconnectViewHeadersSignals();
resizeColumn(secondToLastColumnIndex, getAvailableWidthForColumn(secondToLastColumnIndex));
connectViewHeadersSignals();
}
}
/**
* Initializes all internal variables and prepares the
* the resize modes of the last 2 columns of the table and
*/
TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth) :
tableView(table),
lastColumnMinimumWidth(lastColMinimumWidth),
allColumnsMinimumWidth(allColsMinimumWidth)
{
columnCount = tableView->horizontalHeader()->count();
lastColumnIndex = columnCount - 1;
secondToLastColumnIndex = columnCount - 2;
tableView->horizontalHeader()->setMinimumSectionSize(allColumnsMinimumWidth);
setViewHeaderResizeMode(secondToLastColumnIndex, QHeaderView::Interactive);
setViewHeaderResizeMode(lastColumnIndex, QHeaderView::Interactive);
}
#ifdef WIN32
boost::filesystem::path static StartupShortcutPath()
{

View file

@ -8,6 +8,8 @@
#include <QMessageBox>
#include <QObject>
#include <QString>
#include <QTableView>
#include <QHeaderView>
class QValidatedLineEdit;
class SendCoinsRecipient;
@ -116,6 +118,44 @@ namespace GUIUtil
int size_threshold;
};
/**
* Makes a QTableView last column feel as if it was being resized from its left border.
* Also makes sure the column widths are never larger than the table's viewport.
* In Qt, all columns are resizable from the right, but it's not intuitive resizing the last column from the right.
* Usually our second to last columns behave as if stretched, and when on strech mode, columns aren't resizable
* interactively or programatically.
*
* This helper object takes care of this issue.
*
*/
class TableViewLastColumnResizingFixer: public QObject
{
Q_OBJECT
public:
TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth);
void stretchColumnWidth(int column);
private:
QTableView* tableView;
int lastColumnMinimumWidth;
int allColumnsMinimumWidth;
int lastColumnIndex;
int columnCount;
int secondToLastColumnIndex;
void adjustTableColumnsWidth();
int getAvailableWidthForColumn(int column);
int getColumnsWidth();
void connectViewHeadersSignals();
void disconnectViewHeadersSignals();
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode);
void resizeColumn(int nColumnIndex, int width);
private slots:
void on_sectionResized(int logicalIndex, int oldSize, int newSize);
void on_geometriesChanged();
};
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);

View file

@ -55,34 +55,35 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) :
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}
void ReceiveCoinsDialog::setModel(WalletModel *model)
{
this->model = model;
if(model && model->getOptionsModel())
{
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
ui->recentRequestsView->setModel(model->getRecentRequestsTableModel());
ui->recentRequestsView->setAlternatingRowColors(true);
ui->recentRequestsView->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->recentRequestsView->setSelectionMode(QAbstractItemView::ContiguousSelection);
ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Date, 130);
ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Label, 120);
#if QT_VERSION < 0x050000
ui->recentRequestsView->horizontalHeader()->setResizeMode(RecentRequestsTableModel::Message, QHeaderView::Stretch);
#else
ui->recentRequestsView->horizontalHeader()->setSectionResizeMode(RecentRequestsTableModel::Message, QHeaderView::Stretch);
#endif
ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Amount, 100);
model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
connect(ui->recentRequestsView->selectionModel(),
SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
this,
SLOT(on_recentRequestsView_selectionChanged(QItemSelection, QItemSelection)));
updateDisplayUnit();
QTableView* tableView = ui->recentRequestsView;
tableView->verticalHeader()->hide();
tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
tableView->setModel(model->getRecentRequestsTableModel());
tableView->setAlternatingRowColors(true);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
//(last 2 columns are set when the table geometry is ready) by the columnResizingFixer.
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH);
}
}
@ -200,6 +201,12 @@ void ReceiveCoinsDialog::on_removeRequestButton_clicked()
model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
}
//We override the virtual resizeEvent of the QWidget to adjust tablet's column sizes as the table's width is proportional to the dialog's.
void ReceiveCoinsDialog::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
columnResizingFixer->stretchColumnWidth(RecentRequestsTableModel::Message);
}
void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return)

View file

@ -10,7 +10,9 @@
#include <QMenu>
#include <QPoint>
#include <QVariant>
#include <QHeaderView>
#include <QItemSelection>
#include "guiutil.h"
namespace Ui {
class ReceiveCoinsDialog;
@ -28,11 +30,18 @@ class ReceiveCoinsDialog : public QDialog
Q_OBJECT
public:
enum ColumnWidths {
DATE_COLUMN_WIDTH = 130,
LABEL_COLUMN_WIDTH = 120,
AMOUNT_MINIMUM_COLUMN_WIDTH = 160,
MINIMUM_COLUMN_WIDTH = 130
};
explicit ReceiveCoinsDialog(QWidget *parent = 0);
~ReceiveCoinsDialog();
void setModel(WalletModel *model);
public slots:
void clear();
void reject();
@ -43,9 +52,11 @@ protected:
private:
Ui::ReceiveCoinsDialog *ui;
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
WalletModel *model;
QMenu *contextMenu;
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent* event);
private slots:
void on_receiveButton_clicked();

View file

@ -168,6 +168,7 @@ void TransactionView::setModel(WalletModel *model)
transactionProxyModel->setSortRole(Qt::EditRole);
transactionView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
transactionView->setModel(transactionProxyModel);
transactionView->setAlternatingRowColors(true);
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
@ -176,15 +177,12 @@ void TransactionView::setModel(WalletModel *model)
transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
#if QT_VERSION < 0x050000
transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#else
transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
#endif
transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH);
}
}
@ -439,3 +437,9 @@ void TransactionView::focusTransaction(const QModelIndex &idx)
transactionView->setCurrentIndex(targetIdx);
transactionView->setFocus();
}
//We override the virtual resizeEvent of the QWidget to adjust tablet's column sizes as the table's width is proportional to the dialog's.
void TransactionView::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
}

View file

@ -6,6 +6,7 @@
#define TRANSACTIONVIEW_H
#include <QWidget>
#include "guiutil.h"
class TransactionFilterProxy;
class WalletModel;
@ -44,6 +45,14 @@ public:
Range
};
enum ColumnWidths {
STATUS_COLUMN_WIDTH = 23,
DATE_COLUMN_WIDTH = 120,
TYPE_COLUMN_WIDTH = 120,
AMOUNT_MINIMUM_COLUMN_WIDTH = 120,
MINIMUM_COLUMN_WIDTH = 23
};
private:
WalletModel *model;
TransactionFilterProxy *transactionProxyModel;
@ -62,6 +71,10 @@ private:
QWidget *createDateRangeWidget();
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
virtual void resizeEvent(QResizeEvent* event);
private slots:
void contextualMenu(const QPoint &);
void dateRangeChanged();