aboutsummaryrefslogtreecommitdiff
path: root/src/qt
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt')
-rw-r--r--src/qt/README.md12
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/addresstablemodel.cpp34
-rw-r--r--src/qt/addresstablemodel.h9
-rw-r--r--src/qt/bitcoin.cpp4
-rw-r--r--src/qt/bitcoingui.cpp5
-rw-r--r--src/qt/coincontroldialog.cpp2
-rw-r--r--src/qt/editaddressdialog.cpp21
-rw-r--r--src/qt/editaddressdialog.h5
-rw-r--r--src/qt/optionsmodel.cpp23
-rw-r--r--src/qt/sendcoinsdialog.cpp14
-rw-r--r--src/qt/test/addressbooktests.cpp143
-rw-r--r--src/qt/test/addressbooktests.h15
-rw-r--r--src/qt/test/test_main.cpp5
-rw-r--r--src/qt/test/util.cpp22
-rw-r--r--src/qt/test/util.h12
-rw-r--r--src/qt/test/wallettests.cpp24
-rw-r--r--src/qt/transactiondesc.cpp10
-rw-r--r--src/qt/walletmodel.cpp5
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/qt/walletview.cpp11
21 files changed, 320 insertions, 60 deletions
diff --git a/src/qt/README.md b/src/qt/README.md
index 7ffea98170..d8acf96ceb 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -1,6 +1,6 @@
-This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross platform framework [QT](https://www1.qt.io/developers/).
+This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross-platform framework [Qt](https://www1.qt.io/developers/).
-The current precise version for QT 5 is specified in [qt.mk](/depends/packages/qt.mk). QT 4 is also supported (see [#8263](https://github.com/bitcoin/bitcoin/issues/8263)).
+The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/qt.mk). Qt 4 is also supported (see [#8263](https://github.com/bitcoin/bitcoin/issues/8263)).
## Compile and run
@@ -16,7 +16,7 @@ To run:
### forms
-Contains [Designer UI](http://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#use-qt-Creator-as IDE), but can be edited using any text editor.
+Contains [Designer UI](http://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#using-qt-creator-as-ide), but can be edited using any text editor.
### locale
@@ -36,7 +36,7 @@ Represents the main window of the Bitcoin UI.
### \*model.(h/cpp)
-The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](http://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other QT classes like [QValidator](http://doc.qt.io/qt-5/qvalidator.html).
+The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](http://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](http://doc.qt.io/qt-5/qvalidator.html).
ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`.
@@ -69,7 +69,7 @@ Represents the view to a single wallet.
## Contribute
-See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. Specifically for QT:
+See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. Specifically for Qt:
* don't change `local/bitcoin_en.ts`; this happens [automatically](/doc/translation_process.md#writing-code-with-translations)
@@ -83,7 +83,7 @@ Uncheck everything except Qt Creator during the installation process.
Instructions for OSX:
-1. Make sure you installed everything through Homebrew mentioned in the [OSX build instructions](/docs/build-osx.md)
+1. Make sure you installed everything through Homebrew mentioned in the [OSX build instructions](/doc/build-osx.md)
2. Use `./configure` with the `--enable-debug` flag
3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project
4. Enter "bitcoin-qt" as project name, enter src/qt as location
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index 8877d07330..ba420c5e15 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -38,7 +38,7 @@ public:
ForEditing /**< Open address book for editing */
};
- explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent);
+ explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent = 0);
~AddressBookPage();
void setModel(AddressTableModel *model);
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index b6ecd40e81..25b615e6f8 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -266,7 +266,8 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
}
// Check for duplicate addresses to prevent accidental deletion of addresses, if you try
// to paste an existing address over another address (with a different label)
- if (walletModel->wallet().getAddress(newAddress))
+ if (walletModel->wallet().getAddress(
+ newAddress, /* name= */ nullptr, /* is_mine= */ nullptr, /* purpose= */ nullptr))
{
editStatus = DUPLICATE_ADDRESS;
return false;
@@ -351,7 +352,8 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
}
// Check for duplicate addresses
{
- if(walletModel->wallet().getAddress(DecodeDestination(strAddress)))
+ if (walletModel->wallet().getAddress(
+ DecodeDestination(strAddress), /* name= */ nullptr, /* is_mine= */ nullptr, /* purpose= */ nullptr))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
@@ -405,21 +407,31 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
return true;
}
-/* Look up label for address in address book, if not found return empty string.
- */
QString AddressTableModel::labelForAddress(const QString &address) const
{
- {
- CTxDestination destination = DecodeDestination(address.toStdString());
- std::string name;
- if (walletModel->wallet().getAddress(destination, &name))
- {
- return QString::fromStdString(name);
- }
+ std::string name;
+ if (getAddressData(address, &name, /* purpose= */ nullptr)) {
+ return QString::fromStdString(name);
+ }
+ return QString();
+}
+
+QString AddressTableModel::purposeForAddress(const QString &address) const
+{
+ std::string purpose;
+ if (getAddressData(address, /* name= */ nullptr, &purpose)) {
+ return QString::fromStdString(purpose);
}
return QString();
}
+bool AddressTableModel::getAddressData(const QString &address,
+ std::string* name,
+ std::string* purpose) const {
+ CTxDestination destination = DecodeDestination(address.toStdString());
+ return walletModel->wallet().getAddress(destination, name, /* is_mine= */ nullptr, purpose);
+}
+
int AddressTableModel::lookupAddress(const QString &address) const
{
QModelIndexList lst = match(index(0, Address, QModelIndex()),
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 0c4d585d51..6e1b53b049 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -67,10 +67,12 @@ public:
*/
QString addRow(const QString &type, const QString &label, const QString &address, const OutputType address_type);
- /* Look up label for address in address book, if not found return empty string.
- */
+ /** Look up label for address in address book, if not found return empty string. */
QString labelForAddress(const QString &address) const;
+ /** Look up purpose for address in address book, if not found return empty string. */
+ QString purposeForAddress(const QString &address) const;
+
/* Look up row index of an address in the model.
Return -1 if not found.
*/
@@ -86,6 +88,9 @@ private:
QStringList columns;
EditStatus editStatus = OK;
+ /** Look up address book data given an address string. */
+ bool getAddressData(const QString &address, std::string* name, std::string* purpose) const;
+
/** Notify listeners that data changed. */
void emitDataChanged(int index);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 599c3c0985..57fe4552a1 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -403,6 +403,10 @@ void BitcoinApplication::startThread()
void BitcoinApplication::parameterSetup()
{
+ // Default printtoconsole to false for the GUI. GUI programs should not
+ // print to the console unnecessarily.
+ gArgs.SoftSetBoolArg("-printtoconsole", false);
+
m_node.initLogging();
m_node.initParameterInteraction();
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index bfa8844a09..aed5374a7d 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -968,6 +968,11 @@ void BitcoinGUI::changeEvent(QEvent *e)
QTimer::singleShot(0, this, SLOT(hide()));
e->ignore();
}
+ else if((wsevt->oldState() & Qt::WindowMinimized) && !isMinimized())
+ {
+ QTimer::singleShot(0, this, SLOT(show()));
+ e->ignore();
+ }
}
}
#endif
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 601a77fc85..b08de27041 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -509,7 +509,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = model->node().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */);
+ nPayFee = model->wallet().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */);
if (nPayAmount > 0)
{
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index 38411c499f..f26a31158e 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -109,7 +109,7 @@ void EditAddressDialog::accept()
break;
case AddressTableModel::DUPLICATE_ADDRESS:
QMessageBox::warning(this, windowTitle(),
- tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()),
+ getDuplicateAddressWarning(),
QMessageBox::Ok, QMessageBox::Ok);
break;
case AddressTableModel::WALLET_UNLOCK_FAILURE:
@@ -129,6 +129,25 @@ void EditAddressDialog::accept()
QDialog::accept();
}
+QString EditAddressDialog::getDuplicateAddressWarning() const
+{
+ QString dup_address = ui->addressEdit->text();
+ QString existing_label = model->labelForAddress(dup_address);
+ QString existing_purpose = model->purposeForAddress(dup_address);
+
+ if (existing_purpose == "receive" &&
+ (mode == NewSendingAddress || mode == EditSendingAddress)) {
+ return tr(
+ "Address \"%1\" already exists as a receiving address with label "
+ "\"%2\" and so cannot be added as a sending address."
+ ).arg(dup_address).arg(existing_label);
+ }
+ return tr(
+ "The entered address \"%1\" is already in the address book with "
+ "label \"%2\"."
+ ).arg(dup_address).arg(existing_label);
+}
+
QString EditAddressDialog::getAddress() const
{
return address;
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index 41c5d1708a..3aba74bf08 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -30,7 +30,7 @@ public:
EditSendingAddress
};
- explicit EditAddressDialog(Mode mode, QWidget *parent);
+ explicit EditAddressDialog(Mode mode, QWidget *parent = 0);
~EditAddressDialog();
void setModel(AddressTableModel *model);
@@ -45,6 +45,9 @@ public Q_SLOTS:
private:
bool saveCurrentRow();
+ /** Return a descriptive string when adding an already-existing address fails. */
+ QString getDuplicateAddressWarning() const;
+
Ui::EditAddressDialog *ui;
QDataWidgetMapper *mapper;
Mode mode;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 30c8124c58..cae9dace4c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -24,6 +24,8 @@
const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
+static const QString GetDefaultProxyAddress();
+
OptionsModel::OptionsModel(interfaces::Node& node, QObject *parent, bool resetSettings) :
QAbstractListModel(parent), m_node(node)
{
@@ -121,7 +123,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseProxy"))
settings.setValue("fUseProxy", false);
if (!settings.contains("addrProxy"))
- settings.setValue("addrProxy", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
+ settings.setValue("addrProxy", GetDefaultProxyAddress());
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !m_node.softSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
addOverriddenOption("-proxy");
@@ -131,7 +133,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("fUseSeparateProxyTor"))
settings.setValue("fUseSeparateProxyTor", false);
if (!settings.contains("addrSeparateProxyTor"))
- settings.setValue("addrSeparateProxyTor", QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST, DEFAULT_GUI_PROXY_PORT));
+ settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
// Only try to set -onion, if user has enabled fUseSeparateProxyTor
if (settings.value("fUseSeparateProxyTor").toBool() && !m_node.softSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
addOverriddenOption("-onion");
@@ -223,6 +225,11 @@ static void SetProxySetting(QSettings &settings, const QString &name, const Prox
settings.setValue(name, ip_port.ip + ":" + ip_port.port);
}
+static const QString GetDefaultProxyAddress()
+{
+ return QString("%1:%2").arg(DEFAULT_GUI_PROXY_HOST).arg(DEFAULT_GUI_PROXY_PORT);
+}
+
// read QSettings values and return them
QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
@@ -485,4 +492,16 @@ void OptionsModel::checkAndMigrate()
settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
}
+
+ // Overwrite the 'addrProxy' setting in case it has been set to an illegal
+ // default value (see issue #12623; PR #12650).
+ if (settings.contains("addrProxy") && settings.value("addrProxy").toString().endsWith("%2")) {
+ settings.setValue("addrProxy", GetDefaultProxyAddress());
+ }
+
+ // Overwrite the 'addrSeparateProxyTor' setting in case it has been set to an illegal
+ // default value (see issue #12623; PR #12650).
+ if (settings.contains("addrSeparateProxyTor") && settings.value("addrSeparateProxyTor").toString().endsWith("%2")) {
+ settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
+ }
}
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 0874a0ada4..261ab7a948 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -114,7 +114,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
if (!settings.contains("nSmartFeeSliderPosition"))
settings.setValue("nSmartFeeSliderPosition", 0);
if (!settings.contains("nTransactionFee"))
- settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
+ settings.setValue("nTransactionFee", (qint64)DEFAULT_PAY_TX_FEE);
if (!settings.contains("fPayOnlyMinFee"))
settings.setValue("fPayOnlyMinFee", false);
ui->groupFee->setId(ui->radioSmartFee, 0);
@@ -175,7 +175,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(model->node().getRequiredFee(1000));
+ ui->customFee->setSingleStep(model->wallet().getRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
@@ -193,7 +193,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
settings.remove("nSmartFeeSliderPosition");
}
if (settings.value("nConfTarget").toInt() == 0)
- ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->node().getTxConfirmTarget()));
+ ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(model->wallet().getConfirmTarget()));
else
ui->confTargetSelector->setCurrentIndex(getIndexForConfTarget(settings.value("nConfTarget").toInt()));
}
@@ -629,7 +629,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
void SendCoinsDialog::setMinimumFee()
{
- ui->customFee->setValue(model->node().getRequiredFee(1000));
+ ui->customFee->setValue(model->wallet().getRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
@@ -661,7 +661,7 @@ void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getRequiredFee(1000)) + "/kB")
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getRequiredFee(1000)) + "/kB")
);
}
@@ -675,7 +675,7 @@ void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
// Avoid using global defaults when sending money from the GUI
// Either custom fee will be used or if not selected, the confirmation target from dropdown box
ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
- ctrl.signalRbf = ui->optInRBF->isChecked();
+ ctrl.m_signal_bip125_rbf = ui->optInRBF->isChecked();
}
void SendCoinsDialog::updateSmartFeeLabel()
@@ -687,7 +687,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
int returned_target;
FeeReason reason;
- CFeeRate feeRate = CFeeRate(model->node().getMinimumFee(1000, coin_control, &returned_target, &reason));
+ CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, coin_control, &returned_target, &reason));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
new file mode 100644
index 0000000000..0c2e7ae71d
--- /dev/null
+++ b/src/qt/test/addressbooktests.cpp
@@ -0,0 +1,143 @@
+#include <qt/test/addressbooktests.h>
+#include <qt/test/util.h>
+#include <test/test_bitcoin.h>
+
+#include <interfaces/node.h>
+#include <qt/addressbookpage.h>
+#include <qt/addresstablemodel.h>
+#include <qt/editaddressdialog.h>
+#include <qt/callback.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/qvalidatedlineedit.h>
+#include <qt/walletmodel.h>
+
+#include <key.h>
+#include <pubkey.h>
+#include <key_io.h>
+#include <wallet/wallet.h>
+
+#include <QTimer>
+#include <QMessageBox>
+
+namespace
+{
+
+/**
+ * Fill the edit address dialog box with data, submit it, and ensure that
+ * the resulting message meets expectations.
+ */
+void EditAddressAndSubmit(
+ EditAddressDialog* dialog,
+ const QString& label, const QString& address, QString expected_msg)
+{
+ QString warning_text;
+
+ dialog->findChild<QLineEdit*>("labelEdit")->setText(label);
+ dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address);
+
+ ConfirmMessage(&warning_text, 5);
+ dialog->accept();
+ QCOMPARE(warning_text, expected_msg);
+}
+
+/**
+ * Test adding various send addresses to the address book.
+ *
+ * There are three cases tested:
+ *
+ * - new_address: a new address which should add as a send address successfully.
+ * - existing_s_address: an existing sending address which won't add successfully.
+ * - existing_r_address: an existing receiving address which won't add successfully.
+ *
+ * In each case, verify the resulting state of the address book and optionally
+ * the warning message presented to the user.
+ */
+void TestAddAddressesToSendBook()
+{
+ TestChain100Setup test;
+ CWallet wallet("mock", WalletDatabase::CreateMock());
+ bool firstRun;
+ wallet.LoadWallet(firstRun);
+
+ auto build_address = [&wallet]() {
+ CKey key;
+ key.MakeNewKey(true);
+ CTxDestination dest(GetDestinationForKey(
+ key.GetPubKey(), wallet.m_default_address_type));
+
+ return std::make_pair(dest, QString::fromStdString(EncodeDestination(dest)));
+ };
+
+ CTxDestination r_key_dest, s_key_dest;
+
+ // Add a preexisting "receive" entry in the address book.
+ QString preexisting_r_address;
+ QString r_label("already here (r)");
+
+ // Add a preexisting "send" entry in the address book.
+ QString preexisting_s_address;
+ QString s_label("already here (s)");
+
+ // Define a new address (which should add to the address book successfully).
+ QString new_address;
+
+ std::tie(r_key_dest, preexisting_r_address) = build_address();
+ std::tie(s_key_dest, preexisting_s_address) = build_address();
+ std::tie(std::ignore, new_address) = build_address();
+
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetAddressBook(r_key_dest, r_label.toStdString(), "receive");
+ wallet.SetAddressBook(s_key_dest, s_label.toStdString(), "send");
+ }
+
+ auto check_addbook_size = [&wallet](int expected_size) {
+ QCOMPARE(static_cast<int>(wallet.mapAddressBook.size()), expected_size);
+ };
+
+ // We should start with the two addresses we added earlier and nothing else.
+ check_addbook_size(2);
+
+ // Initialize relevant QT models.
+ std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
+ auto node = interfaces::MakeNode();
+ OptionsModel optionsModel(*node);
+ AddWallet(&wallet);
+ WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel);
+ RemoveWallet(&wallet);
+ EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress);
+ editAddressDialog.setModel(walletModel.getAddressTableModel());
+
+ EditAddressAndSubmit(
+ &editAddressDialog, QString("uhoh"), preexisting_r_address,
+ QString(
+ "Address \"%1\" already exists as a receiving address with label "
+ "\"%2\" and so cannot be added as a sending address."
+ ).arg(preexisting_r_address).arg(r_label));
+
+ check_addbook_size(2);
+
+ EditAddressAndSubmit(
+ &editAddressDialog, QString("uhoh, different"), preexisting_s_address,
+ QString(
+ "The entered address \"%1\" is already in the address book with "
+ "label \"%2\"."
+ ).arg(preexisting_s_address).arg(s_label));
+
+ check_addbook_size(2);
+
+ // Submit a new address which should add successfully - we expect the
+ // warning message to be blank.
+ EditAddressAndSubmit(
+ &editAddressDialog, QString("new"), new_address, QString(""));
+
+ check_addbook_size(3);
+}
+
+} // namespace
+
+void AddressBookTests::addressBookTests()
+{
+ TestAddAddressesToSendBook();
+}
diff --git a/src/qt/test/addressbooktests.h b/src/qt/test/addressbooktests.h
new file mode 100644
index 0000000000..beeb9e76a9
--- /dev/null
+++ b/src/qt/test/addressbooktests.h
@@ -0,0 +1,15 @@
+#ifndef BITCOIN_QT_TEST_ADDRESSBOOKTESTS_H
+#define BITCOIN_QT_TEST_ADDRESSBOOKTESTS_H
+
+#include <QObject>
+#include <QTest>
+
+class AddressBookTests : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void addressBookTests();
+};
+
+#endif // BITCOIN_QT_TEST_ADDRESSBOOKTESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 25ee66dc6b..56d4d3e457 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -13,6 +13,7 @@
#include <qt/test/compattests.h>
#ifdef ENABLE_WALLET
+#include <qt/test/addressbooktests.h>
#include <qt/test/paymentservertests.h>
#include <qt/test/wallettests.h>
#endif
@@ -99,6 +100,10 @@ int main(int argc, char *argv[])
if (QTest::qExec(&test5) != 0) {
fInvalid = true;
}
+ AddressBookTests test6;
+ if (QTest::qExec(&test6) != 0) {
+ fInvalid = true;
+ }
#endif
fs::remove_all(pathTemp);
diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp
new file mode 100644
index 0000000000..261caaaee5
--- /dev/null
+++ b/src/qt/test/util.cpp
@@ -0,0 +1,22 @@
+#include <qt/callback.h>
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QTimer>
+#include <QString>
+#include <QPushButton>
+#include <QWidget>
+
+void ConfirmMessage(QString* text, int msec)
+{
+ QTimer::singleShot(msec, makeCallback([text](Callback* callback) {
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("QMessageBox")) {
+ QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
+ if (text) *text = messageBox->text();
+ messageBox->defaultButton()->click();
+ }
+ }
+ delete callback;
+ }), SLOT(call()));
+}
diff --git a/src/qt/test/util.h b/src/qt/test/util.h
new file mode 100644
index 0000000000..324386c139
--- /dev/null
+++ b/src/qt/test/util.h
@@ -0,0 +1,12 @@
+#ifndef BITCOIN_QT_TEST_UTIL_H
+#define BITCOIN_QT_TEST_UTIL_H
+
+/**
+ * Press "Ok" button in message box dialog.
+ *
+ * @param text - Optionally store dialog text.
+ * @param msec - Number of miliseconds to pause before triggering the callback.
+ */
+void ConfirmMessage(QString* text = nullptr, int msec = 0);
+
+#endif // BITCOIN_QT_TEST_UTIL_H
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index dcc834c352..a09d98dfe5 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,4 +1,5 @@
#include <qt/test/wallettests.h>
+#include <qt/test/util.h>
#include <interfaces/node.h>
#include <qt/bitcoinamountfield.h>
@@ -35,21 +36,6 @@
namespace
{
-//! Press "Ok" button in message box dialog.
-void ConfirmMessage(QString* text = nullptr)
-{
- QTimer::singleShot(0, makeCallback([text](Callback* callback) {
- for (QWidget* widget : QApplication::topLevelWidgets()) {
- if (widget->inherits("QMessageBox")) {
- QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
- if (text) *text = messageBox->text();
- messageBox->defaultButton()->click();
- }
- }
- delete callback;
- }), SLOT(call()));
-}
-
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString* text = nullptr, bool cancel = false)
{
@@ -180,9 +166,9 @@ void TestGUI()
TransactionView transactionView(platformStyle.get());
auto node = interfaces::MakeNode();
OptionsModel optionsModel(*node);
- vpwallets.insert(vpwallets.begin(), &wallet);
- WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel);
- vpwallets.erase(vpwallets.begin());
+ AddWallet(&wallet);
+ WalletModel walletModel(std::move(node->getWallets().back()), *node, platformStyle.get(), &optionsModel);
+ RemoveWallet(&wallet);
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
@@ -264,7 +250,7 @@ void TestGUI()
QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
}
-}
+} // namespace
void WalletTests::walletTests()
{
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index f316c3ca45..2cb446c459 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -102,7 +102,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
if (IsValidDestination(address)) {
std::string name;
isminetype ismine;
- if (wallet.getAddress(address, &name, &ismine))
+ if (wallet.getAddress(address, &name, &ismine, /* purpose= */ nullptr))
{
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
strHTML += "<b>" + tr("To") + ":</b> ";
@@ -128,7 +128,8 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += "<b>" + tr("To") + ":</b> ";
CTxDestination dest = DecodeDestination(strAddress);
std::string name;
- if (wallet.getAddress(dest, &name) && !name.empty())
+ if (wallet.getAddress(
+ dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
strHTML += GUIUtil::HtmlEscape(name) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
}
@@ -196,7 +197,8 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
{
strHTML += "<b>" + tr("To") + ":</b> ";
std::string name;
- if (wallet.getAddress(address, &name) && !name.empty())
+ if (wallet.getAddress(
+ address, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
strHTML += GUIUtil::HtmlEscape(name) + " ";
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
@@ -319,7 +321,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
if (ExtractDestination(vout.scriptPubKey, address))
{
std::string name;
- if (wallet.getAddress(address, &name) && !name.empty())
+ if (wallet.getAddress(address, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
strHTML += GUIUtil::HtmlEscape(name) + " ";
strHTML += QString::fromStdString(EncodeDestination(address));
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 00b98901c0..3418b1f1a9 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -274,7 +274,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
{
// Check if we have a new address or an updated label
std::string name;
- if (!m_wallet->getAddress(dest, &name))
+ if (!m_wallet->getAddress(
+ dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr))
{
m_wallet->setAddressBook(dest, strLabel, "send");
}
@@ -486,7 +487,7 @@ bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t
bool WalletModel::bumpFee(uint256 hash)
{
CCoinControl coin_control;
- coin_control.signalRbf = true;
+ coin_control.m_signal_bip125_rbf = true;
std::vector<std::string> errors;
CAmount old_fee;
CAmount new_fee;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index e5ed5b4e82..9173fcae52 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -204,6 +204,8 @@ public:
QString getWalletName() const;
bool isMultiwallet();
+
+ AddressTableModel* getAddressTableModel() const { return addressTableModel; }
private:
std::unique_ptr<interfaces::Wallet> m_wallet;
std::unique_ptr<interfaces::Handler> m_handler_status_changed;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 8b9b85c8c9..d529595dec 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -315,9 +315,9 @@ void WalletView::showProgress(const QString &title, int nProgress)
progressDialog = new QProgressDialog(title, "", 0, 100);
progressDialog->setWindowModality(Qt::ApplicationModal);
progressDialog->setMinimumDuration(0);
- progressDialog->setCancelButton(0);
progressDialog->setAutoClose(false);
progressDialog->setValue(0);
+ progressDialog->setCancelButtonText(tr("Cancel"));
}
else if (nProgress == 100)
{
@@ -327,8 +327,13 @@ void WalletView::showProgress(const QString &title, int nProgress)
progressDialog->deleteLater();
}
}
- else if (progressDialog)
- progressDialog->setValue(nProgress);
+ else if (progressDialog) {
+ if (progressDialog->wasCanceled()) {
+ getWalletModel()->wallet().abortRescan();
+ } else {
+ progressDialog->setValue(nProgress);
+ }
+ }
}
void WalletView::requestedSyncWarningInfo()