@ -91,87 +91,80 @@ public:
Call with transaction that was added , removed or changed .
Call with transaction that was added , removed or changed .
*/
*/
void updateWallet ( const uint256 & hash , int status )
void updateWallet ( const uint256 & hash , int status , bool showTransaction )
{
{
qDebug ( ) < < " TransactionTablePriv::updateWallet : " + QString : : fromStdString ( hash . ToString ( ) ) + " " + QString : : number ( status ) ;
qDebug ( ) < < " TransactionTablePriv::updateWallet : " + QString : : fromStdString ( hash . ToString ( ) ) + " " + QString : : number ( status ) ;
{
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
// Find transaction in wallet
// Find bounds of this transaction in model
std : : map < uint256 , CWalletTx > : : iterator mi = wallet - > mapWallet . find ( hash ) ;
QList < TransactionRecord > : : iterator lower = qLowerBound (
bool inWallet = mi ! = wallet - > mapWallet . end ( ) ;
cachedWallet . begin ( ) , cachedWallet . end ( ) , hash , TxLessThan ( ) ) ;
QList < TransactionRecord > : : iterator upper = qUpperBound (
cachedWallet . begin ( ) , cachedWallet . end ( ) , hash , TxLessThan ( ) ) ;
int lowerIndex = ( lower - cachedWallet . begin ( ) ) ;
int upperIndex = ( upper - cachedWallet . begin ( ) ) ;
bool inModel = ( lower ! = upper ) ;
// Find bounds of this transaction in model
if ( status = = CT_UPDATED )
QList < TransactionRecord > : : iterator lower = qLowerBound (
{
cachedWallet . begin ( ) , cachedWallet . end ( ) , hash , TxLessThan ( ) ) ;
if ( showTransaction & & ! inModel )
QList < TransactionRecord > : : iterator upper = qUpperBound (
status = CT_NEW ; /* Not in model, but want to show, treat as new */
cachedWallet . begin ( ) , cachedWallet . end ( ) , hash , TxLessThan ( ) ) ;
if ( ! showTransaction & & inModel )
int lowerIndex = ( lower - cachedWallet . begin ( ) ) ;
status = CT_DELETED ; /* In model, but want to hide, treat as deleted */
int upperIndex = ( upper - cachedWallet . begin ( ) ) ;
}
bool inModel = ( lower ! = upper ) ;
// Determine whether to show transaction or not
qDebug ( ) < < " inModel= " + QString : : number ( inModel ) +
bool showTransaction = ( inWallet & & TransactionRecord : : showTransaction ( mi - > second ) ) ;
" Index= " + QString : : number ( lowerIndex ) + " - " + QString : : number ( upperIndex ) +
" showTransaction= " + QString : : number ( showTransaction ) + " derivedStatus= " + QString : : number ( status ) ;
if ( status = = CT_UPDATED )
switch ( status )
{
case CT_NEW :
if ( inModel )
{
{
if ( showTransaction & & ! inModel )
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model " ;
status = CT_NEW ; /* Not in model, but want to show, treat as new */
break ;
if ( ! showTransaction & & inModel )
status = CT_DELETED ; /* In model, but want to hide, treat as deleted */
}
}
if ( showTransaction )
qDebug ( ) < < " inWallet= " + QString : : number ( inWallet ) + " inModel= " + QString : : number ( inModel ) +
" Index= " + QString : : number ( lowerIndex ) + " - " + QString : : number ( upperIndex ) +
" showTransaction= " + QString : : number ( showTransaction ) + " derivedStatus= " + QString : : number ( status ) ;
switch ( status )
{
{
case CT_NEW :
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
if ( inModel )
// Find transaction in wallet
{
std : : map < uint256 , CWalletTx > : : iterator mi = wallet - > mapWallet . find ( hash ) ;
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model " ;
if ( mi = = wallet - > mapWallet . end ( ) )
break ;
}
if ( ! inWallet )
{
{
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet " ;
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet " ;
break ;
break ;
}
}
if ( showTransaction )
// Added -- insert at the right position
QList < TransactionRecord > toInsert =
TransactionRecord : : decomposeTransaction ( wallet , mi - > second ) ;
if ( ! toInsert . isEmpty ( ) ) /* only if something to insert */
{
{
// Added -- insert at the right position
parent - > beginInsertRows ( QModelIndex ( ) , lowerIndex , lowerIndex + toInsert . size ( ) - 1 ) ;
QList < TransactionRecord > toInsert =
int insert_idx = lowerIndex ;
TransactionRecord : : decomposeTransaction ( wallet , mi - > second ) ;
foreach ( const TransactionRecord & rec , toInsert )
if ( ! toInsert . isEmpty ( ) ) /* only if something to insert */
{
{
parent - > beginInsertRows ( QModelIndex ( ) , lowerIndex , lowerIndex + toInsert . size ( ) - 1 ) ;
cachedWallet . insert ( insert_idx , rec ) ;
int insert_idx = lowerIndex ;
insert_idx + = 1 ;
foreach ( const TransactionRecord & rec , toInsert )
{
cachedWallet . insert ( insert_idx , rec ) ;
insert_idx + = 1 ;
}
parent - > endInsertRows ( ) ;
}
}
parent - > endInsertRows ( ) ;
}
}
break ;
}
case CT_DELETED :
break ;
if ( ! inModel )
case CT_DELETED :
{
if ( ! inModel )
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model " ;
{
break ;
qWarning ( ) < < " TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model " ;
}
// Removed -- remove entire transaction from table
parent - > beginRemoveRows ( QModelIndex ( ) , lowerIndex , upperIndex - 1 ) ;
cachedWallet . erase ( lower , upper ) ;
parent - > endRemoveRows ( ) ;
break ;
case CT_UPDATED :
// Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
// visible transactions.
break ;
break ;
}
}
// Removed -- remove entire transaction from table
parent - > beginRemoveRows ( QModelIndex ( ) , lowerIndex , upperIndex - 1 ) ;
cachedWallet . erase ( lower , upper ) ;
parent - > endRemoveRows ( ) ;
break ;
case CT_UPDATED :
// Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
// visible transactions.
break ;
}
}
}
}
@ -230,16 +223,20 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
QAbstractTableModel ( parent ) ,
QAbstractTableModel ( parent ) ,
wallet ( wallet ) ,
wallet ( wallet ) ,
walletModel ( parent ) ,
walletModel ( parent ) ,
priv ( new TransactionTablePriv ( wallet , this ) )
priv ( new TransactionTablePriv ( wallet , this ) ) ,
fProcessingQueuedTransactions ( false )
{
{
columns < < QString ( ) < < QString ( ) < < tr ( " Date " ) < < tr ( " Type " ) < < tr ( " Address " ) < < BitcoinUnits : : getAmountColumnTitle ( walletModel - > getOptionsModel ( ) - > getDisplayUnit ( ) ) ;
columns < < QString ( ) < < QString ( ) < < tr ( " Date " ) < < tr ( " Type " ) < < tr ( " Address " ) < < BitcoinUnits : : getAmountColumnTitle ( walletModel - > getOptionsModel ( ) - > getDisplayUnit ( ) ) ;
priv - > refreshWallet ( ) ;
priv - > refreshWallet ( ) ;
connect ( walletModel - > getOptionsModel ( ) , SIGNAL ( displayUnitChanged ( int ) ) , this , SLOT ( updateDisplayUnit ( ) ) ) ;
connect ( walletModel - > getOptionsModel ( ) , SIGNAL ( displayUnitChanged ( int ) ) , this , SLOT ( updateDisplayUnit ( ) ) ) ;
subscribeToCoreSignals ( ) ;
}
}
TransactionTableModel : : ~ TransactionTableModel ( )
TransactionTableModel : : ~ TransactionTableModel ( )
{
{
unsubscribeFromCoreSignals ( ) ;
delete priv ;
delete priv ;
}
}
@ -250,12 +247,12 @@ void TransactionTableModel::updateAmountColumnTitle()
emit headerDataChanged ( Qt : : Horizontal , Amount , Amount ) ;
emit headerDataChanged ( Qt : : Horizontal , Amount , Amount ) ;
}
}
void TransactionTableModel : : updateTransaction ( const QString & hash , int status )
void TransactionTableModel : : updateTransaction ( const QString & hash , int status , bool showTransaction )
{
{
uint256 updated ;
uint256 updated ;
updated . SetHex ( hash . toStdString ( ) ) ;
updated . SetHex ( hash . toStdString ( ) ) ;
priv - > updateWallet ( updated , status ) ;
priv - > updateWallet ( updated , status , showTransaction ) ;
}
}
void TransactionTableModel : : updateConfirmations ( )
void TransactionTableModel : : updateConfirmations ( )
@ -649,3 +646,82 @@ void TransactionTableModel::updateDisplayUnit()
updateAmountColumnTitle ( ) ;
updateAmountColumnTitle ( ) ;
emit dataChanged ( index ( 0 , Amount ) , index ( priv - > size ( ) - 1 , Amount ) ) ;
emit dataChanged ( index ( 0 , Amount ) , index ( priv - > size ( ) - 1 , Amount ) ) ;
}
}
// queue notifications to show a non freezing progress dialog e.g. for rescan
struct TransactionNotification
{
public :
TransactionNotification ( ) { }
TransactionNotification ( uint256 hash , ChangeType status , bool showTransaction ) :
hash ( hash ) , status ( status ) , showTransaction ( showTransaction ) { }
void invoke ( QObject * ttm )
{
QString strHash = QString : : fromStdString ( hash . GetHex ( ) ) ;
qDebug ( ) < < " NotifyTransactionChanged : " + strHash + " status= " + QString : : number ( status ) ;
QMetaObject : : invokeMethod ( ttm , " updateTransaction " , Qt : : QueuedConnection ,
Q_ARG ( QString , strHash ) ,
Q_ARG ( int , status ) ,
Q_ARG ( bool , showTransaction ) ) ;
}
private :
uint256 hash ;
ChangeType status ;
bool showTransaction ;
} ;
static bool fQueueNotifications = false ;
static std : : vector < TransactionNotification > vQueueNotifications ;
static void NotifyTransactionChanged ( TransactionTableModel * ttm , CWallet * wallet , const uint256 & hash , ChangeType status )
{
// Find transaction in wallet
std : : map < uint256 , CWalletTx > : : iterator mi = wallet - > mapWallet . find ( hash ) ;
// Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
bool inWallet = mi ! = wallet - > mapWallet . end ( ) ;
bool showTransaction = ( inWallet & & TransactionRecord : : showTransaction ( mi - > second ) ) ;
TransactionNotification notification ( hash , status , showTransaction ) ;
if ( fQueueNotifications )
{
vQueueNotifications . push_back ( notification ) ;
return ;
}
notification . invoke ( ttm ) ;
}
static void ShowProgress ( TransactionTableModel * ttm , const std : : string & title , int nProgress )
{
if ( nProgress = = 0 )
fQueueNotifications = true ;
if ( nProgress = = 100 )
{
fQueueNotifications = false ;
if ( vQueueNotifications . size ( ) > 10 ) // prevent balloon spam, show maximum 10 balloons
QMetaObject : : invokeMethod ( ttm , " setProcessingQueuedTransactions " , Qt : : QueuedConnection , Q_ARG ( bool , true ) ) ;
for ( unsigned int i = 0 ; i < vQueueNotifications . size ( ) ; + + i )
{
if ( vQueueNotifications . size ( ) - i < = 10 )
QMetaObject : : invokeMethod ( ttm , " setProcessingQueuedTransactions " , Qt : : QueuedConnection , Q_ARG ( bool , false ) ) ;
vQueueNotifications [ i ] . invoke ( ttm ) ;
}
std : : vector < TransactionNotification > ( ) . swap ( vQueueNotifications ) ; // clear
}
}
void TransactionTableModel : : subscribeToCoreSignals ( )
{
// Connect signals to wallet
wallet - > NotifyTransactionChanged . connect ( boost : : bind ( NotifyTransactionChanged , this , _1 , _2 , _3 ) ) ;
wallet - > ShowProgress . connect ( boost : : bind ( ShowProgress , this , _1 , _2 ) ) ;
}
void TransactionTableModel : : unsubscribeFromCoreSignals ( )
{
// Disconnect signals from wallet
wallet - > NotifyTransactionChanged . disconnect ( boost : : bind ( NotifyTransactionChanged , this , _1 , _2 , _3 ) ) ;
wallet - > ShowProgress . disconnect ( boost : : bind ( ShowProgress , this , _1 , _2 ) ) ;
}