diff --git a/components/DaemonManagerDialog.qml b/components/DaemonManagerDialog.qml index f07e982d..0780b513 100644 --- a/components/DaemonManagerDialog.qml +++ b/components/DaemonManagerDialog.qml @@ -39,12 +39,14 @@ Window { id: root modality: Qt.ApplicationModal flags: Qt.Window | Qt.FramelessWindowHint - + property int countDown: 5; signal rejected() signal started(); function open() { show() + countDown = 5; + timer.start(); } // TODO: implement without hardcoding sizes @@ -61,15 +63,29 @@ Window { //anchors {fill: parent; margins: 16 } Layout.alignment: Qt.AlignHCenter - Label { - text: qsTr("Daemon doesn't appear to be running") + Timer { + id: timer + interval: 1000; + running: false; + repeat: true + onTriggered: { + countDown--; + if(countDown < 0){ + running = false; + // Start daemon + root.close() + appWindow.startDaemon(persistentSettings.daemonFlags); + root.started(); + } + } + } + + Text { + text: qsTr("Starting Monero daemon in %1 seconds").arg(countDown); + font.pixelSize: 18 Layout.alignment: Qt.AlignHCenter - Layout.columnSpan: 2 Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter - font.pixelSize: 24 - font.family: "Arial" - color: "#555555" } } @@ -81,57 +97,39 @@ Window { MoneroComponents.StandardButton { id: okButton - width: 120 + visible:false fontSize: 14 shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" releasedColor: "#FF6C3C" pressedColor: "#FF4304" - text: qsTr("Start daemon") + text: qsTr("Start daemon (%1)").arg(countDown) KeyNavigation.tab: cancelButton onClicked: { + timer.stop(); root.close() - appWindow.startDaemon(daemonFlags.text); + appWindow.startDaemon(persistentSettings.daemonFlags); root.started() } } MoneroComponents.StandardButton { id: cancelButton - width: 120 fontSize: 14 shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" releasedColor: "#FF6C3C" pressedColor: "#FF4304" - text: qsTr("Cancel") + text: qsTr("Use custom settings") onClicked: { + timer.stop(); root.close() root.rejected() } } } - RowLayout { - id: advancedRow - MoneroComponents.Label { - id: daemonFlagsLabel - color: "#4A4949" - text: qsTr("Daemon startup flags") + translationManager.emptyString - fontSize: 16 - } - - MoneroComponents.LineEdit { - id: daemonFlags - Layout.preferredWidth: 200 - Layout.fillWidth: true - text: appWindow.persistentSettings.daemonFlags; - placeholderText: qsTr("(optional)") - } - - } } - } diff --git a/components/ProcessingSplash.qml b/components/ProcessingSplash.qml index d8dc0e84..2f6725db 100644 --- a/components/ProcessingSplash.qml +++ b/components/ProcessingSplash.qml @@ -61,7 +61,7 @@ Window { id: messageTitle text: "Please wait..." font { - pointSize: 22 + pixelSize: 22 } horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter @@ -72,7 +72,7 @@ Window { Text { id: heightProgress font { - pointSize: 18 + pixelSize: 18 } horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter diff --git a/main.cpp b/main.cpp index 0b6aa297..2c839529 100644 --- a/main.cpp +++ b/main.cpp @@ -64,6 +64,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt int main(int argc, char *argv[]) { + Monero::Wallet::init(argv[0], "monero-wallet-gui"); qInstallMessageHandler(messageHandler); QApplication app(argc, argv); @@ -141,7 +142,6 @@ int main(int argc, char *argv[]) // Exclude daemon manager from IOS #ifndef Q_OS_IOS DaemonManager * daemonManager = DaemonManager::instance(&arguments); - QObject::connect(&app, SIGNAL(aboutToQuit()), daemonManager, SLOT(closing())); engine.rootContext()->setContextProperty("daemonManager", daemonManager); #endif diff --git a/main.qml b/main.qml index 3aa9d6cc..6d780051 100644 --- a/main.qml +++ b/main.qml @@ -147,6 +147,11 @@ ApplicationWindow { function mousePressed(obj, mouseX, mouseY) {} function mouseReleased(obj, mouseX, mouseY) {} + function loadPage(page) { + middlePanel.state = page; + leftPanel.selectItem(page); + } + function openWalletFromFile(){ persistentSettings.restore_height = 0 restoreHeight = 0; @@ -274,7 +279,7 @@ ApplicationWindow { leftPanel.progressBar.visible = (status === Wallet.ConnectionStatus_Connected) && !daemonSynced // If wallet isnt connected and no daemon is running - Ask - if(!walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running()){ + if(!walletInitialized && status === Wallet.ConnectionStatus_Disconnected && !daemonManager.running(persistentSettings.testnet)){ daemonManagerDialog.open(); } // initialize transaction history once wallet is initialized first time; @@ -341,7 +346,7 @@ ApplicationWindow { } // Daemon connected - leftPanel.networkStatus.connected = currentWallet.connected + leftPanel.networkStatus.connected = currentWallet.connected() // Check daemon status var dCurrentBlock = currentWallet.daemonBlockChainHeight(); @@ -352,9 +357,9 @@ ApplicationWindow { daemonSynced = dCurrentBlock >= dTargetBlock // Update daemon sync progress leftPanel.progressBar.updateProgress(dCurrentBlock,dTargetBlock); - leftPanel.progressBar.visible = !daemonSynced && currentWallet.connected !== Wallet.ConnectionStatus_Disconnected + leftPanel.progressBar.visible = !daemonSynced && currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected // Update wallet sync progress - updateSyncing((currentWallet.connected !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced) + updateSyncing((currentWallet.connected() !== Wallet.ConnectionStatus_Disconnected) && !daemonSynced) // Update transfer page status middlePanel.updateStatus(); @@ -380,23 +385,25 @@ ApplicationWindow { function startDaemon(flags){ appWindow.showProcessingSplash(qsTr("Waiting for daemon to start...")) - daemonManager.start(flags); + daemonManager.start(flags, persistentSettings.testnet); persistentSettings.daemonFlags = flags } function stopDaemon(){ appWindow.showProcessingSplash(qsTr("Waiting for daemon to stop...")) - daemonManager.stop(); + daemonManager.stop(persistentSettings.testnet); } function onDaemonStarted(){ console.log("daemon started"); daemonRunning = true; + hideProcessingSplash(); } function onDaemonStopped(){ console.log("daemon stopped"); hideProcessingSplash(); daemonRunning = false; + currentWallet.connected(true); } function onWalletNewBlock(blockHeight, targetHeight) { @@ -438,7 +445,7 @@ ApplicationWindow { if (transaction.status !== PendingTransaction.Status_Ok) { console.error("Can't create transaction: ", transaction.errorString); informationPopup.title = qsTr("Error") + translationManager.emptyString; - if (currentWallet.connected == Wallet.ConnectionStatus_WrongVersion) + if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion) informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString else informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString @@ -870,6 +877,9 @@ ApplicationWindow { DaemonManagerDialog { id: daemonManagerDialog + onRejected: { + loadPage("Settings"); + } } @@ -1220,7 +1230,5 @@ ApplicationWindow { onClosing: { // Close wallet non async on exit walletManager.closeWallet(); - // Stop daemon and pool miner - daemonManager.stop(); } } diff --git a/pages/Receive.qml b/pages/Receive.qml index 5ba14527..3191460c 100644 --- a/pages/Receive.qml +++ b/pages/Receive.qml @@ -96,7 +96,7 @@ Rectangle { setTrackingLineText("-") return } - if (appWindow.currentWallet.connected == Wallet.ConnectionStatus_Disconnected) { + if (appWindow.currentWallet.connected() == Wallet.ConnectionStatus_Disconnected) { setTrackingLineText(qsTr("WARNING: no connection to daemon")) return } diff --git a/pages/Settings.qml b/pages/Settings.qml index d2e1a3b3..651357cb 100644 --- a/pages/Settings.qml +++ b/pages/Settings.qml @@ -171,23 +171,10 @@ Rectangle { } } - StandardButton { - visible: true - id: daemonConsolePopupButton - text: qsTr("Show log") + translationManager.emptyString - shadowReleasedColor: "#FF4304" - shadowPressedColor: "#B32D00" - releasedColor: "#FF6C3C" - pressedColor: "#FF4304" - onClicked: { - daemonConsolePopup.open(); - } - } - StandardButton { visible: true id: daemonStatusButton - text: qsTr("Status") + translationManager.emptyString + text: qsTr("Show status") + translationManager.emptyString shadowReleasedColor: "#FF4304" shadowPressedColor: "#B32D00" releasedColor: "#FF6C3C" @@ -420,6 +407,7 @@ Rectangle { console.log("Settings page loaded"); initSettings(); viewOnly = currentWallet.viewOnly; + daemonManager.running(persistentSettings.testnet) } // fires only once diff --git a/pages/Transfer.qml b/pages/Transfer.qml index 1d482474..d141532a 100644 --- a/pages/Transfer.qml +++ b/pages/Transfer.qml @@ -700,7 +700,7 @@ Rectangle { } pageRoot.enabled = false; - switch (currentWallet.connected) { + switch (currentWallet.connected()) { case Wallet.ConnectionStatus_Disconnected: statusText.text = qsTr("Wallet is not connected to daemon.") + "
" + root.startLinkText break diff --git a/src/daemon/DaemonManager.cpp b/src/daemon/DaemonManager.cpp index 5298743a..dd08feb9 100644 --- a/src/daemon/DaemonManager.cpp +++ b/src/daemon/DaemonManager.cpp @@ -23,10 +23,14 @@ DaemonManager *DaemonManager::instance(const QStringList *args) return m_instance; } -bool DaemonManager::start(const QString &flags) +bool DaemonManager::start(const QString &flags, bool testnet) { // prepare command line arguments and pass to monerod QStringList arguments; + arguments << "--detach"; + if(testnet) + arguments << "--testnet"; + foreach (const QString &str, m_clArgs) { qDebug() << QString(" [%1] ").arg(str); if (!str.isEmpty()) @@ -52,8 +56,7 @@ bool DaemonManager::start(const QString &flags) connect (m_daemon, SIGNAL(readyReadStandardError()), this, SLOT(printError())); // Start monerod - m_daemon->start(m_monerod, arguments); - bool started = m_daemon->waitForStarted(); + bool started = m_daemon->startDetached(m_monerod, arguments); // add state changed listener connect(m_daemon,SIGNAL(stateChanged(QProcess::ProcessState)),this,SLOT(stateChanged(QProcess::ProcessState))); @@ -67,16 +70,14 @@ bool DaemonManager::start(const QString &flags) return started; } -bool DaemonManager::stop() +bool DaemonManager::stop(bool testnet) { - if (initialized) { - qDebug() << "stopping daemon"; - // we can't use QProcess::terminate() on windows console process - // write exit command to stdin - m_daemon->write("exit\n"); - } - - return true; + QString message; + bool stopped = sendCommand("exit",testnet,message); + qDebug() << message; + if(stopped) + emit daemonStopped(); + return stopped; } void DaemonManager::stateChanged(QProcess::ProcessState state) @@ -109,40 +110,42 @@ void DaemonManager::printError() } } -bool DaemonManager::running() const -{ - if (initialized) { - qDebug() << m_daemon->state(); - qDebug() << QProcess::NotRunning; - // m_daemon->write("status\n"); - return m_daemon->state() > QProcess::NotRunning; - } - return false; -} - -bool DaemonManager::sendCommand(const QString &cmd,bool testnet) -{ - // If daemon is started by GUI - interactive mode - if (initialized && running()) { - m_daemon->write(cmd.toUtf8() +"\n"); +bool DaemonManager::running(bool testnet) const +{ + QString status; + sendCommand("status",testnet, status); + qDebug() << status; + // `./monerod status` returns BUSY when syncing. + // Treat busy as connected, until fixed upstream. + if (status.contains("Height:") || status.contains("BUSY") ) { + emit daemonStarted(); return true; } + emit daemonStopped(); + return false; +} +bool DaemonManager::sendCommand(const QString &cmd,bool testnet) const +{ + QString message; + return sendCommand(cmd, testnet, message); +} - // else send external command +bool DaemonManager::sendCommand(const QString &cmd,bool testnet, QString &message) const +{ QProcess p; QString external_cmd = m_monerod + " " + cmd; + qDebug() << "sending external cmd: " << external_cmd; - // Add nestnet flag if needed + // Add testnet flag if needed if (testnet) external_cmd += " --testnet"; external_cmd += "\n"; p.start(external_cmd); - bool started = p.waitForFinished(-1); - QString p_stdout = p.readAllStandardOutput(); - qDebug() << p_stdout; - emit daemonConsoleUpdated(p_stdout); + bool started = p.waitForFinished(-1); + message = p.readAllStandardOutput(); + emit daemonConsoleUpdated(message); return started; } @@ -162,13 +165,3 @@ DaemonManager::DaemonManager(QObject *parent) m_has_daemon = false; } } - -void DaemonManager::closing() -{ - qDebug() << __FUNCTION__; - stop(); - // Wait for daemon to stop before exiting (max 10 secs) - if (initialized) { - m_daemon->waitForFinished(10000); - } -} diff --git a/src/daemon/DaemonManager.h b/src/daemon/DaemonManager.h index 2a2b38df..bd13ef60 100644 --- a/src/daemon/DaemonManager.h +++ b/src/daemon/DaemonManager.h @@ -13,26 +13,27 @@ public: static DaemonManager * instance(const QStringList *args); - Q_INVOKABLE bool start(const QString &flags); - Q_INVOKABLE bool stop(); + Q_INVOKABLE bool start(const QString &flags, bool testnet); + Q_INVOKABLE bool stop(bool testnet); // return true if daemon process is started - Q_INVOKABLE bool running() const; - Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet); + Q_INVOKABLE bool running(bool testnet) const; + // Send daemon command from qml and prints output in console window. + Q_INVOKABLE bool sendCommand(const QString &cmd, bool testnet) const; +private: + bool sendCommand(const QString &cmd, bool testnet, QString &message) const; signals: - void daemonStarted(); - void daemonStopped(); - void daemonConsoleUpdated(QString message); + void daemonStarted() const; + void daemonStopped() const; + void daemonConsoleUpdated(QString message) const; public slots: void printOutput(); void printError(); - void closing(); void stateChanged(QProcess::ProcessState state); private: - explicit DaemonManager(QObject *parent = 0); static DaemonManager * m_instance; static QStringList m_clArgs; diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index 5780a93b..8913d4c3 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -20,7 +20,7 @@ #include namespace { - static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 10; + static const int DAEMON_BLOCKCHAIN_HEIGHT_CACHE_TTL_SECONDS = 5; static const int DAEMON_BLOCKCHAIN_TARGET_HEIGHT_CACHE_TTL_SECONDS = 60; static const int WALLET_CONNECTION_STATUS_CACHE_TTL_SECONDS = 5; } @@ -118,6 +118,7 @@ void Wallet::updateConnectionStatusAsync() if (newStatus != m_connectionStatus || !m_initialized) { m_initialized = true; m_connectionStatus = newStatus; + qDebug() << "NEW STATUS " << newStatus; emit connectionStatusChanged(newStatus); } // Release lock diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 7e9651e4..a11cabe9 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -28,7 +28,7 @@ class Wallet : public QObject Q_PROPERTY(QString seedLanguage READ getSeedLanguage) Q_PROPERTY(Status status READ status) Q_PROPERTY(bool testnet READ testnet) - Q_PROPERTY(ConnectionStatus connected READ connected) +// Q_PROPERTY(ConnectionStatus connected READ connected) Q_PROPERTY(bool synchronized READ synchronized) Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(QString address READ address) @@ -77,7 +77,7 @@ public: bool testnet() const; //! returns whether the wallet is connected, and version status - ConnectionStatus connected(bool forceCheck = false); + Q_INVOKABLE ConnectionStatus connected(bool forceCheck = false); void updateConnectionStatusAsync(); //! returns true if wallet was ever synchronized