Implement SI-style (thin space) thoudands separator
This commit is contained in:
parent
9b4b3cf9cf
commit
7007402956
10 changed files with 184 additions and 37 deletions
|
@ -14,6 +14,51 @@
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <qmath.h> // for qPow()
|
#include <qmath.h> // for qPow()
|
||||||
|
|
||||||
|
// QDoubleSpinBox that shows SI-style thin space thousands separators
|
||||||
|
class AmountSpinBox: public QDoubleSpinBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AmountSpinBox(QWidget *parent):
|
||||||
|
QDoubleSpinBox(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
QString textFromValue(double value) const
|
||||||
|
{
|
||||||
|
QStringList parts = QDoubleSpinBox::textFromValue(value).split(".");
|
||||||
|
QString quotient_str = parts[0];
|
||||||
|
QString remainder_str;
|
||||||
|
if(parts.size() > 1)
|
||||||
|
remainder_str = parts[1];
|
||||||
|
|
||||||
|
// Code duplication between here and BitcoinUnits::format
|
||||||
|
// TODO: Figure out how to share this code
|
||||||
|
QChar thin_sp(THIN_SP_CP);
|
||||||
|
int q_size = quotient_str.size();
|
||||||
|
if (q_size > 4)
|
||||||
|
for (int i = 3; i < q_size; i += 3)
|
||||||
|
quotient_str.insert(q_size - i, thin_sp);
|
||||||
|
|
||||||
|
int r_size = remainder_str.size();
|
||||||
|
if (r_size > 4)
|
||||||
|
for (int i = 3, adj = 0; i < r_size; i += 3, adj++)
|
||||||
|
remainder_str.insert(i + adj, thin_sp);
|
||||||
|
|
||||||
|
if(remainder_str.isEmpty())
|
||||||
|
return quotient_str;
|
||||||
|
else
|
||||||
|
return quotient_str + QString(".") + remainder_str;
|
||||||
|
}
|
||||||
|
QValidator::State validate (QString &text, int &pos) const
|
||||||
|
{
|
||||||
|
QString s(BitcoinUnits::removeSpaces(text));
|
||||||
|
return QDoubleSpinBox::validate(s, pos);
|
||||||
|
}
|
||||||
|
double valueFromText(const QString& text) const
|
||||||
|
{
|
||||||
|
return QDoubleSpinBox::valueFromText(BitcoinUnits::removeSpaces(text));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
|
BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
amount(0),
|
amount(0),
|
||||||
|
@ -21,7 +66,7 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
|
||||||
{
|
{
|
||||||
nSingleStep = 100000; // satoshis
|
nSingleStep = 100000; // satoshis
|
||||||
|
|
||||||
amount = new QDoubleSpinBox(this);
|
amount = new AmountSpinBox(this);
|
||||||
amount->setLocale(QLocale::c());
|
amount->setLocale(QLocale::c());
|
||||||
amount->installEventFilter(this);
|
amount->installEventFilter(this);
|
||||||
amount->setMaximumWidth(170);
|
amount->setMaximumWidth(170);
|
||||||
|
@ -52,7 +97,7 @@ void BitcoinAmountField::setText(const QString &text)
|
||||||
if (text.isEmpty())
|
if (text.isEmpty())
|
||||||
amount->clear();
|
amount->clear();
|
||||||
else
|
else
|
||||||
amount->setValue(text.toDouble());
|
amount->setValue(BitcoinUnits::removeSpaces(text).toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcoinAmountField::clear()
|
void BitcoinAmountField::clear()
|
||||||
|
|
|
@ -50,8 +50,8 @@ QString BitcoinUnits::description(int unit)
|
||||||
switch(unit)
|
switch(unit)
|
||||||
{
|
{
|
||||||
case BTC: return QString("Bitcoins");
|
case BTC: return QString("Bitcoins");
|
||||||
case mBTC: return QString("Milli-Bitcoins (1 / 1,000)");
|
case mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
|
||||||
case uBTC: return QString("Micro-Bitcoins (1 / 1,000,000)");
|
case uBTC: return QString("Micro-Bitcoins (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
|
||||||
default: return QString("???");
|
default: return QString("???");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ int BitcoinUnits::decimals(int unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
|
QString BitcoinUnits::format(int unit, qint64 n, bool fPlus, SeparatorStyle separators, bool fAlign)
|
||||||
{
|
{
|
||||||
// Note: not using straight sprintf here because we do NOT want
|
// Note: not using straight sprintf here because we do NOT want
|
||||||
// localized number formatting.
|
// localized number formatting.
|
||||||
|
@ -119,6 +119,23 @@ QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
|
||||||
for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
|
for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
|
||||||
++nTrim;
|
++nTrim;
|
||||||
remainder_str.chop(nTrim);
|
remainder_str.chop(nTrim);
|
||||||
|
if (fAlign)
|
||||||
|
remainder_str.append(QString(QChar(FIGURE_SP_CP)).repeated(nTrim));
|
||||||
|
|
||||||
|
// Use SI-stule separators as these are locale indendent and can't be
|
||||||
|
// confused with the decimal marker. Rule is to use a thin space every
|
||||||
|
// three digits on *both* sides of the decimal point - but only if there
|
||||||
|
// are five or more digits
|
||||||
|
QChar thin_sp(THIN_SP_CP);
|
||||||
|
int q_size = quotient_str.size();
|
||||||
|
if (separators == separatorAlways || (separators == separatorStandard && q_size > 4))
|
||||||
|
for (int i = 3; i < q_size; i += 3)
|
||||||
|
quotient_str.insert(q_size - i, thin_sp);
|
||||||
|
|
||||||
|
int r_size = remainder_str.size();
|
||||||
|
if (separators == separatorAlways || (separators == separatorStandard && r_size > 4))
|
||||||
|
for (int i = 3, adj = 0; i < r_size ; i += 3, adj++)
|
||||||
|
remainder_str.insert(i + adj, thin_sp);
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
quotient_str.insert(0, '-');
|
quotient_str.insert(0, '-');
|
||||||
|
@ -127,17 +144,27 @@ QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
|
||||||
return quotient_str + QString(".") + remainder_str;
|
return quotient_str + QString(".") + remainder_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign)
|
QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign, SeparatorStyle separators, bool fAlign)
|
||||||
{
|
{
|
||||||
return format(unit, amount, plussign) + QString(" ") + name(unit);
|
return format(unit, amount, plussign, separators, fAlign) + QString(" ") + name(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString BitcoinUnits::formatHtmlWithUnit(int unit, qint64 amount, bool plussign, SeparatorStyle separators)
|
||||||
|
{
|
||||||
|
QString str(formatWithUnit(unit, amount, plussign, separators));
|
||||||
|
str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
|
||||||
|
return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
|
bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
|
||||||
{
|
{
|
||||||
if(!valid(unit) || value.isEmpty())
|
if(!valid(unit) || value.isEmpty())
|
||||||
return false; // Refuse to parse invalid unit or empty string
|
return false; // Refuse to parse invalid unit or empty string
|
||||||
int num_decimals = decimals(unit);
|
int num_decimals = decimals(unit);
|
||||||
QStringList parts = value.split(".");
|
|
||||||
|
// Ignore spaces and thin spaces when parsing
|
||||||
|
QStringList parts = removeSpaces(value).split(".");
|
||||||
|
|
||||||
if(parts.size() > 2)
|
if(parts.size() > 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,37 @@
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
// U+2009 THIN SPACE = UTF-8 E2 80 89
|
||||||
|
#define REAL_THIN_SP_CP 0x2009
|
||||||
|
#define REAL_THIN_SP_UTF8 "\xE2\x80\x89"
|
||||||
|
#define REAL_THIN_SP_HTML " "
|
||||||
|
|
||||||
|
// U+200A HAIR SPACE = UTF-8 E2 80 8A
|
||||||
|
#define HAIR_SP_CP 0x200A
|
||||||
|
#define HAIR_SP_UTF8 "\xE2\x80\x8A"
|
||||||
|
#define HAIR_SP_HTML " "
|
||||||
|
|
||||||
|
// U+2006 SIX-PER-EM SPACE = UTF-8 E2 80 86
|
||||||
|
#define SIXPEREM_SP_CP 0x2006
|
||||||
|
#define SIXPEREM_SP_UTF8 "\xE2\x80\x86"
|
||||||
|
#define SIXPEREM_SP_HTML " "
|
||||||
|
|
||||||
|
// U+2007 FIGURE SPACE = UTF-8 E2 80 87
|
||||||
|
#define FIGURE_SP_CP 0x2007
|
||||||
|
#define FIGURE_SP_UTF8 "\xE2\x80\x87"
|
||||||
|
#define FIGURE_SP_HTML " "
|
||||||
|
|
||||||
|
// QMessageBox seems to have a bug whereby it doesn't display thin/hair spaces
|
||||||
|
// correctly. Workaround is to display a space in a small font. If you
|
||||||
|
// change this, please test that it doesn't cause the parent span to start
|
||||||
|
// wrapping.
|
||||||
|
#define HTML_HACK_SP "<span style='white-space: nowrap; font-size: 6pt'> </span>"
|
||||||
|
|
||||||
|
// Define THIN_SP_* variables to be our preferred type of thin space
|
||||||
|
#define THIN_SP_CP REAL_THIN_SP_CP
|
||||||
|
#define THIN_SP_UTF8 REAL_THIN_SP_UTF8
|
||||||
|
#define THIN_SP_HTML HTML_HACK_SP
|
||||||
|
|
||||||
/** Bitcoin unit definitions. Encapsulates parsing and formatting
|
/** Bitcoin unit definitions. Encapsulates parsing and formatting
|
||||||
and serves as list model for drop-down selection boxes.
|
and serves as list model for drop-down selection boxes.
|
||||||
*/
|
*/
|
||||||
|
@ -28,6 +59,13 @@ public:
|
||||||
uBTC
|
uBTC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SeparatorStyle
|
||||||
|
{
|
||||||
|
separatorNever,
|
||||||
|
separatorStandard,
|
||||||
|
separatorAlways
|
||||||
|
};
|
||||||
|
|
||||||
//! @name Static API
|
//! @name Static API
|
||||||
//! Unit conversion and formatting
|
//! Unit conversion and formatting
|
||||||
///@{
|
///@{
|
||||||
|
@ -49,9 +87,10 @@ public:
|
||||||
//! Number of decimals left
|
//! Number of decimals left
|
||||||
static int decimals(int unit);
|
static int decimals(int unit);
|
||||||
//! Format as string
|
//! Format as string
|
||||||
static QString format(int unit, qint64 amount, bool plussign=false);
|
static QString format(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard, bool fAlign=false);
|
||||||
//! Format as string (with unit)
|
//! Format as string (with unit)
|
||||||
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
|
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard, bool fAlign=false);
|
||||||
|
static QString formatHtmlWithUnit(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
|
||||||
//! Parse string to coin amount
|
//! Parse string to coin amount
|
||||||
static bool parse(int unit, const QString &value, qint64 *val_out);
|
static bool parse(int unit, const QString &value, qint64 *val_out);
|
||||||
///@}
|
///@}
|
||||||
|
@ -67,6 +106,16 @@ public:
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
static QString removeSpaces(QString text)
|
||||||
|
{
|
||||||
|
text.remove(' ');
|
||||||
|
text.remove(QChar(THIN_SP_CP));
|
||||||
|
#if (THIN_SP_CP != REAL_THIN_SP_CP)
|
||||||
|
text.remove(QChar(REAL_THIN_SP_CP));
|
||||||
|
#endif
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<BitcoinUnits::Unit> unitlist;
|
QList<BitcoinUnits::Unit> unitlist;
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
foreground = option.palette.color(QPalette::Text);
|
foreground = option.palette.color(QPalette::Text);
|
||||||
}
|
}
|
||||||
painter->setPen(foreground);
|
painter->setPen(foreground);
|
||||||
QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true);
|
QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways, true);
|
||||||
if(!confirmed)
|
if(!confirmed)
|
||||||
{
|
{
|
||||||
amountText = QString("[") + amountText + QString("]");
|
amountText = QString("[") + amountText + QString("]");
|
||||||
|
@ -141,10 +141,10 @@ void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64
|
||||||
currentBalance = balance;
|
currentBalance = balance;
|
||||||
currentUnconfirmedBalance = unconfirmedBalance;
|
currentUnconfirmedBalance = unconfirmedBalance;
|
||||||
currentImmatureBalance = immatureBalance;
|
currentImmatureBalance = immatureBalance;
|
||||||
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways, true));
|
||||||
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
|
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance, false, BitcoinUnits::separatorAlways, true));
|
||||||
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance));
|
ui->labelImmature->setText(BitcoinUnits::formatWithUnit(unit, immatureBalance, false, BitcoinUnits::separatorAlways, true));
|
||||||
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance));
|
ui->labelTotal->setText(BitcoinUnits::formatWithUnit(unit, balance + unconfirmedBalance + immatureBalance, false, BitcoinUnits::separatorAlways, true));
|
||||||
|
|
||||||
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
|
// only show immature (newly mined) balance if it's non-zero, so as not to complicate things
|
||||||
// for the non-mining users
|
// for the non-mining users
|
||||||
|
|
|
@ -142,7 +142,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||||
foreach(const SendCoinsRecipient &rcp, recipients)
|
foreach(const SendCoinsRecipient &rcp, recipients)
|
||||||
{
|
{
|
||||||
// generate bold amount string
|
// generate bold amount string
|
||||||
QString amount = "<b>" + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
|
QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
|
||||||
amount.append("</b>");
|
amount.append("</b>");
|
||||||
// generate monospace address string
|
// generate monospace address string
|
||||||
QString address = "<span style='font-family: monospace;'>" + rcp.address;
|
QString address = "<span style='font-family: monospace;'>" + rcp.address;
|
||||||
|
@ -210,7 +210,7 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||||
{
|
{
|
||||||
// append fee string if a fee is required
|
// append fee string if a fee is required
|
||||||
questionString.append("<hr /><span style='color:#aa0000;'>");
|
questionString.append("<hr /><span style='color:#aa0000;'>");
|
||||||
questionString.append(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
|
questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
|
||||||
questionString.append("</span> ");
|
questionString.append("</span> ");
|
||||||
questionString.append(tr("added as transaction fee"));
|
questionString.append(tr("added as transaction fee"));
|
||||||
}
|
}
|
||||||
|
@ -222,10 +222,10 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||||
foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
|
foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
|
||||||
{
|
{
|
||||||
if(u != model->getOptionsModel()->getDisplayUnit())
|
if(u != model->getOptionsModel()->getDisplayUnit())
|
||||||
alternativeUnits.append(BitcoinUnits::formatWithUnit(u, totalAmount));
|
alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
|
||||||
}
|
}
|
||||||
questionString.append(tr("Total Amount %1 (= %2)")
|
questionString.append(tr("Total Amount %1 (= %2)")
|
||||||
.arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))
|
.arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))
|
||||||
.arg(alternativeUnits.join(" " + tr("or") + " ")));
|
.arg(alternativeUnits.join(" " + tr("or") + " ")));
|
||||||
|
|
||||||
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
|
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
|
||||||
|
|
|
@ -138,7 +138,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
nUnmatured += wallet->GetCredit(txout);
|
nUnmatured += wallet->GetCredit(txout);
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
||||||
if (wtx.IsInMainChain())
|
if (wtx.IsInMainChain())
|
||||||
strHTML += BitcoinUnits::formatWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
|
strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
|
||||||
else
|
else
|
||||||
strHTML += "(" + tr("not accepted") + ")";
|
strHTML += "(" + tr("not accepted") + ")";
|
||||||
strHTML += "<br>";
|
strHTML += "<br>";
|
||||||
|
@ -148,7 +148,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
//
|
//
|
||||||
// Credit
|
// Credit
|
||||||
//
|
//
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nNet) + "<br>";
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "<br>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -184,7 +184,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -txout.nValue) + "<br>";
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -txout.nValue) + "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fAllToMe)
|
if (fAllToMe)
|
||||||
|
@ -192,13 +192,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
// Payment to self
|
// Payment to self
|
||||||
int64_t nChange = wtx.GetChange();
|
int64_t nChange = wtx.GetChange();
|
||||||
int64_t nValue = nCredit - nChange;
|
int64_t nValue = nCredit - nChange;
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nValue) + "<br>";
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>";
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nValue) + "<br>";
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t nTxFee = nDebit - wtx.GetValueOut();
|
int64_t nTxFee = nDebit - wtx.GetValueOut();
|
||||||
if (nTxFee > 0)
|
if (nTxFee > 0)
|
||||||
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nTxFee) + "<br>";
|
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -207,14 +207,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
//
|
//
|
||||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||||
if (wallet->IsMine(txin))
|
if (wallet->IsMine(txin))
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
|
||||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||||
if (wallet->IsMine(txout))
|
if (wallet->IsMine(txout))
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nNet, true) + "<br>";
|
strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nNet, true) + "<br>";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Message
|
// Message
|
||||||
|
@ -260,10 +260,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
||||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||||
if(wallet->IsMine(txin))
|
if(wallet->IsMine(txin))
|
||||||
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
|
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin)) + "<br>";
|
||||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||||
if(wallet->IsMine(txout))
|
if(wallet->IsMine(txout))
|
||||||
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
|
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout)) + "<br>";
|
||||||
|
|
||||||
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
||||||
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
|
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
|
||||||
|
@ -289,7 +289,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
||||||
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
|
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
|
||||||
strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
|
strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
|
||||||
}
|
}
|
||||||
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(unit, vout.nValue);
|
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
|
||||||
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
|
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "transactiontablemodel.h"
|
#include "transactiontablemodel.h"
|
||||||
|
|
||||||
#include "addresstablemodel.h"
|
#include "addresstablemodel.h"
|
||||||
#include "bitcoinunits.h"
|
|
||||||
#include "guiconstants.h"
|
#include "guiconstants.h"
|
||||||
#include "guiutil.h"
|
#include "guiutil.h"
|
||||||
#include "optionsmodel.h"
|
#include "optionsmodel.h"
|
||||||
|
@ -425,9 +424,9 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed) const
|
QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators, bool fAlign) const
|
||||||
{
|
{
|
||||||
QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit);
|
QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators, fAlign);
|
||||||
if(showUnconfirmed)
|
if(showUnconfirmed)
|
||||||
{
|
{
|
||||||
if(!wtx->status.countsForBalance)
|
if(!wtx->status.countsForBalance)
|
||||||
|
@ -512,7 +511,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||||
case ToAddress:
|
case ToAddress:
|
||||||
return formatTxToAddress(rec, false);
|
return formatTxToAddress(rec, false);
|
||||||
case Amount:
|
case Amount:
|
||||||
return formatTxAmount(rec);
|
return formatTxAmount(rec, true, BitcoinUnits::separatorAlways, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
|
@ -569,7 +568,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
|
||||||
case ConfirmedRole:
|
case ConfirmedRole:
|
||||||
return rec->status.countsForBalance;
|
return rec->status.countsForBalance;
|
||||||
case FormattedAmountRole:
|
case FormattedAmountRole:
|
||||||
return formatTxAmount(rec, false);
|
// Used for copy/export, so don't include separators
|
||||||
|
return formatTxAmount(rec, false, BitcoinUnits::separatorNever);
|
||||||
case StatusRole:
|
case StatusRole:
|
||||||
return rec->status.status;
|
return rec->status.status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
|
||||||
class TransactionRecord;
|
class TransactionRecord;
|
||||||
class TransactionTablePriv;
|
class TransactionTablePriv;
|
||||||
class WalletModel;
|
class WalletModel;
|
||||||
|
@ -78,7 +80,7 @@ private:
|
||||||
QString formatTxDate(const TransactionRecord *wtx) const;
|
QString formatTxDate(const TransactionRecord *wtx) const;
|
||||||
QString formatTxType(const TransactionRecord *wtx) const;
|
QString formatTxType(const TransactionRecord *wtx) const;
|
||||||
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const;
|
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const;
|
||||||
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true) const;
|
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard, bool fAlign=false) const;
|
||||||
QString formatTooltip(const TransactionRecord *rec) const;
|
QString formatTooltip(const TransactionRecord *rec) const;
|
||||||
QVariant txStatusDecoration(const TransactionRecord *wtx) const;
|
QVariant txStatusDecoration(const TransactionRecord *wtx) const;
|
||||||
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
|
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
|
||||||
|
|
|
@ -123,6 +123,8 @@ TransactionView::TransactionView(QWidget *parent) :
|
||||||
view->setTabKeyNavigation(false);
|
view->setTabKeyNavigation(false);
|
||||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
view->installEventFilter(this);
|
||||||
|
|
||||||
transactionView = view;
|
transactionView = view;
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
@ -480,3 +482,22 @@ void TransactionView::resizeEvent(QResizeEvent* event)
|
||||||
QWidget::resizeEvent(event);
|
QWidget::resizeEvent(event);
|
||||||
columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
|
columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to override default Ctrl+C action for amount as default behaviour is just to copy DisplayRole text
|
||||||
|
bool TransactionView::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
||||||
|
if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier))
|
||||||
|
{
|
||||||
|
QModelIndex i = this->transactionView->currentIndex();
|
||||||
|
if (i.isValid() && i.column() == TransactionTableModel::Amount)
|
||||||
|
{
|
||||||
|
GUIUtil::setClipboard(i.data(TransactionTableModel::FormattedAmountRole).toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QWidget::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "guiutil.h"
|
#include "guiutil.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
class TransactionFilterProxy;
|
class TransactionFilterProxy;
|
||||||
class WalletModel;
|
class WalletModel;
|
||||||
|
@ -78,6 +79,8 @@ private:
|
||||||
|
|
||||||
virtual void resizeEvent(QResizeEvent* event);
|
virtual void resizeEvent(QResizeEvent* event);
|
||||||
|
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void contextualMenu(const QPoint &);
|
void contextualMenu(const QPoint &);
|
||||||
void dateRangeChanged();
|
void dateRangeChanged();
|
||||||
|
|
Loading…
Reference in a new issue