Browse Source

Fix flicker issues on the balances and transactions tables

import_zecw
Aditya Kulkarni 6 years ago
parent
commit
1c282000c8
  1. 7
      application.qrc
  2. 0
      res/Ubuntu-R.ttf
  3. BIN
      res/connected.png
  4. BIN
      res/loading.gif
  5. 0
      res/qt5.natvis
  6. 38
      src/about.ui
  7. 27
      src/balancestablemodel.cpp
  8. 8
      src/balancestablemodel.h
  9. 2
      src/main.cpp
  10. 19
      src/mainwindow.cpp
  11. 4
      src/mainwindow.h
  12. 1
      src/precompiled.h
  13. 102
      src/rpc.cpp
  14. 14
      src/txtablemodel.cpp
  15. 6
      src/txtablemodel.h
  16. 48
      src/ui_about.h
  17. 8
      zcash-qt-wallet.pro

7
application.qrc

@ -1,5 +1,10 @@
<RCC> <RCC>
<qresource prefix="/fonts"> <qresource prefix="/fonts">
<file>Ubuntu-R.ttf</file> <file>res/Ubuntu-R.ttf</file>
</qresource> </qresource>
<qresource prefix="/icons">
<file>res/connected.png</file>
<file>res/loading.gif</file>
</qresource>
</RCC> </RCC>

0
Ubuntu-R.ttf → res/Ubuntu-R.ttf

BIN
res/connected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
res/loading.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

0
qt5.natvis → res/qt5.natvis

38
src/about.ui

@ -14,6 +14,22 @@
<string>Dialog</string> <string>Dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>zcash-qt-wallet</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="versionLabel">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QTextEdit" name="textEdit"> <widget class="QTextEdit" name="textEdit">
<property name="readOnly"> <property name="readOnly">
@ -23,17 +39,17 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.1pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (c) 2018 Aditya Kulkarni. (MIT License)&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;Copyright (c) 2018 Aditya Kulkarni. (MIT License)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Special thanks to:&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;Special thanks to:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;JSON for Modern C++ : &lt;a href=&quot;https://nlohmann.github.io/json/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;https://nlohmann.github.io/json/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;JSON for Modern C++ : &lt;/span&gt;&lt;a href=&quot;https://nlohmann.github.io/json/&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;&quot;&gt;https://nlohmann.github.io/json/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;QR Code generator library Nayuki : &lt;a href=&quot;https://www.nayuki.io/page/qr-code-generator-library&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;https://www.nayuki.io/page/qr-code-ge…&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;QR Code generator library Nayuki : &lt;/span&gt;&lt;a href=&quot;https://www.nayuki.io/page/qr-code-generator-library&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;&quot;&gt;https://www.nayuki.io/page/qr-code-ge…&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Made with QT : &lt;a href=&quot;https://www.qt.io/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;https://www.qt.io/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt; &lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;Made with QT : &lt;/span&gt;&lt;a href=&quot;https://www.qt.io/&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;&quot;&gt;https://www.qt.io/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;LICENSE:&lt;/p&gt; &lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;LICENSE:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:&lt;/p&gt; &lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot;&gt;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&lt;/li&gt; &lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&lt;/li&gt;
&lt;li style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The Software is provided &amp;quot;as is&amp;quot;, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;li style=&quot; font-family:'Ubuntu'; font-size:11pt;&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The Software is provided &amp;quot;as is&amp;quot;, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>

27
src/balancestablemodel.cpp

