Tumin changes #133

Open
duke wants to merge 5 commits from dan_s/SilentDragon:tumin into dev
  1. 1
      application-sdx.qrc
  2. 1
      application.qrc
  3. 24
      build-tumin.sh
  4. 114
      res/css/tumin.css
  5. BIN
      silentdragontumin
  6. 162
      silentdragontumin.pro
  7. 208
      src/addressbook.cpp
  8. 610
      src/connection.cpp
  9. 190
      src/main.cpp
  10. 896
      src/mainwindow.cpp
  11. 76
      src/requestdialog.cpp
  12. 1250
      src/rpc.cpp
  13. 99
      src/senttxstore.cpp
  14. 396
      src/settings.cpp
  15. 288
      src/txtablemodel.cpp

1
application-sdx.qrc

@ -59,6 +59,7 @@
<file alias="light.css">res/css/light.css</file> <file alias="light.css">res/css/light.css</file>
<file alias="midnight.css">res/css/midnight.css</file> <file alias="midnight.css">res/css/midnight.css</file>
<file alias="dragonx.css">res/css/dragonx.css</file> <file alias="dragonx.css">res/css/dragonx.css</file>
<file alias="tumin.css">res/css/tumin.css</file>
</qresource> </qresource>
<qresource prefix="/images/blue"> <qresource prefix="/images/blue">
<file alias="unchecked.png">res/images/blue/unchecked.png</file> <file alias="unchecked.png">res/images/blue/unchecked.png</file>

1
application.qrc

@ -59,6 +59,7 @@
<file alias="light.css">res/css/light.css</file> <file alias="light.css">res/css/light.css</file>
<file alias="midnight.css">res/css/midnight.css</file> <file alias="midnight.css">res/css/midnight.css</file>
<file alias="dragonx.css">res/css/dragonx.css</file> <file alias="dragonx.css">res/css/dragonx.css</file>
<file alias="tumin.css">res/css/tumin.css</file>
</qresource> </qresource>
<qresource prefix="/images/blue"> <qresource prefix="/images/blue">
<file alias="unchecked.png">res/images/blue/unchecked.png</file> <file alias="unchecked.png">res/images/blue/unchecked.png</file>

24
build-tumin.sh

@ -0,0 +1,24 @@
#!/bin/bash
# Copyright 2018-2023 The Hush Developers
# Released under the GPLv3
# This builds a binary called "silentdragonx"
set -e
# TODO: not ideal, hushd.exe should only be looked for on windoze
if [ -e "dragonxd" ]; then
echo "Found dragonxd binary"
elif [ -e "hushd.exe" ]; then
echo "Found hushd.exe binary"
else
echo "dragonxd could not be found!"
echo "Either copy the binary to this dir or make a symlink."
echo "This command will create a symlink to it if this repo is in the same directory as your hush3.git: "
echo "ln -s ../hush3/src/dragonxd"
echo "For windoze you should copy hushd.exe to this directory"
exit 1
fi
# Use a modified QT project file with same build.sh
SDCONF=silentdragontumin.pro ./build.sh $@

114
res/css/tumin.css

@ -0,0 +1,114 @@
QWidget, QMainWindow, QMenuBar, QMenu, QDialog, QTabWidget, QTableView, QScrollArea, QGroupBox, QPlainTextEdit, QLineEdit, QLabel, MainWindow {
background-color: #232834;
color: #91a4b8;
}
QTabWidget QTabBar::tab {
padding-left:20px;
padding-right:20px;
padding-top:5px;
padding-bottom:5px;
border: 1px solid #343F4B;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
}
QTabWidget QTabBar::tab:selected {
min-height: 10px;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
border: 1px ridge #91a4b8;
}
QTabWidget QTabBar::tab:hover {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
border: 1px ridge #91a4b8;
min-height: 20px
}
QHeaderView {
/* Table Header */
background-color:#232834;
}
QHeaderView::section {
/* Table Header Sections */
qproperty-alignment:center;
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color:#91a4b8;
min-height:25px;
font-weight:bold;
font-size:11px;
outline:0;
border:1px solid #343F4B;
border-right:1px solid #91a4b8;
border-left:1px solid #91a4b8;
padding-left:5px;
padding-right:5px;
padding-top:2px;
padding-bottom:2px;
}
QHeaderView::section:last {
border-right: 0px solid #d7d7d7;
}
QScrollArea {
background:transparent;
border:0px;
}
QTableView {
/* Table - has to be selected as a class otherwise it throws off QCalendarWidget */
background:#232834;
}
QTableView::item {
/* Table Item */
background-color:#232834;
border:1px solid #91a4b8;
font-size:12px;
}
QTableView::item:selected {
/* Table Item Selected */
background-color:#91a4b8;
color:#232834;
}
QMenuBar {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color: #91a4b8;
}
QMenuBar::item {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
color: #91a4b8;
}
QMenuBar::item:selected {
background-color:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.25, stop: 0 #343F4B, stop: 1 #232834);
}
QPushButton#startmining {
background-color: #343F4B;
border-color: #91A4B8;
padding: 10px;
}
QPushButton#startmining:hover {
background-color: #232834;
}
QPushButton#startmining:pressed {
background-color: #232834;
}
QPushButton#startmining:disabled {
background-color: #232834;
}
QPushButton#stopmining {
background-color: #343F4B;
border-color: #91A4B8;
padding: 10px;
margin-top: 7px;
}
QPushButton#stopmining:hover {
background-color: #232834;
}
QPushButton#stopmining:pressed {
background-color: #232834;
}
QPushButton#stopmining:disabled {
background-color: #232834;
}
QComboBox#genproclimit{
font-size: 24px;
height: 40px;
}
QMenu::item:selected{
background-color: #343F4B
}

BIN
silentdragontumin

Binary file not shown.

162
silentdragontumin.pro

@ -0,0 +1,162 @@
# Copyright 2018-2023 The Hush Developers
# Released under the GPLv3
QT += core gui network
CONFIG += precompile_header
PRECOMPILED_HEADER = src/precompiled.h
QT += widgets
TARGET = silentdragontumin
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += \
QT_DEPRECATED_WARNINGS
INCLUDEPATH += src/3rdparty/
INCLUDEPATH += src/
mac: LIBS+= -Wl,-dead_strip
mac: LIBS+= -Wl,-dead_strip_dylibs
mac: LIBS+= -Wl,-bind_at_load
RESOURCES = application-sdx.qrc
MOC_DIR = bin
OBJECTS_DIR = bin
UI_DIR = src
CONFIG += c++14
SOURCES += \
src/main.cpp \
src/mainwindow.cpp \
src/rpc.cpp \
src/balancestablemodel.cpp \
src/3rdparty/qrcode/BitBuffer.cpp \
src/3rdparty/qrcode/QrCode.cpp \
src/3rdparty/qrcode/QrSegment.cpp \
src/settings.cpp \
src/sendtab.cpp \
src/senttxstore.cpp \
src/txtablemodel.cpp \
src/peerstablemodel.cpp \
src/bannedpeerstablemodel.cpp \
src/qrcodelabel.cpp \
src/connection.cpp \
src/fillediconlabel.cpp \
src/addressbook.cpp \
src/logger.cpp \
src/addresscombo.cpp \
src/validateaddress.cpp \
src/recurring.cpp \
src/requestdialog.cpp \
src/memoedit.cpp \
src/viewalladdresses.cpp
HEADERS += \
src/guiconstants.h \
src/mainwindow.h \
src/precompiled.h \
src/rpc.h \
src/balancestablemodel.h \
src/3rdparty/qrcode/BitBuffer.hpp \
src/3rdparty/qrcode/QrCode.hpp \
src/3rdparty/qrcode/QrSegment.hpp \
src/settings.h \
src/txtablemodel.h \
src/peerstablemodel.h \
src/bannedpeerstablemodel.h \
src/senttxstore.h \
src/qrcodelabel.h \
src/connection.h \
src/fillediconlabel.h \
src/addressbook.h \
src/logger.h \
src/addresscombo.h \
src/validateaddress.h \
src/recurring.h \
src/requestdialog.h \
src/memoedit.h \
src/viewalladdresses.h
FORMS += \
src/mainwindow.ui \
src/qrcode.ui \
src/rescandialog.ui \
src/settings.ui \
src/about.ui \
src/confirm.ui \
src/privkey.ui \
src/viewkey.ui \
src/memodialog.ui \
src/viewalladdresses.ui \
src/validateaddress.ui \
src/viewalladdresses.ui \
src/connection.ui \
src/addressbook.ui \
src/viewalladdresses.ui \
src/createhushconfdialog.ui \
src/recurringdialog.ui \
src/newrecurring.ui \
src/requestdialog.ui
TRANSLATIONS = res-drgx/silentdragon_be.ts \
res-drgx/silentdragon_bg.ts \
res-drgx/silentdragon_de.ts \
res-drgx/silentdragon_es.ts \
res-drgx/silentdragon_fi.ts \
res-drgx/silentdragon_fil.ts \
res-drgx/silentdragon_fr.ts \
res-drgx/silentdragon_hr.ts \
res-drgx/silentdragon_id.ts \
res-drgx/silentdragon_it.ts \
res-drgx/silentdragon_nl.ts \
res-drgx/silentdragon_pl.ts \
res-drgx/silentdragon_pt.ts \
res-drgx/silentdragon_ro.ts \
res-drgx/silentdragon_ru.ts \
res-drgx/silentdragon_sr.ts \
res-drgx/silentdragon_tr.ts \
res-drgx/silentdragon_uk.ts \
res-drgx/silentdragon_zh.ts
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication _FORTIFY_SOURCE=2
QMAKE_INFO_PLIST = res-drgx/Info.plist
win32: RC_ICONS = res-drgx/icon.ico
ICON = res-drgx/logo.icns
libsodium.target = $$PWD/res/libsodium.a
libsodium.commands = res/libsodium/buildlibsodium.sh
QMAKE_EXTRA_TARGETS += libsodium
QMAKE_CLEAN += res/libsodium.a
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/res/ -llibsodium
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/res/ -llibsodiumd
else:unix: LIBS += -L$$PWD/res/ -lsodium
INCLUDEPATH += $$PWD/res
DEPENDPATH += $$PWD/res
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/res/liblibsodium.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/res/liblibsodium.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/res/libsodium.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/res/libsodiumd.lib
else:unix: PRE_TARGETDEPS += $$PWD/res/libsodium.a

208
src/addressbook.cpp

