]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
Coins: manual input selection
authortobtoht <thotbot@protonmail.com>
Sun, 20 Mar 2022 22:30:48 +0000 (23:30 +0100)
committertobtoht <thotbot@protonmail.com>
Sun, 20 Mar 2022 22:30:48 +0000 (23:30 +0100)
13 files changed:
src/CoinsWidget.cpp
src/CoinsWidget.h
src/MainWindow.cpp
src/MainWindow.h
src/MainWindow.ui
src/appcontext.cpp
src/appcontext.h
src/libwalletqt/Coins.cpp
src/libwalletqt/Coins.h
src/libwalletqt/Wallet.cpp
src/libwalletqt/Wallet.h
src/model/CoinsModel.cpp
src/model/CoinsModel.h

index 4afc22d238d739f1e0a36f5ebb8b7248a3977177..6b623a4abee3643ba2abded3b0255688f88fade6 100644 (file)
@@ -46,12 +46,14 @@ CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
     m_freezeAllSelectedAction = new QAction("Freeze selected", this);
     m_thawAllSelectedAction = new QAction("Thaw selected", this);
 
+    m_spendAction = new QAction("Spend", this);
     m_viewOutputAction = new QAction("Details", this);
     m_sweepOutputAction = new QAction("Sweep output", this);
     m_sweepOutputsAction = new QAction("Sweep selected outputs", this);
 
     connect(m_freezeOutputAction, &QAction::triggered, this, &CoinsWidget::freezeAllSelected);
     connect(m_thawOutputAction, &QAction::triggered, this, &CoinsWidget::thawAllSelected);
+    connect(m_spendAction, &QAction::triggered, this, &CoinsWidget::spendSelected);
     connect(m_viewOutputAction, &QAction::triggered, this, &CoinsWidget::viewOutput);
     connect(m_sweepOutputAction, &QAction::triggered, this, &CoinsWidget::onSweepOutputs);
     connect(m_sweepOutputsAction, &QAction::triggered, this, &CoinsWidget::onSweepOutputs);
@@ -68,6 +70,8 @@ CoinsWidget::CoinsWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
     });
 
     connect(ui->search, &QLineEdit::textChanged, this, &CoinsWidget::setSearchFilter);
