From 8563d7fa6124def8f14b9f08425797629e8319eb Mon Sep 17 00:00:00 2001 From: tobtoht Date: Fri, 2 Jul 2021 16:12:07 +0200 Subject: [PATCH] Coins: output labeling --- src/CoinsWidget.cpp | 17 ++++++++--- src/MainWindow.cpp | 10 ++++++ src/libwalletqt/Coins.cpp | 7 +++++ src/libwalletqt/Coins.h | 2 ++ src/libwalletqt/CoinsInfo.cpp | 5 +++ src/libwalletqt/CoinsInfo.h | 3 ++ src/libwalletqt/Wallet.cpp | 1 + src/model/CoinsModel.cpp | 57 +++++++++++++++++++++++++++++------ src/model/CoinsModel.h | 12 ++++++-- 9 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/CoinsWidget.cpp b/src/CoinsWidget.cpp index 4620737..97ac2df 100644 --- a/src/CoinsWidget.cpp +++ b/src/CoinsWidget.cpp @@ -57,7 +57,12 @@ CoinsWidget::CoinsWidget(QSharedPointer ctx, QWidget *parent) connect(m_thawAllSelectedAction, &QAction::triggered, this, &CoinsWidget::thawAllSelected); connect(ui->coins, &QTreeView::customContextMenuRequested, this, &CoinsWidget::showContextMenu); - connect(ui->coins, &QTreeView::doubleClicked, this, &CoinsWidget::viewOutput); + connect(ui->coins, &QTreeView::doubleClicked, [this](QModelIndex index){ + if (!m_model) return; + if (!(m_model->flags(index) & Qt::ItemIsEditable)) { + this->viewOutput(); + } + }); connect(ui->search, &QLineEdit::textChanged, this, &CoinsWidget::setSearchFilter); } @@ -79,7 +84,7 @@ void CoinsWidget::setModel(CoinsModel * model, Coins * coins) { } ui->coins->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui->coins->header()->setSectionResizeMode(CoinsModel::AddressLabel, QHeaderView::Stretch); + ui->coins->header()->setSectionResizeMode(CoinsModel::Label, QHeaderView::Stretch); ui->coins->header()->setSortIndicator(CoinsModel::BlockHeight, Qt::DescendingOrder); ui->coins->setSortingEnabled(true); } @@ -241,9 +246,13 @@ void CoinsWidget::copy(copyField field) { case Address: data = c->address(); break; - case Label: - data = c->addressLabel(); + case Label: { + if (!c->description().isEmpty()) + data = c->description(); + else + data = c->addressLabel(); break; + } case Height: data = QString::number(c->blockHeight()); break; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 732b140..7175ed6 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -447,6 +447,16 @@ void MainWindow::onWalletOpened() { // coins page m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount()); m_coinsWidget->setModel(m_ctx->wallet->coinsModel(), m_ctx->wallet->coins()); + m_ctx->wallet->coinsModel()->setCurrentSubaddressAccount(m_ctx->wallet->currentSubaddressAccount()); + + // Coin labeling uses set_tx_note, so we need to refresh history too + connect(m_ctx->wallet->coins(), &Coins::descriptionChanged, [this] { + m_ctx->wallet->history()->refresh(m_ctx->wallet->currentSubaddressAccount()); + }); + // Vice versa + connect(m_ctx->wallet->history(), &TransactionHistory::txNoteChanged, [this] { + m_ctx->wallet->coins()->refresh(m_ctx->wallet->currentSubaddressAccount()); + }); this->updatePasswordIcon(); this->updateTitle(); diff --git a/src/libwalletqt/Coins.cpp b/src/libwalletqt/Coins.cpp index d0440db..ac49d27 100644 --- a/src/libwalletqt/Coins.cpp +++ b/src/libwalletqt/Coins.cpp @@ -96,6 +96,13 @@ QVector Coins::coins_from_txid(const QString &txid) return coins; } +void Coins::setDescription(int index, quint32 accountIndex, const QString &description) +{ + m_pimpl->setDescription(index, description.toStdString()); + this->refresh(accountIndex); + emit descriptionChanged(); +} + Coins::Coins(Monero::Coins *pimpl, QObject *parent) : QObject(parent) , m_pimpl(pimpl) diff --git a/src/libwalletqt/Coins.h b/src/libwalletqt/Coins.h index 62060a9..1813cb0 100644 --- a/src/libwalletqt/Coins.h +++ b/src/libwalletqt/Coins.h @@ -31,6 +31,7 @@ public: Q_INVOKABLE void freeze(int index) const; Q_INVOKABLE void thaw(int index) const; Q_INVOKABLE QVector coins_from_txid(const QString &txid); + Q_INVOKABLE void setDescription(int index, quint32 accountIndex, const QString &description); quint64 count() const; @@ -39,6 +40,7 @@ signals: void refreshFinished() const; void coinFrozen() const; void coinThawed() const; + void descriptionChanged() const; private: explicit Coins(Monero::Coins * pimpl, QObject *parent = nullptr); diff --git a/src/libwalletqt/CoinsInfo.cpp b/src/libwalletqt/CoinsInfo.cpp index d6076cb..b8ee753 100644 --- a/src/libwalletqt/CoinsInfo.cpp +++ b/src/libwalletqt/CoinsInfo.cpp @@ -104,6 +104,10 @@ bool CoinsInfo::coinbase() const { return m_coinbase; } +QString CoinsInfo::description() const { + return m_description; +} + CoinsInfo::CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent) : QObject(parent) , m_blockHeight(pimpl->blockHeight()) @@ -126,6 +130,7 @@ CoinsInfo::CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent) , m_unlocked(pimpl->unlocked()) , m_pubKey(QString::fromStdString(pimpl->pubKey())) , m_coinbase(pimpl->coinbase()) + , m_description(QString::fromStdString(pimpl->description())) { } diff --git a/src/libwalletqt/CoinsInfo.h b/src/libwalletqt/CoinsInfo.h index 05c71e7..d8143a6 100644 --- a/src/libwalletqt/CoinsInfo.h +++ b/src/libwalletqt/CoinsInfo.h @@ -35,6 +35,7 @@ Q_OBJECT Q_PROPERTY(bool unlocked READ unlocked) Q_PROPERTY(QString pubKey READ pubKey) Q_PROPERTY(bool coinbase READ coinbase) + Q_PROPERTY(QString description READ description) public: quint64 blockHeight() const; @@ -58,6 +59,7 @@ public: bool unlocked() const; QString pubKey() const; bool coinbase() const; + QString description() const; void setUnlocked(bool unlocked); @@ -86,6 +88,7 @@ private: bool m_unlocked; QString m_pubKey; bool m_coinbase; + QString m_description; }; #endif //FEATHER_COINSINFO_H diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index c4943c1..d3e35af 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -377,6 +377,7 @@ void Wallet::switchSubaddressAccount(quint32 accountIndex) m_history->refresh(m_currentSubaddressAccount); m_coins->refresh(m_currentSubaddressAccount); this->subaddressModel()->setCurrentSubaddressAcount(m_currentSubaddressAccount); + this->coinsModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount); emit currentSubaddressAccountChanged(); } } diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp index ca297fb..ee604ec 100644 --- a/src/model/CoinsModel.cpp +++ b/src/model/CoinsModel.cpp @@ -13,8 +13,8 @@ #include CoinsModel::CoinsModel(QObject *parent, Coins *coins) - : QAbstractTableModel(parent), - m_coins(coins) + : QAbstractTableModel(parent) + , m_coins(coins) { connect(m_coins, &Coins::refreshStarted, this, &CoinsModel::startReset); connect(m_coins, &Coins::refreshFinished, this, &CoinsModel::endReset); @@ -97,7 +97,7 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const else if (role == Qt::FontRole) { switch(index.column()) { case PubKey: - case OutputPoint: + case TxID: case Address: result = ModelUtils::getMonospaceFont(); } @@ -137,13 +137,13 @@ QVariant CoinsModel::headerData(int section, Qt::Orientation orientation, int ro switch(section) { case PubKey: return QString("Pub Key"); - case OutputPoint: - return QString("Output point"); + case TxID: + return QString("TxID"); case BlockHeight: return QString("Height"); case Address: return QString("Address"); - case AddressLabel: + case Label: return QString("Label"); case SpentHeight: return QString("Spent Height"); @@ -160,6 +160,38 @@ QVariant CoinsModel::headerData(int section, Qt::Orientation orientation, int ro return QVariant(); } +Qt::ItemFlags CoinsModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + if (index.column() == Label) + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; + + return QAbstractTableModel::flags(index); +} + +bool CoinsModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + const int row = index.row(); + + switch (index.column()) { + case Label: + m_coins->setDescription(row, m_currentSubaddressAccount, value.toString()); + emit descriptionChanged(); + break; + default: + return false; + } + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + + return true; + } + + return false; +} + QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, int role) const { switch (column) @@ -168,14 +200,17 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in return ""; case PubKey: return cInfo.pubKey().mid(0,8); - case OutputPoint: - return cInfo.hash().mid(0, 8) + ":" + QString::number(cInfo.internalOutputIndex()); + case TxID: + return cInfo.hash().mid(0, 8) + " "; case BlockHeight: return cInfo.blockHeight(); case Address: return ModelUtils::displayAddress(cInfo.address(), 1, ""); - case AddressLabel: + case Label: { + if (!cInfo.description().isEmpty()) + return cInfo.description(); return cInfo.addressLabel(); + } case Spent: return cInfo.spent(); case SpentHeight: @@ -197,6 +232,10 @@ QVariant CoinsModel::parseTransactionInfo(const CoinsInfo &cInfo, int column, in } } +void CoinsModel::setCurrentSubaddressAccount(quint32 accountIndex) { + m_currentSubaddressAccount = accountIndex; +} + CoinsInfo* CoinsModel::entryFromIndex(const QModelIndex &index) const { Q_ASSERT(index.isValid() && index.row() < m_coins->count()); return m_coins->coin(index.row()); diff --git a/src/model/CoinsModel.h b/src/model/CoinsModel.h index 97dd19f..0f69d27 100644 --- a/src/model/CoinsModel.h +++ b/src/model/CoinsModel.h @@ -23,9 +23,9 @@ public: { KeyImageKnown = 0, PubKey, - OutputPoint, + TxID, Address, - AddressLabel, + Label, BlockHeight, SpentHeight, Amount, @@ -42,9 +42,16 @@ public: int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; CoinsInfo* entryFromIndex(const QModelIndex &index) const; + void setCurrentSubaddressAccount(quint32 accountIndex); + +signals: + void descriptionChanged(); + public slots: void startReset(); void endReset(); @@ -53,6 +60,7 @@ private: QVariant parseTransactionInfo(const CoinsInfo &cInfo, int column, int role) const; Coins *m_coins; + quint32 m_currentSubaddressAccount; }; #endif //FEATHER_COINSMODEL_H