Browse Source

#23 Basic address book support for sending addresses

zboard small fixes
recurring
Aditya Kulkarni 6 years ago
parent
commit
b2f758242d
  1. 192
      src/addressbook.cpp
  2. 39
      src/addressbook.h
  3. 133
      src/addressbook.ui
  4. 22
      src/mainwindow.cpp
  5. 1
      src/mainwindow.h
  6. 26
      src/mainwindow.ui
  7. 3
      src/precompiled.h
  8. 19
      src/sendtab.cpp
  9. 11
      src/utils.cpp
  10. 2
      src/utils.h
  11. 2
      src/zboard.ui
  12. 9
      zec-qt-wallet.pro

192
src/addressbook.cpp

@ -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

@ -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

@ -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>

22
src/mainwindow.cpp

@ -1,5 +1,7 @@
#include "mainwindow.h"
#include "addressbook.h"
#include "ui_mainwindow.h"
#include "ui_addressbook.h"
#include "ui_zboard.h"
#include "ui_privkey.h"
#include "ui_about.h"
@ -50,6 +52,9 @@ MainWindow::MainWindow(QWidget *parent) :
// 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
QObject::connect(ui->actionAbout, &QAction::triggered, [=] () {
QDialog aboutDialog(this);
@ -404,9 +409,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() {
// Set up a donation to me :)
ui->Address1->setText(Utils::getDonationAddr(
@ -452,11 +471,12 @@ void MainWindow::postToZBoard() {
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;
memo = zb.postAs->text().trimmed() + ":: " + memo;
tx.toAddrs.push_back(ToFields{ Utils::getZboardAddr(), Utils::getZboardAmount(), memo, memo.toUtf8().toHex() });
tx.fee = Utils::getMinerFee();

1
src/mainwindow.h

@ -81,6 +81,7 @@ private:
QString doSendTxValidations(Tx tx);
void donate();
void addressBook();
void postToZBoard();
void importPrivKey();
void exportAllKeys();

26
src/mainwindow.ui

@ -22,7 +22,7 @@
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>2</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -343,6 +343,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="AddressBook1">
<property name="text">
<string>Address Book</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -727,7 +734,6 @@
</property>
<addaction name="actionImport_Private_Key"/>
<addaction name="actionExport_All_Private_Keys"/>
<addaction name="actionSettings"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
@ -746,7 +752,15 @@
<addaction name="actionTurnstile_Migration"/>
<addaction name="actionz_board_net"/>
</widget>
<widget class="QMenu" name="menu_Edit">
<property name="title">
<string>&amp;Edit</string>
</property>
<addaction name="action_Address_Book"/>
<addaction name="actionSettings"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menu_Edit"/>
<addaction name="menuApps"/>
<addaction name="menuHelp"/>
</widget>
@ -805,6 +819,14 @@
<string>Ctrl+A, Ctrl+Z</string>
</property>
</action>
<action name="action_Address_Book">
<property name="text">
<string>Address &amp;Book</string>
</property>
<property name="shortcut">
<string>Ctrl+B</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

3
src/precompiled.h

@ -12,6 +12,8 @@
#include <QClipboard>
#include <QStringBuilder>
#include <QAbstractItemModel>
#include <QTableView>
#include <QHeaderView>
#include <QMessageBox>
#include <QCheckBox>
#include <QScrollBar>
@ -19,6 +21,7 @@
#include <QMovie>
#include <QPair>
#include <QDir>
#include <QMenu>
#include <QDateTime>
#include <QTimer>
#include <QSettings>

19
src/sendtab.cpp

@ -1,5 +1,6 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "addressbook.h"
#include "ui_confirm.h"
#include "ui_memodialog.h"
#include "settings.h"
@ -45,6 +46,12 @@ void MainWindow::setupSendTab() {
this->addressChanged(1, text);
});
// The first address book button
QObject::connect(ui->AddressBook1, &QPushButton::clicked, [=] () {
AddressBook::open(this, ui->Address1);
});
// The first Amount button
QObject::connect(ui->Amount1, &QLineEdit::textChanged, [=] (auto text) {
this->amountChanged(1, text);
@ -143,6 +150,16 @@ void MainWindow::addAddressSection() {
});
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);
auto horizontalLayout_13 = new QHBoxLayout();
@ -546,7 +563,5 @@ QString MainWindow::doSendTxValidations(Tx tx) {
void MainWindow::cancelButton() {
removeExtraAddresses();
// Back to the balances tab
ui->tabWidget->setCurrentIndex(0);
}

11
src/utils.cpp

@ -87,4 +87,15 @@ double Utils::getDevFee() {
return 0;
}
}
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);
}

2
src/utils.h

@ -22,6 +22,8 @@ public:
static double getDevFee();
static double getTotalFee();
static bool isValidAddress(QString addr);
static const int updateSpeed = 20 * 1000; // 20 sec
static const int quickUpdateSpeed = 5 * 1000; // 5 sec
static const int priceRefreshSpeed = 60 * 60 * 1000; // 1 hr

2
src/zboard.ui

@ -95,7 +95,7 @@
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ZBoard is Fully anonymous and untraceable chat messages based on the ZCash blockchain. &lt;a href=&quot;http://www.z-board.net/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.z-board.net/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Posting to ZBoard: #Main_Area&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ZBoard is a fully anonymous and untraceable chat messages based on the ZCash blockchain. &lt;a href=&quot;http://www.z-board.net/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://www.z-board.net/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Posting to ZBoard: #Main_Area&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>

9
zec-qt-wallet.pro

@ -53,7 +53,8 @@ SOURCES += \
src/turnstile.cpp \
src/utils.cpp \
src/qrcodelabel.cpp \
src/connection.cpp
src/connection.cpp \
src/addressbook.cpp
HEADERS += \
src/mainwindow.h \
@ -71,7 +72,8 @@ HEADERS += \
src/turnstile.h \
src/utils.h \
src/qrcodelabel.h \
src/connection.h
src/connection.h \
src/addressbook.h
FORMS += \
src/mainwindow.ui \
@ -83,7 +85,8 @@ FORMS += \
src/privkey.ui \
src/memodialog.ui \
src/connection.ui \
src/zboard.ui
src/zboard.ui \
src/addressbook.ui
win32: RC_ICONS = res/icon.ico

Loading…
Cancel
Save