Merge branch 'master' into embedded
This commit is contained in:
12
README.md
12
README.md
@@ -9,20 +9,20 @@ Head over to the releases page and grab the latest binary. https://github.com/ad
|
|||||||
### Linux
|
### Linux
|
||||||
Extract and run the binary
|
Extract and run the binary
|
||||||
```
|
```
|
||||||
tar -xvf zec-qt-wallet-v0.2.7.tar.gz
|
tar -xvf zec-qt-wallet-v0.2.8.tar.gz
|
||||||
./zec-qt-wallet-v0.2.7/zec-qt-wallet
|
./zec-qt-wallet-v0.2.8/zec-qt-wallet
|
||||||
```
|
```
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
Unzip the release binary and double click on zec-qt-wallet to start.
|
Unzip the release binary and double click on zec-qt-wallet to start.
|
||||||
|
|
||||||
## Prerequisites: zcashd
|
## Prerequisites: zcashd
|
||||||
zec-qt-wallet needs a Zcash node running zcashd. Linux users should download the zcash node software
|
zec-qt-wallet needs a Zcash node running zcashd. Linux users should download the Zcash node software
|
||||||
from [https://z.cash/download/](https://z.cash/download/), configure `zcash.conf`, download the parameters and start zcashd according to the [official documentation](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html).
|
from [https://z.cash/download/](https://z.cash/download/), configure `zcash.conf`, download the parameters and start zcashd according to the [official documentation](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html).
|
||||||
|
|
||||||
There is currently no official zcashd build for Windows so Windows users may either [cross-compile from source on Linux](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#installation) to generate the necessary zcashd executables or simply download community hosted pre-compiled executables such as those hosted by WinZEC developer [@radix42](https://github.com/radix42) at https://zcash.dl.mercerweiss.com/zcash-win-v2.0.1b.zip.
|
There is currently no official zcashd build for Windows so Windows users may either [cross-compile from source on Linux](https://zcash.readthedocs.io/en/latest/rtd_pages/user_guide.html#installation) to generate the necessary zcashd executables or simply download community hosted pre-compiled executables such as those hosted by WinZEC developer [@radix42](https://github.com/radix42) at https://zcash.dl.mercerweiss.com/zcash-win-v2.0.1b.zip.
|
||||||
|
|
||||||
Alternitavely run zcashd inside [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
Alternatively run zcashd inside [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
||||||
|
|
||||||
For all installations zcashd needs to run with RPC enabled (`server=1`, which is the default) and with a RPC username/password set. Add the following entries into `~/.zcash/zcash.conf` for Linux or` C:\Users\your-username\AppData\Roaming\Zcash\zcash.conf` on Windows replacing the default values with a strong password. zec-qt-wallet should detect these settings but if that fails you may edit the connection settings manually via the `File->Settings` menu.
|
For all installations zcashd needs to run with RPC enabled (`server=1`, which is the default) and with a RPC username/password set. Add the following entries into `~/.zcash/zcash.conf` for Linux or` C:\Users\your-username\AppData\Roaming\Zcash\zcash.conf` on Windows replacing the default values with a strong password. zec-qt-wallet should detect these settings but if that fails you may edit the connection settings manually via the `File->Settings` menu.
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ rpcuser=username
|
|||||||
rpcpassword=password
|
rpcpassword=password
|
||||||
```
|
```
|
||||||
|
|
||||||
Additionaly for Windows users the Zcash parameters must be manually downloaded and placed in `C:\Users\your-username\AppData\Roaming\ZcashParams`. The following files are required (and are around ~1.7GB in total).
|
Additionally for Windows users the Zcash parameters must be manually downloaded and placed in `C:\Users\your-username\AppData\Roaming\ZcashParams`. The following files are required (and are around ~1.7GB in total).
|
||||||
|
|
||||||
```
|
```
|
||||||
https://z.cash/downloads/sapling-spend.params
|
https://z.cash/downloads/sapling-spend.params
|
||||||
@@ -87,7 +87,7 @@ The easiest way to connect to a remote node is probably to ssh to it with port f
|
|||||||
ssh -L8232:127.0.0.1:8232 user@remotehost
|
ssh -L8232:127.0.0.1:8232 user@remotehost
|
||||||
```
|
```
|
||||||
### 2. "Not enough balance" when sending transactions
|
### 2. "Not enough balance" when sending transactions
|
||||||
The most likely cause for this is that you are trying to spend unconfirmed funds. Unlike bitcoin, the zcash protocol doesn't let you spent unconfirmed funds yet. Please wait for
|
The most likely cause for this is that you are trying to spend unconfirmed funds. Unlike Bitcoin, the Zcash protocol doesn't let you spent unconfirmed funds yet. Please wait for
|
||||||
1-2 blocks for the funds to confirm and retry the transaction.
|
1-2 blocks for the funds to confirm and retry the transaction.
|
||||||
|
|
||||||
### Support or other questions
|
### Support or other questions
|
||||||
|
|||||||
192
src/addressbook.cpp
Normal file
192
src/addressbook.cpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#include "addressbook.h"
|
||||||
|
#include "ui_addressbook.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
AddressBookModel::AddressBookModel(QTableView *parent)
|
||||||
|
: QAbstractTableModel(parent) {
|
||||||
|
headers << "Label" << "Address";
|
||||||
|
|
||||||
|
this->parent = parent;
|
||||||
|
loadDataFromStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressBookModel::~AddressBookModel() {
|
||||||
|
if (labels != nullptr)
|
||||||
|
saveDataToStorage();
|
||||||
|
|
||||||
|
delete labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressBookModel::saveDataToStorage() {
|
||||||
|
QFile file(writeableFile());
|
||||||
|
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||||
|
QDataStream out(&file); // we will serialize the data into the file
|
||||||
|
out << QString("v1") << *labels;
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// Save column positions
|
||||||
|
QSettings().setValue("addresstablegeometry", parent->horizontalHeader()->saveState());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AddressBookModel::loadDataFromStorage() {
|
||||||
|
QFile file(writeableFile());
|
||||||
|
|
||||||
|
delete labels;
|
||||||
|
labels = new QList<QPair<QString, QString>>();
|
||||||
|
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QDataStream in(&file); // read the data serialized from the file
|
||||||
|
QString version;
|
||||||
|
in >> version >> *labels;
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressBookModel::addNewLabel(QString label, QString addr) {
|
||||||
|
labels->push_back(QPair<QString, QString>(label, addr));
|
||||||
|
|
||||||
|
dataChanged(index(0, 0), index(labels->size()-1, columnCount(index(0,0))-1));
|
||||||
|
layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressBookModel::removeItemAt(int row) {
|
||||||
|
if (row >= labels->size())
|
||||||
|
return;
|
||||||
|
labels->removeAt(row);
|
||||||
|
|
||||||
|
dataChanged(index(0, 0), index(labels->size()-1, columnCount(index(0,0))-1));
|
||||||
|
layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> AddressBookModel::itemAt(int row) {
|
||||||
|
if (row >= labels->size()) return QPair<QString, QString>();
|
||||||
|
|
||||||
|
return labels->at(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString AddressBookModel::writeableFile() {
|
||||||
|
auto filename = QStringLiteral("addresslabels.dat");
|
||||||
|
|
||||||
|
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||||
|
if (!dir.exists())
|
||||||
|
QDir().mkpath(dir.absolutePath());
|
||||||
|
|
||||||
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
|
return dir.filePath("testnet-" % filename);
|
||||||
|
} else {
|
||||||
|
return dir.filePath(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AddressBookModel::rowCount(const QModelIndex&) const {
|
||||||
|
if (labels == nullptr) return 0;
|
||||||
|
return labels->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int AddressBookModel::columnCount(const QModelIndex&) const {
|
||||||
|
return headers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariant AddressBookModel::data(const QModelIndex &index, int role) const {
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
switch(index.column()) {
|
||||||
|
case 0: return labels->at(index.row()).first;
|
||||||
|
case 1: return labels->at(index.row()).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||||
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
|
return headers.at(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressBook::open(MainWindow* parent, QLineEdit* target) {
|
||||||
|
QDialog d(parent);
|
||||||
|
Ui_addressBook ab;
|
||||||
|
ab.setupUi(&d);
|
||||||
|
|
||||||
|
AddressBookModel model(ab.addresses);
|
||||||
|
ab.addresses->setModel(&model);
|
||||||
|
|
||||||
|
// If there is no target, the we'll call the button "Ok", else "Pick"
|
||||||
|
if (target != nullptr) {
|
||||||
|
ab.buttonBox->button(QDialogButtonBox::Ok)->setText("Pick");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a target then make it the addr for the "Add to" button
|
||||||
|
if (target != nullptr && Utils::isValidAddress(target->text())) {
|
||||||
|
ab.addr->setText(target->text());
|
||||||
|
ab.label->setFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (!Utils::isValidAddress(addr)) {
|
||||||
|
QMessageBox::critical(parent, "Address Format Error", addr + " doesn't seem to be a valid Zcash address.", QMessageBox::Ok);
|
||||||
|
} else {
|
||||||
|
model.addNewLabel(ab.label->text(), ab.addr->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Double-Click picks the item
|
||||||
|
QObject::connect(ab.addresses, &QTableView::doubleClicked, [&] (auto index) {
|
||||||
|
if (index.row() < 0) return;
|
||||||
|
|
||||||
|
QString addr = model.itemAt(index.row()).second;
|
||||||
|
d.accept();
|
||||||
|
target->setText(addr);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Right-Click
|
||||||
|
ab.addresses->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
QObject::connect(ab.addresses, &QTableView::customContextMenuRequested, [&] (QPoint pos) {
|
||||||
|
QModelIndex index = ab.addresses->indexAt(pos);
|
||||||
|
|
||||||
|
if (index.row() < 0) return;
|
||||||
|
|
||||||
|
QString addr = model.itemAt(index.row()).second;
|
||||||
|
|
||||||
|
QMenu menu(parent);
|
||||||
|
|
||||||
|
if (target != nullptr) {
|
||||||
|
menu.addAction("Pick", [&] () {
|
||||||
|
target->setText(addr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addAction("Copy Address", [&] () {
|
||||||
|
QGuiApplication::clipboard()->setText(addr);
|
||||||
|
parent->ui->statusBar->showMessage("Copied to clipboard", 3 * 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.addAction("Delete Label", [&] () {
|
||||||
|
model.removeItemAt(index.row());
|
||||||
|
});
|
||||||
|
|
||||||
|
menu.exec(ab.addresses->viewport()->mapToGlobal(pos));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (d.exec() == QDialog::Accepted && target != nullptr) {
|
||||||
|
auto selection = ab.addresses->selectionModel();
|
||||||
|
if (selection->hasSelection()) {
|
||||||
|
target->setText(model.itemAt(selection->selectedRows().at(0).row()).second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
39
src/addressbook.h
Normal file
39
src/addressbook.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef ADDRESSBOOK_H
|
||||||
|
#define ADDRESSBOOK_H
|
||||||
|
|
||||||
|
#include "precompiled.h"
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
|
||||||
|
class AddressBookModel : public QAbstractTableModel {
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddressBookModel(QTableView* parent);
|
||||||
|
~AddressBookModel();
|
||||||
|
|
||||||
|
void addNewLabel(QString label, QString addr);
|
||||||
|
void removeItemAt(int row);
|
||||||
|
QPair<QString, QString> itemAt(int row);
|
||||||
|
|
||||||
|
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:
|
||||||
|
void loadDataFromStorage();
|
||||||
|
void saveDataToStorage();
|
||||||
|
|
||||||
|
QString writeableFile();
|
||||||
|
|
||||||
|
QTableView* parent;
|
||||||
|
QList<QPair<QString, QString>>* labels = nullptr;
|
||||||
|
QStringList headers;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddressBook {
|
||||||
|
public:
|
||||||
|
static void open(MainWindow* parent, QLineEdit* target = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADDRESSBOOK_H
|
||||||
133
src/addressbook.ui
Normal file
133
src/addressbook.ui
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>addressBook</class>
|
||||||
|
<widget class="QDialog" name="addressBook">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>690</width>
|
||||||
|
<height>562</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Address Book</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Add New Address</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_1">
|
||||||
|
<property name="text">
|
||||||
|
<string>Address (z-Addr or t-Addr)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="addr"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Label</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="label"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addNew">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add to Address Book</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="addresses">
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<attribute name="horizontalHeaderStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>addressBook</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>addressBook</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -258,7 +258,7 @@ void ConnectionLoader::refreshZcashdState(Connection* connection) {
|
|||||||
} else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) {
|
} else if (err == QNetworkReply::NetworkError::AuthenticationRequiredError) {
|
||||||
QString explanation = QString()
|
QString explanation = QString()
|
||||||
% "Authentication failed. The username / password you specified was "
|
% "Authentication failed. The username / password you specified was "
|
||||||
% "not accepted by zcashd. Try changing it in the File->Settings menu";
|
% "not accepted by zcashd. Try changing it in the Edit->Settings menu";
|
||||||
|
|
||||||
this->showError(explanation);
|
this->showError(explanation);
|
||||||
} else if (err == QNetworkReply::NetworkError::InternalServerError && !res.is_discarded()) {
|
} else if (err == QNetworkReply::NetworkError::InternalServerError && !res.is_discarded()) {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "addressbook.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
#include "ui_addressbook.h"
|
||||||
|
#include "ui_zboard.h"
|
||||||
#include "ui_privkey.h"
|
#include "ui_privkey.h"
|
||||||
#include "ui_about.h"
|
#include "ui_about.h"
|
||||||
#include "ui_settings.h"
|
#include "ui_settings.h"
|
||||||
@@ -46,6 +49,12 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
// Export All Private Keys
|
// Export All Private Keys
|
||||||
QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys);
|
QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys);
|
||||||
|
|
||||||
|
// z-Board.net
|
||||||
|
QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard);
|
||||||
|
|
||||||
|
// Address Book
|
||||||
|
QObject::connect(ui->action_Address_Book, &QAction::triggered, this, &MainWindow::addressBook);
|
||||||
|
|
||||||
// Set up about action
|
// Set up about action
|
||||||
QObject::connect(ui->actionAbout, &QAction::triggered, [=] () {
|
QObject::connect(ui->actionAbout, &QAction::triggered, [=] () {
|
||||||
QDialog aboutDialog(this);
|
QDialog aboutDialog(this);
|
||||||
@@ -404,9 +413,23 @@ void MainWindow::setupSettingsModal() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::addressBook() {
|
||||||
|
// Check to see if there is a target.
|
||||||
|
QRegExp re("Address[0-9]+", Qt::CaseInsensitive);
|
||||||
|
for (auto target: ui->sendToWidgets->findChildren<QLineEdit *>(re)) {
|
||||||
|
if (target->hasFocus()) {
|
||||||
|
AddressBook::open(this, target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If there was no target, then just run with no target.
|
||||||
|
AddressBook::open(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::donate() {
|
void MainWindow::donate() {
|
||||||
// Set up a donation to me :)
|
// Set up a donation to me :)
|
||||||
ui->Address1->setText(Utils::getDonationAddr(
|
ui->Address1->setText(Utils::getDonationAddr(
|
||||||
@@ -421,6 +444,80 @@ void MainWindow::donate() {
|
|||||||
ui->tabWidget->setCurrentIndex(1);
|
ui->tabWidget->setCurrentIndex(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::postToZBoard() {
|
||||||
|
QDialog d(this);
|
||||||
|
Ui_zboard zb;
|
||||||
|
zb.setupUi(&d);
|
||||||
|
|
||||||
|
// Fill the from field with sapling addresses.
|
||||||
|
for (auto i = rpc->getAllBalances()->keyBegin(); i != rpc->getAllBalances()->keyEnd(); i++) {
|
||||||
|
if (Settings::getInstance()->isSaplingAddress(*i) && rpc->getAllBalances()->value(*i) > 0) {
|
||||||
|
zb.fromAddr->addItem(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Testnet warning
|
||||||
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
|
zb.testnetWarning->setText("You are on testnet, your post won't actually appear on z-board.net");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
zb.testnetWarning->setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
zb.feeAmount->setText(Settings::getInstance()->getZECUSDDisplayFormat(Utils::getZboardAmount() + Utils::getMinerFee()));
|
||||||
|
|
||||||
|
QObject::connect(zb.memoTxt, &QPlainTextEdit::textChanged, [=] () {
|
||||||
|
QString txt = zb.memoTxt->toPlainText();
|
||||||
|
zb.memoSize->setText(QString::number(txt.toUtf8().size()) + "/512");
|
||||||
|
|
||||||
|
if (txt.toUtf8().size() <= 512) {
|
||||||
|
// Everything is fine
|
||||||
|
zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
|
||||||
|
zb.memoSize->setStyleSheet("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Overweight
|
||||||
|
zb.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
zb.memoSize->setStyleSheet("color: red;");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
zb.memoTxt->setFocus();
|
||||||
|
|
||||||
|
if (d.exec() == QDialog::Accepted) {
|
||||||
|
// Create a transaction.
|
||||||
|
Tx tx;
|
||||||
|
|
||||||
|
// Send from your first sapling address that has a balance.
|
||||||
|
tx.fromAddr = zb.fromAddr->currentText();
|
||||||
|
if (tx.fromAddr.isEmpty()) {
|
||||||
|
QMessageBox::critical(this, "Error Posting Message", "You need a sapling address with available balance to post", QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto memo = zb.memoTxt->toPlainText().trimmed();
|
||||||
|
if (!zb.postAs->text().trimmed().isEmpty())
|
||||||
|
memo = zb.postAs->text().trimmed() + ":: " + memo;
|
||||||
|
|
||||||
|
tx.toAddrs.push_back(ToFields{ Utils::getZboardAddr(), Utils::getZboardAmount(), memo, memo.toUtf8().toHex() });
|
||||||
|
tx.fee = Utils::getMinerFee();
|
||||||
|
|
||||||
|
json params = json::array();
|
||||||
|
rpc->fillTxJsonParams(params, tx);
|
||||||
|
std::cout << std::setw(2) << params << std::endl;
|
||||||
|
|
||||||
|
// And send the Tx
|
||||||
|
rpc->sendZTransaction(params, [=](const json& reply) {
|
||||||
|
QString opid = QString::fromStdString(reply.get<json::string_t>());
|
||||||
|
ui->statusBar->showMessage("Computing Tx: " % opid);
|
||||||
|
|
||||||
|
// And then start monitoring the transaction
|
||||||
|
rpc->addNewTxToWatch(tx, opid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::doImport(QList<QString>* keys) {
|
void MainWindow::doImport(QList<QString>* keys) {
|
||||||
qDebug() << keys->size();
|
qDebug() << keys->size();
|
||||||
if (keys->isEmpty()) {
|
if (keys->isEmpty()) {
|
||||||
@@ -644,10 +741,10 @@ void MainWindow::setupTransactionsTab() {
|
|||||||
void MainWindow::addNewZaddr(bool sapling) {
|
void MainWindow::addNewZaddr(bool sapling) {
|
||||||
rpc->newZaddr(sapling, [=] (json reply) {
|
rpc->newZaddr(sapling, [=] (json reply) {
|
||||||
QString addr = QString::fromStdString(reply.get<json::string_t>());
|
QString addr = QString::fromStdString(reply.get<json::string_t>());
|
||||||
// Make sure the RPC class reloads the Z-addrs for future use
|
// Make sure the RPC class reloads the z-addrs for future use
|
||||||
rpc->refreshAddresses();
|
rpc->refreshAddresses();
|
||||||
|
|
||||||
// Just double make sure the Z-address is still checked
|
// Just double make sure the z-address is still checked
|
||||||
if (( sapling && ui->rdioZSAddr->isChecked()) ||
|
if (( sapling && ui->rdioZSAddr->isChecked()) ||
|
||||||
(!sapling && ui->rdioZAddr->isChecked())) {
|
(!sapling && ui->rdioZAddr->isChecked())) {
|
||||||
ui->listRecieveAddresses->insertItem(0, addr);
|
ui->listRecieveAddresses->insertItem(0, addr);
|
||||||
@@ -688,7 +785,7 @@ void MainWindow::setupRecieveTab() {
|
|||||||
rpc->newTaddr([=] (json reply) {
|
rpc->newTaddr([=] (json reply) {
|
||||||
QString addr = QString::fromStdString(reply.get<json::string_t>());
|
QString addr = QString::fromStdString(reply.get<json::string_t>());
|
||||||
|
|
||||||
// Just double make sure the T-address is still checked
|
// Just double make sure the t-address is still checked
|
||||||
if (ui->rdioTAddr->isChecked()) {
|
if (ui->rdioTAddr->isChecked()) {
|
||||||
ui->listRecieveAddresses->insertItem(0, addr);
|
ui->listRecieveAddresses->insertItem(0, addr);
|
||||||
ui->listRecieveAddresses->setCurrentIndex(0);
|
ui->listRecieveAddresses->setCurrentIndex(0);
|
||||||
@@ -700,8 +797,8 @@ void MainWindow::setupRecieveTab() {
|
|||||||
|
|
||||||
// Connect t-addr radio button
|
// Connect t-addr radio button
|
||||||
QObject::connect(ui->rdioTAddr, &QRadioButton::toggled, [=] (bool checked) {
|
QObject::connect(ui->rdioTAddr, &QRadioButton::toggled, [=] (bool checked) {
|
||||||
// Whenever the T-address is selected, we generate a new address, because we don't
|
// Whenever the t-address is selected, we generate a new address, because we don't
|
||||||
// want to reuse T-addrs
|
// want to reuse t-addrs
|
||||||
if (checked && this->rpc->getUTXOs() != nullptr) {
|
if (checked && this->rpc->getUTXOs() != nullptr) {
|
||||||
auto utxos = this->rpc->getUTXOs();
|
auto utxos = this->rpc->getUTXOs();
|
||||||
ui->listRecieveAddresses->clear();
|
ui->listRecieveAddresses->clear();
|
||||||
@@ -733,12 +830,12 @@ void MainWindow::setupRecieveTab() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Focus enter for the Recieve Tab
|
// Focus enter for the Receive Tab
|
||||||
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int tab) {
|
QObject::connect(ui->tabWidget, &QTabWidget::currentChanged, [=] (int tab) {
|
||||||
if (tab == 2) {
|
if (tab == 2) {
|
||||||
// Switched to recieve tab, so update everything.
|
// Switched to receive tab, so update everything.
|
||||||
|
|
||||||
// Hide Sapling radio button if sapling is not active
|
// Hide Sapling radio button if Sapling is not active
|
||||||
if (Settings::getInstance()->isSaplingActive()) {
|
if (Settings::getInstance()->isSaplingActive()) {
|
||||||
ui->rdioZSAddr->setVisible(true);
|
ui->rdioZSAddr->setVisible(true);
|
||||||
ui->rdioZSAddr->setChecked(true);
|
ui->rdioZSAddr->setChecked(true);
|
||||||
@@ -746,7 +843,7 @@ void MainWindow::setupRecieveTab() {
|
|||||||
} else {
|
} else {
|
||||||
ui->rdioZSAddr->setVisible(false);
|
ui->rdioZSAddr->setVisible(false);
|
||||||
ui->rdioZAddr->setChecked(true);
|
ui->rdioZAddr->setChecked(true);
|
||||||
ui->rdioZAddr->setText("z-Addr"); // Don't use the "Sprout" label if there's no sapling
|
ui->rdioZAddr->setText("z-Addr"); // Don't use the "Sprout" label if there's no Sapling
|
||||||
}
|
}
|
||||||
|
|
||||||
// And then select the first one
|
// And then select the first one
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ private:
|
|||||||
QString doSendTxValidations(Tx tx);
|
QString doSendTxValidations(Tx tx);
|
||||||
|
|
||||||
void donate();
|
void donate();
|
||||||
|
void addressBook();
|
||||||
|
void postToZBoard();
|
||||||
void importPrivKey();
|
void importPrivKey();
|
||||||
void exportAllKeys();
|
void exportAllKeys();
|
||||||
void doImport(QList<QString>* keys);
|
void doImport(QList<QString>* keys);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>2</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="tab">
|
<widget class="QWidget" name="tab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
@@ -343,6 +343,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="AddressBook1">
|
||||||
|
<property name="text">
|
||||||
|
<string>Address Book</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -727,8 +734,6 @@
|
|||||||
</property>
|
</property>
|
||||||
<addaction name="actionImport_Private_Key"/>
|
<addaction name="actionImport_Private_Key"/>
|
||||||
<addaction name="actionExport_All_Private_Keys"/>
|
<addaction name="actionExport_All_Private_Keys"/>
|
||||||
<addaction name="actionTurnstile_Migration"/>
|
|
||||||
<addaction name="actionSettings"/>
|
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionExit"/>
|
<addaction name="actionExit"/>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -740,7 +745,23 @@
|
|||||||
<addaction name="actionCheck_for_Updates"/>
|
<addaction name="actionCheck_for_Updates"/>
|
||||||
<addaction name="actionAbout"/>
|
<addaction name="actionAbout"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuApps">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Apps</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionTurnstile_Migration"/>
|
||||||
|
<addaction name="actionz_board_net"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Edit">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Edit</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="action_Address_Book"/>
|
||||||
|
<addaction name="actionSettings"/>
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menu_Edit"/>
|
||||||
|
<addaction name="menuApps"/>
|
||||||
<addaction name="menuHelp"/>
|
<addaction name="menuHelp"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar"/>
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
@@ -776,6 +797,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sapling &Turnstile</string>
|
<string>Sapling &Turnstile</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+A, Ctrl+T</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionImport_Private_Key">
|
<action name="actionImport_Private_Key">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -787,6 +811,22 @@
|
|||||||
<string>Export All Private Keys</string>
|
<string>Export All Private Keys</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionz_board_net">
|
||||||
|
<property name="text">
|
||||||
|
<string>&z-board.net</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+A, Ctrl+Z</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_Address_Book">
|
||||||
|
<property name="text">
|
||||||
|
<string>Address &Book</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+B</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Memo</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QHeaderView>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
#include <QMovie>
|
#include <QMovie>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMenu>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ void RPC::getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>
|
|||||||
|
|
||||||
// A special function that will call the callback when two lists have been added
|
// A special function that will call the callback when two lists have been added
|
||||||
auto holder = new QPair<int, QList<QPair<QString, QString>>>();
|
auto holder = new QPair<int, QList<QPair<QString, QString>>>();
|
||||||
holder->first = 0; // This is the number of times the callback has been called, initalized to 0
|
holder->first = 0; // This is the number of times the callback has been called, initialized to 0
|
||||||
auto fnCombineTwoLists = [=] (QList<QPair<QString, QString>> list) {
|
auto fnCombineTwoLists = [=] (QList<QPair<QString, QString>> list) {
|
||||||
// Increment the callback counter
|
// Increment the callback counter
|
||||||
holder->first++;
|
holder->first++;
|
||||||
@@ -277,7 +277,7 @@ void RPC::getAllPrivKeys(const std::function<void(QList<QPair<QString, QString>>
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// First get all the T and Z addresses.
|
// First get all the t and z addresses.
|
||||||
json payloadT = {
|
json payloadT = {
|
||||||
{"jsonrpc", "1.0"},
|
{"jsonrpc", "1.0"},
|
||||||
{"id", "someid"},
|
{"id", "someid"},
|
||||||
@@ -707,7 +707,7 @@ void RPC::watchTxStatus() {
|
|||||||
conn->doRPCWithDefaultErrorHandling(payload, [=] (const json& reply) {
|
conn->doRPCWithDefaultErrorHandling(payload, [=] (const json& reply) {
|
||||||
// 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 its status became "success", then we'll show a status bar alert
|
||||||
QString id = QString::fromStdString(it["id"]);
|
QString id = QString::fromStdString(it["id"]);
|
||||||
if (watchingOps.contains(id)) {
|
if (watchingOps.contains(id)) {
|
||||||
// And if it ended up successful
|
// And if it ended up successful
|
||||||
@@ -763,7 +763,7 @@ void RPC::watchTxStatus() {
|
|||||||
|
|
||||||
// Get the ZEC->USD price from coinmarketcap using their API
|
// Get the ZEC->USD price from coinmarketcap using their API
|
||||||
void RPC::refreshZECPrice() {
|
void RPC::refreshZECPrice() {
|
||||||
qDebug() << QString::fromStdString("Getting zec price");
|
qDebug() << QString::fromStdString("Getting ZEC price");
|
||||||
if (conn == nullptr)
|
if (conn == nullptr)
|
||||||
return noConnection();
|
return noConnection();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ echo "Linux"
|
|||||||
|
|
||||||
echo -n "Configuring..."
|
echo -n "Configuring..."
|
||||||
$QT_STATIC/bin/qmake zec-qt-wallet.pro -spec linux-clang CONFIG+=release > /dev/null
|
$QT_STATIC/bin/qmake zec-qt-wallet.pro -spec linux-clang CONFIG+=release > /dev/null
|
||||||
#Mingw seems to have trouble with precompiled heades, so strip that option from the .pro file
|
#Mingw seems to have trouble with precompiled headers, so strip that option from the .pro file
|
||||||
echo "[OK]"
|
echo "[OK]"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
#include "addressbook.h"
|
||||||
#include "ui_confirm.h"
|
#include "ui_confirm.h"
|
||||||
#include "ui_memodialog.h"
|
#include "ui_memodialog.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -45,6 +46,12 @@ void MainWindow::setupSendTab() {
|
|||||||
this->addressChanged(1, text);
|
this->addressChanged(1, text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The first address book button
|
||||||
|
QObject::connect(ui->AddressBook1, &QPushButton::clicked, [=] () {
|
||||||
|
AddressBook::open(this, ui->Address1);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// The first Amount button
|
// The first Amount button
|
||||||
QObject::connect(ui->Amount1, &QLineEdit::textChanged, [=] (auto text) {
|
QObject::connect(ui->Amount1, &QLineEdit::textChanged, [=] (auto text) {
|
||||||
this->amountChanged(1, text);
|
this->amountChanged(1, text);
|
||||||
@@ -143,6 +150,16 @@ void MainWindow::addAddressSection() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
horizontalLayout_12->addWidget(Address1);
|
horizontalLayout_12->addWidget(Address1);
|
||||||
|
|
||||||
|
auto addressBook1 = new QPushButton(verticalGroupBox);
|
||||||
|
addressBook1->setObjectName(QStringLiteral("AddressBook") % QString::number(itemNumber));
|
||||||
|
addressBook1->setText("Address Book");
|
||||||
|
QObject::connect(addressBook1, &QPushButton::clicked, [=] () {
|
||||||
|
AddressBook::open(this, Address1);
|
||||||
|
});
|
||||||
|
|
||||||
|
horizontalLayout_12->addWidget(addressBook1);
|
||||||
|
|
||||||
sendAddressLayout->addLayout(horizontalLayout_12);
|
sendAddressLayout->addLayout(horizontalLayout_12);
|
||||||
|
|
||||||
auto horizontalLayout_13 = new QHBoxLayout();
|
auto horizontalLayout_13 = new QHBoxLayout();
|
||||||
@@ -217,7 +234,7 @@ void MainWindow::setMemoEnabled(int number, bool enabled) {
|
|||||||
memoBtn->setToolTip("");
|
memoBtn->setToolTip("");
|
||||||
} else {
|
} else {
|
||||||
memoBtn->setEnabled(false);
|
memoBtn->setEnabled(false);
|
||||||
memoBtn->setToolTip("Only Z addresses can have memos");
|
memoBtn->setToolTip("Only z-addresses can have memos");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,8 +242,8 @@ void MainWindow::memoButtonClicked(int number) {
|
|||||||
// Memos can only be used with zAddrs. So check that first
|
// Memos can only be used with zAddrs. So check that first
|
||||||
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") + QString::number(number));
|
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address") + QString::number(number));
|
||||||
if (!addr->text().trimmed().startsWith("z")) {
|
if (!addr->text().trimmed().startsWith("z")) {
|
||||||
QMessageBox msg(QMessageBox::Critical, "Memos can only be used with z Addresses",
|
QMessageBox msg(QMessageBox::Critical, "Memos can only be used with z-addresses",
|
||||||
"The Memo field can only be used with a z Address.\n" + addr->text() + "\ndoesn't look like a z Address",
|
"The memo field can only be used with a z-address.\n" + addr->text() + "\ndoesn't look like a z-address",
|
||||||
QMessageBox::Ok, this);
|
QMessageBox::Ok, this);
|
||||||
|
|
||||||
msg.exec();
|
msg.exec();
|
||||||
@@ -245,7 +262,17 @@ void MainWindow::memoButtonClicked(int number) {
|
|||||||
QString txt = memoDialog.memoTxt->toPlainText();
|
QString txt = memoDialog.memoTxt->toPlainText();
|
||||||
memoDialog.memoSize->setText(QString::number(txt.toUtf8().size()) + "/512");
|
memoDialog.memoSize->setText(QString::number(txt.toUtf8().size()) + "/512");
|
||||||
|
|
||||||
memoDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(txt.toUtf8().size() <= 512);
|
if (txt.toUtf8().size() <= 512) {
|
||||||
|
// Everything is fine
|
||||||
|
memoDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
|
||||||
|
memoDialog.memoSize->setStyleSheet("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Overweight
|
||||||
|
memoDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
memoDialog.memoSize->setStyleSheet("color: red;");
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
memoDialog.memoTxt->setPlainText(currentMemo);
|
memoDialog.memoTxt->setPlainText(currentMemo);
|
||||||
@@ -261,7 +288,7 @@ void MainWindow::removeExtraAddresses() {
|
|||||||
// The last one is a spacer, so ignore that
|
// The last one is a spacer, so ignore that
|
||||||
int totalItems = ui->sendToWidgets->children().size() - 2;
|
int totalItems = ui->sendToWidgets->children().size() - 2;
|
||||||
|
|
||||||
// Clear the first recepient fields
|
// Clear the first recipient fields
|
||||||
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address1"));
|
auto addr = ui->sendToWidgets->findChild<QLineEdit*>(QString("Address1"));
|
||||||
addr->clear();
|
addr->clear();
|
||||||
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount1"));
|
auto amt = ui->sendToWidgets->findChild<QLineEdit*>(QString("Amount1"));
|
||||||
@@ -511,7 +538,7 @@ void MainWindow::sendButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::doSendTxValidations(Tx tx) {
|
QString MainWindow::doSendTxValidations(Tx tx) {
|
||||||
// 1. Addresses are valid format.
|
// 1. Addresses have valid format.
|
||||||
QRegExp zcexp("^z[a-z0-9]{94}$", Qt::CaseInsensitive);
|
QRegExp zcexp("^z[a-z0-9]{94}$", Qt::CaseInsensitive);
|
||||||
QRegExp zsexp("^z[a-z0-9]{77}$", Qt::CaseInsensitive);
|
QRegExp zsexp("^z[a-z0-9]{77}$", Qt::CaseInsensitive);
|
||||||
QRegExp ztsexp("^ztestsapling[a-z0-9]{76}", Qt::CaseInsensitive);
|
QRegExp ztsexp("^ztestsapling[a-z0-9]{76}", Qt::CaseInsensitive);
|
||||||
@@ -536,7 +563,5 @@ QString MainWindow::doSendTxValidations(Tx tx) {
|
|||||||
|
|
||||||
void MainWindow::cancelButton() {
|
void MainWindow::cancelButton() {
|
||||||
removeExtraAddresses();
|
removeExtraAddresses();
|
||||||
// Back to the balances tab
|
|
||||||
ui->tabWidget->setCurrentIndex(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) {
|
|||||||
if (!Settings::getInstance()->getSaveZtxs())
|
if (!Settings::getInstance()->getSaveZtxs())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Also, only store outgoing Txs where the from address is a z-Addr. Else, regular zcashd
|
// Also, only store outgoing txs where the from address is a z-Addr. Else, regular zcashd
|
||||||
// stores it just fine
|
// stores it just fine
|
||||||
if (!tx.fromAddr.startsWith("z"))
|
if (!tx.fromAddr.startsWith("z"))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void Turnstile::planMigration(QString zaddr, QString destAddr, int numsplits, in
|
|||||||
auto bal = rpc->getAllBalances()->value(zaddr);
|
auto bal = rpc->getAllBalances()->value(zaddr);
|
||||||
auto splits = splitAmount(bal, numsplits);
|
auto splits = splitAmount(bal, numsplits);
|
||||||
|
|
||||||
// Then, generate an intermediate t-Address for each part using getBatchRPC
|
// Then, generate an intermediate t-address for each part using getBatchRPC
|
||||||
rpc->getConnection()->doBatchRPC<double>(splits,
|
rpc->getConnection()->doBatchRPC<double>(splits,
|
||||||
[=] (double /*unused*/) {
|
[=] (double /*unused*/) {
|
||||||
json payload = {
|
json payload = {
|
||||||
@@ -186,7 +186,7 @@ void Turnstile::fillAmounts(QList<double>& amounts, double amount, int count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get a random amount off the amount (between half and full) and call recursively.
|
// Get a random amount off the amount (between half and full) and call recursively.
|
||||||
// Multiply by hundered, because we'll operate on 0.01 ZEC minimum. We'll divide by 100 later
|
// Multiply by hundred, because we'll operate on 0.01 ZEC minimum. We'll divide by 100 later
|
||||||
double curAmount = std::rand() % (int)std::floor(amount * 100);
|
double curAmount = std::rand() % (int)std::floor(amount * 100);
|
||||||
|
|
||||||
// Try to round it off
|
// Try to round it off
|
||||||
@@ -319,14 +319,14 @@ void Turnstile::executeMigrationStep() {
|
|||||||
|
|
||||||
} else if (nextStep->status == TurnstileMigrationItemStatus::SentToT) {
|
} else if (nextStep->status == TurnstileMigrationItemStatus::SentToT) {
|
||||||
// First thing to do is check to see if the funds are confirmed.
|
// First thing to do is check to see if the funds are confirmed.
|
||||||
// We'll check both the original sprout address and the intermediate T addr for safety.
|
// We'll check both the original sprout address and the intermediate t-addr for safety.
|
||||||
if (fnHasUnconfirmed(nextStep->intTAddr) || fnHasUnconfirmed(nextStep->fromAddr)) {
|
if (fnHasUnconfirmed(nextStep->intTAddr) || fnHasUnconfirmed(nextStep->fromAddr)) {
|
||||||
//qDebug() << QString("unconfirmed, waiting");
|
//qDebug() << QString("unconfirmed, waiting");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rpc->getAllBalances()->keys().contains(nextStep->intTAddr)) {
|
if (!rpc->getAllBalances()->keys().contains(nextStep->intTAddr)) {
|
||||||
qDebug() << QString("The intermediate Taddress doesn't have balance, even though it is confirmed");
|
qDebug() << QString("The intermediate t-address doesn't have balance, even though it is confirmed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const QString Utils::getDevAddr(Tx tx) {
|
|||||||
return devAddr;
|
return devAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// t-Addr, find if it is going to a sprout or sapling address
|
// t-Addr, find if it is going to a Sprout or Sapling address
|
||||||
for (const ToFields& to : tx.toAddrs) {
|
for (const ToFields& to : tx.toAddrs) {
|
||||||
devAddr = testnetAddrLookup(to.addr);
|
devAddr = testnetAddrLookup(to.addr);
|
||||||
if (!devAddr.isEmpty()) {
|
if (!devAddr.isEmpty()) {
|
||||||
@@ -55,7 +55,7 @@ const QString Utils::getDevAddr(Tx tx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a t-Addr -> t-Addr transaction, use the sapling address by default
|
// If this is a t-Addr -> t-Addr transaction, use the Sapling address by default
|
||||||
return testnetAddrLookup("ztestsapling");
|
return testnetAddrLookup("ztestsapling");
|
||||||
} else {
|
} else {
|
||||||
// Mainnet doesn't have a fee yet!
|
// Mainnet doesn't have a fee yet!
|
||||||
@@ -67,6 +67,19 @@ const QString Utils::getDevAddr(Tx tx) {
|
|||||||
double Utils::getMinerFee() {
|
double Utils::getMinerFee() {
|
||||||
return 0.0001;
|
return 0.0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Utils::getZboardAmount() {
|
||||||
|
return 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Utils::getZboardAddr() {
|
||||||
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
|
return getDonationAddr(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "zs10m00rvkhfm4f7n23e4sxsx275r7ptnggx39ygl0vy46j9mdll5c97gl6dxgpk0njuptg2mn9w5s";
|
||||||
|
}
|
||||||
|
}
|
||||||
double Utils::getDevFee() {
|
double Utils::getDevFee() {
|
||||||
if (Settings::getInstance()->isTestnet()) {
|
if (Settings::getInstance()->isTestnet()) {
|
||||||
return 0.0001;
|
return 0.0001;
|
||||||
@@ -74,4 +87,15 @@ double Utils::getDevFee() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double Utils::getTotalFee() { return getMinerFee() + getDevFee(); }
|
double Utils::getTotalFee() { return getMinerFee() + getDevFee(); }
|
||||||
|
|
||||||
|
bool Utils::isValidAddress(QString addr) {
|
||||||
|
QRegExp zcexp("^z[a-z0-9]{94}$", Qt::CaseInsensitive);
|
||||||
|
QRegExp zsexp("^z[a-z0-9]{77}$", Qt::CaseInsensitive);
|
||||||
|
QRegExp ztsexp("^ztestsapling[a-z0-9]{76}", Qt::CaseInsensitive);
|
||||||
|
QRegExp texp("^t[a-z0-9]{34}$", Qt::CaseInsensitive);
|
||||||
|
|
||||||
|
return zcexp.exactMatch(addr) || texp.exactMatch(addr) ||
|
||||||
|
ztsexp.exactMatch(addr) || zsexp.exactMatch(addr);
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,9 +17,13 @@ public:
|
|||||||
static const QString getDonationAddr(bool sapling);
|
static const QString getDonationAddr(bool sapling);
|
||||||
|
|
||||||
static double getMinerFee();
|
static double getMinerFee();
|
||||||
|
static double getZboardAmount();
|
||||||
|
static QString getZboardAddr();
|
||||||
static double getDevFee();
|
static double getDevFee();
|
||||||
static double getTotalFee();
|
static double getTotalFee();
|
||||||
|
|
||||||
|
static bool isValidAddress(QString addr);
|
||||||
|
|
||||||
static const int updateSpeed = 20 * 1000; // 20 sec
|
static const int updateSpeed = 20 * 1000; // 20 sec
|
||||||
static const int quickUpdateSpeed = 5 * 1000; // 5 sec
|
static const int quickUpdateSpeed = 5 * 1000; // 5 sec
|
||||||
static const int priceRefreshSpeed = 60 * 60 * 1000; // 1 hr
|
static const int priceRefreshSpeed = 60 * 60 * 1000; // 1 hr
|
||||||
|
|||||||
160
src/zboard.ui
Normal file
160
src/zboard.ui
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>zboard</class>
|
||||||
|
<widget class="QDialog" name="zboard">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>588</width>
|
||||||
|
<height>431</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Post to z-board.net</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="14" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Total Fee</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="1">
|
||||||
|
<widget class="QLabel" name="feeAmount">
|
||||||
|
<property name="text">
|
||||||
|
<string>feeamount</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="1">
|
||||||
|
<widget class="QLabel" name="memoSize">
|
||||||
|
<property name="text">
|
||||||
|
<string>0 / 512</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="16" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Memo</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="postAs">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>(optional)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Send From</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Post As:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>ZBoard: Fully anonymous and untraceable chat messages based on the ZCash blockchain. <a href="http://www.z-board.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.z-board.net/</span></a></p><p>Posting to ZBoard: #Main_Area</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="0" colspan="2">
|
||||||
|
<widget class="QPlainTextEdit" name="memoTxt"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0" colspan="2">
|
||||||
|
<widget class="QComboBox" name="fromAddr"/>
|
||||||
|
</item>
|
||||||
|
<item row="15" column="0">
|
||||||
|
<widget class="QLabel" name="testnetWarning">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color:red;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="2">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>fromAddr</tabstop>
|
||||||
|
<tabstop>postAs</tabstop>
|
||||||
|
<tabstop>memoTxt</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>zboard</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>zboard</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
@@ -13,7 +13,7 @@ PRECOMPILED_HEADER = src/precompiled.h
|
|||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
TARGET = zec-qt-wallet
|
TARGET = zec-qt-wallet
|
||||||
APP_VERSION=\\\"0.2.7\\\"
|
APP_VERSION=\\\"0.2.8\\\"
|
||||||
|
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
@@ -54,7 +54,8 @@ SOURCES += \
|
|||||||
src/utils.cpp \
|
src/utils.cpp \
|
||||||
src/qrcodelabel.cpp \
|
src/qrcodelabel.cpp \
|
||||||
src/connection.cpp \
|
src/connection.cpp \
|
||||||
src/fillediconlabel.cpp
|
src/fillediconlabel.cpp \
|
||||||
|
src/addressbook.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/mainwindow.h \
|
src/mainwindow.h \
|
||||||
@@ -73,7 +74,8 @@ HEADERS += \
|
|||||||
src/utils.h \
|
src/utils.h \
|
||||||
src/qrcodelabel.h \
|
src/qrcodelabel.h \
|
||||||
src/connection.h \
|
src/connection.h \
|
||||||
src/fillediconlabel.h
|
src/fillediconlabel.h \
|
||||||
|
src/addressbook.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
src/mainwindow.ui \
|
src/mainwindow.ui \
|
||||||
@@ -84,7 +86,9 @@ FORMS += \
|
|||||||
src/turnstileprogress.ui \
|
src/turnstileprogress.ui \
|
||||||
src/privkey.ui \
|
src/privkey.ui \
|
||||||
src/memodialog.ui \
|
src/memodialog.ui \
|
||||||
src/connection.ui
|
src/connection.ui \
|
||||||
|
src/zboard.ui \
|
||||||
|
src/addressbook.ui
|
||||||
|
|
||||||
win32: RC_ICONS = res/icon.ico
|
win32: RC_ICONS = res/icon.ico
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user