Browse Source

Added dynamic variables to support building for any HSC

pull/133/head
D 9 months ago
parent
commit
a0eb012ec9
  1. 1
      application-sdx.qrc
  2. 1
      application.qrc
  3. 114
      res/css/tumin.css
  4. 4
      src/3rdparty/qrcode/QrCode.cpp
  5. 2
      src/3rdparty/qrcode/QrCode.hpp
  6. 208
      src/addressbook.cpp
  7. 610
      src/connection.cpp
  8. 188
      src/main.cpp
  9. 895
      src/mainwindow.cpp
  10. 76
      src/requestdialog.cpp
  11. 1250
      src/rpc.cpp
  12. 99
      src/senttxstore.cpp
  13. 396
      src/settings.cpp
  14. 288
      src/txtablemodel.cpp

1
application-sdx.qrc

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

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
}

4
src/3rdparty/qrcode/QrCode.cpp

@ -166,7 +166,7 @@ bool QrCode::getModule(int x, int y) const {
}
std::string QrCode::toSvgString(int border) const {
QString QrCode::toSvgString(int border) const {
if (border < 0)
throw std::domain_error("Border must be non-negative");
if (border > INT_MAX / 2 || border * 2 > INT_MAX - size)
@ -190,7 +190,7 @@ std::string QrCode::toSvgString(int border) const {
}
sb << "\" fill=\"#000000\"/>\n";
sb << "</svg>\n";
return sb.str();
return QString::fromStdString(sb.str());
}

2
src/3rdparty/qrcode/QrCode.hpp

@ -187,7 +187,7 @@ class QrCode final {
* Returns a string of SVG code for an image depicting this QR Code, with the given number
* of border modules. The string always uses Unix newlines (\n), regardless of the platform.
*/
public: std::string toSvgString(int border) const;
public: QString toSvgString(int border) const;

208
src/addressbook.cpp

@ -7,96 +7,110 @@
#include "mainwindow.h"
#include "rpc.h"
extern bool isdragonx;
extern bool isHSC;
extern std::string HSC_name;
AddressBookModel::AddressBookModel(QTableView *parent)
: QAbstractTableModel(parent) {
: QAbstractTableModel(parent)
{
headers << tr("Label") << tr("Address");
this->parent = parent;
loadData();
}
AddressBookModel::~AddressBookModel() {
AddressBookModel::~AddressBookModel()
{
saveData();
}
void AddressBookModel::saveData() {
void AddressBookModel::saveData()
{
// Save column positions
QSettings().setValue("addresstablegeometry", parent->horizontalHeader()->saveState());
}
void AddressBookModel::loadData() {
void AddressBookModel::loadData()
{
labels = AddressBook::getInstance()->getAllAddressLabels();
parent->horizontalHeader()->restoreState(QSettings().value("addresstablegeometry").toByteArray());
}
void AddressBookModel::addNewLabel(QString label, QString addr) {
//labels.push_back(QPair<QString, QString>(label, addr));
void AddressBookModel::addNewLabel(QString label, QString addr)
{
// labels.push_back(QPair<QString, QString>(label, addr));
AddressBook::getInstance()->addAddressLabel(label, addr);
labels.clear();
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();
}
void AddressBookModel::removeItemAt(int row) {
void AddressBookModel::removeItemAt(int row)
{
if (row >= labels.size())
return;
AddressBook::getInstance()->removeAddressLabel(labels[row].first, labels[row].second);
labels.clear();
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();
}
QPair<QString, QString> AddressBookModel::itemAt(int row) {
if (row >= labels.size()) return QPair<QString, QString>();
QPair<QString, QString> AddressBookModel::itemAt(int row)
{
if (row >= labels.size())
return QPair<QString, QString>();
return labels.at(row);
}
int AddressBookModel::rowCount(const QModelIndex&) const {
int AddressBookModel::rowCount(const QModelIndex &) const
{
return labels.size();
}
int AddressBookModel::columnCount(const QModelIndex&) const {
int AddressBookModel::columnCount(const QModelIndex &) const
{
return headers.size();
}
QVariant AddressBookModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) {
switch(index.column()) {
case 0: return labels.at(index.row()).first;
case 1: return labels.at(index.row()).second;
QVariant AddressBookModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case 0:
return labels.at(index.row()).first;
case 1:
return labels.at(index.row()).second;
}
}
return QVariant();
}
}
QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
return headers.at(section);
}
return QVariant();
}
//===============
// AddressBook
//===============
void AddressBook::open(MainWindow* parent, QLineEdit* target) {
void AddressBook::open(MainWindow *parent, QLineEdit *target)
{
QDialog d(parent);
Ui_addressBook ab;
ab.setupUi(&d);
@ -109,21 +123,25 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
ab.addresses->setModel(&model);
// 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"));
}
}
// 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 (target != nullptr && Settings::isValidAddress(target->text())) {
if (target != nullptr && Settings::isValidAddress(target->text()))
{
ab.addr->setText(target->text());
ab.label->setFocus();
}
// Add new address button
QObject::connect(ab.addNew, &QPushButton::clicked, [&] () {
QObject::connect(ab.addNew, &QPushButton::clicked, [&]()
{
auto addr = ab.addr->text().trimmed();
QString newLabel = ab.label->text();
@ -150,11 +168,11 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
return;
}
model.addNewLabel(newLabel, ab.addr->text());
});
model.addNewLabel(newLabel, ab.addr->text()); });
// Import Button
QObject::connect(ab.btnImport, &QPushButton::clicked, [&] () {
QObject::connect(ab.btnImport, &QPushButton::clicked, [&]()
{
// Get the import file name.
auto fileName = QFileDialog::getOpenFileUrl(&d, QObject::tr("Import Address Book"), QUrl(),
"CSV file (*.csv)");
@ -184,15 +202,16 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
}
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);
};
// 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 (!target)
return;
@ -202,12 +221,12 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
QString lbl = model.itemAt(index.row()).first;
QString addr = model.itemAt(index.row()).second;
d.accept();
fnSetTargetLabelAddr(target, lbl, addr);
});
fnSetTargetLabelAddr(target, lbl, addr); });
// Right-Click
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);
if (index.row() < 0) return;
@ -233,12 +252,13 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
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();
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());
fnSetTargetLabelAddr(target, item.first, item.second);
}
@ -251,26 +271,30 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) {
//=============
// AddressBook singleton class
//=============
AddressBook* AddressBook::getInstance() {
AddressBook *AddressBook::getInstance()
{
if (!instance)
instance = new AddressBook();
return instance;
}
AddressBook::AddressBook() {
AddressBook::AddressBook()
{
readFromStorage();
}
void AddressBook::readFromStorage() {
void AddressBook::readFromStorage()
{
QFile file(AddressBook::writeableFile());
if (file.exists()) {
if (file.exists())
{
allLabels.clear();
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;
in >> version >> allLabels;
in >> version >> allLabels;
file.close();
}
@ -284,40 +308,48 @@ void AddressBook::readFromStorage() {
// }
}
void AddressBook::writeToStorage() {
void AddressBook::writeToStorage()
{
QFile file(AddressBook::writeableFile());
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;
file.close();
}
QString AddressBook::writeableFile() {
QString AddressBook::writeableFile()
{
auto filename = QStringLiteral("addresslabels.dat");
if (isdragonx) {
filename = QStringLiteral("addresslabels-drgx.dat");
if (isHSC)
{
filename = QString::fromStdString("addresslabels-" + HSC_name + ".dat");
}
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (!dir.exists())
QDir().mkpath(dir.absolutePath());
if (Settings::getInstance()->isTestnet()) {
if (Settings::getInstance()->isTestnet())
{
return dir.filePath("testnet-" % filename);
} else {
}
else
{
return dir.filePath(filename);
}
}
// 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));
// First, remove any existing label
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) {
if (allLabels[i].first == label) {
for (int i = 0; i < allLabels.size(); i++)
{
if (allLabels[i].first == label)
{
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
void AddressBook::removeAddressLabel(QString label, QString address) {
void AddressBook::removeAddressLabel(QString label, QString address)
{
// Iterate over the list and remove the label/address
for (int i=0; i < allLabels.size(); i++) {
if (allLabels[i].first == label && allLabels[i].second == address) {
for (int i = 0; i < allLabels.size(); i++)
{
if (allLabels[i].first == label && allLabels[i].second == address)
{
allLabels.removeAt(i);
writeToStorage();
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
for (int i = 0; i < allLabels.size(); i++) {
if (allLabels[i].first == oldlabel && allLabels[i].second == address) {
for (int i = 0; i < allLabels.size(); i++)
{
if (allLabels[i].first == oldlabel && allLabels[i].second == address)
{
allLabels[i].first = newlabel;
writeToStorage();
return;
@ -350,16 +388,20 @@ void AddressBook::updateLabel(QString oldlabel, QString address, QString newlabe
}
// Read all addresses
const QList<QPair<QString, QString>>& AddressBook::getAllAddressLabels() {
if (allLabels.isEmpty()) {
const QList<QPair<QString, QString>> &AddressBook::getAllAddressLabels()
{
if (allLabels.isEmpty())
{
readFromStorage();
}
return allLabels;
}
// Get the label for an address
QString AddressBook::getLabelForAddress(QString addr) {
for (auto i : allLabels) {
QString AddressBook::getLabelForAddress(QString addr)
{
for (auto i : allLabels)
{
if (i.second == addr)
return i.first;
}
@ -368,8 +410,10 @@ QString AddressBook::getLabelForAddress(QString addr) {
}
// Get the address for a label
QString AddressBook::getAddressForLabel(QString label) {
for (auto i: allLabels) {
QString AddressBook::getAddressForLabel(QString label)
{
for (auto i : allLabels)
{
if (i.first == label)
return i.second;
}
@ -377,7 +421,8 @@ QString AddressBook::getAddressForLabel(QString label) {
return "";
}
QString AddressBook::addLabelToAddress(QString addr) {
QString AddressBook::addLabelToAddress(QString addr)
{
QString label = AddressBook::getInstance()->getLabelForAddress(addr);
if (!label.isEmpty())
return label + "/" + addr;
@ -385,8 +430,9 @@ QString AddressBook::addLabelToAddress(QString addr) {
return addr;
}
QString AddressBook::addressFromAddressLabel(const QString& lblAddr) {
return lblAddr.trimmed().split("/").last();
QString AddressBook::addressFromAddressLabel(const QString &lblAddr)
{
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

188
src/main.cpp

@ -7,9 +7,21 @@
#include "settings.h"
#include "version.h"
bool isdragonx = 0;
class SignalHandler
bool isHSC = 1;
std::string HSC_name = "dragonx";
std::string HSC_ticker = "drgx";
std::string HSC_default_theme = "dragonx";
std::string HSC_app_name = "silentdragonx";
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 = "SilentDragonX";
std::string HSC_ac_name = "DRAGONX";
std::string HSC_port = "21769";
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";
class SignalHandler
{
public:
SignalHandler(int mask = DEFAULT_SIGNALS);
@ -17,12 +29,12 @@ public:
enum SIGNALS
{
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_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_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_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_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_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]
DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
};
static const int numSignals = 6;
@ -44,7 +56,7 @@ private:
#endif //!_WIN32
// There can be only ONE SignalHandler per process
SignalHandler* g_handler(NULL);
SignalHandler *g_handler(NULL);
#ifndef _WIN32
@ -59,7 +71,7 @@ SignalHandler::SignalHandler(int mask) : _mask(mask)
assert(g_handler == NULL);
g_handler = this;
for (int i=0;i<numSignals;i++)
for (int i = 0; i < numSignals; i++)
{
int logical = 0x1 << i;
if (_mask & logical)
@ -73,13 +85,12 @@ SignalHandler::SignalHandler(int mask) : _mask(mask)
#endif //_WIN32
}
}
}
SignalHandler::~SignalHandler()
{
#ifndef _WIN32
for (int i=0;i<numSignals;i++)
for (int i = 0; i < numSignals; i++)
{
int logical = 0x1 << i;
if (_mask & logical)
@ -90,33 +101,38 @@ SignalHandler::~SignalHandler()
#endif //_WIN32
}
#ifndef _WIN32
int POSIX_logicalToPhysical(int signal)
{
switch (signal)
{
case SignalHandler::SIG_INT: return SIGINT;
case SignalHandler::SIG_TERM: return SIGTERM;
case SignalHandler::SIG_INT:
return SIGINT;
case SignalHandler::SIG_TERM:
return SIGTERM;
// In case the client asks for a SIG_CLOSE handler, accept and
// bind it to a SIGTERM. Anyway the signal will never be raised
case SignalHandler::SIG_CLOSE: return SIGTERM;
case SignalHandler::SIG_RELOAD: return SIGHUP;
default:
case SignalHandler::SIG_CLOSE:
return SIGTERM;
case SignalHandler::SIG_RELOAD:
return SIGHUP;
default:
return -1; // SIG_ERR = -1
}
}
#endif //_WIN32
#ifndef _WIN32
int POSIX_physicalToLogical(int signal)
{
switch (signal)
{
case SIGINT: return SignalHandler::SIG_INT;
case SIGTERM: return SignalHandler::SIG_TERM;
case SIGHUP: return SignalHandler::SIG_RELOAD;
case SIGINT:
return SignalHandler::SIG_INT;
case SIGTERM:
return SignalHandler::SIG_TERM;
case SIGHUP:
return SignalHandler::SIG_RELOAD;
default:
return SignalHandler::SIG_UNHANDLED;
}
@ -141,16 +157,20 @@ public:
~Application() {}
int main(int argc, char *argv[]) {
fprintf(stderr,"%s: argv0 = %s\n", __func__, argv[0]);
int main(int argc, char *argv[])
{
fprintf(stderr, "%s: argv0 = %s\n", __func__, argv[0]);
QString binaryName(argv[0]);
binaryName = binaryName.toLower();
QStringList pathParts = binaryName.split(QLatin1Char('/'));
qDebug() << pathParts;
isdragonx = binaryName.endsWith("dragonx") || binaryName.endsWith("dragonx.exe") || binaryName.endsWith("dragonx.app");
qDebug() << "isdragonx=" << isdragonx;
std::string appname_exe = HSC_app_name + ".exe";
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_EnableHighDpiScaling);
@ -176,25 +196,30 @@ public:
parser.process(a);
// Check for a positional argument indicating a Hush payment URI
if (a.isSecondary()) {
if (parser.positionalArguments().length() > 0) {
a.sendMessage(parser.positionalArguments()[0].toUtf8());
if (a.isSecondary())
{
if (parser.positionalArguments().length() > 0)
{
a.sendMessage(parser.positionalArguments()[0].toUtf8());
}
a.exit( 0 );
return 0;
}
a.exit(0);
return 0;
}
QCoreApplication::setOrganizationName("Hush");
QCoreApplication::setApplicationName(isdragonx ? "SilentDragonX" : "SilentDragon");
QCoreApplication::setApplicationName(isHSC ? App_title.c_str() : "SilentDragon");
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;
QTranslator translator;
if(isdragonx) {
if (isHSC)
{
translator.load(QString(":/translations/silentdragon_") + locale);
} else {
}
else
{
translator.load(QString(":/translations/silentdragon_") + locale);
}
a.installTranslator(&translator);
@ -202,65 +227,76 @@ public:
QIcon icon(":/icons/icon.ico");
QApplication::setWindowIcon(icon);
// TODO: update for SD
#ifdef Q_OS_LINUX
QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf");
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif
// TODO: update for SD
#ifdef Q_OS_LINUX
QFontDatabase::addApplicationFont(":/fonts/Ubuntu-R.ttf");
qApp->setFont(QFont("Ubuntu", 11, QFont::Normal, false));
#endif
// 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();
#else
// This will be used only during debugging for compatibility reasons
#else
// This will be used only during debugging for compatibility reasons
unsigned int seed = std::time(0);
#endif
#endif
std::srand(seed);
Settings::init();
// Set up libsodium
if (sodium_init() < 0) {
if (sodium_init() < 0)
{
/* panic! the library couldn't be initialized, it is not safe to use */
qDebug() << "libsodium is not initialized!";
exit(0);
}
// Check for embedded option
if (parser.isSet(noembeddedOption)) {
if (parser.isSet(noembeddedOption))
{
Settings::getInstance()->setUseEmbedded(false);
} else {
}
else
{
Settings::getInstance()->setUseEmbedded(true);
}
w = new MainWindow();
if(isdragonx) {
w->setWindowTitle("SilentDragonX v" + QString(APP_VERSION));
} else {
if (isHSC)
{
w->setWindowTitle((QString::fromStdString(App_title) + " v" + QString(APP_VERSION)));
}
else
{
w->setWindowTitle("SilentDragon v" + QString(APP_VERSION));
}
// 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]);
}
// 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);
// 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
a.installEventFilter(w);
// Check if starting headless
if (parser.isSet(headlessOption)) {
if (parser.isSet(headlessOption))
{
Settings::getInstance()->setHeadless(true);
a.setQuitOnLastWindowClosed(false);
} else {
a.setQuitOnLastWindowClosed(false);
}
else
{
Settings::getInstance()->setHeadless(false);
w->show();
}
@ -271,42 +307,44 @@ public:
void DispatchToMainThread(std::function<void()> callback)
{
// any thread
QTimer* timer = new QTimer();
QTimer *timer = new QTimer();
timer->moveToThread(qApp->thread());
timer->setSingleShot(true);
QObject::connect(timer, &QTimer::timeout, [=]()
{
{
// main thread
callback();
timer->deleteLater();
});
timer->deleteLater(); });
QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0));
}
bool handleSignal(int signal)
{
std::cout << std::endl << "Interrupted with signal " << signal << std::endl;
if (w && w->getRPC()) {
std::cout << std::endl
<< "Interrupted with signal " << signal << std::endl;
if (w && w->getRPC())
{
// Blocking call to closeEvent on the UI thread.
DispatchToMainThread([=] {
DispatchToMainThread([=]
{
w->doClose();
QApplication::quit();
});
} else {
QApplication::quit(); });
}
else
{
QApplication::quit();
}
return true;
}
private:
MainWindow* w;
MainWindow *w;
};
int main(int argc, char* argv[])
int main(int argc, char *argv[])
{
Application app;
return app.main(argc, argv);
}

895
src/mainwindow.cpp

File diff suppressed because it is too large

76
src/requestdialog.cpp

@ -8,11 +8,13 @@
#include "rpc.h"
#include "settings.h"
#include "precompiled.h"
extern bool isdragonx;
RequestDialog::RequestDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::RequestDialog)
extern bool isHSC;
extern std::string HSC_ac_name;
extern std::string HSC_ticker;
RequestDialog::RequestDialog(QWidget *parent) : QDialog(parent),
ui(new Ui::RequestDialog)
{
ui->setupUi(this);
}
@ -22,7 +24,8 @@ RequestDialog::~RequestDialog()
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);
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())
return;
for (auto addr : *main->getRPC()->getAllZAddresses()) {
for (auto addr : *main->getRPC()->getAllZAddresses())
{
auto bal = main->getRPC()->getAllBalances()->value(addr);
if (Settings::getInstance()->isSaplingAddress(addr)) {
if (Settings::getInstance()->isSaplingAddress(addr))
{
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
void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI) {
void RequestDialog::showPaymentConfirmation(MainWindow *main, QString paymentURI)
{
PaymentURI payInfo = Settings::parseURI(paymentURI);
if (!payInfo.error.isEmpty()) {
if(isdragonx) {
QMessageBox::critical(main, tr("Error paying DRAGONX URI"),
tr("URI should be of the form 'drgx:<addr>?amt=x&memo=y") + "\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);
if (!payInfo.error.isEmpty())
{
if (isHSC)
{
std::string error = "Error paying " + HSC_ac_name + " URI";
std::string error2 = "URI should be of the form '" + HSC_ticker + ":<addr>?amt=x&memo=y";
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;
}
QDialog d(main);
Ui_RequestDialog req;
setupDialog(main, &d, &req);
setupDialog(main, &d, &req);
// In the view mode, all fields are read-only
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."));
if (d.exec() == QDialog::Accepted) {
if (d.exec() == QDialog::Accepted)
{
main->payHushURI(paymentURI, req.cmbMyAddress->currentText());
}
}
// Static method that shows the request dialog
void RequestDialog::showRequestZcash(MainWindow* main) {
void RequestDialog::showRequestZcash(MainWindow *main)
{
QDialog d(main);
Ui_RequestDialog req;
@ -100,7 +113,8 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
// Setup the Label completer for the Address
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);
if (!Settings::getInstance()->isSaplingAddress(addr)) {
req.lblSaplingWarning->setText(tr("Can only request from Sapling addresses"));
@ -108,19 +122,16 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
} else {
req.lblSaplingWarning->setText("");
req.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
});
} });
// Wire up AddressBook button
QObject::connect(req.btnAddressBook, &QPushButton::clicked, [=] () {
AddressBook::open(main, req.txtFrom);
});
QObject::connect(req.btnAddressBook, &QPushButton::clicked, [=]()
{ AddressBook::open(main, req.txtFrom); });
// Amount textbox
req.txtAmount->setValidator(main->getAmountValidator());
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=] (auto text) {
req.txtAmountUSD->setText(Settings::getUSDFormat(text.toDouble()));
});
QObject::connect(req.txtAmount, &QLineEdit::textChanged, [=](auto text)
{ req.txtAmountUSD->setText(Settings::getUSDFormat(text.toDouble())); });
req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble()));
req.txtMemo->setAcceptButton(req.buttonBox->button(QDialogButtonBox::Ok));
@ -129,15 +140,12 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
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.
QString memoURI = (isdragonx ? "drgx:" : "hush:" ) + req.cmbMyAddress->currentText()
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
QString memoURI = (isHSC ? (QString::fromStdString(HSC_ticker) + ":") : "hush:") + req.cmbMyAddress->currentText() + "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble()) + "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
QString sendURI = (isdragonx ? "drgx:" : "hush:" ) + AddressBook::addressFromAddressLabel(req.txtFrom->text())
+ "?amt=0.0001"
+ "&memo=" + QUrl::toPercentEncoding(memoURI);
QString sendURI = (isHSC ? QString::fromStdString((HSC_ticker) + ":") : "hush:") + AddressBook::addressFromAddressLabel(req.txtFrom->text()) + "?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
// 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 "settings.h"
extern bool isdragonx;
extern bool isHSC;
extern std::string HSC_ticker;
/// Get the location of the app data file to be written.
QString SentTxStore::writeableFile() {
/// Get the location of the app data file to be written.
QString SentTxStore::writeableFile()
{
auto filename = QStringLiteral("senttxstore.dat");
if (isdragonx) {
filename = QStringLiteral("senttxstore-drgx.dat");
if (isHSC)
{
std::string ticker = ("senttxstore-" + HSC_ticker + ".dat");
filename = QString::fromStdString(ticker);
}
auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
if (!dir.exists())
QDir().mkpath(dir.absolutePath());
if (Settings::getInstance()->isTestnet()) {
if (Settings::getInstance()->isTestnet())
{
return dir.filePath("testnet-" % filename);
} else {
}
else
{
qDebug() << "senttxstore file = " + dir.filePath(filename);
return dir.filePath(filename);
}
}
// delete the sent history.
void SentTxStore::deleteHistory() {
// delete the sent history.
void SentTxStore::deleteHistory()
{
QFile data(writeableFile());
data.remove();
data.close();
}
QList<TransactionItem> SentTxStore::readSentTxFile() {
QList<TransactionItem> SentTxStore::readSentTxFile()
{
QFile data(writeableFile());
if (!data.exists()) {
if (!data.exists())
{
return QList<TransactionItem>();
}
QJsonDocument jsonDoc;
data.open(QFile::ReadOnly);
data.open(QFile::ReadOnly);
jsonDoc = QJsonDocument::fromJson(data.readAll());
data.close();
QList<TransactionItem> items;
for (auto i : jsonDoc.array()) {
for (auto i : jsonDoc.array())
{
auto sentTx = i.toObject();
TransactionItem t{"send", (qint64)sentTx["datetime"].toVariant().toLongLong(),
sentTx["address"].toString(),
sentTx["txid"].toString(),
sentTx["amount"].toDouble() + sentTx["fee"].toDouble(),
TransactionItem t{"send", (qint64)sentTx["datetime"].toVariant().toLongLong(),
sentTx["address"].toString(),
sentTx["txid"].toString(),
sentTx["amount"].toDouble() + sentTx["fee"].toDouble(),
0, sentTx["from"].toString(), sentTx["memo"].toString()};
items.push_back(t);
}
@ -58,21 +69,23 @@ QList<TransactionItem> SentTxStore::readSentTxFile() {
return items;
}
void SentTxStore::addToSentTx(Tx tx, QString txid) {
void SentTxStore::addToSentTx(Tx tx, QString txid)
{
// Save transactions only if the settings are allowed
if (!Settings::getInstance()->getSaveZtxs())
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
if (!tx.fromAddr.startsWith("z"))
if (!tx.fromAddr.startsWith("z"))
return;
QFile data(writeableFile());
QJsonDocument jsonDoc;
// If data doesn't exist, then create a blank one
if (!data.exists()) {
if (!data.exists())
{
QJsonArray a;
jsonDoc.setArray(a);
@ -80,46 +93,54 @@ void SentTxStore::addToSentTx(Tx tx, QString txid) {
newFile.open(QFile::WriteOnly);
newFile.write(jsonDoc.toJson());
newFile.close();
} else {
data.open(QFile::ReadOnly);
}
else
{
data.open(QFile::ReadOnly);
jsonDoc = QJsonDocument().fromJson(data.readAll());
data.close();
}
// Calculate total amount in this tx
double totalAmount = 0;
for (auto i : tx.toAddrs) {
for (auto i : tx.toAddrs)
{
totalAmount += i.amount;
}
QString toAddresses;
if (tx.toAddrs.length() == 1) {
if (tx.toAddrs.length() == 1)
{
toAddresses = tx.toAddrs[0].addr;
} else {
}
else
{
// Concatenate all the toAddresses
for (auto a : tx.toAddrs) {
for (auto a : tx.toAddrs)
{
toAddresses += a.addr % "(" % Settings::getDisplayFormat(a.amount) % ") ";
}
}
auto list = jsonDoc.array();
QJsonObject txItem;
txItem["type"] = "sent";
txItem["from"] = tx.fromAddr;
txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000;
txItem["address"] = toAddresses;
txItem["txid"] = txid;
txItem["amount"] = -totalAmount;
txItem["fee"] = -tx.fee;
txItem["type"] = "sent";
txItem["from"] = tx.fromAddr;
txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000;
txItem["address"] = toAddresses;
txItem["txid"] = txid;
txItem["amount"] = -totalAmount;
txItem["fee"] = -tx.fee;
// TODO: store all outgoing memos
txItem["memo"] = tx.toAddrs[0].txtMemo;
txItem["memo"] = tx.toAddrs[0].txtMemo;
list.append(txItem);
jsonDoc.setArray(list);
QFile writer(writeableFile());
if (writer.open(QFile::WriteOnly | QFile::Truncate)) {
if (writer.open(QFile::WriteOnly | QFile::Truncate))
{
writer.write(jsonDoc.toJson());
}
}
writer.close();
}

396
src/settings.cpp

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

288
src/txtablemodel.cpp

@ -5,21 +5,26 @@
#include "rpc.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)
: QAbstractTableModel(parent) {
: QAbstractTableModel(parent)
{
headers << QObject::tr("Type") << QObject::tr("Address") << QObject::tr("Date/Time") << QObject::tr("Amount");
}
TxTableModel::~TxTableModel() {
TxTableModel::~TxTableModel()
{
delete modeldata;
delete tTrans;
delete zsTrans;
delete zrTrans;
}
void TxTableModel::addZSentData(const QList<TransactionItem>& data) {
void TxTableModel::addZSentData(const QList<TransactionItem> &data)
{
delete zsTrans;
zsTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*zsTrans));
@ -27,7 +32,8 @@ void TxTableModel::addZSentData(const QList<TransactionItem>& data) {
updateAllData();
}
void TxTableModel::addZRecvData(const QList<TransactionItem>& data) {
void TxTableModel::addZRecvData(const QList<TransactionItem> &data)
{
delete zrTrans;
zrTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*zrTrans));
@ -35,8 +41,8 @@ void TxTableModel::addZRecvData(const QList<TransactionItem>& data) {
updateAllData();
}
void TxTableModel::addTData(const QList<TransactionItem>& data) {
void TxTableModel::addTData(const QList<TransactionItem> &data)
{
delete tTrans;
tTrans = new QList<TransactionItem>();
std::copy(data.begin(), data.end(), std::back_inserter(*tTrans));
@ -44,7 +50,8 @@ void TxTableModel::addTData(const QList<TransactionItem>& data) {
updateAllData();
}
bool TxTableModel::exportToCsv(QString fileName) const {
bool TxTableModel::exportToCsv(QString fileName) const
{
if (!modeldata)
return false;
@ -52,18 +59,21 @@ bool TxTableModel::exportToCsv(QString fileName) const {
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate))
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
for (int i = 0; i < headers.length(); i++) {
for (int i = 0; i < headers.length(); i++)
{
out << "\"" << headers[i] << "\",";
}
out << "\"Memo\"";
out << endl;
// Write out each row
for (int row = 0; row < modeldata->length(); row++) {
for (int col = 0; col < headers.length(); col++) {
for (int row = 0; row < modeldata->length(); row++)
{
for (int col = 0; col < headers.length(); col++)
{
out << "\"" << data(index(row, col), Qt::DisplayRole).toString() << "\",";
}
// Memo
@ -75,33 +85,38 @@ bool TxTableModel::exportToCsv(QString fileName) const {
return true;
}
void TxTableModel::updateAllData() {
void TxTableModel::updateAllData()
{
auto newmodeldata = new QList<TransactionItem>();
if (tTrans != nullptr) std::copy( tTrans->begin(), tTrans->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));
if (tTrans != nullptr)
std::copy(tTrans->begin(), tTrans->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
std::sort(newmodeldata->begin(), newmodeldata->end(), [=] (auto a, auto b) {
return a.datetime > b.datetime; // reverse sort
});
std::sort(newmodeldata->begin(), newmodeldata->end(), [=](auto a, auto b)
{
return a.datetime > b.datetime; // reverse sort
});
// And then swap out the modeldata with the new one.
delete modeldata;
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();
}
QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const{
QImage TxTableModel::colorizeIcon(QIcon icon, QColor color) const
{
QImage img(icon.pixmap(16, 16).toImage());
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);
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;
}
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();
}
int TxTableModel::columnCount(const QModelIndex&) const
int TxTableModel::columnCount(const QModelIndex &) const
{
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
QString theme_name = Settings::getInstance()->get_theme_name();
QBrush b;
QColor color;
if (theme_name == "dark" || theme_name == "midnight") {
if (theme_name == "dark" || theme_name == "midnight")
{
color = COLOR_WHITE;
}else if(theme_name == "dragonx"){
}
else if (theme_name == (QString::fromStdString(HSC_default_theme)))
{
color = COLOR_DRAGONX_TEXT;
}else{
}
else
{
color = COLOR_BLACK;
}
// Align column 4 (amount) right
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::TextAlignmentRole && index.column() == 3)
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
if (role == Qt::ForegroundRole)
{
if (modeldata->at(index.row()).confirmations == 0)
{
b.setColor(COLOR_UNCONFIRMED_TX);
return b;
}
if (theme_name == "dark" || theme_name == "midnight") {
if (theme_name == "dark" || theme_name == "midnight")
{
b.setColor(color);
return b;
}else{
}
else
{
b.setColor(color);
return b;
}
return b;
return b;
}
auto dat = modeldata->at(index.row());
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0: return dat.type;
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::getDisplayFormat(modeldata->at(index.row()).amount);
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case 0:
return dat.type;
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::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(isdragonx) {
if (dat.memo.startsWith("drgx:")) {
if (isHSC)
{
std::string ticker = "" + HSC_ticker + ":";
if (dat.memo.startsWith(ticker.c_str()))
{
QIcon icon(":/icons/paymentreq.gif");
return QVariant(icon.pixmap(16, 16));
}
} else if (dat.memo.startsWith("hush:")) {
}
else if (dat.memo.startsWith("hush:"))
{
QIcon icon(":/icons/paymentreq.gif");
return QVariant(icon.pixmap(16, 16));
}
// 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));
} else {
}
else
{
// 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
if(this->getType(index.row()) == "send"){
if (this->getType(index.row()) == "send")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_output.png"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
return QVariant(icon.pixmap(16, 16));
}
// 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);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
@ -234,7 +284,8 @@ int TxTableModel::columnCount(const QModelIndex&) const
}
// Receive
if(this->getType(index.row()) == "receive"){
if (this->getType(index.row()) == "receive")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_input.png"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
@ -242,7 +293,8 @@ int TxTableModel::columnCount(const QModelIndex&) const
}
// Mined
if(this->getType(index.row()) == "generate"){
if (this->getType(index.row()) == "generate")
{
QImage image = colorizeIcon(QIcon(":/icons/tx_mined.png"), color);
QIcon icon;
icon.addPixmap(QPixmap::fromImage(image));
@ -257,54 +309,64 @@ int TxTableModel::columnCount(const QModelIndex&) const
}
return QVariant();
}
}
QVariant TxTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::TextAlignmentRole && section == 3) return QVariant(Qt::AlignRight | Qt::AlignVCenter);
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::FontRole) {
QFont f;
f.setBold(true);
return f;
}
if (role == Qt::FontRole)
{
QFont f;
f.setBold(true);
return f;
}
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
return headers.at(section);
}
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
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;
}
QString TxTableModel::getMemo(int row) const {
QString TxTableModel::getMemo(int row) const
{
return modeldata->at(row).memo;
}
qint64 TxTableModel::getConfirmations(int row) const {
qint64 TxTableModel::getConfirmations(int row) const
{
return modeldata->at(row).confirmations;
}
QString TxTableModel::getAddr(int row) const {
QString TxTableModel::getAddr(int row) const
{
return modeldata->at(row).address.trimmed();
}
QString TxTableModel::getFromAddr(int row) const {
QString TxTableModel::getFromAddr(int row) const
{
return modeldata->at(row).fromAddr.trimmed();
}
qint64 TxTableModel::getDate(int row) const {
qint64 TxTableModel::getDate(int row) const
{
return modeldata->at(row).datetime;
}
QString TxTableModel::getType(int row) const {
QString TxTableModel::getType(int row) const
{
return modeldata->at(row).type;
}
QString TxTableModel::getAmt(int row) const {
QString TxTableModel::getAmt(int row) const
{
return Settings::getDecimalString(modeldata->at(row).amount);
}

Loading…
Cancel
Save