Skip to content

Commit 72477eb

Browse files
committed
Merge bitcoin-core/gui#556: refactor: Make BitcoinUnits::Unit a scoped enum
0e5dedb qt/wallettests: sort includes (William Casarin) 0554251 qt: Skip displayUnitChanged signal if unit is not actually changed (Hennadii Stepanov) ffbc2fe qt, refactor: Remove default cases for scoped enum (Hennadii Stepanov) 152d5ba qt, refactor: Remove BitcoinUnits::valid function (Hennadii Stepanov) aa23960 qt, refactor: Make BitcoinUnits::Unit a scoped enum (Hennadii Stepanov) 75832fd qt: Use QVariant instead of int for BitcoinUnit in QSettings (Hennadii Stepanov) Pull request description: This is a rebased version of #60 Since Qt 5.5 there are [means](https://doc.qt.io/qt-5/qobject.html#Q_ENUM) to register an enum type with the meta-object system (such enum still lacks an ability to interact with [QSettings::setValue()](https://doc.qt.io/qt-5/qsettings.html#setValue) and [QSettings::value()](https://doc.qt.io/qt-5/qsettings.html#value) without defined stream operators). In order to reduce global namespace polluting and to force strong type checking, this PR makes BitcoinUnits::Unit a scoped enum (typedef BitcoinUnits::Unit BitcoinUnit;). No behavior change. ACKs for top commit: jonatack: ACK 0e5dedb, review and debug build of each commit after rebase on current master, lightly tested running the GUI, changing units a few times, and verifying persistence after restarting promag: Code review ACK 0e5dedb Tree-SHA512: 39ec0d7e4f0b9b25be287888121a8db6b282339674e37ec3a3554da63a9e22d6fe079e8310ca289b2a0356a19b3c7e55afa17d09dd34e0f222177f603bb053a3
2 parents 7190de9 + 0e5dedb commit 72477eb

19 files changed

+188
-157
lines changed

src/qt/bitcoin.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ static void RegisterMetaTypes()
9595
qRegisterMetaType<std::function<void()>>("std::function<void()>");
9696
qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
9797
qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
98+
99+
qRegisterMetaTypeStreamOperators<BitcoinUnit>("BitcoinUnit");
98100
}
99101

100102
static QString GetLangTerritory()

src/qt/bitcoinamountfield.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include <QHBoxLayout>
1515
#include <QKeyEvent>
1616
#include <QLineEdit>
17+
#include <QVariant>
18+
19+
#include <cassert>
1720

1821
/** QSpinBox that uses fixed-point numbers internally and uses our own
1922
* formatting/parsing functions.
@@ -96,7 +99,7 @@ class AmountSpinBox: public QAbstractSpinBox
9699
setValue(val);
97100
}
98101

99-
void setDisplayUnit(int unit)
102+
void setDisplayUnit(BitcoinUnit unit)
100103
{
101104
bool valid = false;
102105
CAmount val = value(&valid);
@@ -122,7 +125,7 @@ class AmountSpinBox: public QAbstractSpinBox
122125

123126
const QFontMetrics fm(fontMetrics());
124127
int h = lineEdit()->minimumSizeHint().height();
125-
int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS));
128+
int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnit::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::SeparatorStyle::ALWAYS));
126129
w += 2; // cursor blinking space
127130

128131
QStyleOptionSpinBox opt;
@@ -148,7 +151,7 @@ class AmountSpinBox: public QAbstractSpinBox
148151
}
149152

150153
private:
151-
int currentUnit{BitcoinUnits::BTC};
154+
BitcoinUnit currentUnit{BitcoinUnit::BTC};
152155
CAmount singleStep{CAmount(100000)}; // satoshis
153156
mutable QSize cachedMinimumSizeHint;
154157
bool m_allow_empty{true};
@@ -326,14 +329,14 @@ void BitcoinAmountField::unitChanged(int idx)
326329
unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
327330

328331
// Determine new unit ID
329-
int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
330-
331-
amount->setDisplayUnit(newUnit);
332+
QVariant new_unit = unit->currentData(BitcoinUnits::UnitRole);
333+
assert(new_unit.isValid());
334+
amount->setDisplayUnit(new_unit.value<BitcoinUnit>());
332335
}
333336

334-
void BitcoinAmountField::setDisplayUnit(int newUnit)
337+
void BitcoinAmountField::setDisplayUnit(BitcoinUnit new_unit)
335338
{
336-
unit->setValue(newUnit);
339+
unit->setValue(QVariant::fromValue(new_unit));
337340
}
338341

339342
void BitcoinAmountField::setSingleStep(const CAmount& step)

src/qt/bitcoinamountfield.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define BITCOIN_QT_BITCOINAMOUNTFIELD_H
77

88
#include <consensus/amount.h>
9+
#include <qt/bitcoinunits.h>
910

1011
#include <QWidget>
1112

@@ -52,7 +53,7 @@ class BitcoinAmountField: public QWidget
5253
bool validate();
5354

5455
/** Change unit used to display amount. */
55-
void setDisplayUnit(int unit);
56+
void setDisplayUnit(BitcoinUnit new_unit);
5657

