From e9398962259452e46891ee2022961ff0c40bc36b Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 28 Jul 2019 19:17:27 -0700 Subject: [PATCH] Merge in a lot of zecwallet upstream changes Includes chinese translation, validation of addresses and various bugfixes Conflicts: silentdragon.pro src/mainwindow.cpp --- application.qrc | 1 + res/zec_qt_wallet_zh.qm | Bin 0 -> 35219 bytes silentdragon.pro | 19 ++++-- src/addressbook.cpp | 69 ++++++++++++++----- src/addressbook.h | 8 ++- src/addressbook.ui | 2 +- src/mainwindow.cpp | 142 ++++++++++++++++++++++++++++++++------- src/mainwindow.h | 4 +- src/mainwindow.ui | 25 +++++-- src/precompiled.h | 2 + src/privkey.ui | 2 +- src/rpc.cpp | 12 ++++ src/rpc.h | 1 + src/settings.cpp | 9 +++ src/settings.h | 1 + src/validateaddress.cpp | 37 ++++++++++ src/validateaddress.h | 23 +++++++ src/validateaddress.ui | 85 +++++++++++++++++++++++ src/viewalladdresses.cpp | 38 +++++++++++ src/viewalladdresses.h | 24 +++++++ src/viewalladdresses.ui | 81 ++++++++++++++++++++++ 21 files changed, 528 insertions(+), 57 deletions(-) create mode 100644 res/zec_qt_wallet_zh.qm create mode 100644 src/validateaddress.cpp create mode 100644 src/validateaddress.h create mode 100644 src/validateaddress.ui create mode 100644 src/viewalladdresses.cpp create mode 100644 src/viewalladdresses.h create mode 100644 src/viewalladdresses.ui diff --git a/application.qrc b/application.qrc index c7201af..52afaf1 100644 --- a/application.qrc +++ b/application.qrc @@ -17,5 +17,6 @@ res/zec_qt_wallet_fr.qm res/zec_qt_wallet_pt.qm res/zec_qt_wallet_it.qm + res/zec_qt_wallet_zh.qm diff --git a/res/zec_qt_wallet_zh.qm b/res/zec_qt_wallet_zh.qm new file mode 100644 index 0000000000000000000000000000000000000000..de6ed575f2d0e6a5cba6662797ec58701eba4cea GIT binary patch literal 35219 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 literal 0 HcmV?d00001 diff --git a/silentdragon.pro b/silentdragon.pro index 025ba3a..090294d 100644 --- a/silentdragon.pro +++ b/silentdragon.pro @@ -53,11 +53,13 @@ SOURCES += \ src/addressbook.cpp \ src/logger.cpp \ src/addresscombo.cpp \ + src/validateaddress.cpp \ src/websockets.cpp \ src/mobileappconnector.cpp \ src/recurring.cpp \ src/requestdialog.cpp \ - src/memoedit.cpp + src/memoedit.cpp \ + src/viewalladdresses.cpp HEADERS += \ src/mainwindow.h \ @@ -77,12 +79,14 @@ HEADERS += \ src/fillediconlabel.h \ src/addressbook.h \ src/logger.h \ - src/addresscombo.h \ + src/addresscombo.h \ + src/validateaddress.h \ src/websockets.h \ src/mobileappconnector.h \ src/recurring.h \ src/requestdialog.h \ - src/memoedit.h + src/memoedit.h \ + src/viewalladdresses.h FORMS += \ src/mainwindow.ui \ @@ -92,10 +96,14 @@ FORMS += \ src/turnstile.ui \ src/turnstileprogress.ui \ src/privkey.ui \ - src/memodialog.ui \ + src/memodialog.ui \ + src/viewalladdresses.ui \ + src/validateaddress.ui \ + src/viewalladdresses.ui \ src/connection.ui \ src/zboard.ui \ src/addressbook.ui \ + src/viewalladdresses.ui \ src/mobileappconnector.ui \ src/createzcashconfdialog.ui \ src/recurringdialog.ui \ @@ -107,7 +115,8 @@ TRANSLATIONS = res/zec_qt_wallet_es.ts \ res/zec_qt_wallet_fr.ts \ res/zec_qt_wallet_de.ts \ res/zec_qt_wallet_pt.ts \ - res/zec_qt_wallet_it.ts + res/zec_qt_wallet_it.ts \ + res/zec_qt_wallet_zh.ts include(singleapplication/singleapplication.pri) DEFINES += QAPPLICATION_CLASS=QApplication diff --git a/src/addressbook.cpp b/src/addressbook.cpp index 6cf0489..4ef2d2b 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -122,14 +122,32 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { // Add new address button QObject::connect(ab.addNew, &QPushButton::clicked, [&] () { auto addr = ab.addr->text().trimmed(); - if (!addr.isEmpty() && !ab.label->text().isEmpty()) { - // Test if address is valid. - if (!Settings::isValidAddress(addr)) { - QMessageBox::critical(parent, QObject::tr("Address Format Error"), addr + QObject::tr(" doesn't seem to be a valid Hush address."), QMessageBox::Ok); - } else { - model.addNewLabel(ab.label->text(), ab.addr->text()); - } + QString newLabel = ab.label->text(); + + if (addr.isEmpty() || newLabel.isEmpty()) { + QMessageBox::critical(parent, QObject::tr("Address or Label Error"), + QObject::tr("Address or Label cannot be empty"), QMessageBox::Ok); + return; } + // Test if address is valid. + if (!Settings::isValidAddress(addr)) { + QMessageBox::critical(parent, QObject::tr("Address Format Error"), + QObject::tr("%1 doesn't seem to be a valid Zcash address.") + .arg(addr), + QMessageBox::Ok); + return; + } + + // Don't allow duplicate address labels. + if (!getInstance()->getAddressForLabel(newLabel).isEmpty()) { + QMessageBox::critical(parent, QObject::tr("Label Error"), + QObject::tr("The label '%1' already exists. Please remove the existing label.") + .arg(newLabel), + QMessageBox::Ok); + return; + } + + model.addNewLabel(newLabel, ab.addr->text()); }); // Import Button @@ -217,7 +235,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { if (d.exec() == QDialog::Accepted && target != nullptr) { auto selection = ab.addresses->selectionModel(); - if (selection->hasSelection()) { + if (selection && selection->hasSelection() && selection->selectedRows().size() > 0) { auto item = model.itemAt(selection->selectedRows().at(0).row()); fnSetTargetLabelAddr(target, item.first, item.second); } @@ -244,17 +262,24 @@ AddressBook::AddressBook() { void AddressBook::readFromStorage() { QFile file(AddressBook::writeableFile()); - if (!file.exists()) { - return; - } + if (file.exists()) { + allLabels.clear(); + file.open(QIODevice::ReadOnly); + QDataStream in(&file); // read the data serialized from the file + QString version; + in >> version >> allLabels; - allLabels.clear(); - file.open(QIODevice::ReadOnly); - QDataStream in(&file); // read the data serialized from the file - QString version; - in >> version >> allLabels; + file.close(); + } - file.close(); + // Special. + // Add the default ZecWallet donation address if it isn't already present + // QList allAddresses; + // std::transform(allLabels.begin(), allLabels.end(), + // std::back_inserter(allAddresses), [=] (auto i) { return i.second; }); + // if (!allAddresses.contains(Settings::getDonationAddr(true))) { + // allLabels.append(QPair("ZecWallet donation", Settings::getDonationAddr(true))); + // } } void AddressBook::writeToStorage() { @@ -337,6 +362,16 @@ QString AddressBook::getLabelForAddress(QString addr) { return ""; } +// Get the address for a label +QString AddressBook::getAddressForLabel(QString label) { + for (auto i: allLabels) { + if (i.first == label) + return i.second; + } + + return ""; +} + QString AddressBook::addLabelToAddress(QString addr) { QString label = AddressBook::getInstance()->getLabelForAddress(addr); if (!label.isEmpty()) diff --git a/src/addressbook.h b/src/addressbook.h index 41f9ff9..af64c07 100644 --- a/src/addressbook.h +++ b/src/addressbook.h @@ -10,9 +10,9 @@ class AddressBookModel : public QAbstractTableModel { public: AddressBookModel(QTableView* parent); ~AddressBookModel(); - - void addNewLabel(QString label, QString addr); - void removeItemAt(int row); + + void addNewLabel(QString label, QString addr); + void removeItemAt(int row); QPair itemAt(int row); int rowCount(const QModelIndex &parent) const; @@ -52,6 +52,8 @@ public: // Get an address's first label QString getLabelForAddress(QString address); + // Get a Label's address + QString getAddressForLabel(QString label); private: AddressBook(); diff --git a/src/addressbook.ui b/src/addressbook.ui index 946fb13..a20ee8f 100644 --- a/src/addressbook.ui +++ b/src/addressbook.ui @@ -23,7 +23,7 @@ - Address + Address (z-Addr or t-Addr) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c285882..279068b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,5 +1,7 @@ #include "mainwindow.h" #include "addressbook.h" +#include "viewalladdresses.h" +#include "validateaddress.h" #include "ui_mainwindow.h" #include "ui_mobileappconnector.h" #include "ui_addressbook.h" @@ -9,6 +11,8 @@ #include "ui_settings.h" #include "ui_turnstile.h" #include "ui_turnstileprogress.h" +#include "ui_viewalladdresses.h" +#include "ui_validateaddress.h" #include "rpc.h" #include "balancestablemodel.h" #include "settings.h" @@ -75,6 +79,9 @@ MainWindow::MainWindow(QWidget *parent) : // z-Board.net QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); + // Validate Address + QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress); + // Connect mobile app QObject::connect(ui->actionConnect_Mobile_App, &QAction::triggered, this, [=] () { if (rpc->getConnection() == nullptr) @@ -109,7 +116,7 @@ MainWindow::MainWindow(QWidget *parent) : setupSendTab(); setupTransactionsTab(); - setupRecieveTab(); + setupReceiveTab(); setupBalancesTab(); setupTurnstileDialog(); setupZcashdTab(); @@ -628,6 +635,48 @@ void MainWindow::donate() { ui->tabWidget->setCurrentIndex(1); } +/** + * Validate an address + */ +void MainWindow::validateAddress() { + // Make sure everything is up and running + if (!getRPC() || !getRPC()->getConnection()) + return; + + // First thing is ask the user for an address + bool ok; + auto address = QInputDialog::getText(this, tr("Enter Address to validate"), + tr("Transparent or Shielded Address:") + QString(" ").repeated(140), // Pad the label so the dialog box is wide enough + QLineEdit::Normal, "", &ok); + if (!ok) + return; + + getRPC()->validateAddress(address, [=] (json props) { + QDialog d(this); + Ui_ValidateAddress va; + va.setupUi(&d); + Settings::saveRestore(&d); + Settings::saveRestoreTableHeader(va.tblProps, &d, "validateaddressprops"); + va.tblProps->horizontalHeader()->setStretchLastSection(true); + + va.lblAddress->setText(address); + + QList> propsList; + for (auto it = props.begin(); it != props.end(); it++) { + + propsList.append( + QPair( + QString::fromStdString(it.key()), QString::fromStdString(it.value().dump())) + ); + } + + ValidateAddressesModel model(va.tblProps, propsList); + va.tblProps->setModel(&model); + + d.exec(); + }); + +} void MainWindow::postToZBoard() { QDialog d(this); @@ -827,7 +876,7 @@ void MainWindow::payZcashURI(QString uri, QString myAddr) { return; // Extract the address - qDebug() << "Recieved URI " << uri; + qDebug() << "Received URI " << uri; PaymentURI paymentInfo = Settings::parseURI(uri); if (!paymentInfo.error.isEmpty()) { QMessageBox::critical(this, tr("Error paying pirate URI"), @@ -1238,7 +1287,6 @@ void MainWindow::setupTransactionsTab() { } void MainWindow::addNewZaddr(bool sapling) { - rpc->newZaddr(sapling, [=] (json reply) { QString addr = QString::fromStdString(reply.get()); // Make sure the RPC class reloads the z-addrs for future use @@ -1246,8 +1294,8 @@ void MainWindow::addNewZaddr(bool sapling) { // Just double make sure the z-address is still checked if ( sapling && ui->rdioZSAddr->isChecked() ) { - ui->listRecieveAddresses->insertItem(0, addr); - ui->listRecieveAddresses->setCurrentIndex(0); + ui->listReceiveAddresses->insertItem(0, addr); + ui->listReceiveAddresses->setCurrentIndex(0); ui->statusBar->showMessage(QString::fromStdString("Created new zAddr") % (sapling ? "(Sapling)" : "(Sprout)"), @@ -1263,14 +1311,14 @@ std::function MainWindow::addZAddrsToComboList(bool sapling) { return [=] (bool checked) { if (checked && this->rpc->getAllZAddresses() != nullptr) { auto addrs = this->rpc->getAllZAddresses(); - ui->listRecieveAddresses->clear(); + ui->listReceiveAddresses->clear(); std::for_each(addrs->begin(), addrs->end(), [=] (auto addr) { if ( (sapling && Settings::getInstance()->isSaplingAddress(addr)) || (!sapling && !Settings::getInstance()->isSaplingAddress(addr))) { if (rpc->getAllBalances()) { auto bal = rpc->getAllBalances()->value(addr); - ui->listRecieveAddresses->addItem(addr, bal); + ui->listReceiveAddresses->addItem(addr, bal); } } }); @@ -1283,15 +1331,17 @@ std::function MainWindow::addZAddrsToComboList(bool sapling) { }; } -void MainWindow::setupRecieveTab() { +void MainWindow::setupReceiveTab() { auto addNewTAddr = [=] () { rpc->newTaddr([=] (json reply) { QString addr = QString::fromStdString(reply.get()); + // Make sure the RPC class reloads the t-addrs for future use + rpc->refreshAddresses(); // Just double make sure the t-address is still checked if (ui->rdioTAddr->isChecked()) { - ui->listRecieveAddresses->insertItem(0, addr); - ui->listRecieveAddresses->setCurrentIndex(0); + ui->listReceiveAddresses->insertItem(0, addr); + ui->listReceiveAddresses->setCurrentIndex(0); ui->statusBar->showMessage(tr("Created new t-Addr"), 10 * 1000); } @@ -1304,14 +1354,58 @@ void MainWindow::setupRecieveTab() { // want to reuse t-addrs if (checked && this->rpc->getUTXOs() != nullptr) { updateTAddrCombo(checked); - addNewTAddr(); } + + // Toggle the "View all addresses" button as well + ui->btnViewAllAddresses->setVisible(checked); + }); + + // View all addresses goes to "View all private keys" + QObject::connect(ui->btnViewAllAddresses, &QPushButton::clicked, [=] () { + // If there's no RPC, return + if (!getRPC()) + return; + + QDialog d(this); + Ui_ViewAddressesDialog viewaddrs; + viewaddrs.setupUi(&d); + Settings::saveRestore(&d); + Settings::saveRestoreTableHeader(viewaddrs.tblAddresses, &d, "viewalladdressestable"); + viewaddrs.tblAddresses->horizontalHeader()->setStretchLastSection(true); + + ViewAllAddressesModel model(viewaddrs.tblAddresses, *getRPC()->getAllTAddresses(), getRPC()); + viewaddrs.tblAddresses->setModel(&model); + + QObject::connect(viewaddrs.btnExportAll, &QPushButton::clicked, this, &MainWindow::exportAllKeys); + + viewaddrs.tblAddresses->setContextMenuPolicy(Qt::CustomContextMenu); + QObject::connect(viewaddrs.tblAddresses, &QTableView::customContextMenuRequested, [=] (QPoint pos) { + QModelIndex index = viewaddrs.tblAddresses->indexAt(pos); + if (index.row() < 0) return; + + index = index.sibling(index.row(), 0); + QString addr = viewaddrs.tblAddresses->model()->data(index).toString(); + + QMenu menu(this); + menu.addAction(tr("Export Private Key"), [=] () { + if (addr.isEmpty()) + return; + + this->exportKeys(addr); + }); + menu.addAction(tr("Copy Address"), [=]() { + QGuiApplication::clipboard()->setText(addr); + }); + menu.exec(viewaddrs.tblAddresses->viewport()->mapToGlobal(pos)); + }); + + d.exec(); }); QObject::connect(ui->rdioZSAddr, &QRadioButton::toggled, addZAddrsToComboList(true)); // Explicitly get new address button. - QObject::connect(ui->btnRecieveNewAddr, &QPushButton::clicked, [=] () { + QObject::connect(ui->btnReceiveNewAddr, &QPushButton::clicked, [=] () { if (!rpc->getConnection()) return; @@ -1327,9 +1421,10 @@ void MainWindow::setupRecieveTab() { if (tab == 2) { // Switched to receive tab, select the z-addr radio button ui->rdioZSAddr->setChecked(true); + ui->btnViewAllAddresses->setVisible(false); // And then select the first one - ui->listRecieveAddresses->setCurrentIndex(0); + ui->listReceiveAddresses->setCurrentIndex(0); } }); @@ -1338,15 +1433,15 @@ void MainWindow::setupRecieveTab() { ui->rcvLabel->setValidator(v); // Select item in address list - QObject::connect(ui->listRecieveAddresses, + QObject::connect(ui->listReceiveAddresses, QOverload::of(&QComboBox::currentIndexChanged), [=] (int index) { - QString addr = ui->listRecieveAddresses->itemText(index); + QString addr = ui->listReceiveAddresses->itemText(index); if (addr.isEmpty()) { // Draw empty stuff ui->rcvLabel->clear(); ui->rcvBal->clear(); - ui->txtRecieve->clear(); + ui->txtReceive->clear(); ui->qrcodeDisplay->clear(); return; } @@ -1361,7 +1456,7 @@ void MainWindow::setupRecieveTab() { ui->rcvLabel->setText(label); ui->rcvBal->setText(Settings::getZECUSDDisplayFormat(rpc->getAllBalances()->value(addr))); - ui->txtRecieve->setPlainText(addr); + ui->txtReceive->setPlainText(addr); ui->qrcodeDisplay->setQrcodeString(addr); if (rpc->getUsedAddresses()->value(addr, false)) { ui->rcvBal->setToolTip(tr("Address has been previously used")); @@ -1373,7 +1468,7 @@ void MainWindow::setupRecieveTab() { // Receive tab add/update label QObject::connect(ui->rcvUpdateLabel, &QPushButton::clicked, [=]() { - QString addr = ui->listRecieveAddresses->currentText(); + QString addr = ui->listReceiveAddresses->currentText(); if (addr.isEmpty()) return; @@ -1407,9 +1502,9 @@ void MainWindow::setupRecieveTab() { } }); - // Recieve Export Key + // Receive Export Key QObject::connect(ui->exportKey, &QPushButton::clicked, [=]() { - QString addr = ui->listRecieveAddresses->currentText(); + QString addr = ui->listReceiveAddresses->currentText(); if (addr.isEmpty()) return; @@ -1417,16 +1512,17 @@ void MainWindow::setupRecieveTab() { }); } + void MainWindow::updateTAddrCombo(bool checked) { if (checked) { auto utxos = this->rpc->getUTXOs(); - ui->listRecieveAddresses->clear(); + ui->listReceiveAddresses->clear(); std::for_each(utxos->begin(), utxos->end(), [=](auto& utxo) { auto addr = utxo.address; - if (addr.startsWith("R") && ui->listRecieveAddresses->findText(addr) < 0) { + if (addr.startsWith("R") && ui->listReceiveAddresses->findText(addr) < 0) { auto bal = rpc->getAllBalances()->value(addr); - ui->listRecieveAddresses->addItem(addr, bal); + ui->listReceiveAddresses->addItem(addr, bal); } }); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 9a1971d..7a14fa3 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -56,6 +56,8 @@ public: void balancesReady(); void payZcashURI(QString uri = "", QString myAddr = ""); + void validateAddress(); + void updateLabels(); void updateTAddrCombo(bool checked); void updateFromCombo(); @@ -76,7 +78,7 @@ private: void setupSendTab(); void setupTransactionsTab(); - void setupRecieveTab(); + void setupReceiveTab(); void setupBalancesTab(); void setupZcashdTab(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index b11eb6d..34eb4db 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -756,7 +756,7 @@ - + 0 @@ -769,12 +769,19 @@ - + New Address + + + + View All Addresses + + + @@ -825,7 +832,7 @@ - + 0 @@ -1335,6 +1342,7 @@ &Apps + @@ -1451,6 +1459,11 @@ Request HUSH... + + + Validate Address + + @@ -1483,9 +1496,9 @@ cancelSendButton rdioZSAddr rdioTAddr - listRecieveAddresses - btnRecieveNewAddr - txtRecieve + listReceiveAddresses + btnReceiveNewAddr + txtReceive rcvLabel rcvUpdateLabel transactionsTable diff --git a/src/precompiled.h b/src/precompiled.h index 5745182..79c4c8b 100644 --- a/src/precompiled.h +++ b/src/precompiled.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/privkey.ui b/src/privkey.ui index 9fe3760..57bdb16 100644 --- a/src/privkey.ui +++ b/src/privkey.ui @@ -11,7 +11,7 @@ - Private Key + Private Keys diff --git a/src/rpc.cpp b/src/rpc.cpp index cdd727d..64e09e8 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -230,6 +230,18 @@ void RPC::importTPrivKey(QString privkey, bool rescan, const std::functiondoRPCWithDefaultErrorHandling(payload, cb); } +void RPC::validateAddress(QString address, const std::function& cb) { + QString method = address.startsWith("z") ? "z_validateaddress" : "validateaddress"; + + json payload = { + {"jsonrpc", "1.0"}, + {"id", "someid"}, + {"method", method.toStdString() }, + {"params", { address.toStdString() } }, + }; + + conn->doRPCWithDefaultErrorHandling(payload, cb); +} void RPC::getBalance(const std::function& cb) { json payload = { diff --git a/src/rpc.h b/src/rpc.h index 3b95a71..48193ee 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -75,6 +75,7 @@ public: void getTPrivKey(QString addr, const std::function& cb); void importZPrivKey(QString addr, bool rescan, const std::function& cb); void importTPrivKey(QString addr, bool rescan, const std::function& cb); + void validateAddress(QString address, const std::function& cb); void shutdownZcashd(); void noConnection(); diff --git a/src/settings.cpp b/src/settings.cpp index 27499a7..b8e4891 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -40,6 +40,15 @@ void Settings::saveSettings(const QString& host, const QString& port, const QStr init(); } +void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tablename) { + table->horizontalHeader()->restoreState(QSettings().value(tablename).toByteArray()); + table->horizontalHeader()->setStretchLastSection(true); + + QObject::connect(d, &QDialog::finished, [=](auto) { + QSettings().setValue(tablename, table->horizontalHeader()->saveState()); + }); +} + void Settings::setUsingZcashConf(QString confLocation) { if (!confLocation.isEmpty()) _confLocation = confLocation; diff --git a/src/settings.h b/src/settings.h index e72434e..fb289cc 100644 --- a/src/settings.h +++ b/src/settings.h @@ -76,6 +76,7 @@ public: static const QString txidStatusMessage; static void saveRestore(QDialog* d); + static void saveRestoreTableHeader(QTableView* table, QDialog* d, QString tablename) ; static PaymentURI parseURI(QString paymentURI); static QString paymentURIPretty(PaymentURI); diff --git a/src/validateaddress.cpp b/src/validateaddress.cpp new file mode 100644 index 0000000..d82e82e --- /dev/null +++ b/src/validateaddress.cpp @@ -0,0 +1,37 @@ +#include "validateaddress.h" + + +ValidateAddressesModel::ValidateAddressesModel(QTableView *parent, QList> props) + : QAbstractTableModel(parent) { + headers << tr("Property") << tr("Value"); + this->props = props; +} + + +int ValidateAddressesModel::rowCount(const QModelIndex&) const { + return props.size(); +} + +int ValidateAddressesModel::columnCount(const QModelIndex&) const { + return headers.size(); +} + +QVariant ValidateAddressesModel::data(const QModelIndex &index, int role) const { + QPair p = props.at(index.row()); + if (role == Qt::DisplayRole) { + switch(index.column()) { + case 0: return p.first; + case 1: return p.second; + } + } + return QVariant(); +} + + +QVariant ValidateAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + return headers.at(section); + } + + return QVariant(); +} diff --git a/src/validateaddress.h b/src/validateaddress.h new file mode 100644 index 0000000..19db4cb --- /dev/null +++ b/src/validateaddress.h @@ -0,0 +1,23 @@ +#ifndef VALIDATEADDRESS_H +#define VALIDATEADDRESS_H + +#include "precompiled.h" + +class ValidateAddressesModel : public QAbstractTableModel { + +public: + ValidateAddressesModel(QTableView* parent, QList> props); + ~ValidateAddressesModel() = default; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + +private: + QList> props; + QStringList headers; +}; + + +#endif // VALIDATEADDRESS_H diff --git a/src/validateaddress.ui b/src/validateaddress.ui new file mode 100644 index 0000000..20caebb --- /dev/null +++ b/src/validateaddress.ui @@ -0,0 +1,85 @@ + + + ValidateAddress + + + + 0 + 0 + 400 + 300 + + + + Validate Address + + + + + + TextLabel + + + + + + + Address: + + + + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + ValidateAddress + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ValidateAddress + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/viewalladdresses.cpp b/src/viewalladdresses.cpp new file mode 100644 index 0000000..7b7af7d --- /dev/null +++ b/src/viewalladdresses.cpp @@ -0,0 +1,38 @@ +#include "viewalladdresses.h" +#include "settings.h" + +ViewAllAddressesModel::ViewAllAddressesModel(QTableView *parent, QList taddrs, RPC* rpc) + : QAbstractTableModel(parent) { + headers << tr("Address") << tr("Balance (%1)").arg(Settings::getTokenName()); + addresses = taddrs; + this->rpc = rpc; +} + + +int ViewAllAddressesModel::rowCount(const QModelIndex&) const { + return addresses.size(); +} + +int ViewAllAddressesModel::columnCount(const QModelIndex&) const { + return headers.size(); +} + +QVariant ViewAllAddressesModel::data(const QModelIndex &index, int role) const { + QString address = addresses.at(index.row()); + if (role == Qt::DisplayRole) { + switch(index.column()) { + case 0: return address; + case 1: return rpc->getAllBalances()->value(address, 0.0); + } + } + return QVariant(); +} + + +QVariant ViewAllAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { + return headers.at(section); + } + + return QVariant(); +} diff --git a/src/viewalladdresses.h b/src/viewalladdresses.h new file mode 100644 index 0000000..4e9e3d4 --- /dev/null +++ b/src/viewalladdresses.h @@ -0,0 +1,24 @@ +#ifndef VIEWALLADDRESSES_H +#define VIEWALLADDRESSES_H + +#include "precompiled.h" +#include "rpc.h" + +class ViewAllAddressesModel : public QAbstractTableModel { + +public: + ViewAllAddressesModel(QTableView* parent, QList taddrs, RPC* rpc); + ~ViewAllAddressesModel() = default; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + +private: + QList addresses; + QStringList headers; + RPC* rpc; +}; + +#endif \ No newline at end of file diff --git a/src/viewalladdresses.ui b/src/viewalladdresses.ui new file mode 100644 index 0000000..fae5ecf --- /dev/null +++ b/src/viewalladdresses.ui @@ -0,0 +1,81 @@ + + + ViewAddressesDialog + + + + 0 + 0 + 400 + 300 + + + + All Addresses + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + Export All Keys + + + + + + + QAbstractItemView::SingleSelection + + + true + + + + + + + + + buttonBox + accepted() + ViewAddressesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ViewAddressesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +