diff options
Diffstat (limited to 'src/qt')
32 files changed, 707 insertions, 243 deletions
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index a89a15bc9d..c9f17d12ec 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -18,12 +18,13 @@ #include <QMessageBox> #include <QPushButton> -AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : +AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) : QDialog(parent), ui(new Ui::AskPassphraseDialog), mode(_mode), model(nullptr), - fCapsLock(false) + fCapsLock(false), + m_passphrase_out(passphrase_out) { ui->setupUi(this); @@ -90,7 +91,7 @@ void AskPassphraseDialog::setModel(WalletModel *_model) void AskPassphraseDialog::accept() { SecureString oldpass, newpass1, newpass2; - if(!model) + if (!model && mode != Encrypt) return; oldpass.reserve(MAX_PASSPHRASE_SIZE); newpass1.reserve(MAX_PASSPHRASE_SIZE); @@ -119,24 +120,33 @@ void AskPassphraseDialog::accept() { if(newpass1 == newpass2) { - if(model->setWalletEncrypted(true, newpass1)) - { - QMessageBox::warning(this, tr("Wallet encrypted"), + QString encryption_reminder = tr("Remember that encrypting your wallet cannot fully protect " + "your bitcoins from being stolen by malware infecting your computer."); + if (m_passphrase_out) { + m_passphrase_out->assign(newpass1); + QMessageBox::warning(this, tr("Wallet to be encrypted"), "<qt>" + - tr("Your wallet is now encrypted. " - "Remember that encrypting your wallet cannot fully protect " - "your bitcoins from being stolen by malware infecting your computer.") + - "<br><br><b>" + - tr("IMPORTANT: Any previous backups you have made of your wallet file " - "should be replaced with the newly generated, encrypted wallet file. " - "For security reasons, previous backups of the unencrypted wallet file " - "will become useless as soon as you start using the new, encrypted wallet.") + + tr("Your wallet is about to be encrypted. ") + encryption_reminder + "</b></qt>"); - } - else - { - QMessageBox::critical(this, tr("Wallet encryption failed"), - tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); + } else { + assert(model != nullptr); + if(model->setWalletEncrypted(true, newpass1)) + { + QMessageBox::warning(this, tr("Wallet encrypted"), + "<qt>" + + tr("Your wallet is now encrypted. ") + encryption_reminder + + "<br><br><b>" + + tr("IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated, encrypted wallet file. " + "For security reasons, previous backups of the unencrypted wallet file " + "will become useless as soon as you start using the new, encrypted wallet.") + + "</b></qt>"); + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); + } } QDialog::accept(); // Success } diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index ac31569f63..bdfd3fb9a0 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -7,6 +7,8 @@ #include <QDialog> +#include <support/allocators/secure.h> + class WalletModel; namespace Ui { @@ -27,7 +29,7 @@ public: Decrypt /**< Ask passphrase and decrypt wallet */ }; - explicit AskPassphraseDialog(Mode mode, QWidget *parent); + explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr); ~AskPassphraseDialog(); void accept(); @@ -39,6 +41,7 @@ private: Mode mode; WalletModel *model; bool fCapsLock; + SecureString* m_passphrase_out; private Q_SLOTS: void textChanged(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index eb8b224929..46f8deee57 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -517,7 +517,7 @@ int GuiMain(int argc, char* argv[]) // - QSettings() will use the new application name after this, resulting in network-specific settings // - Needs to be done before createOptionsModel - // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) + // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { @@ -530,7 +530,7 @@ int GuiMain(int argc, char* argv[]) PaymentServer::ipcParseCommandLine(*node, argc, argv); #endif - QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString())); assert(!networkStyle.isNull()); // Allow for separate UI settings for testnets QApplication::setApplicationName(networkStyle->getAppName()); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 5854ade655..9fa49b87fa 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -6,6 +6,7 @@ #include <qt/bitcoinunits.h> #include <qt/guiconstants.h> +#include <qt/guiutil.h> #include <qt/qvaluecombobox.h> #include <QApplication> @@ -121,7 +122,7 @@ public: const QFontMetrics fm(fontMetrics()); int h = lineEdit()->minimumSizeHint().height(); - int w = fm.width(BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways)); + int w = GUIUtil::TextWidth(fm, BitcoinUnits::format(BitcoinUnits::BTC, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways)); w += 2; // cursor blinking space QStyleOptionSpinBox opt; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index bc9af9793e..c672171cfb 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -6,6 +6,7 @@ #include <qt/bitcoinunits.h> #include <qt/clientmodel.h> +#include <qt/createwalletdialog.h> #include <qt/guiconstants.h> #include <qt/guiutil.h> #include <qt/modaloverlay.h> @@ -40,7 +41,6 @@ #include <QApplication> #include <QComboBox> #include <QDateTime> -#include <QDesktopWidget> #include <QDragEnterEvent> #include <QListWidget> #include <QMenu> @@ -48,6 +48,7 @@ #include <QMessageBox> #include <QMimeData> #include <QProgressDialog> +#include <QScreen> #include <QSettings> #include <QShortcut> #include <QStackedWidget> @@ -81,7 +82,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty QSettings settings; if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) { // Restore failed (perhaps missing setting), center the window - move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); + move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center()); } #ifdef ENABLE_WALLET @@ -339,6 +340,9 @@ void BitcoinGUI::createActions() m_close_wallet_action = new QAction(tr("Close Wallet..."), this); m_close_wallet_action->setStatusTip(tr("Close wallet")); + m_create_wallet_action = new QAction(tr("Create Wallet..."), this); + m_create_wallet_action->setStatusTip(tr("Create a new wallet")); + showHelpMessageAction = new QAction(tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME)); @@ -371,6 +375,8 @@ void BitcoinGUI::createActions() for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) { const std::string& path = i.first; QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + // Menu items remove single &. Single & are shown when && is in the string, but only the first occurrence. So replace only the first & with && + name.replace(name.indexOf(QChar('&')), 1, QString("&&")); QAction* action = m_open_wallet_menu->addAction(name); if (i.second) { @@ -379,31 +385,11 @@ void BitcoinGUI::createActions() continue; } - connect(action, &QAction::triggered, [this, name, path] { - OpenWalletActivity* activity = m_wallet_controller->openWallet(path); - - QProgressDialog* dialog = new QProgressDialog(this); - dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped())); - dialog->setRange(0, 0); - dialog->setCancelButton(nullptr); - dialog->setWindowModality(Qt::ApplicationModal); - dialog->show(); - - connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) { - QMessageBox box; - box.setIcon(icon); - box.setText(tr("Open Wallet Failed")); - box.setInformativeText(text); - box.setStandardButtons(QMessageBox::Ok); - box.setDefaultButton(QMessageBox::Ok); - connect(this, &QObject::destroyed, &box, &QDialog::accept); - box.exec(); - }); + connect(action, &QAction::triggered, [this, path] { + auto activity = new OpenWalletActivity(m_wallet_controller, this); connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet); connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater); - connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater); - bool invoked = QMetaObject::invokeMethod(activity, "open"); - assert(invoked); + activity->open(path); }); } if (m_open_wallet_menu->isEmpty()) { @@ -414,6 +400,12 @@ void BitcoinGUI::createActions() connect(m_close_wallet_action, &QAction::triggered, [this] { m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this); }); + connect(m_create_wallet_action, &QAction::triggered, [this] { + auto activity = new CreateWalletActivity(m_wallet_controller, this); + connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet); + connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater); + activity->create(); + }); } #endif // ENABLE_WALLET @@ -435,6 +427,7 @@ void BitcoinGUI::createMenuBar() QMenu *file = appMenuBar->addMenu(tr("&File")); if(walletFrame) { + file->addAction(m_create_wallet_action); file->addAction(m_open_wallet_action); file->addAction(m_close_wallet_action); file->addSeparator(); @@ -480,24 +473,16 @@ void BitcoinGUI::createMenuBar() connect(qApp, &QApplication::focusWindowChanged, [zoom_action] (QWindow* window) { zoom_action->setEnabled(window != nullptr); }); -#else - QAction* restore_action = window_menu->addAction(tr("Restore")); - connect(restore_action, &QAction::triggered, [] { - qApp->focusWindow()->showNormal(); - }); - - connect(qApp, &QApplication::focusWindowChanged, [restore_action] (QWindow* window) { - restore_action->setEnabled(window != nullptr); - }); #endif if (walletFrame) { +#ifdef Q_OS_MAC window_menu->addSeparator(); QAction* main_window_action = window_menu->addAction(tr("Main Window")); connect(main_window_action, &QAction::triggered, [this] { GUIUtil::bringToFront(this); }); - +#endif window_menu->addSeparator(); window_menu->addAction(usedSendingAddressesAction); window_menu->addAction(usedReceivingAddressesAction); @@ -1407,7 +1392,7 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl const QFontMetrics fm(font()); for (const BitcoinUnits::Unit unit : units) { - max_width = qMax(max_width, fm.width(BitcoinUnits::longName(unit))); + max_width = qMax(max_width, GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit))); } setMinimumSize(max_width, 0); setAlignment(Qt::AlignRight | Qt::AlignVCenter); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 46ced79007..809cf8b4ed 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -147,6 +147,7 @@ private: QAction* openRPCConsoleAction = nullptr; QAction* openAction = nullptr; QAction* showHelpMessageAction = nullptr; + QAction* m_create_wallet_action{nullptr}; QAction* m_open_wallet_action{nullptr}; QMenu* m_open_wallet_menu{nullptr}; QAction* m_close_wallet_action{nullptr}; diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 87736cd185..5cde21eec6 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -131,12 +131,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shu QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Invalid P2P permission: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"), -QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."), @@ -170,7 +170,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction fee and change calculation failed"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction has too long of a mempool chain"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"), -QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."), diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp new file mode 100644 index 0000000000..10262c37c3 --- /dev/null +++ b/src/qt/createwalletdialog.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <qt/createwalletdialog.h> +#include <qt/forms/ui_createwalletdialog.h> + +#include <QPushButton> + +CreateWalletDialog::CreateWalletDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::CreateWalletDialog) +{ + ui->setupUi(this); + ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create")); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->wallet_name_line_edit->setFocus(Qt::ActiveWindowFocusReason); + + connect(ui->wallet_name_line_edit, &QLineEdit::textEdited, [this](const QString& text) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); + }); + + connect(ui->encrypt_wallet_checkbox, &QCheckBox::toggled, [this](bool checked) { + // Disable disable_privkeys_checkbox when encrypt is set to true, enable it when encrypt is false + ui->disable_privkeys_checkbox->setEnabled(!checked); + + // When the disable_privkeys_checkbox is disabled, uncheck it. + if (!ui->disable_privkeys_checkbox->isEnabled()) { + ui->disable_privkeys_checkbox->setChecked(false); + } + }); +} + +CreateWalletDialog::~CreateWalletDialog() +{ + delete ui; +} + +QString CreateWalletDialog::walletName() const +{ + return ui->wallet_name_line_edit->text(); +} + +bool CreateWalletDialog::encrypt() const +{ + return ui->encrypt_wallet_checkbox->isChecked(); +} + +bool CreateWalletDialog::disablePrivateKeys() const +{ + return ui->disable_privkeys_checkbox->isChecked(); +} + +bool CreateWalletDialog::blank() const +{ + return ui->blank_wallet_checkbox->isChecked(); +} diff --git a/src/qt/createwalletdialog.h b/src/qt/createwalletdialog.h new file mode 100644 index 0000000000..a1365b5969 --- /dev/null +++ b/src/qt/createwalletdialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_CREATEWALLETDIALOG_H +#define BITCOIN_QT_CREATEWALLETDIALOG_H + +#include <QDialog> + +class WalletModel; + +namespace Ui { + class CreateWalletDialog; +} + +/** Dialog for creating wallets + */ +class CreateWalletDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CreateWalletDialog(QWidget* parent); + virtual ~CreateWalletDialog(); + + QString walletName() const; + bool encrypt() const; + bool disablePrivateKeys() const; + bool blank() const; + +private: + Ui::CreateWalletDialog *ui; +}; + +#endif // BITCOIN_QT_CREATEWALLETDIALOG_H diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui new file mode 100644 index 0000000000..1fbaeeaaab --- /dev/null +++ b/src/qt/forms/createwalletdialog.ui @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CreateWalletDialog</class> + <widget class="QDialog" name="CreateWalletDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>364</width> + <height>185</height> + </rect> + </property> + <property name="windowTitle"> + <string>Create Wallet</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>10</x> + <y>140</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QLineEdit" name="wallet_name_line_edit"> + <property name="geometry"> + <rect> + <x>120</x> + <y>20</y> + <width>231</width> + <height>24</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="label"> + <property name="geometry"> + <rect> + <x>20</x> + <y>20</y> + <width>101</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>Wallet Name</string> + </property> + </widget> + <widget class="QCheckBox" name="encrypt_wallet_checkbox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>50</y> + <width>171</width> + <height>22</height> + </rect> + </property> + <property name="toolTip"> + <string>Encrypt the wallet. The wallet will be encrypted with a password of your choice.</string> + </property> + <property name="text"> + <string>Encrypt Wallet</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QCheckBox" name="disable_privkeys_checkbox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="geometry"> + <rect> + <x>20</x> + <y>80</y> + <width>171</width> + <height>22</height> + </rect> + </property> + <property name="toolTip"> + <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string> + </property> + <property name="text"> + <string>Disable Private Keys</string> + </property> + </widget> + <widget class="QCheckBox" name="blank_wallet_checkbox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>110</y> + <width>171</width> + <height>22</height> + </rect> + </property> + <property name="toolTip"> + <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string> + </property> + <property name="text"> + <string>Make Blank Wallet</string> + </property> + </widget> + </widget> + <tabstops> + <tabstop>wallet_name_line_edit</tabstop> + <tabstop>encrypt_wallet_checkbox</tabstop> + <tabstop>disable_privkeys_checkbox</tabstop> + <tabstop>blank_wallet_checkbox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CreateWalletDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CreateWalletDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 6e52c5e477..be807b20c0 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -15,6 +15,25 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> + <widget class="QLabel" name="label_alerts"> + <property name="visible"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="margin"> + <number>3</number> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> <number>0</number> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index d8f5594983..dcdb247977 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_QT_GUICONSTANTS_H #define BITCOIN_QT_GUICONSTANTS_H +#include <cstdint> + /* Milliseconds between model updates */ static const int MODEL_UPDATE_DELAY = 250; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index dc1da7f8a9..c4e0321f28 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -39,7 +39,6 @@ #include <QClipboard> #include <QDateTime> #include <QDesktopServices> -#include <QDesktopWidget> #include <QDoubleValidator> #include <QFileDialog> #include <QFont> @@ -58,9 +57,10 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#include <objc/objc-runtime.h> #include <CoreServices/CoreServices.h> #include <QProcess> + +void ForceActivation(); #endif namespace GUIUtil { @@ -360,10 +360,7 @@ bool isObscured(QWidget *w) void bringToFront(QWidget* w) { #ifdef Q_OS_MAC - // Force application activation on macOS. With Qt 5.4 this is required when - // an action in the dock menu is triggered. - id app = objc_msgSend((id) objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - objc_msgSend(app, sel_registerName("activateIgnoringOtherApps:"), YES); + ForceActivation(); #endif if (w) { @@ -591,7 +588,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) // Start client minimized QString strArgs = "-min"; // Set -testnet /-regtest options - strArgs += QString::fromStdString(strprintf(" -testnet=%d -regtest=%d", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false))); + strArgs += QString::fromStdString(strprintf(" -chain=%s", gArgs.GetChainName())); // Set the path to the shortcut target psl->SetPath(pszExePath); @@ -686,7 +683,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) optionFile << "Name=Bitcoin\n"; else optionFile << strprintf("Name=Bitcoin (%s)\n", chain); - optionFile << "Exec=" << pszExePath << strprintf(" -min -testnet=%d -regtest=%d\n", gArgs.GetBoolArg("-testnet", false), gArgs.GetBoolArg("-regtest", false)); + optionFile << "Exec=" << pszExePath << strprintf(" -min -chain=%s\n", chain); optionFile << "Terminal=false\n"; optionFile << "Hidden=false\n"; optionFile.close(); @@ -916,7 +913,7 @@ qreal calculateIdealFontSize(int width, const QString& text, QFont font, qreal m while(font_size >= minPointSize) { font.setPointSizeF(font_size); QFontMetrics fm(font); - if (fm.width(text) < width) { + if (TextWidth(fm, text) < width) { break; } font_size -= 0.5; @@ -948,7 +945,7 @@ void PolishProgressDialog(QProgressDialog* dialog) { #ifdef Q_OS_MAC // Workaround for macOS-only Qt bug; see: QTBUG-65750, QTBUG-70357. - const int margin = dialog->fontMetrics().width("X"); + const int margin = TextWidth(dialog->fontMetrics(), ("X")); dialog->resize(dialog->width() + 2 * margin, dialog->height()); dialog->show(); #else @@ -956,4 +953,13 @@ void PolishProgressDialog(QProgressDialog* dialog) #endif } +int TextWidth(const QFontMetrics& fm, const QString& text) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + return fm.horizontalAdvance(text); +#else + return fm.width(text); +#endif +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index bea4a83494..9db92f94d7 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -257,6 +257,14 @@ namespace GUIUtil // Fix known bugs in QProgressDialog class. void PolishProgressDialog(QProgressDialog* dialog); + + /** + * Returns the distance in pixels appropriate for drawing a subsequent character after text. + * + * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 13.0. + * In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced. + */ + int TextWidth(const QFontMetrics& fm, const QString& text); } // namespace GUIUtil #endif // BITCOIN_QT_GUIUTIL_H diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index bff7469071..7864f97f31 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -132,7 +132,7 @@ <context> <name>AddressTableModel</name> <message> - <location filename="../addresstablemodel.cpp" line="+163"/> + <location filename="../addresstablemodel.cpp" line="+165"/> <source>Label</source> <translation type="unfinished"></translation> </message> @@ -297,7 +297,7 @@ <context> <name>BanTableModel</name> <message> - <location filename="../bantablemodel.cpp" line="+86"/> + <location filename="../bantablemodel.cpp" line="+88"/> <source>IP/Netmask</source> <translation type="unfinished"></translation> </message> @@ -310,17 +310,17 @@ <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+318"/> + <location filename="../bitcoingui.cpp" line="+315"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+638"/> + <location line="+637"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-716"/> + <location line="-715"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -400,7 +400,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+217"/> + <location line="+216"/> <source>Wallet:</source> <translation type="unfinished"></translation> </message> @@ -435,7 +435,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-1036"/> + <location line="-1035"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -500,7 +500,7 @@ <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> - <location line="+118"/> + <location line="+117"/> <source>&File</source> <translation>&File</translation> </message> @@ -520,7 +520,7 @@ <translation>Tabs toolbar</translation> </message> <message> - <location line="-271"/> + <location line="-270"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> @@ -545,7 +545,7 @@ <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+540"/> + <location line="+539"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -606,7 +606,7 @@ <translation>Up to date</translation> </message> <message> - <location line="-657"/> + <location line="-656"/> <source>&Sending addresses</source> <translation type="unfinished"></translation> </message> @@ -641,7 +641,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+30"/> + <location line="+29"/> <source>default wallet</source> <translation type="unfinished"></translation> </message> @@ -782,7 +782,7 @@ <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+390"/> + <location filename="../bitcoin.cpp" line="+382"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation type="unfinished"></translation> </message> @@ -941,7 +941,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+155"/> + <location line="+157"/> <source>yes</source> <translation type="unfinished"></translation> </message> @@ -1736,14 +1736,14 @@ <location filename="../paymentserver.cpp" line="+226"/> <location line="+346"/> <location line="+42"/> - <location line="+110"/> + <location line="+108"/> <location line="+14"/> <location line="+18"/> <source>Payment request error</source> <translation type="unfinished"></translation> </message> <message> - <location line="-529"/> + <location line="-527"/> <source>Cannot start bitcoin: click-to-pay handler</source> <translation type="unfinished"></translation> </message> @@ -1805,12 +1805,12 @@ <location line="+31"/> <location line="+10"/> <location line="+17"/> - <location line="+85"/> + <location line="+83"/> <source>Payment request rejected</source> <translation type="unfinished"></translation> </message> <message> - <location line="-152"/> + <location line="-150"/> <source>Payment request network doesn't match client network.</source> <translation type="unfinished"></translation> </message> @@ -1841,7 +1841,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+65"/> + <location line="+63"/> <source>Refund from %1</source> <translation type="unfinished"></translation> </message> @@ -1879,7 +1879,7 @@ <context> <name>PeerTableModel</name> <message> - <location filename="../peertablemodel.cpp" line="+108"/> + <location filename="../peertablemodel.cpp" line="+110"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> @@ -1922,7 +1922,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+702"/> + <location line="+699"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -1938,7 +1938,7 @@ </message> <message> <location line="+2"/> - <location line="+50"/> + <location line="+47"/> <source>%1 s</source> <translation type="unfinished"></translation> </message> @@ -2032,27 +2032,22 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+74"/> - <source>Error parsing command line arguments: %1.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+37"/> + <location filename="../bitcoin.cpp" line="+116"/> <source>Error: Specified data directory "%1" does not exist.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>Error: Cannot parse configuration file: %1.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>Error: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+57"/> + <location line="+59"/> <source>%1 didn't yet exit safely...</source> <translation type="unfinished"></translation> </message> @@ -2103,7 +2098,7 @@ <context> <name>RPCConsole</name> <message> - <location filename="../forms/debugwindow.ui" line="+56"/> + <location filename="../forms/debugwindow.ui" line="+75"/> <location line="+26"/> <location line="+26"/> <location line="+26"/> @@ -2147,12 +2142,12 @@ <translation>&Information</translation> </message> <message> - <location line="-10"/> + <location line="-29"/> <source>Debug window</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+44"/> <source>General</source> <translation type="unfinished"></translation> </message> @@ -2265,8 +2260,8 @@ </message> <message> <location line="+65"/> - <location filename="../rpcconsole.cpp" line="+498"/> - <location line="+757"/> + <location filename="../rpcconsole.cpp" line="+497"/> + <location line="+759"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> @@ -2417,7 +2412,7 @@ <translation>Clear console</translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-252"/> + <location filename="../rpcconsole.cpp" line="-243"/> <source>1 &hour</source> <translation type="unfinished"></translation> </message> @@ -2450,7 +2445,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+47"/> + <location line="+38"/> <source>&Unban</source> <translation type="unfinished"></translation> </message> @@ -2628,7 +2623,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../receivecoinsdialog.cpp" line="+45"/> + <location filename="../receivecoinsdialog.cpp" line="+46"/> <source>Copy URI</source> <translation type="unfinished"></translation> </message> @@ -2714,7 +2709,7 @@ <context> <name>RecentRequestsTableModel</name> <message> - <location filename="../recentrequeststablemodel.cpp" line="+25"/> + <location filename="../recentrequeststablemodel.cpp" line="+27"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -2753,7 +2748,7 @@ <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+600"/> + <location filename="../sendcoinsdialog.cpp" line="+601"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -2940,7 +2935,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-512"/> + <location filename="../sendcoinsdialog.cpp" line="-513"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -2980,7 +2975,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+117"/> + <location line="+118"/> <source> from wallet '%1'</source> <translation type="unfinished"></translation> </message> @@ -3698,7 +3693,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+223"/> + <location filename="../transactiontablemodel.cpp" line="+225"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -3834,7 +3829,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+70"/> + <location filename="../transactionview.cpp" line="+69"/> <location line="+16"/> <source>All</source> <translation type="unfinished"></translation> @@ -3955,7 +3950,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+199"/> + <location line="+194"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> @@ -4033,7 +4028,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>UnitDisplayStatusBarControl</name> <message> - <location filename="../bitcoingui.cpp" line="+155"/> + <location filename="../bitcoingui.cpp" line="+156"/> <source>Unit to show amounts in. Click to select another unit.</source> <translation type="unfinished"></translation> </message> @@ -4041,7 +4036,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="+70"/> + <location filename="../walletcontroller.cpp" line="+73"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> @@ -4072,7 +4067,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished">Send Coins</translation> </message> <message> - <location line="+301"/> + <location line="+309"/> <location line="+39"/> <location line="+5"/> <source>Fee bump error</source> @@ -4205,12 +4200,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> + <location line="+30"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-168"/> + <location line="-167"/> <source>The %s developers</source> <translation type="unfinished"></translation> </message> @@ -4391,6 +4386,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+4"/> + <source>Invalid P2P permission: '%s'</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation type="unfinished"></translation> </message> @@ -4405,17 +4405,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+22"/> <source>Specified blocks directory "%s" does not exist.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> + <location line="+25"/> <source>Upgrading txindex database</source> <translation type="unfinished"></translation> </message> <message> - <location line="-45"/> + <location line="-44"/> <source>Loading P2P addresses...</source> <translation type="unfinished"></translation> </message> @@ -4465,7 +4465,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+5"/> <source>Unable to bind to %s on this computer. %s is probably already running.</source> <translation type="unfinished"></translation> </message> @@ -4500,7 +4500,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-155"/> + <location line="-154"/> <source>Error: Listening for incoming connections failed (listen returned error %s)</source> <translation type="unfinished"></translation> </message> @@ -4545,7 +4545,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> <translation type="unfinished"></translation> </message> @@ -4555,7 +4555,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+5"/> <source>Need to specify a port with -whitebind: '%s'</source> <translation type="unfinished"></translation> </message> @@ -4617,11 +4617,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+5"/> - <source>Transaction too large for fee policy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> <source>Transaction too large</source> <translation>Transaction too large</translation> </message> @@ -4661,7 +4656,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-178"/> + <location line="-177"/> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation type="unfinished"></translation> </message> @@ -4696,12 +4691,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+20"/> - <source>Keypool ran out, please call keypoolrefill first</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+21"/> + <location line="+41"/> <source>Starting network threads...</source> <translation type="unfinished"></translation> </message> @@ -4736,12 +4726,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> + <location line="+9"/> <source>Unknown network specified in -onlynet: '%s'</source> <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-51"/> + <location line="-50"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index 102adce6c5..5eb23c76e6 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -1,12 +1,11 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "macdockiconhandler.h" -#undef slots -#include <objc/objc.h> -#include <objc/message.h> +#include <AppKit/AppKit.h> +#include <objc/runtime.h> static MacDockIconHandler *s_instance = nullptr; @@ -21,9 +20,7 @@ bool dockClickHandler(id self, SEL _cmd, ...) { } void setupDockClickHandler() { - id app = objc_msgSend((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - id delegate = objc_msgSend(app, sel_registerName("delegate")); - Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class")); + Class delClass = (Class)[[[NSApplication sharedApplication] delegate] class]; SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"); class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"); } @@ -44,3 +41,13 @@ void MacDockIconHandler::cleanup() { delete s_instance; } + +/** + * Force application activation on macOS. With Qt 5.5.1 this is required when + * an action in the Dock menu is triggered. + * TODO: Define a Qt version where it's no-longer necessary. + */ +void ForceActivation() +{ + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; +} diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index f0c860e669..5c039a939e 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -6,6 +6,9 @@ #include <qt/guiconstants.h> +#include <chainparamsbase.h> +#include <tinyformat.h> + #include <QApplication> static const struct { @@ -13,11 +16,10 @@ static const struct { const char *appName; const int iconColorHueShift; const int iconColorSaturationReduction; - const char *titleAddText; } network_styles[] = { - {"main", QAPP_APP_NAME_DEFAULT, 0, 0, ""}, - {"test", QAPP_APP_NAME_TESTNET, 70, 30, QT_TRANSLATE_NOOP("SplashScreen", "[testnet]")}, - {"regtest", QAPP_APP_NAME_REGTEST, 160, 30, "[regtest]"} + {"main", QAPP_APP_NAME_DEFAULT, 0, 0}, + {"test", QAPP_APP_NAME_TESTNET, 70, 30}, + {"regtest", QAPP_APP_NAME_REGTEST, 160, 30} }; static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); @@ -75,8 +77,9 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, trayAndWindowIcon = QIcon(pixmap.scaled(QSize(256,256))); } -const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) +const NetworkStyle* NetworkStyle::instantiate(const std::string& networkId) { + std::string titleAddText = networkId == CBaseChainParams::MAIN ? "" : strprintf("[%s]", networkId); for (unsigned x=0; x<network_styles_count; ++x) { if (networkId == network_styles[x].networkId) @@ -85,7 +88,7 @@ const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) network_styles[x].appName, network_styles[x].iconColorHueShift, network_styles[x].iconColorSaturationReduction, - network_styles[x].titleAddText); + titleAddText.c_str()); } } return nullptr; diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h index b78a9f5948..bb12dd1b6e 100644 --- a/src/qt/networkstyle.h +++ b/src/qt/networkstyle.h @@ -14,7 +14,7 @@ class NetworkStyle { public: /** Get style associated with provided BIP70 network id, or 0 if not known */ - static const NetworkStyle *instantiate(const QString &networkId); + static const NetworkStyle* instantiate(const std::string& networkId); const QString &getAppName() const { return appName; } const QIcon &getAppIcon() const { return appIcon; } diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index d8e48f350a..07ffff0126 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -204,9 +204,8 @@ void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly) void OverviewPage::setClientModel(ClientModel *model) { this->clientModel = model; - if(model) - { - // Show warning if this is a prerelease version + if (model) { + // Show warning, for example if this is a prerelease version connect(model, &ClientModel::alertsChanged, this, &OverviewPage::updateAlerts); updateAlerts(model->getStatusBarWarnings()); } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index f3f5d28af9..0bb87742e9 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -41,8 +41,8 @@ #include <QNetworkReply> #include <QNetworkRequest> #include <QSslCertificate> +#include <QSslConfiguration> #include <QSslError> -#include <QSslSocket> #include <QStringList> #include <QTextDocument> #include <QUrlQuery> @@ -448,9 +448,9 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) certList = QSslCertificate::fromPath(certFile); // Use those certificates when fetching payment requests, too: - QSslSocket::setDefaultCaCertificates(certList); + QSslConfiguration::defaultConfiguration().setCaCertificates(certList); } else - certList = QSslSocket::systemCaCertificates(); + certList = QSslConfiguration::systemCaCertificates(); int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 05157c2a4a..e8cf432131 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -261,7 +261,7 @@ void ReceiveCoinsDialog::copyColumnToClipboard(int column) if (!firstIndex.isValid()) { return; } - GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString()); + GUIUtil::setClipboard(model->getRecentRequestsTableModel()->index(firstIndex.row(), column).data(Qt::EditRole).toString()); } // context menu diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index 8a1140e952..130b709d46 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -76,7 +76,7 @@ public: QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); Qt::ItemFlags flags(const QModelIndex &index) const; /*@}*/ diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 19b11ba1cd..eccc34e12f 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -28,13 +28,12 @@ #include <wallet/wallet.h> #endif -#include <QDesktopWidget> #include <QKeyEvent> #include <QMenu> #include <QMessageBox> #include <QScrollBar> +#include <QScreen> #include <QSettings> -#include <QSignalMapper> #include <QTime> #include <QTimer> #include <QStringList> @@ -451,7 +450,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty QSettings settings; if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) { // Restore failed (perhaps missing setting), center the window - move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); + move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center()); } QChar nonbreaking_hyphen(8209); @@ -558,6 +557,17 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event) void RPCConsole::setClientModel(ClientModel *model) { clientModel = model; + + bool wallet_enabled{false}; +#ifdef ENABLE_WALLET + wallet_enabled = WalletModel::isWalletEnabled(); +#endif // ENABLE_WALLET + if (model && !wallet_enabled) { + // Show warning, for example if this is a prerelease version + connect(model, &ClientModel::alertsChanged, this, &RPCConsole::updateAlerts); + updateAlerts(model->getStatusBarWarnings()); + } + ui->trafficGraph->setClientModel(model); if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) { // Keep up to date with client @@ -603,19 +613,10 @@ void RPCConsole::setClientModel(ClientModel *model) peersTableContextMenu->addAction(banAction7d); peersTableContextMenu->addAction(banAction365d); - // Add a signal mapping to allow dynamic context menu arguments. - // We need to use int (instead of int64_t), because signal mapper only supports - // int or objects, which is okay because max bantime (1 year) is < int_max. - QSignalMapper* signalMapper = new QSignalMapper(this); - signalMapper->setMapping(banAction1h, 60*60); - signalMapper->setMapping(banAction24h, 60*60*24); - signalMapper->setMapping(banAction7d, 60*60*24*7); - signalMapper->setMapping(banAction365d, 60*60*24*365); - connect(banAction1h, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); - connect(banAction24h, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); - connect(banAction7d, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); - connect(banAction365d, &QAction::triggered, signalMapper, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); - connect(signalMapper, static_cast<void (QSignalMapper::*)(int)>(&QSignalMapper::mapped), this, &RPCConsole::banSelectedNode); + connect(banAction1h, &QAction::triggered, [this] { banSelectedNode(60 * 60); }); + connect(banAction24h, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24); }); + connect(banAction7d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 7); }); + connect(banAction365d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 365); }); // peer table context menu signals connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu); @@ -1274,3 +1275,9 @@ QString RPCConsole::tabTitle(TabTypes tab_type) const { return ui->tabWidget->tabText(tab_type); } + +void RPCConsole::updateAlerts(const QString& warnings) +{ + this->ui->label_alerts->setVisible(!warnings.isEmpty()); + this->ui->label_alerts->setText(warnings); +} diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 38015e38fd..3f7a74ba03 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -167,6 +167,9 @@ private: /** Update UI with latest network info from model. */ void updateNetworkState(); + +private Q_SLOTS: + void updateAlerts(const QString& warnings); }; #endif // BITCOIN_QT_RPCCONSOLE_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0ed057bc8b..a88119d8c5 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -283,7 +283,7 @@ void SendCoinsDialog::on_sendButton_clicked() // generate amount string with wallet name in case of multiwallet QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); if (model->isMultiwallet()) { - amount.append(tr(" from wallet '%1'").arg(model->getWalletName())); + amount.append(tr(" from wallet '%1'").arg(GUIUtil::HtmlEscape(model->getWalletName()))); } // generate address string @@ -297,7 +297,7 @@ void SendCoinsDialog::on_sendButton_clicked() { if(rcp.label.length() > 0) // label with address { - recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.label)); + recipientElement.append(tr("%1 to '%2'").arg(amount, GUIUtil::HtmlEscape(rcp.label))); recipientElement.append(QString(" (%1)").arg(address)); } else // just address @@ -704,7 +704,7 @@ void SendCoinsDialog::updateSmartFeeLabel() int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness(); QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14)); ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }"); - ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x")); + ui->fallbackFeeWarningLabel->setIndent(GUIUtil::TextWidth(QFontMetrics(ui->fallbackFeeWarningLabel->font()), "x")); } else { diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 5bceb1f945..0e5abb89f3 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -8,12 +8,12 @@ #include <qt/splashscreen.h> -#include <qt/networkstyle.h> - #include <clientversion.h> #include <interfaces/handler.h> #include <interfaces/node.h> #include <interfaces/wallet.h> +#include <qt/guiutil.h> +#include <qt/networkstyle.h> #include <ui_interface.h> #include <util/system.h> #include <util/translation.h> @@ -21,9 +21,9 @@ #include <QApplication> #include <QCloseEvent> -#include <QDesktopWidget> #include <QPainter> #include <QRadialGradient> +#include <QScreen> SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) : @@ -75,21 +75,21 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw // check font size and drawing with pixPaint.setFont(QFont(font, 33*fontFactor)); QFontMetrics fm = pixPaint.fontMetrics(); - int titleTextWidth = fm.width(titleText); + int titleTextWidth = GUIUtil::TextWidth(fm, titleText); if (titleTextWidth > 176) { fontFactor = fontFactor * 176 / titleTextWidth; } pixPaint.setFont(QFont(font, 33*fontFactor)); fm = pixPaint.fontMetrics(); - titleTextWidth = fm.width(titleText); + titleTextWidth = GUIUtil::TextWidth(fm, titleText); pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight,paddingTop,titleText); pixPaint.setFont(QFont(font, 15*fontFactor)); // if the version string is too long, reduce size fm = pixPaint.fontMetrics(); - int versionTextWidth = fm.width(versionText); + int versionTextWidth = GUIUtil::TextWidth(fm, versionText); if(versionTextWidth > titleTextWidth+paddingRight-10) { pixPaint.setFont(QFont(font, 10*fontFactor)); titleVersionVSpace -= 5; @@ -111,7 +111,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw boldFont.setWeight(QFont::Bold); pixPaint.setFont(boldFont); fm = pixPaint.fontMetrics(); - int titleAddTextWidth = fm.width(titleAddText); + int titleAddTextWidth = GUIUtil::TextWidth(fm, titleAddText); pixPaint.drawText(pixmap.width()/devicePixelRatio-titleAddTextWidth-10,15,titleAddText); } @@ -124,7 +124,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw QRect r(QPoint(), QSize(pixmap.size().width()/devicePixelRatio,pixmap.size().height()/devicePixelRatio)); resize(r.size()); setFixedSize(r.size()); - move(QApplication::desktop()->screenGeometry().center() - r.center()); + move(QGuiApplication::primaryScreen()->geometry().center() - r.center()); subscribeToCoreSignals(); installEventFilter(this); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 49e9e072a8..8ae01ac093 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -68,8 +68,7 @@ void AppTests::appTests() m_app.parameterSetup(); m_app.createOptionsModel(true /* reset settings */); - QScopedPointer<const NetworkStyle> style( - NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().NetworkIDString())); m_app.setupPlatformStyle(); m_app.createWindow(style.data()); connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 17e174e57a..cbc4ab49f5 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -30,7 +30,6 @@ #include <QMenu> #include <QPoint> #include <QScrollBar> -#include <QSignalMapper> #include <QTableView> #include <QTimer> #include <QUrl> @@ -176,11 +175,6 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa contextMenu->addAction(abandonAction); contextMenu->addAction(editLabelAction); - mapperThirdPartyTxUrls = new QSignalMapper(this); - - // Connect actions - connect(mapperThirdPartyTxUrls, static_cast<void (QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped), this, &TransactionView::openThirdPartyTxUrl); - connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate); connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType); connect(watchOnlyWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseWatchonly); @@ -246,15 +240,15 @@ void TransactionView::setModel(WalletModel *_model) QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts); for (int i = 0; i < listUrls.size(); ++i) { - QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host(); + QString url = listUrls[i].trimmed(); + QString host = QUrl(url, QUrl::StrictMode).host(); if (!host.isEmpty()) { QAction *thirdPartyTxUrlAction = new QAction(host, this); // use host as menu item label if (i == 0) contextMenu->addSeparator(); contextMenu->addAction(thirdPartyTxUrlAction); - connect(thirdPartyTxUrlAction, &QAction::triggered, mapperThirdPartyTxUrls, static_cast<void (QSignalMapper::*)()>(&QSignalMapper::map)); - mapperThirdPartyTxUrls->setMapping(thirdPartyTxUrlAction, listUrls[i].trimmed()); + connect(thirdPartyTxUrlAction, &QAction::triggered, [this, url] { openThirdPartyTxUrl(url); }); } } } diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index e07181d1c8..79347c371f 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -23,7 +23,6 @@ class QFrame; class QLineEdit; class QMenu; class QModelIndex; -class QSignalMapper; class QTableView; QT_END_NAMESPACE @@ -72,7 +71,6 @@ private: QLineEdit *amountWidget; QMenu *contextMenu; - QSignalMapper *mapperThirdPartyTxUrls; QFrame *dateRangeWidget; QDateTimeEdit *dateFrom; diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index a8e7bce6b5..8b8283d3d8 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -2,8 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <qt/askpassphrasedialog.h> +#include <qt/createwalletdialog.h> +#include <qt/guiconstants.h> +#include <qt/guiutil.h> #include <qt/walletcontroller.h> +#include <wallet/wallet.h> + #include <interfaces/handler.h> #include <interfaces/node.h> @@ -13,10 +19,13 @@ #include <QMessageBox> #include <QMutexLocker> #include <QThread> +#include <QTimer> #include <QWindow> WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent) : QObject(parent) + , m_activity_thread(new QThread(this)) + , m_activity_worker(new QObject) , m_node(node) , m_platform_style(platform_style) , m_options_model(options_model) @@ -29,15 +38,17 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle* getOrCreateWallet(std::move(wallet)); } - m_activity_thread.start(); + m_activity_worker->moveToThread(m_activity_thread); + m_activity_thread->start(); } // Not using the default destructor because not all member types definitions are // available in the header, just forward declared. WalletController::~WalletController() { - m_activity_thread.quit(); - m_activity_thread.wait(); + m_activity_thread->quit(); + m_activity_thread->wait(); + delete m_activity_worker; } std::vector<WalletModel*> WalletController::getOpenWallets() const @@ -60,18 +71,11 @@ std::map<std::string, bool> WalletController::listWalletDir() const return wallets; } -OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent) -{ - OpenWalletActivity* activity = new OpenWalletActivity(this, name); - activity->moveToThread(&m_activity_thread); - return activity; -} - void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) { QMessageBox box(parent); box.setWindowTitle(tr("Close wallet")); - box.setText(tr("Are you sure you wish to close wallet <i>%1</i>?").arg(wallet_model->getDisplayName())); + box.setText(tr("Are you sure you wish to close wallet <i>%1</i>?").arg(GUIUtil::HtmlEscape(wallet_model->getDisplayName()))); box.setInformativeText(tr("Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.")); box.setStandardButtons(QMessageBox::Yes|QMessageBox::Cancel); box.setDefaultButton(QMessageBox::Yes); @@ -140,23 +144,147 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model) delete wallet_model; } +WalletControllerActivity::WalletControllerActivity(WalletController* wallet_controller, QWidget* parent_widget) + : QObject(wallet_controller) + , m_wallet_controller(wallet_controller) + , m_parent_widget(parent_widget) +{ +} -OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name) - : m_wallet_controller(wallet_controller) - , m_name(name) -{} +WalletControllerActivity::~WalletControllerActivity() +{ + delete m_progress_dialog; +} -void OpenWalletActivity::open() +void WalletControllerActivity::showProgressDialog(const QString& label_text) { - std::string error, warning; - std::unique_ptr<interfaces::Wallet> wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning); - if (!warning.empty()) { - Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning)); + m_progress_dialog = new QProgressDialog(m_parent_widget); + + m_progress_dialog->setLabelText(label_text); + m_progress_dialog->setRange(0, 0); + m_progress_dialog->setCancelButton(nullptr); + m_progress_dialog->setWindowModality(Qt::ApplicationModal); + GUIUtil::PolishProgressDialog(m_progress_dialog); +} + +CreateWalletActivity::CreateWalletActivity(WalletController* wallet_controller, QWidget* parent_widget) + : WalletControllerActivity(wallet_controller, parent_widget) +{ + m_passphrase.reserve(MAX_PASSPHRASE_SIZE); +} + +CreateWalletActivity::~CreateWalletActivity() +{ + delete m_create_wallet_dialog; + delete m_passphrase_dialog; +} + +void CreateWalletActivity::askPasshprase() +{ + m_passphrase_dialog = new AskPassphraseDialog(AskPassphraseDialog::Encrypt, m_parent_widget, &m_passphrase); + m_passphrase_dialog->show(); + + connect(m_passphrase_dialog, &QObject::destroyed, [this] { + m_passphrase_dialog = nullptr; + }); + connect(m_passphrase_dialog, &QDialog::accepted, [this] { + createWallet(); + }); + connect(m_passphrase_dialog, &QDialog::rejected, [this] { + Q_EMIT finished(); + }); +} + +void CreateWalletActivity::createWallet() +{ + showProgressDialog(tr("Creating Wallet <b>%1</b>...").arg(m_create_wallet_dialog->walletName().toHtmlEscaped())); + + std::string name = m_create_wallet_dialog->walletName().toStdString(); + uint64_t flags = 0; + if (m_create_wallet_dialog->disablePrivateKeys()) { + flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } - if (wallet) { - Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet))); - } else { - Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error)); + if (m_create_wallet_dialog->blank()) { + flags |= WALLET_FLAG_BLANK_WALLET; } + + QTimer::singleShot(500, worker(), [this, name, flags] { + std::unique_ptr<interfaces::Wallet> wallet; + WalletCreationStatus status = node().createWallet(m_passphrase, flags, name, m_error_message, m_warning_message, wallet); + + if (status == WalletCreationStatus::SUCCESS) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + + QTimer::singleShot(500, this, &CreateWalletActivity::finish); + }); +} + +void CreateWalletActivity::finish() +{ + m_progress_dialog->hide(); + + if (!m_error_message.empty()) { + QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message)); + } else if (!m_warning_message.empty()) { + QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(m_warning_message)); + } + + if (m_wallet_model) Q_EMIT created(m_wallet_model); + + Q_EMIT finished(); +} + +void CreateWalletActivity::create() +{ + m_create_wallet_dialog = new CreateWalletDialog(m_parent_widget); + m_create_wallet_dialog->setWindowModality(Qt::ApplicationModal); + m_create_wallet_dialog->show(); + + connect(m_create_wallet_dialog, &QObject::destroyed, [this] { + m_create_wallet_dialog = nullptr; + }); + connect(m_create_wallet_dialog, &QDialog::rejected, [this] { + Q_EMIT finished(); + }); + connect(m_create_wallet_dialog, &QDialog::accepted, [this] { + if (m_create_wallet_dialog->encrypt()) { + askPasshprase(); + } else { + createWallet(); + } + }); +} + +OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, QWidget* parent_widget) + : WalletControllerActivity(wallet_controller, parent_widget) +{ +} + +void OpenWalletActivity::finish() +{ + m_progress_dialog->hide(); + + if (!m_error_message.empty()) { + QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message)); + } else if (!m_warning_message.empty()) { + QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(m_warning_message)); + } + + if (m_wallet_model) Q_EMIT opened(m_wallet_model); + Q_EMIT finished(); } + +void OpenWalletActivity::open(const std::string& path) +{ + QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + + showProgressDialog(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped())); + + QTimer::singleShot(0, worker(), [this, path] { + std::unique_ptr<interfaces::Wallet> wallet = node().loadWallet(path, m_error_message, m_warning_message); + + if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + + QTimer::singleShot(0, this, &OpenWalletActivity::finish); + }); +} diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index be1c282919..4e1a772f3a 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -6,15 +6,20 @@ #define BITCOIN_QT_WALLETCONTROLLER_H #include <qt/walletmodel.h> +#include <support/allocators/secure.h> #include <sync.h> #include <map> #include <memory> +#include <string> #include <vector> #include <QMessageBox> #include <QMutex> +#include <QProgressDialog> #include <QThread> +#include <QTimer> +#include <QString> class OptionsModel; class PlatformStyle; @@ -24,7 +29,11 @@ class Handler; class Node; } // namespace interfaces +class AskPassphraseDialog; +class CreateWalletActivity; +class CreateWalletDialog; class OpenWalletActivity; +class WalletControllerActivity; /** * Controller between interfaces::Node, WalletModel instances and the GUI. @@ -33,7 +42,6 @@ class WalletController : public QObject { Q_OBJECT - WalletModel* getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet); void removeAndDeleteWallet(WalletModel* wallet_model); public: @@ -43,11 +51,12 @@ public: //! Returns wallet models currently open. std::vector<WalletModel*> getOpenWallets() const; + WalletModel* getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet); + //! Returns all wallet names in the wallet dir mapped to whether the wallet //! is loaded. std::map<std::string, bool> listWalletDir() const; - OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr); void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); Q_SIGNALS: @@ -57,7 +66,8 @@ Q_SIGNALS: void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction); private: - QThread m_activity_thread; + QThread* const m_activity_thread; + QObject* const m_activity_worker; interfaces::Node& m_node; const PlatformStyle* const m_platform_style; OptionsModel* const m_options_model; @@ -65,27 +75,72 @@ private: std::vector<WalletModel*> m_wallets; std::unique_ptr<interfaces::Handler> m_handler_load_wallet; - friend class OpenWalletActivity; + friend class WalletControllerActivity; }; -class OpenWalletActivity : public QObject +class WalletControllerActivity : public QObject { Q_OBJECT public: - OpenWalletActivity(WalletController* wallet_controller, const std::string& name); - -public Q_SLOTS: - void open(); + WalletControllerActivity(WalletController* wallet_controller, QWidget* parent_widget); + virtual ~WalletControllerActivity(); Q_SIGNALS: - void message(QMessageBox::Icon icon, const QString text); void finished(); + +protected: + interfaces::Node& node() const { return m_wallet_controller->m_node; } + QObject* worker() const { return m_wallet_controller->m_activity_worker; } + + void showProgressDialog(const QString& label_text); + + WalletController* const m_wallet_controller; + QWidget* const m_parent_widget; + QProgressDialog* m_progress_dialog{nullptr}; + WalletModel* m_wallet_model{nullptr}; + std::string m_error_message; + std::string m_warning_message; +}; + + +class CreateWalletActivity : public WalletControllerActivity +{ + Q_OBJECT + +public: + CreateWalletActivity(WalletController* wallet_controller, QWidget* parent_widget); + virtual ~CreateWalletActivity(); + + void create(); + +Q_SIGNALS: + void created(WalletModel* wallet_model); + +private: + void askPasshprase(); + void createWallet(); + void finish(); + + SecureString m_passphrase; + CreateWalletDialog* m_create_wallet_dialog{nullptr}; + AskPassphraseDialog* m_passphrase_dialog{nullptr}; +}; + +class OpenWalletActivity : public WalletControllerActivity +{ + Q_OBJECT + +public: + OpenWalletActivity(WalletController* wallet_controller, QWidget* parent_widget); + + void open(const std::string& path); + +Q_SIGNALS: void opened(WalletModel* wallet_model); private: - WalletController* const m_wallet_controller; - std::string const m_name; + void finish(); }; #endif // BITCOIN_QT_WALLETCONTROLLER_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index be47f67f95..8652827b59 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -170,9 +170,9 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int QString type = ttm->index(start, TransactionTableModel::Type, parent).data().toString(); QModelIndex index = ttm->index(start, 0, parent); QString address = ttm->data(index, TransactionTableModel::AddressRole).toString(); - QString label = ttm->data(index, TransactionTableModel::LabelRole).toString(); + QString label = GUIUtil::HtmlEscape(ttm->data(index, TransactionTableModel::LabelRole).toString()); - Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, walletModel->getWalletName()); + Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, GUIUtil::HtmlEscape(walletModel->getWalletName())); } void WalletView::gotoOverviewPage() |