5758
/** Make field empty and ready for new input. */
5859
void clear();

src/qt/bitcoingui.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,7 @@ void BitcoinGUI::showEvent(QShowEvent *event)
12451245
}
12461246

12471247
#ifdef ENABLE_WALLET
1248-
void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
1248+
void BitcoinGUI::incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName)
12491249
{
12501250
// On new transaction, make an info balloon
12511251
QString msg = tr("Date: %1\n").arg(date) +
@@ -1496,11 +1496,10 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl
14961496
{
14971497
createContextMenu();
14981498
setToolTip(tr("Unit to show amounts in. Click to select another unit."));
1499-
QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
1499+
QList<BitcoinUnit> units = BitcoinUnits::availableUnits();
15001500
int max_width = 0;
15011501
const QFontMetrics fm(font());
1502-
for (const BitcoinUnits::Unit unit : units)
1503-
{
1502+
for (const BitcoinUnit unit : units) {
15041503
max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
15051504
}
15061505
setMinimumSize(max_width, 0);
@@ -1530,8 +1529,8 @@ void UnitDisplayStatusBarControl::changeEvent(QEvent* e)
15301529
void UnitDisplayStatusBarControl::createContextMenu()
15311530
{
15321531
menu = new QMenu(this);
1533-
for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) {
1534-
menu->addAction(BitcoinUnits::longName(u))->setData(QVariant(u));
1532+
for (const BitcoinUnit u : BitcoinUnits::availableUnits()) {
1533+
menu->addAction(BitcoinUnits::longName(u))->setData(QVariant::fromValue(u));
15351534
}
15361535
connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection);
15371536
}
@@ -1552,7 +1551,7 @@ void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel)
15521551
}
15531552

15541553
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
1555-
void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
1554+
void UnitDisplayStatusBarControl::updateDisplayUnit(BitcoinUnit newUnits)
15561555
{
15571556
setText(BitcoinUnits::longName(newUnits));
15581557
}

src/qt/bitcoingui.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <config/bitcoin-config.h>
1010
#endif
1111

12+
#include <qt/bitcoinunits.h>
1213
#include <qt/guiutil.h>
1314
#include <qt/optionsdialog.h>
1415

@@ -260,7 +261,7 @@ public Q_SLOTS:
260261
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
261262

262263
/** Show incoming transaction notification for new transactions. */
263-
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
264+
void incomingTransaction(const QString& date, BitcoinUnit unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName);
264265
#endif // ENABLE_WALLET
265266

266267
private:
@@ -341,7 +342,7 @@ class UnitDisplayStatusBarControl : public QLabel
341342

342343
private Q_SLOTS:
343344
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
344-
void updateDisplayUnit(int newUnits);
345+
void updateDisplayUnit(BitcoinUnit newUnits);
345346
/** Tells underlying optionsModel to update its current display unit. */
346347
void onMenuSelection(QAction* action);
347348
};

src/qt/bitcoinunits.cpp

Lines changed: 93 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,94 +18,75 @@ BitcoinUnits::BitcoinUnits(QObject *parent):
1818
{
1919
}
2020

21-
QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
21+
QList<BitcoinUnit> BitcoinUnits::availableUnits()
2222
{
23-
QList<BitcoinUnits::Unit> unitlist;
24-
unitlist.append(BTC);
25-
unitlist.append(mBTC);
26-
unitlist.append(uBTC);
27-
unitlist.append(SAT);
23+
QList<BitcoinUnit> unitlist;
24+
unitlist.append(Unit::BTC);
25+
unitlist.append(Unit::mBTC);
26+
unitlist.append(Unit::uBTC);
27+
unitlist.append(Unit::SAT);
2828
return unitlist;
2929
}
3030

