311993ab10
- allows to directly select an address from the addressbook, chose "send coins" from the context menu, which sends you to sendcoins tab and fills in the selected address
326 lines
9.0 KiB
C++
326 lines
9.0 KiB
C++
#include "sendcoinsdialog.h"
|
|
#include "ui_sendcoinsdialog.h"
|
|
|
|
#include "walletmodel.h"
|
|
#include "bitcoinunits.h"
|
|
#include "addressbookpage.h"
|
|
#include "optionsmodel.h"
|
|
#include "sendcoinsentry.h"
|
|
#include "guiutil.h"
|
|
#include "askpassphrasedialog.h"
|
|
#include "base58.h"
|
|
|
|
#include <QMessageBox>
|
|
#include <QTextDocument>
|
|
#include <QScrollBar>
|
|
|
|
SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
|
|
QDialog(parent),
|
|
ui(new Ui::SendCoinsDialog),
|
|
model(0)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
|
|
ui->addButton->setIcon(QIcon());
|
|
ui->clearButton->setIcon(QIcon());
|
|
ui->sendButton->setIcon(QIcon());
|
|
#endif
|
|
|
|
addEntry();
|
|
|
|
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
|
|
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
|
|
|
fNewRecipientAllowed = true;
|
|
}
|
|
|
|
void SendCoinsDialog::setModel(WalletModel *model)
|
|
{
|
|
this->model = model;
|
|
|
|
for(int i = 0; i < ui->entries->count(); ++i)
|
|
{
|
|
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
|
if(entry)
|
|
{
|
|
entry->setModel(model);
|
|
}
|
|
}
|
|
if(model && model->getOptionsModel())
|
|
{
|
|
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
|
|
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
|
|
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
|
}
|
|
}
|
|
|
|
SendCoinsDialog::~SendCoinsDialog()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void SendCoinsDialog::on_sendButton_clicked()
|
|
{
|
|
QList<SendCoinsRecipient> recipients;
|
|
bool valid = true;
|
|
|
|
if(!model)
|
|
return;
|
|
|
|
for(int i = 0; i < ui->entries->count(); ++i)
|
|
{
|
|
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
|
if(entry)
|
|
{
|
|
if(entry->validate())
|
|
{
|
|
recipients.append(entry->getValue());
|
|
}
|
|
else
|
|
{
|
|
valid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!valid || recipients.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Format confirmation message
|
|
QStringList formatted;
|
|
foreach(const SendCoinsRecipient &rcp, recipients)
|
|
{
|
|
formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
|
|
}
|
|
|
|
fNewRecipientAllowed = false;
|
|
|
|
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
|
|
tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
|
|
QMessageBox::Yes|QMessageBox::Cancel,
|
|
QMessageBox::Cancel);
|
|
|
|
if(retval != QMessageBox::Yes)
|
|
{
|
|
fNewRecipientAllowed = true;
|
|
return;
|
|
}
|
|
|
|
WalletModel::UnlockContext ctx(model->requestUnlock());
|
|
if(!ctx.isValid())
|
|
{
|
|
// Unlock wallet was cancelled
|
|
fNewRecipientAllowed = true;
|
|
return;
|
|
}
|
|
|
|
WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
|
|
switch(sendstatus.status)
|
|
{
|
|
case WalletModel::InvalidAddress:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("The recipient address is not valid, please recheck."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::InvalidAmount:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("The amount to pay must be larger than 0."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::AmountExceedsBalance:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("The amount exceeds your balance."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::AmountWithFeeExceedsBalance:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("The total exceeds your balance when the %1 transaction fee is included.").
|
|
arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::DuplicateAddress:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("Duplicate address found, can only send to each address once per send operation."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::TransactionCreationFailed:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("Error: Transaction creation failed!"),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::TransactionCommitFailed:
|
|
QMessageBox::warning(this, tr("Send Coins"),
|
|
tr("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
break;
|
|
case WalletModel::Aborted: // User aborted, nothing to do
|
|
break;
|
|
case WalletModel::OK:
|
|
accept();
|
|
break;
|
|
}
|
|
fNewRecipientAllowed = true;
|
|
}
|
|
|
|
void SendCoinsDialog::clear()
|
|
{
|
|
// Remove entries until only one left
|
|
while(ui->entries->count())
|
|
{
|
|
delete ui->entries->takeAt(0)->widget();
|
|
}
|
|
addEntry();
|
|
|
|
updateRemoveEnabled();
|
|
|
|
ui->sendButton->setDefault(true);
|
|
}
|
|
|
|
void SendCoinsDialog::reject()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void SendCoinsDialog::accept()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
SendCoinsEntry *SendCoinsDialog::addEntry()
|
|
{
|
|
SendCoinsEntry *entry = new SendCoinsEntry(this);
|
|
entry->setModel(model);
|
|
ui->entries->addWidget(entry);
|
|
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
|
|
|
|
updateRemoveEnabled();
|
|
|
|
// Focus the field, so that entry can start immediately
|
|
entry->clear();
|
|
entry->setFocus();
|
|
ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
|
|
QCoreApplication::instance()->processEvents();
|
|
QScrollBar* bar = ui->scrollArea->verticalScrollBar();
|
|
if(bar)
|
|
bar->setSliderPosition(bar->maximum());
|
|
return entry;
|
|
}
|
|
|
|
void SendCoinsDialog::updateRemoveEnabled()
|
|
{
|
|
// Remove buttons are enabled as soon as there is more than one send-entry
|
|
bool enabled = (ui->entries->count() > 1);
|
|
for(int i = 0; i < ui->entries->count(); ++i)
|
|
{
|
|
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
|
if(entry)
|
|
{
|
|
entry->setRemoveEnabled(enabled);
|
|
}
|
|
}
|
|
setupTabChain(0);
|
|
}
|
|
|
|
void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
|
|
{
|
|
delete entry;
|
|
updateRemoveEnabled();
|
|
}
|
|
|
|
QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
|
|
{
|
|
for(int i = 0; i < ui->entries->count(); ++i)
|
|
{
|
|
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
|
|
if(entry)
|
|
{
|
|
prev = entry->setupTabChain(prev);
|
|
}
|
|
}
|
|
QWidget::setTabOrder(prev, ui->addButton);
|
|
QWidget::setTabOrder(ui->addButton, ui->sendButton);
|
|
return ui->sendButton;
|
|
}
|
|
|
|
void SendCoinsDialog::setAddress(const QString &address)
|
|
{
|
|
SendCoinsEntry *entry = 0;
|
|
// Replace the first entry if it is still unused
|
|
if(ui->entries->count() == 1)
|
|
{
|
|
SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
|
|
if(first->isClear())
|
|
{
|
|
entry = first;
|
|
}
|
|
}
|
|
if(!entry)
|
|
{
|
|
entry = addEntry();
|
|
}
|
|
|
|
entry->setAddress(address);
|
|
}
|
|
|
|
void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
|
|
{
|
|
if(!fNewRecipientAllowed)
|
|
return;
|
|
|
|
SendCoinsEntry *entry = 0;
|
|
// Replace the first entry if it is still unused
|
|
if(ui->entries->count() == 1)
|
|
{
|
|
SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
|
|
if(first->isClear())
|
|
{
|
|
entry = first;
|
|
}
|
|
}
|
|
if(!entry)
|
|
{
|
|
entry = addEntry();
|
|
}
|
|
|
|
entry->setValue(rv);
|
|
}
|
|
|
|
bool SendCoinsDialog::handleURI(const QString &uri)
|
|
{
|
|
SendCoinsRecipient rv;
|
|
// URI has to be valid
|
|
if (GUIUtil::parseBitcoinURI(uri, &rv))
|
|
{
|
|
CBitcoinAddress address(rv.address.toStdString());
|
|
if (!address.IsValid())
|
|
return false;
|
|
pasteEntry(rv);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
|
|
{
|
|
Q_UNUSED(unconfirmedBalance);
|
|
Q_UNUSED(immatureBalance);
|
|
if(!model || !model->getOptionsModel())
|
|
return;
|
|
|
|
int unit = model->getOptionsModel()->getDisplayUnit();
|
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
|
|
}
|
|
|
|
void SendCoinsDialog::updateDisplayUnit()
|
|
{
|
|
if(model && model->getOptionsModel())
|
|
{
|
|
// Update labelBalance with the current balance and the current unit
|
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance()));
|
|
}
|
|
}
|