mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-15 14:22:37 -03:00
68692d33c6
ac7ccd67d7
scripted-diff: Remove unused "What's This" button in dialogs on Windows (Hennadii Stepanov)b6951483ec
qt: Add flags to prevent a "What's This" button on Windows OS (Hennadii Stepanov) Pull request description: Fix #74. From [Qt docs](https://doc.qt.io/qt-5/qdialog.html#QDialog): > The widget flags _f_ are passed on to the `QWidget` constructor. If, for example, you don't want a **What's This** button in the title bar of the dialog, pass `Qt::WindowTitleHint | Qt::WindowSystemMenuHint` in _f_. Screenshot on Windows 10 (2004): - master (3ba25e3bdd
) ![Screenshot from 2020-09-07 16-55-42](https://user-images.githubusercontent.com/32963518/92402384-20dc6a00-f138-11ea-9dcb-3e0f6373ff22.png) - this PR (e322fe7e19ac504272d14b9b4f9b28b13df888ed) ![Screenshot from 2020-09-07 18-31-16](https://user-images.githubusercontent.com/32963518/92402509-5aad7080-f138-11ea-8b63-9bbbf8b9b9e1.png) ACKs for top commit: Bosch-0: tACKac7ccd67d7
Tested on Windows 10.0.18363 Build 18363. promag: Code review ACKac7ccd67d7
but with some suggestions. jonasschnelli: utACKac7ccd67d7
Tree-SHA512: f6750a17b7203106cb4db5870becba1cef6a505d4edcc710ba131338bd3aae051510627e62c9bcb8345a7f497c614709e11aeb8f6ae3ea85967bbce2a8c69e64
335 lines
10 KiB
C++
335 lines
10 KiB
C++
// Copyright (c) 2011-2020 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include <config/bitcoin-config.h>
|
|
#endif
|
|
|
|
#include <qt/addressbookpage.h>
|
|
#include <qt/forms/ui_addressbookpage.h>
|
|
|
|
#include <qt/addresstablemodel.h>
|
|
#include <qt/csvmodelwriter.h>
|
|
#include <qt/editaddressdialog.h>
|
|
#include <qt/guiutil.h>
|
|
#include <qt/platformstyle.h>
|
|
|
|
#include <QIcon>
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
#include <QSortFilterProxyModel>
|
|
|
|
class AddressBookSortFilterProxyModel final : public QSortFilterProxyModel
|
|
{
|
|
const QString m_type;
|
|
|
|
public:
|
|
AddressBookSortFilterProxyModel(const QString& type, QObject* parent)
|
|
: QSortFilterProxyModel(parent)
|
|
, m_type(type)
|
|
{
|
|
setDynamicSortFilter(true);
|
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
}
|
|
|
|
protected:
|
|
bool filterAcceptsRow(int row, const QModelIndex& parent) const override
|
|
{
|
|
auto model = sourceModel();
|
|
auto label = model->index(row, AddressTableModel::Label, parent);
|
|
|
|
if (model->data(label, AddressTableModel::TypeRole).toString() != m_type) {
|
|
return false;
|
|
}
|
|
|
|
auto address = model->index(row, AddressTableModel::Address, parent);
|
|
|
|
if (filterRegExp().indexIn(model->data(address).toString()) < 0 &&
|
|
filterRegExp().indexIn(model->data(label).toString()) < 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
|
|
QDialog(parent, GUIUtil::dialog_flags),
|
|
ui(new Ui::AddressBookPage),
|
|
model(nullptr),
|
|
mode(_mode),
|
|
tab(_tab)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
if (!platformStyle->getImagesOnButtons()) {
|
|
ui->newAddress->setIcon(QIcon());
|
|
ui->copyAddress->setIcon(QIcon());
|
|
ui->deleteAddress->setIcon(QIcon());
|
|
ui->exportButton->setIcon(QIcon());
|
|
} else {
|
|
ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
|
|
ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
|
|
ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
|
|
ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
|
|
}
|
|
|
|
switch(mode)
|
|
{
|
|
case ForSelection:
|
|
switch(tab)
|
|
{
|
|
case SendingTab: setWindowTitle(tr("Choose the address to send coins to")); break;
|
|
case ReceivingTab: setWindowTitle(tr("Choose the address to receive coins with")); break;
|
|
}
|
|
connect(ui->tableView, &QTableView::doubleClicked, this, &QDialog::accept);
|
|
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
ui->tableView->setFocus();
|
|
ui->closeButton->setText(tr("C&hoose"));
|
|
ui->exportButton->hide();
|
|
break;
|
|
case ForEditing:
|
|
switch(tab)
|
|
{
|
|
case SendingTab: setWindowTitle(tr("Sending addresses")); break;
|
|
case ReceivingTab: setWindowTitle(tr("Receiving addresses")); break;
|
|
}
|
|
break;
|
|
}
|
|
switch(tab)
|
|
{
|
|
case SendingTab:
|
|
ui->labelExplanation->setText(tr("These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins."));
|
|
ui->deleteAddress->setVisible(true);
|
|
ui->newAddress->setVisible(true);
|
|
break;
|
|
case ReceivingTab:
|
|
ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.\nSigning is only possible with addresses of the type 'legacy'."));
|
|
ui->deleteAddress->setVisible(false);
|
|
ui->newAddress->setVisible(false);
|
|
break;
|
|
}
|
|
|
|
// Context menu actions
|
|
QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
|
|
QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
|
|
QAction *editAction = new QAction(tr("&Edit"), this);
|
|
deleteAction = new QAction(ui->deleteAddress->text(), this);
|
|
|
|
// Build context menu
|
|
contextMenu = new QMenu(this);
|
|
contextMenu->addAction(copyAddressAction);
|
|
contextMenu->addAction(copyLabelAction);
|
|
contextMenu->addAction(editAction);
|
|
if(tab == SendingTab)
|
|
contextMenu->addAction(deleteAction);
|
|
contextMenu->addSeparator();
|
|
|
|
// Connect signals for context menu actions
|
|
connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked);
|
|
connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction);
|
|
connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction);
|
|
connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked);
|
|
|
|
connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu);
|
|
|
|
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
|
|
|
|
GUIUtil::handleCloseWindowShortcut(this);
|
|
}
|
|
|
|
AddressBookPage::~AddressBookPage()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void AddressBookPage::setModel(AddressTableModel *_model)
|
|
{
|
|
this->model = _model;
|
|
if(!_model)
|
|
return;
|
|
|
|
auto type = tab == ReceivingTab ? AddressTableModel::Receive : AddressTableModel::Send;
|
|
proxyModel = new AddressBookSortFilterProxyModel(type, this);
|
|
proxyModel->setSourceModel(_model);
|
|
|
|
connect(ui->searchLineEdit, &QLineEdit::textChanged, proxyModel, &QSortFilterProxyModel::setFilterWildcard);
|
|
|
|
ui->tableView->setModel(proxyModel);
|
|
ui->tableView->sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
// Set column widths
|
|
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Label, QHeaderView::Stretch);
|
|
ui->tableView->horizontalHeader()->setSectionResizeMode(AddressTableModel::Address, QHeaderView::ResizeToContents);
|
|
|
|
connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
|
|
this, &AddressBookPage::selectionChanged);
|
|
|
|
// Select row for newly created address
|
|
connect(_model, &AddressTableModel::rowsInserted, this, &AddressBookPage::selectNewAddress);
|
|
|
|
selectionChanged();
|
|
}
|
|
|
|
void AddressBookPage::on_copyAddress_clicked()
|
|
{
|
|
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
|
|
}
|
|
|
|
void AddressBookPage::onCopyLabelAction()
|
|
{
|
|
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
|
|
}
|
|
|
|
void AddressBookPage::onEditAction()
|
|
{
|
|
if(!model)
|
|
return;
|
|
|
|
if(!ui->tableView->selectionModel())
|
|
return;
|
|
QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
|
|
if(indexes.isEmpty())
|
|
return;
|
|
|
|
EditAddressDialog dlg(
|
|
tab == SendingTab ?
|
|
EditAddressDialog::EditSendingAddress :
|
|
EditAddressDialog::EditReceivingAddress, this);
|
|
dlg.setModel(model);
|
|
QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
|
|
dlg.loadRow(origIndex.row());
|
|
dlg.exec();
|
|
}
|
|
|
|
void AddressBookPage::on_newAddress_clicked()
|
|
{
|
|
if(!model)
|
|
return;
|
|
|
|
if (tab == ReceivingTab) {
|
|
return;
|
|
}
|
|
|
|
EditAddressDialog dlg(EditAddressDialog::NewSendingAddress, this);
|
|
dlg.setModel(model);
|
|
if(dlg.exec())
|
|
{
|
|
newAddressToSelect = dlg.getAddress();
|
|
}
|
|
}
|
|
|
|
void AddressBookPage::on_deleteAddress_clicked()
|
|
{
|
|
QTableView *table = ui->tableView;
|
|
if(!table->selectionModel())
|
|
return;
|
|
|
|
QModelIndexList indexes = table->selectionModel()->selectedRows();
|
|
if(!indexes.isEmpty())
|
|
{
|
|
table->model()->removeRow(indexes.at(0).row());
|
|
}
|
|
}
|
|
|
|
void AddressBookPage::selectionChanged()
|
|
{
|
|
// Set button states based on selected tab and selection
|
|
QTableView *table = ui->tableView;
|
|
if(!table->selectionModel())
|
|
return;
|
|
|
|
if(table->selectionModel()->hasSelection())
|
|
{
|
|
switch(tab)
|
|
{
|
|
case SendingTab:
|
|
// In sending tab, allow deletion of selection
|
|
ui->deleteAddress->setEnabled(true);
|
|
ui->deleteAddress->setVisible(true);
|
|
deleteAction->setEnabled(true);
|
|
break;
|
|
case ReceivingTab:
|
|
// Deleting receiving addresses, however, is not allowed
|
|
ui->deleteAddress->setEnabled(false);
|
|
ui->deleteAddress->setVisible(false);
|
|
deleteAction->setEnabled(false);
|
|
break;
|
|
}
|
|
ui->copyAddress->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
ui->deleteAddress->setEnabled(false);
|
|
ui->copyAddress->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void AddressBookPage::done(int retval)
|
|
{
|
|
QTableView *table = ui->tableView;
|
|
if(!table->selectionModel() || !table->model())
|
|
return;
|
|
|
|
// Figure out which address was selected, and return it
|
|
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
|
|
|
|
for (const QModelIndex& index : indexes) {
|
|
QVariant address = table->model()->data(index);
|
|
returnValue = address.toString();
|
|
}
|
|
|
|
if(returnValue.isEmpty())
|
|
{
|
|
// If no address entry selected, return rejected
|
|
retval = Rejected;
|
|
}
|
|
|
|
QDialog::done(retval);
|
|
}
|
|
|
|
void AddressBookPage::on_exportButton_clicked()
|
|
{
|
|
// CSV is currently the only supported format
|
|
QString filename = GUIUtil::getSaveFileName(this,
|
|
tr("Export Address List"), QString(),
|
|
tr("Comma separated file (*.csv)"), nullptr);
|
|
|
|
if (filename.isNull())
|
|
return;
|
|
|
|
CSVModelWriter writer(filename);
|
|
|
|
// name, column, role
|
|
writer.setModel(proxyModel);
|
|
writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
|
|
writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
|
|
|
|
if(!writer.write()) {
|
|
QMessageBox::critical(this, tr("Exporting Failed"),
|
|
tr("There was an error trying to save the address list to %1. Please try again.").arg(filename));
|
|
}
|
|
}
|
|
|
|
void AddressBookPage::contextualMenu(const QPoint &point)
|
|
{
|
|
QModelIndex index = ui->tableView->indexAt(point);
|
|
if(index.isValid())
|
|
{
|
|
contextMenu->exec(QCursor::pos());
|
|
}
|
|
}
|
|
|
|
void AddressBookPage::selectNewAddress(const QModelIndex &parent, int begin, int /*end*/)
|
|
{
|
|
QModelIndex idx = proxyModel->mapFromSource(model->index(begin, AddressTableModel::Address, parent));
|
|
if(idx.isValid() && (idx.data(Qt::EditRole).toString() == newAddressToSelect))
|
|
{
|
|
// Select row of newly created address, once
|
|
ui->tableView->setFocus();
|
|
ui->tableView->selectRow(idx.row());
|
|
newAddressToSelect.clear();
|
|
}
|
|
}
|