31-
bool BitcoinUnits::valid(int unit)
31+
QString BitcoinUnits::longName(Unit unit)
3232
{
33-
switch(unit)
34-
{
35-
case BTC:
36-
case mBTC:
37-
case uBTC:
38-
case SAT:
39-
return true;
40-
default:
41-
return false;
42-
}
43-
}
44-
45-
QString BitcoinUnits::longName(int unit)
46-
{
47-
switch(unit)
48-
{
49-
case BTC: return QString("BTC");
50-
case mBTC: return QString("mBTC");
51-
case uBTC: return QString::fromUtf8("µBTC (bits)");
52-
case SAT: return QString("Satoshi (sat)");
53-
default: return QString("???");
54-
}
33+
switch (unit) {
34+
case Unit::BTC: return QString("BTC");
35+
case Unit::mBTC: return QString("mBTC");
36+
case Unit::uBTC: return QString::fromUtf8("µBTC (bits)");
37+
case Unit::SAT: return QString("Satoshi (sat)");
38+
} // no default case, so the compiler can warn about missing cases
39+
assert(false);
5540
}
5641

57-
QString BitcoinUnits::shortName(int unit)
42+
QString BitcoinUnits::shortName(Unit unit)
5843
{
59-
switch(unit)
60-
{
61-
case uBTC: return QString::fromUtf8("bits");
62-
case SAT: return QString("sat");
63-
default: return longName(unit);
64-
}
44+
switch (unit) {
45+
case Unit::BTC: return longName(unit);
46+
case Unit::mBTC: return longName(unit);
47+
case Unit::uBTC: return QString("bits");
48+
case Unit::SAT: return QString("sat");
49+
} // no default case, so the compiler can warn about missing cases
50+
assert(false);
6551
}
6652

67-
QString BitcoinUnits::description(int unit)
53+
QString BitcoinUnits::description(Unit unit)
6854
{
69-
switch(unit)
70-
{
71-
case BTC: return QString("Bitcoins");
72-
case mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
73-
case uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
74-
case SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
75-
default: return QString("???");
76-
}
55+
switch (unit) {
56+
case Unit::BTC: return QString("Bitcoins");
57+
case Unit::mBTC: return QString("Milli-Bitcoins (1 / 1" THIN_SP_UTF8 "000)");
58+
case Unit::uBTC: return QString("Micro-Bitcoins (bits) (1 / 1" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
59+
case Unit::SAT: return QString("Satoshi (sat) (1 / 100" THIN_SP_UTF8 "000" THIN_SP_UTF8 "000)");
60+
} // no default case, so the compiler can warn about missing cases
61+
assert(false);
7762
}
7863

79-
qint64 BitcoinUnits::factor(int unit)
64+
qint64 BitcoinUnits::factor(Unit unit)
8065
{
81-
switch(unit)
82-
{
83-
case BTC: return 100000000;
84-
case mBTC: return 100000;
85-
case uBTC: return 100;
86-
case SAT: return 1;
87-
default: return 100000000;
88-
}
66+
switch (unit) {
67+
case Unit::BTC: return 100'000'000;
68+
case Unit::mBTC: return 100'000;
69+
case Unit::uBTC: return 100;
70+
case Unit::SAT: return 1;
71+
} // no default case, so the compiler can warn about missing cases
72+
assert(false);
8973
}
9074

91-
int BitcoinUnits::decimals(int unit)
75+
int BitcoinUnits::decimals(Unit unit)
9276
{
93-
switch(unit)
94-
{
95-
case BTC: return 8;
96-
case mBTC: return 5;
97-
case uBTC: return 2;
98-
case SAT: return 0;
99-
default: return 0;
100-
}
77+
switch (unit) {
78+
case Unit::BTC: return 8;
79+
case Unit::mBTC: return 5;
80+
case Unit::uBTC: return 2;
81+
case Unit::SAT: return 0;
82+
} // no default case, so the compiler can warn about missing cases
83+
assert(false);
10184
}
10285

103-
QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify)
86+
QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool justify)
10487
{
10588
// Note: not using straight sprintf here because we do NOT want
10689
// localized number formatting.
107-
if(!valid(unit))
108-
return QString(); // Refuse to format invalid unit
10990
qint64 n = (qint64)nIn;
11091
qint64 coin = factor(unit);
11192
int num_decimals = decimals(unit);
@@ -147,19 +128,19 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
147128
// Please take care to use formatHtmlWithUnit instead, when
148129
// appropriate.
149130

150-
QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
131+
QString BitcoinUnits::formatWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
151132
{
152133
return format(unit, amount, plussign, separators) + QString(" ") + shortName(unit);
153134
}
154135

155-
QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
136+
QString BitcoinUnits::formatHtmlWithUnit(Unit unit, const CAmount& amount, bool plussign, SeparatorStyle separators)
156137
{
157138
QString str(formatWithUnit(unit, amount, plussign, separators));
158139
str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML));
159140
return QString("<span style='white-space: nowrap;'>%1</span>").arg(str);
160141
}
161142