@ -1,21 +1,29 @@
#include "balancestablemodel.h" #include "balancestablemodel.h"
BalancesTableModel::BalancesTableModel( BalancesTableModel::BalancesTableModel(QObject *parent)
QObject *parent,
const QMap<QString, double>* balances,
const QList<UnspentOutput>* outputs)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
{
}
void BalancesTableModel::setNewData(const QMap<QString, double>* balances,
const QList<UnspentOutput>* outputs)
{ {
// Copy over the utxos for our use // Copy over the utxos for our use
delete utxos;
utxos = new QList<UnspentOutput>(); utxos = new QList<UnspentOutput>();
// This is a QList deep copy. // This is a QList deep copy.
*utxos = *outputs; *utxos = *outputs;
// Process the address balances into a list // Process the address balances into a list
delete modeldata;
modeldata = new QList<std::tuple<QString, QString>>(); modeldata = new QList<std::tuple<QString, QString>>();
std::for_each(balances->constKeyValueBegin(), balances->constKeyValueEnd(), [=] (auto it) { 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, 'f')));
}); });
// And then update the data
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1));
layoutChanged();
} }
BalancesTableModel::~BalancesTableModel() { BalancesTableModel::~BalancesTableModel() {
@ -25,6 +33,7 @@ BalancesTableModel::~BalancesTableModel() {
int BalancesTableModel::rowCount(const QModelIndex&) const int BalancesTableModel::rowCount(const QModelIndex&) const
{ {
if (modeldata == nullptr) return 0;
return modeldata->size(); return modeldata->size();
} }
@ -36,6 +45,14 @@ int BalancesTableModel::columnCount(const QModelIndex&) const
QVariant BalancesTableModel::data(const QModelIndex &index, int role) const QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
{ {
auto fnSplitAddressForWrap = [=] (const QString& a) -> QString {
if (!a.startsWith("z")) return a;
auto half = a.length() / 2;
auto splitted = a.left(half) + "\n" + a.right(a.length() - half);
return splitted;
};
if (role == Qt::TextAlignmentRole && index.column() == 1) return QVariant(Qt::AlignRight | Qt::AlignVCenter); if (role == Qt::TextAlignmentRole && index.column() == 1) return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::ForegroundRole) { if (role == Qt::ForegroundRole) {
@ -57,7 +74,7 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole || role == Qt::ToolTipRole) { if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
switch (index.column()) { switch (index.column()) {
case 0: return std::get<0>(modeldata->at(index.row())); case 0: return fnSplitAddressForWrap(std::get<0>(modeldata->at(index.row())));
case 1: return QVariant(std::get<1>(modeldata->at(index.row())) % " ZEC"); case 1: return QVariant(std::get<1>(modeldata->at(index.row())) % " ZEC");
} }
} }

8
src/balancestablemodel.h

@ -8,17 +8,19 @@
class BalancesTableModel : public QAbstractTableModel class BalancesTableModel : public QAbstractTableModel
{ {
public: public:
BalancesTableModel(QObject* parent, const QMap<QString, double>* balances, const QList<UnspentOutput>* outputs); BalancesTableModel(QObject* parent);
~BalancesTableModel(); ~BalancesTableModel();
void setNewData(const QMap<QString, double>* balances, const QList<UnspentOutput>* outputs);
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private: private:
QList<std::tuple<QString, QString>>* modeldata; QList<std::tuple<QString, QString>>* modeldata = nullptr;
QList<UnspentOutput>* utxos; QList<UnspentOutput>* utxos = nullptr;
}; };
#endif // BALANCESTABLEMODEL_H #endif // BALANCESTABLEMODEL_H

2
src/main.cpp

@ -12,7 +12,7 @@ int main(int argc, char *argv[])
QApplication a(argc, argv); QApplication a(argc, argv);
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf"); QFontDatabase::addApplicationFont(":/fonts/res/Ubuntu-R.ttf");
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false)); qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif #endif

19
src/mainwindow.cpp

@ -21,8 +21,19 @@ MainWindow::MainWindow(QWidget *parent) :
settings = new Settings(); settings = new Settings();
// Status Bar // Status Bar
loadingLabel = new QLabel();
loadingMovie = new QMovie(":/icons/res/loading.gif");
loadingMovie->setScaledSize(QSize(32, 16));
loadingMovie->start();
loadingLabel->setAttribute(Qt::WA_NoSystemBackground);
loadingLabel->setMovie(loadingMovie);
ui->statusBar->addPermanentWidget(loadingLabel);
loadingLabel->setVisible(false);
statusLabel = new QLabel(); statusLabel = new QLabel();
ui->statusBar->addPermanentWidget(statusLabel); ui->statusBar->addPermanentWidget(statusLabel);
statusIcon = new QLabel(); statusIcon = new QLabel();
ui->statusBar->addPermanentWidget(statusIcon); ui->statusBar->addPermanentWidget(statusIcon);
@ -65,7 +76,11 @@ MainWindow::MainWindow(QWidget *parent) :
QObject::connect(ui->actionAbout, &QAction::triggered, [=] () { QObject::connect(ui->actionAbout, &QAction::triggered, [=] () {
QDialog aboutDialog(this); QDialog aboutDialog(this);
Ui_about about; Ui_about about;
about.setupUi(&aboutDialog); about.setupUi(&aboutDialog);
QString version = QString("Version ") % QString(APP_VERSION) % " (" % QString(__DATE__) % ")";
about.versionLabel->setText(version);
aboutDialog.exec(); aboutDialog.exec();
}); });
@ -272,4 +287,6 @@ MainWindow::~MainWindow()
delete ui; delete ui;
delete rpc; delete rpc;
delete settings; delete settings;
delete loadingMovie;
} }

