neobytes/src/qt/overviewpage.cpp
Alexander Block 9707ca5cea Backport Bitcoin Qt/Gui changes up to 0.14.x part 2 (#1615)
* Merge #7506: Use CCoinControl selection in CWallet::FundTransaction

d6cc6a1 Use CCoinControl selection in CWallet::FundTransaction (João Barbosa)

* Merge #7732: [Qt] Debug window: replace "Build date" with "Datadir"

fc737d1 [Qt] remove unused formatBuildDate method (Jonas Schnelli)
4856f1d [Qt] Debug window: replace "Build date" with "Datadir" (Jonas Schnelli)

* Merge #7707: [RPC][QT] UI support for abandoned transactions

8efed3b [Qt] Support for abandoned/abandoning transactions (Jonas Schnelli)

* Merge #7688: List solvability in listunspent output and improve help

c3932b3 List solvability in listunspent output and improve help (Pieter Wuille)

* Merge #8006: Qt: Add option to disable the system tray icon

8b0e497 Qt: Add option to hide the system tray icon (Tyler Hardin)

* Merge #8073: qt: askpassphrasedialog: Clear pass fields on accept

02ce2a3 qt: askpassphrasedialog: Clear pass fields on accept (Pavel Vasin)

* Merge #8231: [Qt] fix a bug where the SplashScreen will not be hidden during startup

b3e1348 [Qt] fix a bug where the SplashScreen will not be hidden during startup (Jonas Schnelli)

* Merge #8257: Do not ask a UI question from bitcoind

1acf1db Do not ask a UI question from bitcoind (Pieter Wuille)

* Merge #8463: [qt] Remove Priority from coincontrol dialog

fa8dd78 [qt] Remove Priority from coincontrol dialog (MarcoFalke)

* Merge #8678: [Qt][CoinControl] fix UI bug that could result in paying unexpected fee

0480293 [Qt][CoinControl] fix UI bug that could result in paying unexpected fee (Jonas Schnelli)

* Merge #8672: Qt: Show transaction size in transaction details window

c015634 qt: Adding transaction size to transaction details window (Hampus Sjöberg)
 \-- merge fix for s/size/total size/
fdf82fb Adding method GetTotalSize() to CTransaction (Hampus Sjöberg)

* Merge #8371: [Qt] Add out-of-sync modal info layer

08827df [Qt] modalinfolayer: removed unused comments, renamed signal, code style overhaul (Jonas Schnelli)
d8b062e [Qt] only update "amount of blocks left" when the header chain is in-sync (Jonas Schnelli)
e3245b4 [Qt] add out-of-sync modal info layer (Jonas Schnelli)
e47052f [Qt] ClientModel add method to get the height of the header chain (Jonas Schnelli)
a001f18 [Qt] Always pass the numBlocksChanged signal for headers tip changed (Jonas Schnelli)
bd44a04 [Qt] make Out-Of-Sync warning icon clickable (Jonas Schnelli)
0904c3c [Refactor] refactor function that forms human readable text out of a timeoffset (Jonas Schnelli)

* Merge #8805: Trivial: Grammar and capitalization

c9ce17b Trivial: Grammar and capitalization (Derek Miller)

* Merge #8885: gui: fix ban from qt console

cb78c60 gui: fix ban from qt console (Cory Fields)

* Merge #8821: [qt] sync-overlay: Don't block during reindex

fa85e86 [qt] sync-overlay: Don't show estimated number of headers left (MarcoFalke)
faa4de2 [qt] sync-overlay: Don't block during reindex (MarcoFalke)

* Support themes for new transaction_abandoned icon

* Fix constructor call to COutput

* Merge #7842: RPC: do not print minping time in getpeerinfo when no ping received yet

62a6486 RPC: do not print ping info in getpeerinfo when no ping received yet, fix help (Pavel Janík)

* Merge #8918: Qt: Add "Copy URI" to payment request context menu

21f5a63 Qt: Add "Copy URI" to payment request context menu (Luke Dashjr)

* Merge #8925: qt: Display minimum ping in debug window.

1724a40 Display minimum ping in debug window. (R E Broadley)

* Merge #8972: [Qt] make warnings label selectable (jonasschnelli)

ef0c9ee [Qt] make warnings label selectable (Jonas Schnelli)

* Make background of warning icon transparent in modaloverlay

* Merge #9088: Reduce ambiguity of warning message

77cbbd9 Make warning message about wallet balance possibly being incorrect less ambiguous. (R E Broadley)

* Replace Bitcoin with Dash in modal overlay

* Remove clicked signals from labelWalletStatus and labelTransactionsStatus

As both are really just labels, clicking on those is not possible.
This is different in Bitcoin, where these labels are actually buttons.

* Pull out modaloverlay show/hide into it's own if/else block and switch to time based check

Also don't use masternodeSync.IsBlockchainSynced() for now as it won't
report the blockchain being synced before the first block (or other MN
data?) arrives. This would otherwise give the impression that sync is
being stuck.
2017-09-09 10:04:02 +03:00

679 lines
30 KiB
C++

// Copyright (c) 2011-2015 The Bitcoin Core developers
// Copyright (c) 2014-2017 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "overviewpage.h"
#include "ui_overviewpage.h"
#include "bitcoinunits.h"
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "init.h"
#include "optionsmodel.h"
#include "platformstyle.h"
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
#include "utilitydialog.h"
#include "walletmodel.h"
#include "instantx.h"
#include "darksendconfig.h"
#include "masternode-sync.h"
#include "privatesend-client.h"
#include <QAbstractItemDelegate>
#include <QPainter>
#include <QSettings>
#include <QTimer>
#define ICON_OFFSET 16
#define DECORATION_SIZE 54
#define NUM_ITEMS 5
#define NUM_ITEMS_ADV 7
class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
TxViewDelegate(const PlatformStyle *platformStyle):
QAbstractItemDelegate(), unit(BitcoinUnits::DASH),
platformStyle(platformStyle)
{
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
painter->save();
QIcon icon = qvariant_cast<QIcon>(index.data(TransactionTableModel::RawDecorationRole));
QRect mainRect = option.rect;
mainRect.moveLeft(ICON_OFFSET);
QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
int xspace = DECORATION_SIZE + 8;
int ypad = 6;
int halfheight = (mainRect.height() - 2*ypad)/2;
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace - ICON_OFFSET, halfheight);
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
icon = platformStyle->SingleColorIcon(icon);
icon.paint(painter, decorationRect);
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
QString address = index.data(Qt::DisplayRole).toString();
qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
QVariant value = index.data(Qt::ForegroundRole);
QColor foreground = option.palette.color(QPalette::Text);
if(value.canConvert<QBrush>())
{
QBrush brush = qvariant_cast<QBrush>(value);
foreground = brush.color();
}
painter->setPen(foreground);
QRect boundingRect;
painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect);
if (index.data(TransactionTableModel::WatchonlyRole).toBool())
{
QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
iconWatchonly.paint(painter, watchonlyRect);
}
if(amount < 0)
{
foreground = COLOR_NEGATIVE;
}
else if(!confirmed)
{
foreground = COLOR_UNCONFIRMED;
}
else
{
foreground = option.palette.color(QPalette::Text);
}
painter->setPen(foreground);
QString amountText = BitcoinUnits::floorWithUnit(unit, amount, true, BitcoinUnits::separatorAlways);
if(!confirmed)
{
amountText = QString("[") + amountText + QString("]");
}
painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
painter->setPen(option.palette.color(QPalette::Text));
painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(DECORATION_SIZE, DECORATION_SIZE);
}
int unit;
const PlatformStyle *platformStyle;
};
#include "overviewpage.moc"
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
clientModel(0),
walletModel(0),
currentBalance(-1),
currentUnconfirmedBalance(-1),
currentImmatureBalance(-1),
currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1),
txdelegate(new TxViewDelegate(platformStyle)),
filter(0)
{
ui->setupUi(this);
QString theme = GUIUtil::getThemeName();
// Recent transactions
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
// Note: minimum height of listTransactions will be set later in updateAdvancedPSUI() to reflect actual settings
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
// init "out of sync" warning labels
ui->labelWalletStatus->setText("(" + tr("out of sync") + ")");
ui->labelPrivateSendSyncStatus->setText("(" + tr("out of sync") + ")");
ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")");
// hide PS frame (helps to preserve saved size)
// we'll setup and make it visible in updateAdvancedPSUI() later if we are not in litemode
ui->framePrivateSend->setVisible(false);
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
// that's it for litemode
if(fLiteMode) return;
// Disable any PS UI for masternode or when autobackup is disabled or failed for whatever reason
if(fMasterNode || nWalletBackups <= 0){
DisablePrivateSendCompletely();
if (nWalletBackups <= 0) {
ui->labelPrivateSendEnabled->setToolTip(tr("Automatic backups are disabled, no mixing available!"));
}
} else {
if(!privateSendClient.fEnablePrivateSend){
ui->togglePrivateSend->setText(tr("Start Mixing"));
} else {
ui->togglePrivateSend->setText(tr("Stop Mixing"));
}
// Disable privateSendClient builtin support for automatic backups while we are in GUI,
// we'll handle automatic backups and user warnings in privateSendStatus()
privateSendClient.fCreateAutoBackups = false;
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus()));
timer->start(1000);
}
}
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
if(filter)
Q_EMIT transactionClicked(filter->mapToSource(index));
}
void OverviewPage::handleOutOfSyncWarningClicks()
{
Q_EMIT outOfSyncWarningClicked();
}
OverviewPage::~OverviewPage()
{
if(!fLiteMode && !fMasterNode) disconnect(timer, SIGNAL(timeout()), this, SLOT(privateSendStatus()));
delete ui;
}
void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance)
{
currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance;
currentImmatureBalance = immatureBalance;
currentAnonymizedBalance = anonymizedBalance;
currentWatchOnlyBalance = watchOnlyBalance;
currentWatchUnconfBalance = watchUnconfBalance;
currentWatchImmatureBalance = watchImmatureBalance;
ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance, false, BitcoinUnits::separatorAlways));
ui->labelUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, unconfirmedBalance, false, BitcoinUnits::separatorAlways));
ui->labelImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, immatureBalance, false, BitcoinUnits::separatorAlways));
ui->labelAnonymized->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, anonymizedBalance, false, BitcoinUnits::separatorAlways));
ui->labelTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance + unconfirmedBalance + immatureBalance, false, BitcoinUnits::separatorAlways));
ui->labelWatchAvailable->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchOnlyBalance, false, BitcoinUnits::separatorAlways));
ui->labelWatchPending->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchUnconfBalance, false, BitcoinUnits::separatorAlways));
ui->labelWatchImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchImmatureBalance, false, BitcoinUnits::separatorAlways));
ui->labelWatchTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchOnlyBalance + watchUnconfBalance + watchImmatureBalance, false, BitcoinUnits::separatorAlways));
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
// for the non-mining users
bool showImmature = immatureBalance != 0;
bool showWatchOnlyImmature = watchImmatureBalance != 0;
// for symmetry reasons also show immature label when the watch-only one is shown
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance
updatePrivateSendProgress();
static int cachedTxLocks = 0;
if(cachedTxLocks != nCompleteTXLocks){
cachedTxLocks = nCompleteTXLocks;
ui->listTransactions->update();
}
}
// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{
ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active)
ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label
ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line
ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance
ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance
if (!showWatchOnly){
ui->labelWatchImmature->hide();
}
else{
ui->labelBalance->setIndent(20);
ui->labelUnconfirmed->setIndent(20);
ui->labelImmature->setIndent(20);
ui->labelTotal->setIndent(20);
}
}
void OverviewPage::setClientModel(ClientModel *model)
{
this->clientModel = model;
if(model)
{
// Show warning if this is a prerelease version
connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString)));
updateAlerts(model->getStatusBarWarnings());
}
}
void OverviewPage::setWalletModel(WalletModel *model)
{
this->walletModel = model;
if(model && model->getOptionsModel())
{
// update the display unit, to not use the default ("DASH")
updateDisplayUnit();
// Keep up to date with wallet
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance(),
model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
connect(model->getOptionsModel(), SIGNAL(privateSendRoundsChanged()), this, SLOT(updatePrivateSendProgress()));
connect(model->getOptionsModel(), SIGNAL(privateSentAmountChanged()), this, SLOT(updatePrivateSendProgress()));
connect(model->getOptionsModel(), SIGNAL(advancedPSUIChanged(bool)), this, SLOT(updateAdvancedPSUI(bool)));
// explicitly update PS frame and transaction list to reflect actual settings
updateAdvancedPSUI(model->getOptionsModel()->getShowAdvancedPSUI());
connect(ui->privateSendAuto, SIGNAL(clicked()), this, SLOT(privateSendAuto()));
connect(ui->privateSendReset, SIGNAL(clicked()), this, SLOT(privateSendReset()));
connect(ui->privateSendInfo, SIGNAL(clicked()), this, SLOT(privateSendInfo()));
connect(ui->togglePrivateSend, SIGNAL(clicked()), this, SLOT(togglePrivateSend()));
updateWatchOnlyLabels(model->haveWatchOnly());
connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
}
}
void OverviewPage::updateDisplayUnit()
{
if(walletModel && walletModel->getOptionsModel())
{
nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit();
if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance, currentAnonymizedBalance,
currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance);
// Update txdelegate->unit with the current unit
txdelegate->unit = nDisplayUnit;
ui->listTransactions->update();
}
}
void OverviewPage::updateAlerts(const QString &warnings)
{
this->ui->labelAlerts->setVisible(!warnings.isEmpty());
this->ui->labelAlerts->setText(warnings);
}
void OverviewPage::showOutOfSyncWarning(bool fShow)
{
ui->labelWalletStatus->setVisible(fShow);
ui->labelPrivateSendSyncStatus->setVisible(fShow);
ui->labelTransactionsStatus->setVisible(fShow);
}
void OverviewPage::updatePrivateSendProgress()
{
if(!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return;
if(!pwalletMain) return;
QString strAmountAndRounds;
QString strPrivateSendAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, privateSendClient.nPrivateSendAmount * COIN, false, BitcoinUnits::separatorAlways);
if(currentBalance == 0)
{
ui->privateSendProgress->setValue(0);
ui->privateSendProgress->setToolTip(tr("No inputs detected"));
// when balance is zero just show info from settings
strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1);
strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds);
ui->labelAmountRounds->setToolTip(tr("No inputs detected"));
ui->labelAmountRounds->setText(strAmountAndRounds);
return;
}
CAmount nDenominatedConfirmedBalance;
CAmount nDenominatedUnconfirmedBalance;
CAmount nAnonymizableBalance;
CAmount nNormalizedAnonymizedBalance;
float nAverageAnonymizedRounds;
{
nDenominatedConfirmedBalance = pwalletMain->GetDenominatedBalance();
nDenominatedUnconfirmedBalance = pwalletMain->GetDenominatedBalance(true);
nAnonymizableBalance = pwalletMain->GetAnonymizableBalance(false, false);
nNormalizedAnonymizedBalance = pwalletMain->GetNormalizedAnonymizedBalance();
nAverageAnonymizedRounds = pwalletMain->GetAverageAnonymizedRounds();
}
CAmount nMaxToAnonymize = nAnonymizableBalance + currentAnonymizedBalance;
// If it's more than the anon threshold, limit to that.
if(nMaxToAnonymize > privateSendClient.nPrivateSendAmount*COIN) nMaxToAnonymize = privateSendClient.nPrivateSendAmount*COIN;
if(nMaxToAnonymize == 0) return;
if(nMaxToAnonymize >= privateSendClient.nPrivateSendAmount * COIN) {
ui->labelAmountRounds->setToolTip(tr("Found enough compatible inputs to anonymize %1")
.arg(strPrivateSendAmount));
strPrivateSendAmount = strPrivateSendAmount.remove(strPrivateSendAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1);
strAmountAndRounds = strPrivateSendAmount + " / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds);
} else {
QString strMaxToAnonymize = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, nMaxToAnonymize, false, BitcoinUnits::separatorAlways);
ui->labelAmountRounds->setToolTip(tr("Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>"
"will anonymize <span style='color:red;'>%2</span> instead")
.arg(strPrivateSendAmount)
.arg(strMaxToAnonymize));
strMaxToAnonymize = strMaxToAnonymize.remove(strMaxToAnonymize.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1);
strAmountAndRounds = "<span style='color:red;'>" +
QString(BitcoinUnits::factor(nDisplayUnit) == 1 ? "" : "~") + strMaxToAnonymize +
" / " + tr("%n Rounds", "", privateSendClient.nPrivateSendRounds) + "</span>";
}
ui->labelAmountRounds->setText(strAmountAndRounds);
// calculate parts of the progress, each of them shouldn't be higher than 1
// progress of denominating
float denomPart = 0;
// mixing progress of denominated balance
float anonNormPart = 0;
// completeness of full amount anonymization
float anonFullPart = 0;
CAmount denominatedBalance = nDenominatedConfirmedBalance + nDenominatedUnconfirmedBalance;
denomPart = (float)denominatedBalance / nMaxToAnonymize;
denomPart = denomPart > 1 ? 1 : denomPart;
denomPart *= 100;
anonNormPart = (float)nNormalizedAnonymizedBalance / nMaxToAnonymize;
anonNormPart = anonNormPart > 1 ? 1 : anonNormPart;
anonNormPart *= 100;
anonFullPart = (float)currentAnonymizedBalance / nMaxToAnonymize;
anonFullPart = anonFullPart > 1 ? 1 : anonFullPart;
anonFullPart *= 100;
// apply some weights to them ...
float denomWeight = 1;
float anonNormWeight = privateSendClient.nPrivateSendRounds;
float anonFullWeight = 2;
float fullWeight = denomWeight + anonNormWeight + anonFullWeight;
// ... and calculate the whole progress
float denomPartCalc = ceilf((denomPart * denomWeight / fullWeight) * 100) / 100;
float anonNormPartCalc = ceilf((anonNormPart * anonNormWeight / fullWeight) * 100) / 100;
float anonFullPartCalc = ceilf((anonFullPart * anonFullWeight / fullWeight) * 100) / 100;
float progress = denomPartCalc + anonNormPartCalc + anonFullPartCalc;
if(progress >= 100) progress = 100;
ui->privateSendProgress->setValue(progress);
QString strToolPip = ("<b>" + tr("Overall progress") + ": %1%</b><br/>" +
tr("Denominated") + ": %2%<br/>" +
tr("Mixed") + ": %3%<br/>" +
tr("Anonymized") + ": %4%<br/>" +
tr("Denominated inputs have %5 of %n rounds on average", "", privateSendClient.nPrivateSendRounds))
.arg(progress).arg(denomPart).arg(anonNormPart).arg(anonFullPart)
.arg(nAverageAnonymizedRounds);
ui->privateSendProgress->setToolTip(strToolPip);
}
void OverviewPage::updateAdvancedPSUI(bool fShowAdvancedPSUI) {
this->fShowAdvancedPSUI = fShowAdvancedPSUI;
int nNumItems = (fLiteMode || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV;
SetupTransactionList(nNumItems);
if (fLiteMode) return;
ui->framePrivateSend->setVisible(true);
ui->labelCompletitionText->setVisible(fShowAdvancedPSUI);
ui->privateSendProgress->setVisible(fShowAdvancedPSUI);
ui->labelSubmittedDenomText->setVisible(fShowAdvancedPSUI);
ui->labelSubmittedDenom->setVisible(fShowAdvancedPSUI);
ui->privateSendAuto->setVisible(fShowAdvancedPSUI);
ui->privateSendReset->setVisible(fShowAdvancedPSUI);
ui->privateSendInfo->setVisible(true);
ui->labelPrivateSendLastMessage->setVisible(fShowAdvancedPSUI);
}
void OverviewPage::privateSendStatus()
{
if(!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return;
static int64_t nLastDSProgressBlockTime = 0;
int nBestHeight = clientModel->getNumBlocks();
// We are processing more then 1 block per second, we'll just leave
if(((nBestHeight - privateSendClient.nCachedNumBlocks) / (GetTimeMillis() - nLastDSProgressBlockTime + 1) > 1)) return;
nLastDSProgressBlockTime = GetTimeMillis();
QString strKeysLeftText(tr("keys left: %1").arg(pwalletMain->nKeysLeftSinceAutoBackup));
if(pwalletMain->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
strKeysLeftText = "<span style='color:red;'>" + strKeysLeftText + "</span>";
}
ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText);
if (!privateSendClient.fEnablePrivateSend) {
if (nBestHeight != privateSendClient.nCachedNumBlocks) {
privateSendClient.nCachedNumBlocks = nBestHeight;
updatePrivateSendProgress();
}
ui->labelPrivateSendLastMessage->setText("");
ui->togglePrivateSend->setText(tr("Start Mixing"));
QString strEnabled = tr("Disabled");
// Show how many keys left in advanced PS UI mode only
if (fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText;
ui->labelPrivateSendEnabled->setText(strEnabled);
return;
}
// Warn user that wallet is running out of keys
// NOTE: we do NOT warn user and do NOT create autobackups if mixing is not running
if (nWalletBackups > 0 && pwalletMain->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
QSettings settings;
if(settings.value("fLowKeysWarning").toBool()) {
QString strWarn = tr("Very low number of keys left since last automatic backup!") + "<br><br>" +
tr("We are about to create a new automatic backup for you, however "
"<span style='color:red;'> you should always make sure you have backups "
"saved in some safe place</span>!") + "<br><br>" +
tr("Note: You turn this message off in options.");
ui->labelPrivateSendEnabled->setToolTip(strWarn);
LogPrintf("OverviewPage::privateSendStatus -- Very low number of keys left since last automatic backup, warning user and trying to create new backup...\n");
QMessageBox::warning(this, tr("PrivateSend"), strWarn, QMessageBox::Ok, QMessageBox::Ok);
} else {
LogPrintf("OverviewPage::privateSendStatus -- Very low number of keys left since last automatic backup, skipping warning and trying to create new backup...\n");
}
std::string strBackupWarning;
std::string strBackupError;
if(!AutoBackupWallet(pwalletMain, "", strBackupWarning, strBackupError)) {
if (!strBackupWarning.empty()) {
// It's still more or less safe to continue but warn user anyway
LogPrintf("OverviewPage::privateSendStatus -- WARNING! Something went wrong on automatic backup: %s\n", strBackupWarning);
QMessageBox::warning(this, tr("PrivateSend"),
tr("WARNING! Something went wrong on automatic backup") + ":<br><br>" + strBackupWarning.c_str(),
QMessageBox::Ok, QMessageBox::Ok);
}
if (!strBackupError.empty()) {
// Things are really broken, warn user and stop mixing immediately
LogPrintf("OverviewPage::privateSendStatus -- ERROR! Failed to create automatic backup: %s\n", strBackupError);
QMessageBox::warning(this, tr("PrivateSend"),
tr("ERROR! Failed to create automatic backup") + ":<br><br>" + strBackupError.c_str() + "<br>" +
tr("Mixing is disabled, please close your wallet and fix the issue!"),
QMessageBox::Ok, QMessageBox::Ok);
}
}
}
QString strEnabled = privateSendClient.fEnablePrivateSend ? tr("Enabled") : tr("Disabled");
// Show how many keys left in advanced PS UI mode only
if(fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText;
ui->labelPrivateSendEnabled->setText(strEnabled);
if(nWalletBackups == -1) {
// Automatic backup failed, nothing else we can do until user fixes the issue manually
DisablePrivateSendCompletely();
QString strError = tr("ERROR! Failed to create automatic backup") + ", " +
tr("see debug.log for details.") + "<br><br>" +
tr("Mixing is disabled, please close your wallet and fix the issue!");
ui->labelPrivateSendEnabled->setToolTip(strError);
return;
} else if(nWalletBackups == -2) {
// We were able to create automatic backup but keypool was not replenished because wallet is locked.
QString strWarning = tr("WARNING! Failed to replenish keypool, please unlock your wallet to do so.");
ui->labelPrivateSendEnabled->setToolTip(strWarning);
}
// check darksend status and unlock if needed
if(nBestHeight != privateSendClient.nCachedNumBlocks) {
// Balance and number of transactions might have changed
privateSendClient.nCachedNumBlocks = nBestHeight;
updatePrivateSendProgress();
}
QString strStatus = QString(privateSendClient.GetStatus().c_str());
QString s = tr("Last PrivateSend message:\n") + strStatus;
if(s != ui->labelPrivateSendLastMessage->text())
LogPrintf("OverviewPage::privateSendStatus -- Last PrivateSend message: %s\n", strStatus.toStdString());
ui->labelPrivateSendLastMessage->setText(s);
if(privateSendClient.nSessionDenom == 0){
ui->labelSubmittedDenom->setText(tr("N/A"));
} else {
QString strDenom(CPrivateSend::GetDenominationsToString(privateSendClient.nSessionDenom).c_str());
ui->labelSubmittedDenom->setText(strDenom);
}
}
void OverviewPage::privateSendAuto(){
privateSendClient.DoAutomaticDenominating(*g_connman);
}
void OverviewPage::privateSendReset(){
privateSendClient.ResetPool();
QMessageBox::warning(this, tr("PrivateSend"),
tr("PrivateSend was successfully reset."),
QMessageBox::Ok, QMessageBox::Ok);
}
void OverviewPage::privateSendInfo(){
HelpMessageDialog dlg(this, HelpMessageDialog::pshelp);
dlg.exec();
}
void OverviewPage::togglePrivateSend(){
QSettings settings;
// Popup some information on first mixing
QString hasMixed = settings.value("hasMixed").toString();
if(hasMixed.isEmpty()){
QMessageBox::information(this, tr("PrivateSend"),
tr("If you don't want to see internal PrivateSend fees/transactions select \"Most Common\" as Type on the \"Transactions\" tab."),
QMessageBox::Ok, QMessageBox::Ok);
settings.setValue("hasMixed", "hasMixed");
}
if(!privateSendClient.fEnablePrivateSend){
const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount();
if(currentBalance < nMinAmount){
QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, nMinAmount));
QMessageBox::warning(this, tr("PrivateSend"),
tr("PrivateSend requires at least %1 to use.").arg(strMinAmount),
QMessageBox::Ok, QMessageBox::Ok);
return;
}
// if wallet is locked, ask for a passphrase
if (walletModel->getEncryptionStatus() == WalletModel::Locked)
{
WalletModel::UnlockContext ctx(walletModel->requestUnlock(true));
if(!ctx.isValid())
{
//unlock was cancelled
privateSendClient.nCachedNumBlocks = std::numeric_limits<int>::max();
QMessageBox::warning(this, tr("PrivateSend"),
tr("Wallet is locked and user declined to unlock. Disabling PrivateSend."),
QMessageBox::Ok, QMessageBox::Ok);
LogPrint("privatesend", "OverviewPage::togglePrivateSend -- Wallet is locked and user declined to unlock. Disabling PrivateSend.\n");
return;
}
}
}
privateSendClient.fEnablePrivateSend = !privateSendClient.fEnablePrivateSend;
privateSendClient.nCachedNumBlocks = std::numeric_limits<int>::max();
if(!privateSendClient.fEnablePrivateSend){
ui->togglePrivateSend->setText(tr("Start Mixing"));
privateSendClient.UnlockCoins();
} else {
ui->togglePrivateSend->setText(tr("Stop Mixing"));
/* show darksend configuration if client has defaults set */
if(privateSendClient.nPrivateSendAmount == 0){
DarksendConfig dlg(this);
dlg.setModel(walletModel);
dlg.exec();
}
}
}
void OverviewPage::SetupTransactionList(int nNumItems) {
ui->listTransactions->setMinimumHeight(nNumItems * (DECORATION_SIZE + 2));
if(walletModel && walletModel->getOptionsModel()) {
// Set up transaction list
filter = new TransactionFilterProxy();
filter->setSourceModel(walletModel->getTransactionTableModel());
filter->setLimit(nNumItems);
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
}
}
void OverviewPage::DisablePrivateSendCompletely() {
ui->togglePrivateSend->setText("(" + tr("Disabled") + ")");
ui->privateSendAuto->setText("(" + tr("Disabled") + ")");
ui->privateSendReset->setText("(" + tr("Disabled") + ")");
ui->framePrivateSend->setEnabled(false);
if (nWalletBackups <= 0) {
ui->labelPrivateSendEnabled->setText("<span style='color:red;'>(" + tr("Disabled") + ")</span>");
}
privateSendClient.fEnablePrivateSend = false;
}