@ -7,96 +7,110 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "rpc.h" #include "rpc.h"
extern bool isdragonx; extern bool isHSC;
extern std::string HSC_name;
AddressBookModel::AddressBookModel(QTableView *parent) AddressBookModel::AddressBookModel(QTableView *parent)
: QAbstractTableModel(parent) { : QAbstractTableModel(parent)
{
headers << tr("Label") << tr("Address"); headers << tr("Label") << tr("Address");
this->parent = parent; this->parent = parent;
loadData(); loadData();
} }
AddressBookModel::~AddressBookModel() { AddressBookModel::~AddressBookModel()
{
saveData(); saveData();
} }
void AddressBookModel::saveData() { void AddressBookModel::saveData()
{
// Save column positions // Save column positions
QSettings().setValue("addresstablegeometry", parent->horizontalHeader()->saveState()); QSettings().setValue("addresstablegeometry", parent->horizontalHeader()->saveState());
} }
void AddressBookModel::loadData()
void AddressBookModel::loadData() { {
labels = AddressBook::getInstance()->getAllAddressLabels(); labels = AddressBook::getInstance()->getAllAddressLabels();
parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray()); parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray());
} }
void AddressBookModel::addNewLabel(QString label, QString addr) { void AddressBookModel::addNewLabel(QString label, QString addr)
//labels.push_back(QPair<QString, QString>(label, addr)); {
// labels.push_back(QPair<QString, QString>(label, addr));
AddressBook::getInstance()->addAddressLabel(label, addr); AddressBook::getInstance()->addAddressLabel(label, addr);
labels.clear(); labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels(); labels = AddressBook::getInstance()->getAllAddressLabels();
dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1)); dataChanged(index(0, 0), index(labels.size() - 1, columnCount(index(0, 0)) - 1));
layoutChanged(); layoutChanged();
} }
void AddressBookModel::removeItemAt(int row) { void AddressBookModel::removeItemAt(int row)
{
if (row >= labels.size()) if (row >= labels.size())
return; return;
AddressBook::getInstance()->removeAddressLabel(labels[row].first, labels[row].second); AddressBook::getInstance()->removeAddressLabel(labels[row].first, labels[row].second);
labels.clear(); labels.clear();
labels = AddressBook::getInstance()->getAllAddressLabels(); labels = AddressBook::getInstance()->getAllAddressLabels();
dataChanged(index(0, 0), index(labels.size()-1, columnCount(index(0,0))-1)); dataChanged(index(0, 0), index(labels.size() - 1, columnCount(index(0, 0)) - 1));
layoutChanged(); layoutChanged();
} }
QPair<QString, QString> AddressBookModel::itemAt(int row) { QPair<QString, QString> AddressBookModel::itemAt(int row)
if (row >= labels.size()) return QPair<QString, QString>(); {
if (row >= labels.size())
return QPair<QString, QString>();
return labels.at(row); return labels.at(row);
} }
int AddressBookModel::rowCount(const QModelIndex &) const
int AddressBookModel::rowCount(const QModelIndex&) const { {
return labels.size(); return labels.size();
} }
int AddressBookModel::columnCount(const QModelIndex&) const { int AddressBookModel::columnCount(const QModelIndex &) const
{
return headers.size(); return headers.size();
} }
QVariant AddressBookModel::data(const QModelIndex &index, int role) const
QVariant AddressBookModel::data(const QModelIndex &index, int role) const { {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole)
switch(index.column()) { {
case 0: return labels.at(index.row()).first; switch (index.column())
case 1: return labels.at(index.row()).second; {
case 0:
return labels.at(index.row()).first;
case 1:
return labels.at(index.row()).second;
} }
} }
return QVariant(); return QVariant();
} }
QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { {
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
return headers.at(section); return headers.at(section);
} }
return QVariant(); return QVariant();
} }
//=============== //===============
// AddressBook // AddressBook
//=============== //===============
void AddressBook::open(MainWindow* parent, QLineEdit* target) { void AddressBook::open(MainWindow *parent, QLineEdit *target)
{
QDialog d(parent); QDialog d(parent);
Ui_addressBook ab; Ui_addressBook ab;
ab.setupUi(&d); ab.setupUi(&d);
@ -109,21 +123,25 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
ab.addresses->setModel(&model); ab.addresses->setModel(&model);
// If there is no target, the we'll call the button "Ok", else "Pick" // If there is no target, the we'll call the button "Ok", else "Pick"
if (target != nullptr) { if (target != nullptr)
{
ab.buttonBox->button(QDialogButtonBox::Ok)->setText(QObject::tr("Pick")); ab.buttonBox->button(QDialogButtonBox::Ok)->setText(QObject::tr("Pick"));
} }
// Connect the dialog's closing to updating the label address completor // Connect the dialog's closing to updating the label address completor
QObject::connect(&d, &QDialog::finished, [=] (auto) { parent->updateLabels(); }); QObject::connect(&d, &QDialog::finished, [=](auto)
{ parent->updateLabels(); });
// If there is a target then make it the addr for the "Add to" button // If there is a target then make it the addr for the "Add to" button
if (target != nullptr && Settings::isValidAddress(target->text())) { if (target != nullptr && Settings::isValidAddress(target->text()))
{
ab.addr->setText(target->text()); ab.addr->setText(target->text());
ab.label->setFocus(); ab.label->setFocus();
} }
// Add new address button // Add new address button
QObject::connect(ab.addNew, &QPushButton::clicked, [&] () { QObject::connect(ab.addNew, &QPushButton::clicked, [&]()
{
auto addr = ab.addr->text().trimmed(); auto addr = ab.addr->text().trimmed();
QString newLabel = ab.label->text(); QString newLabel = ab.label->text();
@ -150,11 +168,11 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
return; return;
} }
model.addNewLabel(newLabel, ab.addr->text()); model.addNewLabel(newLabel, ab.addr->text()); });
});
// Import Button // Import Button
QObject::connect(ab.btnImport, &QPushButton::clicked, [&] () { QObject::connect(ab.btnImport, &QPushButton::clicked, [&]()
{
// Get the import file name. // Get the import file name.
auto fileName = QFileDialog::getOpenFileUrl(&d, QObject::tr("Import Address Book"), QUrl(), auto fileName = QFileDialog::getOpenFileUrl(&d, QObject::tr("Import Address Book"), QUrl(),
"CSV file (*.csv)"); "CSV file (*.csv)");
@ -184,15 +202,16 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
} }
QMessageBox::information(&d, QObject::tr("Address Book Import Done"), QMessageBox::information(&d, QObject::tr("Address Book Import Done"),
QObject::tr("Imported %1 new Address book entries").arg(numImported)); QObject::tr("Imported %1 new Address book entries").arg(numImported)); });
});
auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr) { auto fnSetTargetLabelAddr = [=](QLineEdit *target, QString label, QString addr)
{
target->setText(label % "/" % addr); target->setText(label % "/" % addr);
}; };
// Double-Click picks the item // Double-Click picks the item
QObject::connect(ab.addresses, &QTableView::doubleClicked, [&] (auto index) { QObject::connect(ab.addresses, &QTableView::doubleClicked, [&](auto index)
{
// If there's no target, then double-clicking does nothing. // If there's no target, then double-clicking does nothing.
if (!target) if (!target)
return; return;
@ -202,12 +221,12 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
QString lbl = model.itemAt(index.row()).first; QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second; QString addr = model.itemAt(index.row()).second;
d.accept(); d.accept();
fnSetTargetLabelAddr(target, lbl, addr); fnSetTargetLabelAddr(target, lbl, addr); });
});
// Right-Click // Right-Click
ab.addresses->setContextMenuPolicy(Qt::CustomContextMenu); ab.addresses->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(ab.addresses, &QTableView::customContextMenuRequested, [&] (QPoint pos) { QObject::connect(ab.addresses, &QTableView::customContextMenuRequested, [&](QPoint pos)
{
QModelIndex index = ab.addresses->indexAt(pos); QModelIndex index = ab.addresses->indexAt(pos);
if (index.row() < 0) return; if (index.row() < 0) return;
@ -233,12 +252,13 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
model.removeItemAt(index.row()); model.removeItemAt(index.row());
}); });
menu.exec(ab.addresses->viewport()->mapToGlobal(pos)); menu.exec(ab.addresses->viewport()->mapToGlobal(pos)); });
});
if (d.exec() == QDialog::Accepted && target != nullptr) { if (d.exec() == QDialog::Accepted && target != nullptr)
{
auto selection = ab.addresses->selectionModel(); auto selection = ab.addresses->selectionModel();
if (selection && selection->hasSelection() && selection->selectedRows().size() > 0) { if (selection && selection->hasSelection() && selection->selectedRows().size() > 0)
{
auto item = model.itemAt(selection->selectedRows().at(0).row()); auto item = model.itemAt(selection->selectedRows().at(0).row());
fnSetTargetLabelAddr(target, item.first, item.second); fnSetTargetLabelAddr(target, item.first, item.second);
} }
@ -251,26 +271,30 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
//============= //=============
// AddressBook singleton class // AddressBook singleton class
//============= //=============
AddressBook* AddressBook::getInstance() { AddressBook *AddressBook::getInstance()
{
if (!instance) if (!instance)
instance = new AddressBook(); instance = new AddressBook();
return instance; return instance;
} }
AddressBook::AddressBook() { AddressBook::AddressBook()
{
readFromStorage(); readFromStorage();
} }
void AddressBook::readFromStorage() { void AddressBook::readFromStorage()
{
QFile file(AddressBook::writeableFile()); QFile file(AddressBook::writeableFile());
if (file.exists()) { if (file.exists())
{
allLabels.clear(); allLabels.clear();
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
QDataStream in(&file); // read the data serialized from the file QDataStream in(&file); // read the data serialized from the file
QString version; QString version;
in >> version >> allLabels; in >> version >> allLabels;
file.close(); file.close();
} }
@ -284,40 +308,48 @@ void AddressBook::readFromStorage() {
// } // }
} }
void AddressBook::writeToStorage() { void AddressBook::writeToStorage()
{
QFile file(AddressBook::writeableFile()); QFile file(AddressBook::writeableFile());
file.open(QIODevice::ReadWrite | QIODevice::Truncate); file.open(QIODevice::ReadWrite | QIODevice::Truncate);
QDataStream out(&file); // we will serialize the data into the file QDataStream out(&file); // we will serialize the data into the file
out << QString("v1") << allLabels; out << QString("v1") << allLabels;
file.close(); file.close();
} }
QString AddressBook::writeableFile() { QString AddressBook::writeableFile()
{
auto filename = QStringLiteral("addresslabels.dat"); auto filename = QStringLiteral("addresslabels.dat");
if (isdragonx) { if (isHSC)
filename = QStringLiteral("addresslabels-drgx.dat"); {
filename = QString::fromStdString("addresslabels-" + HSC_name + ".dat");
} }
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (!dir.exists()) if (!dir.exists())
QDir().mkpath(dir.absolutePath()); QDir().mkpath(dir.absolutePath());
if (Settings::getInstance()->isTestnet()) { if (Settings::getInstance()->isTestnet())
{
return dir.filePath("testnet-" % filename); return dir.filePath("testnet-" % filename);
} else { }
else
{
return dir.filePath(filename); return dir.filePath(filename);
} }
} }
// Add a new address/label to the database // Add a new address/label to the database
void AddressBook::addAddressLabel(QString label, QString address) { void AddressBook::addAddressLabel(QString label, QString address)
{
Q_ASSERT(Settings::isValidAddress(address)); Q_ASSERT(Settings::isValidAddress(address));
// First, remove any existing label // First, remove any existing label
// Iterate over the list and remove the label/address // Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) { for (int i = 0; i < allLabels.size(); i++)
if (allLabels[i].first == label) { {
if (allLabels[i].first == label)
{
removeAddressLabel(allLabels[i].first, allLabels[i].second); removeAddressLabel(allLabels[i].first, allLabels[i].second);
} }
} }
@ -327,10 +359,13 @@ void AddressBook::addAddressLabel(QString label, QString address) {
} }
// Remove a new address/label from the database // Remove a new address/label from the database
void AddressBook::removeAddressLabel(QString label, QString address) { void AddressBook::removeAddressLabel(QString label, QString address)
{
// Iterate over the list and remove the label/address // Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) { for (int i = 0; i < allLabels.size(); i++)
if (allLabels[i].first == label && allLabels[i].second == address) { {
if (allLabels[i].first == label && allLabels[i].second == address)
{
allLabels.removeAt(i); allLabels.removeAt(i);
writeToStorage(); writeToStorage();
return; return;
@ -338,10 +373,13 @@ void AddressBook::removeAddressLabel(QString label, QString address) {
} }
} }
void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabel) { void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabel)
{
// Iterate over the list and update the label/address // Iterate over the list and update the label/address
for (int i = 0; i < allLabels.size(); i++) { for (int i = 0; i < allLabels.size(); i++)
if (allLabels[i].first == oldlabel && allLabels[i].second == address) { {
if (allLabels[i].first == oldlabel && allLabels[i].second == address)
{
allLabels[i].first = newlabel; allLabels[i].first = newlabel;
writeToStorage(); writeToStorage();
return; return;
@ -350,16 +388,20 @@ void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabe
} }
// Read all addresses // Read all addresses
const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels() { const QList<QPair<QString, QString>> &AddressBook::getAllAddressLabels()
if (allLabels.isEmpty()) { {
if (allLabels.isEmpty())
{
readFromStorage(); readFromStorage();
} }
return allLabels; return allLabels;
} }
// Get the label for an address // Get the label for an address
QString AddressBook::getLabelForAddress(QString addr) { QString AddressBook::getLabelForAddress(QString addr)
for (auto i : allLabels) { {
for (auto i : allLabels)
{
if (i.second == addr) if (i.second == addr)
return i.first; return i.first;
} }
@ -368,8 +410,10 @@ QString AddressBook::getLabelForAddress(QString addr) {
} }
// Get the address for a label // Get the address for a label
QString AddressBook::getAddressForLabel(QString label) { QString AddressBook::getAddressForLabel(QString label)
for (auto i: allLabels) { {
for (auto i : allLabels)
{
if (i.first == label) if (i.first == label)
return i.second; return i.second;
} }
@ -377,7 +421,8 @@ QString AddressBook::getAddressForLabel(QString label) {
return ""; return "";
} }
QString AddressBook::addLabelToAddress(QString addr) { QString AddressBook::addLabelToAddress(QString addr)
{
QString label = AddressBook::getInstance()->getLabelForAddress(addr); QString label = AddressBook::getInstance()->getLabelForAddress(addr);
if (!label.isEmpty()) if (!label.isEmpty())
return label + "/" + addr; return label + "/" + addr;
@ -385,8 +430,9 @@ QString AddressBook::addLabelToAddress(QString addr) {
return addr; return addr;
} }
QString AddressBook::addressFromAddressLabel(const QString& lblAddr) { QString AddressBook::addressFromAddressLabel(const QString &lblAddr)
return lblAddr.trimmed().split("/").last(); {
return lblAddr.trimmed().split("/").last();
} }
AddressBook* AddressBook::instance = nullptr; AddressBook *AddressBook::instance = nullptr;

610
src/connection.cpp

File diff suppressed because it is too large

190
src/main.cpp

@ -7,9 +7,23 @@
#include "settings.h" #include "settings.h"
#include "version.h" #include "version.h"
bool isdragonx = 0; bool isHSC = 1;
std::string HSC_name = "tumin";
class SignalHandler std::string HSC_ticker = "tumin";
std::string HSC_default_theme = "dragonx";
std::string HSC_app_name = "silentdragontumin";
std::string HSC_TG_link = "dragonx.is/tg";
std::string HSC_website = "dragonx.is";
std::string HSC_explorer = "explorer.dragonx.is";
std::string App_title = "SilentDragon - Tumin";
std::string HSC_ac_name = "TUMIN";
// std::string HSC_port = "21769";
std::string HSC_port = "40855";
// std::string HSC_param = " -ac_name=" + HSC_ac_name + " -ac_algo=randomx -ac_halving=3500000 -ac_reward=300000000 -ac_blocktime=36 -ac_private=1 -addnode=176.126.87.241";
std::string HSC_param = " -ac_name=TUMIN -ac_algo=memhash -ac_halving=0 -ac_reward=1000000 -ac_supply=7000000 -ac_blocktime=200 -ac_private=1";
class SignalHandler
{ {
public: public:
SignalHandler(int mask = DEFAULT_SIGNALS); SignalHandler(int mask = DEFAULT_SIGNALS);
@ -17,12 +31,12 @@ public:
enum SIGNALS enum SIGNALS
{ {
SIG_UNHANDLED = 0, // Physical signal not supported by this class SIG_UNHANDLED = 0, // Physical signal not supported by this class
SIG_NOOP = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway) SIG_NOOP = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway)
SIG_INT = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit) SIG_INT = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit)
SIG_TERM = 4, // Control+Break (should terminate now without regarding the consquences) SIG_TERM = 4, // Control+Break (should terminate now without regarding the consquences)
SIG_CLOSE = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM] SIG_CLOSE = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM]
SIG_RELOAD = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP] SIG_RELOAD = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP]
DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE, DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
}; };
static const int numSignals = 6; static const int numSignals = 6;
@ -44,7 +58,7 @@ private:
#endif //!_WIN32 #endif //!_WIN32
// There can be only ONE SignalHandler per process // There can be only ONE SignalHandler per process
SignalHandler* g_handler(NULL); SignalHandler *g_handler(NULL);
#ifndef _WIN32 #ifndef _WIN32
@ -59,7 +73,7 @@ SignalHandler::SignalHandler(int mask) : _mask(mask)
assert(g_handler == NULL); assert(g_handler == NULL);
g_handler = this; g_handler = this;
for (int i=0;i<numSignals;i++) for (int i = 0; i < numSignals; i++)
{ {
int logical = 0x1 << i; int logical = 0x1 << i;
if (_mask & logical) if (_mask & logical)
@ -73,13 +87,12 @@ SignalHandler::SignalHandler(int mask) : _mask(mask)
#endif //_WIN32 #endif //_WIN32
} }
} }
} }
SignalHandler::~SignalHandler() SignalHandler::~SignalHandler()
{ {
#ifndef _WIN32 #ifndef _WIN32
for (int i=0;i<numSignals;i++) for (int i = 0; i < numSignals; i++)
{ {
int logical = 0x1 << i; int logical = 0x1 << i;
if (_mask & logical) if (_mask & logical)
@ -90,33 +103,38 @@ SignalHandler::~SignalHandler()
#endif //_WIN32 #endif //_WIN32
} }
#ifndef _WIN32 #ifndef _WIN32
int POSIX_logicalToPhysical(int signal) int POSIX_logicalToPhysical(int signal)
{ {
switch (signal) switch (signal)
{ {
case SignalHandler::SIG_INT: return SIGINT; case SignalHandler::SIG_INT:
case SignalHandler::SIG_TERM: return SIGTERM; return SIGINT;
case SignalHandler::SIG_TERM:
return SIGTERM;
// In case the client asks for a SIG_CLOSE handler, accept and // In case the client asks for a SIG_CLOSE handler, accept and
// bind it to a SIGTERM. Anyway the signal will never be raised // bind it to a SIGTERM. Anyway the signal will never be raised
case SignalHandler::SIG_CLOSE: return SIGTERM; case SignalHandler::SIG_CLOSE:
case SignalHandler::SIG_RELOAD: return SIGHUP; return SIGTERM;
default: case SignalHandler::SIG_RELOAD:
return SIGHUP;
default:
return -1; // SIG_ERR = -1 return -1; // SIG_ERR = -1
} }
} }
#endif //_WIN32 #endif //_WIN32
#ifndef _WIN32 #ifndef _WIN32
int POSIX_physicalToLogical(int signal) int POSIX_physicalToLogical(int signal)
{ {
switch (signal) switch (signal)
{ {
case SIGINT: return SignalHandler::SIG_INT; case SIGINT:
case SIGTERM: return SignalHandler::SIG_TERM; return SignalHandler::SIG_INT;
case SIGHUP: return SignalHandler::SIG_RELOAD; case SIGTERM:
return SignalHandler::SIG_TERM;
case SIGHUP:
return SignalHandler::SIG_RELOAD;
default: default:
return SignalHandler::SIG_UNHANDLED; return SignalHandler::SIG_UNHANDLED;
} }
@ -141,16 +159,20 @@ public:
~Application() {} ~Application() {}
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
fprintf(stderr,"%s: argv0 = %s\n", __func__, argv[0]); {
fprintf(stderr, "%s: argv0 = %s\n", __func__, argv[0]);
QString binaryName(argv[0]); QString binaryName(argv[0]);
binaryName = binaryName.toLower(); binaryName = binaryName.toLower();
QStringList pathParts = binaryName.split(QLatin1Char('/')); QStringList pathParts = binaryName.split(QLatin1Char('/'));
qDebug() << pathParts; qDebug() << pathParts;
isdragonx = binaryName.endsWith("dragonx") || binaryName.endsWith("dragonx.exe") || binaryName.endsWith("dragonx.app"); std::string appname_exe = HSC_app_name + ".exe";
qDebug() << "isdragonx=" << isdragonx; std::string appname_app = HSC_app_name + ".app";
isHSC = binaryName.endsWith(HSC_app_name.c_str()) || binaryName.endsWith((appname_exe.c_str())) || binaryName.endsWith((appname_app.c_str()));
qDebug() << "isHSC=" << isHSC;
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
@ -176,25 +198,30 @@ public:
parser.process(a); parser.process(a);
// Check for a positional argument indicating a Hush payment URI // Check for a positional argument indicating a Hush payment URI
if (a.isSecondary()) { if (a.isSecondary())
if (parser.positionalArguments().length() > 0) { {
a.sendMessage(parser.positionalArguments()[0].toUtf8()); if (parser.positionalArguments().length() > 0)
{
a.sendMessage(parser.positionalArguments()[0].toUtf8());
} }
a.exit( 0 ); a.exit(0);
return 0; return 0;
} }
QCoreApplication::setOrganizationName("Hush"); QCoreApplication::setOrganizationName("Hush");
QCoreApplication::setApplicationName(isdragonx ? "SilentDragonX" : "SilentDragon"); QCoreApplication::setApplicationName(isHSC ? App_title.c_str() : "SilentDragon");
QString locale = QLocale::system().name(); QString locale = QLocale::system().name();
locale.truncate(locale.lastIndexOf('_')); // Get the language code locale.truncate(locale.lastIndexOf('_')); // Get the language code
qDebug() << "Loading locale " << locale; qDebug() << "Loading locale " << locale;
QTranslator translator; QTranslator translator;
if(isdragonx) { if (isHSC)
{
translator.load(QString(":/translations/silentdragon_") + locale); translator.load(QString(":/translations/silentdragon_") + locale);
} else { }
else
{
translator.load(QString(":/translations/silentdragon_") + locale); translator.load(QString(":/translations/silentdragon_") + locale);
} }
a.installTranslator(&translator); a.installTranslator(&translator);
@ -202,65 +229,76 @@ public:
QIcon icon(":/icons/icon.ico"); QIcon icon(":/icons/icon.ico");
QApplication::setWindowIcon(icon); QApplication::setWindowIcon(icon);
// TODO: update for SD // TODO: update for SD
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf"); QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf");
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false)); qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif #endif
// QRandomGenerator generates a secure random number, which we use to seed. // QRandomGenerator generates a secure random number, which we use to seed.
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
unsigned int seed = QRandomGenerator::securelySeeded().generate(); unsigned int seed = QRandomGenerator::securelySeeded().generate();
#else #else
// This will be used only during debugging for compatibility reasons // This will be used only during debugging for compatibility reasons
unsigned int seed = std::time(0); unsigned int seed = std::time(0);
#endif #endif
std::srand(seed); std::srand(seed);
Settings::init(); Settings::init();
// Set up libsodium // Set up libsodium
if (sodium_init() < 0) { if (sodium_init() < 0)
{
/* panic! the library couldn't be initialized, it is not safe to use */ /* panic! the library couldn't be initialized, it is not safe to use */
qDebug() << "libsodium is not initialized!"; qDebug() << "libsodium is not initialized!";
exit(0); exit(0);
} }
// Check for embedded option // Check for embedded option
if (parser.isSet(noembeddedOption)) { if (parser.isSet(noembeddedOption))
{
Settings::getInstance()->setUseEmbedded(false); Settings::getInstance()->setUseEmbedded(false);
} else { }
else
{
Settings::getInstance()->setUseEmbedded(true); Settings::getInstance()->setUseEmbedded(true);
} }
w = new MainWindow(); w = new MainWindow();
if(isdragonx) { if (isHSC)
w->setWindowTitle("SilentDragonX v" + QString(APP_VERSION)); {
} else { w->setWindowTitle((QString::fromStdString(App_title) + " v" + QString(APP_VERSION)));
}
else
{
w->setWindowTitle("SilentDragon v" + QString(APP_VERSION)); w->setWindowTitle("SilentDragon v" + QString(APP_VERSION));
} }
// If there was a payment URI on the command line, pay it // If there was a payment URI on the command line, pay it
if (parser.positionalArguments().length() > 0) { if (parser.positionalArguments().length() > 0)
{
w->payHushURI(parser.positionalArguments()[0]); w->payHushURI(parser.positionalArguments()[0]);
} }
// Listen for any secondary instances telling us about a Hush payment URI // Listen for any secondary instances telling us about a Hush payment URI
QObject::connect(&a, &SingleApplication::receivedMessage, [=] (quint32, QByteArray msg) { QObject::connect(&a, &SingleApplication::receivedMessage, [=](quint32, QByteArray msg)
{
QString uri(msg); QString uri(msg);
// We need to execute this async, otherwise the app seems to crash for some reason. // We need to execute this async, otherwise the app seems to crash for some reason.
QTimer::singleShot(1, [=]() { w->payHushURI(uri); }); QTimer::singleShot(1, [=]() { w->payHushURI(uri); }); });
});
// For MacOS, we have an event filter // For MacOS, we have an event filter
a.installEventFilter(w); a.installEventFilter(w);
// Check if starting headless // Check if starting headless
if (parser.isSet(headlessOption)) { if (parser.isSet(headlessOption))
{
Settings::getInstance()->setHeadless(true); Settings::getInstance()->setHeadless(true);
a.setQuitOnLastWindowClosed(false); a.setQuitOnLastWindowClosed(false);
} else { }
else
{
Settings::getInstance()->setHeadless(false); Settings::getInstance()->setHeadless(false);
w->show(); w->show();
} }
@ -271,42 +309,44 @@ public:
void DispatchToMainThread(std::function<void()> callback) void DispatchToMainThread(std::function<void()> callback)
{ {
// any thread // any thread
QTimer* timer = new QTimer(); QTimer *timer = new QTimer();
timer->moveToThread(qApp->thread()); timer->moveToThread(qApp->thread());
timer->setSingleShot(true); timer->setSingleShot(true);
QObject::connect(timer, &QTimer::timeout, [=]() QObject::connect(timer, &QTimer::timeout, [=]()
{ {
// main thread // main thread
callback(); callback();
timer->deleteLater(); timer->deleteLater(); });
});
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
} }
bool handleSignal(int signal) bool handleSignal(int signal)
{ {
std::cout << std::endl << "Interrupted with signal " << signal << std::endl; std::cout << std::endl
<< "Interrupted with signal " << signal << std::endl;
if (w && w->getRPC()) {
if (w && w->getRPC())
{
// Blocking call to closeEvent on the UI thread. // Blocking call to closeEvent on the UI thread.
DispatchToMainThread([=] { DispatchToMainThread([=]
{
w->doClose(); w->doClose();
QApplication::quit(); QApplication::quit(); });
}); }
} else { else
{
QApplication::quit(); QApplication::quit();
} }
return true; return true;
} }
private: private:
MainWindow* w; MainWindow *w;
}; };
int main(int argc, char* argv[]) int main(int argc, char *argv[])
{ {
Application app; Application app;
return app.main(argc, argv); return app.main(argc, argv);
} }

