|
|
@ -6,85 +6,99 @@ |
|
|
|
#include "controller.h" |
|
|
|
|
|
|
|
|
|
|
|
AddressBookModel::AddressBookModel(QTableView *parent) |
|
|
|
: QAbstractTableModel(parent) { |
|
|
|
AddressBookModel::AddressBookModel(QTableView *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()); |
|
|
|
QSettings().setValue( |
|
|
|
"addresstablegeometry", |
|
|
|
parent->horizontalHeader()->saveState() |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AddressBookModel::loadData() { |
|
|
|
void AddressBookModel::loadData() |
|
|
|
{ |
|
|
|
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));
|
|
|
|
AddressBook::getInstance()->addAddressLabel(label, addr); |
|
|
|
|
|
|
|
labels.clear(); |
|
|
|
labels = AddressBook::getInstance()->getAllAddressLabels(); |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
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)); |
|
|
|
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()) { |
|
|
|
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(); |
|
|
|
} |
|
|
@ -93,28 +107,27 @@ QVariant AddressBookModel::headerData(int section, Qt::Orientation orientation, |
|
|
|
//===============
|
|
|
|
// AddressBook
|
|
|
|
//===============
|
|
|
|
void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
void AddressBook::open(MainWindow* parent, QLineEdit* target) |
|
|
|
{ |
|
|
|
QDialog d(parent); |
|
|
|
Ui_addressBook ab; |
|
|
|
ab.setupUi(&d); |
|
|
|
Settings::saveRestore(&d); |
|
|
|
|
|
|
|
QRegExpValidator v(QRegExp(Settings::labelRegExp), ab.label); |
|
|
|
ab.label->setValidator(&v); |
|
|
|
|
|
|
|
AddressBookModel model(ab.addresses); |
|
|
|
ab.addresses->setModel(&model); |
|
|
|
|
|
|
|
// If there is no target, the we'll call the button "Ok", else "Pick"
|
|
|
|
if (target != nullptr) { |
|
|
|
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(); }); |
|
|
|
|
|
|
|
// 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(); |
|
|
|
} |
|
|
@ -124,26 +137,37 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
auto addr = ab.addr->text().trimmed(); |
|
|
|
QString newLabel = ab.label->text(); |
|
|
|
|
|
|
|
if (addr.isEmpty() || newLabel.isEmpty()) { |
|
|
|
QMessageBox::critical(parent, QObject::tr("Address or Label Error"), |
|
|
|
QObject::tr("Address or Label cannot be empty"), QMessageBox::Ok); |
|
|
|
if (addr.isEmpty() || newLabel.isEmpty()) |
|
|
|
{ |
|
|
|
QMessageBox::critical( |
|
|
|
parent, |
|
|
|
QObject::tr("Address or Label Error"), |
|
|
|
QObject::tr("Address or Label cannot be empty"), |
|
|
|
QMessageBox::Ok |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
// Test if address is valid.
|
|
|
|
if (!Settings::isValidAddress(addr)) { |
|
|
|
QMessageBox::critical(parent, QObject::tr("Address Format Error"), |
|
|
|
QObject::tr("%1 doesn't seem to be a valid hush address.") |
|
|
|
.arg(addr), |
|
|
|
QMessageBox::Ok); |
|
|
|
if (!Settings::isValidAddress(addr)) |
|
|
|
{ |
|
|
|
QMessageBox::critical( |
|
|
|
parent, |
|
|
|
QObject::tr("Address Format Error"), |
|
|
|
QObject::tr("%1 doesn't seem to be a valid hush address.").arg(addr), |
|
|
|
QMessageBox::Ok |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Don't allow duplicate address labels.
|
|
|
|
if (!getInstance()->getAddressForLabel(newLabel).isEmpty()) { |
|
|
|
QMessageBox::critical(parent, QObject::tr("Label Error"), |
|
|
|
QObject::tr("The label '%1' already exists. Please remove the existing label.") |
|
|
|
.arg(newLabel), |
|
|
|
QMessageBox::Ok); |
|
|
|
if (!getInstance()->getAddressForLabel(newLabel).isEmpty()) |
|
|
|
{ |
|
|
|
QMessageBox::critical( |
|
|
|
parent, |
|
|
|
QObject::tr("Label Error"), |
|
|
|
QObject::tr("The label '%1' already exists. Please remove the existing label.").arg(newLabel), |
|
|
|
QMessageBox::Ok |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
@ -153,21 +177,30 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
// Import Button
|
|
|
|
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)"); |
|
|
|
auto fileName = QFileDialog::getOpenFileUrl( |
|
|
|
&d, QObject::tr("Import Address Book"), |
|
|
|
QUrl(), |
|
|
|
"CSV file (*.csv)" |
|
|
|
); |
|
|
|
if (fileName.isEmpty()) |
|
|
|
return; |
|
|
|
|
|
|
|
QFile file(fileName.toLocalFile()); |
|
|
|
if (!file.open(QIODevice::ReadOnly)) { |
|
|
|
QMessageBox::information(&d, QObject::tr("Unable to open file"), file.errorString()); |
|
|
|
if (!file.open(QIODevice::ReadOnly)) |
|
|
|
{ |
|
|
|
QMessageBox::information( |
|
|
|
&d, |
|
|
|
QObject::tr("Unable to open file"), |
|
|
|
file.errorString() |
|
|
|
); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
QTextStream in(&file); |
|
|
|
QString line; |
|
|
|
int numImported = 0; |
|
|
|
while (in.readLineInto(&line)) { |
|
|
|
while (in.readLineInto(&line)) |
|
|
|
{ |
|
|
|
QStringList items = line.split(","); |
|
|
|
if (items.size() != 2) |
|
|
|
continue; |
|
|
@ -180,8 +213,11 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
numImported++; |
|
|
|
} |
|
|
|
|
|
|
|
QMessageBox::information(&d, QObject::tr("Address Book Import Done"), |
|
|
|
QObject::tr("Imported %1 new Address book entries").arg(numImported)); |
|
|
|
QMessageBox::information( |
|
|
|
&d, |
|
|
|
QObject::tr("Address Book Import Done"), |
|
|
|
QObject::tr("Imported %1 new Address book entries").arg(numImported) |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr) { |
|
|
@ -194,7 +230,8 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
if (!target) |
|
|
|
return; |
|
|
|
|
|
|
|
if (index.row() < 0) return; |
|
|
|
if (index.row() < 0) |
|
|
|
return; |
|
|
|
|
|
|
|
QString lbl = model.itemAt(index.row()).first; |
|
|
|
QString addr = model.itemAt(index.row()).second; |
|
|
@ -206,20 +243,19 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) { |
|
|
|
ab.addresses->setContextMenuPolicy(Qt::CustomContextMenu); |
|
|
|
QObject::connect(ab.addresses, &QTableView::customContextMenuRequested, [&] (QPoint pos) { |
|
|
|
QModelIndex index = ab.addresses->indexAt(pos); |
|
|
|
|
|
|
|
if (index.row() < 0) return; |
|
|
|
if (index.row() < 0) |
|
|
|
return; |
|
|
|
|
|
|
|
QString lbl = model.itemAt(index.row()).first; |
|
|
|
QString addr = model.itemAt(index.row()).second; |
|
|
|
|
|
|
|
QMenu menu(parent); |
|
|
|
|
|
|
|
if (target != nullptr) { |
|
|
|
if (target != nullptr) |
|
|
|
menu.addAction("Pick", [&] () { |
|
|
|
d.accept(); |
|
|
|
fnSetTargetLabelAddr(target, lbl, addr); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
menu.addAction(QObject::tr("Copy address"), [&] () { |
|
|
|
QGuiApplication::clipboard()->setText(addr); |
|
|
@ -248,27 +284,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
|
|
|
|
QString version; |
|
|
|
in >> version >> allLabels; |
|
|
|
|
|
|
|
file.close(); |
|
|
|
} |
|
|
|
|
|
|
@ -282,7 +321,8 @@ 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
|
|
|
@ -290,42 +330,44 @@ void AddressBook::writeToStorage() { |
|
|
|
file.close(); |
|
|
|
} |
|
|
|
|
|
|
|
QString AddressBook::writeableFile() { |
|
|
|
QString AddressBook::writeableFile() |
|
|
|
{ |
|
|
|
auto filename = QStringLiteral("addresslabels.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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
allLabels.push_back(QPair<QString, QString>(label, address)); |
|
|
|
writeToStorage(); |
|
|
|
} |
|
|
|
|
|
|
|
// 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; |
|
|
@ -333,10 +375,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; |
|
|
@ -345,42 +390,46 @@ 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; |
|
|
|
} |
|
|
|
|
|
|
|
return ""; |
|
|
|
} |
|
|
|
|
|
|
|
// 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; |
|
|
|
} |
|
|
|
|
|
|
|
return ""; |
|
|
|
} |
|
|
|
|
|
|
|
QString AddressBook::addLabelToAddress(QString addr) { |
|
|
|
QString AddressBook::addLabelToAddress(QString addr) |
|
|
|
{ |
|
|
|
QString label = AddressBook::getInstance()->getLabelForAddress(addr); |
|
|
|
if (!label.isEmpty()) |
|
|
|
return label + "/" + addr; |
|
|
|
|
|
|
|
else |
|
|
|
return addr; |
|
|
|
} |
|
|
|
|
|
|
|
QString AddressBook::addressFromAddressLabel(const QString& lblAddr) { |
|
|
|
QString AddressBook::addressFromAddressLabel(const QString& lblAddr) |
|
|
|
{ |
|
|
|
return lblAddr.trimmed().split("/").last(); |
|
|
|
} |
|
|
|
|
|
|
|