From 18112a039472f2d81643fce6d092324335e755bb Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Thu, 30 Jun 2016 03:12:59 +0200 Subject: [PATCH] refs #693, integrated GUI close dialog * utility function in CGuiApplication containing the logic (dialog needed, ..) * closeEvent function --- src/blackcore/application.cpp | 50 ++++++++++++++++++++++------ src/blackcore/application.h | 16 +++++++++ src/blackgui/guiapplication.cpp | 33 +++++++++++++++--- src/blackgui/guiapplication.h | 10 ++++-- src/swiftdata/swiftdata.cpp | 10 ++++++ src/swiftdata/swiftdata.h | 6 ++++ src/swiftguistandard/swiftguistd.cpp | 15 +++++++-- src/swiftguistandard/swiftguistd.h | 11 +++--- 8 files changed, 125 insertions(+), 26 deletions(-) diff --git a/src/blackcore/application.cpp b/src/blackcore/application.cpp index 0c640a7ea..80cb60a38 100644 --- a/src/blackcore/application.cpp +++ b/src/blackcore/application.cpp @@ -217,6 +217,8 @@ namespace BlackCore CLogMessage::preformatted(m); } + // Settings are distributed via DBus. So only one application is responsible for saving. `enableLocalSave()` means + // "this is the application responsible for saving". If swiftgui requests a setting to be saved, it is sent to swiftcore and saved by swiftcore. CSettingsCache::instance()->enableLocalSave(); } @@ -344,6 +346,34 @@ namespace BlackCore return env; } + bool CApplication::hasUnsavedSettings() const + { + return !this->getAllUnsavedSettings().isEmpty(); + } + + void CApplication::setSettingsAutoSave(bool autoSave) + { + this->m_autoSaveSettings = autoSave; + } + + QStringList CApplication::getAllUnsavedSettings() const + { + return CSettingsCache::instance()->getAllUnsavedKeys(); + } + + CStatusMessage CApplication::saveSettingsByKey(const QStringList &keys) + { + if (keys.isEmpty()) { return CStatusMessage(); } + if (this->supportsContexts()) + { + return this->getIContextApplication()->saveSettingsByKey(keys); + } + else + { + return CSettingsCache::instance()->saveToStore(keys); + } + } + QString CApplication::getInfoString(const QString &separator) const { QString str(CVersion::version()); @@ -604,7 +634,7 @@ namespace BlackCore CStatusMessage m; if (this->m_parsed) { - if (this->supportsContexts()) + if (this->supportsContexts() && this->m_autoSaveSettings) { // this will eventually also call saveToStore m = this->getIContextApplication()->saveSettings(); @@ -698,9 +728,9 @@ namespace BlackCore return l; } -// --------------------------------------------------------------------------------- -// Parsing -// --------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------- + // Parsing + // --------------------------------------------------------------------------------- bool CApplication::addParserOption(const QCommandLineOption &option) { @@ -824,9 +854,9 @@ namespace BlackCore printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), qPrintable(QCoreApplication::applicationVersion())); } -// --------------------------------------------------------------------------------- -// Contexts -// --------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------- + // Contexts + // --------------------------------------------------------------------------------- bool CApplication::supportsContexts() const { @@ -896,9 +926,9 @@ namespace BlackCore return this->m_coreFacade->getIContextSimulator(); } -// --------------------------------------------------------------------------------- -// Setup -// --------------------------------------------------------------------------------- + // --------------------------------------------------------------------------------- + // Setup + // --------------------------------------------------------------------------------- CUrlList CApplication::getVatsimMetarUrls() const { diff --git a/src/blackcore/application.h b/src/blackcore/application.h index 27e9d17b0..41a050b6e 100644 --- a/src/blackcore/application.h +++ b/src/blackcore/application.h @@ -161,6 +161,18 @@ namespace BlackCore //! To string QString getInfoString(const QString &separator) const; + //! Unsaved settings + bool hasUnsavedSettings() const; + + //! Automatically and always save settings + void setSettingsAutoSave(bool autoSave); + + //! All unsave settings + QStringList getAllUnsavedSettings() const; + + //! Save all settings + BlackMisc::CStatusMessage saveSettingsByKey(const QStringList &keys); + //! Run event loop static int exec(); @@ -226,6 +238,8 @@ namespace BlackCore //! @{ //! Supports contexts + //! \remark checks the real availability of the contexts, so it can happen that we want to use contexts, and they are not yet initialized (false here) + //! \sa m_useContexts we use or we will use contexts bool supportsContexts() const; //! Init the contexts part and start core facade @@ -402,6 +416,8 @@ namespace BlackCore bool m_signalStartup = true; //!< signal startup automatically bool m_devEnv = false; //!< dev. environment bool m_unitTest = false; //!< is UNIT test + bool m_autoSaveSettings = true;//!< automatically saving all settings + }; } // namespace diff --git a/src/blackgui/guiapplication.cpp b/src/blackgui/guiapplication.cpp index 2f4c75fc7..c6aff7c0a 100644 --- a/src/blackgui/guiapplication.cpp +++ b/src/blackgui/guiapplication.cpp @@ -10,6 +10,7 @@ #include "blackconfig/buildconfig.h" #include "blackcore/data/globalsetup.h" #include "blackcore/data/updateinfo.h" +#include "blackgui/components/applicationclosedialog.h" #include "blackgui/guiapplication.h" #include "blackgui/guiutility.h" #include "blackgui/registermetadata.h" @@ -23,6 +24,7 @@ #include "blackmisc/verify.h" #include +#include #include #include #include @@ -40,11 +42,13 @@ #include #include #include +#include #include using namespace BlackConfig; using namespace BlackMisc; using namespace BlackMisc::Network; +using namespace BlackGui::Components; using namespace BlackCore::Data; BlackGui::CGuiApplication *sGui = nullptr; // set by constructor @@ -486,12 +490,33 @@ namespace BlackGui return m_styleSheetUtility.updateFonts(fontFamily, fontSize, fontStyle, fontWeight, fontColor); } + QDialog::DialogCode CGuiApplication::showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent) + { + bool needsDialog = this->hasUnsavedSettings(); + if (!needsDialog) { return QDialog::Accepted; } + if (!this->m_closeDialog) + { + this->m_closeDialog = new CApplicationCloseDialog(mainWindow); + if (mainWindow && !mainWindow->windowTitle().isEmpty()) + { + this->setSettingsAutoSave(false); // will be handled by dialog + this->m_closeDialog->setWindowTitle(mainWindow->windowTitle()); + this->m_closeDialog->setModal(true); + } + } + const QDialog::DialogCode c = static_cast(this->m_closeDialog->exec()); + if (c == QDialog::Rejected) + { + if (closeEvent) { closeEvent->ignore(); } + } + return c; + } + void CGuiApplication::cmdLineHelpMessage() { if (CBuildConfig::isRunningOnWindowsNtPlatform()) { - QMessageBox::information(nullptr, - QGuiApplication::applicationDisplayName(), + QMessageBox::information(nullptr, QGuiApplication::applicationDisplayName(), "
" + this->m_parser.helpText() + "
"); } else @@ -504,8 +529,7 @@ namespace BlackGui { if (CBuildConfig::isRunningOnWindowsNtPlatform()) { - QMessageBox::information(nullptr, - QGuiApplication::applicationDisplayName(), + QMessageBox::information(nullptr, QGuiApplication::applicationDisplayName(), QGuiApplication::applicationDisplayName() + ' ' + QCoreApplication::applicationVersion()); } else @@ -518,5 +542,4 @@ namespace BlackGui { return true; } - } // ns diff --git a/src/blackgui/guiapplication.h b/src/blackgui/guiapplication.h index 513f784b6..bc0a5761c 100644 --- a/src/blackgui/guiapplication.h +++ b/src/blackgui/guiapplication.h @@ -21,6 +21,7 @@ #include "blackmisc/statusmessage.h" #include +#include #include #include #include @@ -30,9 +31,10 @@ class QMenu; class QSplashScreen; class QWidget; +class QMainWindow; namespace BlackMisc { class CLogCategoryList; } - +namespace BlackGui { namespace Components { class CApplicationCloseDialog; }} namespace BlackGui { /*! @@ -138,6 +140,9 @@ namespace BlackGui //! Update the fonts bool updateFonts(const QString &fontFamily, const QString &fontSize, const QString &fontStyle, const QString &fontWeight, const QString &fontColor); + //! Show close dialog + QDialog::DialogCode showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent); + //! Set icon //! \note Pixmap requires a valid QApplication, so it cannot be passed as constructor parameter static void setWindowIcon(const QPixmap &icon); @@ -184,8 +189,9 @@ namespace BlackGui QCommandLineOption m_cmdWindowStateMinimized { "empty" }; //!< window state (minimized) QCommandLineOption m_cmdWindowMode { "empty" }; //!< window mode (flags: frameless ...) CStyleSheetUtility m_styleSheetUtility{{}, this}; //!< style sheet utility - QScopedPointer m_splashScreen; //!< splash screen 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) //! Qt help message to formatted HTML static QString beautifyHelpMessage(const QString &helpText); diff --git a/src/swiftdata/swiftdata.cpp b/src/swiftdata/swiftdata.cpp index 82836d3b9..498b5c6f5 100644 --- a/src/swiftdata/swiftdata.cpp +++ b/src/swiftdata/swiftdata.cpp @@ -58,6 +58,16 @@ void CSwiftData::initStyleSheet() CSwiftData::~CSwiftData() { } +void CSwiftData::closeEvent(QCloseEvent *event) +{ + if (sGui) + { + // save settings + if (sGui->showCloseDialog(this, event) == QDialog::Rejected) { return; } + } + this->performGracefulShutdown(); +} + void CSwiftData::ps_appendLogMessage(const CStatusMessage &message) { CLogComponent *logComponent = ui->comp_MainInfoArea->getLogComponent(); diff --git a/src/swiftdata/swiftdata.h b/src/swiftdata/swiftdata.h index b69ed594a..fd76473ad 100644 --- a/src/swiftdata/swiftdata.h +++ b/src/swiftdata/swiftdata.h @@ -46,6 +46,12 @@ public: //! Destructor ~CSwiftData(); +protected: + //! \name QMainWindow events + //! @[ + virtual void closeEvent(QCloseEvent *event) override; + //! @} + private slots: //! Append log message void ps_appendLogMessage(const BlackMisc::CStatusMessage &message); diff --git a/src/swiftguistandard/swiftguistd.cpp b/src/swiftguistandard/swiftguistd.cpp index f8ea4ea6e..9d55f7b32 100644 --- a/src/swiftguistandard/swiftguistd.cpp +++ b/src/swiftguistandard/swiftguistd.cpp @@ -131,9 +131,20 @@ void SwiftGuiStd::performGracefulShutdown() void SwiftGuiStd::closeEvent(QCloseEvent *event) { - Q_UNUSED(event); + if (sGui) + { + if (sGui->getIContextNetwork() && sGui->getIContextNetwork()->isConnected()) + { + // we do not just logoff, but give the user a chance to respond + event->ignore(); + QTimer::singleShot(500, this, &SwiftGuiStd::ps_loginRequested); + return; + } + + // save settings + if (sGui->showCloseDialog(this, event) == QDialog::Rejected) { return; } + } this->performGracefulShutdown(); - CGuiApplication::exit(); } void SwiftGuiStd::changeEvent(QEvent *event) diff --git a/src/swiftguistandard/swiftguistd.h b/src/swiftguistandard/swiftguistd.h index 09145fbda..47cb0aa9d 100644 --- a/src/swiftguistandard/swiftguistd.h +++ b/src/swiftguistandard/swiftguistd.h @@ -80,17 +80,14 @@ signals: void currentMainInfoAreaChanged(const QWidget *currentWidget); protected: - //! \copydoc QMainWindow::mouseMoveEvent + + //! \name QMainWindow events + //! @[ virtual void mouseMoveEvent(QMouseEvent *event) override; - - //! \copydoc QMainWindow::mousePressEvent virtual void mousePressEvent(QMouseEvent *event) override; - - //! \copydoc QMainWindow::closeEvent virtual void closeEvent(QCloseEvent *event) override; - - //! \copydoc QMainWindow::changeEvent virtual void changeEvent(QEvent *event) override; + //! @} //! Get a minimize action which minimizes the window QAction *getWindowMinimizeAction(QObject *parent);