/** * @RDE_HEADER@ * main for OperatorApplication * $Id$ * $HeadURL$ * $Author$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class CmdLineParser : public LtsCommandLineParser::LtsCommandLineParser { public: CmdLineParser() : LtsCommandLineParser(ProvideCommandLineParameterOptions(CreateDomainIdFromIp | DomainId | ExerciseId | TcpConnectionUrl)) { addOption({{QStringLiteral("a"), QStringLiteral("application")}, QStringLiteral("Specify the initial application to start (Default: Situation [Demo / Dev - otherwise NOT SPECIFIED => starts AppChooser]"), QStringLiteral("Application"), QStringLiteral("Situation") }); // TODO: remove default on release addOption({{QStringLiteral("b"), QStringLiteral("basePlugin")}, QStringLiteral("Base Project Plugin Iid to start the application with (Default: )"), QStringLiteral("Base Project Plugin Iid"), QString() }); // TODO: remove default on release addOption({{QStringLiteral("s"), QStringLiteral("stylePlugin")}, QStringLiteral("Style Plugin to start the application with (Default: rme.light)"), QStringLiteral("Style Plugin Iid"), QStringLiteral("rme.light") }); addOption({{QStringLiteral("u"), QStringLiteral("username")}, QStringLiteral("Preset Username to skip login (also specify -p !)"), QStringLiteral("username") }); addOption({{QStringLiteral("x"), QStringLiteral("tabletmode")}, QStringLiteral("Enforce Tablet Mode"), QStringLiteral("false") }); addOption({{QStringLiteral("w"), QStringLiteral("workstationmode")}, QStringLiteral("Enforce Workstation Mode"), QStringLiteral("false") }); addOption({{QStringLiteral("q"), QStringLiteral("qos_file")}, QStringLiteral("Define QoS Profile "), QStringLiteral("qos_file") }); addOption({{QStringLiteral("p"), QStringLiteral("password")}, QStringLiteral("Preset Password to skip login (also specify -u !)"), QStringLiteral("password") }); addOption({{QStringLiteral("k"), QStringLiteral("skipScreen")}, QStringLiteral("Tell the Multi Monitor mode to not put anything on the screen with id n (example: 1 (skips entire screen 1)) - or on sub screen 0 or 1 (left or right) for ultra wide screens (example: 1.1 (skips the right side of screen 1)) (Default: (none))"), QStringLiteral("screen id"), }); addOption({{QStringLiteral("m"), QStringLiteral("multi-monitor-mode")}, QStringLiteral("Use the Multi Monitor mode to place Base Layouts on Screens in Fullscreen") }); #ifdef LTS_DEBUG addOption({QStringLiteral("dbgmmm"), QStringLiteral("Start the multi-monitor-mode with reduced size for use on development maschines") }); #endif addOption({{QStringLiteral("r"), QStringLiteral("replayId")}, QStringLiteral("Default: -1"), QStringLiteral("Replay ID"), QStringLiteral("-1") }); addOption({{QStringLiteral("l"), QStringLiteral("lang")}, QStringLiteral("Language iso code to use (de_DE, en_GB, en_US)"), QStringLiteral("") }); addOption({QStringLiteral("ignore-plugins"), QStringLiteral("Ignore these plugins, which otherwise would be loaded, " "specified by apps.json of the selected Base Plugin. " "Example: \"--ignore-plugins data:avm,data:bdv,gui:avm\""), QStringLiteral("ignore-plugins") // <= value }); addOption({QStringLiteral("projection"), QStringLiteral("Application is started on an Projection Workstation."), }); addOption({QStringLiteral("check-requirements"), QStringLiteral("Lets the Plugin Loader check if every App's requirements are met before starting"), }); addOption({QStringLiteral("enable-experimental-web-platform-features"), QString(), }); addOption({QStringLiteral("script"), QStringLiteral("Id of a script. The script has to exist in the given exercise."), QStringLiteral("ScriptId"), QStringLiteral("0") }); addOption({QStringLiteral("place-script-screens"), QStringLiteral("Let the screen 1 and screen 2 of the script-editor be placed automatically on startup.") }); m_additionalHelpStr = QStringLiteral("\n\n\e[33m example OWS : %1 -m -a0 -d1 -b legatus -t EXCTDS01:7400 -l de_DE \n\n\e[0m").arg(QCoreApplication::arguments().at(0)); // fprintf(stdout, "\n\n\e[33m example OWS : %s -m -a0 -d1 -b legatus -t EXCTDS01:7400 -l de_DE \n\n\e[0m", QCoreApplication::arguments().at(0).toLatin1().data()); } QString operatorName() const { return value(QStringLiteral("u")); } QString password() const { return value(QStringLiteral("p")); } int replayId() const { return value(QStringLiteral("r")).toInt(); } QString projectPluginIid() const { return value(QStringLiteral("b")); } QString stylePluginIid() const { return value(QStringLiteral("s")); } int applicationId() const { bool idk = false; int id = value(QStringLiteral("a")).toInt(&idk); if (!idk) { return -1; } return id; } bool multiMonitorMode() const { return isSet(QStringLiteral("m")); } bool isProjectionWorkstation() const { return isSet(QStringLiteral("projection")); } bool isForcedTabletMode() const { return isSet(QStringLiteral("x")); } bool isForcedWSMode() const { return isSet(QStringLiteral("w")); } QString langIsoCode() const { return value(QStringLiteral("l")); } QStringList ignoredPlugins() const { return value(QStringLiteral("ignore-plugins")).split(QLatin1Char(','), QString::SkipEmptyParts); } bool checkRequirements() const { return isSet(QStringLiteral("check-requirements")); } QString skipScreen() const { return value(QStringLiteral("k")); } QString qosFile() const { return value(QStringLiteral("q")).size() > 0 ? value(QStringLiteral("q")) : QString(); } int scriptId() const { return value(QStringLiteral("script")).toInt(); } bool placeScriptScreens() const { return isSet(QStringLiteral("place-script-screens")); } #ifdef LTS_DEBUG bool debugMultiMonitorMode() const { return isSet(QStringLiteral("dbgmmm")); } #endif }; // ------------------------------------------------------------------ int main(int argc, char **argv) // TODO: json strings to lower { qsrand(time(nullptr)); QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); QScrollerProperties props; props.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff); props.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff); QScrollerProperties::setDefaultScrollerProperties(props); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); //LtsApp app(argc, argv); NGLApplication app(argc, argv); app.createLogger("opApp"); QApplication::setQuitOnLastWindowClosed(false); // we are cool enough to handle it ourselves 8) QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QNetworkProxy::setApplicationProxy(QNetworkProxy()); // do NOT use proxies anywhere! NGL::LoggerHandler *lh = NGL::LoggerHandler::getLoggerHandler(); if (lh) { const QByteArray postfix = lh->loggerNamePostfix().toLocal8Bit() + "_dds_"; const QByteArray prefix = lh->loggerNamePrefix().toLocal8Bit(); rti::config::Logger &ddsLogger = rti::config::Logger::instance(); //ddsLogger.output_file(fdopen(STDOUT_FILENO, "w")); ddsLogger.output_file_set(postfix.data(), prefix.data(), 10 * 1024 * 1024, 10); ddsLogger.verbosity(rti::config::Verbosity_def::WARNING); //ddsLogger.verbosity_by_category(rti::config::LogCategory_def::COMMUNICATION, rti::config::Verbosity_def::STATUS_ALL); } // TODO: replace all exit(x) with qApp.quit() and an error msg LtsWidgets::LtsGlobalWaitDialog::getInstance()->setVisible(false); // avoid wait screen, we have the splash for this reason! #ifdef __linux__ // svcSituationRep - pgrep/pkill length limitation QProcess::startDetached(QLatin1String("pkill -9 svcSituationRep")); // kill it! QProcess::startDetached(QLatin1String("pkill -9 ffmpeg")); // otherwise a stray ffmpeg may record until the the disk is full #elif _WIN32 QProcess::startDetached(QLatin1String("taskkill /im svcSituationReplay /f")); #endif // Parse Options CmdLineParser options; if (!options.init()) return -1; // Set Translation QString langIsoCode = options.langIsoCode(); if (langIsoCode.isEmpty()) langIsoCode = QLocale::system().name(); NGL::setTranslationLocale(langIsoCode.toLatin1()); // Set Style QString stylePluginName = options.stylePluginIid(); if (stylePluginName.isEmpty()) { ERROR_LOG(app.baseLogger()) << "No Style Plugin Iid specified - abort."; return -1; } // .. to keep some compatibility to old resource structure TODO: rm ! QDir::setSearchPaths(QLatin1String("icon"), QStringList(QLatin1String(":/style/icons/"))); QDir::setSearchPaths(QLatin1String("icon"), QStringList(QLatin1String(":/style/"))); // FIXME: does qt check for recursion ?? LtsUtils::StyleManager::getInstance()->loadStyle(stylePluginName); // Load Plugins LtsPluginManager::LtsPluginLoader *pluginLoader = LtsPluginManager::LtsPluginLoader::getInstance(); QString projectPluginName = options.projectPluginIid(); if (projectPluginName.isEmpty()) { bool k; projectPluginName = QInputDialog::getText(nullptr, QCoreApplication::tr("No Project Plugin specified"), QCoreApplication::tr("Please specify a Project Plugin:"), QLineEdit::Normal, QString(), &k); // blocking, no event loop needed if (!k || projectPluginName.isEmpty()) { ERROR_LOG(app.baseLogger()) << "No Project Plugin Iid specified - abort."; return -1; } } // load project plugin if (!pluginLoader->loadPlugins(LtsPluginManager::PluginType::PROJECT, nullptr, {projectPluginName})) { ERROR_LOG(app.baseLogger()) << "Error loading Project Plugin - abort."; return -1; } LtsUtils::ProjectSettings::initFromFile(QStringLiteral(":project/project_settings.json")); // Setup Application if (options.multiMonitorMode()) LtsMultiMonitor::LtsMultiMonitor::getInstance()->setEnableMultiMonitorMode(); #ifdef LTS_DEBUG if (options.debugMultiMonitorMode()) LtsMultiMonitor::LtsMultiMonitor::getInstance()->setDebugMultiMonitorMode(); #endif // show splash LtsWidgets::Splash::getInstance()->show(); LtsAppDescriptor::App applicationId = LtsAppDescriptor::LtsAppDescriptor::appFromInteger(options.applicationId()); int exerciseId = options.exerciseId(); // -1 = invalid, 0 = admin, >0 = exercise int replayId = options.replayId(); // -1 = invalid, TODO: comment doku int scriptId = options.scriptId(); // <0 = invalid, 0 = default = ignore, >0 script QString operatorName = options.operatorName(); QString password = options.password(); QStringList qos_file = QStringList(options.qosFile()); // TODO: log4cxx/NGLLlogger does not flush here !! messages not seen ! if (scriptId < 0) { ERROR_LOG(app.baseLogger()) << "Given scriptId " << scriptId << " is invalid - abort."; return -1; } if (scriptId > 0 && applicationId != LtsAppDescriptor::App::Scripts) { ERROR_LOG(app.baseLogger()) << "ScriptId set but given app is not Scripts - abort."; return -1; } if (scriptId > 0 && exerciseId < 1) { ERROR_LOG(app.baseLogger()) << "ScriptId set but no exercise is given - abort."; return -1; } if (scriptId > 0 && exerciseId > 0 && applicationId == LtsAppDescriptor::App::Scripts) { LtsSessionData::LtsSessionData::getInstance()->setScriptId(scriptId); } if (options.placeScriptScreens() && applicationId != LtsAppDescriptor::App::Scripts) { ERROR_LOG(app.baseLogger()) << "PlaceScriptScreensn is set but given app is not Scripts - abort."; return -1; } LtsSessionData::LtsSessionData::getInstance()->setPlaceScriptScreens(options.placeScriptScreens()); if (operatorName.isEmpty() != password.isEmpty()) // check for xor and warn user { ERROR_LOG(app.baseLogger()) << "Specify -u if -p is specified & vise versa - abort."; return 1; } if (options.domainId() < 0) { ERROR_LOG(app.baseLogger()) << "Invalid configuration for domainId (" << options.domainId() << ") from LtsConfig - abort."; QMessageBox::critical(nullptr, QCoreApplication::tr("Invalid Domain Id"), QCoreApplication::tr("Domain #%1 is not valid - abort.").arg(options.domainId())); return -1; } // } LtsSessionData::LtsSessionData *sessionData = LtsSessionData::LtsSessionData::getInstance(); sessionData->setDomainIdPreset(options.domainId()); sessionData->setRequestedAppId(applicationId); if (options.useTcpConnection()) sessionData->setTcpConnectionUrl(options.tcpConnectionUrl()); if (options.checkRequirements()) sessionData->setDebugFlagValue(QStringLiteral("PluginManager.CheckAppRequirements"), true); // load JSON app description file QFile appsFile(QStringLiteral(":project/apps.json")); // TODO: convert Json => Binary Json if (!appsFile.open(QFile::ReadOnly)) { ERROR_LOG(app.baseLogger()) << "Could not read App Description File"; return -1; } QStringList lastErrors; QString loginPluginIid; LtsAppDescriptor::AppDescriptionVector appDescs = LtsAppDescriptor::LtsAppDescriptor::getAppDescriptionVector(appsFile.readAll(), lastErrors, options.ignoredPlugins(), loginPluginIid); if (loginPluginIid.isEmpty()) loginPluginIid = QStringLiteral("opm.login"); QString skipScreen = options.skipScreen(); int skipScreenId = -1; int skipSubScreenId = -1; if (!skipScreen.isEmpty()) { QStringList skipScreenList(skipScreen.split(QLatin1Char('.'), QString::SkipEmptyParts)); int skipScreenListCount = skipScreenList.count(); if (skipScreenListCount > 2) { qWarning() << "invalid skip screen syntax:" << skipScreen; return -1; } if (skipScreenListCount > 0) { bool k = false; skipScreenId = skipScreenList.at(0).toInt(&k); if (!k) { qWarning() << "invalid skip screen syntax:" << skipScreen; return -1; } } if (skipScreenListCount > 1) { bool k = false; skipSubScreenId = skipScreenList.at(1).toInt(&k); if (!k) { qWarning() << "invalid skip screen syntax:" << skipScreen; return -1; } } } LtsMultiMonitor::LtsMultiMonitor::getInstance()->setSkipScreen(skipScreenId, skipSubScreenId); appsFile.close(); if (!lastErrors.isEmpty()) { QMessageBox::critical(nullptr, QString(), lastErrors.join(QStringLiteral("\r\n\r\n"))); // TODO: log precise msg !! return -1; } if(options.isForcedTabletMode()) sessionData->setAsTablet(); else if (options.isForcedWSMode()) sessionData->setAsTablet(false); else if (!QTouchDevice::devices().isEmpty()) sessionData->setAsTablet(); LtsWidgets::LtsComboBox::setUseSelectionDialog(sessionData->isTablet()); LtsAppManager::LtsAppManager *appManager = LtsAppManager::LtsAppManager::getInstance(); appManager->setAvailableApps(appDescs); // Projection Specific Setup if (options.isProjectionWorkstation()) { if (operatorName.isEmpty() && password.isEmpty()) { ERROR_LOG(app.baseLogger()) << "Projection-User & Password has to be specified when --projection option is active!"; return 1; } applicationId = LtsAppDescriptor::App::Situation; LtsProjectionWorkstation::LtsProjectionWorkstation::getInstance()->setProjectionOperatorPreset(operatorName, password); } // Normal Setup else { if (applicationId == LtsAppDescriptor::App::Login) INFO_LOG(app.baseLogger()) << "No Application specified - starting with App Chooser."; // TODO: replayid can not life without exerciseId if (exerciseId >= 0 && replayId >= 0) // do not set both! { ERROR_LOG(app.baseLogger()) << "Use either -e (exercise) or -r (replay) - abort."; return 1; } if (!operatorName.isEmpty() && !password.isEmpty()) { sessionData->setOperatorPreset(operatorName, password); // if -u and -p (no Login window !) } if (exerciseId == 0) // Admin Session was requested explicitly { //sessionManager->setGlobalSessionVisible(); sessionData->setPartitionPreset(exerciseId, IDL::PartitionType::Global); } if (!qos_file.isEmpty()) // use defined qos file { //sessionManager->setGlobalSessionVisible(); DEBUG_LOG(app.baseLogger()) << "QOS -> using new file" << qos_file.join(QStringLiteral(",")); sessionData->setQosFile(qos_file); } if (exerciseId > 0) // non Admin => Exercise sessionData->setPartitionPreset(exerciseId, IDL::PartitionType::Exercise); if (replayId >= 0) // Replay sessionData->setPartitionPreset(replayId, IDL::PartitionType::Replay); } appManager->setLoginPluginIid(loginPluginIid); appManager->setMainApp(applicationId); if (applicationId == LtsAppDescriptor::App::ThpSituationReplay) { LtsSessionData::LtsSessionData::getInstance()->setVisibleParties({}); LtsSessionData::LtsSessionData::getInstance()->setOperatorRights({-1}); QTimer::singleShot(0, appManager, [qos_file, appManager]() { LtsSession::DdsConnectionParams params; params.domainId = 1; params.exerciseId = 2; params.partitionId = 2; if (!qos_file.isEmpty()) params.qos_file = qos_file; params.partitionType = IDL::PartitionType::Replay; appManager->createApp(LtsAppDescriptor::App::Situation, params, {}, false, true); } ); } else { appManager->showLogin(); } // Startup Application STARTUP_LOG(app.baseLogger()); int iRet = app.exec(); SHUTDOWN_LOG(app.baseLogger()); return iRet; }