diff --git a/src/blackmisc/network/entityflags.cpp b/src/blackmisc/network/entityflags.cpp index 5a7e11490..52c4ab267 100644 --- a/src/blackmisc/network/entityflags.cpp +++ b/src/blackmisc/network/entityflags.cpp @@ -112,6 +112,11 @@ namespace BlackMisc } } + CEntityFlags::Entity CEntityFlags::entityFlagToEntity(CEntityFlags::EntityFlag entityFlag) + { + return static_cast(static_cast(entityFlag)); + } + CEntityFlags::EntityFlag CEntityFlags::entityToEntityFlag(Entity entity) { return static_cast(static_cast(entity)); diff --git a/src/blackmisc/network/entityflags.h b/src/blackmisc/network/entityflags.h index c5937d091..878ab6769 100644 --- a/src/blackmisc/network/entityflags.h +++ b/src/blackmisc/network/entityflags.h @@ -86,9 +86,12 @@ namespace BlackMisc static QString flagToString(ReadState flag); //! Flag to severity - static BlackMisc::CStatusMessage::StatusSeverity flagToSeverity(ReadState state); + static CStatusMessage::StatusSeverity flagToSeverity(ReadState state); - //! To flag + //! To entity (when explicit conversion is needed) + static Entity entityFlagToEntity(EntityFlag entityFlag); + + //! To flag (when explicit conversion is needed) static EntityFlag entityToEntityFlag(Entity entity); //! Return single entity and remove it from entities diff --git a/src/swiftguistandard/swiftguistd.cpp b/src/swiftguistandard/swiftguistd.cpp index 080b15729..53639ac3e 100644 --- a/src/swiftguistandard/swiftguistd.cpp +++ b/src/swiftguistandard/swiftguistd.cpp @@ -398,6 +398,7 @@ void SwiftGuiStd::navigatorClosed() void SwiftGuiStd::verifyModelSet() { + if (!sGui || sGui->isShuttingDown()) { return; } const CSimulatorInfo sims = sGui->getIContextSimulator()->simulatorsWithInitializedModelSet(); if (sims.isNoSimulator()) { @@ -405,31 +406,65 @@ void SwiftGuiStd::verifyModelSet() } } -void SwiftGuiStd::sharedInfoObjectsLoaded() +void SwiftGuiStd::checkDbDataLoaded() { - Q_ASSERT_X(sGui && sGui->hasWebDataServices(), Q_FUNC_INFO, "Missing web services"); - Q_ASSERT_X(CThreadUtils::isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Wrong thread"); - const CEntityFlags::Entity newEntities = sGui->getWebDataServices()->getEntitiesWithNewerSharedFile(CEntityFlags::AllDbEntities); - if (newEntities == CEntityFlags::NoEntity) { return; } - CStatusMessage sm = CStatusMessage(this).info("New data for shared files:"); - CStatusMessageList sms({sm}); - const QSet newSingleEntities = CEntityFlags::asSingleEntities(newEntities); + if (!sGui || sGui->isShuttingDown()) { return; } + Q_ASSERT_X(sGui->hasWebDataServices(), Q_FUNC_INFO, "Missing web services"); + Q_ASSERT_X(CThreadUtils::isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Wrong thread, needs to run in main thread"); + CEntityFlags::Entity loadEntities = sGui->getWebDataServices()->getEntitiesWithNewerSharedFile(CEntityFlags::AllDbEntities); + const CEntityFlags::Entity checkForEmpty = CEntityFlags::entityFlagToEntity(CEntityFlags::AllDbEntitiesNoInfoObjects) & ~loadEntities; + + // it can happen the timestamps are not newer, but the data are empty + // - can happen if caches are copied and the TS does not represent the DB timestamp + // - cache files have been deleted + // - sync all DB entities + // - fast if there are no data + // - no impact if already synced + // - slow if newer synced before and all has to be done now + if (!m_dbDataLoading) { sGui->getWebDataServices()->synchronizeDbCaches(checkForEmpty); } + + // we have no newer timestamps, but incomplete data + loadEntities |= sGui->getWebDataServices()->getEmptyEntities(); + if (loadEntities == CEntityFlags::NoEntity) + { + m_dbDataLoading = false; + return; + } + + CStatusMessage sm = m_dbDataLoading ? + CStatusMessage(this).info("Loading in progress:") : + CStatusMessage(this).info("New data for shared files:"); + CStatusMessageList sms(sm); + const QSet newSingleEntities = CEntityFlags::asSingleEntities(loadEntities); + const QString m = m_dbDataLoading ? QStringLiteral("Loading data for '%1'") : QStringLiteral("Load data for '%1'?"); for (CEntityFlags::Entity newSingleEntity : newSingleEntities) { - sm = CStatusMessage(this).info("Load data for '%1'?") << CEntityFlags::flagToString(newSingleEntity); + sm = CStatusMessage(this).info(m) << CEntityFlags::flagToString(newSingleEntity); sms.push_back(sm); } - // allow to init GUI completely before showing overlays - const int delay = 2500; + constexpr int checkAgain = 5000; + if (m_dbDataLoading) + { + // already loading + ui->fr_CentralFrameInside->showOverlayMessages(sms, false, 1.2 * checkAgain); + return; + } + + // data need to be loaded + constexpr int delay = 2500; // allow to init GUI completely before showing overlays QTimer::singleShot(delay, this, [ = ] { // delayed call - auto lambda = [newEntities]() + auto lambda = [ = ]() { - sGui->getWebDataServices()->triggerLoadingDirectlyFromSharedFiles(newEntities, false); + sGui->getWebDataServices()->triggerLoadingDirectlyFromSharedFiles(loadEntities, false); + m_dbDataLoading = true; + + // re-check + QTimer::singleShot(checkAgain, this, &SwiftGuiStd::checkDbDataLoaded); }; - ui->fr_CentralFrameInside->showOverlayMessagesWithConfirmation(sms, false, "Load data?", lambda); + ui->fr_CentralFrameInside->showOverlayMessagesWithConfirmation(sms, false, "Load DB data?", lambda); }); } diff --git a/src/swiftguistandard/swiftguistd.h b/src/swiftguistandard/swiftguistd.h index 25bfa980a..2762953a1 100644 --- a/src/swiftguistandard/swiftguistd.h +++ b/src/swiftguistandard/swiftguistd.h @@ -114,6 +114,7 @@ private: bool m_contextNetworkAvailable = false; //!< network context available? bool m_contextAudioAvailable = false; //!< audio context available? bool m_displayingDBusReconnect = false; //!< currently displaying reconnect dialog + bool m_dbDataLoading = false; //!< DB or shared data loading in progress QTimer m_timerContextWatchdog { this }; //!< core available? BlackMisc::Simulation::CSimulatedAircraft m_ownAircraft; //!< own aircraft's state @@ -124,7 +125,7 @@ private: void initStyleSheet(); //! 1st data reads - void initialDataReads(); + void initialContextDataReads(); //! Init data (post GUI init) void init(); @@ -155,7 +156,7 @@ private: bool isMainPageSelected(MainPageIndex mainPage) const; //! Stop all timers - //! \param disconnect also disconnect signal/slots + //! \param disconnectSignalSlots also disconnect signal/slots void stopAllTimers(bool disconnectSignalSlots); //! Play notifcation sound @@ -246,8 +247,8 @@ private: //! Checks if model set is available void verifyModelSet(); - //! The shared info objects have been loaded - void sharedInfoObjectsLoaded(); + //! Ckeck if the DB data have been loaded + void checkDbDataLoaded(); }; #pragma pop_macro("interface") diff --git a/src/swiftguistandard/swiftguistdinit.cpp b/src/swiftguistandard/swiftguistdinit.cpp index 9ab6f2db5..94eff6fea 100644 --- a/src/swiftguistandard/swiftguistdinit.cpp +++ b/src/swiftguistandard/swiftguistdinit.cpp @@ -7,6 +7,8 @@ * contained in the LICENSE file. */ +#include "swiftguistd.h" +#include "ui_swiftguistd.h" #include "blackconfig/buildconfig.h" #include "blackcore/webdataservices.h" #include "blackcore/context/contextnetwork.h" @@ -32,9 +34,8 @@ #include "blackmisc/loghandler.h" #include "blackmisc/logmessage.h" #include "blackmisc/logpattern.h" +#include "blackmisc/slot.h" #include "blackmisc/statusmessage.h" -#include "swiftguistd.h" -#include "ui_swiftguistd.h" #include #include @@ -117,9 +118,7 @@ void SwiftGuiStd::init() this->initGuiSignals(); // signal / slots contexts / timers - bool s = connect(sGui->getWebDataServices(), &CWebDataServices::sharedInfoObjectsRead, this, &SwiftGuiStd::sharedInfoObjectsLoaded, Qt::QueuedConnection); - Q_ASSERT(s); - s = connect(sGui->getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &SwiftGuiStd::onConnectionStatusChanged, Qt::QueuedConnection); + bool s = connect(sGui->getIContextNetwork(), &IContextNetwork::connectionStatusChanged, this, &SwiftGuiStd::onConnectionStatusChanged, Qt::QueuedConnection); Q_ASSERT(s); s = connect(sGui->getIContextNetwork(), &IContextNetwork::kicked, this, &SwiftGuiStd::onKickedFromNetwork, Qt::QueuedConnection); Q_ASSERT(s); @@ -130,6 +129,11 @@ void SwiftGuiStd::init() s = connect(&m_timerContextWatchdog, &QTimer::timeout, this, &SwiftGuiStd::handleTimerBasedUpdates); Q_ASSERT(s); Q_UNUSED(s); + + // check if DB data have been loaded + // only check once, so data can be loaded and + connectOnce(sGui->getWebDataServices(), &CWebDataServices::sharedInfoObjectsRead, this, &SwiftGuiStd::checkDbDataLoaded, Qt::QueuedConnection); + // start timers, update timers will be started when network is connected m_timerContextWatchdog.start(2500); @@ -137,7 +141,7 @@ void SwiftGuiStd::init() this->setContextAvailability(); // data - this->initialDataReads(); + this->initialContextDataReads(); // start screen and complete menu this->setMainPageToInfoArea(); @@ -156,8 +160,8 @@ void SwiftGuiStd::init() emit sGui->startUpCompleted(true); m_init = true; - QTimer::singleShot(2500, this, &SwiftGuiStd::verifyModelSet); + QTimer::singleShot(2500, this, &SwiftGuiStd::verifyModelSet); if (!sGui->isNetworkAccessible()) { CLogMessage(this).error("No network interface, software will not work properly"); @@ -240,7 +244,7 @@ void SwiftGuiStd::initGuiSignals() connect(ui->comp_MainInfoArea, &CMainInfoAreaComponent::changedWholeInfoAreaFloating, this, &SwiftGuiStd::onChangedMainInfoAreaFloating); } -void SwiftGuiStd::initialDataReads() +void SwiftGuiStd::initialContextDataReads() { this->setContextAvailability(); if (!m_coreAvailable)