+
+    connect(m_ctx.get(), &AppContext::selectedInputsChanged, this, &CoinsWidget::selectCoins);
 }
 
 void CoinsWidget::setModel(CoinsModel * model, Coins * coins) {
@@ -106,6 +110,7 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
 
     auto *menu = new QMenu(ui->coins);
     if (list.size() > 1) {
+        menu->addAction(m_spendAction);
         menu->addAction(m_freezeAllSelectedAction);
         menu->addAction(m_thawAllSelectedAction);
         menu->addAction(m_sweepOutputsAction);
@@ -118,6 +123,7 @@ void CoinsWidget::showContextMenu(const QPoint &point) {
         bool isFrozen = c->frozen();
         bool isUnlocked = c->unlocked();
 
+        menu->addAction(m_spendAction);
         menu->addMenu(m_copyMenu);
         menu->addAction(m_editLabelAction);
 
@@ -174,6 +180,18 @@ void CoinsWidget::thawAllSelected() {
     this->thawCoins(pubkeys);
 }
 
+void CoinsWidget::spendSelected() {
+    QModelIndexList list = ui->coins->selectionModel()->selectedRows();
+
+    QStringList keyimages;
+    for (QModelIndex index: list) {
+        keyimages << m_model->entryFromIndex(m_proxyModel->mapToSource(index))->keyImage();
+    }
+
+    m_ctx->setSelectedInputs(keyimages);
+    this->selectCoins(keyimages);
+}
+
 void CoinsWidget::viewOutput() {
     CoinsInfo* c = this->currentEntry();
     if (!c) return;
@@ -294,6 +312,11 @@ void CoinsWidget::thawCoins(QStringList &pubkeys) {
     m_ctx->updateBalance();
 }
 
+void CoinsWidget::selectCoins(const QStringList &keyimages) {
+    m_model->setSelected(keyimages);
+    ui->coins->clearSelection();
+}
+
 void CoinsWidget::editLabel() {
     QModelIndex index = ui->coins->currentIndex().siblingAtColumn(m_model->ModelColumn::Label);
     ui->coins->setCurrentIndex(index);
index 0c4be12f9817af4200de9169b60aa44741f90a72..f0978d7da3547cecc552751977f07deabe43f3c3 100644 (file)
@@ -26,6 +26,11 @@ public:
     void setModel(CoinsModel * model, Coins * coins);
     ~CoinsWidget() override;
 
+    void setSpendSelected(const QStringList &pubkeys);
+
+signals:
+    void spendSelectedChanged(const QStringList &pubkeys);
+
 public slots:
     void setSearchbarVisible(bool visible);
     void focusSearchbar();
@@ -35,6 +40,7 @@ private slots:
     void setShowSpent(bool show);
     void freezeAllSelected();
     void thawAllSelected();
+    void spendSelected();
     void viewOutput();
     void onSweepOutputs();
     void setSearchFilter(const QString &filter);
@@ -43,6 +49,7 @@ private slots:
 private:
     void freezeCoins(QStringList &pubkeys);
     void thawCoins(QStringList &pubkeys);
+    void selectCoins(const QStringList &pubkeys);
 
     enum copyField {
         PubKey = 0,
@@ -60,6 +67,7 @@ private:
     QMenu *m_contextMenu;
     QMenu *m_headerMenu;
     QMenu *m_copyMenu;
+    QAction *m_spendAction;
     QAction *m_showSpentAction;
     QAction *m_freezeOutputAction;
     QAction *m_freezeAllSelectedAction;
index f509cc77add2cd24573257936f19d7768fa5a622..c0a010bb0cd572bd04df77e13613dbb7d1f582c3 100644 (file)
@@ -25,6 +25,7 @@
 #include "dialog/WalletCacheDebugDialog.h"
 #include "dialog/UpdateDialog.h"
 #include "libwalletqt/AddressBook.h"
+#include "libwalletqt/CoinsInfo.h"
 #include "libwalletqt/Transfer.h"
 #include "utils/AppData.h"
 #include "utils/AsyncTask.h"
@@ -217,6 +218,11 @@ void MainWindow::initWidgets() {
 #if defined(Q_OS_MACOS)
     ui->line->hide();
 #endif
+
+    ui->frame_coinControl->setVisible(false);
+    connect(ui->btn_resetCoinControl, &QPushButton::clicked, [this]{
+       m_ctx->setSelectedInputs({});
+    });
 }
 
 void MainWindow::initMenu() {
@@ -384,6 +390,7 @@ void MainWindow::initWalletContext() {
     connect(m_ctx.get(), &AppContext::endTransaction,           this, &MainWindow::onEndTransaction);
     connect(m_ctx.get(), &AppContext::customRestoreHeightSet,   this, &MainWindow::onCustomRestoreHeightSet);
     connect(m_ctx.get(), &AppContext::keysCorrupted,            this, &MainWindow::onKeysCorrupted);
+    connect(m_ctx.get(), &AppContext::selectedInputsChanged,    this, &MainWindow::onSelectedInputsChanged);
 
     // Nodes
     connect(m_ctx->nodes, &Nodes::nodeExhausted,   this, &MainWindow::showNodeExhaustedMessage);
@@ -1446,6 +1453,24 @@ void MainWindow::onKeysCorrupted() {
     }
 }
 
+void MainWindow::onSelectedInputsChanged(const QStringList &selectedInputs) {
+    int numInputs = selectedInputs.size();
+
+    ui->frame_coinControl->setStyleSheet(ColorScheme::GREEN.asStylesheet(true));
+    ui->frame_coinControl->setVisible(numInputs > 0);
+
+    if (numInputs > 0) {
+        quint64 totalAmount = 0;
+        auto coins = m_ctx->wallet->coins()->coinsFromKeyImage(selectedInputs);
+        for (const auto coin : coins) {
+            totalAmount += coin->amount();
+        }
+
+        QString text = QString("Coin control active: %1 selected outputs, %2 XMR").arg(QString::number(numInputs), WalletManager::displayAmount(totalAmount));
+        ui->label_coinControl->setText(text);
+    }
+}
+
 void MainWindow::onExportHistoryCSV(bool checked) {
     if (m_ctx->wallet == nullptr)
         return;
index a8b3464c4d63e6a619bb5903ecb7ecc6fa67d7cc..0b24c2c6fe9301562ae2412cced03c4e33366f1f 100644 (file)
@@ -140,6 +140,7 @@ private slots:
     void onEndTransaction();
     void onCustomRestoreHeightSet(int height);
     void onKeysCorrupted();
+    void onSelectedInputsChanged(const QStringList &selectedInputs);
 
     // libwalletqt
     void onBalanceUpdated(quint64 balance, quint64 spendable);
index 3d82bf17ccc4eef3bcfd3abd9f0ae28280964bd0..9d1602e0d5010b01a419cebc54d37bbba03b117b 100644 (file)
       </widget>
      </widget>
     </item>
+    <item row="2" column="0">
+     <widget class="QFrame" name="frame_coinControl">
+      <property name="frameShape">
+       <enum>QFrame::StyledPanel</enum>
+      </property>
+      <property name="frameShadow">
+       <enum>QFrame::Raised</enum>
+      </property>
+      <layout class="QHBoxLayout" name="horizontalLayout_3">
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QLabel" name="label_coinControl">
+         <property name="text">
+          <string>Coin control active: </string>
+         </property>
+         <property name="textInteractionFlags">
+          <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="btn_resetCoinControl">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>Reset</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </item>
    </layout>
   </widget>
   <widget class="QStatusBar" name="statusBar"/>
index 15420b0cd61a6af28f97a6ed0242e05f48684da4..523093492456826ed0ea39ca5f1098dad4327056 100644 (file)
@@ -82,9 +82,9 @@ void AppContext::onCreateTransaction(const QString &address, quint64 amount, con
 
     qInfo() << "Creating transaction";
     if (all)
-        this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority);
+        this->wallet->createTransactionAllAsync(address, "", constants::mixin, this->tx_priority, m_selectedInputs);
     else
-        this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority);
+        this->wallet->createTransactionAsync(address, "", amount, constants::mixin, this->tx_priority, m_selectedInputs);
 
     emit initiateTransaction();
 }
@@ -103,7 +103,7 @@ void AppContext::onCreateTransactionMultiDest(const QVector<QString> &addresses,
     }
 
     qInfo() << "Creating transaction";
-    this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority);
+    this->wallet->createTransactionMultiDestAsync(addresses, amounts, this->tx_priority, m_selectedInputs);
 
     emit initiateTransaction();
 }
@@ -131,6 +131,9 @@ void AppContext::onCancelTransaction(PendingTransaction *tx, const QVector<QStri
 }
 
 void AppContext::commitTransaction(PendingTransaction *tx, const QString &description) {
+    // Clear list of selected transfers
+    this->setSelectedInputs({});
+
     // Nodes - even well-connected, properly configured ones - consistently fail to relay transactions
     // To mitigate transactions failing we just send the transaction to every node we know about over Tor
     if (config()->get(Config::multiBroadcast).toBool()) {
@@ -180,6 +183,11 @@ void AppContext::onDeviceError(const QString &message) {
 
 // ################## Misc ##################
 
+void AppContext::setSelectedInputs(const QStringList &selectedInputs) {
+    m_selectedInputs = selectedInputs;
+    emit selectedInputsChanged(selectedInputs);
+}
+
 void AppContext::onTorSettingsChanged() {
     if (Utils::isTorsocks()) {
         return;
index dd6fcdebd192b9a2aad5b3f4032768f400f078f7..2035a84693e7906528401ffe4c99dddf9d11b25d 100644 (file)
@@ -49,6 +49,8 @@ public:
     void addCacheTransaction(const QString &txid, const QString &txHex) const;
     QString getCacheTransaction(const QString &txid) const;
 
+    void setSelectedInputs(const QStringList &selectedInputs);
+
 public slots:
     void onCreateTransaction(const QString &address, quint64 amount, const QString &description, bool all);
     void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
@@ -93,10 +95,12 @@ signals:
     void deviceButtonPressed();
     void deviceError(const QString &message);
     void keysCorrupted();
+    void selectedInputsChanged(const QStringList &selectedInputs);
 
 private:
     DaemonRpc *m_rpc;
     QTimer m_storeTimer;
+    QStringList m_selectedInputs;
 };
 
 #endif //FEATHER_APPCONTEXT_H
index f000bb031552c2d7c27cdebc105838a1cf5de26b..66f520641e170fcb8fcd83da76d853a3b44f5b79 100644 (file)
@@ -96,6 +96,19 @@ QVector<CoinsInfo*> Coins::coins_from_txid(const QString &txid)
     return coins;
 }
 
+QVector<CoinsInfo*> Coins::coinsFromKeyImage(const QStringList &keyimages) {
+    QVector<CoinsInfo*> coins;
+
+    for (int i = 0; i < this->count(); i++) {
+        CoinsInfo* coin = this->coin(i);
+        if (coin->keyImageKnown() && keyimages.contains(coin->keyImage())) {
+            coins.append(coin);
+        }
+    }
+
+    return coins;
+}
+
 void Coins::setDescription(const QString &publicKey, quint32 accountIndex, const QString &description)
 {
     m_pimpl->setDescription(publicKey.toStdString(), description.toStdString());
index efde480c3b198b64fb71cc855f4e34eeac98f6e3..3af24cf122af87e80a82a2890d4c0a3e29bffe38 100644 (file)
@@ -21,17 +21,17 @@ class CoinsInfo;
 class Coins : public QObject
 {
 Q_OBJECT
-    Q_PROPERTY(int count READ count)
 
 public:
-    Q_INVOKABLE bool coin(int index, std::function<void (CoinsInfo &)> callback);
-    Q_INVOKABLE CoinsInfo * coin(int index);
-    Q_INVOKABLE void refresh(quint32 accountIndex);
-    Q_INVOKABLE void refreshUnlocked();
-    Q_INVOKABLE void freeze(QString &publicKey) const;
-    Q_INVOKABLE void thaw(QString &publicKey) const;
-    Q_INVOKABLE QVector<CoinsInfo*> coins_from_txid(const QString &txid);
-    Q_INVOKABLE void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description);
+    bool coin(int index, std::function<void (CoinsInfo &)> callback);
+    CoinsInfo * coin(int index);
+    void refresh(quint32 accountIndex);
+    void refreshUnlocked();
+    void freeze(QString &publicKey) const;
+    void thaw(QString &publicKey) const;
+    QVector<CoinsInfo*> coins_from_txid(const QString &txid);
+    QVector<CoinsInfo*> coinsFromKeyImage(const QStringList &keyimages);
+    void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description);
 
     quint64 count() const;
 
index 6a60cd197471940cc8a2a0916fdc5fce50df345b..e996fca955382837b357cb63b8fb21bdcd535c76 100644 (file)
@@ -609,14 +609,18 @@ void Wallet::pauseRefresh()
 
 PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QString &payment_id,
                                               quint64 amount, quint32 mixin_count,
-                                              PendingTransaction::Priority priority)
+                                              PendingTransaction::Priority priority, const QStringList &preferredInputs)
 {
 //    pauseRefresh();
+    std::set<std::string> preferred_inputs;
+    for (const auto &input : preferredInputs) {
+        preferred_inputs.insert(input.toStdString());
+    }
 
     std::set<uint32_t> subaddr_indices;
     Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
             dst_addr.toStdString(), payment_id.toStdString(), amount, mixin_count,
-            static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
+            static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
     PendingTransaction * result = new PendingTransaction(ptImpl, nullptr);
 
 //    startRefresh();
@@ -625,17 +629,17 @@ PendingTransaction *Wallet::createTransaction(const QString &dst_addr, const QSt
 
 void Wallet::createTransactionAsync(const QString &dst_addr, const QString &payment_id,
                                     quint64 amount, quint32 mixin_count,
-                                    PendingTransaction::Priority priority)
+                                    PendingTransaction::Priority priority, const QStringList &preferredInputs)
 {
-    m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority] {
-        PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority);
+    m_scheduler.run([this, dst_addr, payment_id, amount, mixin_count, priority, preferredInputs] {
+        PendingTransaction *tx = createTransaction(dst_addr, payment_id, amount, mixin_count, priority, preferredInputs);
         QVector<QString> address {dst_addr};
         emit transactionCreated(tx, address);
     });
 }
 
 PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
-                                                       PendingTransaction::Priority priority)
+                                                       PendingTransaction::Priority priority, const QStringList &preferredInputs)
 {
 //    pauseRefresh();
 
@@ -649,8 +653,14 @@ PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &d
         amounts.push_back(a);
     }
 
+    std::set<std::string> preferred_inputs;
+    for (const auto &input : preferredInputs) {
+        preferred_inputs.insert(input.toStdString());
+    }
+
     // TODO: remove mixin count
-    Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority));
+    std::set<uint32_t> subaddr_indices;
+    Monero::PendingTransaction * ptImpl = m_walletImpl->createTransactionMultDest(dests, "", amounts, 11, static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
     PendingTransaction * result = new PendingTransaction(ptImpl);
 
 //    startRefresh();
@@ -658,10 +668,10 @@ PendingTransaction* Wallet::createTransactionMultiDest(const QVector<QString> &d
 }
 
 void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
-                                             PendingTransaction::Priority priority)
+                                             PendingTransaction::Priority priority, const QStringList &preferredInputs)
 {
-    m_scheduler.run([this, dst_addr, amount, priority] {
-        PendingTransaction *tx = createTransactionMultiDest(dst_addr, amount, priority);
+    m_scheduler.run([this, dst_addr, amount, priority, preferredInputs] {
+        PendingTransaction *tx = createTransactionMultiDest(dst_addr, amount, priority, preferredInputs);
         QVector<QString> addresses;
         for (auto &addr : dst_addr) {
             addresses.push_back(addr);
@@ -671,14 +681,20 @@ void Wallet::createTransactionMultiDestAsync(const QVector<QString> &dst_addr, c
 }
 
 PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const QString &payment_id,
-                                                 quint32 mixin_count, PendingTransaction::Priority priority)
+                                                 quint32 mixin_count, PendingTransaction::Priority priority,
+                                                 const QStringList &preferredInputs)
 {
 //    pauseRefresh();
 
+    std::set<std::string> preferred_inputs;
+    for (const auto &input : preferredInputs) {
+        preferred_inputs.insert(input.toStdString());
+    }
+
     std::set<uint32_t> subaddr_indices;
     Monero::PendingTransaction * ptImpl = m_walletImpl->createTransaction(
             dst_addr.toStdString(), payment_id.toStdString(), Monero::optional<uint64_t>(), mixin_count,
-            static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices);
+            static_cast<Monero::PendingTransaction::Priority>(priority), currentSubaddressAccount(), subaddr_indices, preferred_inputs);
     PendingTransaction * result = new PendingTransaction(ptImpl, this);
 
 //    startRefresh();
@@ -687,10 +703,10 @@ PendingTransaction *Wallet::createTransactionAll(const QString &dst_addr, const
 
 void Wallet::createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
                                        quint32 mixin_count,
-                                       PendingTransaction::Priority priority)
+                                       PendingTransaction::Priority priority, const QStringList &preferredInputs)
 {
-    m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority] {
-        PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority);
+    m_scheduler.run([this, dst_addr, payment_id, mixin_count, priority, preferredInputs] {
+        PendingTransaction *tx = createTransactionAll(dst_addr, payment_id, mixin_count, priority, preferredInputs);
         QVector<QString> address {dst_addr};
         emit transactionCreated(tx, address);
     });
index 9b08f5e80a08ad359fa7d5cc34dd548a31107ed5..ed30083f1bd782067d305a978a943db78196c1a7 100644 (file)
@@ -271,30 +271,33 @@ public:
 
     //! creates transaction
     PendingTransaction * createTransaction(const QString &dst_addr, const QString &payment_id,
-                                                       quint64 amount, quint32 mixin_count,
-                                                       PendingTransaction::Priority priority);
+                                           quint64 amount, quint32 mixin_count,
+                                           PendingTransaction::Priority priority,
+                                           const QStringList &preferredInputs);
 
     //! creates async transaction
     void createTransactionAsync(const QString &dst_addr, const QString &payment_id,
-                                            quint64 amount, quint32 mixin_count,
-                                            PendingTransaction::Priority priority);
+                                quint64 amount, quint32 mixin_count,
+                                PendingTransaction::Priority priority, const QStringList &preferredInputs);
 
     //! creates multi-destination transaction
     PendingTransaction * createTransactionMultiDest(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
-                                                                PendingTransaction::Priority priority);
+                                                    PendingTransaction::Priority priority, const QStringList &preferredInputs);
 
     //! creates async multi-destination transaction
     void createTransactionMultiDestAsync(const QVector<QString> &dst_addr, const QVector<quint64> &amount,
-                                                     PendingTransaction::Priority priority);
+                                         PendingTransaction::Priority priority, const QStringList &preferredInputs);
 
 
     //! creates transaction with all outputs
     PendingTransaction * createTransactionAll(const QString &dst_addr, const QString &payment_id,
-                                                          quint32 mixin_count, PendingTransaction::Priority priority);
+                                              quint32 mixin_count, PendingTransaction::Priority priority,
+                                              const QStringList &preferredInputs);
 
     //! creates async transaction with all outputs
     void createTransactionAllAsync(const QString &dst_addr, const QString &payment_id,
-                                               quint32 mixin_count, PendingTransaction::Priority priority);
+                                   quint32 mixin_count, PendingTransaction::Priority priority,
+                                   const QStringList &preferredInputs);
 
     //! creates transaction with single input
     PendingTransaction * createTransactionSingle(const QString &key_image, const QString &dst_addr,
index b099676116285d291ab5b23d0a43907e17693fed..45c2949adad664b62820310eacbadf01c66bb3f5 100644 (file)
@@ -61,6 +61,8 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
     QVariant result;
 
     bool found = m_coins->coin(index.row(), [this, &index, &result, &role](const CoinsInfo &cInfo) {
+        bool selected = cInfo.keyImageKnown() && m_selected.contains(cInfo.keyImage());
+
         if(role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
             result = parseTransactionInfo(cInfo, index.column(), role);
         }
@@ -74,6 +76,9 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
             else if (!cInfo.unlocked()) {
                 result = QBrush(ColorScheme::YELLOW.asColor(true));
             }
+            else if (selected) {
+                result = QBrush(ColorScheme::GREEN.asColor(true));
+            }
         }
         else if (role == Qt::TextAlignmentRole) {
             switch (index.column()) {
@@ -122,6 +127,9 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const
             else if (cInfo.spent()) {
                 result = "Output is spent";
             }
+            else if (selected) {
+                result = "Coin selected to be spent";
+            }
         }
     });
     if (!found) {
@@ -247,6 +255,14 @@ void CoinsModel::setCurrentSubaddressAccount(quint32 accountIndex) {
     m_currentSubaddressAccount = accountIndex;
 }
 
+void CoinsModel::setSelected(const QStringList &keyimages) {
+    m_selected.clear();
+    for (const auto &ki : keyimages) {
+        m_selected.insert(ki);
+    }
+    emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
+}
+
 CoinsInfo* CoinsModel::entryFromIndex(const QModelIndex &index) const {
     Q_ASSERT(index.isValid() && index.row() < m_coins->count());
     return m_coins->coin(index.row());
index ce9a62b2a96d3a3fe21c82ab88d58fffb3563dc0..2e17e8aa38d8b76c10b40ca61a22d5153660f993 100644 (file)
@@ -48,6 +48,7 @@ public:
     CoinsInfo* entryFromIndex(const QModelIndex &index) const;
 
     void setCurrentSubaddressAccount(quint32 accountIndex);
+    void setSelected(const QStringList &selected);
 
 signals:
     void descriptionChanged();
@@ -61,6 +62,7 @@ private:
 
     Coins *m_coins;
     quint32 m_currentSubaddressAccount;
+    QSet<QString> m_selected;
 };
 
 #endif //FEATHER_COINSMODEL_H