4
src/mainwindow.h

@ -25,6 +25,8 @@ public:
QLabel* statusLabel; QLabel* statusLabel;
QLabel* statusIcon; QLabel* statusIcon;
QLabel* loadingLabel;
private: private:
void setupSendTab(); void setupSendTab();
void setupTransactionsTab(); void setupTransactionsTab();
@ -42,6 +44,8 @@ private:
RPC* rpc; RPC* rpc;
Settings* settings; Settings* settings;
QMovie* loadingMovie;
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

1
src/precompiled.h

@ -13,6 +13,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QScrollBar> #include <QScrollBar>
#include <QPainter> #include <QPainter>
#include <QMovie>
#include <QTimer> #include <QTimer>
#include <QSettings> #include <QSettings>
#include <QFile> #include <QFile>

102
src/rpc.cpp

@ -9,6 +9,19 @@ RPC::RPC(QNetworkAccessManager* client, MainWindow* main) {
this->main = main; this->main = main;
this->ui = main->ui; this->ui = main->ui;
// Setup balances table model
balancesTableModel = new BalancesTableModel(main->ui->balancesTable);
main->ui->balancesTable->setModel(balancesTableModel);
main->ui->balancesTable->setColumnWidth(0, 300);
// Setup transactions table model
transactionsTableModel = new TxTableModel(ui->transactionsTable);
main->ui->transactionsTable->setModel(transactionsTableModel);
main->ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
main->ui->transactionsTable->setColumnWidth(1, 350);
main->ui->transactionsTable->setColumnWidth(2, 200);
main->ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
reloadConnectionInfo(); reloadConnectionInfo();
// Set up a timer to refresh the UI every few seconds // Set up a timer to refresh the UI every few seconds
@ -16,15 +29,15 @@ RPC::RPC(QNetworkAccessManager* client, MainWindow* main) {
QObject::connect(timer, &QTimer::timeout, [=]() { QObject::connect(timer, &QTimer::timeout, [=]() {
refresh(); refresh();
}); });
timer->start(1 * 60 * 1000); // Query every minute timer->start(10 * 1000);
// Set up the timer to watch for tx status // Set up the timer to watch for tx status
txTimer = new QTimer(main); txTimer = new QTimer(main);
QObject::connect(txTimer, &QTimer::timeout, [=]() { QObject::connect(txTimer, &QTimer::timeout, [=]() {
refreshTxStatus(); refreshTxStatus();
}); });
// Start at every minute. When an operation is pending, this will change to every second // Start at every 10s. When an operation is pending, this will change to every second
txTimer->start(1 * 60 * 1000); txTimer->start(10 * 1000);
} }
RPC::~RPC() { RPC::~RPC() {
@ -276,7 +289,8 @@ void RPC::getInfoThenRefresh() {
.append(QString::number(reply["blocks"].get<json::number_unsigned_t>())) .append(QString::number(reply["blocks"].get<json::number_unsigned_t>()))
.append(")"); .append(")");
main->statusLabel->setText(statusText); main->statusLabel->setText(statusText);
main->statusIcon->clear(); // TODO: Add checked icon QIcon i(":/icons/res/connected.png");
main->statusIcon->setPixmap(i.pixmap(16, 16));
// Refresh everything. // Refresh everything.
refreshBalances(); refreshBalances();
@ -337,17 +351,9 @@ void RPC::refreshBalances() {
}; };
// Function to create the data model and update the views, used below. // Function to create the data model and update the views, used below.
auto updateUI = [=] () { auto updateUI = [=] () {
// Create the balances table model. // Update balances model data, which will update the table too
balancesTableModel->setNewData(allBalances, utxos);
// Delete the old Model, because the setModel() doesn't take ownership of the Model object
delete balancesTableModel;
balancesTableModel = new BalancesTableModel(ui->balancesTable, allBalances, utxos);
ui->balancesTable->setModel(balancesTableModel);
// Configure Balances Table
ui->balancesTable->setColumnWidth(0, 300);
// Add all the addresses into the inputs combo box // Add all the addresses into the inputs combo box
auto lastFromAddr = ui->inputsCombo->currentText().split("(")[0].trimmed(); auto lastFromAddr = ui->inputsCombo->currentText().split("(")[0].trimmed();
@ -355,7 +361,7 @@ void RPC::refreshBalances() {
ui->inputsCombo->clear(); ui->inputsCombo->clear();
auto i = allBalances->constBegin(); auto i = allBalances->constBegin();
while (i != allBalances->constEnd()) { while (i != allBalances->constEnd()) {
QString item = i.key() % "(" % QString::number(i.value(), 'f', 8) % " ZEC)"; QString item = i.key() % "(" % QString::number(i.value(), 'f') % " ZEC)";
ui->inputsCombo->addItem(item); ui->inputsCombo->addItem(item);
if (item.startsWith(lastFromAddr)) ui->inputsCombo->setCurrentText(item); if (item.startsWith(lastFromAddr)) ui->inputsCombo->setCurrentText(item);
@ -376,9 +382,6 @@ void RPC::refreshBalances() {
} }
void RPC::refreshTransactions() { void RPC::refreshTransactions() {
// First, delete the previous headers
delete transactionsTableModel;
auto txdata = new QList<TransactionItem>(); auto txdata = new QList<TransactionItem>();
getTransactions([=] (json reply) { getTransactions([=] (json reply) {
@ -395,12 +398,8 @@ void RPC::refreshTransactions() {
txdata->push_front(tx); txdata->push_front(tx);
} }
transactionsTableModel = new TxTableModel(ui->transactionsTable, txdata); // Update model data, which updates the table view
ui->transactionsTable->setModel(transactionsTableModel); transactionsTableModel->setNewData(txdata);
ui->transactionsTable->setColumnWidth(1, 300);
ui->transactionsTable->setColumnWidth(2, 200);
ui->transactionsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
}); });
} }
@ -418,6 +417,14 @@ void RPC::refreshTxStatus(const QString& newOpid) {
}; };
doRPC(payload, [=] (const json& reply) { 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");
}
// There's an array for each item in the status // There's an array for each item in the status
for (auto& it : reply.get<json::array_t>()) { for (auto& it : reply.get<json::array_t>()) {
// If we were watching this Tx and it's status became "success", then we'll show a status bar alert // If we were watching this Tx and it's status became "success", then we'll show a status bar alert
@ -425,20 +432,18 @@ void RPC::refreshTxStatus(const QString& newOpid) {
if (watchingOps.contains(id)) { if (watchingOps.contains(id)) {
// And if it ended up successful // And if it ended up successful
QString status = QString::fromStdString(it["status"]); QString status = QString::fromStdString(it["status"]);
qDebug() << QString::fromStdString("Watching opid, current status= ") % status;
if (status == "success") { if (status == "success") {
qDebug() << QString::fromStdString("Success, showing status message");
main->ui->statusBar->showMessage(" Tx " % id % " computed successfully and submitted"); main->ui->statusBar->showMessage(" Tx " % id % " computed successfully and submitted");
main->loadingLabel->setVisible(false);
watchingOps.remove(id); watchingOps.remove(id);
txTimer->start(1 * 60 * 1000); txTimer->start(10 * 1000);
// Refresh balances to show unconfirmed balances // Refresh balances to show unconfirmed balances
refresh(); refresh();
} else if (status == "failed") { } else if (status == "failed") {
// If it failed, then we'll actually show a warning. // If it failed, then we'll actually show a warning.
auto errorMsg = QString::fromStdString(it["error"]["message"]); auto errorMsg = QString::fromStdString(it["error"]["message"]);
qDebug() << QString::fromStdString("Failed with message") % errorMsg;
QMessageBox msg( QMessageBox msg(
QMessageBox::Critical, QMessageBox::Critical,
"Transaction Error", "Transaction Error",
@ -447,47 +452,18 @@ void RPC::refreshTxStatus(const QString& newOpid) {
main main
); );
txTimer->start(1 * 60 * 1000);
watchingOps.remove(id); watchingOps.remove(id);
txTimer->start(10 * 1000);
main->ui->statusBar->showMessage(" Tx " % id % " failed", 15 * 1000); main->ui->statusBar->showMessage(" Tx " % id % " failed", 15 * 1000);
main->loadingLabel->setVisible(false);
msg.exec(); msg.exec();
} else if (status == "executing") { } else if (status == "executing") {
// If the operation is executing, then watch every second. // If the operation is executing, then watch every second.
qDebug() << QString::fromStdString("executing, doing again in 1 sec");
txTimer->start(1 * 1000); txTimer->start(1 * 1000);
} }
} }
} }
}); });
} }
/*
[
{
"id": "opid-ad54b34c-1d89-48af-9cb5-4825905fc62e",
"status": "executing",
"creation_time": 1539490482,
"method": "z_sendmany",
"params": {
"fromaddress": "t1aWhRh9JNKWzpzjn2gmULDJzfKLC724EPS",
"amounts": [
{
"address": "zcVHg9euUSQF8ef7ZXztrv4LcdC1mytEUYLuoj4W5iSygLFYjm1yQCggAYnnydUaHLy2GBaxF4PX5vjaJjnj2Lq3ecQtGF4",
"amount": 0.0001
}
],
"minconf": 1,
"fee": 0.0001
}
},{
"id": "opid-7807e672-7f8c-428a-8587-3354d0ae1b88",
"status": "failed",
"creation_time": 1539490847,
"error": {
"code": -6,
"message": "Insufficient protected funds, have 0.0006001, need 111.0001"
},
]
*/

14
src/txtablemodel.cpp

@ -1,9 +1,8 @@
#include "txtablemodel.h" #include "txtablemodel.h"
TxTableModel::TxTableModel(QObject *parent, QList<TransactionItem>* data) TxTableModel::TxTableModel(QObject *parent)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
{ {
modeldata = data;
headers << "Category" << "Address" << "Date/Time" << "Amount"; headers << "Category" << "Address" << "Date/Time" << "Amount";
} }
@ -11,8 +10,17 @@ TxTableModel::~TxTableModel() {
delete modeldata; delete modeldata;
} }
void TxTableModel::setNewData(QList<TransactionItem>* data) {
delete modeldata;
modeldata = data;
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1));
layoutChanged();
}
int TxTableModel::rowCount(const QModelIndex&) const int TxTableModel::rowCount(const QModelIndex&) const
{ {
if (modeldata == nullptr) return 0;
return modeldata->size(); return modeldata->size();
} }
@ -45,7 +53,7 @@ TxTableModel::~TxTableModel() {
case 0: return modeldata->at(index.row()).type; case 0: return modeldata->at(index.row()).type;
case 1: return modeldata->at(index.row()).address; case 1: return modeldata->at(index.row()).address;
case 2: return modeldata->at(index.row()).datetime; case 2: return modeldata->at(index.row()).datetime;
case 3: return QVariant(QString::number(modeldata->at(index.row()).amount, 'f', 8) % " ZEC"); case 3: return QVariant(QString::number(modeldata->at(index.row()).amount, 'f') % " ZEC");
} }
} }

