diff --git a/src/blackgui/components/dbmappingcomponent.cpp b/src/blackgui/components/dbmappingcomponent.cpp index 472075013..ab12af40a 100644 --- a/src/blackgui/components/dbmappingcomponent.cpp +++ b/src/blackgui/components/dbmappingcomponent.cpp @@ -29,6 +29,7 @@ using namespace BlackGui; using namespace BlackGui::Editors; using namespace BlackGui::Views; using namespace BlackGui::Models; +using namespace BlackGui::Menus; namespace BlackGui { @@ -48,6 +49,7 @@ namespace BlackGui this->ui->tvp_AircraftModelsForVPilot->addFilterDialog(); // own models + ui->comp_OwnAircraftModels->view()->setCustomMenu(new CMergeWithVPilotMenu(this)); ui->comp_OwnAircraftModels->view()->setCustomMenu(new COwnModelSetMenu(this, true)); ui->comp_OwnAircraftModels->view()->setCustomMenu(new CModelStashToolsMenu(this, false)); @@ -104,8 +106,9 @@ namespace BlackGui this->ui->tvp_AircraftModelsForVPilot->setCustomMenu(new CMappingVPilotMenu(this, true)); this->ui->tvp_AircraftModelsForVPilot->setCustomMenu(new CModelStashToolsMenu(this, false)); this->ui->tvp_AircraftModelsForVPilot->setDisplayAutomatically(true); + this->ui->tvp_AircraftModelsForVPilot->addFilterDialog(); - const CAircraftModelList vPilotModels(m_cachedVPilotModels.get()); + const CAircraftModelList vPilotModels(m_vPilotReader.getAsModelsFromCache()); this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(vPilotModels); int noModels = vPilotModels.size(); CLogMessage(this).info("%1 cached vPilot models loaded") << noModels; @@ -413,15 +416,6 @@ namespace BlackGui { this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(models); } - CStatusMessage msg = m_cachedVPilotModels.set(models); - if (msg.isWarningOrAbove()) - { - CLogMessage::preformatted(msg); - } - else - { - CLogMessage(this).info("Written %1 vPilot rules to cache") << models.size(); - } } else { @@ -434,7 +428,7 @@ namespace BlackGui { if (this->ui->tvp_AircraftModelsForVPilot->displayAutomatically()) { - this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(this->m_cachedVPilotModels.get()); + this->ui->tvp_AircraftModelsForVPilot->updateContainerMaybeAsync(this->m_vPilotReader.getAsModelsFromCache()); } } @@ -500,6 +494,48 @@ namespace BlackGui CLogMessage::preformatted(m); } + void CDbMappingComponent::ps_mergeWithVPilotModels() + { + if (!ui->comp_OwnAircraftModels->modelLoader()) { return; } + if (this->m_vPilotReader.getModelsCount() < 1) { return; } + const CSimulatorInfo sim(ui->comp_OwnAircraftModels->getOwnModelsSimulator()); + if (!sim.isSingleSimulator() || !sim.isMicrosoftOrPrepare3DSimulator()) { return; } + CAircraftModelList ownModels(getOwnModels()); + if (ownModels.isEmpty()) { return; } + ui->comp_OwnAircraftModels->view()->showLoadIndicator(); + CAircraftModelUtilities::mergeWithVPilotData(ownModels, this->m_vPilotReader.getAsModelsFromCache(), true); + ui->comp_OwnAircraftModels->updateViewAndCache(ownModels); + } + + void CDbMappingComponent::ps_mergeSelectedWithVPilotModels() + { + if (!ui->comp_OwnAircraftModels->modelLoader()) { return; } + if (this->m_vPilotReader.getModelsCount() < 1) { return; } + if (!ui->comp_OwnAircraftModels->view()->hasSelection()) { return; } + const CSimulatorInfo sim(ui->comp_OwnAircraftModels->getOwnModelsSimulator()); + if (!sim.isSingleSimulator() || !sim.isMicrosoftOrPrepare3DSimulator()) { return; } + CAircraftModelList ownModels(getOwnSelectedModels()); // subset + if (ownModels.isEmpty()) { return; } + ui->comp_OwnAircraftModels->view()->showLoadIndicator(); + CAircraftModelUtilities::mergeWithVPilotData(ownModels, this->m_vPilotReader.getAsModelsFromCache(), true); + + // full models + CAircraftModelList allModels = this->m_vPilotReader.getAsModelsFromCache(); + allModels.replaceOrAddModelsWithString(ownModels, Qt::CaseInsensitive); + ui->comp_OwnAircraftModels->updateViewAndCache(allModels); + } + + void CDbMappingComponent::ps_onCustomContextMenu(const QPoint &point) + { + QPoint globalPos = this->mapToGlobal(point); + QScopedPointer contextMenu(new QMenu(this)); + + contextMenu->addAction("Max.data area", this, &CDbMappingComponent::resizeForSelect, QKeySequence(Qt::CTRL + Qt::Key_M, Qt::Key_D)); + contextMenu->addAction("Max.mapping area", this, &CDbMappingComponent::resizeForMapping, QKeySequence(Qt::CTRL + Qt::Key_M, Qt::Key_M)); + QAction *selectedItem = contextMenu.data()->exec(globalPos); + Q_UNUSED(selectedItem); + } + void CDbMappingComponent::ps_onStashCountChanged(int count, bool withFilter) { Q_UNUSED(count); @@ -603,6 +639,11 @@ namespace BlackGui return this->ui->comp_OwnAircraftModels->getOwnModels(); } + CAircraftModelList CDbMappingComponent::getOwnSelectedModels() const + { + return this->ui->comp_OwnAircraftModels->getOwnSelectedModels(); + } + CAircraftModel CDbMappingComponent::getOwnModelForModelString(const QString &modelString) const { return this->ui->comp_OwnAircraftModels->getOwnModelForModelString(modelString); @@ -652,7 +693,7 @@ namespace BlackGui if (canUseVPilot) { this->addSeparator(menu); - menu.addAction(CIcons::appMappings16(), "Load vPilot Rules", mapComp, SLOT(ps_loadVPilotData())); + menu.addAction(CIcons::appMappings16(), "Load vPilot Rules", mapComp, &CDbMappingComponent::ps_loadVPilotData); } this->nestedCustomMenu(menu); } @@ -770,5 +811,35 @@ namespace BlackGui { return qobject_cast(this->parent()); } + + CDbMappingComponent::CMergeWithVPilotMenu::CMergeWithVPilotMenu(CDbMappingComponent *mappingComponent, bool separator) : + IMenuDelegate(mappingComponent, separator) + { + Q_ASSERT_X(mappingComponent, Q_FUNC_INFO, "Missing vPilot reader"); + } + + void CDbMappingComponent::CMergeWithVPilotMenu::customMenu(QMenu &menu) const + { + const CAircraftModelView *mv = mappingComponent()->ui->comp_OwnAircraftModels->view(); + const CSimulatorInfo sim = mappingComponent()->ui->comp_OwnAircraftModels->getOwnModelsSimulator(); + if (!mappingComponent()->withVPilot() || mv->isEmpty() || !sim.isSingleSimulator() || !sim.isMicrosoftOrPrepare3DSimulator()) + { + this->nestedCustomMenu(menu); + return; + } + this->addSeparator(menu); + QMenu *mm = menu.addMenu("Merge with vPilot data"); + mm->addAction("All", mappingComponent(), &CDbMappingComponent::ps_mergeWithVPilotModels); + if (mv->hasSelection()) + { + mm->addAction("Selected only", mappingComponent(), &CDbMappingComponent::ps_mergeSelectedWithVPilotModels); + } + this->nestedCustomMenu(menu); + } + + CDbMappingComponent *CDbMappingComponent::CMergeWithVPilotMenu::mappingComponent() const + { + return qobject_cast(this->parent()); + } } // ns } // ns diff --git a/src/blackgui/components/dbmappingcomponent.h b/src/blackgui/components/dbmappingcomponent.h index fd765d7c7..6f86d3def 100644 --- a/src/blackgui/components/dbmappingcomponent.h +++ b/src/blackgui/components/dbmappingcomponent.h @@ -104,6 +104,9 @@ namespace BlackGui //! Own models BlackMisc::Simulation::CAircraftModelList getOwnModels() const; + //! Own selected models + BlackMisc::Simulation::CAircraftModelList getOwnSelectedModels() const; + //! Own (installed) model for given model string BlackMisc::Simulation::CAircraftModel getOwnModelForModelString(const QString &modelString) const; @@ -222,13 +225,21 @@ namespace BlackGui //! Add to own model set void ps_addToOwnModelSet(); + //! Merge with vPilot models + void ps_mergeWithVPilotModels(); + + //! Merge selected with vPilot models + void ps_mergeSelectedWithVPilotModels(); + + //! Custom menu + void ps_onCustomContextMenu(const QPoint &point); + private: - QScopedPointer ui; - QScopedPointer m_autoStashDialog; //!< dialog auto stashing - QScopedPointer m_modelModifyDialog; //!< dialog when modifying models - BlackMisc::Simulation::FsCommon::CVPilotRulesReader m_vPilotReader; //!< read vPilot rules - BlackMisc::CData m_cachedVPilotModels { this, &CDbMappingComponent::ps_onVPilotCacheChanged }; //!< cache for latest vPilot rules - BlackMisc::CData m_swiftDbUser {this, &CDbMappingComponent::ps_userChanged}; + QScopedPointer ui; + QScopedPointer m_autoStashDialog; //!< dialog auto stashing + QScopedPointer m_modelModifyDialog; //!< dialog when modifying models + BlackMisc::Simulation::FsCommon::CVPilotRulesReader m_vPilotReader; //!< read vPilot rules + BlackMisc::CData m_swiftDbUser {this, &CDbMappingComponent::ps_userChanged}; bool m_vPilot1stInit = true; bool m_withVPilot = false; bool m_autoFilterInDbViews = false; //!< automatically filter the DB view by the current model @@ -314,6 +325,20 @@ namespace BlackGui //! Mapping component CDbMappingComponent *mappingComponent() const; }; + + //! Merge with vPilot data + class CMergeWithVPilotMenu : public BlackGui::Menus::IMenuDelegate + { + public: + //! Constructor + CMergeWithVPilotMenu(CDbMappingComponent *mappingComponent, bool separator = true); + + //! \copydoc IMenuDelegate::customMenu + virtual void customMenu(QMenu &menu) const override; + + //! Mapping component + CDbMappingComponent *mappingComponent() const; + }; }; } // ns } // ns diff --git a/src/blackgui/components/dbownmodelscomponent.cpp b/src/blackgui/components/dbownmodelscomponent.cpp index 2ac638dea..03259c6c9 100644 --- a/src/blackgui/components/dbownmodelscomponent.cpp +++ b/src/blackgui/components/dbownmodelscomponent.cpp @@ -45,7 +45,7 @@ namespace BlackGui this->m_modelLoader->startLoading(IAircraftModelLoader::CacheOnly); } - ui->tvp_OwnAircraftModels->setCustomMenu(new CMergeWithDbDataMenu(ui->tvp_OwnAircraftModels, this->m_modelLoader.get(), false)); + ui->tvp_OwnAircraftModels->setCustomMenu(new CMergeWithDbDataMenu(ui->tvp_OwnAircraftModels, this->modelLoader(), false)); ui->tvp_OwnAircraftModels->setCustomMenu(new CLoadModelsMenu(this, true)); } @@ -64,6 +64,11 @@ namespace BlackGui return ui->tvp_OwnAircraftModels->derivedModel(); } + IAircraftModelLoader *CDbOwnModelsComponent::modelLoader() const + { + return this->m_modelLoader.get(); + } + CAircraftModel CDbOwnModelsComponent::getOwnModelForModelString(const QString &modelString) const { if (!this->m_modelLoader) { return CAircraftModel(); } @@ -77,6 +82,11 @@ namespace BlackGui return this->m_modelLoader->getAircraftModels(); } + CAircraftModelList CDbOwnModelsComponent::getOwnSelectedModels() const + { + return ui->tvp_OwnAircraftModels->selectedObjects(); + } + const CSimulatorInfo &CDbOwnModelsComponent::getOwnModelsSimulator() const { static const CSimulatorInfo noSim; @@ -90,6 +100,16 @@ namespace BlackGui return this->m_modelLoader->getAircraftModelsCount(); } + CStatusMessage CDbOwnModelsComponent::updateViewAndCache(const CAircraftModelList &models) + { + const CStatusMessage m = this->m_modelLoader->setCachedModels(models, this->getOwnModelsSimulator()); + if (m.isSuccess()) + { + ui->tvp_OwnAircraftModels->updateContainerMaybeAsync(models); + } + return m; + } + void CDbOwnModelsComponent::gracefulShutdown() { if (this->m_modelLoader) { this->m_modelLoader->gracefulShutdown(); } diff --git a/src/blackgui/components/dbownmodelscomponent.h b/src/blackgui/components/dbownmodelscomponent.h index 7dc369e58..cfb23c5bf 100644 --- a/src/blackgui/components/dbownmodelscomponent.h +++ b/src/blackgui/components/dbownmodelscomponent.h @@ -46,18 +46,27 @@ namespace BlackGui //! Own models BlackMisc::Simulation::CAircraftModelList getOwnModels() const; + //! Own models selected in view + BlackMisc::Simulation::CAircraftModelList getOwnSelectedModels() const; + //! Own models for simulator const BlackMisc::Simulation::CSimulatorInfo &getOwnModelsSimulator() const; //! Number of own models int getOwnModelsCount() const; + //! Update view and cache + BlackMisc::CStatusMessage updateViewAndCache(const BlackMisc::Simulation::CAircraftModelList &models); + //! Models view BlackGui::Views::CAircraftModelView *view() const; //! Access to aircraft model Models::CAircraftModelListModel *model() const; + //! Access to model loader + BlackMisc::Simulation::IAircraftModelLoader *modelLoader() const; + //! Graceful shutdown void gracefulShutdown(); diff --git a/src/blackgui/menus/aircraftmodelmenus.cpp b/src/blackgui/menus/aircraftmodelmenus.cpp index b6025ac0b..3b448e273 100644 --- a/src/blackgui/menus/aircraftmodelmenus.cpp +++ b/src/blackgui/menus/aircraftmodelmenus.cpp @@ -81,7 +81,7 @@ namespace BlackGui void CMergeWithDbDataMenu::customMenu(QMenu &menu) const { const CAircraftModelView *mv = modelView(); - if (mv->isEmpty()) { return; } + if (mv->isEmpty()) { this->nestedCustomMenu(menu); return; } if (!sGui->hasWebDataServices()) { return; } this->addSeparator(menu); diff --git a/src/blackgui/menus/aircraftmodelmenus.h b/src/blackgui/menus/aircraftmodelmenus.h index e0a8624dc..326e66e69 100644 --- a/src/blackgui/menus/aircraftmodelmenus.h +++ b/src/blackgui/menus/aircraftmodelmenus.h @@ -13,6 +13,7 @@ #include "menudelegate.h" #include "blackgui/views/aircraftmodelview.h" #include "blackmisc/simulation/aircraftmodelloader.h" +#include "blackmisc/simulation/fscommon/vpilotrulesreader.h" #include #include @@ -80,7 +81,9 @@ namespace BlackGui void ps_mergeSelectedData(); private: - BlackMisc::Simulation::IAircraftModelLoader *m_loader = nullptr; //!< optional loader + BlackMisc::Simulation::IModelsSetable *modelsTargetSetable() const; + BlackMisc::Simulation::IModelsUpdatable *modelsTargetUpdatable() const; + QObject *m_modelsTarget = nullptr; //!< optional target for setting/updating the models }; } // ns } // ns diff --git a/src/blackmisc/simulation/aircraftmodel.cpp b/src/blackmisc/simulation/aircraftmodel.cpp index 177216574..6afad9b2b 100644 --- a/src/blackmisc/simulation/aircraftmodel.cpp +++ b/src/blackmisc/simulation/aircraftmodel.cpp @@ -256,9 +256,9 @@ namespace BlackMisc m_livery.setAirlineIcaoCode(airlineIcaoCode); } - bool CAircraftModel::hasAircraftAndAirlineDesignator() const + bool CAircraftModel::hasValidAircraftAndAirlineDesignator() const { - return this->m_aircraftIcao.hasDesignator() && this->m_livery.hasValidAirlineDesignator(); + return this->hasKnownAircraftDesignator() && this->m_livery.hasValidAirlineDesignator(); } bool CAircraftModel::hasAircraftDesignator() const diff --git a/src/blackmisc/simulation/aircraftmodel.h b/src/blackmisc/simulation/aircraftmodel.h index 9200aaf6d..fef6f44e0 100644 --- a/src/blackmisc/simulation/aircraftmodel.h +++ b/src/blackmisc/simulation/aircraftmodel.h @@ -152,8 +152,8 @@ namespace BlackMisc //! Set ICAO codes void setAircraftIcaoCodes(const BlackMisc::Aviation::CAircraftIcaoCode &aircraftIcaoCode, const BlackMisc::Aviation::CAirlineIcaoCode &airlineIcaoCode); - //! Airline and aircraft designator? - bool hasAircraftAndAirlineDesignator() const; + //! Valid airline and aircraft designator? + bool hasValidAircraftAndAirlineDesignator() const; //! Has aircraft designator? bool hasAircraftDesignator() const; diff --git a/src/blackmisc/simulation/aircraftmodelloader.cpp b/src/blackmisc/simulation/aircraftmodelloader.cpp index e038677df..e2be8dc6f 100644 --- a/src/blackmisc/simulation/aircraftmodelloader.cpp +++ b/src/blackmisc/simulation/aircraftmodelloader.cpp @@ -39,46 +39,23 @@ namespace BlackMisc return dir.exists(); } - bool IAircraftModelLoader::mergeWithDbData(CAircraftModelList &modelsFromSimulator, const CAircraftModelList &dbModels, bool force) - { - if (dbModels.isEmpty() || modelsFromSimulator.isEmpty()) { return false; } - for (CAircraftModel &simModel : modelsFromSimulator) - { - if (!force && simModel.hasValidDbKey()) { continue; } // already done - CAircraftModel dbModel(dbModels.findFirstByModelStringOrDefault(simModel.getModelString())); - if (!dbModel.hasValidDbKey()) - { - continue; // not found - } - dbModel.updateMissingParts(simModel, false); - simModel = dbModel; - } - return true; - } - - CStatusMessage IAircraftModelLoader::setModelsInCache(const CAircraftModelList &models, const CSimulatorInfo &simulator) + CStatusMessage IAircraftModelLoader::setCachedModels(const CAircraftModelList &models, const CSimulatorInfo &simulator) { const CSimulatorInfo sim = simulator.isSingleSimulator() ? simulator : this->m_simulatorInfo; if (!sim.isSingleSimulator()) { return CStatusMessage(this, CStatusMessage::SeverityError, "Invalid simuataor"); } - const CStatusMessage m(this->m_caches.setModels(models, sim)); - if (m.isSeverityInfoOrLess()) - { - // set is asynchronous - // emit loadingFinished(true, sim); - } - return m; + return this->m_caches.setCachedModels(models, sim); } - CStatusMessage IAircraftModelLoader::replaceOrAddModelsInCache(const CAircraftModelList &models, const CSimulatorInfo &simulator) + CStatusMessage IAircraftModelLoader::replaceOrAddCachedModels(const CAircraftModelList &models, const CSimulatorInfo &simulator) { if (models.isEmpty()) { return CStatusMessage(this, CStatusMessage::SeverityInfo, "No data"); } const CSimulatorInfo sim = simulator.isSingleSimulator() ? simulator : this->m_simulatorInfo; if (!sim.isSingleSimulator()) { return CStatusMessage(this, CStatusMessage::SeverityError, "Invalid simuataor"); } - CAircraftModelList allModels(this->m_caches.getModels(sim)); + CAircraftModelList allModels(this->m_caches.getCachedModels(sim)); int c = allModels.replaceOrAddModelsWithString(models, Qt::CaseInsensitive); if (c > 0) { - return this->setModelsInCache(models, sim); + return this->setCachedModels(allModels, sim); } else { @@ -186,8 +163,8 @@ namespace BlackMisc if (simInfo.xplane()) { loader = std::make_unique( - CSimulatorInfo(CSimulatorInfo::XPLANE), - CXPlaneUtil::xplaneRootDir()); + CSimulatorInfo(CSimulatorInfo::XPLANE), + CXPlaneUtil::xplaneRootDir()); } else { diff --git a/src/blackmisc/simulation/aircraftmodelloader.h b/src/blackmisc/simulation/aircraftmodelloader.h index 3270c849f..56a1dcda5 100644 --- a/src/blackmisc/simulation/aircraftmodelloader.h +++ b/src/blackmisc/simulation/aircraftmodelloader.h @@ -92,20 +92,25 @@ namespace BlackMisc //! Shutdown void gracefulShutdown(); + //! \name Implementations of the models interfaces + //! @{ + virtual void setModels(const CAircraftModelList &models) override { this->setCachedModels(models, this->m_simulatorInfo); } + virtual void updateModels(const CAircraftModelList &models) override { this->replaceOrAddCachedModels(models, this->m_simulatorInfo); } + virtual void setModels(const CAircraftModelList &models, const CSimulatorInfo &simulator) override { this->setCachedModels(models, simulator); } + virtual void updateModels(const CAircraftModelList &models, const CSimulatorInfo &simulator) override { this->replaceOrAddCachedModels(models, simulator); } + //! @} + //! Create a loader and syncronize caches static std::unique_ptr createModelLoader(const BlackMisc::Simulation::CSimulatorInfo &simInfo); - //! Merge with DB data if possible - static bool mergeWithDbData(BlackMisc::Simulation::CAircraftModelList &modelsFromSimulator, const BlackMisc::Simulation::CAircraftModelList &dbModels, bool force = false); - public slots: //! Set cache from outside, this should only be used in special cases. //! But it allows to modify data elsewhere and update the cache with manipulated data. - BlackMisc::CStatusMessage setModelsInCache(const CAircraftModelList &models, const CSimulatorInfo &simulator = CSimulatorInfo()); + BlackMisc::CStatusMessage setCachedModels(const CAircraftModelList &models, const CSimulatorInfo &simulator = CSimulatorInfo()); //! Set cache from outside, this should only be used in special cases. //! But it allows to modify data elsewhere and update the cache with manipulated data. - BlackMisc::CStatusMessage replaceOrAddModelsInCache(const CAircraftModelList &models, const CSimulatorInfo &simulator = CSimulatorInfo()); + BlackMisc::CStatusMessage replaceOrAddCachedModels(const CAircraftModelList &models, const CSimulatorInfo &simulator = CSimulatorInfo()); signals: //! Parsing is finished diff --git a/src/blackmisc/simulation/simulatorinfo.cpp b/src/blackmisc/simulation/simulatorinfo.cpp index 025082130..8e84905c5 100644 --- a/src/blackmisc/simulation/simulatorinfo.cpp +++ b/src/blackmisc/simulation/simulatorinfo.cpp @@ -82,6 +82,16 @@ namespace BlackMisc return fsx() && fs9() && xplane() && p3d(); } + bool CSimulatorInfo::isMicrosoftSimulator() const + { + return fsx() || fs9(); + } + + bool CSimulatorInfo::isMicrosoftOrPrepare3DSimulator() const + { + return isMicrosoftSimulator() || p3d(); + } + int CSimulatorInfo::numberSimulators() const { int c = fs9() ? 1 : 0; diff --git a/src/blackmisc/simulation/simulatorinfo.h b/src/blackmisc/simulation/simulatorinfo.h index 59b732186..20f9c1c6a 100644 --- a/src/blackmisc/simulation/simulatorinfo.h +++ b/src/blackmisc/simulation/simulatorinfo.h @@ -92,6 +92,12 @@ namespace BlackMisc //! Is all simulators? bool isAllSimulators() const; + //! Microsoft Simulator? + bool isMicrosoftSimulator() const; + + //! Microsoft Simulator or P3D? + bool isMicrosoftOrPrepare3DSimulator() const; + //! Number simulators selected int numberSimulators() const;