mirror of
https://github.com/feather-wallet/feather.git
synced 2024-11-16 17:27:38 +00:00
Receive: persistent settings, cleanup
This commit is contained in:
parent
0616384358
commit
a13ca973cc
17 changed files with 445 additions and 280 deletions
|
@ -41,6 +41,8 @@ file(GLOB SOURCE_FILES
|
||||||
"utils/os/*.cpp"
|
"utils/os/*.cpp"
|
||||||
"libwalletqt/*.h"
|
"libwalletqt/*.h"
|
||||||
"libwalletqt/*.cpp"
|
"libwalletqt/*.cpp"
|
||||||
|
"libwalletqt/rows/*.h"
|
||||||
|
"libwalletqt/rows/*.cpp"
|
||||||
"daemon/*.h"
|
"daemon/*.h"
|
||||||
"daemon/*.cpp"
|
"daemon/*.cpp"
|
||||||
"model/*.h"
|
"model/*.h"
|
||||||
|
@ -129,6 +131,7 @@ target_include_directories(feather PUBLIC
|
||||||
${CMAKE_BINARY_DIR}/src/feather_autogen/include
|
${CMAKE_BINARY_DIR}/src/feather_autogen/include
|
||||||
${CMAKE_SOURCE_DIR}/monero/include
|
${CMAKE_SOURCE_DIR}/monero/include
|
||||||
${CMAKE_SOURCE_DIR}/monero/src
|
${CMAKE_SOURCE_DIR}/monero/src
|
||||||
|
${CMAKE_SOURCE_DIR}/monero/external
|
||||||
${CMAKE_SOURCE_DIR}/monero/external/easylogging++
|
${CMAKE_SOURCE_DIR}/monero/external/easylogging++
|
||||||
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include
|
${CMAKE_SOURCE_DIR}/monero/contrib/epee/include
|
||||||
${CMAKE_SOURCE_DIR}/src
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "dialog/PaymentRequestDialog.h"
|
#include "dialog/PaymentRequestDialog.h"
|
||||||
#include "dialog/QrCodeDialog.h"
|
#include "dialog/QrCodeDialog.h"
|
||||||
|
#include "utils/config.h"
|
||||||
#include "utils/Icons.h"
|
#include "utils/Icons.h"
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ ReceiveWidget::ReceiveWidget(Wallet *wallet, QWidget *parent)
|
||||||
m_model = m_wallet->subaddressModel();
|
m_model = m_wallet->subaddressModel();
|
||||||
m_proxyModel = new SubaddressProxyModel(this, m_wallet->subaddress());
|
m_proxyModel = new SubaddressProxyModel(this, m_wallet->subaddress());
|
||||||
m_proxyModel->setSourceModel(m_model);
|
m_proxyModel->setSourceModel(m_model);
|
||||||
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
|
||||||
|
|
||||||
ui->addresses->setModel(m_proxyModel);
|
ui->addresses->setModel(m_proxyModel);
|
||||||
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
|
ui->addresses->setColumnHidden(SubaddressModel::isUsed, true);
|
||||||
|
@ -42,11 +42,32 @@ ReceiveWidget::ReceiveWidget(Wallet *wallet, QWidget *parent)
|
||||||
// header context menu
|
// header context menu
|
||||||
ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->addresses->header()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
m_headerMenu = new QMenu(this);
|
m_headerMenu = new QMenu(this);
|
||||||
m_showFullAddressesAction = m_headerMenu->addAction("Show full addresses", this, &ReceiveWidget::setShowFullAddresses);
|
auto subMenu = new QMenu(this);
|
||||||
m_showFullAddressesAction->setCheckable(true);
|
subMenu->setTitle("Columns");
|
||||||
m_showChangeAddressesAction = m_headerMenu->addAction("Show change addresses", this, &ReceiveWidget::setShowChangeAddresses);
|
|
||||||
m_showChangeAddressesAction->setCheckable(true);
|
this->addOption(m_headerMenu, "Show used addresses", Config::showUsedAddresses, [this](bool show){
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
this->addOption(m_headerMenu, "Show hidden addresses", Config::showHiddenAddresses, [this](bool show){
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
this->addOption(m_headerMenu, "Show full addresses", Config::showFullAddresses, [this](bool show){
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
this->addOption(m_headerMenu, "Show change address", Config::showChangeAddresses, [this](bool show){
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_headerMenu->addMenu(subMenu);
|
||||||
|
this->addOption(subMenu, "Show index", Config::showAddressIndex, [this](bool show){
|
||||||
|
ui->addresses->setColumnHidden(0, !show);
|
||||||
|
});
|
||||||
|
this->addOption(subMenu, "Show labels", Config::showAddressLabels, [this](bool show){
|
||||||
|
ui->addresses->setColumnHidden(2, !show);
|
||||||
|
});
|
||||||
|
|
||||||
connect(ui->addresses->header(), &QHeaderView::customContextMenuRequested, this, &ReceiveWidget::showHeaderMenu);
|
connect(ui->addresses->header(), &QHeaderView::customContextMenuRequested, this, &ReceiveWidget::showHeaderMenu);
|
||||||
|
ui->toolBtn_options->setMenu(m_headerMenu);
|
||||||
|
|
||||||
// context menu
|
// context menu
|
||||||
ui->addresses->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->addresses->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
@ -59,14 +80,23 @@ ReceiveWidget::ReceiveWidget(Wallet *wallet, QWidget *parent)
|
||||||
connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog);
|
connect(ui->qrCode, &ClickableLabel::clicked, this, &ReceiveWidget::showQrCodeDialog);
|
||||||
connect(ui->search, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter);
|
connect(ui->search, &QLineEdit::textChanged, this, &ReceiveWidget::setSearchFilter);
|
||||||
|
|
||||||
connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses);
|
|
||||||
connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses);
|
|
||||||
|
|
||||||
connect(ui->btn_createPaymentRequest, &QPushButton::clicked, this, &ReceiveWidget::createPaymentRequest);
|
connect(ui->btn_createPaymentRequest, &QPushButton::clicked, this, &ReceiveWidget::createPaymentRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReceiveWidget::addOption(QMenu *menu, const QString &text, Config::ConfigKey key, const std::function<void(bool show)>& func) {
|
||||||
|
// QMenu takes ownership of the returned QAction.
|
||||||
|
QAction *action = menu->addAction(text, func);
|
||||||
|
action->setCheckable(true);
|
||||||
|
bool toggled = conf()->get(key).toBool();
|
||||||
|
action->setChecked(toggled);
|
||||||
|
func(toggled);
|
||||||
|
connect(action, &QAction::toggled, [key](bool toggled){
|
||||||
|
conf()->set(key, toggled);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ReceiveWidget::setSearchbarVisible(bool visible) {
|
void ReceiveWidget::setSearchbarVisible(bool visible) {
|
||||||
ui->search->setVisible(visible);
|
ui->frame_search->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::focusSearchbar() {
|
void ReceiveWidget::focusSearchbar() {
|
||||||
|
@ -91,28 +121,40 @@ void ReceiveWidget::editLabel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::showContextMenu(const QPoint &point) {
|
void ReceiveWidget::showContextMenu(const QPoint &point) {
|
||||||
Monero::SubaddressRow* row = this->currentEntry();
|
SubaddressRow* row = this->currentEntry();
|
||||||
if (!row) return;
|
if (!row) return;
|
||||||
|
|
||||||
QString address = QString::fromStdString(row->getAddress());
|
|
||||||
bool isUsed = row->isUsed();
|
|
||||||
|
|
||||||
auto *menu = new QMenu(ui->addresses);
|
auto *menu = new QMenu(ui->addresses);
|
||||||
|
|
||||||
menu->addAction("Copy address", this, &ReceiveWidget::copyAddress);
|
menu->addAction("Copy address", this, &ReceiveWidget::copyAddress);
|
||||||
menu->addAction("Copy label", this, &ReceiveWidget::copyLabel);
|
menu->addAction("Copy label", this, &ReceiveWidget::copyLabel);
|
||||||
menu->addAction("Edit label", this, &ReceiveWidget::editLabel);
|
menu->addAction("Edit label", this, &ReceiveWidget::editLabel);
|
||||||
|
|
||||||
if (isUsed) {
|
if (row->isUsed()) {
|
||||||
menu->addAction(m_showTransactionsAction);
|
menu->addAction(m_showTransactionsAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList hiddenAddresses = this->getHiddenAddresses();
|
QAction *actionPin = menu->addAction("Pin address", [this](bool toggled){
|
||||||
if (hiddenAddresses.contains(address)) {
|
SubaddressRow* row = this->currentEntry();
|
||||||
menu->addAction("Unhide address", this, &ReceiveWidget::showAddress);
|
if (!row) return;
|
||||||
} else {
|
|
||||||
menu->addAction("Hide address", this, &ReceiveWidget::hideAddress);
|
QString address = row->getAddress();
|
||||||
}
|
m_wallet->subaddress()->setPinned(address, toggled);
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
actionPin->setCheckable(true);
|
||||||
|
actionPin->setChecked(row->isPinned());
|
||||||
|
|
||||||
|
QAction *actionHide = menu->addAction("Hide address", [this](bool toggled){
|
||||||
|
SubaddressRow* row = this->currentEntry();
|
||||||
|
if (!row) return;
|
||||||
|
|
||||||
|
QString address = row->getAddress();
|
||||||
|
m_wallet->subaddress()->setHidden(address, toggled);
|
||||||
|
m_proxyModel->invalidate();
|
||||||
|
});
|
||||||
|
actionHide->setCheckable(true);
|
||||||
|
actionHide->setChecked(row->isHidden());
|
||||||
|
|
||||||
if (m_wallet->isHwBacked()) {
|
if (m_wallet->isHwBacked()) {
|
||||||
menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice);
|
menu->addAction("Show on device", this, &ReceiveWidget::showOnDevice);
|
||||||
|
@ -143,66 +185,26 @@ void ReceiveWidget::onShowTransactions() {
|
||||||
emit showTransactions(address);
|
emit showTransactions(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::setShowChangeAddresses(bool show) {
|
|
||||||
if (!m_proxyModel) return;
|
|
||||||
m_proxyModel->setShowChangeAddresses(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::setShowFullAddresses(bool show) {
|
|
||||||
if (!m_model) return;
|
|
||||||
m_model->setShowFullAddresses(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::setShowUsedAddresses(bool show) {
|
|
||||||
if (!m_proxyModel) return;
|
|
||||||
m_proxyModel->setShowUsed(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::setShowHiddenAddresses(bool show) {
|
|
||||||
if (!m_proxyModel) return;
|
|
||||||
m_proxyModel->setShowHidden(show);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::setSearchFilter(const QString &filter) {
|
void ReceiveWidget::setSearchFilter(const QString &filter) {
|
||||||
if (!m_proxyModel) return;
|
|
||||||
m_proxyModel->setSearchFilter(filter);
|
m_proxyModel->setSearchFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::showHeaderMenu(const QPoint& position)
|
void ReceiveWidget::showHeaderMenu(const QPoint& position)
|
||||||
{
|
{
|
||||||
Q_UNUSED(position);
|
Q_UNUSED(position)
|
||||||
m_showFullAddressesAction->setChecked(m_model->isShowFullAddresses());
|
|
||||||
m_headerMenu->exec(QCursor::pos());
|
m_headerMenu->exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::hideAddress()
|
|
||||||
{
|
|
||||||
Monero::SubaddressRow* row = this->currentEntry();
|
|
||||||
if (!row) return;
|
|
||||||
QString address = QString::fromStdString(row->getAddress());
|
|
||||||
this->addHiddenAddress(address);
|
|
||||||
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::showAddress()
|
|
||||||
{
|
|
||||||
Monero::SubaddressRow* row = this->currentEntry();
|
|
||||||
if (!row) return;
|
|
||||||
QString address = QString::fromStdString(row->getAddress());
|
|
||||||
this->removeHiddenAddress(address);
|
|
||||||
m_proxyModel->setHiddenAddresses(this->getHiddenAddresses());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::showOnDevice() {
|
void ReceiveWidget::showOnDevice() {
|
||||||
Monero::SubaddressRow* row = this->currentEntry();
|
SubaddressRow* row = this->currentEntry();
|
||||||
if (!row) return;
|
if (!row) return;
|
||||||
m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRowId(), "");
|
m_wallet->deviceShowAddressAsync(m_wallet->currentSubaddressAccount(), row->getRow(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveWidget::generateSubaddress() {
|
void ReceiveWidget::generateSubaddress() {
|
||||||
bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
|
bool r = m_wallet->subaddress()->addRow(m_wallet->currentSubaddressAccount(), "");
|
||||||
if (!r) {
|
if (!r) {
|
||||||
Utils::showError(this, "Failed to generate subaddress", m_wallet->subaddress()->errorString());
|
Utils::showError(this, "Failed to generate subaddress", m_wallet->subaddress()->getError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,28 +237,7 @@ void ReceiveWidget::showQrCodeDialog() {
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ReceiveWidget::getHiddenAddresses() {
|
SubaddressRow* ReceiveWidget::currentEntry() {
|
||||||
QString data = m_wallet->getCacheAttribute("feather.hiddenaddresses");
|
|
||||||
return data.split(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::addHiddenAddress(const QString& address) {
|
|
||||||
QStringList hiddenAddresses = this->getHiddenAddresses();
|
|
||||||
if (!hiddenAddresses.contains(address)) {
|
|
||||||
hiddenAddresses.append(address);
|
|
||||||
}
|
|
||||||
QString data = hiddenAddresses.join(",");
|
|
||||||
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveWidget::removeHiddenAddress(const QString &address) {
|
|
||||||
QStringList hiddenAddresses = this->getHiddenAddresses();
|
|
||||||
hiddenAddresses.removeAll(address);
|
|
||||||
QString data = hiddenAddresses.join(",");
|
|
||||||
m_wallet->setCacheAttribute("feather.hiddenaddresses", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Monero::SubaddressRow* ReceiveWidget::currentEntry() {
|
|
||||||
QModelIndexList list = ui->addresses->selectionModel()->selectedRows();
|
QModelIndexList list = ui->addresses->selectionModel()->selectedRows();
|
||||||
if (list.size() == 1) {
|
if (list.size() == 1) {
|
||||||
return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first()));
|
return m_model->entryFromIndex(m_proxyModel->mapToSource(list.first()));
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "model/SubaddressProxyModel.h"
|
#include "model/SubaddressProxyModel.h"
|
||||||
#include "model/SubaddressModel.h"
|
#include "model/SubaddressModel.h"
|
||||||
#include "qrcode/QrCode.h"
|
#include "qrcode/QrCode.h"
|
||||||
|
#include "utils/config.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ReceiveWidget;
|
class ReceiveWidget;
|
||||||
|
@ -34,10 +35,6 @@ public slots:
|
||||||
void copyLabel();
|
void copyLabel();
|
||||||
void editLabel();
|
void editLabel();
|
||||||
void showContextMenu(const QPoint& point);
|
void showContextMenu(const QPoint& point);
|
||||||
void setShowFullAddresses(bool show);
|
|
||||||
void setShowChangeAddresses(bool show);
|
|
||||||
void setShowUsedAddresses(bool show);
|
|
||||||
void setShowHiddenAddresses(bool show);
|
|
||||||
void setSearchFilter(const QString &filter);
|
void setSearchFilter(const QString &filter);
|
||||||
void onShowTransactions();
|
void onShowTransactions();
|
||||||
void createPaymentRequest();
|
void createPaymentRequest();
|
||||||
|
@ -47,8 +44,6 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showHeaderMenu(const QPoint& position);
|
void showHeaderMenu(const QPoint& position);
|
||||||
void hideAddress();
|
|
||||||
void showAddress();
|
|
||||||
void showOnDevice();
|
void showOnDevice();
|
||||||
void generateSubaddress();
|
void generateSubaddress();
|
||||||
|
|
||||||
|
@ -56,18 +51,14 @@ private:
|
||||||
QScopedPointer<Ui::ReceiveWidget> ui;
|
QScopedPointer<Ui::ReceiveWidget> ui;
|
||||||
Wallet *m_wallet;
|
Wallet *m_wallet;
|
||||||
QMenu *m_headerMenu;
|
QMenu *m_headerMenu;
|
||||||
QAction *m_showFullAddressesAction;
|
|
||||||
QAction *m_showTransactionsAction;
|
QAction *m_showTransactionsAction;
|
||||||
QAction *m_showChangeAddressesAction;
|
|
||||||
SubaddressModel *m_model;
|
SubaddressModel *m_model;
|
||||||
SubaddressProxyModel *m_proxyModel;
|
SubaddressProxyModel *m_proxyModel;
|
||||||
|
|
||||||
|
void addOption(QMenu *menu, const QString &text, Config::ConfigKey key, const std::function<void(bool show)>& func);
|
||||||
void updateQrCode();
|
void updateQrCode();
|
||||||
void showQrCodeDialog();
|
void showQrCodeDialog();
|
||||||
QStringList getHiddenAddresses();
|
SubaddressRow* currentEntry();
|
||||||
void addHiddenAddress(const QString& address);
|
|
||||||
void removeHiddenAddress(const QString& address);
|
|
||||||
Monero::SubaddressRow* currentEntry();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FEATHER_RECEIVEWIDGET_H
|
#endif //FEATHER_RECEIVEWIDGET_H
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>878</width>
|
<width>878</width>
|
||||||
<height>512</height>
|
<height>403</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -27,16 +27,54 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="search">
|
<widget class="QFrame" name="frame_search">
|
||||||
<property name="enabled">
|
<property name="frameShape">
|
||||||
<bool>true</bool>
|
<enum>QFrame::NoFrame</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="frameShadow">
|
||||||
<string/>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Search...</string>
|
|
||||||
</property>
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="search">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="toolBtn_options">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="assets.qrc">
|
||||||
|
<normaloff>:/assets/images/preferences.svg</normaloff>:/assets/images/preferences.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="popupMode">
|
||||||
|
<enum>QToolButton::InstantPopup</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -89,27 +127,6 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="check_showUsed">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show used</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="check_showHidden">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show hidden</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btn_generateSubaddress">
|
<widget class="QPushButton" name="btn_generateSubaddress">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -135,6 +152,8 @@
|
||||||
<header>model/SubaddressView.h</header>
|
<header>model/SubaddressView.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources>
|
||||||
|
<include location="assets.qrc"/>
|
||||||
|
</resources>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
<file>assets/images/password-show-off.svg</file>
|
<file>assets/images/password-show-off.svg</file>
|
||||||
<file>assets/images/password-show-on.svg</file>
|
<file>assets/images/password-show-on.svg</file>
|
||||||
<file>assets/images/person.svg</file>
|
<file>assets/images/person.svg</file>
|
||||||
|
<file>assets/images/pin.png</file>
|
||||||
<file>assets/images/preferences.svg</file>
|
<file>assets/images/preferences.svg</file>
|
||||||
<file>assets/images/qrcode.png</file>
|
<file>assets/images/qrcode.png</file>
|
||||||
<file>assets/images/qrcode_white.png</file>
|
<file>assets/images/qrcode_white.png</file>
|
||||||
|
|
BIN
src/assets/images/pin.png
Normal file
BIN
src/assets/images/pin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
|
@ -4,46 +4,20 @@
|
||||||
#include "Subaddress.h"
|
#include "Subaddress.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
Subaddress::Subaddress(Monero::Subaddress *subaddressImpl, QObject *parent)
|
Subaddress::Subaddress(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_subaddressImpl(subaddressImpl)
|
, m_wallet(wallet)
|
||||||
, m_unusedLookahead(0)
|
, m_wallet2(wallet2)
|
||||||
{
|
{
|
||||||
getAll();
|
QString pinned = m_wallet->getCacheAttribute("feather.pinnedaddresses");
|
||||||
|
m_pinned = pinned.split(",");
|
||||||
|
|
||||||
|
QString hidden = m_wallet->getCacheAttribute("feather.hiddenaddresses");
|
||||||
|
m_hidden = hidden.split(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Subaddress::errorString() const
|
bool Subaddress::getRow(int index, std::function<void (SubaddressRow &row)> callback) const
|
||||||
{
|
{
|
||||||
return QString::fromStdString(m_subaddressImpl->errorString());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Subaddress::getAll() const
|
|
||||||
{
|
|
||||||
emit refreshStarted();
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker locker(&m_lock);
|
|
||||||
|
|
||||||
m_unusedLookahead = 0;
|
|
||||||
|
|
||||||
m_rows.clear();
|
|
||||||
for (auto &row: m_subaddressImpl->getAll()) {
|
|
||||||
m_rows.append(row);
|
|
||||||
|
|
||||||
if (row->isUsed())
|
|
||||||
m_unusedLookahead = 0;
|
|
||||||
else
|
|
||||||
m_unusedLookahead += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit refreshFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Subaddress::getRow(int index, std::function<void (Monero::SubaddressRow &row)> callback) const
|
|
||||||
{
|
|
||||||
QReadLocker locker(&m_lock);
|
|
||||||
|
|
||||||
if (index < 0 || index >= m_rows.size())
|
if (index < 0 || index >= m_rows.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -53,48 +27,140 @@ bool Subaddress::getRow(int index, std::function<void (Monero::SubaddressRow &ro
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Subaddress::addRow(quint32 accountIndex, const QString &label) const
|
bool Subaddress::addRow(quint32 accountIndex, const QString &label)
|
||||||
{
|
{
|
||||||
bool r = m_subaddressImpl->addRow(accountIndex, label.toStdString());
|
// This can fail if hardware device is unplugged during operating, catch here to prevent crash
|
||||||
|
// Todo: Notify GUI that it was a device error
|
||||||
if (r)
|
try
|
||||||
getAll();
|
{
|
||||||
|
m_wallet2->add_subaddress(accountIndex, label.toStdString());
|
||||||
return r;
|
refresh(accountIndex);
|
||||||
}
|
|
||||||
|
|
||||||
bool Subaddress::setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) const
|
|
||||||
{
|
|
||||||
bool r = m_subaddressImpl->setLabel(accountIndex, addressIndex, label.toStdString());
|
|
||||||
if (r) {
|
|
||||||
getAll();
|
|
||||||
emit labelChanged();
|
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
if (m_wallet2->key_on_device()) {
|
||||||
|
}
|
||||||
|
m_errorString = QString::fromStdString(e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Subaddress::setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
m_wallet2->set_subaddress_label({accountIndex, addressIndex}, label.toStdString());
|
||||||
|
refresh(accountIndex);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Subaddress::setHidden(const QString &address, bool hidden)
|
||||||
|
{
|
||||||
|
if (hidden) {
|
||||||
|
if (m_hidden.contains(address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_hidden.append(address);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!m_hidden.contains(address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_hidden.removeAll(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r = m_wallet->setCacheAttribute("feather.hiddenaddresses", m_hidden.join(","));
|
||||||
|
|
||||||
|
refresh(m_wallet->currentSubaddressAccount());
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Subaddress::refresh(quint32 accountIndex) const
|
bool Subaddress::isHidden(const QString &address)
|
||||||
{
|
{
|
||||||
bool r = m_subaddressImpl->refresh(accountIndex);
|
return m_hidden.contains(address);
|
||||||
getAll();
|
};
|
||||||
|
|
||||||
|
bool Subaddress::setPinned(const QString &address, bool pinned)
|
||||||
|
{
|
||||||
|
if (pinned) {
|
||||||
|
if (m_pinned.contains(address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_pinned.append(address);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!m_pinned.contains(address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_pinned.removeAll(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool r = m_wallet->setCacheAttribute("feather.pinnedaddresses", m_pinned.join(","));
|
||||||
|
|
||||||
|
refresh(m_wallet->currentSubaddressAccount());
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 Subaddress::unusedLookahead() const
|
bool Subaddress::isPinned(const QString &address)
|
||||||
{
|
{
|
||||||
QReadLocker locker(&m_lock);
|
return m_pinned.contains(address);
|
||||||
|
|
||||||
return m_unusedLookahead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 Subaddress::count() const
|
bool Subaddress::refresh(quint32 accountIndex)
|
||||||
{
|
{
|
||||||
QReadLocker locker(&m_lock);
|
emit refreshStarted();
|
||||||
|
|
||||||
|
this->clearRows();
|
||||||
|
for (qsizetype i = 0; i < m_wallet2->get_num_subaddresses(accountIndex); ++i)
|
||||||
|
{
|
||||||
|
QString address = QString::fromStdString(m_wallet2->get_subaddress_as_str({accountIndex, (uint32_t)i}));
|
||||||
|
|
||||||
|
auto* row = new SubaddressRow{this,
|
||||||
|
i,
|
||||||
|
address,
|
||||||
|
QString::fromStdString(m_wallet2->get_subaddress_label({accountIndex, (uint32_t)i})),
|
||||||
|
m_wallet2->get_subaddress_used({accountIndex, (uint32_t)i}),
|
||||||
|
this->isHidden(address),
|
||||||
|
this->isPinned(address)
|
||||||
|
};
|
||||||
|
|
||||||
|
m_rows.append(row);
|
||||||
|
}
|
||||||
|
|
||||||
return m_rows.size();
|
// Make sure keys are intact. We NEVER want to display incorrect addresses in case of memory corruption.
|
||||||
|
bool keysCorrupt = m_wallet2->get_device_type() == hw::device::SOFTWARE && !m_wallet2->verify_keys();
|
||||||
|
|
||||||
|
if (keysCorrupt) {
|
||||||
|
clearRows();
|
||||||
|
LOG_ERROR("KEY INCONSISTENCY DETECTED, WALLET IS IN CORRUPT STATE.");
|
||||||
|
}
|
||||||
|
|
||||||
|
emit refreshFinished();
|
||||||
|
|
||||||
|
return !keysCorrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Monero::SubaddressRow* Subaddress::row(int index) const
|
qsizetype Subaddress::count() const
|
||||||
{
|
{
|
||||||
|
return m_rows.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subaddress::clearRows() {
|
||||||
|
qDeleteAll(m_rows);
|
||||||
|
m_rows.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
SubaddressRow* Subaddress::row(int index) const {
|
||||||
return m_rows.value(index);
|
return m_rows.value(index);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
QString Subaddress::getError() const {
|
||||||
|
return m_errorString;
|
||||||
|
};
|
|
@ -12,34 +12,52 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include <wallet/wallet2.h>
|
||||||
|
|
||||||
|
#include "Wallet.h"
|
||||||
|
#include "rows/SubaddressRow.h"
|
||||||
|
|
||||||
class Subaddress : public QObject
|
class Subaddress : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void getAll() const;
|
bool getRow(int index, std::function<void (SubaddressRow &row)> callback) const;
|
||||||
bool getRow(int index, std::function<void (Monero::SubaddressRow &row)> callback) const;
|
bool addRow(quint32 accountIndex, const QString &label);
|
||||||
bool addRow(quint32 accountIndex, const QString &label) const;
|
|
||||||
bool setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label) const;
|
bool setLabel(quint32 accountIndex, quint32 addressIndex, const QString &label);
|
||||||
bool refresh(quint32 accountIndex) const;
|
|
||||||
quint64 unusedLookahead() const;
|
bool setHidden(const QString& address, bool hidden);
|
||||||
quint64 count() const;
|
bool isHidden(const QString& address);
|
||||||
QString errorString() const;
|
|
||||||
Monero::SubaddressRow* row(int index) const;
|
bool setPinned(const QString& address, bool pinned);
|
||||||
|
bool isPinned(const QString& address);
|
||||||
|
|
||||||
|
bool refresh(quint32 accountIndex);
|
||||||
|
|
||||||
|
[[nodiscard]] qsizetype count() const;
|
||||||
|
void clearRows();
|
||||||
|
|
||||||
|
[[nodiscard]] SubaddressRow* row(int index) const;
|
||||||
|
|
||||||
|
QString getError() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void refreshStarted() const;
|
void refreshStarted() const;
|
||||||
void refreshFinished() const;
|
void refreshFinished() const;
|
||||||
void labelChanged() const;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Subaddress(Monero::Subaddress * subaddressImpl, QObject *parent);
|
explicit Subaddress(Wallet *wallet, tools::wallet2 *wallet2, QObject *parent);
|
||||||
friend class Wallet;
|
friend class Wallet;
|
||||||
mutable QReadWriteLock m_lock;
|
|
||||||
Monero::Subaddress * m_subaddressImpl;
|
Wallet* m_wallet;
|
||||||
mutable QList<Monero::SubaddressRow*> m_rows;
|
tools::wallet2 *m_wallet2;
|
||||||
mutable quint64 m_unusedLookahead;
|
QList<SubaddressRow*> m_rows;
|
||||||
|
|
||||||
|
QStringList m_pinned;
|
||||||
|
QStringList m_hidden;
|
||||||
|
|
||||||
|
QString m_errorString;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SUBADDRESS_H
|
#endif // SUBADDRESS_H
|
||||||
|
|
|
@ -40,7 +40,7 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
|
||||||
, m_daemonBlockChainTargetHeight(0)
|
, m_daemonBlockChainTargetHeight(0)
|
||||||
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
, m_connectionStatus(Wallet::ConnectionStatus_Disconnected)
|
||||||
, m_currentSubaddressAccount(0)
|
, m_currentSubaddressAccount(0)
|
||||||
, m_subaddress(new Subaddress(m_walletImpl->subaddress(), this))
|
, m_subaddress(new Subaddress(this, wallet->getWallet(), this))
|
||||||
, m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
|
, m_subaddressAccount(new SubaddressAccount(m_walletImpl->subaddressAccount(), this))
|
||||||
, m_refreshNow(false)
|
, m_refreshNow(false)
|
||||||
, m_refreshEnabled(false)
|
, m_refreshEnabled(false)
|
||||||
|
|
40
src/libwalletqt/rows/SubaddressRow.cpp
Normal file
40
src/libwalletqt/rows/SubaddressRow.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||||
|
|
||||||
|
#include "SubaddressRow.h"
|
||||||
|
|
||||||
|
bool SubaddressRow::setHidden(bool hidden) {
|
||||||
|
m_hidden = hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubaddressRow::setUsed(bool used) {
|
||||||
|
m_used = used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubaddressRow::setPinned(bool pinned) {
|
||||||
|
m_used = pinned;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsizetype SubaddressRow::getRow() const {
|
||||||
|
return m_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& SubaddressRow::getAddress() const {
|
||||||
|
return m_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& SubaddressRow::getLabel() const {
|
||||||
|
return m_label;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubaddressRow::isUsed() const {
|
||||||
|
return m_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubaddressRow::isPinned() const {
|
||||||
|
return m_pinned;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubaddressRow::isHidden() const {
|
||||||
|
return m_hidden;
|
||||||
|
}
|
44
src/libwalletqt/rows/SubaddressRow.h
Normal file
44
src/libwalletqt/rows/SubaddressRow.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||||
|
|
||||||
|
#ifndef FEATHER_SUBADDRESSROW_H
|
||||||
|
#define FEATHER_SUBADDRESSROW_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class SubaddressRow : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SubaddressRow(QObject *parent, qsizetype row, const QString& address, const QString &label, bool used, bool hidden, bool pinned)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_row(row)
|
||||||
|
, m_address(address)
|
||||||
|
, m_label(label)
|
||||||
|
, m_used(used)
|
||||||
|
, m_hidden(hidden)
|
||||||
|
, m_pinned(pinned) {}
|
||||||
|
|
||||||
|
bool setUsed(bool used);
|
||||||
|
bool setHidden(bool hidden);
|
||||||
|
bool setPinned(bool pinned);
|
||||||
|
|
||||||
|
qsizetype getRow() const;
|
||||||
|
const QString& getAddress() const;
|
||||||
|
const QString& getLabel() const;
|
||||||
|
bool isUsed() const;
|
||||||
|
bool isHidden() const;
|
||||||
|
bool isPinned() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
qsizetype m_row;
|
||||||
|
QString m_address;
|
||||||
|
QString m_label;
|
||||||
|
bool m_used = false;
|
||||||
|
bool m_hidden = false;
|
||||||
|
bool m_pinned = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FEATHER_SUBADDRESSROW_H
|
|
@ -8,13 +8,14 @@
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
|
|
||||||
|
#include "utils/config.h"
|
||||||
#include "utils/ColorScheme.h"
|
#include "utils/ColorScheme.h"
|
||||||
|
#include "utils/Icons.h"
|
||||||
#include "utils/Utils.h"
|
#include "utils/Utils.h"
|
||||||
|
|
||||||
SubaddressModel::SubaddressModel(QObject *parent, Subaddress *subaddress)
|
SubaddressModel::SubaddressModel(QObject *parent, Subaddress *subaddress)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractTableModel(parent)
|
||||||
, m_subaddress(subaddress)
|
, m_subaddress(subaddress)
|
||||||
, m_showFullAddresses(false)
|
|
||||||
{
|
{
|
||||||
connect(m_subaddress, &Subaddress::refreshStarted, this, &SubaddressModel::startReset);
|
connect(m_subaddress, &Subaddress::refreshStarted, this, &SubaddressModel::startReset);
|
||||||
connect(m_subaddress, &Subaddress::refreshFinished, this, &SubaddressModel::endReset);
|
connect(m_subaddress, &Subaddress::refreshFinished, this, &SubaddressModel::endReset);
|
||||||
|
@ -51,11 +52,20 @@ QVariant SubaddressModel::data(const QModelIndex &index, int role) const
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
QVariant result;
|
QVariant result;
|
||||||
|
|
||||||
bool found = m_subaddress->getRow(index.row(), [this, &index, &role, &result](const Monero::SubaddressRow &subaddress) {
|
bool found = m_subaddress->getRow(index.row(), [this, &index, &role, &result](const SubaddressRow &subaddress) {
|
||||||
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole){
|
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole){
|
||||||
result = parseSubaddressRow(subaddress, index, role);
|
result = parseSubaddressRow(subaddress, index, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (role == Qt::DecorationRole) {
|
||||||
|
if (subaddress.isPinned() && index.column() == ModelColumn::Index) {
|
||||||
|
result = QVariant(icons()->icon("pin.png"));
|
||||||
|
}
|
||||||
|
else if (subaddress.isHidden() && index.column() == ModelColumn::Index) {
|
||||||
|
result = QVariant(icons()->icon("eye_blind.png"));
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (role == Qt::BackgroundRole) {
|
else if (role == Qt::BackgroundRole) {
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case Address:
|
case Address:
|
||||||
|
@ -94,17 +104,25 @@ QVariant SubaddressModel::data(const QModelIndex &index, int role) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant SubaddressModel::parseSubaddressRow(const Monero::SubaddressRow &subaddress, const QModelIndex &index, int role) const
|
QVariant SubaddressModel::parseSubaddressRow(const SubaddressRow &subaddress, const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
|
bool showFull = conf()->get(Config::showFullAddresses).toBool();
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Index:
|
case Index:
|
||||||
{
|
{
|
||||||
return "#" + QString::number(subaddress.getRowId()) + " ";
|
if (role == Qt::UserRole) {
|
||||||
|
if (subaddress.isPinned()) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return subaddress.getRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "#" + QString::number(subaddress.getRow()) + " ";
|
||||||
}
|
}
|
||||||
case Address:
|
case Address:
|
||||||
{
|
{
|
||||||
QString address = QString::fromStdString(subaddress.getAddress());
|
QString address = subaddress.getAddress();
|
||||||
if (!m_showFullAddresses && role != Qt::UserRole) {
|
if (!showFull && role != Qt::UserRole) {
|
||||||
address = Utils::displayAddress(address);
|
address = Utils::displayAddress(address);
|
||||||
}
|
}
|
||||||
return address;
|
return address;
|
||||||
|
@ -117,7 +135,7 @@ QVariant SubaddressModel::parseSubaddressRow(const Monero::SubaddressRow &subadd
|
||||||
else if (index.row() == 0) {
|
else if (index.row() == 0) {
|
||||||
return "Change";
|
return "Change";
|
||||||
}
|
}
|
||||||
return QString::fromStdString(subaddress.getLabel());
|
return subaddress.getLabel();
|
||||||
}
|
}
|
||||||
case isUsed:
|
case isUsed:
|
||||||
return subaddress.isUsed();
|
return subaddress.isUsed();
|
||||||
|
@ -170,12 +188,6 @@ bool SubaddressModel::setData(const QModelIndex &index, const QVariant &value, i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubaddressModel::setShowFullAddresses(bool show)
|
|
||||||
{
|
|
||||||
m_showFullAddresses = show;
|
|
||||||
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags SubaddressModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags SubaddressModel::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
|
@ -187,19 +199,11 @@ Qt::ItemFlags SubaddressModel::flags(const QModelIndex &index) const
|
||||||
return QAbstractTableModel::flags(index);
|
return QAbstractTableModel::flags(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubaddressModel::isShowFullAddresses() const {
|
|
||||||
return m_showFullAddresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SubaddressModel::unusedLookahead() const {
|
|
||||||
return m_subaddress->unusedLookahead();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubaddressModel::setCurrentSubaddressAccount(quint32 accountIndex) {
|
void SubaddressModel::setCurrentSubaddressAccount(quint32 accountIndex) {
|
||||||
m_currentSubaddressAccount = accountIndex;
|
m_currentSubaddressAccount = accountIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Monero::SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const {
|
SubaddressRow* SubaddressModel::entryFromIndex(const QModelIndex &index) const {
|
||||||
Q_ASSERT(index.isValid() && index.row() < m_subaddress->count());
|
Q_ASSERT(index.isValid() && index.row() < m_subaddress->count());
|
||||||
return m_subaddress->row(index.row());
|
return m_subaddress->row(index.row());
|
||||||
}
|
}
|
|
@ -10,6 +10,8 @@
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "rows/SubaddressRow.h"
|
||||||
|
|
||||||
class Subaddress;
|
class Subaddress;
|
||||||
|
|
||||||
class SubaddressModel : public QAbstractTableModel
|
class SubaddressModel : public QAbstractTableModel
|
||||||
|
@ -36,13 +38,9 @@ public:
|
||||||
|
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||||
|
|
||||||
bool isShowFullAddresses() const;
|
SubaddressRow* entryFromIndex(const QModelIndex &index) const;
|
||||||
void setShowFullAddresses(bool show);
|
|
||||||
|
|
||||||
Monero::SubaddressRow* entryFromIndex(const QModelIndex &index) const;
|
|
||||||
|
|
||||||
void setCurrentSubaddressAccount(quint32 accountIndex);
|
void setCurrentSubaddressAccount(quint32 accountIndex);
|
||||||
int unusedLookahead() const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void startReset();
|
void startReset();
|
||||||
|
@ -50,9 +48,8 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Subaddress *m_subaddress;
|
Subaddress *m_subaddress;
|
||||||
QVariant parseSubaddressRow(const Monero::SubaddressRow &subaddress, const QModelIndex &index, int role) const;
|
QVariant parseSubaddressRow(const SubaddressRow &subaddress, const QModelIndex &index, int role) const;
|
||||||
|
|
||||||
bool m_showFullAddresses;
|
|
||||||
quint32 m_currentSubaddressAccount;
|
quint32 m_currentSubaddressAccount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,37 +3,47 @@
|
||||||
|
|
||||||
#include "SubaddressProxyModel.h"
|
#include "SubaddressProxyModel.h"
|
||||||
|
|
||||||
SubaddressProxyModel::SubaddressProxyModel(QObject *parent, Subaddress *subaddress, bool showChange)
|
#include "utils/config.h"
|
||||||
|
|
||||||
|
SubaddressProxyModel::SubaddressProxyModel(QObject *parent, Subaddress *subaddress)
|
||||||
: QSortFilterProxyModel(parent)
|
: QSortFilterProxyModel(parent)
|
||||||
, m_subaddress(subaddress)
|
, m_subaddress(subaddress)
|
||||||
, m_searchRegExp("")
|
, m_searchRegExp("")
|
||||||
, m_searchCaseSensitiveRegExp("")
|
, m_searchCaseSensitiveRegExp("")
|
||||||
, m_showChange(showChange)
|
|
||||||
{
|
{
|
||||||
m_searchRegExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
m_searchRegExp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
|
||||||
|
this->setSortRole(Qt::UserRole);
|
||||||
|
this->sort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
bool SubaddressProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
{
|
{
|
||||||
QString address, label;
|
bool showUsed = conf()->get(Config::showUsedAddresses).toBool();
|
||||||
bool isUsed;
|
bool showHidden = conf()->get(Config::showHiddenAddresses).toBool();
|
||||||
m_subaddress->getRow(sourceRow, [&isUsed, &address, &label](const Monero::SubaddressRow &subaddress){
|
bool showChange = conf()->get(Config::showChangeAddresses).toBool();
|
||||||
isUsed = subaddress.isUsed();
|
|
||||||
address = QString::fromStdString(subaddress.getAddress());
|
|
||||||
label = QString::fromStdString(subaddress.getLabel());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
SubaddressRow* subaddress = m_subaddress->row(sourceRow);
|
||||||
|
if (!subaddress) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pinned addresses are always shown
|
||||||
|
if (subaddress->isPinned()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide primary/change addresses
|
// Hide primary/change addresses
|
||||||
if (!m_showChange && sourceRow == 0) {
|
if (!showChange && sourceRow == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_showHidden && m_hiddenAddresses.contains(address)) {
|
if (!showHidden && subaddress->isHidden()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_searchRegExp.pattern().isEmpty()) {
|
if (!m_searchRegExp.pattern().isEmpty()) {
|
||||||
return address.contains(m_searchCaseSensitiveRegExp) || label.contains(m_searchRegExp);
|
return subaddress->getAddress().contains(m_searchCaseSensitiveRegExp) || subaddress->getLabel().contains(m_searchRegExp);
|
||||||
}
|
}
|
||||||
return (m_showUsed || !isUsed);
|
|
||||||
|
return (showUsed || !subaddress->isUsed());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@
|
||||||
class SubaddressProxyModel : public QSortFilterProxyModel
|
class SubaddressProxyModel : public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SubaddressProxyModel(QObject* parent, Subaddress *subaddress, bool hidePrimary = false);
|
explicit SubaddressProxyModel(QObject* parent, Subaddress *subaddress);
|
||||||
bool filterAcceptsRow(int sourceRow,
|
[[nodiscard]] bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||||
const QModelIndex &sourceParent) const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setSearchFilter(const QString& searchString){
|
void setSearchFilter(const QString& searchString){
|
||||||
|
@ -23,35 +23,10 @@ public slots:
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setShowUsed(const bool showUsed){
|
|
||||||
m_showUsed = showUsed;
|
|
||||||
invalidateFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setShowHidden(const bool showHidden){
|
|
||||||
m_showHidden = showHidden;
|
|
||||||
invalidateFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setHiddenAddresses(const QStringList& hiddenAddresses) {
|
|
||||||
m_hiddenAddresses = hiddenAddresses;
|
|
||||||
invalidateFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setShowChangeAddresses(const bool showChange) {
|
|
||||||
m_showChange = showChange;
|
|
||||||
invalidateFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Subaddress *m_subaddress;
|
Subaddress *m_subaddress;
|
||||||
|
|
||||||
QStringList m_hiddenAddresses;
|
|
||||||
QRegularExpression m_searchRegExp;
|
QRegularExpression m_searchRegExp;
|
||||||
QRegularExpression m_searchCaseSensitiveRegExp;
|
QRegularExpression m_searchCaseSensitiveRegExp;
|
||||||
bool m_showUsed = false;
|
|
||||||
bool m_showHidden = false;
|
|
||||||
bool m_showChange = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //FEATHER_SUBADDRESSPROXYMODEL_H
|
#endif //FEATHER_SUBADDRESSPROXYMODEL_H
|
||||||
|
|
|
@ -48,6 +48,14 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
|
||||||
{Config::showTabCalc,{QS("showTabCalc"), true}},
|
{Config::showTabCalc,{QS("showTabCalc"), true}},
|
||||||
{Config::showSearchbar,{QS("showSearchbar"), true}},
|
{Config::showSearchbar,{QS("showSearchbar"), true}},
|
||||||
|
|
||||||
|
// Receive
|
||||||
|
{Config::showUsedAddresses,{QS("showUsedAddresses"), false}},
|
||||||
|
{Config::showHiddenAddresses,{QS("showHiddenAddresses"), false}},
|
||||||
|
{Config::showFullAddresses, {QS("showFullAddresses"), false}},
|
||||||
|
{Config::showChangeAddresses,{QS("showChangeAddresses"), false}},
|
||||||
|
{Config::showAddressIndex,{QS("showAddressIndex"), true}},
|
||||||
|
{Config::showAddressLabels,{QS("showAddressLabels"), true}},
|
||||||
|
|
||||||
// Mining
|
// Mining
|
||||||
{Config::miningMode,{QS("miningMode"), Config::MiningMode::Pool}},
|
{Config::miningMode,{QS("miningMode"), Config::MiningMode::Pool}},
|
||||||
{Config::xmrigPath,{QS("xmrigPath"), ""}},
|
{Config::xmrigPath,{QS("xmrigPath"), ""}},
|
||||||
|
|
|
@ -50,6 +50,14 @@ public:
|
||||||
showTabCalc,
|
showTabCalc,
|
||||||
showTabXMRig,
|
showTabXMRig,
|
||||||
showSearchbar,
|
showSearchbar,
|
||||||
|
|
||||||
|
// Receive
|
||||||
|
showUsedAddresses,
|
||||||
|
showHiddenAddresses,
|
||||||
|
showFullAddresses,
|
||||||
|
showChangeAddresses,
|
||||||
|
showAddressIndex,
|
||||||
|
showAddressLabels,
|
||||||
|
|
||||||
// Mining
|
// Mining
|
||||||
miningMode,
|
miningMode,
|
||||||
|
|
Loading…
Reference in a new issue