162-
QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, SeparatorStyle separators, bool privacy)
143+
QString BitcoinUnits::formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy)
163144
{
164145
assert(amount >= 0);
165146
QString value;
@@ -171,10 +152,11 @@ QString BitcoinUnits::formatWithPrivacy(int unit, const CAmount& amount, Separat
171152
return value + QString(" ") + shortName(unit);
172153
}
173154

174-
bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
155+
bool BitcoinUnits::parse(Unit unit, const QString& value, CAmount* val_out)
175156
{
176-
if(!valid(unit) || value.isEmpty())
157+
if (value.isEmpty()) {
177158
return false; // Refuse to parse invalid unit or empty string
159+
}
178160
int num_decimals = decimals(unit);
179161

180162
// Ignore spaces and thin spaces when parsing
@@ -210,14 +192,9 @@ bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out)
210192
return ok;
211193
}
212194

213-
QString BitcoinUnits::getAmountColumnTitle(int unit)
195+
QString BitcoinUnits::getAmountColumnTitle(Unit unit)
214196
{
215-
QString amountTitle = QObject::tr("Amount");
216-
if (BitcoinUnits::valid(unit))
217-
{
218-
amountTitle += " ("+BitcoinUnits::shortName(unit) + ")";
219-
}
220-
return amountTitle;
197+
return QObject::tr("Amount") + " (" + shortName(unit) + ")";
221198
}
222199

223200
int BitcoinUnits::rowCount(const QModelIndex &parent) const
@@ -240,7 +217,7 @@ QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
240217
case Qt::ToolTipRole:
241218
return QVariant(description(unit));
242219
case UnitRole:
243-
return QVariant(static_cast<int>(unit));
220+
return QVariant::fromValue(unit);
244221
}
245222
}
246223
return QVariant();
@@ -250,3 +227,40 @@ CAmount BitcoinUnits::maxMoney()
250227
{
251228
return MAX_MONEY;
252229
}
230+
231+
namespace {
232+
qint8 ToQint8(BitcoinUnit unit)
233+
{
234+
switch (unit) {
235+
case BitcoinUnit::BTC: return 0;
236+
case BitcoinUnit::mBTC: return 1;
237+
case BitcoinUnit::uBTC: return 2;
238+
case BitcoinUnit::SAT: return 3;
239+
} // no default case, so the compiler can warn about missing cases
240+
assert(false);
241+
}
242+
243+
BitcoinUnit FromQint8(qint8 num)
244+
{
245+
switch (num) {
246+
case 0: return BitcoinUnit::BTC;
247+
case 1: return BitcoinUnit::mBTC;
248+
case 2: return BitcoinUnit::uBTC;
249+
case 3: return BitcoinUnit::SAT;
250+
}
251+
assert(false);
252+
}
253+
} // namespace
254+
255+
QDataStream& operator<<(QDataStream& out, const BitcoinUnit& unit)
256+
{
257+
return out << ToQint8(unit);
258+
}
259+
260+
QDataStream& operator>>(QDataStream& in, BitcoinUnit& unit)
261+
{
262+
qint8 input;
263+
in >> input;
264+
unit = FromQint8(input);
265+
return in;
266+
}

0 commit comments

Comments
 (0)