/** * @RDE_HEADER@ * * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Last, SLSY, 2017-08-14 */ #include "bdv_controller.h" #include "bdv_dds_controller.h" #include "bdv_bgviewer_widget_container.h" #include #include #include #include #include #include #include #include namespace BuildingViewer { static int argc_dummy = 1; static char *argv_dummy[] = { (char*)"Dummy" }; BgViewerController::BgViewerController(QObject *parent) : QObject(parent) , m_mainloop(argc_dummy, argv_dummy, nullptr) , m_widgetStolen(false) , m_comIfc(nullptr) , m_pBgViewerDDSController(nullptr) , m_bgvApp(nullptr) , m_tickTimer(new QTimer(this)) , m_logger(getLogger("BgViewerControllerSingleton")) { m_tickTimer->setInterval(1000 / 25); // 25fps connect(m_tickTimer, &QTimer::timeout, this, [this]() { m_mainloop.tick(); }); m_mainloop.getViewerInterface()->getMainWindow()->setMinimumSize(200, 200); m_viewerInterface = m_mainloop.getViewerInterface(); m_comIfc = new CommunicationInterfaceInternal(m_viewerInterface); m_viewerInterface->SetViewerCallback(m_comIfc); m_pBgViewerDDSController = new BuildingViewerDdsController(m_comIfc, m_viewerInterface); connect(m_pBgViewerDDSController, &BuildingViewerDdsController::signalDdsInitFinished, this, [this]() { m_initExerciseWasSuccessful = true; }); connect(m_comIfc, &CommunicationInterfaceInternal::signalBgViewerInitFinished, this, &BgViewerController::signalBgViewerInitFinished); connect(m_comIfc, &CommunicationInterfaceInternal::signalReceivedBuildingList, this, &BgViewerController::signalReceivedBuildingList); connect(m_comIfc, &CommunicationInterfaceInternal::signalReceivedViewState, this, &BgViewerController::signalReceivedViewState); connect(m_comIfc, &CommunicationInterfaceInternal::signalPlayerPicked, this, &BgViewerController::signalPlayerPicked); connect(m_comIfc, &CommunicationInterfaceInternal::signalAssetPicked, this, &BgViewerController::signalAssetPicked); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventWidgetClosed, this, &BgViewerController::signalViewerEventWidgetClosed); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventWidgetMaximized, this, &BgViewerController::signalViewerEventWidgetMaximized); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventWidgetMinimized, this, &BgViewerController::signalViewerEventWidgetMinimized); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventWidgetFocused, this, &BgViewerController::signalViewerEventWidgetFocused); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventRoomNameClicked, this, &BgViewerController::signalViewerEventRoomNameClicked); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerZoomChanged, this, &BgViewerController::signalViewerZoomChanged); connect(m_comIfc, &CommunicationInterfaceInternal::signalViewerEventButton, this, &BgViewerController::signalViewerEventButton); } BgViewerController::~BgViewerController() { delete m_tickTimer; if (m_bgvApp != nullptr) { m_bgvApp->disconnect(); delete m_bgvApp; } delete m_pBgViewerDDSController; delete m_comIfc; m_bgvApp = nullptr; m_comIfc = nullptr; m_pBgViewerDDSController = nullptr; } void BgViewerController::excConnect(const std::vector &paths, const QString &strXMLFile) { if (m_comIfc) m_comIfc->excConnect(paths, strXMLFile); } void BgViewerController::excGetBuildingList() { if (m_comIfc) m_comIfc->excGetBuildingList(); } void BgViewerController::excGetViewState() { if (m_comIfc) m_comIfc->excGetViewState(); } void BgViewerController::excHighlightView(const QString &strFeatureID) { if (m_comIfc) m_comIfc->excHighlightView(strFeatureID); } void BgViewerController::excRestoreViewState(const QJsonValue &state) { if (m_comIfc) { m_comIfc->excRestoreViewState(state); m_comIfc->excGetBuildingList(); } } void BgViewerController::excSetGlobalDotsMode(bool useDots) { if (m_comIfc) m_comIfc->excSetGlobalDotsMode(useDots); } void BgViewerController::excSetGlobalTransparency(double transparency) { if (m_comIfc) m_comIfc->excSetGlobalTransparency(transparency); } void BgViewerController::excSetGlobalViewMode(bool useOrtho) { if (m_comIfc) m_comIfc->excSetGlobalViewMode(useOrtho); } void BgViewerController::excSetHitlineDuration(uint32_t duration_s) { if (m_comIfc) m_comIfc->excSetHitlineDuration(duration_s); } void BgViewerController::excStartRecording(const QString &strPathOutputFolder, const QString &strFeatureID, int w, int h, int framerate, int quality) { if (m_comIfc) m_comIfc->excStartRecording(strPathOutputFolder, strFeatureID, w, h, framerate, quality); } void BgViewerController::excStopRecording(const QString &strFeatureID) { if (m_comIfc) m_comIfc->excStopRecording(strFeatureID); } QString BgViewerController::buildingModelPath() { QVector directoriesToSearch = NGL::directories(NGL::FileType::ConfigFile); #ifndef WIN32 directoriesToSearch += QStringLiteral("/opt"); #endif for (const QString &d : qAsConst(directoriesToSearch)) { const QDir dir(d + QStringLiteral("/BuildingModels/StaticMeshes/")); if (dir.exists() && dir.isReadable()) return dir.absolutePath(); INFO_LOG(getLogger("BgViewerController")) << "Map path '" << dir.absolutePath() << "' either does not exist or is not readable - skipping"; } return QString(); } void BgViewerController::clearInterfaces(const LtsSession::DdsConnectionParams &conParams) { DEBUG_LOG(m_logger) << "BgViewerControllerSingleton::clearInterfaces()"; if (m_pBgViewerDDSController && m_currentDdsConnParams == conParams) { m_pBgViewerDDSController->uninitialize(); m_currentDdsConnParams = LtsSession::DdsConnectionParams(); } } void BgViewerController::hideLiveVideo() { /* if (m_pBgViewerDDSController) if (m_pBgViewerDDSController->activeSession()) if (m_pBgViewerDDSController->activeSession()->avmDataIfc()) m_pBgViewerDDSController->activeSession()->avmDataIfc()->hideLiveVideo(); */ // js ftw: m_pBgViewerDDSController?->activeSession()?->avmDataIfc()?->hideLiveVideo(); } bool BgViewerController::isBgViewerApplicationRunning() const { return (m_bgvApp != nullptr); } LtsSession::DdsConnectionParams BgViewerController::currentDdsConnParams() const { return m_currentDdsConnParams; } PluginProvider *BgViewerController::activeSession() const { return m_pBgViewerDDSController->activeSession(); } bool BgViewerController::init(PluginProvider *pSession, bool bStartRendering, const QString &modelPath) { DEBUG_LOG(m_logger) << "getDdsController init: " << pSession->toString(); if (m_currentDdsConnParams == pSession->connParams()) { if (m_initExerciseWasSuccessful) { DEBUG_LOG(m_logger) << "BgViewerControllerSingleton::init Already initialized"; slotLoadBuilding(); // Already initialized //emit signalExerciseInitializationComplete(); } return true; } m_currentDdsConnParams = pSession->connParams(); m_initExerciseWasSuccessful = false; if (!m_pBgViewerDDSController->init(m_bgViewerBaseLayoutWidget, modelPath, pSession)) return false; if (bStartRendering) { m_bgvAppIsInitialized = true; m_tickTimer->start(); } return true; } bool BgViewerController::forceInit(PluginProvider *pSession) { delete m_pBgViewerDDSController; m_pBgViewerDDSController = new BuildingViewerDdsController(m_comIfc, m_viewerInterface); DEBUG_LOG(m_logger) << "FORCE INIT! with " << pSession; return (m_pBgViewerDDSController->init(m_bgViewerBaseLayoutWidget, buildingModelPath(), pSession)); } void BgViewerController::showBgViewerInfoMessageBox() { static bool showMsgBox = true; if (!showMsgBox) return; QMessageBox msgbox; msgbox.setText(tr("BuildingViewer is currently used by another application.\nPlease close the corresponding application.")); msgbox.setIcon(QMessageBox::Information); msgbox.addButton(QMessageBox::Ok); QCheckBox *cb = new QCheckBox(tr("Do not show this message again.")); msgbox.setCheckBox(cb); connect(cb, &QCheckBox::stateChanged, [](int state) { showMsgBox = state != Qt::Checked; }); msgbox.exec(); } bool BgViewerController::startBgViewerAppInSession(PluginProvider* pStartingSession) { DEBUG_LOG(m_logger) << std::hex << this << " startBgViewerAppInSession " << (m_currentDdsConnParams == pStartingSession->connParams()); if (m_bgvApp && (m_currentDdsConnParams == pStartingSession->connParams())) { INFO_LOG(m_logger) << std::hex << this << " BuildingViewer already opened. Doing nothing..."; return true; } // Widget is stolen but BgViewer App is not running -> Do not start App if (!m_bgvApp && m_widgetStolen) { showBgViewerInfoMessageBox(); return false; } if (m_bgvApp) { DEBUG_LOG(m_logger) << std::hex << this << " Releasing m_bgvApp"; delete m_bgvApp; m_bgvApp = nullptr; clearInterfaces(m_currentDdsConnParams); m_comIfc->excCloseAllViews(); } m_bgvAppIsInitialized = false; m_bgvApp = LtsAppManager::LtsAppManager::getInstance()->createApp(LtsAppDescriptor::App::BuildingViewer, pStartingSession->connParams()); if (!m_bgvApp || !m_bgvApp->sessions().size()) { ERROR_LOG(m_logger) << std::hex << this << " m_bgvApp is nullptr or has no associated session!"; return false; } connect(m_bgvApp, &LtsPluginManager::LtsPluginManager::signalInitializationFinished, this, [this, pStartingSession]() { m_tickTimer->start(); m_bgvAppIsInitialized = true; QWidget *w = nullptr; if (m_bgvApp) { LtsSession::LtsSession *session = m_bgvApp->getSession(pStartingSession->connParams().partitionType, pStartingSession->connParams().partitionId); w = session->baseLayoutWidget(); } m_bgViewerBaseLayoutWidget = w; slotLoadBuilding(); emit bgvAppIsInitialized(); }); connect(m_bgvApp, &LtsPluginManager::LtsPluginManager::destroyed, this, [this]() { DEBUG_LOG(m_logger) << std::hex << this << " LtsPluginManager destroyed m_bgvApp"; m_tickTimer->stop(); clearInterfaces(m_currentDdsConnParams); m_comIfc->excCloseAllViews(); m_bgvAppIsInitialized = false; m_bgvApp = nullptr; m_bgViewerBaseLayoutWidget = nullptr; }); return true; } QWidget *BgViewerController::getBgViewerWidget() { if (m_widgetStolen) { showBgViewerInfoMessageBox(); return nullptr; } BgViewerWidgetContainer *pDummy = new BgViewerWidgetContainer(m_mainloop.getViewerInterface()->getMainWindow()); m_widgetStolen = true; connect(pDummy, &BgViewerWidgetContainer::signalWidgetReleased, this, &BgViewerController::slotWidgetReleased); return pDummy; } void BgViewerController::slotWidgetReleased() { m_widgetStolen = false; } void BgViewerController::openBuilding(const QString &strBuildingFeatureId) { m_buildingsToShow.push_back(strBuildingFeatureId.toStdString()); slotLoadBuilding(); } void BgViewerController::closeBuilding(const QString &strBuildingFeatureId) { if (!strBuildingFeatureId.isEmpty()) { const std::string s = strBuildingFeatureId.toStdString(); m_buildingsToShow.erase(std::remove_if(m_buildingsToShow.begin(), m_buildingsToShow.end(), [s](const std::string &str) { return s == str;}), m_buildingsToShow.end()); } else m_buildingsToShow.clear(); if (m_comIfc) { if (strBuildingFeatureId.isEmpty()) m_comIfc->excCloseAllViews(); else m_comIfc->excCloseView({strBuildingFeatureId.toStdString()}); m_comIfc->excGetBuildingList(); } } void BgViewerController::updatePlayerSymbols(int size) { m_pBgViewerDDSController->updatePlayerSymbols(size); } void BgViewerController::closeAll() { m_bgvApp->deleteLater(); } /* * Called each time 'signalInitializationComplete' is emitted. If the user started the BuildingViewer-App * with specifying a building (see 'showBgViewerApplication'), e.g. by starting it through clicking on a building on the situation map, * this slot will load the specified building. Otherwise, nothing will happen. */ void BgViewerController::slotLoadBuilding() { if (!m_bgvAppIsInitialized) return; m_comIfc->excOpenView(m_buildingsToShow); m_comIfc->excGetBuildingList(); m_buildingsToShow.clear(); } void BgViewerController::slotStartRecording(const QString &strFolderPath, const QJsonValue &state) { excRestoreViewState(state); excStartRecording(strFolderPath, QStringLiteral("all"), 800, 600, 15, 40); } void BgViewerController::slotStopRecording() { excStopRecording(); } }