From 0af424533fbec3a17704c4061aa4a4cfee59f1c2 Mon Sep 17 00:00:00 2001
From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
Date: Mon, 20 Jul 2020 11:50:55 +0300
Subject: [PATCH 1/3] qt, util: Split out qt/guifileutil module
---
.../libbitcoin_qt/libbitcoin_qt.vcxproj | 1 +
src/Makefile.qt.include | 2 +
src/qt/addressbookpage.cpp | 1 +
src/qt/clientmodel.cpp | 2 +-
src/qt/guifileutil.cpp | 313 ++++++++++++++++++
src/qt/guifileutil.h | 68 ++++
src/qt/guiutil.cpp | 292 ----------------
src/qt/guiutil.h | 48 ---
src/qt/intro.cpp | 2 +-
src/qt/optionsdialog.cpp | 1 +
src/qt/optionsmodel.cpp | 2 +-
src/qt/paymentserver.cpp | 1 +
src/qt/psbtoperationsdialog.cpp | 3 +-
src/qt/qrimagewidget.cpp | 1 +
src/qt/rpcconsole.cpp | 10 +-
src/qt/rpcconsole.h | 1 -
src/qt/sendcoinsdialog.cpp | 1 +
src/qt/transactionview.cpp | 1 +
src/qt/walletview.cpp | 3 +-
19 files changed, 403 insertions(+), 350 deletions(-)
create mode 100644 src/qt/guifileutil.cpp
create mode 100644 src/qt/guifileutil.h
diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
index 6a3c9f1dc12..a155e16a162 100644
--- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
+++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
@@ -23,6 +23,7 @@
+
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 848053e8417..a0baf9bf961 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -119,6 +119,7 @@ BITCOIN_QT_H = \
qt/csvmodelwriter.h \
qt/editaddressdialog.h \
qt/guiconstants.h \
+ qt/guifileutil.h \
qt/guiutil.h \
qt/intro.h \
qt/macdockiconhandler.h \
@@ -219,6 +220,7 @@ BITCOIN_QT_BASE_CPP = \
qt/bitcoinunits.cpp \
qt/clientmodel.cpp \
qt/csvmodelwriter.cpp \
+ qt/guifileutil.cpp \
qt/guiutil.cpp \
qt/intro.cpp \
qt/modaloverlay.cpp \
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index aa4ec04497a..8780f0b15ef 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 7822d4c5f3a..4a920c5cda1 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,7 +6,7 @@
#include
#include
-#include
+#include
#include
#include
diff --git a/src/qt/guifileutil.cpp b/src/qt/guifileutil.cpp
new file mode 100644
index 00000000000..acabff253eb
--- /dev/null
+++ b/src/qt/guifileutil.cpp
@@ -0,0 +1,313 @@
+// Copyright (c) 2011-2020 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
+
+#include
+#include
+
+#ifdef WIN32
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include
+#include
+#include
+#endif // WIN32
+
+#ifdef Q_OS_LINUX
+#include
+#include
+#endif // Q_OS_LINUX
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef Q_OS_MAC
+#include
+#endif // Q_OS_MAC
+
+namespace GUIUtil {
+
+QString getDefaultDataDirectory()
+{
+ return boostPathToQString(GetDefaultDataDir());
+}
+
+QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut)
+{
+ QString selectedFilter;
+ QString myDir;
+ if(dir.isEmpty()) // Default to user documents location
+ {
+ myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+ }
+ else
+ {
+ myDir = dir;
+ }
+ /* Directly convert path to native OS path separators */
+ QString result = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, caption, myDir, filter, &selectedFilter));
+
+ /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
+ QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
+ QString selectedSuffix;
+ if(filter_re.exactMatch(selectedFilter))
+ {
+ selectedSuffix = filter_re.cap(1);
+ }
+
+ /* Add suffix if needed */
+ QFileInfo info(result);
+ if(!result.isEmpty())
+ {
+ if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
+ {
+ /* No suffix specified, add selected suffix */
+ if(!result.endsWith("."))
+ result.append(".");
+ result.append(selectedSuffix);
+ }
+ }
+
+ /* Return selected suffix if asked to */
+ if(selectedSuffixOut)
+ {
+ *selectedSuffixOut = selectedSuffix;
+ }
+ return result;
+}
+
+QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut)
+{
+ QString selectedFilter;
+ QString myDir;
+ if(dir.isEmpty()) // Default to user documents location
+ {
+ myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+ }
+ else
+ {
+ myDir = dir;
+ }
+ /* Directly convert path to native OS path separators */
+ QString result = QDir::toNativeSeparators(QFileDialog::getOpenFileName(parent, caption, myDir, filter, &selectedFilter));
+
+ if(selectedSuffixOut)
+ {
+ /* Extract first suffix from filter pattern "Description (*.foo)" or "Description (*.foo *.bar ...) */
+ QRegExp filter_re(".* \\(\\*\\.(.*)[ \\)]");
+ QString selectedSuffix;
+ if(filter_re.exactMatch(selectedFilter))
+ {
+ selectedSuffix = filter_re.cap(1);
+ }
+ *selectedSuffixOut = selectedSuffix;
+ }
+ return result;
+}
+
+void openDebugLogfile()
+{
+ fs::path pathDebug = GetDataDir() / "debug.log";
+
+ /* Open debug.log with the associated application */
+ if (fs::exists(pathDebug))
+ QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug)));
+}
+
+bool openBitcoinConf()
+{
+ fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
+
+ /* Create the file */
+ fsbridge::ofstream configFile(pathConfig, std::ios_base::app);
+
+ if (!configFile.good())
+ return false;
+
+ configFile.close();
+
+ /* Open bitcoin.conf with the associated application */
+ bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+#ifdef Q_OS_MAC
+ // Workaround for macOS-specific behavior; see #15409.
+ if (!res) {
+ res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)});
+ }
+#endif
+
+ return res;
+}
+
+#ifdef WIN32
+fs::path static StartupShortcutPath()
+{
+ std::string chain = gArgs.GetChainName();
+ if (chain == CBaseChainParams::MAIN)
+ return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
+ if (chain == CBaseChainParams::TESTNET) // Remove this special case when CBaseChainParams::TESTNET = "testnet4"
+ return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk";
+ return GetSpecialFolderPath(CSIDL_STARTUP) / strprintf("Bitcoin (%s).lnk", chain);
+}
+
+bool GetStartOnSystemStartup()
+{
+ // check for Bitcoin*.lnk
+ return fs::exists(StartupShortcutPath());
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ // If the shortcut exists already, remove it for updating
+ fs::remove(StartupShortcutPath());
+
+ if (fAutoStart)
+ {
+ CoInitialize(nullptr);
+
+ // Get a pointer to the IShellLink interface.
+ IShellLinkW* psl = nullptr;
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr,
+ CLSCTX_INPROC_SERVER, IID_IShellLinkW,
+ reinterpret_cast(&psl));
+
+ if (SUCCEEDED(hres))
+ {
+ // Get the current executable path
+ WCHAR pszExePath[MAX_PATH];
+ GetModuleFileNameW(nullptr, pszExePath, ARRAYSIZE(pszExePath));
+
+ // Start client minimized
+ QString strArgs = "-min";
+ // Set -testnet /-regtest options
+ strArgs += QString::fromStdString(strprintf(" -chain=%s", gArgs.GetChainName()));
+
+ // Set the path to the shortcut target
+ psl->SetPath(pszExePath);
+ PathRemoveFileSpecW(pszExePath);
+ psl->SetWorkingDirectory(pszExePath);
+ psl->SetShowCmd(SW_SHOWMINNOACTIVE);
+ psl->SetArguments(strArgs.toStdWString().c_str());
+
+ // Query IShellLink for the IPersistFile interface for
+ // saving the shortcut in persistent storage.
+ IPersistFile* ppf = nullptr;
+ hres = psl->QueryInterface(IID_IPersistFile, reinterpret_cast(&ppf));
+ if (SUCCEEDED(hres))
+ {
+ // Save the link by calling IPersistFile::Save.
+ hres = ppf->Save(StartupShortcutPath().wstring().c_str(), TRUE);
+ ppf->Release();
+ psl->Release();
+ CoUninitialize();
+ return true;
+ }
+ psl->Release();
+ }
+ CoUninitialize();
+ return false;
+ }
+ return true;
+}
+#elif defined(Q_OS_LINUX)
+
+// Follow the Desktop Application Autostart Spec:
+// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+
+fs::path static GetAutostartDir()
+{
+ char* pszConfigHome = getenv("XDG_CONFIG_HOME");
+ if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
+ char* pszHome = getenv("HOME");
+ if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
+ return fs::path();
+}
+
+fs::path static GetAutostartFilePath()
+{
+ std::string chain = gArgs.GetChainName();
+ if (chain == CBaseChainParams::MAIN)
+ return GetAutostartDir() / "bitcoin.desktop";
+ return GetAutostartDir() / strprintf("bitcoin-%s.desktop", chain);
+}
+
+bool GetStartOnSystemStartup()
+{
+ fsbridge::ifstream optionFile(GetAutostartFilePath());
+ if (!optionFile.good())
+ return false;
+ // Scan through file for "Hidden=true":
+ std::string line;
+ while (!optionFile.eof())
+ {
+ getline(optionFile, line);
+ if (line.find("Hidden") != std::string::npos &&
+ line.find("true") != std::string::npos)
+ return false;
+ }
+ optionFile.close();
+
+ return true;
+}
+
+bool SetStartOnSystemStartup(bool fAutoStart)
+{
+ if (!fAutoStart)
+ fs::remove(GetAutostartFilePath());
+ else
+ {
+ char pszExePath[MAX_PATH+1];
+ ssize_t r = readlink("/proc/self/exe", pszExePath, sizeof(pszExePath) - 1);
+ if (r == -1)
+ return false;
+ pszExePath[r] = '\0';
+
+ fs::create_directories(GetAutostartDir());
+
+ fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc);
+ if (!optionFile.good())
+ return false;
+ std::string chain = gArgs.GetChainName();
+ // Write a bitcoin.desktop file to the autostart directory:
+ optionFile << "[Desktop Entry]\n";
+ optionFile << "Type=Application\n";
+ if (chain == CBaseChainParams::MAIN)
+ optionFile << "Name=Bitcoin\n";
+ else
+ optionFile << strprintf("Name=Bitcoin (%s)\n", chain);
+ optionFile << "Exec=" << pszExePath << strprintf(" -min -chain=%s\n", chain);
+ optionFile << "Terminal=false\n";
+ optionFile << "Hidden=false\n";
+ optionFile.close();
+ }
+ return true;
+}
+
+#else
+
+bool GetStartOnSystemStartup() { return false; }
+bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
+
+#endif
+
+fs::path qstringToBoostPath(const QString &path)
+{
+ return fs::path(path.toStdString());
+}
+
+QString boostPathToQString(const fs::path &path)
+{
+ return QString::fromStdString(path.string());
+}
+
+} // namespace GUIUtil
diff --git a/src/qt/guifileutil.h b/src/qt/guifileutil.h
new file mode 100644
index 00000000000..e2d712d2f5a
--- /dev/null
+++ b/src/qt/guifileutil.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2011-2020 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_GUIFILEUTIL_H
+#define BITCOIN_QT_GUIFILEUTIL_H
+
+#include
+
+#include
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+/** Filesystem utility functions used by the GUI.
+ */
+namespace GUIUtil {
+/**
+ * Determine default data directory for operating system.
+ */
+QString getDefaultDataDirectory();
+
+/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
+ when no suffix is provided by the user.
+
+ @param[in] parent Parent window (or 0)
+ @param[in] caption Window caption (or empty, for default)
+ @param[in] dir Starting directory (or empty, to default to documents directory)
+ @param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
+ @param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
+ Can be useful when choosing the save file format based on suffix.
+ */
+QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut);
+
+/** Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
+
+ @param[in] parent Parent window (or 0)
+ @param[in] caption Window caption (or empty, for default)
+ @param[in] dir Starting directory (or empty, to default to documents directory)
+ @param[in] filter Filter specification such as "Comma Separated Files (*.csv)"
+ @param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
+ Can be useful when choosing the save file format based on suffix.
+ */
+QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
+ const QString &filter,
+ QString *selectedSuffixOut);
+
+// Open debug.log
+void openDebugLogfile();
+
+// Open the config file
+bool openBitcoinConf();
+
+bool GetStartOnSystemStartup();
+bool SetStartOnSystemStartup(bool fAutoStart);
+
+/* Convert QString to OS specific boost path through UTF-8 */
+fs::path qstringToBoostPath(const QString &path);
+
+/* Convert OS specific boost path to QString through UTF-8 */
+QString boostPathToQString(const fs::path &path);
+
+} // namespace GUIUtil
+
+#endif // BITCOIN_QT_GUIFILEUTIL_H
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index bab17562a60..35c271d8fd4 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -10,7 +10,6 @@
#include
#include
-#include
#include
#include
#include
@@ -18,24 +17,12 @@
#include
#include