896
src/mainwindow.cpp

File diff suppressed because it is too large

76
src/requestdialog.cpp

@ -8,11 +8,13 @@
#include "rpc.h" #include "rpc.h"
#include "settings.h" #include "settings.h"
#include "precompiled.h" #include "precompiled.h"
extern bool isdragonx;
RequestDialog::RequestDialog(QWidget *parent) : extern bool isHSC;
QDialog(parent), extern std::string HSC_ac_name;
ui(new Ui::RequestDialog) extern std::string HSC_ticker;
RequestDialog::RequestDialog(QWidget *parent) : QDialog(parent),
ui(new Ui::RequestDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
} }
@ -22,7 +24,8 @@ RequestDialog::~RequestDialog()
delete ui; delete ui;
} }
void RequestDialog::setupDialog(MainWindow* main, QDialog* d, Ui_RequestDialog* req) { void RequestDialog::setupDialog(MainWindow *main, QDialog *d, Ui_RequestDialog *req)
{
req->setupUi(d); req->setupUi(d);
Settings::saveRestore(d); Settings::saveRestore(d);
@ -33,9 +36,11 @@ void RequestDialog::setupDialog(MainWindow* main, QDialog* d, Ui_RequestDialog*
if (!main || !main->getRPC() || !main->getRPC()->getAllZAddresses() || !main->getRPC()->getAllBalances()) if (!main || !main->getRPC() || !main->getRPC()->getAllZAddresses() || !main->getRPC()->getAllBalances())
return; return;
for (auto addr : *main->getRPC()->getAllZAddresses()) { for (auto addr : *main->getRPC()->getAllZAddresses())
{
auto bal = main->getRPC()->getAllBalances()->value(addr); auto bal = main->getRPC()->getAllBalances()->value(addr);
if (Settings::getInstance()->isSaplingAddress(addr)) { if (Settings::getInstance()->isSaplingAddress(addr))
{
req->cmbMyAddress->addItem(addr, bal); req->cmbMyAddress->addItem(addr, bal);
} }
} }
@ -46,22 +51,28 @@ void RequestDialog::setupDialog(MainWindow* main, QDialog* d, Ui_RequestDialog*
} }
// Static method that shows an incoming payment request and prompts the user to pay it // Static method that shows an incoming payment request and prompts the user to pay it
void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI) { void RequestDialog::showPaymentConfirmation(MainWindow *main, QString paymentURI)
{
PaymentURI payInfo = Settings::parseURI(paymentURI); PaymentURI payInfo = Settings::parseURI(paymentURI);
if (!payInfo.error.isEmpty()) { if (!payInfo.error.isEmpty())
if(isdragonx) { {
QMessageBox::critical(main, tr("Error paying DRAGONX URI"), if (isHSC)
tr("URI should be of the form 'drgx:<addr>?amt=x&memo=y") + "\n" + payInfo.error); {
} else { std::string error = "Error paying " + HSC_ac_name + " URI";
QMessageBox::critical(main, tr("Error paying HUSH URI"), std::string error2 = "URI should be of the form '" + HSC_ticker + ":<addr>?amt=x&memo=y";
tr("URI should be of the form 'hush:<addr>?amt=x&memo=y") + "\n" + payInfo.error); QMessageBox::critical(main, tr(error.c_str()), tr(error2.c_str()) + "\n" + payInfo.error);
}
else
{
QMessageBox::critical(main, tr("Error paying HUSH URI"),
tr("URI should be of the form 'hush:<addr>?amt=x&memo=y") + "\n" + payInfo.error);
} }
return; return;
} }
QDialog d(main); QDialog d(main);
Ui_RequestDialog req; Ui_RequestDialog req;
setupDialog(main, &d, &req); setupDialog(main, &d, &req);
// In the view mode, all fields are read-only // In the view mode, all fields are read-only
req.txtAmount->setReadOnly(true); req.txtAmount->setReadOnly(true);
@ -86,13 +97,15 @@ void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI
req.lblHeader->setText(tr("You are paying a payment request. Your address will not be visible to the person requesting this payment.")); req.lblHeader->setText(tr("You are paying a payment request. Your address will not be visible to the person requesting this payment."));
if (d.exec() == QDialog::Accepted) { if (d.exec() == QDialog::Accepted)
{
main->payHushURI(paymentURI, req.cmbMyAddress->currentText()); main->payHushURI(paymentURI, req.cmbMyAddress->currentText());
} }
} }
// Static method that shows the request dialog // Static method that shows the request dialog
void RequestDialog::showRequestZcash(MainWindow* main) { void RequestDialog::showRequestZcash(MainWindow *main)
{
QDialog d(main); QDialog d(main);
Ui_RequestDialog req; Ui_RequestDialog req;
@ -100,7 +113,8 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
// Setup the Label completer for the Address // Setup the Label completer for the Address
req.txtFrom->setCompleter(main->getLabelCompleter()); req.txtFrom->setCompleter(main->getLabelCompleter());
QObject::connect(req.txtFrom, &QLineEdit::textChanged, [=] (auto text) { QObject::connect(req.txtFrom, &QLineEdit::textChanged, [=](auto text)
{
auto addr = AddressBook::addressFromAddressLabel(text); auto addr = AddressBook::addressFromAddressLabel(text);
if (!Settings::getInstance()->isSaplingAddress(addr)) { if (!Settings::getInstance()->isSaplingAddress(addr)) {
req.lblSaplingWarning->setText(tr("Can only request from Sapling addresses")); req.lblSaplingWarning->setText(tr("Can only request from Sapling addresses"));
@ -108,19 +122,16 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
} else { } else {
req.lblSaplingWarning->setText(""); req.lblSaplingWarning->setText("");
req.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); req.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
} } });
});
// Wire up AddressBook button // Wire up AddressBook button
QObject::connect(req.btnAddressBook, &QPushButton::clicked, [=] () { QObject::connect(req.btnAddressBook, &QPushButton::clicked, [=]()
AddressBook::open(main, req.txtFrom); { AddressBook::open(main, req.txtFrom); });
});
// Amount textbox // Amount textbox
req.txtAmount->setValidator(main->getAmountValidator()); req.txtAmount->setValidator(main->getAmountValidator());
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) { QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=](auto text)
req.txtAmountUSD->setText(Settings::getUSDFormat(text.toDouble())); { req.txtAmountUSD->setText(Settings::getUSDFormat(text.toDouble())); });
});
req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble())); req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble()));
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok)); req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
@ -129,15 +140,12 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
req.txtFrom->setFocus(); req.txtFrom->setFocus();
if (d.exec() == QDialog::Accepted) { if (d.exec() == QDialog::Accepted)
{
// Construct a Hush Payment URI with the data and pay it immediately. // Construct a Hush Payment URI with the data and pay it immediately.
QString memoURI = (isdragonx ? "drgx:" : "hush:" ) + req.cmbMyAddress->currentText() QString memoURI = (isHSC ? (QString::fromStdString(HSC_ticker) + ":") : "hush:") + req.cmbMyAddress->currentText() + "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble()) + "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
QString sendURI = (isdragonx ? "drgx:" : "hush:" ) + AddressBook::addressFromAddressLabel(req.txtFrom->text()) QString sendURI = (isHSC ? QString::fromStdString((HSC_ticker) + ":") : "hush:") + AddressBook::addressFromAddressLabel(req.txtFrom->text()) + "?amt=0.0001" + "&memo=" + QUrl::toPercentEncoding(memoURI);
+ "?amt=0.0001"
+ "&memo=" + QUrl::toPercentEncoding(memoURI);
// If the disclosed address in the memo doesn't have a balance, it will automatically fallback to the default // If the disclosed address in the memo doesn't have a balance, it will automatically fallback to the default
// sapling address // sapling address

1250
src/rpc.cpp

File diff suppressed because it is too large

99
src/senttxstore.cpp

@ -3,54 +3,65 @@
#include "senttxstore.h" #include "senttxstore.h"
#include "settings.h" #include "settings.h"
extern bool isdragonx; extern bool isHSC;
extern std::string HSC_ticker;
/// Get the location of the app data file to be written. /// Get the location of the app data file to be written.
QString SentTxStore::writeableFile() { QString SentTxStore::writeableFile()
{
auto filename = QStringLiteral("senttxstore.dat"); auto filename = QStringLiteral("senttxstore.dat");
if (isdragonx) { if (isHSC)
filename = QStringLiteral("senttxstore-drgx.dat"); {
std::string ticker = ("senttxstore-" + HSC_ticker + ".dat");
filename = QString::fromStdString(ticker);
} }
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (!dir.exists()) if (!dir.exists())
QDir().mkpath(dir.absolutePath()); QDir().mkpath(dir.absolutePath());
if (Settings::getInstance()->isTestnet()) { if (Settings::getInstance()->isTestnet())
{
return dir.filePath("testnet-" % filename); return dir.filePath("testnet-" % filename);
} else { }
else
{
qDebug() << "senttxstore file = " + dir.filePath(filename); qDebug() << "senttxstore file = " + dir.filePath(filename);
return dir.filePath(filename); return dir.filePath(filename);
} }
} }
// delete the sent history. // delete the sent history.
void SentTxStore::deleteHistory() { void SentTxStore::deleteHistory()
{
QFile data(writeableFile()); QFile data(writeableFile());
data.remove(); data.remove();
data.close(); data.close();
} }
QList<TransactionItem> SentTxStore::readSentTxFile() { QList<TransactionItem> SentTxStore::readSentTxFile()
{
QFile data(writeableFile()); QFile data(writeableFile());
if (!data.exists()) { if (!data.exists())
{
return QList<TransactionItem>(); return QList<TransactionItem>();
} }
QJsonDocument jsonDoc; QJsonDocument jsonDoc;
data.open(QFile::ReadOnly); data.open(QFile::ReadOnly);
jsonDoc = QJsonDocument::fromJson(data.readAll()); jsonDoc = QJsonDocument::fromJson(data.readAll());
data.close(); data.close();
QList<TransactionItem> items; QList<TransactionItem> items;
for (auto i : jsonDoc.array()) { for (auto i : jsonDoc.array())
{
auto sentTx = i.toObject(); auto sentTx = i.toObject();
TransactionItem t{"send", (qint64)sentTx["datetime"].toVariant().toLongLong(), TransactionItem t{"send", (qint64)sentTx["datetime"].toVariant().toLongLong(),
sentTx["address"].toString(), sentTx["address"].toString(),
sentTx["txid"].toString(), sentTx["txid"].toString(),
sentTx["amount"].toDouble() + sentTx["fee"].toDouble(), sentTx["amount"].toDouble() + sentTx["fee"].toDouble(),
0, sentTx["from"].toString(), sentTx["memo"].toString()}; 0, sentTx["from"].toString(), sentTx["memo"].toString()};
items.push_back(t); items.push_back(t);
} }
@ -58,21 +69,23 @@ QList<TransactionItem> SentTxStore::readSentTxFile() {
return items; return items;
} }
void SentTxStore::addToSentTx(Tx tx, QString txid) { void SentTxStore::addToSentTx(Tx tx, QString txid)
{
// Save transactions only if the settings are allowed // Save transactions only if the settings are allowed
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 hushd // Also, only store outgoing txs where the from address is a z-Addr. Else, regular hushd
// stores it just fine // stores it just fine
if (!tx.fromAddr.startsWith("z")) if (!tx.fromAddr.startsWith("z"))
return; return;
QFile data(writeableFile()); QFile data(writeableFile());
QJsonDocument jsonDoc; QJsonDocument jsonDoc;
// If data doesn't exist, then create a blank one // If data doesn't exist, then create a blank one
if (!data.exists()) { if (!data.exists())
{
QJsonArray a; QJsonArray a;
jsonDoc.setArray(a); jsonDoc.setArray(a);
@ -80,46 +93,54 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) {
newFile.open(QFile::WriteOnly); newFile.open(QFile::WriteOnly);
newFile.write(jsonDoc.toJson()); newFile.write(jsonDoc.toJson());
newFile.close(); newFile.close();
} else { }
data.open(QFile::ReadOnly); else
{
data.open(QFile::ReadOnly);
jsonDoc = QJsonDocument().fromJson(data.readAll()); jsonDoc = QJsonDocument().fromJson(data.readAll());
data.close(); data.close();
} }
// Calculate total amount in this tx // Calculate total amount in this tx
double totalAmount = 0; double totalAmount = 0;
for (auto i : tx.toAddrs) { for (auto i : tx.toAddrs)
{
totalAmount += i.amount; totalAmount += i.amount;
} }
QString toAddresses; QString toAddresses;
if (tx.toAddrs.length() == 1) { if (tx.toAddrs.length() == 1)
{
toAddresses = tx.toAddrs[0].addr; toAddresses = tx.toAddrs[0].addr;
} else { }
else
{
// Concatenate all the toAddresses // Concatenate all the toAddresses
for (auto a : tx.toAddrs) { for (auto a : tx.toAddrs)
{
toAddresses += a.addr % "(" % Settings::getDisplayFormat(a.amount) % ") "; toAddresses += a.addr % "(" % Settings::getDisplayFormat(a.amount) % ") ";
} }
} }
auto list = jsonDoc.array(); auto list = jsonDoc.array();
QJsonObject txItem; QJsonObject txItem;
txItem["type"] = "sent"; txItem["type"] = "sent";
txItem["from"] = tx.fromAddr; txItem["from"] = tx.fromAddr;
txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000; txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000;
txItem["address"] = toAddresses; txItem["address"] = toAddresses;
txItem["txid"] = txid; txItem["txid"] = txid;
txItem["amount"] = -totalAmount; txItem["amount"] = -totalAmount;
txItem["fee"] = -tx.fee; txItem["fee"] = -tx.fee;
// TODO: store all outgoing memos // TODO: store all outgoing memos
txItem["memo"] = tx.toAddrs[0].txtMemo; txItem["memo"] = tx.toAddrs[0].txtMemo;
list.append(txItem); list.append(txItem);
jsonDoc.setArray(list); jsonDoc.setArray(list);
QFile writer(writeableFile()); QFile writer(writeableFile());
if (writer.open(QFile::WriteOnly | QFile::Truncate)) { if (writer.open(QFile::WriteOnly | QFile::Truncate))
{
writer.write(jsonDoc.toJson()); writer.write(jsonDoc.toJson());
} }
writer.close(); writer.close();
} }

396
src/settings.cpp

@ -4,92 +4,107 @@
#include "settings.h" #include "settings.h"
#include "sd.h" #include "sd.h"
extern bool isdragonx; extern bool isHSC;
extern std::string HSC_explorer;
extern std::string HSC_ticker;
Settings* Settings::instance = nullptr; Settings *Settings::instance = nullptr;
Settings* Settings::init() { Settings *Settings::init()
{
if (instance == nullptr) if (instance == nullptr)
instance = new Settings(); instance = new Settings();
return instance; return instance;
} }
Settings* Settings::getInstance() { Settings *Settings::getInstance()
{
return instance; return instance;
} }
bool Settings::getCheckForUpdates() { bool Settings::getCheckForUpdates()
{
return QSettings().value("options/allowcheckupdates", true).toBool(); return QSettings().value("options/allowcheckupdates", true).toBool();
} }
void Settings::setCheckForUpdates(bool allow) { void Settings::setCheckForUpdates(bool allow)
QSettings().setValue("options/allowcheckupdates", allow); {
QSettings().setValue("options/allowcheckupdates", allow);
} }
bool Settings::getAllowFetchPrices() { bool Settings::getAllowFetchPrices()
{
// now defaults to OFF, used to be ON // now defaults to OFF, used to be ON
return QSettings().value("options/allowfetchprices", false).toBool(); return QSettings().value("options/allowfetchprices", false).toBool();
} }
void Settings::setAllowFetchPrices(bool allow) { void Settings::setAllowFetchPrices(bool allow)
QSettings().setValue("options/allowfetchprices", allow); {
QSettings().setValue("options/allowfetchprices", allow);
} }
Explorer Settings::getExplorer() { Explorer Settings::getExplorer()
{
// Load from the QT Settings. // Load from the QT Settings.
QSettings s; QSettings s;
//TODO: make it easy for people to use other explorers // TODO: make it easy for people to use other explorers
QString explorer = "https://explorer.hush.is"; QString explorer = "https://explorer.hush.is";
if(isdragonx) { if (isHSC)
explorer = "https://explorer.dragonx.is"; {
explorer = QString::fromStdString(HSC_explorer);
} }
QString onionExplorer = "http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion"; QString onionExplorer = "http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion";
auto txExplorerUrl = s.value("explorer/txExplorerUrl", explorer + "/tx/").toString(); auto txExplorerUrl = s.value("explorer/txExplorerUrl", explorer + "/tx/").toString();
auto addressExplorerUrl = s.value("explorer/addressExplorerUrl", explorer + "/address/").toString(); auto addressExplorerUrl = s.value("explorer/addressExplorerUrl", explorer + "/address/").toString();
auto onionTxExplorerUrl = s.value("explorer/onionTxExplorerUrl", onionExplorer + "/tx/").toString(); auto onionTxExplorerUrl = s.value("explorer/onionTxExplorerUrl", onionExplorer + "/tx/").toString();
auto onionAddressExplorerUrl = s.value("explorer/onionAddressExplorerUrl", onionExplorer + "/address/").toString(); auto onionAddressExplorerUrl = s.value("explorer/onionAddressExplorerUrl", onionExplorer + "/address/").toString();
// Some users have the old malicious explorer URL saved in their config file, help them out // Some users have the old malicious explorer URL saved in their config file, help them out
if (txExplorerUrl == "https://explorer.myhush.org/tx/") { if (txExplorerUrl == "https://explorer.myhush.org/tx/")
{
txExplorerUrl = explorer + "/tx/"; txExplorerUrl = explorer + "/tx/";
saveExplorer(txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl); saveExplorer(txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl);
} }
if (addressExplorerUrl == "https://explorer.myhush.org/address/") { if (addressExplorerUrl == "https://explorer.myhush.org/address/")
{
addressExplorerUrl = explorer + "/address/"; addressExplorerUrl = explorer + "/address/";
saveExplorer(txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl); saveExplorer(txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl);
} }
//DEBUG("explorer values: " << txExplorerUrl << " " << addressExplorerUrl << " " << onionTxExplorerUrl << " " << onionAddressExplorerUrl ); // DEBUG("explorer values: " << txExplorerUrl << " " << addressExplorerUrl << " " << onionTxExplorerUrl << " " << onionAddressExplorerUrl );
DEBUG("onionTxExplorerUrl=" % onionTxExplorerUrl); DEBUG("onionTxExplorerUrl=" % onionTxExplorerUrl);
DEBUG("onionAddressExplorerUrl=" % onionAddressExplorerUrl); DEBUG("onionAddressExplorerUrl=" % onionAddressExplorerUrl);
return Explorer{txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl}; return Explorer{txExplorerUrl, addressExplorerUrl, onionTxExplorerUrl, onionAddressExplorerUrl};
} }
void Settings::saveExplorer(const QString& txExplorerUrl, const QString& addressExplorerUrl, const QString& onionTxExplorerUrl, const QString& onionAddressExplorerUrl) { void Settings::saveExplorer(const QString &txExplorerUrl, const QString &addressExplorerUrl, const QString &onionTxExplorerUrl, const QString &onionAddressExplorerUrl)
{
QSettings s; QSettings s;
s.setValue("explorer/txExplorerUrl", txExplorerUrl); s.setValue("explorer/txExplorerUrl", txExplorerUrl);
s.setValue("explorer/addressExplorerUrl", addressExplorerUrl); s.setValue("explorer/addressExplorerUrl", addressExplorerUrl);
s.setValue("explorer/onionTxExplorerUrl", onionTxExplorerUrl); s.setValue("explorer/onionTxExplorerUrl", onionTxExplorerUrl);
s.setValue("explorer/onionAddressExplorerUrl", onionAddressExplorerUrl); s.setValue("explorer/onionAddressExplorerUrl", onionAddressExplorerUrl);
//DEBUG("saving explorer values: " << txExplorerUrl << " " << addressExplorerUrl << " " << onionTxExplorerUrl << " " << onionAddressExplorerUrl ); // DEBUG("saving explorer values: " << txExplorerUrl << " " << addressExplorerUrl << " " << onionTxExplorerUrl << " " << onionAddressExplorerUrl );
} }
Config Settings::getSettings() { Config Settings::getSettings()
{
// Load from the QT Settings. // Load from the QT Settings.
QSettings s; QSettings s;
auto host = s.value("connection/host").toString(); auto host = s.value("connection/host").toString();
auto port = s.value("connection/port").toString(); auto port = s.value("connection/port").toString();
auto username = s.value("connection/rpcuser").toString(); auto username = s.value("connection/rpcuser").toString();
auto password = s.value("connection/rpcpassword").toString(); auto password = s.value("connection/rpcpassword").toString();
return Config{host, port, username, password}; return Config{host, port, username, password};
} }
void Settings::saveSettings(const QString& host, const QString& port, const QString& username, const QString& password) { void Settings::saveSettings(const QString &host, const QString &port, const QString &username, const QString &password)
{
QSettings s; QSettings s;
s.setValue("connection/host", host); s.setValue("connection/host", host);
@ -103,218 +118,262 @@ void Settings::saveSettings(const QString& host, const QString& port, const QStr
init(); init();
} }
void Settings::saveRestoreTableHeader(QTableView* table, QDialog* d, QString tablename) { void Settings::saveRestoreTableHeader(QTableView *table, QDialog *d, QString tablename)
{
table->horizontalHeader()->restoreState(QSettings().value(tablename).toByteArray()); table->horizontalHeader()->restoreState(QSettings().value(tablename).toByteArray());
table->horizontalHeader()->setStretchLastSection(true); table->horizontalHeader()->setStretchLastSection(true);
QObject::connect(d, &QDialog::finished, [=](auto) { QObject::connect(d, &QDialog::finished, [=](auto)
QSettings().setValue(tablename, table->horizontalHeader()->saveState()); { QSettings().setValue(tablename, table->horizontalHeader()->saveState()); });
});
} }
void Settings::setUsingHushConf(QString confLocation) { void Settings::setUsingHushConf(QString confLocation)
{
if (!confLocation.isEmpty()) if (!confLocation.isEmpty())
_confLocation = confLocation; _confLocation = confLocation;
} }
bool Settings::isTestnet() { bool Settings::isTestnet()
{
return _isTestnet; return _isTestnet;
} }
void Settings::setTestnet(bool isTestnet) { void Settings::setTestnet(bool isTestnet)
{
this->_isTestnet = isTestnet; this->_isTestnet = isTestnet;
} }
bool Settings::isSaplingAddress(QString addr) { bool Settings::isSaplingAddress(QString addr)
{
if (!isValidAddress(addr)) if (!isValidAddress(addr))
return false; return false;
return ( isTestnet() && addr.startsWith("ztestsapling")) || return (isTestnet() && addr.startsWith("ztestsapling")) ||
(!isTestnet() && addr.startsWith("zs1")); (!isTestnet() && addr.startsWith("zs1"));
} }
bool Settings::isSproutAddress(QString addr) { bool Settings::isSproutAddress(QString addr)
{
if (!isValidAddress(addr)) if (!isValidAddress(addr))
return false; return false;
return isZAddress(addr) && !isSaplingAddress(addr); return isZAddress(addr) && !isSaplingAddress(addr);
} }
bool Settings::isZAddress(QString addr) { bool Settings::isZAddress(QString addr)
{
if (!isValidAddress(addr)) if (!isValidAddress(addr))
return false; return false;
return addr.startsWith("z"); return addr.startsWith("z");
} }
bool Settings::isTAddress(QString addr) { bool Settings::isTAddress(QString addr)
{
if (!isValidAddress(addr)) if (!isValidAddress(addr))
return false; return false;
return addr.startsWith("R"); return addr.startsWith("R");
} }
int Settings::getHushdVersion() { int Settings::getHushdVersion()
{
return _hushdVersion; return _hushdVersion;
} }
void Settings::setHushdVersion(int version) { void Settings::setHushdVersion(int version)
{
_hushdVersion = version; _hushdVersion = version;
} }
bool Settings::isSyncing() { bool Settings::isSyncing()
{
return _isSyncing; return _isSyncing;
} }
void Settings::setSyncing(bool syncing) { void Settings::setSyncing(bool syncing)
{
this->_isSyncing = syncing; this->_isSyncing = syncing;
} }
int Settings::getBlockNumber() { int Settings::getBlockNumber()
{
return this->_blockNumber; return this->_blockNumber;
} }
void Settings::setBlockNumber(int number) { void Settings::setBlockNumber(int number)
{
this->_blockNumber = number; this->_blockNumber = number;
} }
bool Settings::isSaplingActive() { bool Settings::isSaplingActive()
return (isTestnet() && getBlockNumber() > 0) || (!isTestnet() && getBlockNumber() > 0); {
return (isTestnet() && getBlockNumber() > 0) || (!isTestnet() && getBlockNumber() > 0);
} }
double Settings::getHUSHPrice() { double Settings::getHUSHPrice()
{
return hushPrice; return hushPrice;
} }
double Settings::get_price(QString currency) { double Settings::get_price(QString currency)
{
currency = currency.toLower(); currency = currency.toLower();
QString ticker = currency; QString ticker = currency;
auto search = prices.find(currency); auto search = prices.find(currency);
if (search != prices.end()) { if (search != prices.end())
{
qDebug() << "Found price of " << ticker << " = " << search->second; qDebug() << "Found price of " << ticker << " = " << search->second;
return search->second; return search->second;
} else { }
else
{
qDebug() << "Could not find price of" << ticker << "!!!"; qDebug() << "Could not find price of" << ticker << "!!!";
return 0.0; return 0.0;
} }
} }
void Settings::set_price(QString curr, double price) { void Settings::set_price(QString curr, double price)
{
QString ticker = curr; QString ticker = curr;
qDebug() << "Setting price of " << ticker << "=" << QString::number(price); qDebug() << "Setting price of " << ticker << "=" << QString::number(price);
prices.insert( std::make_pair(curr, price) ); prices.insert(std::make_pair(curr, price));
prices.insert( std::make_pair(curr, price) ); prices.insert(std::make_pair(curr, price));
} }
void Settings::set_volume(QString curr, double volume) { void Settings::set_volume(QString curr, double volume)
{
QString ticker = curr; QString ticker = curr;
qDebug() << "Setting volume of " << ticker << "=" << QString::number(volume); qDebug() << "Setting volume of " << ticker << "=" << QString::number(volume);
volumes.insert( std::make_pair(curr, volume) ); volumes.insert(std::make_pair(curr, volume));
} }
double Settings::get_volume(QString currency) { double Settings::get_volume(QString currency)
{
currency = currency.toLower(); currency = currency.toLower();
QString ticker = currency; QString ticker = currency;
auto search = volumes.find(currency); auto search = volumes.find(currency);
if (search != volumes.end()) { if (search != volumes.end())
{
qDebug() << "Found volume of " << ticker << " = " << search->second; qDebug() << "Found volume of " << ticker << " = " << search->second;
return search->second; return search->second;
} else { }
else
{
qDebug() << "Could not find volume of" << ticker << "!!!"; qDebug() << "Could not find volume of" << ticker << "!!!";
return 0.0; return 0.0;
} }
} }
void Settings::set_marketcap(QString curr, double marketcap) { void Settings::set_marketcap(QString curr, double marketcap)
{
QString ticker = curr; QString ticker = curr;
qDebug() << "Setting marketcap of " << ticker << "=" << QString::number(marketcap); qDebug() << "Setting marketcap of " << ticker << "=" << QString::number(marketcap);
marketcaps.insert( std::make_pair(curr, marketcap) ); marketcaps.insert(std::make_pair(curr, marketcap));
} }
double Settings::get_marketcap(QString currency) { double Settings::get_marketcap(QString currency)
{
currency = currency.toLower(); currency = currency.toLower();
QString ticker = currency; QString ticker = currency;
auto search = marketcaps.find(currency); auto search = marketcaps.find(currency);
if (search != marketcaps.end()) { if (search != marketcaps.end())
{
qDebug() << "Found marketcap of " << ticker << " = " << search->second; qDebug() << "Found marketcap of " << ticker << " = " << search->second;
return search->second; return search->second;
} else { }
else
{
qDebug() << "Could not find marketcap of" << ticker << "!!!"; qDebug() << "Could not find marketcap of" << ticker << "!!!";
return -1.0; return -1.0;
} }
} }
unsigned int Settings::getBTCPrice() { unsigned int Settings::getBTCPrice()
{
// in satoshis // in satoshis
return btcPrice; return btcPrice;
} }
bool Settings::getAutoShield() { bool Settings::getAutoShield()
{
// Load from Qt settings // Load from Qt settings
return QSettings().value("options/autoshield", true).toBool(); return QSettings().value("options/autoshield", true).toBool();
} }
void Settings::setAutoShield(bool allow) { void Settings::setAutoShield(bool allow)
{
QSettings().setValue("options/autoshield", allow); QSettings().setValue("options/autoshield", allow);
} }
bool Settings::getAllowCustomFees() { bool Settings::getAllowCustomFees()
{
// Load from the QT Settings. // Load from the QT Settings.
return QSettings().value("options/customfees", true).toBool(); return QSettings().value("options/customfees", true).toBool();
} }
void Settings::setAllowCustomFees(bool allow) { void Settings::setAllowCustomFees(bool allow)
{
QSettings().setValue("options/customfees", allow); QSettings().setValue("options/customfees", allow);
} }
QString Settings::get_theme_name() { QString Settings::get_theme_name()
{
// Load from the QT Settings. // Load from the QT Settings.
QString theme_name = QSettings().value("options/theme_name", false).toString(); QString theme_name = QSettings().value("options/theme_name", false).toString();
//qDebug() << __func__ << ": theme_name=" << theme_name; // qDebug() << __func__ << ": theme_name=" << theme_name;
return theme_name; return theme_name;
} }
void Settings::set_theme_name(QString theme_name) { void Settings::set_theme_name(QString theme_name)
{
qDebug() << __func__ << ": settings theme_name=" << theme_name; qDebug() << __func__ << ": settings theme_name=" << theme_name;
QSettings().setValue("options/theme_name", theme_name); QSettings().setValue("options/theme_name", theme_name);
} }
bool Settings::getSaveZtxs() { bool Settings::getSaveZtxs()
{
// Load from the QT Settings. // Load from the QT Settings.
return QSettings().value("options/savesenttx", true).toBool(); return QSettings().value("options/savesenttx", true).toBool();
} }
void Settings::setSaveZtxs(bool save) { void Settings::setSaveZtxs(bool save)
{
QSettings().setValue("options/savesenttx", save); QSettings().setValue("options/savesenttx", save);
} }
void Settings::setPeers(int peers) { void Settings::setPeers(int peers)
{
_peerConnections = peers; _peerConnections = peers;
} }
int Settings::getPeers() { int Settings::getPeers()
{
return _peerConnections; return _peerConnections;
} }
//================================= //=================================
// Static Stuff // Static Stuff
//================================= //=================================
void Settings::saveRestore(QDialog* d) { void Settings::saveRestore(QDialog *d)
{
d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray()); d->restoreGeometry(QSettings().value(d->objectName() % "geometry").toByteArray());
QObject::connect(d, &QDialog::finished, [=](auto) { QObject::connect(d, &QDialog::finished, [=](auto)
QSettings().setValue(d->objectName() % "geometry", d->saveGeometry()); { QSettings().setValue(d->objectName() % "geometry", d->saveGeometry()); });
});
} }
QString Settings::getUSDFormat(double bal) { QString Settings::getUSDFormat(double bal)
//TODO: respect current locale! {
return QLocale(QLocale::English).toString(bal * Settings::getInstance()->getHUSHPrice(), 'f', 8) + " " +Settings::getInstance()->get_currency_name(); // TODO: respect current locale!
return QLocale(QLocale::English).toString(bal * Settings::getInstance()->getHUSHPrice(), 'f', 8) + " " + Settings::getInstance()->get_currency_name();
} }
QString Settings::getDecimalString(double amt) { QString Settings::getDecimalString(double amt)
{
QString f = QString::number(amt, 'f', 8); QString f = QString::number(amt, 'f', 8);
while (f.contains(".") && (f.right(1) == "0" || f.right(1) == ".")) { while (f.contains(".") && (f.right(1) == "0" || f.right(1) == "."))
{
f = f.left(f.length() - 1); f = f.left(f.length() - 1);
} }
if (f == "-0") if (f == "-0")
@ -323,12 +382,14 @@ QString Settings::getDecimalString(double amt) {
return f; return f;
} }
QString Settings::getDisplayFormat(double bal) { QString Settings::getDisplayFormat(double bal)
{
// This is idiotic. Why doesn't QString have a way to do this? // This is idiotic. Why doesn't QString have a way to do this?
return getDecimalString(bal) % " " % Settings::getTokenName(); return getDecimalString(bal) % " " % Settings::getTokenName();
} }
QString Settings::getHUSHUSDDisplayFormat(double bal) { QString Settings::getHUSHUSDDisplayFormat(double bal)
{
auto usdFormat = getUSDFormat(bal); auto usdFormat = getUSDFormat(bal);
if (!usdFormat.isEmpty()) if (!usdFormat.isEmpty())
return getDisplayFormat(bal) % " (" % getUSDFormat(bal) % ")"; return getDisplayFormat(bal) % " (" % getUSDFormat(bal) % ")";
@ -338,32 +399,39 @@ QString Settings::getHUSHUSDDisplayFormat(double bal) {
const QString Settings::txidStatusMessage = QString(QObject::tr("Transaction submitted (right click to copy) txid:")); const QString Settings::txidStatusMessage = QString(QObject::tr("Transaction submitted (right click to copy) txid:"));
QString Settings::getTokenName() { QString Settings::getTokenName()
if (isdragonx) { {
return "DRGX"; if (isHSC)
{
return QString::fromStdString(HSC_ticker);
} }
if (Settings::getInstance()->isTestnet()) { if (Settings::getInstance()->isTestnet())
{
return "TUSH"; return "TUSH";
} else { }
else
{
return "HUSH"; return "HUSH";
} }
} }
//TODO: this isn't used for donations // TODO: this isn't used for donations
QString Settings::getDonationAddr() { QString Settings::getDonationAddr()
if (Settings::getInstance()->isTestnet()) { {
return "ztestsaplingXXX"; if (Settings::getInstance()->isTestnet())
{
return "ztestsaplingXXX";
} }
// This is used for user feedback // This is used for user feedback
return "zs1aq4xnrkjlnxx0zesqye7jz3dfrf3rjh7q5z6u8l6mwyqqaam3gx3j2fkqakp33v93yavq46j83q"; return "zs1aq4xnrkjlnxx0zesqye7jz3dfrf3rjh7q5z6u8l6mwyqqaam3gx3j2fkqakp33v93yavq46j83q";
} }
bool Settings::addToHushConf(QString confLocation, QString line) { bool Settings::addToHushConf(QString confLocation, QString line)
{
QFile file(confLocation); QFile file(confLocation);
if (!file.open(QIODevice::ReadWrite | QIODevice::Append)) if (!file.open(QIODevice::ReadWrite | QIODevice::Append))
return false; return false;
QTextStream out(&file); QTextStream out(&file);
out << line << "\n"; out << line << "\n";
file.close(); file.close();
@ -371,32 +439,36 @@ bool Settings::addToHushConf(QString confLocation, QString line) {
return true; return true;
} }
QString Settings::get_currency_name() { QString Settings::get_currency_name()
{
// Load from the QT Settings. // Load from the QT Settings.
return QSettings().value("options/currency_name", "BTC").toString(); return QSettings().value("options/currency_name", "BTC").toString();
} }
void Settings::set_currency_name(QString currency_name) { void Settings::set_currency_name(QString currency_name)
{
QSettings().setValue("options/currency_name", currency_name); QSettings().setValue("options/currency_name", currency_name);
} }
QString Settings::get_language() { QString Settings::get_language()
{
// use the default system language if none is set // use the default system language if none is set
QString locale = QLocale::system().name(); QString locale = QLocale::system().name();
// remove country data, i.e. en_US => en // remove country data, i.e. en_US => en
locale.truncate( locale.lastIndexOf("_")); locale.truncate(locale.lastIndexOf("_"));
auto lang = QSettings().value("options/language", locale).toString(); auto lang = QSettings().value("options/language", locale).toString();
qDebug() << __func__ << ": found lang=" << lang << " in config file"; qDebug() << __func__ << ": found lang=" << lang << " in config file";
return lang; return lang;
} }
void Settings::set_language(QString lang) { void Settings::set_language(QString lang)
{
qDebug() << __func__ << ": setting lang=" << lang << " in config file"; qDebug() << __func__ << ": setting lang=" << lang << " in config file";
QSettings().setValue("options/language", lang); QSettings().setValue("options/language", lang);
} }
bool Settings::removeFromHushConf(QString confLocation, QString option)
bool Settings::removeFromHushConf(QString confLocation, QString option) { {
if (confLocation.isEmpty()) if (confLocation.isEmpty())
return false; return false;
@ -407,11 +479,13 @@ bool Settings::removeFromHushConf(QString confLocation, QString option) {
QList<QString> lines; QList<QString> lines;
QTextStream in(&file); QTextStream in(&file);
while (!in.atEnd()) { while (!in.atEnd())
{
QString line = in.readLine(); QString line = in.readLine();
auto s = line.indexOf("="); auto s = line.indexOf("=");
QString name = line.left(s).trimmed().toLower(); QString name = line.left(s).trimmed().toLower();
if (name != option) { if (name != option)
{
lines.append(line); lines.append(line);
} }
} }
@ -422,7 +496,8 @@ bool Settings::removeFromHushConf(QString confLocation, QString option) {
return false; return false;
QTextStream out(&newfile); QTextStream out(&newfile);
for (QString line : lines) { for (QString line : lines)
{
out << line << endl; out << line << endl;
} }
newfile.close(); newfile.close();
@ -430,90 +505,115 @@ bool Settings::removeFromHushConf(QString confLocation, QString option) {
return true; return true;
} }
double Settings::getMinerFee() { double Settings::getMinerFee()
{
return 0.0001; return 0.0001;
} }
bool Settings::isValidSaplingPrivateKey(QString pk) { bool Settings::isValidSaplingPrivateKey(QString pk)
if (isTestnet()) { {
if (isTestnet())
{
QRegExp zspkey("^secret-extended-key-test[0-9a-z]{278}$", Qt::CaseInsensitive); QRegExp zspkey("^secret-extended-key-test[0-9a-z]{278}$", Qt::CaseInsensitive);
return zspkey.exactMatch(pk); return zspkey.exactMatch(pk);
} else { }
else
{
QRegExp zspkey("^secret-extended-key-main[0-9a-z]{278}$", Qt::CaseInsensitive); QRegExp zspkey("^secret-extended-key-main[0-9a-z]{278}$", Qt::CaseInsensitive);
return zspkey.exactMatch(pk); return zspkey.exactMatch(pk);
} }
} }
bool Settings::isValidAddress(QString addr) { bool Settings::isValidAddress(QString addr)
QRegExp zsexp("^zs1[a-z0-9]{75}$", Qt::CaseInsensitive); {
QRegExp zsexp("^zs1[a-z0-9]{75}$", Qt::CaseInsensitive);
QRegExp ztsexp("^ztestsapling[a-z0-9]{76}", Qt::CaseInsensitive); QRegExp ztsexp("^ztestsapling[a-z0-9]{76}", Qt::CaseInsensitive);
QRegExp texp("^R[a-z0-9]{33}$", Qt::CaseInsensitive); QRegExp texp("^R[a-z0-9]{33}$", Qt::CaseInsensitive);
//qDebug() << "isValidAddress(" << addr << ")"; // qDebug() << "isValidAddress(" << addr << ")";
return texp.exactMatch(addr) || ztsexp.exactMatch(addr) || zsexp.exactMatch(addr); return texp.exactMatch(addr) || ztsexp.exactMatch(addr) || zsexp.exactMatch(addr);
} }
// Get a pretty string representation of this Payment URI // Get a pretty string representation of this Payment URI
QString Settings::paymentURIPretty(PaymentURI uri) { QString Settings::paymentURIPretty(PaymentURI uri)
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + getDisplayFormat(uri.amt.toDouble()) {
+ "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8()); return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + getDisplayFormat(uri.amt.toDouble()) + "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8());
} }
// Parse a payment URI string into its components // Parse a payment URI string into its components
PaymentURI Settings::parseURI(QString uri) { PaymentURI Settings::parseURI(QString uri)
{
PaymentURI ans; PaymentURI ans;
auto proto=""; auto proto = "";
if (isdragonx) { if (isHSC)
proto ="drgx:"; {
if (!uri.startsWith(proto % QString(":"))) { std::string ticker = HSC_ticker + ":";
ans.error = "Not a DRGX payment URI"; proto = ((ticker.c_str()));
if (!uri.startsWith(proto % QString(":")))
{
std::string not_a_uri = "Not a " + HSC_ticker + " payment URI";
ans.error = (not_a_uri.c_str());
return ans; return ans;
} }
} else { }
else
{
proto = "hush:"; proto = "hush:";
if (!uri.startsWith(proto % QString(":"))) { if (!uri.startsWith(proto % QString(":")))
{
ans.error = "Not a HUSH payment URI"; ans.error = "Not a HUSH payment URI";
return ans; return ans;
} }
} }
uri = uri.right(uri.length() - QString("hush:").length()); uri = uri.right(uri.length() - QString("hush:").length());
if(isdragonx) { if (isHSC)
uri = uri.right(uri.length() - QString("drgx:").length()); {
uri = uri.right((uri.length() - QString(QString::fromStdString(HSC_ticker) % ":").length()));
} }
QRegExp re("([a-zA-Z0-9]+)"); QRegExp re("([a-zA-Z0-9]+)");
int pos; int pos;
if ( (pos = re.indexIn(uri)) == -1 ) { if ((pos = re.indexIn(uri)) == -1)
{
ans.error = "Couldn't find an address"; ans.error = "Couldn't find an address";
return ans; return ans;
} }
ans.addr = re.cap(1); ans.addr = re.cap(1);
if (!Settings::isValidAddress(ans.addr)) { if (!Settings::isValidAddress(ans.addr))
{
ans.error = "Could not understand address"; ans.error = "Could not understand address";
return ans; return ans;
} }
uri = uri.right(uri.length() - ans.addr.length()-1); // swallow '?' uri = uri.right(uri.length() - ans.addr.length() - 1); // swallow '?'
QUrlQuery query(uri); QUrlQuery query(uri);
// parse out amt / amount // parse out amt / amount
if (query.hasQueryItem("amt")) { if (query.hasQueryItem("amt"))
ans.amt = query.queryItemValue("amt"); {
} else if (query.hasQueryItem("amount")) { ans.amt = query.queryItemValue("amt");
ans.amt = query.queryItemValue("amount"); }
else if (query.hasQueryItem("amount"))
{
ans.amt = query.queryItemValue("amount");
} }
// parse out memo / msg / message // parse out memo / msg / message
if (query.hasQueryItem("memo")) { if (query.hasQueryItem("memo"))
ans.memo = query.queryItemValue("memo"); {
} else if (query.hasQueryItem("msg")) { ans.memo = query.queryItemValue("memo");
ans.memo = query.queryItemValue("msg"); }
} else if (query.hasQueryItem("message")) { else if (query.hasQueryItem("msg"))
ans.memo = query.queryItemValue("message"); {
ans.memo = query.queryItemValue("msg");
}
else if (query.hasQueryItem("message"))
{
ans.memo = query.queryItemValue("message");
} }
return ans; return ans;

288
src/txtablemodel.cpp

@ -5,21 +5,26 @@
#include "rpc.h" #include "rpc.h"
#include "guiconstants.h" #include "guiconstants.h"
extern bool isdragonx; extern bool isHSC;
extern std::string HSC_ticker;
extern std::string HSC_default_theme;
TxTableModel::TxTableModel(QObject *parent) TxTableModel::TxTableModel(QObject *parent)
: QAbstractTableModel(parent) { : QAbstractTableModel(parent)
{
headers << QObject::tr("Type") << QObject::tr("Address") << QObject::tr("Date/Time") << QObject::tr("Amount"); headers << QObject::tr("Type") << QObject::tr("Address") << QObject::tr("Date/Time") << QObject::tr("Amount");
} }
TxTableModel::~TxTableModel() { TxTableModel::~TxTableModel()
{
delete modeldata; delete modeldata;
delete tTrans; delete tTrans;
delete zsTrans; delete zsTrans;
delete zrTrans; delete zrTrans;
} }
void TxTableModel::addZSentData(const QList<TransactionItem>& data) { void TxTableModel::addZSentData(const QList<TransactionItem> &data)
{
delete zsTrans; delete zsTrans;
zsTrans = new QList<TransactionItem>(); zsTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*zsTrans)); std::copy(data.begin(), data.end(), std::back_inserter(*zsTrans));
@ -27,7 +32,8 @@ void TxTableModel::addZSentData(const QList<TransactionItem>& data) {
updateAllData(); updateAllData();
} }
void TxTableModel::addZRecvData(const QList<TransactionItem>& data) { void TxTableModel::addZRecvData(const QList<TransactionItem> &data)
{
delete zrTrans; delete zrTrans;
zrTrans = new QList<TransactionItem>(); zrTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*zrTrans)); std::copy(data.begin(), data.end(), std::back_inserter(*zrTrans));
@ -35,8 +41,8 @@ void TxTableModel::addZRecvData(const QList<TransactionItem>& data) {
updateAllData(); updateAllData();
} }
void TxTableModel::addTData(const QList<TransactionItem> &data)
void TxTableModel::addTData(const QList<TransactionItem>& data) { {
delete tTrans; delete tTrans;
tTrans = new QList<TransactionItem>(); tTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*tTrans)); std::copy(data.begin(), data.end(), std::back_inserter(*tTrans));
@ -44,7 +50,8 @@ void TxTableModel::addTData(const QList<TransactionItem>& data) {
updateAllData(); updateAllData();
} }
bool TxTableModel::exportToCsv(QString fileName) const { bool TxTableModel::exportToCsv(QString fileName) const
{
if (!modeldata) if (!modeldata)
return false; return false;
@ -52,18 +59,21 @@ bool TxTableModel::exportToCsv(QString fileName) const {
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate))
return false; return false;
QTextStream out(&file); // we will serialize the data into the file QTextStream out(&file); // we will serialize the data into the file
// Write headers // Write headers
for (int i = 0; i < headers.length(); i++) { for (int i = 0; i < headers.length(); i++)
{
out << "\"" << headers[i] << "\","; out << "\"" << headers[i] << "\",";
} }
out << "\"Memo\""; out << "\"Memo\"";
out << endl; out << endl;
// Write out each row // Write out each row
for (int row = 0; row < modeldata->length(); row++) { for (int row = 0; row < modeldata->length(); row++)
for (int col = 0; col < headers.length(); col++) { {
for (int col = 0; col < headers.length(); col++)
{
out << "\"" << data(index(row, col), Qt::DisplayRole).toString() << "\","; out << "\"" << data(index(row, col), Qt::DisplayRole).toString() << "\",";
} }
// Memo // Memo
@ -75,33 +85,38 @@ bool TxTableModel::exportToCsv(QString fileName) const {
return true; return true;
} }
void TxTableModel::updateAllData() { void TxTableModel::updateAllData()
{
auto newmodeldata = new QList<TransactionItem>(); auto newmodeldata = new QList<TransactionItem>();
if (tTrans != nullptr) std::copy( tTrans->begin(), tTrans->end(), std::back_inserter(*newmodeldata)); if (tTrans != nullptr)
if (zsTrans != nullptr) std::copy(zsTrans->begin(), zsTrans->end(), std::back_inserter(*newmodeldata)); std::copy(tTrans->begin(), tTrans->end(), std::back_inserter(*newmodeldata));
if (zrTrans != nullptr) std::copy(zrTrans->begin(), zrTrans->end(), std::back_inserter(*newmodeldata)); if (zsTrans != nullptr)
std::copy(zsTrans->begin(), zsTrans->end(), std::back_inserter(*newmodeldata));
if (zrTrans != nullptr)
std::copy(zrTrans->begin(), zrTrans->end(), std::back_inserter(*newmodeldata));
// Sort by reverse time // Sort by reverse time
std::sort(newmodeldata->begin(), newmodeldata->end(), [=] (auto a, auto b) { std::sort(newmodeldata->begin(), newmodeldata->end(), [=](auto a, auto b)
return a.datetime > b.datetime; // reverse sort {
}); return a.datetime > b.datetime; // reverse sort
});
// And then swap out the modeldata with the new one. // And then swap out the modeldata with the new one.
delete modeldata; delete modeldata;
modeldata = newmodeldata; modeldata = newmodeldata;
dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1)); dataChanged(index(0, 0), index(modeldata->size() - 1, columnCount(index(0, 0)) - 1));
layoutChanged(); layoutChanged();
} }
QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const
QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const{ {
QImage img(icon.pixmap(16, 16).toImage()); QImage img(icon.pixmap(16, 16).toImage());
img = img.convertToFormat(QImage::Format_ARGB32); img = img.convertToFormat(QImage::Format_ARGB32);
for (int x = img.width(); x--; ) for (int x = img.width(); x--;)
{ {
for (int y = img.height(); y--; ) for (int y = img.height(); y--;)
{ {
const QRgb rgb = img.pixel(x, y); const QRgb rgb = img.pixel(x, y);
img.setPixel(x, y, qRgba(color.red(), color.green(), color.blue(), qAlpha(rgb))); img.setPixel(x, y, qRgba(color.red(), color.green(), color.blue(), qAlpha(rgb)));
@ -110,123 +125,158 @@ QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const{
return img; return img;
} }
int TxTableModel::rowCount(const QModelIndex &) const
int TxTableModel::rowCount(const QModelIndex&) const
{ {
if (modeldata == nullptr) return 0; if (modeldata == nullptr)
return 0;
return modeldata->size(); return modeldata->size();
} }
int TxTableModel::columnCount(const QModelIndex&) const int TxTableModel::columnCount(const QModelIndex &) const
{ {
return headers.size(); return headers.size();
} }
QVariant TxTableModel::data(const QModelIndex &index, int role) const
QVariant TxTableModel::data(const QModelIndex &index, int role) const {
{
// Get current theme name // Get current theme name
QString theme_name = Settings::getInstance()->get_theme_name(); QString theme_name = Settings::getInstance()->get_theme_name();
QBrush b; QBrush b;
QColor color; QColor color;
if (theme_name == "dark" || theme_name == "midnight") { if (theme_name == "dark" || theme_name == "midnight")
{
color = COLOR_WHITE; color = COLOR_WHITE;
}else if(theme_name == "dragonx"){ }
else if (theme_name == (QString::fromStdString(HSC_default_theme)))
{
color = COLOR_DRAGONX_TEXT; color = COLOR_DRAGONX_TEXT;
}else{ }
else
{
color = COLOR_BLACK; color = COLOR_BLACK;
} }
// Align column 4 (amount) right // Align column 4 (amount) right
if (role == Qt::TextAlignmentRole && index.column() == 3) return QVariant(Qt::AlignRight | Qt::AlignVCenter); if (role == Qt::TextAlignmentRole && index.column() == 3)
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::ForegroundRole) {
if (modeldata->at(index.row()).confirmations == 0) { if (role == Qt::ForegroundRole)
{
if (modeldata->at(index.row()).confirmations == 0)
{
b.setColor(COLOR_UNCONFIRMED_TX); b.setColor(COLOR_UNCONFIRMED_TX);
return b; return b;
} }
if (theme_name == "dark" || theme_name == "midnight") { if (theme_name == "dark" || theme_name == "midnight")
{
b.setColor(color); b.setColor(color);
return b; return b;
}else{ }
else
{
b.setColor(color); b.setColor(color);
return b; return b;
} }
return b; return b;
} }
auto dat = modeldata->at(index.row()); auto dat = modeldata->at(index.row());
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole)
switch (index.column()) { {
case 0: return dat.type; switch (index.column())
case 1: { {
auto addr = modeldata->at(index.row()).address; case 0:
if (addr.trimmed().isEmpty()) return dat.type;
return "(Shielded)"; case 1:
else {
return addr; auto addr = modeldata->at(index.row()).address;
} if (addr.trimmed().isEmpty())
case 2: return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString(); return "(Shielded)";
case 3: return Settings::getDisplayFormat(modeldata->at(index.row()).amount); else
return addr;
}
case 2:
return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString();
case 3:
return Settings::getDisplayFormat(modeldata->at(index.row()).amount);
} }
}
if (role == Qt::ToolTipRole) {
switch (index.column()) {
case 0: {
if (dat.memo.startsWith("hush:")) {
return Settings::paymentURIPretty(Settings::parseURI(dat.memo));
} else {
return modeldata->at(index.row()).type +
(dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo.toHtmlEscaped() + "\"");
}
}
case 1: {
auto addr = modeldata->at(index.row()).address;
if (addr.trimmed().isEmpty())
return "(Shielded)";
else
return addr;
}
case 2: return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString();
case 3: return Settings::getInstance()->getUSDFormat(modeldata->at(index.row()).amount);
}
} }
if (role == Qt::DecorationRole && index.column() == 0) { if (role == Qt::ToolTipRole)
{
switch (index.column())
{
case 0:
{
if (dat.memo.startsWith("hush:"))
{
return Settings::paymentURIPretty(Settings::parseURI(dat.memo));
}
else
{
return modeldata->at(index.row()).type +
(dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo.toHtmlEscaped() + "\"");
}
}
case 1:
{
auto addr = modeldata->at(index.row()).address;
if (addr.trimmed().isEmpty())
return "(Shielded)";
else
return addr;
}
case 2:
return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString();
case 3:
return Settings::getInstance()->getUSDFormat(modeldata->at(index.row()).amount);
}
}
if (role == Qt::DecorationRole && index.column() == 0)
{
//qDebug() << "TX Type = " + dat.type; // qDebug() << "TX Type = " + dat.type;
if (!dat.memo.isEmpty()) { if (!dat.memo.isEmpty())
{
// If the memo is a Payment URI, then show a payment request icon // If the memo is a Payment URI, then show a payment request icon
if(isdragonx) { if (isHSC)
if (dat.memo.startsWith("drgx:")) { {
std::string ticker = "" + HSC_ticker + ":";
if (dat.memo.startsWith(ticker.c_str()))
{
QIcon icon(":/icons/paymentreq.gif"); QIcon icon(":/icons/paymentreq.gif");
return QVariant(icon.pixmap(16, 16)); return QVariant(icon.pixmap(16, 16));
} }
} else if (dat.memo.startsWith("hush:")) { }
else if (dat.memo.startsWith("hush:"))
{
QIcon icon(":/icons/paymentreq.gif"); QIcon icon(":/icons/paymentreq.gif");
return QVariant(icon.pixmap(16, 16)); return QVariant(icon.pixmap(16, 16));
} }
// Return the info pixmap to indicate memo // Return the info pixmap to indicate memo
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
return QVariant(icon.pixmap(16, 16)); return QVariant(icon.pixmap(16, 16));
} else { }
else
{
// TODO: Add appropriate icons for types of txs instead of empty pixmap // TODO: Add appropriate icons for types of txs instead of empty pixmap
//qDebug() << "Type = " +getType(index.row()) + "Address = " +getAddr(index.row()) + "From Address = " +getFromAddr(index.row()); // qDebug() << "Type = " +getType(index.row()) + "Address = " +getAddr(index.row()) + "From Address = " +getFromAddr(index.row());
// Send // Send
if(this->getType(index.row()) == "send"){ if (this->getType(index.row()) == "send")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_output.png"), color); QImage image = colorizeIcon(QIcon(":/icons/tx_output.png"), color);
QIcon icon; QIcon icon;
icon.addPixmap(QPixmap::fromImage(image)); icon.addPixmap(QPixmap::fromImage(image));
return QVariant(icon.pixmap(16, 16)); return QVariant(icon.pixmap(16, 16));
} }
// Send T->Z - Untested // Send T->Z - Untested
if(this->getType(index.row()) == "send" && !this->getFromAddr(index.row()).startsWith("zs1")){ if (this->getType(index.row()) == "send" && !this->getFromAddr(index.row()).startsWith("zs1"))
{
QImage image = colorizeIcon(QIcon(":/icons/lock_closed.png"), color); QImage image = colorizeIcon(QIcon(":/icons/lock_closed.png"), color);
QIcon icon; QIcon icon;
icon.addPixmap(QPixmap::fromImage(image)); icon.addPixmap(QPixmap::fromImage(image));
@ -234,7 +284,8 @@ int TxTableModel::columnCount(const QModelIndex&) const
} }
// Receive // Receive
if(this->getType(index.row()) == "receive"){ if (this->getType(index.row()) == "receive")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_input.png"), color); QImage image = colorizeIcon(QIcon(":/icons/tx_input.png"), color);
QIcon icon; QIcon icon;
icon.addPixmap(QPixmap::fromImage(image)); icon.addPixmap(QPixmap::fromImage(image));
@ -242,7 +293,8 @@ int TxTableModel::columnCount(const QModelIndex&) const
} }
// Mined // Mined
if(this->getType(index.row()) == "generate"){ if (this->getType(index.row()) == "generate")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_mined.png"), color); QImage image = colorizeIcon(QIcon(":/icons/tx_mined.png"), color);
QIcon icon; QIcon icon;
icon.addPixmap(QPixmap::fromImage(image)); icon.addPixmap(QPixmap::fromImage(image));
@ -257,54 +309,64 @@ int TxTableModel::columnCount(const QModelIndex&) const
} }
return QVariant(); return QVariant();
} }
QVariant TxTableModel::headerData(int section, Qt::Orientation orientation, int role) const QVariant TxTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{ {
if (role == Qt::TextAlignmentRole && section == 3) return QVariant(Qt::AlignRight | Qt::AlignVCenter); if (role == Qt::TextAlignmentRole && section == 3)
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::FontRole) { if (role == Qt::FontRole)
QFont f; {
f.setBold(true); QFont f;
return f; f.setBold(true);
} return f;
}
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
return headers.at(section); {
} return headers.at(section);
}
return QVariant(); return QVariant();
} }
QString TxTableModel::getTxId(int row) const { QString TxTableModel::getTxId(int row) const
{
return modeldata->at(row).txid; return modeldata->at(row).txid;
} }
QString TxTableModel::getMemo(int row) const { QString TxTableModel::getMemo(int row) const
{
return modeldata->at(row).memo; return modeldata->at(row).memo;
} }
qint64 TxTableModel::getConfirmations(int row) const { qint64 TxTableModel::getConfirmations(int row) const
{
return modeldata->at(row).confirmations; return modeldata->at(row).confirmations;
} }
QString TxTableModel::getAddr(int row) const { QString TxTableModel::getAddr(int row) const
{
return modeldata->at(row).address.trimmed(); return modeldata->at(row).address.trimmed();
} }
QString TxTableModel::getFromAddr(int row) const { QString TxTableModel::getFromAddr(int row) const
{
return modeldata->at(row).fromAddr.trimmed(); return modeldata->at(row).fromAddr.trimmed();
} }
qint64 TxTableModel::getDate(int row) const { qint64 TxTableModel::getDate(int row) const
{
return modeldata->at(row).datetime; return modeldata->at(row).datetime;
} }
QString TxTableModel::getType(int row) const { QString TxTableModel::getType(int row) const
{
return modeldata->at(row).type; return modeldata->at(row).type;
} }
QString TxTableModel::getAmt(int row) const { QString TxTableModel::getAmt(int row) const
{
return Settings::getDecimalString(modeldata->at(row).amount); return Settings::getDecimalString(modeldata->at(row).amount);
} }

Loading…
Cancel
Save