Improve balance formatting in the UI.
This commit is contained in:
parent
511a8ed75b
commit
a695d0f52b
6 changed files with 193 additions and 16 deletions
|
@ -13,6 +13,43 @@ TEST (uint128_union, decode_dec)
|
|||
ASSERT_EQ (16, value.bytes [15]);
|
||||
}
|
||||
|
||||
struct test_punct : std::moneypunct<char> {
|
||||
pattern do_pos_format () const { return { {value, none, none, none} }; }
|
||||
int do_frac_digits () const { return 0; }
|
||||
char_type do_decimal_point () const { return '+'; }
|
||||
char_type do_thousands_sep () const { return '-'; }
|
||||
string_type do_grouping () const { return "\3\4"; }
|
||||
};
|
||||
|
||||
TEST (uint128_union, balance_format)
|
||||
{
|
||||
ASSERT_EQ ("0", rai::amount (rai::uint128_t ("0")).format_balance (rai::Mxrb_ratio, 0, false));
|
||||
ASSERT_EQ ("0", rai::amount (rai::uint128_t ("0")).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("340,282,366", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (rai::Mxrb_ratio, 0, true));
|
||||
ASSERT_EQ ("340,282,366.920938463463374607431768211455", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (rai::Mxrb_ratio, 64, true));
|
||||
ASSERT_EQ ("340,282,366,920,938,463,463,374,607,431,768,211,455", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (1, 4, true));
|
||||
ASSERT_EQ ("340,282,366", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (rai::Mxrb_ratio, 0, true));
|
||||
ASSERT_EQ ("340,282,366.920938463463374607431768211454", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (rai::Mxrb_ratio, 64, true));
|
||||
ASSERT_EQ ("340282366920938463463374607431768211454", rai::amount (rai::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (1, 4, false));
|
||||
ASSERT_EQ ("170,141,183", rai::amount (rai::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (rai::Mxrb_ratio, 0, true));
|
||||
ASSERT_EQ ("170,141,183.460469231731687303715884105726", rai::amount (rai::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (rai::Mxrb_ratio, 64, true));
|
||||
ASSERT_EQ ("170141183460469231731687303715884105726", rai::amount (rai::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (1, 4, false));
|
||||
ASSERT_EQ ("1", rai::amount (rai::uint128_t ("1000000000000000000000000000000")).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("1.2", rai::amount (rai::uint128_t ("1200000000000000000000000000000")).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("1.23", rai::amount (rai::uint128_t ("1230000000000000000000000000000")).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("1.2", rai::amount (rai::uint128_t ("1230000000000000000000000000000")).format_balance (rai::Mxrb_ratio, 1, true));
|
||||
ASSERT_EQ ("1", rai::amount (rai::uint128_t ("1230000000000000000000000000000")).format_balance (rai::Mxrb_ratio, 0, true));
|
||||
ASSERT_EQ ("< 0.01", rai::amount (rai::xrb_ratio * 10).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("< 0.1", rai::amount (rai::xrb_ratio * 10).format_balance (rai::Mxrb_ratio, 1, true));
|
||||
ASSERT_EQ ("< 1", rai::amount (rai::xrb_ratio * 10).format_balance (rai::Mxrb_ratio, 0, true));
|
||||
ASSERT_EQ ("< 0.01", rai::amount (rai::xrb_ratio * 9999).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("0.01", rai::amount (rai::xrb_ratio * 10000).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("123456789", rai::amount (rai::Mxrb_ratio * 123456789).format_balance (rai::Mxrb_ratio, 2, false));
|
||||
ASSERT_EQ ("123,456,789", rai::amount (rai::Mxrb_ratio * 123456789).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("123,456,789.12", rai::amount (rai::Mxrb_ratio * 123456789 + rai::kxrb_ratio * 123).format_balance (rai::Mxrb_ratio, 2, true));
|
||||
ASSERT_EQ ("12-3456-789+123", rai::amount (rai::Mxrb_ratio * 123456789 + rai::kxrb_ratio * 123).format_balance (rai::Mxrb_ratio, 4, true, std::locale (std::cout.getloc (), new test_punct)));
|
||||
}
|
||||
|
||||
TEST (unions, identity)
|
||||
{
|
||||
ASSERT_EQ (1, rai::uint128_union (1).number ().convert_to <uint8_t> ());
|
||||
|
|
|
@ -311,6 +311,10 @@ bool rai::uint256_union::decode_dec (std::string const & text)
|
|||
{
|
||||
stream >> number_l;
|
||||
*this = number_l;
|
||||
if (!stream.eof ())
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error &)
|
||||
{
|
||||
|
@ -570,6 +574,10 @@ bool rai::uint128_union::decode_dec (std::string const & text)
|
|||
{
|
||||
stream >> number_l;
|
||||
*this = number_l;
|
||||
if (!stream.eof ())
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error &)
|
||||
{
|
||||
|
@ -579,6 +587,114 @@ bool rai::uint128_union::decode_dec (std::string const & text)
|
|||
return result;
|
||||
}
|
||||
|
||||
void format_frac(std::ostringstream & stream, rai::uint128_t value, rai::uint128_t scale, int precision) {
|
||||
auto reduce = scale;
|
||||
auto rem = value;
|
||||
while (reduce > 1 && rem > 0 && precision > 0) {
|
||||
reduce /= 10;
|
||||
auto val = rem / reduce;
|
||||
rem -= val * reduce;
|
||||
stream << val;
|
||||
precision--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void format_dec(std::ostringstream & stream, rai::uint128_t value, char group_sep, const std::string & groupings) {
|
||||
auto largestPow10 = rai::uint256_t (1);
|
||||
int dec_count = 1;
|
||||
while (1) {
|
||||
auto next = largestPow10 * 10;
|
||||
if (next > value) {
|
||||
break;
|
||||
}
|
||||
largestPow10 = next;
|
||||
dec_count++;
|
||||
}
|
||||
|
||||
if (dec_count > 39) {
|
||||
// Impossible.
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be cached per-locale.
|
||||
bool emit_group[39];
|
||||
if (group_sep != 0) {
|
||||
int group_index = 0;
|
||||
int group_count = 0;
|
||||
for (int i = 0; i < dec_count; i++) {
|
||||
int groupMax = groupings [group_index];
|
||||
group_count++;
|
||||
if (group_count > groupings [group_index]) {
|
||||
group_index = std::min (group_index + 1, (int)groupings.length() - 1);
|
||||
group_count = 1;
|
||||
emit_group [i] = true;
|
||||
} else {
|
||||
emit_group [i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto reduce = rai::uint128_t(largestPow10);
|
||||
rai::uint128_t rem = value;
|
||||
while (reduce > 0) {
|
||||
auto val = rem / reduce;
|
||||
rem -= val * reduce;
|
||||
stream << val;
|
||||
dec_count--;
|
||||
if (group_sep != 0 && emit_group [dec_count] && reduce > 1) {
|
||||
stream << group_sep;
|
||||
}
|
||||
reduce /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
std::string format_balance (rai::uint128_t balance, rai::uint128_t scale, int precision, bool group_digits, char thousands_sep, char decimal_point, std::string & grouping)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
auto int_part = balance / scale;
|
||||
auto frac_part = balance % scale;
|
||||
auto prec_scale = scale;
|
||||
for (int i = 0; i < precision; i++) {
|
||||
prec_scale /= 10;
|
||||
}
|
||||
if (int_part == 0 && frac_part > 0 && frac_part / prec_scale == 0) {
|
||||
// Display e.g. "< 0.01" rather than 0.
|
||||
stream << "< ";
|
||||
if (precision > 0) {
|
||||
stream << "0";
|
||||
stream << decimal_point;
|
||||
for (int i = 0; i < precision - 1; i++) {
|
||||
stream << "0";
|
||||
}
|
||||
}
|
||||
stream << "1";
|
||||
} else {
|
||||
format_dec (stream, int_part, group_digits && grouping.length () > 0 ? thousands_sep : 0, grouping);
|
||||
if (precision > 0 && frac_part > 0) {
|
||||
stream << decimal_point;
|
||||
format_frac (stream, frac_part, scale, precision);
|
||||
}
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string rai::uint128_union::format_balance(rai::uint128_t scale, int precision, bool group_digits)
|
||||
{
|
||||
auto thousands_sep = std::use_facet< std::numpunct<char> >(std::locale ()).thousands_sep ();
|
||||
auto decimal_point = std::use_facet< std::numpunct<char> >(std::locale ()).decimal_point ();
|
||||
std::string grouping = "\3";
|
||||
return ::format_balance (number (), scale, precision, group_digits, thousands_sep, decimal_point, grouping);
|
||||
}
|
||||
|
||||
std::string rai::uint128_union::format_balance (rai::uint128_t scale, int precision, bool group_digits, const std::locale & locale)
|
||||
{
|
||||
auto thousands_sep = std::use_facet< std::moneypunct<char> >(locale).thousands_sep ();
|
||||
auto decimal_point = std::use_facet< std::moneypunct<char> >(locale).decimal_point ();
|
||||
std::string grouping = std::use_facet< std::moneypunct<char> >(locale).grouping ();
|
||||
return ::format_balance (number (), scale, precision, group_digits, thousands_sep, decimal_point, grouping);
|
||||
}
|
||||
|
||||
void rai::uint128_union::clear ()
|
||||
{
|
||||
qwords.fill (0);
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
bool decode_hex (std::string const &);
|
||||
void encode_dec (std::string &) const;
|
||||
bool decode_dec (std::string const &);
|
||||
std::string format_balance (rai::uint128_t scale, int precision, bool group_digits);
|
||||
std::string format_balance (rai::uint128_t scale, int precision, bool group_digits, const std::locale & locale);
|
||||
rai::uint128_t number () const;
|
||||
void clear ();
|
||||
bool is_zero () const;
|
||||
|
|
|
@ -104,10 +104,10 @@ wallet (wallet_a)
|
|||
void rai_qt::self_pane::refresh_balance ()
|
||||
{
|
||||
auto balance (wallet.node.balance_pending (wallet.account));
|
||||
auto final_text (std::string ("Balance (XRB): ") + (balance.first / wallet.rendering_ratio).convert_to <std::string> ());
|
||||
auto final_text (std::string ("Balance: ") + wallet.format_balance (balance.first));
|
||||
if (!balance.second.is_zero ())
|
||||
{
|
||||
final_text += "\nPending: " + (balance.second / wallet.rendering_ratio).convert_to <std::string> ();
|
||||
final_text += "\nPending: " + wallet.format_balance (balance.second);
|
||||
}
|
||||
wallet.self.balance_label->setText (QString (final_text.c_str ()));
|
||||
}
|
||||
|
@ -253,10 +253,10 @@ void rai_qt::accounts::refresh_wallet_balance ()
|
|||
balance = balance + (this->wallet.node.ledger.account_balance (transaction, key));
|
||||
pending = pending + (this->wallet.node.ledger.account_pending (transaction, key));
|
||||
}
|
||||
auto final_text (std::string ("Wallet balance (XRB): ") + (balance / this->wallet.rendering_ratio).convert_to <std::string> ());
|
||||
auto final_text (std::string ("Wallet balance (XRB): ") + wallet.format_balance (balance));
|
||||
if (!pending.is_zero ())
|
||||
{
|
||||
final_text += "\nWallet pending: " + (pending / this->wallet.rendering_ratio).convert_to <std::string> ();
|
||||
final_text += "\nWallet pending: " + wallet.format_balance (pending);
|
||||
}
|
||||
wallet_balance_label->setText (QString (final_text.c_str ()));
|
||||
this->wallet.node.alarm.add (std::chrono::system_clock::now () + std::chrono::seconds (60), [this] ()
|
||||
|
@ -295,8 +295,7 @@ void rai_qt::accounts::refresh ()
|
|||
if (display)
|
||||
{
|
||||
QList <QStandardItem *> items;
|
||||
std::string balance;
|
||||
rai::amount (balance_amount / wallet.rendering_ratio).encode_dec (balance);
|
||||
std::string balance = wallet.format_balance (balance_amount);
|
||||
items.push_back (new QStandardItem (balance.c_str ()));
|
||||
auto account (new QStandardItem (QString (key.to_account ().c_str ())));
|
||||
account->setForeground (brush);
|
||||
|
@ -467,7 +466,7 @@ wallet (wallet_a)
|
|||
});
|
||||
}
|
||||
|
||||
rai_qt::history::history (rai::ledger & ledger_a, rai::account const & account_a, rai::uint128_t const & rendering_ratio_a) :
|
||||
rai_qt::history::history (rai::ledger & ledger_a, rai::account const & account_a, rai_qt::wallet & wallet_a) :
|
||||
window (new QWidget),
|
||||
layout (new QVBoxLayout),
|
||||
model (new QStandardItemModel),
|
||||
|
@ -478,7 +477,7 @@ tx_label (new QLabel ("Account history count:")),
|
|||
tx_count (new QSpinBox),
|
||||
ledger (ledger_a),
|
||||
account (account_a),
|
||||
rendering_ratio (rendering_ratio_a)
|
||||
wallet (wallet_a)
|
||||
{/*
|
||||
tx_count->setRange (1, 256);
|
||||
tx_layout->addWidget (tx_label);
|
||||
|
@ -564,7 +563,7 @@ void rai_qt::history::refresh ()
|
|||
block->visit (visitor);
|
||||
items.push_back (new QStandardItem (QString (visitor.type.c_str ())));
|
||||
items.push_back (new QStandardItem (QString (visitor.account.to_account ().c_str ())));
|
||||
items.push_back (new QStandardItem (QString (rai::amount (visitor.amount / rendering_ratio).to_string_dec ().c_str ())));
|
||||
items.push_back (new QStandardItem (QString (wallet.format_balance (visitor.amount).c_str())));
|
||||
items.push_back (new QStandardItem (QString (hash.to_string ().c_str ())));
|
||||
hash = block->previous ();
|
||||
model->appendRow (items);
|
||||
|
@ -678,7 +677,7 @@ refresh (new QPushButton ("Refresh")),
|
|||
balance_window (new QWidget),
|
||||
balance_layout (new QHBoxLayout),
|
||||
balance_label (new QLabel),
|
||||
history (wallet_a.wallet_m->node.ledger, account, wallet_a.rendering_ratio),
|
||||
history (wallet_a.wallet_m->node.ledger, account, wallet_a),
|
||||
back (new QPushButton ("Back")),
|
||||
account (wallet_a.account),
|
||||
wallet (wallet_a)
|
||||
|
@ -706,10 +705,10 @@ wallet (wallet_a)
|
|||
show_line_ok (*account_line);
|
||||
this->history.refresh ();
|
||||
auto balance (this->wallet.node.balance_pending (account));
|
||||
auto final_text (std::string ("Balance (XRB): ") + (balance.first / this->wallet.rendering_ratio).convert_to <std::string> ());
|
||||
auto final_text (std::string ("Balance (XRB): ") + wallet.format_balance (balance.first));
|
||||
if (!balance.second.is_zero ())
|
||||
{
|
||||
final_text += "\nPending: " + (balance.second / this->wallet.rendering_ratio).convert_to <std::string> ();
|
||||
final_text += "\nPending: " + wallet.format_balance (balance.second);
|
||||
}
|
||||
balance_label->setText (QString (final_text.c_str ()));
|
||||
}
|
||||
|
@ -840,7 +839,7 @@ node (node_a),
|
|||
wallet_m (wallet_a),
|
||||
account (account_a),
|
||||
processor (processor_a),
|
||||
history (node.ledger, account, rendering_ratio),
|
||||
history (node.ledger, account, *this),
|
||||
accounts (*this),
|
||||
self (*this, account_a),
|
||||
settings (*this),
|
||||
|
@ -1257,6 +1256,18 @@ void rai_qt::wallet::change_rendering_ratio (rai::uint128_t const & rendering_ra
|
|||
}));
|
||||
}
|
||||
|
||||
std::string rai_qt::wallet::format_balance (rai::uint128_t const & balance) const
|
||||
{
|
||||
auto balance_str = rai::amount (balance).format_balance (rendering_ratio, 2, true, std::locale (""));
|
||||
auto unit = std::string ("XRB");
|
||||
if (rendering_ratio == rai::kxrb_ratio) {
|
||||
unit = std::string ("kxrb");
|
||||
} else if (rendering_ratio == rai::xrb_ratio) {
|
||||
unit = std::string ("xrb");
|
||||
}
|
||||
return balance_str + " " + unit;
|
||||
}
|
||||
|
||||
void rai_qt::wallet::push_main_stack (QWidget * widget_a)
|
||||
{
|
||||
main_stack->addWidget (widget_a);
|
||||
|
|
|
@ -207,7 +207,7 @@ namespace rai_qt {
|
|||
class history
|
||||
{
|
||||
public:
|
||||
history (rai::ledger &, rai::account const &, rai::uint128_t const &);
|
||||
history (rai::ledger &, rai::account const &, rai_qt::wallet &);
|
||||
void refresh ();
|
||||
QWidget * window;
|
||||
QVBoxLayout * layout;
|
||||
|
@ -219,7 +219,7 @@ namespace rai_qt {
|
|||
QSpinBox * tx_count;
|
||||
rai::ledger & ledger;
|
||||
rai::account const & account;
|
||||
rai::uint128_t const & rendering_ratio;
|
||||
rai_qt::wallet & wallet;
|
||||
};
|
||||
class block_viewer
|
||||
{
|
||||
|
@ -288,6 +288,7 @@ namespace rai_qt {
|
|||
void update_connected ();
|
||||
void empty_password ();
|
||||
void change_rendering_ratio (rai::uint128_t const &);
|
||||
std::string format_balance (rai::uint128_t const &) const;
|
||||
rai::uint128_t rendering_ratio;
|
||||
rai::node & node;
|
||||
std::shared_ptr <rai::wallet> wallet_m;
|
||||
|
|
|
@ -436,6 +436,16 @@ TEST (wallet, create_change)
|
|||
TEST (history, short_text)
|
||||
{
|
||||
bool init;
|
||||
rai_qt::eventloop_processor processor;
|
||||
rai::keypair key;
|
||||
rai::system system (24000, 1);
|
||||
system.wallet (0)->insert_adhoc (key.prv);
|
||||
rai::account account;
|
||||
{
|
||||
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, false);
|
||||
account = system.account (transaction, 0);
|
||||
}
|
||||
auto wallet (std::make_shared <rai_qt::wallet> (*test_application, processor, *system.nodes [0], system.wallet (0), account));
|
||||
rai::block_store store (init, rai::unique_path ());
|
||||
ASSERT_TRUE (!init);
|
||||
rai::genesis genesis;
|
||||
|
@ -451,7 +461,7 @@ TEST (history, short_text)
|
|||
rai::change_block change (receive.hash (), key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
|
||||
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, change).code);
|
||||
}
|
||||
rai_qt::history history (ledger, rai::test_genesis_key.pub, rai::Gxrb_ratio);
|
||||
rai_qt::history history (ledger, rai::test_genesis_key.pub, *wallet);
|
||||
history.refresh ();
|
||||
ASSERT_EQ (4, history.model->rowCount ());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue