From af3c781b18789c5391d398ae39bd702bc3c615d5 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 | 53 ++++++++++++++++++++++++++++++--- src/qt/addressbookpage.h | 16 ++++++++++ src/qt/forms/addressbookpage.ui | 10 +++++++ 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 07492ad12b1..f580de46a00 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -173,7 +173,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); @@ -195,6 +195,8 @@ void AddressBookPage::setModel(AddressTableModel *_model) connect(_model, &AddressTableModel::rowsInserted, this, &AddressBookPage::selectNewAddress); selectionChanged(); + + this->setupAddressTypeCombo(); } void AddressBookPage::on_copyAddress_clicked() @@ -223,7 +225,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); } @@ -327,7 +329,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); @@ -351,7 +353,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 @@ -360,3 +362,46 @@ void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int newAddressToSelect.clear(); } } + +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); +} + +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); +} \ No newline at end of file diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index fe7095118bd..8a71e068543 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; @@ -56,6 +58,13 @@ public Q_SLOTS: std::unique_ptr proxyModel{nullptr}; QMenu *contextMenu; QString newAddressToSelect; + 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 */ @@ -77,9 +86,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: + + + + + +