mirror of
https://github.com/dashpay/dash.git
synced 2024-12-29 05:49:11 +01:00
41dddafa8f
f5a3a5b9ab362c58fa424261f313aa9cf46d2a98 gui: Add close window shortcut (Miguel Herranz) Pull request description: CMD+W is the standard shortcut in macOS to close a window without exiting the program. This adds support to use the shortcut in both main and debug windows. ACKs for top commit: jonasschnelli: Tested ACK f5a3a5b9ab362c58fa424261f313aa9cf46d2a98 hebasto: ACK f5a3a5b9ab362c58fa424261f313aa9cf46d2a98, tested on Linux Mint 19.3 by manually opening available dialogs and sub-windows, and applying the `Ctrl+W` shortcut. Also tested with "Minimize on close" option enabled / disabled. Tree-SHA512: 39851f6680cf97c334d5759c6f8597cb45685359417493ff8b0566672edbd32303fa15ac4260ec8ab5ea1458a600a329153014f25609e1db9cf399aa851ae2f9
361 lines
11 KiB
C++
361 lines
11 KiB
C++
// Copyright (c) 2011-2019 The Bitcoin Core developers
|
|
// Copyright (c) 2014-2022 The Dash 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/optionsmodel.h>
|
|
#include <qt/qrdialog.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(Mode _mode, Tabs _tab, QWidget* parent) :
|
|
QDialog(parent),
|
|
ui(new Ui::AddressBookPage),
|
|
model(nullptr),
|
|
mode(_mode),
|
|
tab(_tab)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
ui->showAddressQRCode->setIcon(QIcon());
|
|
#ifndef USE_QRCODE
|
|
ui->showAddressQRCode->setEnabled(false);
|
|
#endif
|
|
|
|
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 Dash 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 Dash addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses."));
|
|
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);
|
|
QAction *showAddressQRCodeAction = new QAction(tr("&Show address QR code"), this);
|
|
deleteAction = new QAction(ui->deleteAddress->text(), this);
|
|
#ifndef USE_QRCODE
|
|
showAddressQRCodeAction->setEnabled(false);
|
|
#endif
|
|
|
|
// Build context menu
|
|
contextMenu = new QMenu(this);
|
|
contextMenu->addAction(copyAddressAction);
|
|
contextMenu->addAction(copyLabelAction);
|
|
contextMenu->addAction(editAction);
|
|
if(tab == SendingTab)
|
|
contextMenu->addAction(deleteAction);
|
|
contextMenu->addSeparator();
|
|
contextMenu->addAction(showAddressQRCodeAction);
|
|
|
|
// 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(showAddressQRCodeAction, &QAction::triggered, this, &AddressBookPage::on_showAddressQRCode_clicked);
|
|
connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu);
|
|
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
|
|
|
|
GUIUtil::updateFonts();
|
|
|
|
GUIUtil::disableMacFocusRect(this);
|
|
|
|
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::on_showAddressQRCode_clicked()
|
|
{
|
|
QList<QModelIndex> entries = GUIUtil::getEntryData(ui->tableView, AddressTableModel::Address);
|
|
if (entries.empty()) {
|
|
return;
|
|
}
|
|
|
|
QString strAddress = entries.at(0).data(Qt::EditRole).toString();
|
|
QRDialog* dialog = new QRDialog(this);
|
|
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
dialog->setInfo(tr("QR code"), "dash:"+strAddress, "", strAddress);
|
|
dialog->show();
|
|
}
|
|
|
|
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);
|
|
#ifdef USE_QRCODE
|
|
ui->showAddressQRCode->setEnabled(true);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ui->deleteAddress->setEnabled(false);
|
|
ui->copyAddress->setEnabled(false);
|
|
#ifdef USE_QRCODE
|
|
ui->showAddressQRCode->setEnabled(false);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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"),
|
|
//: %1 is a name of the file (e.g., "addrbook.csv") that the bitcoin addresses were exported to.
|
|
tr("There was an error trying to save the address list to %1. Please try again.", "An error message.").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();
|
|
}
|
|
}
|