mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-15 22:32:37 -03:00
bb3da8fe41
The recent requests table will allow you to copy data points even if they do not exist. This PR implements checks to disable the 'copy label', 'copy message', and 'copy amount' context menu action if the respective fields are empty.
329 lines
12 KiB
C++
329 lines
12 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.
|
|
|
|
#include <wallet/wallet.h>
|
|
|
|
#include <qt/receivecoinsdialog.h>
|
|
#include <qt/forms/ui_receivecoinsdialog.h>
|
|
|
|
#include <qt/addresstablemodel.h>
|
|
#include <qt/guiutil.h>
|
|
#include <qt/optionsmodel.h>
|
|
#include <qt/platformstyle.h>
|
|
#include <qt/receiverequestdialog.h>
|
|
#include <qt/recentrequeststablemodel.h>
|
|
#include <qt/walletmodel.h>
|
|
|
|
#include <QAction>
|
|
#include <QCursor>
|
|
#include <QMessageBox>
|
|
#include <QScrollBar>
|
|
#include <QSettings>
|
|
#include <QTextDocument>
|
|
|
|
ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
|
|
QDialog(parent, GUIUtil::dialog_flags),
|
|
ui(new Ui::ReceiveCoinsDialog),
|
|
model(nullptr),
|
|
platformStyle(_platformStyle)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
if (!_platformStyle->getImagesOnButtons()) {
|
|
ui->clearButton->setIcon(QIcon());
|
|
ui->receiveButton->setIcon(QIcon());
|
|
ui->showRequestButton->setIcon(QIcon());
|
|
ui->removeRequestButton->setIcon(QIcon());
|
|
} else {
|
|
ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
|
|
ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
|
|
ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
|
|
ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
|
|
}
|
|
|
|
// context menu actions
|
|
QAction *copyURIAction = new QAction(tr("Copy URI"), this);
|
|
QAction* copyAddressAction = new QAction(tr("Copy address"), this);
|
|
copyLabelAction = new QAction(tr("Copy label"), this);
|
|
copyMessageAction = new QAction(tr("Copy message"), this);
|
|
copyAmountAction = new QAction(tr("Copy amount"), this);
|
|
|
|
// context menu
|
|
contextMenu = new QMenu(this);
|
|
contextMenu->addAction(copyURIAction);
|
|
contextMenu->addAction(copyAddressAction);
|
|
contextMenu->addAction(copyLabelAction);
|
|
contextMenu->addAction(copyMessageAction);
|
|
contextMenu->addAction(copyAmountAction);
|
|
|
|
// context menu signals
|
|
connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu);
|
|
connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI);
|
|
connect(copyAddressAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAddress);
|
|
connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel);
|
|
connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage);
|
|
connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount);
|
|
|
|
connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear);
|
|
|
|
QTableView* tableView = ui->recentRequestsView;
|
|
tableView->verticalHeader()->hide();
|
|
tableView->setAlternatingRowColors(true);
|
|
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
|
|
|
|
QSettings settings;
|
|
if (!tableView->horizontalHeader()->restoreState(settings.value("RecentRequestsViewHeaderState").toByteArray())) {
|
|
tableView->setColumnWidth(RecentRequestsTableModel::Date, DATE_COLUMN_WIDTH);
|
|
tableView->setColumnWidth(RecentRequestsTableModel::Label, LABEL_COLUMN_WIDTH);
|
|
tableView->setColumnWidth(RecentRequestsTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
|
|
tableView->horizontalHeader()->setMinimumSectionSize(MINIMUM_COLUMN_WIDTH);
|
|
tableView->horizontalHeader()->setStretchLastSection(true);
|
|
}
|
|
tableView->horizontalHeader()->setSortIndicator(RecentRequestsTableModel::Date, Qt::DescendingOrder);
|
|
}
|
|
|
|
void ReceiveCoinsDialog::setModel(WalletModel *_model)
|
|
{
|
|
this->model = _model;
|
|
|
|
if(_model && _model->getOptionsModel())
|
|
{
|
|
_model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
|
|
connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &ReceiveCoinsDialog::updateDisplayUnit);
|
|
updateDisplayUnit();
|
|
|
|
QTableView* tableView = ui->recentRequestsView;
|
|
tableView->setModel(_model->getRecentRequestsTableModel());
|
|
connect(tableView->selectionModel(),
|
|
&QItemSelectionModel::selectionChanged, this,
|
|
&ReceiveCoinsDialog::recentRequestsView_selectionChanged);
|
|
|
|
if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
|
|
ui->useBech32->setCheckState(Qt::Checked);
|
|
} else {
|
|
ui->useBech32->setCheckState(Qt::Unchecked);
|
|
}
|
|
|
|
// Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
|
|
ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
|
|
|
|
// Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
|
|
connect(model, &WalletModel::canGetAddressesChanged, [this] {
|
|
ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
|
|
});
|
|
}
|
|
}
|
|
|
|
ReceiveCoinsDialog::~ReceiveCoinsDialog()
|
|
{
|
|
QSettings settings;
|
|
settings.setValue("RecentRequestsViewHeaderState", ui->recentRequestsView->horizontalHeader()->saveState());
|
|
delete ui;
|
|
}
|
|
|
|
void ReceiveCoinsDialog::clear()
|
|
{
|
|
ui->reqAmount->clear();
|
|
ui->reqLabel->setText("");
|
|
ui->reqMessage->setText("");
|
|
updateDisplayUnit();
|
|
}
|
|
|
|
void ReceiveCoinsDialog::reject()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void ReceiveCoinsDialog::accept()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void ReceiveCoinsDialog::updateDisplayUnit()
|
|
{
|
|
if(model && model->getOptionsModel())
|
|
{
|
|
ui->reqAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
|
|
}
|
|
}
|
|
|
|
void ReceiveCoinsDialog::on_receiveButton_clicked()
|
|
{
|
|
if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel())
|
|
return;
|
|
|
|
QString address;
|
|
QString label = ui->reqLabel->text();
|
|
/* Generate new receiving address */
|
|
OutputType address_type;
|
|
if (ui->useBech32->isChecked()) {
|
|
address_type = OutputType::BECH32;
|
|
} else {
|
|
address_type = model->wallet().getDefaultAddressType();
|
|
if (address_type == OutputType::BECH32) {
|
|
address_type = OutputType::P2SH_SEGWIT;
|
|
}
|
|
}
|
|
address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type);
|
|
|
|
switch(model->getAddressTableModel()->getEditStatus())
|
|
{
|
|
case AddressTableModel::EditStatus::OK: {
|
|
// Success
|
|
SendCoinsRecipient info(address, label,
|
|
ui->reqAmount->value(), ui->reqMessage->text());
|
|
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
dialog->setModel(model);
|
|
dialog->setInfo(info);
|
|
dialog->show();
|
|
|
|
/* Store request for later reference */
|
|
model->getRecentRequestsTableModel()->addNewRequest(info);
|
|
break;
|
|
}
|
|
case AddressTableModel::EditStatus::WALLET_UNLOCK_FAILURE:
|
|
QMessageBox::critical(this, windowTitle(),
|
|
tr("Could not unlock wallet."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case AddressTableModel::EditStatus::KEY_GENERATION_FAILURE:
|
|
QMessageBox::critical(this, windowTitle(),
|
|
tr("Could not generate new %1 address").arg(QString::fromStdString(FormatOutputType(address_type))),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
// These aren't valid return values for our action
|
|
case AddressTableModel::EditStatus::INVALID_ADDRESS:
|
|
case AddressTableModel::EditStatus::DUPLICATE_ADDRESS:
|
|
case AddressTableModel::EditStatus::NO_CHANGES:
|
|
assert(false);
|
|
}
|
|
clear();
|
|
}
|
|
|
|
void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index)
|
|
{
|
|
const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel();
|
|
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
|
|
dialog->setModel(model);
|
|
dialog->setInfo(submodel->entry(index.row()).recipient);
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
dialog->show();
|
|
}
|
|
|
|
void ReceiveCoinsDialog::recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
|
|
{
|
|
// Enable Show/Remove buttons only if anything is selected.
|
|
bool enable = !ui->recentRequestsView->selectionModel()->selectedRows().isEmpty();
|
|
ui->showRequestButton->setEnabled(enable);
|
|
ui->removeRequestButton->setEnabled(enable);
|
|
}
|
|
|
|
void ReceiveCoinsDialog::on_showRequestButton_clicked()
|
|
{
|
|
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
|
|
|
|
for (const QModelIndex& index : selection) {
|
|
on_recentRequestsView_doubleClicked(index);
|
|
}
|
|
}
|
|
|
|
void ReceiveCoinsDialog::on_removeRequestButton_clicked()
|
|
{
|
|
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
|
|
if(selection.empty())
|
|
return;
|
|
// correct for selection mode ContiguousSelection
|
|
QModelIndex firstIndex = selection.at(0);
|
|
model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent());
|
|
}
|
|
|
|
QModelIndex ReceiveCoinsDialog::selectedRow()
|
|
{
|
|
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
|
|
return QModelIndex();
|
|
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
|
|
if(selection.empty())
|
|
return QModelIndex();
|
|
// correct for selection mode ContiguousSelection
|
|
QModelIndex firstIndex = selection.at(0);
|
|
return firstIndex;
|
|
}
|
|
|
|
// copy column of selected row to clipboard
|
|
void ReceiveCoinsDialog::copyColumnToClipboard(int column)
|
|
{
|
|
QModelIndex firstIndex = selectedRow();
|
|
if (!firstIndex.isValid()) {
|
|
return;
|
|
}
|
|
GUIUtil::setClipboard(model->getRecentRequestsTableModel()->index(firstIndex.row(), column).data(Qt::EditRole).toString());
|
|
}
|
|
|
|
// context menu
|
|
void ReceiveCoinsDialog::showMenu(const QPoint &point)
|
|
{
|
|
const QModelIndex sel = selectedRow();
|
|
if (!sel.isValid()) {
|
|
return;
|
|
}
|
|
|
|
// disable context menu actions when appropriate
|
|
const RecentRequestsTableModel* const submodel = model->getRecentRequestsTableModel();
|
|
const RecentRequestEntry& req = submodel->entry(sel.row());
|
|
copyLabelAction->setDisabled(req.recipient.label.isEmpty());
|
|
copyMessageAction->setDisabled(req.recipient.message.isEmpty());
|
|
copyAmountAction->setDisabled(req.recipient.amount == 0);
|
|
|
|
contextMenu->exec(QCursor::pos());
|
|
}
|
|
|
|
// context menu action: copy URI
|
|
void ReceiveCoinsDialog::copyURI()
|
|
{
|
|
QModelIndex sel = selectedRow();
|
|
if (!sel.isValid()) {
|
|
return;
|
|
}
|
|
|
|
const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
|
|
const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
|
|
GUIUtil::setClipboard(uri);
|
|
}
|
|
|
|
// context menu action: copy address
|
|
void ReceiveCoinsDialog::copyAddress()
|
|
{
|
|
const QModelIndex sel = selectedRow();
|
|
if (!sel.isValid()) {
|
|
return;
|
|
}
|
|
|
|
const RecentRequestsTableModel* const submodel = model->getRecentRequestsTableModel();
|
|
const QString address = submodel->entry(sel.row()).recipient.address;
|
|
GUIUtil::setClipboard(address);
|
|
}
|
|
|
|
// context menu action: copy label
|
|
void ReceiveCoinsDialog::copyLabel()
|
|
{
|
|
copyColumnToClipboard(RecentRequestsTableModel::Label);
|
|
}
|
|
|
|
// context menu action: copy message
|
|
void ReceiveCoinsDialog::copyMessage()
|
|
{
|
|
copyColumnToClipboard(RecentRequestsTableModel::Message);
|
|
}
|
|
|
|
// context menu action: copy amount
|
|
void ReceiveCoinsDialog::copyAmount()
|
|
{
|
|
copyColumnToClipboard(RecentRequestsTableModel::Amount);
|
|
}
|