diff --git a/src/blackcore/application.cpp b/src/blackcore/application.cpp index b4ab5ca06..b32fab825 100644 --- a/src/blackcore/application.cpp +++ b/src/blackcore/application.cpp @@ -356,8 +356,8 @@ namespace BlackCore }); } - // load setup - if (m_startSetupReader && !m_setupReader->isSetupAvailable()) + //! \fixme KB 9/17 waiting for setup reader here is supposed to be replaced by explicitly waiting for reader + if (!m_setupReader->isSetupAvailable()) { msgs = this->requestReloadOfSetupAndVersion(); if (msgs.isFailure()) { break; } @@ -396,14 +396,14 @@ namespace BlackCore CLogMessage::preformatted(msgs); } - m_started = m_startSetupReader; // only if requested it will be started + m_started = true; return m_started; } - CStatusMessageList CApplication::waitForSetup() + CStatusMessageList CApplication::waitForSetup(int timeoutMs) { if (!m_setupReader) { return CStatusMessage(this).error("No setup reader"); } - CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, CNetworkUtils::getLongTimeoutMs(), [this] + CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, timeoutMs, [this] { return m_setupReader->isSetupAvailable(); }); @@ -718,30 +718,12 @@ namespace BlackCore return m_networkWatchDog && m_networkWatchDog->isSwiftDbAccessible(); } - bool CApplication::hasSetupReader() const - { - // m_startSetupReader set to false, if something wrong with parsing - return m_setupReader && m_startSetupReader; - } - - QString CApplication::getLastSuccesfulSetupUrl() const - { - if (!this->hasSetupReader()) { return ""; } - return m_setupReader->getLastSuccessfulSetupUrl(); - } - CUrl CApplication::getWorkingSharedUrl() const { if (!m_networkWatchDog || !this->isNetworkAccessible()) { return CUrl(); } return m_networkWatchDog->getWorkingSharedUrl(); } - QString CApplication::getLastSuccesfulDistributionUrl() const - { - if (!this->hasSetupReader()) { return ""; } - return m_setupReader->getLastSuccessfulDistributionUrl(); - } - void CApplication::exit(int retcode) { if (instance()) @@ -1183,11 +1165,17 @@ namespace BlackCore if (!this->parsingHookIn()) { return false; } // setup reader - m_startSetupReader = m_setupReader->parseCmdLineArguments(); + m_setupReader->parseCmdLineArguments(); m_parsed = true; return true; } + bool CApplication::parseAndSynchronizeSetup(int timeoutMs) + { + if (!this->parseAndStartupCheck()) return false; + return !this->synchronizeSetup(timeoutMs).hasErrorMessages(); + } + bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const { Q_UNUSED(retry); // only works with UI version @@ -1220,6 +1208,14 @@ namespace BlackCore return args; } + QString CApplication::cmdLineArgumentsAsString(bool withExecutable) + { + QStringList args = QCoreApplication::arguments(); + if (!withExecutable && !args.isEmpty()) args.removeFirst(); + if (args.isEmpty()) return ""; + return args.join(' '); + } + void CApplication::cmdLineHelpMessage() { m_parser.showHelp(); // terminates @@ -1307,6 +1303,34 @@ namespace BlackCore // Setup // --------------------------------------------------------------------------------- + bool CApplication::hasSetupReader() const + { + return m_setupReader; + } + + CSetupReader *CApplication::getSetupReader() const + { + return m_setupReader.data(); + } + + QString CApplication::getLastSuccesfulSetupUrl() const + { + if (!this->hasSetupReader()) { return ""; } + return m_setupReader->getLastSuccessfulSetupUrl(); + } + + QString CApplication::getLastSuccesfulDistributionUrl() const + { + if (!this->hasSetupReader()) { return ""; } + return m_setupReader->getLastSuccessfulDistributionUrl(); + } + + CStatusMessageList CApplication::synchronizeSetup(int timeoutMs) + { + this->requestReloadOfSetupAndVersion(); + return this->waitForSetup(timeoutMs); + } + CUrlList CApplication::getVatsimMetarUrls() const { if (m_shutdown) { return CUrlList(); } diff --git a/src/blackcore/application.h b/src/blackcore/application.h index 68627cc52..842c49b16 100644 --- a/src/blackcore/application.h +++ b/src/blackcore/application.h @@ -181,9 +181,6 @@ namespace BlackCore //! \remark supposed to be used only in special cases const QNetworkAccessManager *getNetworkAccessManager() const { return m_accessManager; } - //! Setup reader? - bool hasSetupReader() const; - //! Last setup URL (successfully read) //! \threadsafe QString getLastSuccesfulSetupUrl() const; @@ -192,9 +189,6 @@ namespace BlackCore //! \threadsafe QString getLastSuccesfulDistributionUrl() const; - //! Setup already synchronized - bool isSetupAvailable() const; - //! Reload setup and version BlackMisc::CStatusMessageList requestReloadOfSetupAndVersion(); @@ -312,7 +306,11 @@ namespace BlackCore //! \sa parsingHookIn //! \return true means to continue, false to stop bool parseAndStartupCheck(); - //! @} + + //! Combined function + //! \see parseAndStartupCheck + //! \see synchronizeSetup + virtual bool parseAndSynchronizeSetup(int timeoutMs = BlackMisc::Network::CNetworkUtils::getLongTimeoutMs()); //! Display error message virtual bool cmdLineErrorMessage(const QString &cmdLineErrorMessage, bool retry = false) const; @@ -323,6 +321,10 @@ namespace BlackCore //! Arguments to be passed to another swift appplication QStringList inheritedArguments(bool withVatlibArgs = true) const; + //! cmd line arguments as string + virtual QString cmdLineArgumentsAsString(bool withExecutable = true); + //! @} + // ----------------------- contexts ---------------------------------------- //! \name Context / core facade related @@ -364,7 +366,20 @@ namespace BlackCore Context::IContextSimulator *getIContextSimulator(); //! @} - // ----------------------- direct access to some setup data --------------------------------- + // ----------------------- setup data --------------------------------- + //! Read and wait for setup + //! \sa waitForSetup + BlackMisc::CStatusMessageList synchronizeSetup(int timeoutMs = BlackMisc::Network::CNetworkUtils::getLongTimeoutMs()); + + //! Setup reader? + bool hasSetupReader() const; + + //! Access to setup reader + //! \remark supposed to be used only in special cases + BlackCore::CSetupReader *getSetupReader() const; + + //! Setup already synchronized + bool isSetupAvailable() const; //! Consolidated version of METAR URLs, either from CGlobalSetup or CVatsimSetup //! \threadsafe @@ -374,15 +389,13 @@ namespace BlackCore //! \threadsafe BlackMisc::Network::CUrlList getVatsimDataFileUrls() const; - public slots: //! Graceful shutdown virtual void gracefulShutdown(); //! Start services, if not yet parsed call CApplication::parse virtual bool start(); - //! Wait for setup data by calling the event loop and waiting until everything is ready - BlackMisc::CStatusMessageList waitForSetup(); + // ------------------------- network ----------------------------------------------- public: static constexpr int NoRedirects = -1; //!< network request not allowing redirects @@ -463,11 +476,12 @@ namespace BlackCore //! Setup read/synchronized void setupHandlingIsCompleted(bool available); - //! Startup completed - virtual void startupCompleted(); + //! Wait for setup data by calling the event loop and waiting until everything is ready + //! \remark requires parsing upfront + BlackMisc::CStatusMessageList waitForSetup(int timeoutMs = BlackMisc::Network::CNetworkUtils::getLongTimeoutMs()); - //! Problem with network access manager - virtual void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible); + //! Startup completed + virtual void onStartUpCompleted(); //! Init class, allows to init from BlackGui::CGuiApplication as well (pseudo virtual) void init(bool withMetadata); @@ -516,7 +530,6 @@ namespace BlackCore QCommandLineOption m_cmdTestCrashpad {"testcrashpad"}; //!< Test a crasphpad upload bool m_parsed = false; //!< Parsing accomplished? bool m_started = false; //!< started with success? - bool m_startSetupReader = false; //!< start the setup reader bool m_singleApplication = true; //!< only one instance of that application bool m_alreadyRunning = false; //!< Application already running diff --git a/src/blackgui/guiapplication.cpp b/src/blackgui/guiapplication.cpp index be5b9638a..53253b591 100644 --- a/src/blackgui/guiapplication.cpp +++ b/src/blackgui/guiapplication.cpp @@ -9,11 +9,13 @@ #include "blackconfig/buildconfig.h" #include "blackcore/context/contextnetwork.h" +#include "blackcore/setupreader.h" #include "blackcore/data/globalsetup.h" #include "blackcore/webdataservices.h" #include "blackgui/components/applicationclosedialog.h" #include "blackgui/components/downloadandinstalldialog.h" #include "blackgui/components/aboutdialog.h" +#include "blackgui/components/setuploadingdialog.h" #include "blackgui/guiapplication.h" #include "blackgui/guiutility.h" #include "blackgui/registermetadata.h" @@ -82,6 +84,7 @@ namespace BlackGui { CGuiApplication::registerMetadata(); CApplication::init(false); // base class without metadata + if (this->hasSetupReader()) { this->getSetupReader()->setCheckCmdLineBootstrapUrl(false); } // no connect checks on setup reader (handled with interactive setup loading) CGuiApplication::adjustPalette(); this->setWindowIcon(icon); this->settingsChanged(); @@ -207,9 +210,9 @@ namespace BlackGui qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); } - void CGuiApplication::startupCompleted() + void CGuiApplication::onStartUpCompleted() { - CApplication::startupCompleted(); + CApplication::onStartUpCompleted(); if (this->m_splashScreen) { this->m_splashScreen->close(); @@ -597,6 +600,44 @@ namespace BlackGui return m_styleSheetUtility.resetFont(); } + bool CGuiApplication::interactivelySynchronizeSetup(int timeoutMs) + { + bool ok = false; + do + { + const CStatusMessageList msgs = this->synchronizeSetup(timeoutMs); + if (msgs.hasErrorMessages()) + { + static const QString style = sGui->getStyleSheetUtility().styles( + { + CStyleSheetUtility::fileNameFonts(), + CStyleSheetUtility::fileNameStandardWidget() + }); + CSetupLoadingDialog dialog(msgs, this->mainApplicationWindow()); + dialog.setStyleSheet(style); + const int r = dialog.exec(); + if (r == QDialog::Rejected) + { + ok = false; + break; + } + } + else + { + ok = true; + break; + } + } + while (true); + return ok; + } + + bool CGuiApplication::parseAndSynchronizeSetup(int timeoutMs) + { + if (!this->parseAndStartupCheck()) return false; + return this->interactivelySynchronizeSetup(timeoutMs); + } + QDialog::DialogCode CGuiApplication::showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent) { const bool needsDialog = this->hasUnsavedSettings(); diff --git a/src/blackgui/guiapplication.h b/src/blackgui/guiapplication.h index 0cc8ed32f..9811bc78a 100644 --- a/src/blackgui/guiapplication.h +++ b/src/blackgui/guiapplication.h @@ -19,6 +19,7 @@ #include "blackgui/settings/guisettings.h" #include "blackgui/settings/updatenotification.h" #include "blackgui/stylesheetutility.h" +#include "blackmisc/network/networkutils.h" #include "blackmisc/icons.h" #include "blackmisc/statusmessage.h" @@ -162,6 +163,14 @@ namespace BlackGui //! Reset the font to default bool resetFont(); + //! Wait for setup, in case it fails display a dialog how to continue + bool interactivelySynchronizeSetup(int timeoutMs = BlackMisc::Network::CNetworkUtils::getLongTimeoutMs()); + + //! Combined function + //! \see parseAndStartupCheck + //! \see interactivelySynchronizeSetup + virtual bool parseAndSynchronizeSetup(int timeoutMs = BlackMisc::Network::CNetworkUtils::getLongTimeoutMs()) override; + //! Show close dialog QDialog::DialogCode showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent); @@ -194,7 +203,7 @@ namespace BlackGui protected slots: //! Startup competed - virtual void startupCompleted() override; + virtual void onStartUpCompleted() override; protected: //! \name print messages generated during parsing / cmd handling @@ -214,15 +223,15 @@ namespace BlackGui private: QPixmap m_windowIcon; - BlackGui::Components::CDownloadAndInstallDialog *m_installDialog = nullptr; //!< software installation dialog QCommandLineOption m_cmdWindowStateMinimized { "empty" }; //!< window state (minimized) QCommandLineOption m_cmdWindowMode { "empty" }; //!< window mode (flags: frameless ...) CStyleSheetUtility m_styleSheetUtility{{}, this}; //!< style sheet utility bool m_uiSetupCompleted = false; //!< ui setup completed QScopedPointer m_splashScreen; //!< splash screen - BlackGui::Components::CApplicationCloseDialog *m_closeDialog = nullptr; //!< close dialog (no QScopedPointer because I need to set parent) - BlackMisc::CSettingReadOnly m_guiSettings{ this, &CGuiApplication::settingsChanged }; - BlackMisc::CSettingReadOnly m_updateSetting { this }; //!< update notification settings + Components::CDownloadAndInstallDialog *m_installDialog = nullptr; //!< software installation dialog + Components::CApplicationCloseDialog *m_closeDialog = nullptr; //!< close dialog (no QScopedPointer because I need to set parent) + BlackMisc::CSettingReadOnly m_guiSettings{ this, &CGuiApplication::settingsChanged }; + BlackMisc::CSettingReadOnly m_updateSetting { this }; //!< update notification settings //! Qt help message to formatted HTML static QString beautifyHelpMessage(const QString &helpText); diff --git a/src/swiftcore/main.cpp b/src/swiftcore/main.cpp index 26cb5ac47..8105e88e0 100644 --- a/src/swiftcore/main.cpp +++ b/src/swiftcore/main.cpp @@ -35,7 +35,7 @@ int main(int argc, char *argv[]) a.addVatlibOptions(); a.addParserOption({{"r", "start"}, QCoreApplication::translate("main", "Start the server.")}); a.addParserOption({{"c", "coreaudio"}, QCoreApplication::translate("main", "Audio in core.")}); - if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; } + if (!a.parseAndSynchronizeSetup()) { return EXIT_FAILURE; } const QString dBusAdress(a.getCmdDBusAddressValue()); a.useContexts(a.isParserOptionSet("coreaudio") ? diff --git a/src/swiftdata/main.cpp b/src/swiftdata/main.cpp index 8c6f92543..79be35bd8 100644 --- a/src/swiftdata/main.cpp +++ b/src/swiftdata/main.cpp @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48()); a.setSignalStartupAutomatically(false); // application will signal startup on its own a.splashScreen(CIcons::swiftDatabase256()); - if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; } + if (!a.parseAndSynchronizeSetup()) { return EXIT_FAILURE; } a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forMappingTool()); if (!a.start()) { diff --git a/src/swiftguistandard/main.cpp b/src/swiftguistandard/main.cpp index 7b379cae9..afd116b29 100644 --- a/src/swiftguistandard/main.cpp +++ b/src/swiftguistandard/main.cpp @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) CSwiftGuiStdApplication a; a.setSignalStartupAutomatically(false); // application will signal startup on its own a.splashScreen(CIcons::swift256()); - if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; } + if (!a.parseAndSynchronizeSetup()) { return EXIT_FAILURE; } if (!a.hasSetupReader() || !a.start()) { a.gracefulShutdown(); diff --git a/src/swiftlauncher/main.cpp b/src/swiftlauncher/main.cpp index 0772b96d1..d2f5d2749 100644 --- a/src/swiftlauncher/main.cpp +++ b/src/swiftlauncher/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) CGuiApplication a(CApplicationInfo::swiftLauncher(), CApplicationInfo::Laucher, CIcons::swiftLauncher1024()); a.addVatlibOptions(); // so it can be passed to started applications a.addParserOption({{"i", "installer"}, QCoreApplication::translate("main", "Installer setup.") }); - if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; } + if (!a.parseAndSynchronizeSetup()) { return EXIT_FAILURE; } a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forLauncher()); if (!a.start()) {