@@ -91,87 +91,80 @@ class TransactionTablePriv
91
91
92
92
Call with transaction that was added, removed or changed.
93
93
*/
94
- void updateWallet (const uint256 &hash, int status)
94
+ void updateWallet (const uint256 &hash, int status, bool showTransaction )
95
95
{
96
96
qDebug () << " TransactionTablePriv::updateWallet : " + QString::fromStdString (hash.ToString ()) + " " + QString::number (status);
97
- {
98
- LOCK2 (cs_main, wallet->cs_wallet );
99
97
100
- // Find transaction in wallet
101
- std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet .find (hash);
102
- bool inWallet = mi != wallet->mapWallet .end ();
98
+ // Find bounds of this transaction in model
99
+ QList<TransactionRecord>::iterator lower = qLowerBound (
100
+ cachedWallet.begin (), cachedWallet.end (), hash, TxLessThan ());
101
+ QList<TransactionRecord>::iterator upper = qUpperBound (
102
+ cachedWallet.begin (), cachedWallet.end (), hash, TxLessThan ());
103
+ int lowerIndex = (lower - cachedWallet.begin ());
104
+ int upperIndex = (upper - cachedWallet.begin ());
105
+ bool inModel = (lower != upper);
103
106
104
- // Find bounds of this transaction in model
105
- QList<TransactionRecord>::iterator lower = qLowerBound (
106
- cachedWallet.begin (), cachedWallet.end (), hash, TxLessThan ());
107
- QList<TransactionRecord>::iterator upper = qUpperBound (
108
- cachedWallet.begin (), cachedWallet.end (), hash, TxLessThan ());
109
- int lowerIndex = (lower - cachedWallet.begin ());
110
- int upperIndex = (upper - cachedWallet.begin ());
111
- bool inModel = (lower != upper);
107
+ if (status == CT_UPDATED)
108
+ {
109
+ if (showTransaction && !inModel)
110
+ status = CT_NEW; /* Not in model, but want to show, treat as new */
111
+ if (!showTransaction && inModel)
112
+ status = CT_DELETED; /* In model, but want to hide, treat as deleted */
113
+ }
112
114
113
- // Determine whether to show transaction or not
114
- bool showTransaction = (inWallet && TransactionRecord::showTransaction (mi->second ));
115
+ qDebug () << " inModel=" + QString::number (inModel) +
116
+ " Index=" + QString::number (lowerIndex) + " -" + QString::number (upperIndex) +
117
+ " showTransaction=" + QString::number (showTransaction) + " derivedStatus=" + QString::number (status);
115
118
116
- if (status == CT_UPDATED)
119
+ switch (status)
120
+ {
121
+ case CT_NEW:
122
+ if (inModel)
117
123
{
118
- if (showTransaction && !inModel)
119
- status = CT_NEW; /* Not in model, but want to show, treat as new */
120
- if (!showTransaction && inModel)
121
- status = CT_DELETED; /* In model, but want to hide, treat as deleted */
124
+ qWarning () << " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model" ;
125
+ break ;
122
126
}
123
-
124
- qDebug () << " inWallet=" + QString::number (inWallet) + " inModel=" + QString::number (inModel) +
125
- " Index=" + QString::number (lowerIndex) + " -" + QString::number (upperIndex) +
126
- " showTransaction=" + QString::number (showTransaction) + " derivedStatus=" + QString::number (status);
127
-
128
- switch (status)
127
+ if (showTransaction)
129
128
{
130
- case CT_NEW:
131
- if (inModel)
132
- {
133
- qWarning () << " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model" ;
134
- break ;
135
- }
136
- if (!inWallet)
129
+ LOCK2 (cs_main, wallet->cs_wallet );
130
+ // Find transaction in wallet
131
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet .find (hash);
132
+ if (mi == wallet->mapWallet .end ())
137
133
{
138
134
qWarning () << " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet" ;
139
135
break ;
140
136
}
141
- if (showTransaction)
137
+ // Added -- insert at the right position
138
+ QList<TransactionRecord> toInsert =
139
+ TransactionRecord::decomposeTransaction (wallet, mi->second );
140
+ if (!toInsert.isEmpty ()) /* only if something to insert */
142
141
{
143
- // Added -- insert at the right position
144
- QList<TransactionRecord> toInsert =
145
- TransactionRecord::decomposeTransaction (wallet, mi->second );
146
- if (!toInsert.isEmpty ()) /* only if something to insert */
142
+ parent->beginInsertRows (QModelIndex (), lowerIndex, lowerIndex+toInsert.size ()-1 );
143
+ int insert_idx = lowerIndex;
144
+ foreach (const TransactionRecord &rec, toInsert)
147
145
{
148
- parent->beginInsertRows (QModelIndex (), lowerIndex, lowerIndex+toInsert.size ()-1 );
149
- int insert_idx = lowerIndex;
150
- foreach (const TransactionRecord &rec, toInsert)
151
- {
152
- cachedWallet.insert (insert_idx, rec);
153
- insert_idx += 1 ;
154
- }
155
- parent->endInsertRows ();
146
+ cachedWallet.insert (insert_idx, rec);
147
+ insert_idx += 1 ;
156
148
}
149
+ parent->endInsertRows ();
157
150
}
158
- break ;
159
- case CT_DELETED:
160
- if (!inModel)
161
- {
162
- qWarning () << " TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model" ;
163
- break ;
164
- }
165
- // Removed -- remove entire transaction from table
166
- parent->beginRemoveRows (QModelIndex (), lowerIndex, upperIndex-1 );
167
- cachedWallet.erase (lower, upper);
168
- parent->endRemoveRows ();
169
- break ;
170
- case CT_UPDATED:
171
- // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
172
- // visible transactions.
151
+ }
152
+ break ;
153
+ case CT_DELETED:
154
+ if (!inModel)
155
+ {
156
+ qWarning () << " TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model" ;
173
157
break ;
174
158
}
159
+ // Removed -- remove entire transaction from table
160
+ parent->beginRemoveRows (QModelIndex (), lowerIndex, upperIndex-1 );
161
+ cachedWallet.erase (lower, upper);
162
+ parent->endRemoveRows ();
163
+ break ;
164
+ case CT_UPDATED:
165
+ // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
166
+ // visible transactions.
167
+ break ;
175
168
}
176
169
}
177
170
@@ -230,16 +223,20 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
230
223
QAbstractTableModel(parent),
231
224
wallet(wallet),
232
225
walletModel(parent),
233
- priv(new TransactionTablePriv(wallet, this ))
226
+ priv(new TransactionTablePriv(wallet, this )),
227
+ fProcessingQueuedTransactions(false )
234
228
{
235
229
columns << QString () << QString () << tr (" Date" ) << tr (" Type" ) << tr (" Address" ) << BitcoinUnits::getAmountColumnTitle (walletModel->getOptionsModel ()->getDisplayUnit ());
236
230
priv->refreshWallet ();
237
231
238
232
connect (walletModel->getOptionsModel (), SIGNAL (displayUnitChanged (int )), this , SLOT (updateDisplayUnit ()));
233
+
234
+ subscribeToCoreSignals ();
239
235
}
240
236
241
237
TransactionTableModel::~TransactionTableModel ()
242
238
{
239
+ unsubscribeFromCoreSignals ();
243
240
delete priv;
244
241
}
245
242
@@ -250,12 +247,12 @@ void TransactionTableModel::updateAmountColumnTitle()
250
247
emit headerDataChanged (Qt::Horizontal,Amount,Amount);
251
248
}
252
249
253
- void TransactionTableModel::updateTransaction (const QString &hash, int status)
250
+ void TransactionTableModel::updateTransaction (const QString &hash, int status, bool showTransaction )
254
251
{
255
252
uint256 updated;
256
253
updated.SetHex (hash.toStdString ());
257
254
258
- priv->updateWallet (updated, status);
255
+ priv->updateWallet (updated, status, showTransaction );
259
256
}
260
257
261
258
void TransactionTableModel::updateConfirmations ()
@@ -649,3 +646,82 @@ void TransactionTableModel::updateDisplayUnit()
649
646
updateAmountColumnTitle ();
650
647
emit dataChanged (index (0 , Amount), index (priv->size ()-1 , Amount));
651
648
}
649
+
650
+ // queue notifications to show a non freezing progress dialog e.g. for rescan
651
+ struct TransactionNotification
652
+ {
653
+ public:
654
+ TransactionNotification () {}
655
+ TransactionNotification (uint256 hash, ChangeType status, bool showTransaction):
656
+ hash (hash), status(status), showTransaction(showTransaction) {}
657
+
658
+ void invoke (QObject *ttm)
659
+ {
660
+ QString strHash = QString::fromStdString (hash.GetHex ());
661
+ qDebug () << " NotifyTransactionChanged : " + strHash + " status= " + QString::number (status);
662
+ QMetaObject::invokeMethod (ttm, " updateTransaction" , Qt::QueuedConnection,
663
+ Q_ARG (QString, strHash),
664
+ Q_ARG (int , status),
665
+ Q_ARG (bool , showTransaction));
666
+ }
667
+ private:
668
+ uint256 hash;
669
+ ChangeType status;
670
+ bool showTransaction;
671
+ };
672
+
673
+ static bool fQueueNotifications = false ;
674
+ static std::vector< TransactionNotification > vQueueNotifications;
675
+
676
+ static void NotifyTransactionChanged (TransactionTableModel *ttm, CWallet *wallet, const uint256 &hash, ChangeType status)
677
+ {
678
+ // Find transaction in wallet
679
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet .find (hash);
680
+ // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
681
+ bool inWallet = mi != wallet->mapWallet .end ();
682
+ bool showTransaction = (inWallet && TransactionRecord::showTransaction (mi->second ));
683
+
684
+ TransactionNotification notification (hash, status, showTransaction);
685
+
686
+ if (fQueueNotifications )
687
+ {
688
+ vQueueNotifications.push_back (notification);
689
+ return ;
690
+ }
691
+ notification.invoke (ttm);
692
+ }
693
+
694
+ static void ShowProgress (TransactionTableModel *ttm, const std::string &title, int nProgress)
695
+ {
696
+ if (nProgress == 0 )
697
+ fQueueNotifications = true ;
698
+
699
+ if (nProgress == 100 )
700
+ {
701
+ fQueueNotifications = false ;
702
+ if (vQueueNotifications.size () > 10 ) // prevent balloon spam, show maximum 10 balloons
703
+ QMetaObject::invokeMethod (ttm, " setProcessingQueuedTransactions" , Qt::QueuedConnection, Q_ARG (bool , true ));
704
+ for (unsigned int i = 0 ; i < vQueueNotifications.size (); ++i)
705
+ {
706
+ if (vQueueNotifications.size () - i <= 10 )
707
+ QMetaObject::invokeMethod (ttm, " setProcessingQueuedTransactions" , Qt::QueuedConnection, Q_ARG (bool , false ));
708
+
709
+ vQueueNotifications[i].invoke (ttm);
710
+ }
711
+ std::vector<TransactionNotification >().swap (vQueueNotifications); // clear
712
+ }
713
+ }
714
+
715
+ void TransactionTableModel::subscribeToCoreSignals ()
716
+ {
717
+ // Connect signals to wallet
718
+ wallet->NotifyTransactionChanged .connect (boost::bind (NotifyTransactionChanged, this , _1, _2, _3));
719
+ wallet->ShowProgress .connect (boost::bind (ShowProgress, this , _1, _2));
720
+ }
721
+
722
+ void TransactionTableModel::unsubscribeFromCoreSignals ()
723
+ {
724
+ // Disconnect signals from wallet
725
+ wallet->NotifyTransactionChanged .disconnect (boost::bind (NotifyTransactionChanged, this , _1, _2, _3));
726
+ wallet->ShowProgress .disconnect (boost::bind (ShowProgress, this , _1, _2));
727
+ }
0 commit comments