]> Git Repo - VerusCoin.git/blame - src/qt/walletmodel.cpp
Convert UI interface to boost::signals2.
[VerusCoin.git] / src / qt / walletmodel.cpp
CommitLineData
ef079e18
WL
1#include "walletmodel.h"
2#include "guiconstants.h"
3#include "optionsmodel.h"
4#include "addresstablemodel.h"
5#include "transactiontablemodel.h"
6
6b6aaa16 7#include "ui_interface.h"
ed6d0b5f 8#include "wallet.h"
9eace6b1 9#include "walletdb.h" // for BackupWallet
ef079e18 10
a5e6d723 11#include <QSet>
ef079e18 12
ee014e5b
WL
13WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
14 QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
5df0b03c 15 transactionTableModel(0),
ae8adeb9
WL
16 cachedBalance(0), cachedUnconfirmedBalance(0), cachedNumTransactions(0),
17 cachedEncryptionStatus(Unencrypted)
ef079e18 18{
ef079e18
WL
19 addressTableModel = new AddressTableModel(wallet, this);
20 transactionTableModel = new TransactionTableModel(wallet, this);
ab1b288f
WL
21
22 subscribeToCoreSignals();
23}
24
25WalletModel::~WalletModel()
26{
27 unsubscribeFromCoreSignals();
ef079e18
WL
28}
29
30qint64 WalletModel::getBalance() const
31{
32 return wallet->GetBalance();
33}
34
df5ccbd2
WL
35qint64 WalletModel::getUnconfirmedBalance() const
36{
37 return wallet->GetUnconfirmedBalance();
38}
39
ef079e18
WL
40int WalletModel::getNumTransactions() const
41{
42 int numTransactions = 0;
ef079e18 43 {
f8dcd5ca 44 LOCK(wallet->cs_wallet);
ef079e18
WL
45 numTransactions = wallet->mapWallet.size();
46 }
47 return numTransactions;
48}
49
fe4a6550 50void WalletModel::updateStatus()
ef079e18 51{
fe4a6550
WL
52 EncryptionStatus newEncryptionStatus = getEncryptionStatus();
53
54 if(cachedEncryptionStatus != newEncryptionStatus)
55 emit encryptionStatusChanged(newEncryptionStatus);
56}
57
58void WalletModel::updateTransaction(const QString &hash, int status)
59{
60 if(transactionTableModel)
61 transactionTableModel->updateTransaction(hash, status);
62
63 // Balance and number of transactions might have changed
5df0b03c
WL
64 qint64 newBalance = getBalance();
65 qint64 newUnconfirmedBalance = getUnconfirmedBalance();
66 int newNumTransactions = getNumTransactions();
67
68 if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance)
69 emit balanceChanged(newBalance, newUnconfirmedBalance);
5df0b03c
WL
70 if(cachedNumTransactions != newNumTransactions)
71 emit numTransactionsChanged(newNumTransactions);
72
73 cachedBalance = newBalance;
74 cachedUnconfirmedBalance = newUnconfirmedBalance;
75 cachedNumTransactions = newNumTransactions;
ef079e18
WL
76}
77
fe4a6550 78void WalletModel::updateAddressBook(const QString &address, const QString &label, int status)
98e61758 79{
fe4a6550
WL
80 if(addressTableModel)
81 addressTableModel->updateEntry(address, label, status);
98e61758
WL
82}
83
a5e6d723 84bool WalletModel::validateAddress(const QString &address)
ef079e18 85{
491ad6db
WL
86 CBitcoinAddress addressParsed(address.toStdString());
87 return addressParsed.IsValid();
a5e6d723
WL
88}
89
90WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipient> &recipients)
91{
92 qint64 total = 0;
93 QSet<QString> setAddress;
94 QString hex;
95
96 if(recipients.empty())
ef079e18 97 {
a5e6d723 98 return OK;
ef079e18
WL
99 }
100
a5e6d723
WL
101 // Pre-check input data for validity
102 foreach(const SendCoinsRecipient &rcp, recipients)
ef079e18 103 {
491ad6db 104 if(!validateAddress(rcp.address))
a5e6d723
WL
105 {
106 return InvalidAddress;
107 }
108 setAddress.insert(rcp.address);
109
110 if(rcp.amount <= 0)
111 {
112 return InvalidAmount;
113 }
114 total += rcp.amount;
ef079e18
WL
115 }
116
a5e6d723
WL
117 if(recipients.size() > setAddress.size())
118 {
119 return DuplicateAddress;
120 }
121
122 if(total > getBalance())
ef079e18
WL
123 {
124 return AmountExceedsBalance;
125 }
126
a5e6d723 127 if((total + nTransactionFee) > getBalance())
ef079e18 128 {
a5e6d723 129 return SendCoinsReturn(AmountWithFeeExceedsBalance, nTransactionFee);
ef079e18
WL
130 }
131
ef079e18 132 {
f8dcd5ca
PW
133 LOCK2(cs_main, wallet->cs_wallet);
134
a5e6d723 135 // Sendmany
bde280b9 136 std::vector<std::pair<CScript, int64> > vecSend;
a5e6d723
WL
137 foreach(const SendCoinsRecipient &rcp, recipients)
138 {
139 CScript scriptPubKey;
140 scriptPubKey.SetBitcoinAddress(rcp.address.toStdString());
141 vecSend.push_back(make_pair(scriptPubKey, rcp.amount));
142 }
143
ef079e18 144 CWalletTx wtx;
a5e6d723 145 CReserveKey keyChange(wallet);
bde280b9 146 int64 nFeeRequired = 0;
a5e6d723 147 bool fCreated = wallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
ef079e18 148
a5e6d723 149 if(!fCreated)
ef079e18 150 {
a5e6d723
WL
151 if((total + nFeeRequired) > wallet->GetBalance())
152 {
153 return SendCoinsReturn(AmountWithFeeExceedsBalance, nFeeRequired);
154 }
155 return TransactionCreationFailed;
ef079e18 156 }
ab1b288f 157 if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
ef079e18
WL
158 {
159 return Aborted;
160 }
a5e6d723 161 if(!wallet->CommitTransaction(wtx, keyChange))
ef079e18 162 {
a5e6d723 163 return TransactionCommitFailed;
ef079e18 164 }
a5e6d723 165 hex = QString::fromStdString(wtx.GetHash().GetHex());
ef079e18
WL
166 }
167
dab7acdf 168 // Add addresses / update labels that we've sent to to the address book
a5e6d723 169 foreach(const SendCoinsRecipient &rcp, recipients)
ef079e18 170 {
a5e6d723 171 std::string strAddress = rcp.address.toStdString();
dab7acdf 172 std::string strLabel = rcp.label.toStdString();
a5e6d723 173 {
f8dcd5ca 174 LOCK(wallet->cs_wallet);
dab7acdf
PK
175
176 std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(strAddress);
177
178 // Check if we have a new address or an updated label
179 if (mi == wallet->mapAddressBook.end() || mi->second != strLabel)
180 {
181 wallet->SetAddressBookName(strAddress, strLabel);
182 }
a5e6d723 183 }
ef079e18 184 }
a5e13258 185
a5e6d723 186 return SendCoinsReturn(OK, 0, hex);
ef079e18
WL
187}
188
189OptionsModel *WalletModel::getOptionsModel()
190{
191 return optionsModel;
192}
193
194AddressTableModel *WalletModel::getAddressTableModel()
195{
196 return addressTableModel;
197}
198
199TransactionTableModel *WalletModel::getTransactionTableModel()
200{
201 return transactionTableModel;
202}
ebff5c40 203
ae8adeb9
WL
204WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
205{
206 if(!wallet->IsCrypted())
207 {
208 return Unencrypted;
209 }
210 else if(wallet->IsLocked())
211 {
212 return Locked;
213 }
214 else
215 {
216 return Unlocked;
217 }
218}
b7bcaf94 219
94f778bd 220bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase)
b7bcaf94
WL
221{
222 if(encrypted)
223 {
224 // Encrypt
225 return wallet->EncryptWallet(passphrase);
226 }
227 else
228 {
229 // Decrypt -- TODO; not supported yet
230 return false;
231 }
232}
233
94f778bd 234bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase)
b7bcaf94
WL
235{
236 if(locked)
237 {
238 // Lock
239 return wallet->Lock();
240 }
241 else
242 {
243 // Unlock
244 return wallet->Unlock(passPhrase);
245 }
246}
247
94f778bd 248bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureString &newPass)
b7bcaf94
WL
249{
250 bool retval;
b7bcaf94 251 {
f8dcd5ca 252 LOCK(wallet->cs_wallet);
b7bcaf94
WL
253 wallet->Lock(); // Make sure wallet is locked before attempting pass change
254 retval = wallet->ChangeWalletPassphrase(oldPass, newPass);
255 }
256 return retval;
257}
258
4efbda3f 259bool WalletModel::backupWallet(const QString &filename)
260{
261 return BackupWallet(*wallet, filename.toLocal8Bit().data());
262}
263
ab1b288f
WL
264// Handlers for core signals
265static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStore *wallet)
266{
267 OutputDebugStringF("NotifyKeyStoreStatusChanged\n");
268 QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
269}
270
271static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const std::string &address, const std::string &label, ChangeType status)
272{
273 OutputDebugStringF("NotifyAddressBookChanged %s %s status=%i\n", address.c_str(), label.c_str(), status);
274 QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
275 Q_ARG(QString, QString::fromStdString(address)),
276 Q_ARG(QString, QString::fromStdString(label)),
277 Q_ARG(int, status));
278}
279
280static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status)
281{
282 OutputDebugStringF("NotifyTransactionChanged %s status=%i\n", hash.GetHex().c_str(), status);
283 QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection,
284 Q_ARG(QString, QString::fromStdString(hash.GetHex())),
285 Q_ARG(int, status));
286}
287
288void WalletModel::subscribeToCoreSignals()
289{
290 // Connect signals to wallet
291 wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
292 wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4));
293 wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
294}
295
296void WalletModel::unsubscribeFromCoreSignals()
297{
298 // Disconnect signals from wallet
299 wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1));
300 wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4));
301 wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
302}
303
b7bcaf94
WL
304// WalletModel::UnlockContext implementation
305WalletModel::UnlockContext WalletModel::requestUnlock()
306{
307 bool was_locked = getEncryptionStatus() == Locked;
308 if(was_locked)
309 {
310 // Request UI to unlock wallet
311 emit requireUnlock();
312 }
313 // If wallet is still locked, unlock was failed or cancelled, mark context as invalid
314 bool valid = getEncryptionStatus() != Locked;
315
316 return UnlockContext(this, valid, was_locked);
317}
318
319WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
320 wallet(wallet),
321 valid(valid),
322 relock(relock)
323{
324}
325
326WalletModel::UnlockContext::~UnlockContext()
327{
328 if(valid && relock)
329 {
330 wallet->setWalletLocked(true);
331 }
332}
333
334void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
335{
336 // Transfer context; old object no longer relocks wallet
337 *this = rhs;
338 rhs.relock = false;
339}
This page took 0.105057 seconds and 4 git commands to generate.