2011-05-12 05:49:42 -07:00
# include "sendcoinsdialog.h"
2011-05-12 05:44:52 -07:00
# include "ui_sendcoinsdialog.h"
2013-01-23 12:51:02 -08:00
2011-06-30 09:05:29 -07:00
# include "walletmodel.h"
2011-07-25 12:35:45 -07:00
# include "bitcoinunits.h"
2011-07-07 08:33:15 -07:00
# include "addressbookpage.h"
2011-06-01 00:34:12 -07:00
# include "optionsmodel.h"
2011-07-16 10:01:05 -07:00
# include "sendcoinsentry.h"
2011-08-07 07:04:48 -07:00
# include "guiutil.h"
2011-08-24 13:07:26 -07:00
# include "askpassphrasedialog.h"
2012-08-07 10:19:14 -07:00
# include "base58.h"
2011-05-12 08:55:24 -07:00
2011-05-15 10:31:20 -07:00
# include <QMessageBox>
2011-07-31 03:56:46 -07:00
# include <QTextDocument>
2011-12-06 21:00:04 -08:00
# include <QScrollBar>
2011-05-12 11:16:42 -07:00
2011-07-16 10:01:05 -07:00
SendCoinsDialog : : SendCoinsDialog ( QWidget * parent ) :
2011-05-12 05:44:52 -07:00
QDialog ( parent ) ,
2011-05-30 11:20:12 -07:00
ui ( new Ui : : SendCoinsDialog ) ,
model ( 0 )
2011-05-12 05:44:52 -07:00
{
ui - > setupUi ( this ) ;
2011-07-08 10:25:35 -07:00
2012-09-21 10:06:53 -07:00
# ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
2011-10-07 04:21:45 -07:00
ui - > addButton - > setIcon ( QIcon ( ) ) ;
ui - > clearButton - > setIcon ( QIcon ( ) ) ;
ui - > sendButton - > setIcon ( QIcon ( ) ) ;
# endif
2011-07-16 10:01:05 -07:00
addEntry ( ) ;
2011-05-15 10:31:20 -07:00
2011-07-16 10:01:05 -07:00
connect ( ui - > addButton , SIGNAL ( clicked ( ) ) , this , SLOT ( addEntry ( ) ) ) ;
2011-09-27 07:46:19 -07:00
connect ( ui - > clearButton , SIGNAL ( clicked ( ) ) , this , SLOT ( clear ( ) ) ) ;
2011-12-23 20:27:12 -08:00
fNewRecipientAllowed = true ;
2011-05-12 05:44:52 -07:00
}
2011-06-30 09:05:29 -07:00
void SendCoinsDialog : : setModel ( WalletModel * model )
2011-05-30 11:20:12 -07:00
{
this - > model = model ;
2011-07-16 10:01:05 -07:00
2013-08-23 04:07:20 -07:00
if ( model & & model - > getOptionsModel ( ) )
2011-07-16 10:01:05 -07:00
{
2013-08-23 04:07:20 -07:00
for ( int i = 0 ; i < ui - > entries - > count ( ) ; + + i )
2011-07-16 10:01:05 -07:00
{
2013-08-23 04:07:20 -07:00
SendCoinsEntry * entry = qobject_cast < SendCoinsEntry * > ( ui - > entries - > itemAt ( i ) - > widget ( ) ) ;
if ( entry )
{
entry - > setModel ( model ) ;
}
2011-07-16 10:01:05 -07:00
}
2013-08-23 04:07:20 -07:00
2012-02-14 03:08:00 -08:00
setBalance ( model - > getBalance ( ) , model - > getUnconfirmedBalance ( ) , model - > getImmatureBalance ( ) ) ;
connect ( model , SIGNAL ( balanceChanged ( qint64 , qint64 , qint64 ) ) , this , SLOT ( setBalance ( qint64 , qint64 , qint64 ) ) ) ;
2012-06-09 06:41:21 -07:00
connect ( model - > getOptionsModel ( ) , SIGNAL ( displayUnitChanged ( int ) ) , this , SLOT ( updateDisplayUnit ( ) ) ) ;
2011-11-08 12:18:36 -08:00
}
2011-05-30 11:20:12 -07:00
}
2011-05-12 05:44:52 -07:00
SendCoinsDialog : : ~ SendCoinsDialog ( )
{
delete ui ;
}
2011-05-12 08:55:24 -07:00
void SendCoinsDialog : : on_sendButton_clicked ( )
{
2013-08-24 06:07:17 -07:00
if ( ! model | | ! model - > getOptionsModel ( ) )
return ;
2011-07-16 10:01:05 -07:00
QList < SendCoinsRecipient > recipients ;
bool valid = true ;
2011-11-08 12:18:36 -08:00
2011-07-16 10:01:05 -07:00
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 ;
}
}
}
2011-05-30 11:20:12 -07:00
2011-07-16 10:01:05 -07:00
if ( ! valid | | recipients . isEmpty ( ) )
2011-05-14 08:25:05 -07:00
{
2011-05-15 10:31:20 -07:00
return ;
2011-05-14 08:25:05 -07:00
}
2011-05-27 12:43:05 -07:00
2011-07-16 10:01:05 -07:00
// Format confirmation message
QStringList formatted ;
foreach ( const SendCoinsRecipient & rcp , recipients )
{
2013-08-24 06:07:17 -07:00
QString amount = BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , rcp . amount ) ;
2013-07-21 23:50:39 -07:00
if ( rcp . authenticatedMerchant . isEmpty ( ) )
{
2013-08-30 11:04:48 -07:00
QString recipientElement = QString ( " <b>%1</b> " ) . arg ( BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , rcp . amount ) ) ;
recipientElement . append ( tr ( " to " ) ) ;
if ( rcp . label . length ( ) > 0 )
{
recipientElement . append ( QString ( " %1 <span style='font-size:8px;'>%2</span><br /> " ) . arg ( GUIUtil : : HtmlEscape ( rcp . label ) , rcp . address ) ) ; // add address with label
}
else
{
recipientElement . append ( QString ( " %1<br /> " ) . arg ( rcp . address ) ) ; // add address WITHOUT label
}
formatted . append ( recipientElement ) ;
2013-07-21 23:50:39 -07:00
}
else
{
2013-08-30 05:32:00 -07:00
QString merchant = GUIUtil : : HtmlEscape ( rcp . authenticatedMerchant ) ;
2013-07-21 23:50:39 -07:00
formatted . append ( tr ( " <b>%1</b> to %2 " ) . arg ( amount , merchant ) ) ;
}
2011-07-16 10:01:05 -07:00
}
2011-06-25 10:32:36 -07:00
2011-12-23 20:27:12 -08:00
fNewRecipientAllowed = false ;
2011-07-07 08:33:15 -07:00
2011-08-24 13:07:26 -07:00
WalletModel : : UnlockContext ctx ( model - > requestUnlock ( ) ) ;
if ( ! ctx . isValid ( ) )
{
// Unlock wallet was cancelled
2011-12-23 20:27:12 -08:00
fNewRecipientAllowed = true ;
2011-08-24 13:07:26 -07:00
return ;
}
2013-08-30 11:04:48 -07:00
// prepare transaction for getting txFee earlier
WalletModelTransaction currentTransaction ( recipients ) ;
WalletModel : : SendCoinsReturn prepareStatus = model - > prepareTransaction ( currentTransaction ) ;
switch ( prepareStatus . status )
2011-05-14 08:25:05 -07:00
{
2011-06-30 09:05:29 -07:00
case WalletModel : : InvalidAddress :
2011-05-30 11:20:12 -07:00
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-07-25 19:07:43 -07:00
tr ( " The recipient address is not valid, please recheck. " ) ,
2011-05-30 11:20:12 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
2011-06-30 09:05:29 -07:00
case WalletModel : : InvalidAmount :
2011-05-30 11:20:12 -07:00
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
tr ( " The amount to pay must be larger than 0. " ) ,
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
2011-06-30 09:05:29 -07:00
case WalletModel : : AmountExceedsBalance :
2011-05-30 11:20:12 -07:00
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-05-13 06:41:00 -07:00
tr ( " The amount exceeds your balance. " ) ,
2011-05-30 11:20:12 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
2011-06-30 09:05:29 -07:00
case WalletModel : : AmountWithFeeExceedsBalance :
2011-05-30 11:20:12 -07:00
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-05-13 06:41:00 -07:00
tr ( " The total exceeds your balance when the %1 transaction fee is included. " ) .
2013-08-30 11:04:48 -07:00
arg ( BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , currentTransaction . getTransactionFee ( ) ) ) ,
2011-07-16 10:01:05 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
case WalletModel : : DuplicateAddress :
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-05-13 06:41:00 -07:00
tr ( " Duplicate address found, can only send to each address once per send operation. " ) ,
2011-07-16 10:01:05 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
case WalletModel : : TransactionCreationFailed :
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-09-18 09:26:02 -07:00
tr ( " Error: Transaction creation failed! " ) ,
2011-07-16 10:01:05 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
2013-08-30 11:04:48 -07:00
case WalletModel : : Aborted : // User aborted, nothing to do
case WalletModel : : OK :
case WalletModel : : TransactionCommitFailed :
break ;
}
if ( prepareStatus . status ! = WalletModel : : OK ) {
fNewRecipientAllowed = true ;
return ;
}
qint64 txFee = currentTransaction . getTransactionFee ( ) ;
QString questionString = tr ( " Are you sure you want to send? " ) ;
questionString . append ( " <br /><br />%1 " ) ;
if ( txFee > 0 )
{
// append fee string if a fee is required
questionString . append ( " <hr /><span style='color:#aa0000;'> " ) ;
questionString . append ( BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , txFee ) ) ;
questionString . append ( " </span> " ) ;
questionString . append ( tr ( " added as transaction fee " ) ) ;
}
if ( txFee > 0 | | recipients . count ( ) > 1 )
{
// add total amount string if there are more then one recipients or a fee is required
questionString . append ( " <hr /> " ) ;
questionString . append ( tr ( " Total Amount %1 " ) . arg ( BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , currentTransaction . getTotalTransactionAmount ( ) + txFee ) ) ) ;
}
QMessageBox : : StandardButton retval = QMessageBox : : question ( this , tr ( " Confirm send coins " ) ,
questionString . arg ( formatted . join ( " <br /> " ) ) ,
QMessageBox : : Yes | QMessageBox : : Cancel ,
QMessageBox : : Cancel ) ;
if ( retval ! = QMessageBox : : Yes )
{
fNewRecipientAllowed = true ;
return ;
}
// now send the prepared transaction
WalletModel : : SendCoinsReturn sendstatus = model - > sendCoins ( currentTransaction ) ;
switch ( sendstatus . status )
{
2011-07-16 10:01:05 -07:00
case WalletModel : : TransactionCommitFailed :
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
2012-05-13 06:41:00 -07:00
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. " ) ,
2011-05-30 11:20:12 -07:00
QMessageBox : : Ok , QMessageBox : : Ok ) ;
break ;
2012-04-15 03:42:52 -07:00
case WalletModel : : Aborted : // User aborted, nothing to do
break ;
2011-06-30 09:05:29 -07:00
case WalletModel : : OK :
2011-05-31 13:24:53 -07:00
accept ( ) ;
break ;
2013-08-30 11:04:48 -07:00
default :
break ;
2011-05-14 08:25:05 -07:00
}
2011-12-23 20:27:12 -08:00
fNewRecipientAllowed = true ;
2011-05-12 08:55:24 -07:00
}
2011-07-16 10:01:05 -07:00
void SendCoinsDialog : : clear ( )
2011-05-12 08:55:24 -07:00
{
2011-07-16 10:01:05 -07:00
// Remove entries until only one left
2011-08-07 07:04:48 -07:00
while ( ui - > entries - > count ( ) )
2011-07-16 10:01:05 -07:00
{
delete ui - > entries - > takeAt ( 0 ) - > widget ( ) ;
}
2011-08-07 07:04:48 -07:00
addEntry ( ) ;
2011-05-13 13:00:27 -07:00
2011-07-16 10:01:05 -07:00
updateRemoveEnabled ( ) ;
2011-07-07 08:33:15 -07:00
2011-07-08 10:51:24 -07:00
ui - > sendButton - > setDefault ( true ) ;
2011-07-07 08:33:15 -07:00
}
void SendCoinsDialog : : reject ( )
{
clear ( ) ;
}
void SendCoinsDialog : : accept ( )
{
clear ( ) ;
}
2011-07-16 10:01:05 -07:00
2011-08-07 07:04:48 -07:00
SendCoinsEntry * SendCoinsDialog : : addEntry ( )
2011-07-16 10:01:05 -07:00
{
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 ( ) ;
2011-12-06 21:00:04 -08:00
entry - > setFocus ( ) ;
ui - > scrollAreaWidgetContents - > resize ( ui - > scrollAreaWidgetContents - > sizeHint ( ) ) ;
2013-04-02 08:30:14 -07:00
qApp - > processEvents ( ) ;
2011-12-06 21:00:04 -08:00
QScrollBar * bar = ui - > scrollArea - > verticalScrollBar ( ) ;
2012-06-09 06:41:21 -07:00
if ( bar )
2011-12-06 21:00:04 -08:00
bar - > setSliderPosition ( bar - > maximum ( ) ) ;
2011-08-07 07:04:48 -07:00
return entry ;
2011-07-16 10:01:05 -07:00
}
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 ;
}
2011-08-07 07:04:48 -07:00
2013-01-25 09:46:53 -08:00
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 ) ;
}
2011-08-07 07:04:48 -07:00
void SendCoinsDialog : : pasteEntry ( const SendCoinsRecipient & rv )
{
2012-06-09 06:41:21 -07:00
if ( ! fNewRecipientAllowed )
2011-12-23 20:27:12 -08:00
return ;
2011-08-07 07:04:48 -07:00
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 ) ;
}
2013-07-21 23:50:39 -07:00
bool SendCoinsDialog : : handlePaymentRequest ( const SendCoinsRecipient & rv )
2011-08-07 07:04:48 -07:00
{
2013-07-21 23:50:39 -07:00
if ( ! rv . authenticatedMerchant . isEmpty ( ) ) {
// Expired payment request?
const payments : : PaymentDetails & details = rv . paymentRequest . getDetails ( ) ;
if ( details . has_expires ( ) & & ( int64 ) details . expires ( ) < GetTime ( ) )
{
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
tr ( " Payment request expired " ) ) ;
return false ;
}
}
else {
2012-08-07 10:19:14 -07:00
CBitcoinAddress address ( rv . address . toStdString ( ) ) ;
2013-07-21 23:50:39 -07:00
if ( ! address . IsValid ( ) ) {
QString strAddress ( address . ToString ( ) . c_str ( ) ) ;
QMessageBox : : warning ( this , tr ( " Send Coins " ) ,
tr ( " Invalid payment address %1 " ) . arg ( strAddress ) ) ;
2012-08-07 10:19:14 -07:00
return false ;
2013-07-21 23:50:39 -07:00
}
2011-08-07 07:04:48 -07:00
}
2012-03-28 05:55:29 -07:00
2013-07-21 23:50:39 -07:00
pasteEntry ( rv ) ;
return true ;
2011-08-07 07:04:48 -07:00
}
2011-09-22 10:02:01 -07:00
2012-02-14 03:08:00 -08:00
void SendCoinsDialog : : setBalance ( qint64 balance , qint64 unconfirmedBalance , qint64 immatureBalance )
2011-09-22 10:02:01 -07:00
{
Q_UNUSED ( unconfirmedBalance ) ;
2012-02-14 03:08:00 -08:00
Q_UNUSED ( immatureBalance ) ;
2011-11-08 12:18:36 -08:00
2013-08-24 06:07:17 -07:00
if ( model & & model - > getOptionsModel ( ) )
{
ui - > labelBalance - > setText ( BitcoinUnits : : formatWithUnit ( model - > getOptionsModel ( ) - > getDisplayUnit ( ) , balance ) ) ;
}
2011-09-22 10:02:01 -07:00
}
2012-06-09 06:41:21 -07:00
void SendCoinsDialog : : updateDisplayUnit ( )
{
2013-08-24 06:07:17 -07:00
setBalance ( model - > getBalance ( ) , 0 , 0 ) ;
2012-06-09 06:41:21 -07:00
}