Changeset View
Changeset View
Standalone View
Standalone View
src/qt/coincontroldialog.cpp
Show First 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { | ||||
Qt::Unchecked) { | Qt::Unchecked) { | ||||
state = Qt::Unchecked; | state = Qt::Unchecked; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
ui->treeWidget->setEnabled(false); | ui->treeWidget->setEnabled(false); | ||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) | for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) | ||||
if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != | if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != | ||||
state) | state) { | ||||
ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, | ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, | ||||
state); | state); | ||||
} | |||||
ui->treeWidget->setEnabled(true); | ui->treeWidget->setEnabled(true); | ||||
if (state == Qt::Unchecked) { | if (state == Qt::Unchecked) { | ||||
// just to be sure | // just to be sure | ||||
coinControl->UnSelectAll(); | coinControl->UnSelectAll(); | ||||
} | } | ||||
CoinControlDialog::updateLabels(model, this); | CoinControlDialog::updateLabels(model, this); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | void CoinControlDialog::copyLabel() { | ||||
else | else | ||||
GUIUtil::setClipboard(contextMenuItem->text(COLUMN_LABEL)); | GUIUtil::setClipboard(contextMenuItem->text(COLUMN_LABEL)); | ||||
} | } | ||||
// context menu action: copy address | // context menu action: copy address | ||||
void CoinControlDialog::copyAddress() { | void CoinControlDialog::copyAddress() { | ||||
if (ui->radioTreeMode->isChecked() && | if (ui->radioTreeMode->isChecked() && | ||||
contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && | contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && | ||||
contextMenuItem->parent()) | contextMenuItem->parent()) { | ||||
GUIUtil::setClipboard(contextMenuItem->parent()->text(COLUMN_ADDRESS)); | GUIUtil::setClipboard(contextMenuItem->parent()->text(COLUMN_ADDRESS)); | ||||
else | } else { | ||||
GUIUtil::setClipboard(contextMenuItem->text(COLUMN_ADDRESS)); | GUIUtil::setClipboard(contextMenuItem->text(COLUMN_ADDRESS)); | ||||
} | } | ||||
} | |||||
// context menu action: copy transaction id | // context menu action: copy transaction id | ||||
void CoinControlDialog::copyTransactionHash() { | void CoinControlDialog::copyTransactionHash() { | ||||
GUIUtil::setClipboard(contextMenuItem->text(COLUMN_TXHASH)); | GUIUtil::setClipboard(contextMenuItem->text(COLUMN_TXHASH)); | ||||
} | } | ||||
// context menu action: lock coin | // context menu action: lock coin | ||||
void CoinControlDialog::lockCoin() { | void CoinControlDialog::lockCoin() { | ||||
if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) | if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) { | ||||
contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); | ||||
} | |||||
COutPoint outpt( | COutPoint outpt( | ||||
uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), | uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), | ||||
contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); | contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); | ||||
model->lockCoin(outpt); | model->lockCoin(outpt); | ||||
contextMenuItem->setDisabled(true); | contextMenuItem->setDisabled(true); | ||||
contextMenuItem->setIcon( | contextMenuItem->setIcon( | ||||
COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); | COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
// treeview: clicked on header | // treeview: clicked on header | ||||
void CoinControlDialog::headerSectionClicked(int logicalIndex) { | void CoinControlDialog::headerSectionClicked(int logicalIndex) { | ||||
// click on most left column -> do nothing | // click on most left column -> do nothing | ||||
if (logicalIndex == COLUMN_CHECKBOX) { | if (logicalIndex == COLUMN_CHECKBOX) { | ||||
ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); | ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); | ||||
} else { | } else { | ||||
if (sortColumn == logicalIndex) | if (sortColumn == logicalIndex) { | ||||
sortOrder = | sortOrder = | ||||
((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder | ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder | ||||
: Qt::AscendingOrder); | : Qt::AscendingOrder); | ||||
else { | } else { | ||||
sortColumn = logicalIndex; | sortColumn = logicalIndex; | ||||
// if label or address then default => asc, else default => desc | // if label or address then default => asc, else default => desc | ||||
sortOrder = | sortOrder = | ||||
((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) | ((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) | ||||
? Qt::AscendingOrder | ? Qt::AscendingOrder | ||||
: Qt::DescendingOrder); | : Qt::DescendingOrder); | ||||
} | } | ||||
sortView(sortColumn, sortOrder); | sortView(sortColumn, sortOrder); | ||||
} | } | ||||
} | } | ||||
// toggle tree mode | // toggle tree mode | ||||
void CoinControlDialog::radioTreeMode(bool checked) { | void CoinControlDialog::radioTreeMode(bool checked) { | ||||
if (checked && model) updateView(); | if (checked && model) { | ||||
updateView(); | |||||
} | |||||
} | } | ||||
// toggle list mode | // toggle list mode | ||||
void CoinControlDialog::radioListMode(bool checked) { | void CoinControlDialog::radioListMode(bool checked) { | ||||
if (checked && model) updateView(); | if (checked && model) { | ||||
updateView(); | |||||
} | |||||
} | } | ||||
// checkbox clicked by user | // checkbox clicked by user | ||||
void CoinControlDialog::viewItemChanged(QTreeWidgetItem *item, int column) { | void CoinControlDialog::viewItemChanged(QTreeWidgetItem *item, int column) { | ||||
// transaction hash is 64 characters (this means its a child node, so its | // transaction hash is 64 characters (this means its a child node, so its | ||||
// not a parent node in tree mode) | // not a parent node in tree mode) | ||||
if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) { | if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) { | ||||
COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), | COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), | ||||
Show All 15 Lines | if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) { | ||||
} | } | ||||
} | } | ||||
// TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used. | // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used. | ||||
// Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473 | // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473 | ||||
#if QT_VERSION >= 0x050000 | #if QT_VERSION >= 0x050000 | ||||
else if (column == COLUMN_CHECKBOX && item->childCount() > 0) { | else if (column == COLUMN_CHECKBOX && item->childCount() > 0) { | ||||
if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && | if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && | ||||
item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked) | item->child(0)->checkState(COLUMN_CHECKBOX) == | ||||
Qt::PartiallyChecked) { | |||||
item->setCheckState(COLUMN_CHECKBOX, Qt::Checked); | item->setCheckState(COLUMN_CHECKBOX, Qt::Checked); | ||||
} | } | ||||
} | |||||
#endif | #endif | ||||
} | } | ||||
// shows count of locked unspent outputs | // shows count of locked unspent outputs | ||||
void CoinControlDialog::updateLabelLocked() { | void CoinControlDialog::updateLabelLocked() { | ||||
std::vector<COutPoint> vOutpts; | std::vector<COutPoint> vOutpts; | ||||
model->listLockedCoins(vOutpts); | model->listLockedCoins(vOutpts); | ||||
if (vOutpts.size() > 0) { | if (vOutpts.size() > 0) { | ||||
ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size())); | ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size())); | ||||
ui->labelLocked->setVisible(true); | ui->labelLocked->setVisible(true); | ||||
} else | } else { | ||||
ui->labelLocked->setVisible(false); | ui->labelLocked->setVisible(false); | ||||
} | } | ||||
} | |||||
void CoinControlDialog::updateLabels(WalletModel *model, QDialog *dialog) { | void CoinControlDialog::updateLabels(WalletModel *model, QDialog *dialog) { | ||||
if (!model) return; | if (!model) { | ||||
return; | |||||
} | |||||
// nPayAmount | // nPayAmount | ||||
Amount nPayAmount(0); | Amount nPayAmount(0); | ||||
bool fDust = false; | bool fDust = false; | ||||
CMutableTransaction txDummy; | CMutableTransaction txDummy; | ||||
for (const Amount amount : CoinControlDialog::payAmounts) { | for (const Amount amount : CoinControlDialog::payAmounts) { | ||||
nPayAmount += amount; | nPayAmount += amount; | ||||
if (amount > Amount(0)) { | if (amount > Amount(0)) { | ||||
CTxOut txout(Amount(amount), (CScript)std::vector<uint8_t>(24, 0)); | CTxOut txout(Amount(amount), (CScript)std::vector<uint8_t>(24, 0)); | ||||
txDummy.vout.push_back(txout); | txDummy.vout.push_back(txout); | ||||
if (txout.IsDust(dustRelayFee)) fDust = true; | if (txout.IsDust(dustRelayFee)) { | ||||
fDust = true; | |||||
} | |||||
} | } | ||||
} | } | ||||
Amount nAmount(0); | Amount nAmount(0); | ||||
Amount nPayFee(0); | Amount nPayFee(0); | ||||
Amount nAfterFee(0); | Amount nAfterFee(0); | ||||
Amount nChange(0); | Amount nChange(0); | ||||
unsigned int nBytes = 0; | unsigned int nBytes = 0; | ||||
Show All 24 Lines | for (const COutput &out : vOutputs) { | ||||
// Bytes | // Bytes | ||||
CTxDestination address; | CTxDestination address; | ||||
if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { | if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) { | ||||
CPubKey pubkey; | CPubKey pubkey; | ||||
CKeyID *keyid = boost::get<CKeyID>(&address); | CKeyID *keyid = boost::get<CKeyID>(&address); | ||||
if (keyid && model->getPubKey(*keyid, pubkey)) { | if (keyid && model->getPubKey(*keyid, pubkey)) { | ||||
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); | nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); | ||||
if (!pubkey.IsCompressed()) nQuantityUncompressed++; | if (!pubkey.IsCompressed()) { | ||||
nQuantityUncompressed++; | |||||
} | |||||
} else { | } else { | ||||
// in all error cases, simply assume 148 here | // in all error cases, simply assume 148 here | ||||
nBytesInputs += 148; | nBytesInputs += 148; | ||||
} | } | ||||
} else | } else { | ||||
nBytesInputs += 148; | nBytesInputs += 148; | ||||
} | } | ||||
} | |||||
// calculation | // calculation | ||||
if (nQuantity > 0) { | if (nQuantity > 0) { | ||||
// Bytes | // Bytes | ||||
// always assume +1 output for change here | // always assume +1 output for change here | ||||
nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 | nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 | ||||
? CoinControlDialog::payAmounts.size() + 1 | ? CoinControlDialog::payAmounts.size() + 1 | ||||
: 2) * | : 2) * | ||||
Show All 12 Lines | if (nQuantity > 0) { | ||||
// Fee | // Fee | ||||
nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); | nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool); | ||||
if (nPayFee > Amount(0) && coinControl->nMinimumTotalFee > nPayFee) { | if (nPayFee > Amount(0) && coinControl->nMinimumTotalFee > nPayFee) { | ||||
nPayFee = coinControl->nMinimumTotalFee; | nPayFee = coinControl->nMinimumTotalFee; | ||||
} | } | ||||
if (nPayAmount > Amount(0)) { | if (nPayAmount > Amount(0)) { | ||||
nChange = nAmount - nPayAmount; | nChange = nAmount - nPayAmount; | ||||
if (!CoinControlDialog::fSubtractFeeFromAmount) nChange -= nPayFee; | if (!CoinControlDialog::fSubtractFeeFromAmount) { | ||||
nChange -= nPayFee; | |||||
} | |||||
// Never create dust outputs; if we would, just add the dust to the | // Never create dust outputs; if we would, just add the dust to the | ||||
// fee. | // fee. | ||||
if (nChange > Amount(0) && nChange < MIN_CHANGE) { | if (nChange > Amount(0) && nChange < MIN_CHANGE) { | ||||
CTxOut txout(nChange, (CScript)std::vector<uint8_t>(24, 0)); | CTxOut txout(nChange, (CScript)std::vector<uint8_t>(24, 0)); | ||||
if (txout.IsDust(dustRelayFee)) { | if (txout.IsDust(dustRelayFee)) { | ||||
// dust-change will be raised until no dust | // dust-change will be raised until no dust | ||||
if (CoinControlDialog::fSubtractFeeFromAmount) { | if (CoinControlDialog::fSubtractFeeFromAmount) { | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | for (const std::pair<QString, std::vector<COutput>> &coins : mapCoins) { | ||||
QString sAddress = ""; | QString sAddress = ""; | ||||
if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, | if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, | ||||
outputAddress)) { | outputAddress)) { | ||||
sAddress = | sAddress = | ||||
QString::fromStdString(EncodeDestination(outputAddress)); | QString::fromStdString(EncodeDestination(outputAddress)); | ||||
// if listMode or change => show bitcoin address. In tree mode, | // if listMode or change => show bitcoin address. In tree mode, | ||||
// address is not shown again for direct wallet address outputs | // address is not shown again for direct wallet address outputs | ||||
if (!treeMode || (!(sAddress == sWalletAddress))) | if (!treeMode || (!(sAddress == sWalletAddress))) { | ||||
itemOutput->setText(COLUMN_ADDRESS, sAddress); | itemOutput->setText(COLUMN_ADDRESS, sAddress); | ||||
} | } | ||||
} | |||||
// label | // label | ||||
if (!(sAddress == sWalletAddress)) { | if (!(sAddress == sWalletAddress)) { | ||||
// change tooltip from where the change comes from | // change tooltip from where the change comes from | ||||
itemOutput->setToolTip(COLUMN_LABEL, | itemOutput->setToolTip(COLUMN_LABEL, | ||||
tr("change from %1 (%2)") | tr("change from %1 (%2)") | ||||
.arg(sWalletLabel) | .arg(sWalletLabel) | ||||
.arg(sWalletAddress)); | .arg(sWalletAddress)); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | for (const std::pair<QString, std::vector<COutput>> &coins : mapCoins) { | ||||
COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); | COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); | ||||
itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, | itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, | ||||
QVariant((qlonglong)nSum.GetSatoshis())); | QVariant((qlonglong)nSum.GetSatoshis())); | ||||
} | } | ||||
} | } | ||||
// expand all partially selected | // expand all partially selected | ||||
if (treeMode) { | if (treeMode) { | ||||
for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) | for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { | ||||
if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == | if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == | ||||
Qt::PartiallyChecked) | Qt::PartiallyChecked) | ||||
ui->treeWidget->topLevelItem(i)->setExpanded(true); | ui->treeWidget->topLevelItem(i)->setExpanded(true); | ||||
} | } | ||||
} | |||||
// sort view | // sort view | ||||
sortView(sortColumn, sortOrder); | sortView(sortColumn, sortOrder); | ||||
ui->treeWidget->setEnabled(true); | ui->treeWidget->setEnabled(true); | ||||
} | } |