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);
}
}
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);
}
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;
// 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();
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)
Q_INVOKABLE void freeze(int index) const;
Q_INVOKABLE void thaw(int index) const;
Q_INVOKABLE QVector<CoinsInfo*> coins_from_txid(const QString &txid);
+ Q_INVOKABLE void setDescription(int index, quint32 accountIndex, const QString &description);
quint64 count() const;
void refreshFinished() const;
void coinFrozen() const;
void coinThawed() const;
+ void descriptionChanged() const;
private:
explicit Coins(Monero::Coins * pimpl, QObject *parent = nullptr);
return m_coinbase;
}
+QString CoinsInfo::description() const {
+ return m_description;
+}
+
CoinsInfo::CoinsInfo(const Monero::CoinsInfo *pimpl, QObject *parent)
: QObject(parent)
, m_blockHeight(pimpl->blockHeight())
, m_unlocked(pimpl->unlocked())
, m_pubKey(QString::fromStdString(pimpl->pubKey()))
, m_coinbase(pimpl->coinbase())
+ , m_description(QString::fromStdString(pimpl->description()))
{
}
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;
bool unlocked() const;
QString pubKey() const;
bool coinbase() const;
+ QString description() const;
void setUnlocked(bool unlocked);
bool m_unlocked;
QString m_pubKey;
bool m_coinbase;
+ QString m_description;
};
#endif //FEATHER_COINSINFO_H
m_history->refresh(m_currentSubaddressAccount);
m_coins->refresh(m_currentSubaddressAccount);
this->subaddressModel()->setCurrentSubaddressAcount(m_currentSubaddressAccount);
+ this->coinsModel()->setCurrentSubaddressAccount(m_currentSubaddressAccount);
emit currentSubaddressAccountChanged();
}
}
#include <QBrush>
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);
else if (role == Qt::FontRole) {
switch(index.column()) {
case PubKey:
- case OutputPoint:
+ case TxID:
case Address:
result = ModelUtils::getMonospaceFont();
}
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");
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)
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:
}
}
+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());
{
KeyImageKnown = 0,
PubKey,
- OutputPoint,
+ TxID,
Address,
- AddressLabel,
+ Label,
BlockHeight,
SpentHeight,
Amount,
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();
QVariant parseTransactionInfo(const CoinsInfo &cInfo, int column, int role) const;
Coins *m_coins;
+ quint32 m_currentSubaddressAccount;
};
#endif //FEATHER_COINSMODEL_H