6
src/txtablemodel.h

@ -7,9 +7,11 @@
class TxTableModel: public QAbstractTableModel class TxTableModel: public QAbstractTableModel
{ {
public: public:
TxTableModel(QObject* parent, QList<TransactionItem>* addresses); TxTableModel(QObject* parent);
~TxTableModel(); ~TxTableModel();
void setNewData(QList<TransactionItem>* addresses);
QString getTxId(int row); QString getTxId(int row);
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const;
@ -18,7 +20,7 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private: private:
QList<TransactionItem>* modeldata; QList<TransactionItem>* modeldata = nullptr;
QList<QString> headers; QList<QString> headers;
}; };

48
src/ui_about.h

@ -13,6 +13,8 @@
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtWidgets/QDialog> #include <QtWidgets/QDialog>
#include <QtWidgets/QDialogButtonBox> #include <QtWidgets/QDialogButtonBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QTextEdit> #include <QtWidgets/QTextEdit>
#include <QtWidgets/QVBoxLayout> #include <QtWidgets/QVBoxLayout>
@ -22,6 +24,9 @@ class Ui_about
{ {
public: public:
QVBoxLayout *verticalLayout; QVBoxLayout *verticalLayout;
QGroupBox *groupBox;
QVBoxLayout *verticalLayout_2;
QLabel *versionLabel;
QTextEdit *textEdit; QTextEdit *textEdit;
QDialogButtonBox *buttonBox; QDialogButtonBox *buttonBox;
@ -32,6 +37,18 @@ public:
about->resize(497, 448); about->resize(497, 448);
verticalLayout = new QVBoxLayout(about); verticalLayout = new QVBoxLayout(about);
verticalLayout->setObjectName(QStringLiteral("verticalLayout")); verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
groupBox = new QGroupBox(about);
groupBox->setObjectName(QStringLiteral("groupBox"));
verticalLayout_2 = new QVBoxLayout(groupBox);
verticalLayout_2->setObjectName(QStringLiteral("verticalLayout_2"));
versionLabel = new QLabel(groupBox);
versionLabel->setObjectName(QStringLiteral("versionLabel"));
verticalLayout_2->addWidget(versionLabel);
verticalLayout->addWidget(groupBox);
textEdit = new QTextEdit(about); textEdit = new QTextEdit(about);
textEdit->setObjectName(QStringLiteral("textEdit")); textEdit->setObjectName(QStringLiteral("textEdit"));
textEdit->setReadOnly(true); textEdit->setReadOnly(true);
@ -56,23 +73,26 @@ public:
void retranslateUi(QDialog *about) void retranslateUi(QDialog *about)
{ {
about->setWindowTitle(QApplication::translate("about", "Dialog", nullptr)); about->setWindowTitle(QApplication::translate("about", "Dialog", nullptr));
groupBox->setTitle(QApplication::translate("about", "zcash-qt-wallet", nullptr));
versionLabel->setText(QApplication::translate("about", "Version", nullptr));
textEdit->setHtml(QApplication::translate("about", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" textEdit->setHtml(QApplication::translate("about", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n" "p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;\">\n" "</style></head><body style=\" font-family:'MS Shell Dlg 2'; font-size:8.1pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Copyright (c) 2018 Aditya Kulkarni. (MIT License)</p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">Copyright (c) 2018 Aditya Kulkarni. (MIT License)</span></p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n" "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;\"><br /></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Special thanks to:</p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">Special thanks to:</span></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">JSON for Modern C++ : <a href=\"https://nlohmann.github.io/json/\"><span style=\"" "<p style=\" margin-top:0px; marg"
" text-decoration: underline; color:#007af4;\">https://nlohmann.github.io/json/</span></a></p>\n" "in-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">JSON for Modern C++ : </span><a href=\"https://nlohmann.github.io/json/\"><span style=\" font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;\">https://nlohmann.github.io/json/</span></a></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">QR Code generator library Nayuki : <a href=\"https://www.nayuki.io/page/qr-code-generator-library\"><span style=\" text-decoration: underline; color:#007af4;\">https://www.nayuki.io/page/qr-code-ge\342\200\246</span></a></p>\n" "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">QR Code generator library Nayuki : </span><a href=\"https://www.nayuki.io/page/qr-code-generator-library\"><span style=\" font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;\">https://www.nayuki.io/page/qr-code-ge\342\200\246</span></a></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Made with QT : <a href=\"https://www.qt.io/\"><span style=\" text-decoration: underline; color:#007af4;\">https://www.qt.io/</span></a></p>\n" "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">Made with QT : </span><a hr"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">LICENSE:</p>\n" "ef=\"https://www.qt.io/\"><span style=\" font-family:'Ubuntu'; font-size:11pt; text-decoration: underline; color:#007af4;\">https://www.qt.io/</span></a></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Permission is hereby granted, free of charge, " "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">LICENSE:</span></p>\n"
"to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>\n" "<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Ubuntu'; font-size:11pt;\">Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</span></p>\n"
"<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</li>\n" "<ul style=\"margin-top: 0"
"<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The Software is provided &quot;as is&quot;, without warranty of any kind, express or implied, including but not limited to the w" "px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" font-family:'Ubuntu'; font-size:11pt;\" style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</li>\n"
"arranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.</li></ul></body></html>", nullptr)); "<li style=\" font-family:'Ubuntu'; font-size:11pt;\" style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The Software is provided &quot;as is&quot;, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the"
" Software.</li></ul></body></html>", nullptr));
} // retranslateUi } // retranslateUi
}; };

8
zcash-qt-wallet.pro

@ -13,13 +13,19 @@ PRECOMPILED_HEADER = src/precompiled.h
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = zcash-qt-wallet TARGET = zcash-qt-wallet
APP_VERSION=\\\"0.1.5\\\"
TEMPLATE = app TEMPLATE = app
# The following define makes your compiler emit warnings if you use # The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings # any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the # depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it. # deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS DEFINES += \
QT_DEPRECATED_WARNINGS \
APP_VERSION=$$APP_VERSION
INCLUDEPATH += src/3rdparty/ INCLUDEPATH += src/3rdparty/

Loading…
Cancel
Save