From dee0b3dcab48eba50609be83f9bd3c2807e6b027 Mon Sep 17 00:00:00 2001 From: pablomartin4btc Date: Sun, 10 Sep 2023 00:18:35 -0300 Subject: [PATCH] gui: Add a combo widget to filter by address type Introduce a label and a combobox UI widgets for address type filtering on the address book page. These 2 widgets are been displayed only on the Receiving tab. To ensure that the combo box selection updates the filter model correctly, an intermediary signal (addressTypeChanged) and a slot (handleAddressTypeChanged) were necessary due to the incompatibility between QComboBox::currentIndexChanged and QSortFilterProxyModel::setFilterFixedString. Update filter model to use nested filtering so when selected item changes on address type combo it will update the filter pattern on top of what the parent filter has already, which is lead by the searchLineEdit widget and all references of the current proxyModel (eg mapToSource, mapFromSource) to the nested and final filter model. Use GUIUtil::AddItemsToAddressTypeCombo to populate the combo with the default output types descriptions passing a defined local map for the output types tooltips that will be displayed for each item, similarly to the address types combobox in receivecoinsdialog. --- src/qt/addressbookpage.cpp | 104 ++++++++++++++++++++++++++++++-- src/qt/addressbookpage.h | 16 +++++ src/qt/forms/addressbookpage.ui | 10 +++ 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 82bd23c3808..bdae90fecef 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -163,7 +163,7 @@ void AddressBookPage::setModel(AddressTableModel *_model) return; auto type = tab == ReceivingTab ? AddressTableModel::Receive : AddressTableModel::Send; - proxyModel.reset(new AddressBookSortFilterProxyModel(type, this, false)); + proxyModel.reset(new AddressBookSortFilterProxyModel(type, this, true)); proxyModel->setSourceModel(_model); connect(ui->searchLineEdit, &QLineEdit::textChanged, proxyModel.get(), &QSortFilterProxyModel::setFilterWildcard); @@ -186,6 +186,8 @@ void AddressBookPage::setModel(AddressTableModel *_model) selectionChanged(); this->updateWindowsTitleWithWalletName(); + + this->setupAddressTypeCombo(); } void AddressBookPage::on_copyAddress_clicked() @@ -214,7 +216,7 @@ void AddressBookPage::onEditAction() EditAddressDialog::EditSendingAddress : EditAddressDialog::EditReceivingAddress, this); dlg->setModel(model); - QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0)); + QModelIndex origIndex = proxyModel->nestedProxyModel()->mapToSource(indexes.at(0)); dlg->loadRow(origIndex.row()); GUIUtil::ShowModalDialogAsynchronously(dlg); } @@ -318,7 +320,7 @@ void AddressBookPage::on_exportButton_clicked() CSVModelWriter writer(filename); // name, column, role - writer.setModel(proxyModel.get()); + writer.setModel(proxyModel->nestedProxyModel()); writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole); writer.addColumn("Address Type", AddressTableModel::Type, Qt::EditRole); writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole); @@ -342,7 +344,7 @@ void AddressBookPage::contextualMenu(const QPoint &point) void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/) { - QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent)); + QModelIndex idx = proxyModel.get()->mapFromSource(model->index(begin, AddressTableModel::Address, parent)); if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect)) { // Select row of newly created address, once @@ -364,3 +366,97 @@ void AddressBookPage::updateWindowsTitleWithWalletName() } } } + +std::map AddressBookPage::addressTypeTooltipMap() { + return {{OutputType::LEGACY, QObject::tr("Not recommended due to higher fees and less protection against typos.")}, + {OutputType::P2SH_SEGWIT, QObject::tr("An address compatible with older wallets.")}, + {OutputType::BECH32, QObject::tr("Native segwit address (BIP-173). Some old wallets don't support it.")}, + {OutputType::BECH32M, QObject::tr("Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.")}}; +} + +QString AddressBookPage::showAllTypes() const{ + return QObject::tr("All"); +} + +QString AddressBookPage::showAllTypesToolTip() const{ + return QObject::tr("Select an address type to filter by."); +} + +void AddressBookPage::handleAddressTypeChanged(int index) +{ + QString selectedValue = ui->addressType->currentText(); + // If show all types is selected then clear the selected value + // that will be sent to the filter so it shows everything + if (selectedValue == showAllTypes()) selectedValue.clear(); + // Emit a signal with the selected value + Q_EMIT addressTypeChanged(selectedValue); + // Forcing the resize as if it was selected an item with + // shorter content and right after a longer one, the + // columns are not resizing properly, this fixes it + ui->tableView->resizeColumnsToContents(); +} + +void AddressBookPage::initializeAddressTypeCombo() +{ + const auto index = ui->addressType->count(); + ui->addressType->addItem(showAllTypes(), index); + ui->addressType->setItemData(index, showAllTypesToolTip(), Qt::ToolTipRole); + ui->addressType->setCurrentIndex(index); +} + +void AddressBookPage::setupAddressTypeCombo() +{ + this->initializeAddressTypeCombo(); + ui->labelAddressType->setVisible(tab == ReceivingTab); + ui->addressType->setVisible(tab == ReceivingTab); + GUIUtil::AddItemsToAddressTypeCombo(ui->addressType, true, this->addressTypeTooltipMap()); + connect(ui->addressType, qOverload(&QComboBox::currentIndexChanged), this, &AddressBookPage::handleAddressTypeChanged); + connect(this, &AddressBookPage::addressTypeChanged, proxyModel->nestedProxyModel(), &QSortFilterProxyModel::setFilterFixedString); +} + +std::map AddressBookPage::addressTypeTooltipMap() { + return {{OutputType::LEGACY, QObject::tr("Not recommended due to higher fees and less protection against typos.")}, + {OutputType::P2SH_SEGWIT, QObject::tr("An address compatible with older wallets.")}, + {OutputType::BECH32, QObject::tr("Native segwit address (BIP-173). Some old wallets don't support it.")}, + {OutputType::BECH32M, QObject::tr("Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.")}}; +} + +QString AddressBookPage::showAllTypes() const{ + return QObject::tr("All"); +} + +QString AddressBookPage::showAllTypesToolTip() const{ + return QObject::tr("Select an address type to filter by."); +} + +void AddressBookPage::handleAddressTypeChanged(int index) +{ + QString selectedValue = ui->addressType->currentText(); + // If show all types is selected then clear the selected value + // that will be sent to the filter so it shows everything + if (selectedValue == showAllTypes()) selectedValue.clear(); + // Emit a signal with the selected value + Q_EMIT addressTypeChanged(selectedValue); + // Forcing the resize as if it was selected an item with + // shorter content and right after a longer one, the + // columns are not resizing properly, this fixes it + ui->tableView->resizeColumnsToContents(); +} + +void AddressBookPage::initializeAddressTypeCombo() +{ + const auto index = ui->addressType->count(); + ui->addressType->addItem(showAllTypes(), index); + ui->addressType->setItemData(index, showAllTypesToolTip(), Qt::ToolTipRole); + ui->addressType->setCurrentIndex(index); +} + +void AddressBookPage::setupAddressTypeCombo() +{ + this->initializeAddressTypeCombo(); + ui->labelAddressType->setVisible(tab == ReceivingTab); + ui->addressType->setVisible(tab == ReceivingTab); + GUIUtil::AddItemsToAddressTypeCombo(ui->addressType, true, this->addressTypeTooltipMap()); + connect(ui->addressType, qOverload(&QComboBox::currentIndexChanged), this, &AddressBookPage::handleAddressTypeChanged); + connect(this, &AddressBookPage::addressTypeChanged, proxyModel->nestedProxyModel(), &QSortFilterProxyModel::setFilterFixedString); +} diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 28d27b500a4..5cef233f368 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_QT_ADDRESSBOOKPAGE_H #define BITCOIN_QT_ADDRESSBOOKPAGE_H +#include + #include class AddressBookSortFilterProxyModel; @@ -57,6 +59,13 @@ public Q_SLOTS: QMenu *contextMenu; QString newAddressToSelect; void updateWindowsTitleWithWalletName(); + void initializeAddressTypeCombo(); + /** Default selected item of the address type combo to display all address types */ + QString showAllTypes() const; + QString showAllTypesToolTip() const; + /** Tooltip for each address type that will be displayed on the combo*/ + std::map addressTypeTooltipMap(); + void setupAddressTypeCombo(); private Q_SLOTS: /** Delete currently selected address entry */ @@ -78,9 +87,16 @@ private Q_SLOTS: void contextualMenu(const QPoint &point); /** New entry/entries were added to address table */ void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/); + /** Address type combo selection changed */ + void handleAddressTypeChanged(int index); Q_SIGNALS: void sendCoins(QString addr); + /** Emitted when the addressType combobox is changed (handled by handleAddressTypeChange). + * This signal is used as a workaround to connect the combobox and the proxy model filter, + * preventing the compiler error "Signal and slot arguments are not compatible."*/ + void addressTypeChanged(const QString &addressType); + }; #endif // BITCOIN_QT_ADDRESSBOOKPAGE_H diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index 7ac216286c8..c751d257aa0 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -109,6 +109,16 @@ + + + + Show address type: + + + + + +