diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 487878fc1..b2c0b9e8f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -391,6 +391,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() { diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index f1dee388c..d7de4c606 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include @@ -118,6 +120,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); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 2af3949ae..f63032494 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -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) diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index bfe8b3401..1d051d932 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -10,7 +10,9 @@ #include #include #include +#include #include +#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(); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 0dd324bb2..c5135b94d 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -175,6 +175,7 @@ void TransactionView::setModel(WalletModel *model) transactionProxyModel->setSortRole(Qt::EditRole); + transactionView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); transactionView->setModel(transactionProxyModel); transactionView->setAlternatingRowColors(true); transactionView->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -183,15 +184,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); } } @@ -460,3 +458,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); +} diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index f0e07c179..5985f66c7 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -6,6 +6,7 @@ #define TRANSACTIONVIEW_H #include +#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();