Fix ZEC double precision display, add validations
This commit is contained in:
@@ -18,7 +18,7 @@ void BalancesTableModel::setNewData(const QMap<QString, double>* balances,
|
||||
delete modeldata;
|
||||
modeldata = new QList<std::tuple<QString, QString>>();
|
||||
std::for_each(balances->constKeyValueBegin(), balances->constKeyValueEnd(), [=] (auto it) {
|
||||
modeldata->push_back(std::make_tuple(it.first, QString::number(it.second, 'f')));
|
||||
modeldata->push_back(std::make_tuple(it.first, QString::number(it.second, 'g', 8)));
|
||||
});
|
||||
|
||||
// And then update the data
|
||||
|
||||
12
src/main.cpp
12
src/main.cpp
@@ -3,6 +3,13 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QFontDatabase::addApplicationFont(":/fonts/res/Ubuntu-R.ttf");
|
||||
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
|
||||
#endif
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
|
||||
@@ -10,11 +17,6 @@ int main(int argc, char *argv[])
|
||||
QCoreApplication::setOrganizationDomain("adityapk.com");
|
||||
QCoreApplication::setApplicationName("zcash-qt-wallet");
|
||||
|
||||
QApplication a(argc, argv);
|
||||
#ifdef Q_OS_LINUX
|
||||
QFontDatabase::addApplicationFont(":/fonts/res/Ubuntu-R.ttf");
|
||||
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
|
||||
#endif
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
@@ -70,7 +70,10 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
});
|
||||
|
||||
// Set up exit action
|
||||
QObject::connect(ui->actionExit, &QAction::triggered, [=] { this->close(); });
|
||||
QObject::connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||
|
||||
// Set up donate action
|
||||
QObject::connect(ui->actionDonate, &QAction::triggered, this, &MainWindow::donate);
|
||||
|
||||
// Set up about action
|
||||
QObject::connect(ui->actionAbout, &QAction::triggered, [=] () {
|
||||
@@ -97,6 +100,18 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
rpc->refresh();
|
||||
}
|
||||
|
||||
void MainWindow::donate() {
|
||||
// Set up a donation to me :)
|
||||
ui->Address1->setText("zcEgrceTwvoiFdEvPWcsJHAMrpLsprMF6aRJiQa3fan5ZphyXLPuHghnEPrEPRoEVzUy65GnMVyCTRdkT6BYBepnXh6NBYs");
|
||||
ui->Address1->setCursorPosition(0);
|
||||
ui->Amount1->setText("0.01");
|
||||
|
||||
ui->statusBar->showMessage("Donate 0.01 ZEC to support zcash-qt-wallet");
|
||||
|
||||
// And switch to the send tab.
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void MainWindow::setupBalancesTab() {
|
||||
ui->unconfirmedWarning->setVisible(false);
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ private:
|
||||
void addAddressSection();
|
||||
void maxAmountChecked(int checked);
|
||||
|
||||
QString doSendTxValidations(QString fromAddr, QList<QPair<QString, double>> toAddrs);
|
||||
|
||||
void donate();
|
||||
|
||||
RPC* rpc;
|
||||
Settings* settings;
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>838</width>
|
||||
<height>595</height>
|
||||
<width>889</width>
|
||||
<height>603</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -18,7 +18,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
@@ -247,8 +247,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>774</width>
|
||||
<height>276</height>
|
||||
<width>772</width>
|
||||
<height>218</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="sendToLayout">
|
||||
@@ -610,8 +610,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>838</width>
|
||||
<height>21</height>
|
||||
<width>889</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuBalance">
|
||||
@@ -626,6 +626,7 @@
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionDonate"/>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<addaction name="menuBalance"/>
|
||||
@@ -647,6 +648,11 @@
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDonate">
|
||||
<property name="text">
|
||||
<string>Donate</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<tabstops>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QScrollBar>
|
||||
#include <QPainter>
|
||||
#include <QMovie>
|
||||
#include <QPair>
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
#include <QFile>
|
||||
|
||||
21
src/rpc.cpp
21
src/rpc.cpp
@@ -341,7 +341,7 @@ void RPC::refreshBalances() {
|
||||
UnspentOutput(
|
||||
qsAddr,
|
||||
QString::fromStdString(it["txid"]),
|
||||
QString::number(it["amount"].get<json::number_float_t>(), 'f', 8),
|
||||
QString::number(it["amount"].get<json::number_float_t>(), 'g', 8),
|
||||
confirmations
|
||||
)
|
||||
);
|
||||
@@ -361,7 +361,7 @@ void RPC::refreshBalances() {
|
||||
ui->inputsCombo->clear();
|
||||
auto i = allBalances->constBegin();
|
||||
while (i != allBalances->constEnd()) {
|
||||
QString item = i.key() % "(" % QString::number(i.value(), 'f') % " ZEC)";
|
||||
QString item = i.key() % "(" % QString::number(i.value(), 'g', 8) % " ZEC)";
|
||||
ui->inputsCombo->addItem(item);
|
||||
if (item.startsWith(lastFromAddr)) ui->inputsCombo->setCurrentText(item);
|
||||
|
||||
@@ -417,13 +417,7 @@ void RPC::refreshTxStatus(const QString& newOpid) {
|
||||
};
|
||||
|
||||
doRPC(payload, [=] (const json& reply) {
|
||||
// If there is some op that we are watching, then show the loading bar, otherwise hide it
|
||||
if (watchingOps.isEmpty()) {
|
||||
main->loadingLabel->setVisible(false);
|
||||
} else {
|
||||
main->loadingLabel->setVisible(true);
|
||||
main->loadingLabel->setToolTip(QString::number(watchingOps.size()) + " tx computing");
|
||||
}
|
||||
int numExecuting = 0;
|
||||
|
||||
// There's an array for each item in the status
|
||||
for (auto& it : reply.get<json::array_t>()) {
|
||||
@@ -462,8 +456,17 @@ void RPC::refreshTxStatus(const QString& newOpid) {
|
||||
} else if (status == "executing") {
|
||||
// If the operation is executing, then watch every second.
|
||||
txTimer->start(1 * 1000);
|
||||
numExecuting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is some op that we are watching, then show the loading bar, otherwise hide it
|
||||
if (numExecuting == 0) {
|
||||
main->loadingLabel->setVisible(false);
|
||||
} else {
|
||||
main->loadingLabel->setVisible(true);
|
||||
main->loadingLabel->setToolTip(QString::number(numExecuting) + " tx computing");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ void MainWindow::setDefaultPayFrom() {
|
||||
|
||||
void MainWindow::inputComboTextChanged(const QString& text) {
|
||||
auto bal = rpc->getAllBalances()->value(text.split("(")[0].trimmed());
|
||||
auto balFmt = QString::number(bal, 'f', 8) + " ZEC";
|
||||
auto balFmt = QString::number(bal, 'g', 8) + " ZEC";
|
||||
ui->sendAddressBalance->setText(balFmt);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ void MainWindow::maxAmountChecked(int checked) {
|
||||
auto maxamount = rpc->getAllBalances()->value(addr) - sumAllAmounts;
|
||||
maxamount = (maxamount < 0) ? 0 : maxamount;
|
||||
|
||||
ui->Amount1->setText(QString::number(maxamount, 'f'));
|
||||
ui->Amount1->setText(QString::number(maxamount, 'g', 8));
|
||||
} else if (checked == Qt::Unchecked) {
|
||||
// Just remove the readonly part, don't change the content
|
||||
ui->Amount1->setReadOnly(false);
|
||||
@@ -179,6 +179,34 @@ void MainWindow::sendButton() {
|
||||
return splitted;
|
||||
};
|
||||
|
||||
// Gather the from / to addresses
|
||||
QString fromAddr = ui->inputsCombo->currentText().split("(")[0].trimmed();
|
||||
|
||||
QList<QPair<QString, double>> toAddrs;
|
||||
// For each addr/amt in the sendTo tab
|
||||
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
||||
for (int i=0; i < totalItems; i++) {
|
||||
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1))->text().trimmed();
|
||||
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1))->text().trimmed().toDouble();
|
||||
toAddrs.push_back(QPair<QString, double>(addr, amt));
|
||||
}
|
||||
|
||||
QString error = doSendTxValidations(fromAddr, toAddrs);
|
||||
if (!error.isEmpty()) {
|
||||
// Something went wrong, so show an error and exit
|
||||
QMessageBox msg(
|
||||
QMessageBox::Critical,
|
||||
"Transaction Error",
|
||||
error,
|
||||
QMessageBox::Ok,
|
||||
this
|
||||
);
|
||||
|
||||
msg.exec();
|
||||
// abort the Tx
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all the addresses and amounts
|
||||
json allRecepients = json::array();
|
||||
|
||||
@@ -197,16 +225,15 @@ void MainWindow::sendButton() {
|
||||
delete amt;
|
||||
}
|
||||
|
||||
// For each addr/amt in the sendTo tab
|
||||
int totalItems = ui->sendToWidgets->children().size() - 2; // The last one is a spacer, so ignore that
|
||||
for (int i=0; i < totalItems; i++) {
|
||||
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") % QString::number(i+1));
|
||||
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount") % QString::number(i+1));
|
||||
// For each addr/amt
|
||||
//std::for_each(toAddr.begin(), toAddr.end(), [&] (auto toAddr) {
|
||||
for (int i=0; i < toAddrs.size(); i++) {
|
||||
auto toAddr = toAddrs[i];
|
||||
|
||||
// Construct the JSON params
|
||||
json rec = json::object();
|
||||
rec["address"] = addr->text().toStdString();
|
||||
rec["amount"] = amt->text().toDouble();
|
||||
rec["address"] = toAddr.first.toStdString();
|
||||
rec["amount"] = toAddr.second;
|
||||
allRecepients.push_back(rec);
|
||||
|
||||
// Add new Address widgets instead of the same one.
|
||||
@@ -214,24 +241,24 @@ void MainWindow::sendButton() {
|
||||
auto Addr = new QLabel(confirm.sendToAddrs);
|
||||
Addr->setObjectName(QString("Addr") % QString::number(i + 1));
|
||||
Addr->setWordWrap(true);
|
||||
Addr->setText(fnSplitAddressForWrap(addr->text()));
|
||||
Addr->setText(fnSplitAddressForWrap(toAddr.first));
|
||||
confirm.gridLayout->addWidget(Addr, i, 0, 1, 1);
|
||||
|
||||
auto Amt = new QLabel(confirm.sendToAddrs);
|
||||
Amt->setObjectName(QString("Amt") % QString::number(i + 1));
|
||||
Amt->setText(amt->text() % " ZEC");
|
||||
Amt->setText(QString::number(toAddr.second, 'g', 8) % " ZEC");
|
||||
Amt->setAlignment(Qt::AlignRight | Qt::AlignTrailing | Qt::AlignVCenter);
|
||||
confirm.gridLayout->addWidget(Amt, i, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add sender
|
||||
json params = json::array();
|
||||
params.push_back(ui->inputsCombo->currentText().split("(")[0].trimmed().toStdString());
|
||||
params.push_back(fromAddr.toStdString());
|
||||
params.push_back(allRecepients);
|
||||
|
||||
// And show it in the confirm dialog
|
||||
auto fromAddr = ui->inputsCombo->currentText().split("(")[0];
|
||||
confirm.sendFrom->setText(fnSplitAddressForWrap(fromAddr));
|
||||
|
||||
// Show the dialog and submit it if the user confirms
|
||||
@@ -249,8 +276,32 @@ void MainWindow::sendButton() {
|
||||
}
|
||||
}
|
||||
|
||||
QString MainWindow::doSendTxValidations(QString fromAddr, QList<QPair<QString, double>> toAddrs) {
|
||||
// 1. Addresses are valid format.
|
||||
QRegExp zcexp("^zc[a-z0-9]{93}$", Qt::CaseInsensitive);
|
||||
QRegExp zsexp("^zc[a-z0-9]{76}$", Qt::CaseInsensitive);
|
||||
QRegExp texp("^t[a-z0-9]{34}$", Qt::CaseInsensitive);
|
||||
|
||||
auto matchesAnyAddr = [&] (QString addr) {
|
||||
return zcexp.exactMatch(addr) ||
|
||||
texp.exactMatch(addr) ||
|
||||
zsexp.exactMatch(addr);
|
||||
};
|
||||
|
||||
|
||||
if (!matchesAnyAddr(fromAddr)) return QString("From Address is Invalid");
|
||||
|
||||
for (auto toAddr = toAddrs.begin(); toAddr != toAddrs.end(); toAddr++) {
|
||||
if (!matchesAnyAddr(toAddr->first))
|
||||
return QString("To Address ") % toAddr->first % " is Invalid";
|
||||
};
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void MainWindow::cancelButton() {
|
||||
removeExtraAddresses();
|
||||
// Back to the balances tab
|
||||
ui->tabWidget->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ void TxTableModel::setNewData(QList<TransactionItem>* data) {
|
||||
case 0: return modeldata->at(index.row()).type;
|
||||
case 1: return modeldata->at(index.row()).address;
|
||||
case 2: return modeldata->at(index.row()).datetime;
|
||||
case 3: return QVariant(QString::number(modeldata->at(index.row()).amount, 'f') % " ZEC");
|
||||
case 3: return QVariant(QString::number(modeldata->at(index.row()).amount, 'g', 8) % " ZEC");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
QAction *actionExit;
|
||||
QAction *actionAbout;
|
||||
QAction *actionSettings;
|
||||
QAction *actionDonate;
|
||||
QWidget *centralWidget;
|
||||
QGridLayout *gridLayout_3;
|
||||
QTabWidget *tabWidget;
|
||||
@@ -134,13 +135,15 @@ public:
|
||||
{
|
||||
if (MainWindow->objectName().isEmpty())
|
||||
MainWindow->setObjectName(QStringLiteral("MainWindow"));
|
||||
MainWindow->resize(838, 595);
|
||||
MainWindow->resize(889, 603);
|
||||
actionExit = new QAction(MainWindow);
|
||||
actionExit->setObjectName(QStringLiteral("actionExit"));
|
||||
actionAbout = new QAction(MainWindow);
|
||||
actionAbout->setObjectName(QStringLiteral("actionAbout"));
|
||||
actionSettings = new QAction(MainWindow);
|
||||
actionSettings->setObjectName(QStringLiteral("actionSettings"));
|
||||
actionDonate = new QAction(MainWindow);
|
||||
actionDonate->setObjectName(QStringLiteral("actionDonate"));
|
||||
centralWidget = new QWidget(MainWindow);
|
||||
centralWidget->setObjectName(QStringLiteral("centralWidget"));
|
||||
gridLayout_3 = new QGridLayout(centralWidget);
|
||||
@@ -327,7 +330,7 @@ public:
|
||||
sendToScrollArea->setWidgetResizable(true);
|
||||
sendToWidgets = new QWidget();
|
||||
sendToWidgets->setObjectName(QStringLiteral("sendToWidgets"));
|
||||
sendToWidgets->setGeometry(QRect(0, 0, 774, 276));
|
||||
sendToWidgets->setGeometry(QRect(0, 0, 772, 218));
|
||||
sendToLayout = new QVBoxLayout(sendToWidgets);
|
||||
sendToLayout->setSpacing(6);
|
||||
sendToLayout->setContentsMargins(11, 11, 11, 11);
|
||||
@@ -586,7 +589,7 @@ public:
|
||||
MainWindow->setCentralWidget(centralWidget);
|
||||
menuBar = new QMenuBar(MainWindow);
|
||||
menuBar->setObjectName(QStringLiteral("menuBar"));
|
||||
menuBar->setGeometry(QRect(0, 0, 838, 21));
|
||||
menuBar->setGeometry(QRect(0, 0, 889, 22));
|
||||
menuBalance = new QMenu(menuBar);
|
||||
menuBalance->setObjectName(QStringLiteral("menuBalance"));
|
||||
menuHelp = new QMenu(menuBar);
|
||||
@@ -618,11 +621,12 @@ public:
|
||||
menuBalance->addAction(actionSettings);
|
||||
menuBalance->addSeparator();
|
||||
menuBalance->addAction(actionExit);
|
||||
menuHelp->addAction(actionDonate);
|
||||
menuHelp->addAction(actionAbout);
|
||||
|
||||
retranslateUi(MainWindow);
|
||||
|
||||
tabWidget->setCurrentIndex(1);
|
||||
tabWidget->setCurrentIndex(0);
|
||||
|
||||
|
||||
QMetaObject::connectSlotsByName(MainWindow);
|
||||
@@ -634,6 +638,7 @@ public:
|
||||
actionExit->setText(QApplication::translate("MainWindow", "Exit", nullptr));
|
||||
actionAbout->setText(QApplication::translate("MainWindow", "About", nullptr));
|
||||
actionSettings->setText(QApplication::translate("MainWindow", "Settings", nullptr));
|
||||
actionDonate->setText(QApplication::translate("MainWindow", "Donate", nullptr));
|
||||
groupBox->setTitle(QApplication::translate("MainWindow", "Summary", nullptr));
|
||||
label->setText(QApplication::translate("MainWindow", "Shielded", nullptr));
|
||||
balSheilded->setText(QString());
|
||||
|
||||
Reference in New Issue
Block a user