Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/Common/LtsSession/lts_session.cpp
T
torsten 05095c6813 LtsSession/LtsElevation: BUILD_RTI Guards komplett, EXTERNAL_DEPENDENCIES.md
- lts_session_data_dds.h/cpp: Vollständig mit #ifdef BUILD_RTI geschützt
  Vermeidet vtable/qt_metacast Linker-Fehler bei BUILD_RTI=OFF
- lts_session.cpp: LtsSessionDataDds-Aufrufe mit BUILD_RTI Guards
  toString(): N/A-Placeholder im else-Zweig
  event(): QObject::event(e) statt LtsSessionDataDds::event(e)
- lts_elevation_manager.cpp:
  - m_logger im Initializer-List initialisieren (Reference-Member)
  - initDDS: Kein Zugriff auf incomplete type bei BUILD_RTI=OFF
  - createInstance: Rückgabetyp korrigiert (nullptr statt QStringList)
  - getFilenamesForExercise/TrainingArea: #ifdef BUILD_RTI
  - exerciseIdToTrainingAreaId: static method mit BUILD_RTI guard
- elevation_map_manager.h: QPoint3D-STUB entfernt, Forward-Declaration
- cnr_frequency_planning_helper.h/cpp: Vollständig mit BUILD_RTI geschützt
- EXTERNAL_DEPENDENCIES.md: Dokumentation fehlender external deps
  - RTI GCC-Inkompatibilität (DDS_OctetSeq vs DDS_OctetsSeq)
  - BUILD_RTI temporär OFF, BUILD_ARCGIS=ON default

Build-Status: LtsSession [17/1589] erfolgreich, LtsElevation gebaut
Offene Build-Fehler durch fehlende externe Dependencies (erwartet)
2026-08-21 01:48:52 +02:00

1849 lines
61 KiB
C++

/**
* @RDE_HEADER@
* Keeps the DDS Connector and common data about the session
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2016-05-15
*/
#include "lts_session.h"
#ifdef BUILD_RTI
#include "lts_session_data_dds.h"
#include "lts_session_lock_handler.h"
#endif
// Stub logging macros when BUILD_RTI=OFF
#ifndef BUILD_RTI
// Logging deaktivieren - qDebug() wird verwendet weil es operator<< für QString unterstützt
#define DEBUG_LOG(logger) if (false) qDebug()
#define WARNING_LOG(logger) if (false) qDebug()
#define ERROR_LOG(logger) if (false) qDebug()
#define INFO_LOG(logger) if (false) qDebug()
#define TRACE_LOG(logger) if (false) qDebug()
#define LOGFUNCTION ""
#endif
#include "lts_session_manager.h"
#include <LtsMultiMonitor/lts_multi_monitor.h>
#include <LtsMultiMonitor/lts_screen_base.h>
#include <LtsNotification/lts_notification.h>
#include <LtsNotification/lts_notification_ctl.h>
#include <LtsPluginManager/lts_plugin_loader.h>
#include <LtsSession/lts_session_data.h>
#include <LtsUtilsGuiDds/dds_vector_to_pixmap.h> // app icons
#include <LtsUtilsGuiDds/request_helper.h> // TODO: rm on release !
#include <LtsWidgets/lts_background_widget.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <LtsWidgets/lts_global_wait_dialog.h>
#include <LtsWidgets/lts_tab_widget.h>
#include <PluginInterfaces/data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#ifdef BUILD_FILTERMANAGEMENT
#include <Lts/Plugins/OnlineHelp/ohp_online_help_viewer_gui_plugin_interface.h> // XXX: grrr..
#endif
#include <QApplication>
#include <QHostInfo>
#include <QLabel>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QPainter>
#include <QScreen>
#include <QSvgRenderer>
#include <QTimer>
#include <QUuid>
#include <QWidget>
// #include <QDebug>
using namespace LtsWidgets;
namespace LtsSession
{
bool LtsSession::s_valgrind = false;
int LtsSession::s_nextSessionId = 0;
#ifdef BUILD_RTI
LtsSession::LtsSession(LtsSessionManager* sessionManager)
: m_sessionManager(sessionManager), m_mainBackground(nullptr), m_hasBaseLayout(false), m_baseLayout(nullptr),
m_markedForDeletion(false), m_payloads(false), m_initDone(false), m_menuVisible(true), m_firstActionsFetch(true),
m_exerciseData(new LtsWidgets::ExerciseData),
m_currentInitIfc(nullptr), m_slotPluginInitDoneMutex(false), m_pluginInitDone(false),
m_hidden(false), m_loadedFromSavegame(false), m_foreverInvisible(false),
m_id(s_nextSessionId++)
#else
LtsSession::LtsSession()
: m_mainBackground(nullptr), m_hasBaseLayout(false), m_baseLayout(nullptr),
m_markedForDeletion(false), m_payloads(false), m_initDone(false), m_menuVisible(true), m_firstActionsFetch(true),
m_exerciseData(nullptr), m_hidden(false), m_loadedFromSavegame(false), m_foreverInvisible(false),
m_id(s_nextSessionId++)
#endif
{
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait();
connect(this, &LtsSession::signalDoneInitializingSession, this, &LtsSession::slotStopWaitDialog);
connect(this, &LtsSession::signalInitializationAborted, this, &LtsSession::slotStopWaitDialog);
// preparations for stack connect
connect(this, &LtsSession::_signalDoneInitializingSession, this, [this]() {
// if (m_initDone)
// qWarning() << "blub";
disconnect(this, &LtsSession::_signalDoneInitializingSession, this, nullptr);
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
m_initDone = true;
emit signalDoneInitializingSession();
});
QTimer* t = new QTimer(this);
t->setInterval(1000);
connect(t, &QTimer::timeout, this, &LtsSession::signalStillAlive);
t->start();
m_scriptEditorTimer = new QTimer(this);
// [Qatar MNQ-474] Crash open Script Editor application Hack
if (strcmp(PROJECTBUILD, "qatarmout") == 0 || strcmp(PROJECTBUILD, "qatar") == 0)
{
#ifdef BUILD_RTI
DEBUG_LOG(m_logger) << "qatarmout Timer = 4000";
#endif
m_scriptEditorTimer->setInterval(4000);
}
else
{
#ifdef BUILD_RTI
DEBUG_LOG(m_logger) << "qatarmout Timer = 0";
#endif
m_scriptEditorTimer->setInterval(0);
}
m_scriptEditorTimer->setSingleShot(true);
#ifdef BUILD_RTI
connect(m_scriptEditorTimer, &QTimer::timeout, this, &LtsSession::delayScriptEditorStart);
#endif
}
LtsSession::~LtsSession()
{
// qCritical() << "~LtsSession";
// delete m_mainBackground; parented on hiddenWidget!
#ifdef BUILD_RTI
delete m_baseLayout; // TODO: deleteLater? problem: clear interfaces!
// qWarning() << this << "deleted" << m_baseLayout;
#endif
// Don't: qDeleteAll(m_notiCtlList);
// make sure to unref the data plugins, as they carry this LtsSession, and the erase method would not delete the
// Session (avoid circular dependencies)
#ifdef BUILD_RTI
clearGuiPluginInterfaces();
clearDataPluginInterfaces();
#endif
#ifdef BUILD_RTI
delete m_exerciseData;
#endif
}
QString LtsSession::toString() const
{
QString str;
str.append(QStringLiteral("LtsSession: this=%1").arg(QString::number(reinterpret_cast<quintptr>(this))));
#ifdef BUILD_RTI
str.append(QStringLiteral(", domainId=%1, partitionId=%2").arg(domainId()).arg(partitionId()));
#endif
str.append(QStringLiteral(", workspaceId='%1'").arg(workspaceId()));
#ifdef BUILD_RTI
str.append(QStringLiteral(", appToString='%1'").arg(appToString(app())));
str.append(QStringLiteral(", partitionType=%1, exerciseId='%2'").arg(partitionType()).arg(exerciseId()));
str.append(QStringLiteral(", LtsSessionDataDds=%1").arg(LtsSessionDataDds::toString()));
#else
str.append(QStringLiteral(", app=Login (stub)"));
str.append(QStringLiteral(", partitionType=N/A, exerciseId=N/A"));
#endif
return str;
}
#ifdef BUILD_RTI
QWidget* LtsSession::baseLayoutWidget()
{
// qWarning() << "baseLayoutWidget" << m_baseLayout;
// qWarning() << "baseLayoutWidget (widget)" << static_cast<QWidget *>(m_baseLayout);
return static_cast<QWidget*>(m_baseLayout);
}
#else
QWidget* LtsSession::baseLayoutWidget()
{
return nullptr;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::aboutToCloseTab(LayoutArea area)
{
m_baseLayout->getTabFromLayoutArea(area)->aboutToClose();
}
#else
void LtsSession::aboutToCloseTab(LayoutArea /*area*/)
{
// no-op in non-RTI build
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::aboutToClose()
{
emit sessionAboutToBeDestroyed(this);
if (m_baseLayout == nullptr)
return;
aboutToCloseTab(LayoutArea::eDialogTab);
aboutToCloseTab(LayoutArea::eInfoTab);
aboutToCloseTab(LayoutArea::eSpecialTab);
aboutToCloseTab(LayoutArea::eMainTab);
}
#else
void LtsSession::aboutToClose()
{
emit sessionAboutToBeDestroyed(this);
// no-op in non-RTI build
}
#endif // BUILD_RTI
void LtsSession::slotStopWaitDialog()
{
#ifdef BUILD_RTI
disconnect(this, &LtsSession::signalDoneInitializingSession, this, &LtsSession::slotStopWaitDialog);
disconnect(this, &LtsSession::signalInitializationAborted, this, &LtsSession::slotStopWaitDialog);
#endif
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
}
QString LtsSession::appToString(LtsAppDescriptor::App app)
{
using namespace LtsAppDescriptor;
switch (app)
{
case App::Situation:
return tr("Situation");
case App::ResourceManager:
return tr("Resource Manager");
case App::PlanEditor:
return tr("Plan Editor");
case App::BuildingViewer:
return tr("Building Viewer");
case App::OC:
return tr("O/C");
case App::OrgChart:
return tr("Organisation Chart");
case App::Scripts:
return tr("Scripts");
case App::Snapshot:
return tr("Snapshot");
case App::SystemMonitor:
return tr("System Monitor");
case App::Timeline:
return tr("Timeline");
case App::SymbolEditor:
return tr("Symbol Editor");
case App::ScriptEditorEssentialsView:
return tr("Scripts Essentials View");
case App::BaseDownloader:
return tr("Base Downloader");
case App::OnlineHelp:
return tr("Online Help");
case App::ThpSituationReplay:
return tr("THP Situation Replay");
case App::SituationTablet:
return tr("Situation (Tablet)");
case App::SilhouetteEditor:
return tr("Silhouette Editor");
case App::Shootback:
return tr("Shootback");
case App::Login:
return tr("Login");
break;
case App::SAAs:
return tr("SAAs");
break;
}
return tr("Unknown");
}
QString LtsSession::appIconFilename(LtsAppDescriptor::App app)
{
using namespace LtsAppDescriptor;
switch (app)
{
case App::Situation:
return QStringLiteral("icon:situation.svg");
case App::ResourceManager:
return QStringLiteral("icon:player_equipment.svg");
case App::PlanEditor:
return QStringLiteral("icon:plan_editor.svg");
case App::BuildingViewer:
return QStringLiteral("icon:3d_viewer.svg");
case App::OC:
return QStringLiteral("icon:display_oc_evaluations.svg");
case App::OrgChart:
return QStringLiteral("icon:org_chart.svg");
case App::Scripts:
return QStringLiteral("icon:insert_script.svg");
case App::Snapshot:
return QStringLiteral("icon:snapshots.svg");
case App::SystemMonitor:
return QStringLiteral("icon:system_status.svg");
case App::Timeline:
return QStringLiteral("icon:timeline.svg");
case App::SymbolEditor:
return QStringLiteral("icon:define_tactical_symbols.svg");
case App::ScriptEditorEssentialsView:
return QStringLiteral("icon:evaluation_elements.svg");
case App::BaseDownloader:
return QStringLiteral("icon:download.svg");
case App::OnlineHelp:
return QStringLiteral("icon:help.svg");
case App::ThpSituationReplay:
return QStringLiteral("icon:restart.svg");
case App::SituationTablet:
return QStringLiteral("icon:situation.svg");
case App::SilhouetteEditor:
return QStringLiteral("icon:situation.svg");
case App::Shootback:
return QStringLiteral("icon:target.svg");
case App::SAAs:
return QStringLiteral("icon:saa_remote_desktop.svg");
case App::Login:
break;
}
return {};
}
QIcon LtsSession::appToIcon(LtsAppDescriptor::App app)
{
return LtsUtils::iconFromSvg(appIconFilename(app));
}
#ifdef BUILD_RTI
bool LtsSession::removeMenuAction(LtsWidgets::LtsDragIcon* icon)
{
if (!m_baseLayout)
return false;
return m_baseLayout->removeMenuAction(icon);
}
#endif
#ifdef BUILD_RTI
void LtsSession::setMenuVisible(bool visible)
{
m_menuVisible = visible;
if (m_baseLayout == nullptr)
return;
m_baseLayout->getMenu()->setVisible(visible);
}
#else
void LtsSession::setMenuVisible(bool /*visible*/)
{
// no-op in non-RTI build
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
LtsDragIcon* LtsSession::addAction(const LtsWidgets::PluginData& plData, bool isFirstRun)
{
if (!m_baseLayout)
{
ERROR_LOG(m_logger) << "No BaseLayout available atm, cannot add action!";
return nullptr;
}
return m_baseLayout->addMenuAction(plData, isFirstRun);
}
LtsNotification::LtsNotification* LtsSession::createNotification(const QString& identifier)
{
LtsNotification::LtsNotificationController* c = new LtsNotification::LtsNotificationController(identifier);
LtsNotification::LtsNotification* n = new LtsNotification::LtsNotification(c);
if (m_baseLayout)
m_baseLayout->addNotification(c->createWidget());
m_notiCtlList.append(c);
// Wenn die notification getötet wird, auch wieder austragen...
connect(c, &LtsNotification::LtsNotificationController::destroyed, this,
[this, c]() { m_notiCtlList.removeAll(c); });
return n;
}
#else
LtsDragIcon* LtsSession::addAction(const LtsWidgets::PluginData& /*plData*/, bool /*isFirstRun*/)
{
// no-op in non-RTI build
return nullptr;
}
LtsNotification::LtsNotification* LtsSession::createNotification(const QString& /*identifier*/)
{
// no-op in non-RTI build
return nullptr;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
bool LtsSession::init(const DdsConnectionParams& connParams,
const QVector<LtsPluginManager::AppPluginInstance>& dataPluginList,
const QVector<LtsPluginManager::AppPluginInstance>& guiPluginList, bool hidden)
{
m_foreverInvisible = hidden;
if (!LtsSessionDataDds::init(connParams))
return false;
initializePlugins(dataPluginList, guiPluginList);
return true;
}
bool LtsSession::init(const dds::domain::DomainParticipant& dp, const DdsConnectionParams& connParams,
const QVector<LtsPluginManager::AppPluginInstance>& dataPluginList,
const QVector<LtsPluginManager::AppPluginInstance>& guiPluginList)
{
if (!LtsSessionDataDds::init(dp, connParams))
return false;
initializePlugins(dataPluginList, guiPluginList);
return true;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::initializePlugins(const QVector<LtsPluginManager::AppPluginInstance>& dataPluginList,
const QVector<LtsPluginManager::AppPluginInstance>& guiPluginList)
{
initializeDataPlugins(dataPluginList);
initializeGuiPlugins(guiPluginList);
}
void LtsSession::initializeDataPlugins(const QVector<LtsPluginManager::AppPluginInstance>&
dataPluginList) // TODO: DOC: no gui ifcs in data ifcs ! (as
// fetchInterfaces() is done before gui ifcs are loaded)
{
QMap<QString, std::shared_ptr<DataPluginBase::Interface>> newDataPluginInterfaces;
for (const LtsPluginManager::AppPluginInstance& api : dataPluginList)
{
DataPluginBase::Plugin* plugin = qobject_cast<DataPluginBase::Plugin*>(api.pluginInstance.plugin);
if (!plugin)
{
WARNING_LOG(m_logger) << "Session: invalid data plugin ("
<< api.pluginInstance.plugin->metaObject()->className() << ")"
<< api.pluginInstance.fileName;
continue;
}
// super heavy hardcore hack to speed up login -> we need to check what plugins are needed for an app!
if (app() == LtsAppDescriptor::App::Login &&
(!plugin->pluginName().contains(QStringLiteral("AssetManagement")) &&
!plugin->pluginName().contains(QStringLiteral("OperatorManagement")) &&
!plugin->pluginName().contains(QStringLiteral("ExerciseManagement"))))
continue;
// check if plugin has to be loaded in this session type
if (!plugin->availableInPartition(partitionType()))
{
DEBUG_LOG(m_logger) << "Data plugin " << api.pluginInstance.pluginName
<< " is not available in this partition type " << partitionType();
continue;
}
// super heavy hardcore hack to speed up login
if ((!plugin->pluginName().contains(QStringLiteral("AssetManagement")) &&
!plugin->pluginName().contains(QStringLiteral("OperatorManagement")) &&
!plugin->pluginName().contains(QStringLiteral("ExerciseManagement"))) &&
app() == LtsAppDescriptor::App::Login)
continue;
std::shared_ptr<DataPluginBase::Interface> ifc = plugin->createDataInterface(this);
if (!ifc)
{
WARNING_LOG(m_logger) << "Create data interface failed for '" << api.pluginInstance.pluginName << "' !";
continue;
}
m_dataPluginInterfaces[plugin->pluginName()] = ifc;
newDataPluginInterfaces[plugin->pluginName()] = ifc;
DEBUG_LOG(m_logger) << "Adding data plugin " << plugin->pluginName() << " for " << partitionType() << " - "
<< this;
}
addAvailablaeDataPluginInterfaces(newDataPluginInterfaces);
}
#endif
#ifdef BUILD_RTI
void LtsSession::initializeGuiPlugins(const QVector<LtsPluginManager::AppPluginInstance>& guiPluginList)
{
m_failedFetches.clear();
/* important to create gui interfaces even if they are not available in a session,
* but foreign plugins can still use their ForeignGuiInterface to use
* their windows */
for (auto i = guiPluginList.constBegin(); i != guiPluginList.constEnd(); ++i)
{
const LtsPluginManager::AppPluginInstance& api = *i;
GuiPluginBase::Plugin* plugin = qobject_cast<GuiPluginBase::Plugin*>(api.pluginInstance.plugin);
if (!plugin)
{
WARNING_LOG(m_logger) << "Session: invalid gui plugin ("
<< api.pluginInstance.plugin->metaObject()->className() << ")"
<< api.pluginInstance.fileName;
continue;
}
// check if plugin has to be loaded in this session type
if (!plugin->availableInPartition(partitionType()))
{
DEBUG_LOG(m_logger) << "Gui plugin " << api.pluginInstance.pluginName
<< " is not available in this partition type " << partitionType();
continue;
}
std::shared_ptr<GuiPluginBase::Interface> ifc = plugin->createGuiInterface(this);
if (!ifc)
{
WARNING_LOG(m_logger) << "Create gui interface failed for '" << api.pluginInstance.pluginName << "' ("
<< api.pluginInstance.plugin->metaObject()->className() << ") !";
continue;
}
QFlags<LtsAppDescriptor::PluginInfo::Flag> flags = api.m_flags; // copy flags
if (api.pluginInstance.pluginName == QStringLiteral("dev"))
flags |= LtsAppDescriptor::PluginInfo::Flag::ACTIONS;
ifc->setFlags(flags); // durchreichen.. raw plugin => plugin instance
ifc->setOptions(api.m_options); // s.a.a.
ifc->setAppId(api.m_appId); // s.a.a.
m_guiPluginInterfaces[plugin->pluginName()] = ifc;
DEBUG_LOG(m_logger) << "Adding gui plugin " << plugin->pluginName() << " for " << partitionType() << " - "
<< this;
}
/*/
* there are all plugin instances in this list
* if fetchInterface of a single plugin failes, that plugin instance will be removed (does not find his obligatory
plugin(s) in this list)
* a refetch has to be done, in case some other plugin(s) used that plugin which is now deleted
/*/
QMutableMapIterator<QString, std::shared_ptr<GuiPluginBase::Interface>> it(
m_guiPluginInterfaces); // modify a list while iterating through it
while (it.hasNext())
{
const auto val = it.next();
const QString& guiPluginKey = val.key();
std::shared_ptr<GuiPluginBase::Interface> guiPlugin = val.value();
if (!guiPlugin->fetchInterfaces())
{
DEBUG_LOG(m_logger) << "Fetching interfaces failed for Gui Plugin '" << guiPluginKey
<< "' - removing and refetching !";
m_failedFetches.append(guiPluginKey);
it.remove();
it.toFront(); // rewind!
// remove from payloads list if failed, because payload might already be added before refetching, but we
// don't want payloads of plugins that failed fetching interfaces..
for (auto i = m_payloadPriorityMap.begin(); i != m_payloadPriorityMap.end(); ++i)
{
std::shared_ptr<GuiPluginBase::Interface> payloadIfc = *i;
if (payloadIfc == guiPlugin)
break;
}
m_payloadList.removeAll(guiPlugin);
}
else
{
// ERROR_LOG(m_logger) << "GUI FETCH INTERFACE OKAY!";
int executionPriority = guiPlugin->executionPriority();
if (executionPriority > -1)
{
if (m_payloads && guiPlugin->getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::PAYLOAD))
{
if (executionPriority == 9999)
{
if (!m_payloadList.contains(guiPlugin))
m_payloadList.append(guiPlugin);
}
else
m_payloadPriorityMap.insert(executionPriority,
guiPlugin); // addPayload(executionPriority, guiPlugin);
// DEBUG_LOG(m_logger) << " > has payloads, adding payload request to session";
}
}
// DEBUG_LOG(m_logger) << " > done";
}
}
QTimer::singleShot(100, this, &LtsSession::slotStartPluginInit);
// executePayloads(); // does not execute when there are no payloads, but is needed to be called here !
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
LtsTabWidget* LtsSession::locateWidget(QWidget* widgetToLocate, LayoutArea area)
{
if (!m_baseLayout)
return nullptr;
LtsTabWidget* tabWidget = m_baseLayout->getTabFromLayoutArea(area);
if (tabWidget->indexOf(widgetToLocate) >= 0)
return tabWidget;
return nullptr; // not found!
}
#else
LtsTabWidget* LtsSession::locateWidget(QWidget* /*widgetToLocate*/, LayoutArea /*area*/)
{
return nullptr;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::enableBaseLayoutMenu(bool on)
{
if (m_baseLayout)
{
QWidget* ltsMenu = m_baseLayout->getMenu();
if (ltsMenu)
ltsMenu->setEnabled(on);
}
}
void LtsSession::enableBaseLayoutArea(LtsWidgets::LayoutArea area, bool on)
{
if (m_baseLayout)
{
QWidget* ltsWidget = m_baseLayout->getTabFromLayoutArea(area);
if (ltsWidget)
ltsWidget->setEnabled(on);
}
}
#else
void LtsSession::enableBaseLayoutMenu(bool /*on*/)
{
// no-op in non-RTI build
}
void LtsSession::enableBaseLayoutArea(LtsWidgets::LayoutArea /*area*/, bool /*on*/)
{
// no-op in non-RTI build
}
#endif // BUILD_RTI
int LtsSession::workstationIp()
{
static int wsId = -1;
if (wsId == -1)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
const QString hostname = workstationName();
const auto addreses = QHostInfo::fromName(hostname).addresses();
for (const QHostAddress& ha : addreses)
{
if (ha.isLoopback())
continue;
if (ha.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
continue;
wsId = static_cast<int>(ha.toIPv4Address());
break;
}
#else
const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
for (const QNetworkInterface& ninterface : interfaces)
{
if (ninterface.type() == QNetworkInterface::InterfaceType::Wifi)
continue;
const auto addreseEntry = ninterface.addressEntries();
for (const QNetworkAddressEntry& ent : addreseEntry)
{
const QHostAddress ha = ent.ip();
if (ha.isLoopback())
continue;
if (ha.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
continue;
wsId = static_cast<int>(ha.toIPv4Address());
break;
}
if (wsId != -1)
break;
}
#endif
}
return wsId;
}
QString LtsSession::workstationName()
{
return QHostInfo::localHostName().toUpper();
}
const QString LtsSession::workspaceId() const
{
#ifdef BUILD_RTI
if (isReplayPartition())
return QStringLiteral("replay_%1").arg(QString::number(partitionId()));
#endif
return m_workspaceId; // sessionManager->workspaceId();
}
void LtsSession::setWorkspaceId(const QString &newWorkspaceId /* <= MW: that's why I like "get" in getter names (needed to prepend "new" because of already existing method with the name "workspaceId") */)
{
#ifdef BUILD_RTI
DEBUG_LOG(m_logger) << LOGFUNCTION << " change workspaceId: cur = '" << m_workspaceId << "' for app '"
<< appToString(app()) << "'";
DEBUG_LOG(m_logger) << LOGFUNCTION << " change workspaceId: new = '" << newWorkspaceId << "' for app '"
<< appToString(app()) << "'";
#else
Q_UNUSED(newWorkspaceId)
#endif
m_workspaceId = newWorkspaceId; // m_sessionManager->setWorkspaceId(workspaceId);
#ifdef BUILD_RTI
if (m_baseLayout)
m_baseLayout->setWorkspaceId(workspaceId() /* use getter instead of member var, as replay partition strings can only be retrieved with the getter */);
#endif // BUILD_RTI
emit workspaceIdChanged(newWorkspaceId);
}
#ifdef BUILD_RTI
ExcState LtsSession::exerciseState() const
{
return m_exerciseData ? m_exerciseData->exState : ExerciseState::eUnknown;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::connectOnlineHelpButton(LtsWidgets::LtsDialog* widget)
{
// FIXME: HACK: also connect show online help here !!
connect(widget, &LtsDialog::signalShowOnlineHelp, this, &LtsSession::slotShowOnlineHelp, Qt::UniqueConnection);
}
void LtsSession::slotStapleTopicLockHandler(LtsWidgets::LtsDialog* widget)
{
if (widget->property("topicLockStapled").isValid())
{
Q_ASSERT(false);
return;
}
widget->setProperty("topicLockStapled", true);
connectOnlineHelpButton(widget);
if (m_coreFtc == nullptr)
{
DEBUG_LOG(m_logger) << "no core ftc, no TopicLockHandler for " << toString();
return;
}
auto* topicLockHandler = new TopicLockHandler(/* widget <= see comment below */);
/*/
* Conceptional: widgets is closing, widget deletes lock handler, lock handler unlocks via ftc,
* lock handler was deleted, ftc answers to already deleted lock handler => crash
* This is a conceptional problem in all the ftc handlers
/*/
if (!topicLockHandler->init(m_coreFtc, m_exerciseId))
{
WARNING_LOG(m_logger) << "LtsSession::addWidget: init of TopicLockHandler failed!";
delete topicLockHandler;
return;
}
connect(topicLockHandler, &TopicLockHandler::signalLockDialog, widget, &LtsDialog::slotLock, Qt::QueuedConnection);
connect(topicLockHandler, &TopicLockHandler::signalUnlockDialog, widget, &LtsDialog::slotUnlock,
Qt::QueuedConnection);
connect(widget, &LtsDialog::signalLockTopic, topicLockHandler, &TopicLockHandler::slotTryLock,
Qt::DirectConnection); // sync!
// widget->setTopicLockHandler(topicLockHandler);
connect(widget, &LtsDialog::destroyed, topicLockHandler, &TopicLockHandler::slotFinalize, Qt::QueuedConnection);
// qWarning() << "added tlh to" << widget->windowTitle();
connectOnlineHelpButton(widget);
}
#else
void LtsSession::connectOnlineHelpButton(LtsWidgets::LtsDialog* widget)
{
Q_UNUSED(widget)
// no-op in non-RTI build
}
void LtsSession::slotStapleTopicLockHandler(LtsWidgets::LtsDialog* widget)
{
Q_UNUSED(widget)
// no-op in non-RTI build
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
bool LtsSession::focusTab(const QString& menuGroup, const QString& identifier, LtsWidgets::LayoutArea area)
{
if (!m_baseLayout)
{
ERROR_LOG(m_logger) << "no base layout to focus a tab on! menuGroup: " << menuGroup << "ident: " << identifier;
return false;
}
return m_baseLayout->focusTab(menuGroup, identifier, area);
}
#else
bool LtsSession::focusTab(const QString& menuGroup, const QString& identifier, LtsWidgets::LayoutArea area)
{
Q_UNUSED(menuGroup)
Q_UNUSED(identifier)
Q_UNUSED(area)
return false;
}
#endif
#ifdef BUILD_RTI
LtsWidgets::LtsDialog* LtsSession::getWidget(const QString& menuGroup, const QString& identifier,
LtsWidgets::LayoutArea area)
{
if (!m_baseLayout)
{
ERROR_LOG(m_logger) << "no base layout to get a widget from! menuGroup: " << menuGroup
<< "ident: " << identifier;
return nullptr;
}
return m_baseLayout->getWidget(menuGroup, identifier, area);
}
#else
LtsWidgets::LtsDialog* LtsSession::getWidget(const QString& menuGroup, const QString& identifier,
LtsWidgets::LayoutArea area)
{
Q_UNUSED(menuGroup)
Q_UNUSED(identifier)
Q_UNUSED(area)
return nullptr;
}
#endif
#ifdef BUILD_RTI
bool LtsSession::widgetExists(const QString& menuGroup, const QString& identifier, LayoutArea area) const
{
if (!m_baseLayout)
return false;
LtsTabWidget* tab = m_baseLayout->getTabFromLayoutArea(area);
if (!tab)
return false;
QWidget* existingWidget = tab->getWidget(menuGroup, identifier);
return existingWidget != nullptr;
}
#else
bool LtsSession::widgetExists(const QString& /*menuGroup*/, const QString& /*identifier*/, LayoutArea /*area*/) const
{
return false;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
bool LtsSession::addWidget(LtsDialog* widget, const QString& menuGroup, const QString& identifier, LayoutArea area,
bool setClosable)
{
// TODO: operator selection + possibility to permanent select base layout until its dissolving
if (!m_baseLayout)
{
ERROR_LOG(m_logger) << "no base layout to put a widget on! menuGroup: " << menuGroup << "ident: " << identifier;
return false;
}
// slotStapleTopicLockHandler(widget); => already done in blw's addWidget (below!)
// FIXMe: connect(widget, &LtsDialog::signalShowOnlineHelp,
// this, &LtsSession::slotShowOnlineHelp,
// Qt::UniqueConnection) done in slotStaple.. because using LtsDialog::addDialog does NOT reach this
// code here !
return m_baseLayout->addWidget(widget, menuGroup, identifier, area, setClosable);
}
#else
bool LtsSession::addWidget(LtsDialog* widget, const QString& menuGroup, const QString& identifier, LayoutArea area,
bool setClosable)
{
Q_UNUSED(widget)
Q_UNUSED(menuGroup)
Q_UNUSED(identifier)
Q_UNUSED(area)
Q_UNUSED(setClosable)
return false;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::setExerciseData(const LtsWidgets::ExerciseData& exerciseData)
{
// avoid mutiple calls (and signal to emitted multiple times)
if ((*m_exerciseData) == exerciseData)
return;
*m_exerciseData = exerciseData;
// partitionType(); ?!?
if (!m_baseLayout)
return;
m_baseLayout->setExerciseData(exerciseData);
emit signalExerciseDataChanged();
}
void LtsSession::setProfilePicture(const QPixmap& pixmap)
{
// partitionType(); ?!?
if (!m_baseLayout)
return;
m_baseLayout->setProfilePicture(pixmap);
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::makeVisible()
{
Q_ASSERT(m_baseLayout == nullptr);
if (m_baseLayout) // onyl create a new base layout when there was not one before !
{
qCritical() << "base layout already visible";
return;
}
createBaseLayout();
}
#else
void LtsSession::makeVisible()
{
// BUILD_RTI=OFF: No base layout to create
}
#endif
#ifdef BUILD_RTI
void LtsSession::refetchActions()
{
// get actions
for (auto i = m_guiPluginInterfaces.cbegin(); i != m_guiPluginInterfaces.cend(); ++i)
{
std::shared_ptr<GuiPluginBase::Interface> ifc = *i;
if (!ifc->availableInPartition(partitionType()))
{
DEBUG_LOG(m_logger) << i.key() << " is not available in this partition type " << partitionType();
continue;
}
if (m_firstActionsFetch && ifc->getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN) &&
!ifc->getFlags().testFlag(
LtsAppDescriptor::PluginInfo::Flag::ACTIONS)) // respect the MAIN flag, even though ACTIONS is not set
// (main, but NOT actions) [but only if this is NOT a
// refetch]
{
ERROR_LOG(m_logger) << "Plugin '" << i.key()
<< "' has flag 'MAIN' but is missing the 'ACTIONS' flag - ingoring actions!";
continue;
}
if (ifc->getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::ACTIONS))
{
// get gui plugin's actions (only when init was successful)
const QVector<LtsWidgets::PluginData> plData = ifc->getActions();
if (plData.isEmpty())
DEBUG_LOG(m_logger) << i.key() << " (" << ifc->menuGroup() << ") does not provide actions";
// WARNING_LOG(m_logger) << " > " << plData.count() << " Actions";
for (const LtsWidgets::PluginData& pd : plData)
{
if (!pd.menuGroup.isEmpty() && !pd.menuText.isEmpty() &&
pd.identifier.isEmpty()) // check if identifier is missing
ERROR_LOG(m_logger) << "Identifier for Action " << pd.menuGroup << " - " << pd.menuText
<< " missing - not added!";
else
{
if (!LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(pd.operatorRight))
m_missingRightActions += pd;
m_baseLayout->addMenuAction(pd, m_firstActionsFetch);
}
}
}
else
{
// WARNING_LOG(m_logger) << " > " << plData.count() << " Actions - but ignored by flag";
}
}
#ifdef LTS_DEBUG
if (m_firstActionsFetch)
{
const QString& executeAction(qEnvironmentVariable("EXCON_EXECUTE_ACTION", {}));
if (!executeAction.isEmpty())
{
WARNING_LOG(m_logger) << "EXCON_EXECUTE_ACTION was set to: " << executeAction;
m_baseLayout->executeAction(executeAction);
}
}
#endif
m_firstActionsFetch = false;
}
#else
void LtsSession::refetchActions()
{
// BUILD_RTI=OFF: No actions to fetch
m_firstActionsFetch = false;
}
#endif
#ifdef BUILD_RTI
void LtsSession::slotSwap()
{
LtsMultiMonitor::LtsMultiMonitor::getInstance()->selectAndSwap(m_baseLayout);
}
#else
void LtsSession::slotSwap()
{
// BUILD_RTI=OFF: No base layout to swap
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
int LtsSession::screenId() const
{
if (m_baseLayout == nullptr)
return -1;
LtsMultiMonitor::LtsScreenBase* screen =
LtsMultiMonitor::LtsMultiMonitor::getInstance()->widgetsScreen(m_baseLayout);
if (screen == nullptr)
return -2;
return screen->screenId();
}
#else
int LtsSession::screenId() const
{
return -1;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
int LtsSession::screenContainerId() const
{
if (m_baseLayout == nullptr)
return -1;
LtsMultiMonitor::LtsScreenBase* screen =
LtsMultiMonitor::LtsMultiMonitor::getInstance()->widgetsScreen(m_baseLayout);
if (screen == nullptr)
return -2;
try
{
return screen->containerIdOfWidget(m_baseLayout);
}
catch (...)
{
}
return -3;
}
#else
int LtsSession::screenContainerId() const
{
return -1;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
int LtsSession::screenTypeId() const
{
if (m_baseLayout == nullptr)
return -1;
LtsMultiMonitor::LtsScreenBase* screen =
LtsMultiMonitor::LtsMultiMonitor::getInstance()->widgetsScreen(m_baseLayout);
if (screen == nullptr)
return -2;
return screen->screenType();
}
#else
int LtsSession::screenTypeId() const
{
return -1;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
LtsAppDescriptor::App LtsSession::app() const
{
return m_sessionManager ? m_sessionManager->appId() : LtsAppDescriptor::App::Login;
}
#else
LtsAppDescriptor::App LtsSession::app() const
{
return LtsAppDescriptor::App::Login;
}
#endif
#ifdef BUILD_RTI
bool LtsSession::event(QEvent* e)
{
if (e->type() == QEvent::LanguageChange)
m_baseLayout->setAppName(appToString(app()));
return LtsSessionDataDds::event(e);
}
#else
bool LtsSession::event(QEvent* e)
{
if (e->type() == QEvent::LanguageChange)
m_baseLayout->setAppName(appToString(app()));
return QObject::event(e);
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::addDeveloperActions()
{
// DEVELOPER / DEBUG MENU
{
LtsWidgets::PluginData p;
p.menuGroup = QStringLiteral("[Dev]");
p.menuText = QStringLiteral("Open Admin Session");
p.identifier = QStringLiteral("OpenAdminSession");
p.directFunc = [&](const LtsWidgets::PluginData&) {
LtsSession* adminSession = m_sessionManager->getSession(IDL::PartitionType::Global, 0);
if (!adminSession)
{
// QMessageBox::information(nullptr, QString(), QStringLiteral("no admin session"));
DdsConnectionParams connParams;
connParams.domainId = domainId();
connParams.partitionId = 0;
connParams.exerciseId = 0;
connParams.partitionType = IDL::PartitionType::Global;
connParams.tcpConnectionUrl = tcpConnectionUrl();
connParams.qos_file = m_qosFileList;
adminSession = m_sessionManager->createSession(
connParams, true,
false); // no payloads !! TODO: is this a real domainId or a dead var ??
return;
}
else
adminSession->makeVisible();
};
m_baseLayout->addMenuAction(p);
}
{
LtsWidgets::PluginData p;
p.menuGroup = QStringLiteral("[Dev]");
p.menuText = QStringLiteral("Slow down RequestHelper");
p.identifier = QStringLiteral("SlowDownRequestHelper");
p.directFunc = [&](const LtsWidgets::PluginData&) { LtsUtils::RequestHelper::s_debug = true; };
m_baseLayout->addMenuAction(p);
}
{
LtsWidgets::PluginData p;
p.menuGroup = QStringLiteral("[Dev]");
p.menuText = QStringLiteral("Reset RequestHelper");
p.identifier = QStringLiteral("ResetRequestHelper");
p.directFunc = [&](const LtsWidgets::PluginData&) { LtsUtils::RequestHelper::s_debug = false; };
m_baseLayout->addMenuAction(p);
}
{
LtsWidgets::PluginData p;
p.menuGroup = QStringLiteral("[Dev]");
p.menuText = QStringLiteral("fake DoneInitializingSession");
p.identifier = QStringLiteral("fakeDoneInitializingSession");
p.directFunc = [&](const LtsWidgets::PluginData&) {
m_initDone = true;
emit _signalDoneInitializingSession();
};
m_baseLayout->addMenuAction(p);
}
// END DEVELOPER / DEBUG MENU
}
#endif
#ifdef BUILD_RTI
bool LtsSession::notifyUnsavedChanges()
{
if (m_baseLayout == nullptr)
return true;
return m_baseLayout->notifyUnsavedChanges();
}
#else
bool LtsSession::notifyUnsavedChanges()
{
return true;
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::createBaseLayout()
{
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
using namespace LtsAppDescriptor;
TRACE_LOG(m_logger) << LOGFUNCTION << " START, Creating Base Layout for Session " << partitionId();
Q_ASSERT(m_baseLayout == nullptr);
if (m_baseLayout != nullptr)
{
WARNING_LOG(m_logger) << "Base Layout already exists for Session" << this;
return; // already exists
}
m_baseLayout = new LtsBaseLayoutWidget; // main widget
connect(m_baseLayout, &LtsBaseLayoutWidget::signalSuccessfullyPlaced, this, [this]() {
DEBUG_LOG(m_logger) << "current APP " << appToString(this->app());
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
if (this->app() == App::Scripts)
{
m_scriptEditorTimer->start();
}
else
{
if (m_needsToBeSuccessfullyPlaced)
{
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
emit
_signalDoneInitializingSession(); // needs to be emitted here, as if 'm_needsToBeSuccessfullyPlaced' is
// TRUE, it was not emitted before
}
}
});
connect(m_baseLayout, &LtsBaseLayoutWidget::destroyed, this, [this]() {
m_baseLayout = nullptr; // sec
// qWarning() << "baseLayout deleted";
});
m_baseLayout->hide(); // hide
m_baseLayout->setSessionInfo(domainId(), partitionType(), partitionId(),
workspaceId()); // this shd ptr has a different counter ..
m_baseLayout->setWindowIcon(
appToIcon(app())); // for the magic corner to have an icon to show for switching to / from secondaries
// auto *x = new QLabel;
// x->setPixmap(m_baseLayout->windowIcon().pixmap(128, 128));
// x->show();
if (app() == App::ScriptEditorEssentialsView || // NOTE: timeline's replay app and snapshot's edit plan are
// secondaries, too - setSecondaryWidget needs to be called from
// timeline & snapshot app, too
m_presetBaseLayoutAsSecondaryWidget)
m_baseLayout->setSecondaryWidget();
connect(m_baseLayout, &LtsBaseLayoutWidget::signalRetranslateActions, this, &LtsSession::refetchActions);
connect(m_baseLayout, &LtsBaseLayoutWidget::signalClose, this, &LtsSession::signalClose);
connect(m_baseLayout, &LtsBaseLayoutWidget::signalLogout, this, &LtsSession::signalLogout);
connect(m_baseLayout, &LtsBaseLayoutWidget::signalShowOperatorSettings, this,
&LtsSession::slotShowOperatorSettings);
connect(m_baseLayout, &LtsBaseLayoutWidget::signalSwap, this, &LtsSession::slotSwap);
connect(this, &LtsSession::partitionTimeChanged, m_baseLayout, &LtsBaseLayoutWidget::setExerciseTime);
connect(m_baseLayout, &LtsBaseLayoutWidget::signalStapleTopicLockHandler, this,
&LtsSession::slotStapleTopicLockHandler, Qt::DirectConnection);
const auto* sessionData = LtsSessionData::LtsSessionData::getInstance();
const QString& operatorName = sessionData->getOperatorName();
bool showTerminalWindow = sessionData->getShowTerminalWindow();
m_baseLayout->setOperatorName(operatorName, showTerminalWindow);
m_baseLayout->setProfilePicture(sessionData->getProfilePicture());
m_baseLayout->setAppName(appToString(app()));
refetchActions();
#ifdef LTS_DEBUG
bool showDeveloperActions = true;
#else
bool showDeveloperActions = false;
#endif
if (sessionData->hasDebugFlag(QStringLiteral("DeveloperTools.Active")))
showDeveloperActions = true;
if (showDeveloperActions)
addDeveloperActions();
for (LtsNotification::LtsNotificationController* ctl : qAsConst(m_notiCtlList))
{
if (!m_baseLayout->notificationExists(ctl->identifier())) // add if non-existent only
m_baseLayout->addNotification(ctl->createWidget()); // FIXME: crash when no icons?
}
m_hasBaseLayout = true; // not needed anymore, but for its correctness.....
m_baseLayout->getMenu()->setVisible(m_menuVisible);
m_baseLayout->initilizationFinished();
// QMessageBox::warning(nullptr, QStringLiteral("attach!"), QString());
if (!m_foreverInvisible)
{
// build list of irreplacable widgets by the dependency tree of its dependencies and their dependencies'
// dependencies
QVector<QWidget*> irreplacableWidgets{baseLayoutWidget()};
LtsSession* dependencySession = dependency();
int runaway = 100;
while (dependencySession && runaway > 0)
{
irreplacableWidgets += dependencySession->baseLayoutWidget();
dependencySession = dependencySession->dependency();
runaway--;
}
// qWarning() << "#2 irreplacableWidgets count" << irreplacableWidgets.count() << "from" << this;
// for (QWidget *w : irreplacableWidgets)
// qWarning() << "irre" << w;
LtsMultiMonitor::LtsMultiMonitor* multiMonitor = LtsMultiMonitor::LtsMultiMonitor::getInstance();
WARNING_LOG(m_logger) << "Presets: ScreenId: " << m_screenIdPreset
<< ", screenContainerId: " << m_screenContainerIdPreset;
if (m_screenIdPreset >= 0)
multiMonitor->putScreen(m_baseLayout, m_screenIdPreset, m_screenContainerIdPreset);
else
multiMonitor->selectScreen(m_baseLayout, nullptr, true, false, irreplacableWidgets);
slotMonitorSelected();
connect(multiMonitor, &LtsMultiMonitor::LtsMultiMonitor::signalSelected, this, &LtsSession::slotMonitorSelected,
Qt::UniqueConnection);
connect(multiMonitor, &LtsMultiMonitor::LtsMultiMonitor::signalScreenCountChanged, m_baseLayout,
&LtsBaseLayoutWidget::slotScreenCountChanged);
m_baseLayout->slotScreenCountChanged(multiMonitor->screenCount());
}
if (!sessionData->isTablet())
return; // done here if not a tablet
LtsNotification::LtsNotification* noti = createNotification(QStringLiteral("TabletWindowSwitcher"));
noti->setIcon(QIcon(QStringLiteral("icon:switch_display.svg")));
noti->setAction([this]() { emit taskSwitch(this /* tell it that we are the caller, don't hide US! */); });
emit hideAllOtherBLWs(this);
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::slotMonitorSelected()
{
auto mmm = LtsMultiMonitor::LtsMultiMonitor::getInstance();
LtsMultiMonitor::LtsScreenBase* screen = mmm->widgetsScreen(m_baseLayout);
if (!screen)
return;
int newScreenContainerId;
try
{
newScreenContainerId = screen->containerIdOfWidget(m_baseLayout);
}
catch (...)
{
WARNING_LOG(m_logger) << "cannot find container for base layout";
return;
}
const int newScreenId = screen->screenId();
if (m_screenId != newScreenId)
{
m_screenId = newScreenId;
m_screenContainerId = newScreenContainerId;
emit signalScreenIdChanged(m_screenId, m_screenContainerId, screen->screenType());
}
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::delayScriptEditorStart()
{
DEBUG_LOG(m_logger) << "LtsSession::delayScriptEditorStart ";
if (m_needsToBeSuccessfullyPlaced)
{
// qWarning() << "delayScriptEditorStart mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
emit _signalDoneInitializingSession(); // needs to be emitted here, as if 'm_needsToBeSuccessfullyPlaced' is
// TRUE, it was not emitted before
}
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
bool LtsSession::isChildOfSession(QWidget* child)
{
if (!child)
{
return false;
}
return baseLayout()->isAncestorOf(child);
}
#else
bool LtsSession::isChildOfSession(QWidget* /*child*/)
{
return false;
}
#endif // BUILD_RTI
void LtsSession::doneInitializingSession()
{
LtsGlobalWaitDialog::getInstance()->done();
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
if (m_markedForDeletion)
{
emit signalInitializationAborted(); // to call done() on global wait dialog
emit signalClose(); // session manager removes us from his list and then deletes us
return;
}
#ifdef BUILD_RTI
if (!m_sessionManager->isHeadless()) // disallow base layout creation if app is headless
{
int sessionCount = m_sessionManager->sessionCount();
if (!m_hidden &&
(m_hasBaseLayout || sessionCount < 1)) // show base layout if m_hasBaseLayout is true OR IF there is only
// this session (e.g. Payloads have not started any sessions)
makeVisible();
// if (!m_hasBaseLayout) // delete session if it's useless & empty
// {
// emit signalClose();
// return;
// }
}
#endif
#ifdef BUILD_RTI
// qWarning() << "emit signalDoneInitializingSession();";
if (!createTopicClient<Core::Interface::Ftc>(m_coreFtc))
WARNING_LOG(m_logger) << "could not create core ftc - no tlh";
m_coreFtc->enableAll();
if (!getForeignGuiInterface(m_ohvIfc))
WARNING_LOG(m_logger) << "no ovh ifc, no Help-Button !";
INFO_LOG(m_logger) << "emit signalDoneInitializingSession, session=" << this;
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
// qWarning() << !m_needsToBeSuccessfullyPlaced << m_sessionManager->isHeadless() << !m_hasBaseLayout;
if (!m_needsToBeSuccessfullyPlaced || m_sessionManager->isHeadless() ||
!m_hasBaseLayout) // can't be placed if without something to show .. :)
{
// qWarning() << "mep" <<
// QStringLiteral("%1:%2").arg(QString::fromUtf8(__FILE__).split(QStringLiteral("/")).last()).arg(__LINE__);
// qWarning() << "!! headless !";
emit _signalDoneInitializingSession();
}
// qWarning() << "not headless !";
#else
// Non-RTI build: always emit signal after initialization
emit _signalDoneInitializingSession();
#endif // BUILD_RTI
}
void LtsSession::slotShowOnlineHelp(const QString& fileName)
{
#ifdef BUILD_RTI
if (m_ohvIfc == nullptr)
{
LtsWidgets::LtsMessageDialog::showMessage(baseLayout() /* can be 0ptr */, tr("Online Help not available."));
return;
}
m_ohvIfc->showHelp(fileName);
#else
Q_UNUSED(fileName)
// no-op in non-RTI build
#endif
}
#ifdef BUILD_RTI
void LtsSession::slotShowOperatorSettings()
{
const QMap<LtsDragIcon*, PluginData>& mapButtons = m_baseLayout->mapButtons();
for (auto i = mapButtons.constBegin(); i != mapButtons.constEnd(); ++i)
{
const PluginData& pd = *i;
if (pd.identifier == QStringLiteral("_OpmShowOperatorSettings"))
{
LtsDialog* showOperatorSettingsDlg = pd.createWidgetFunc(nullptr);
if (showOperatorSettingsDlg != nullptr)
{
addWidget(showOperatorSettingsDlg, pd.menuGroup, pd.identifier, pd.layoutArea, pd.closable);
// qWarning() << "showing operator settings";
}
else
WARNING_LOG(m_logger) << "could not create operator settings dialog from action";
return;
}
}
WARNING_LOG(m_logger) << "action for showing operator settings not found !!";
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::slotStartPluginInit()
{
m_initializeThesePlugins = m_guiPluginInterfaces; // copy
slotPluginInitDone();
}
void LtsSession::slotPluginInitDone() // NEVER call this directly, queue a signal to this slot !
{
// qWarning() << "LtsSession::slotPluginInitDone: sender" << sender();
if (m_pluginInitDone)
return;
if (m_slotPluginInitDoneMutex)
{
// qWarning() << "<< never call slotPluginInitDone directly or after all initialization was done! bad sender
// was" << sender(); abort();
return;
}
m_slotPluginInitDoneMutex = true; // lock
GuiPluginBase::Interface* theSender = dynamic_cast<GuiPluginBase::Interface*>(sender());
if (theSender != m_currentInitIfc)
{
WARNING_LOG(m_logger)
<< this
<< " called slotPluginInitDone from plugin which was not currently active for initialization - ignoring";
#ifdef LTS_DEBUG
WARNING_LOG(m_logger) << "current init ifc: " << m_currentInitIfc << ", sender: " << sender();
#endif
m_slotPluginInitDoneMutex = false; // unlock
return;
}
// qWarning() << "currently initializing ifc"<<m_currentInitIfc<<"has finished!";
m_currentInitIfc = nullptr;
auto i = m_initializeThesePlugins.begin();
if (i == m_initializeThesePlugins.end()) // list empty, everything initialized, now execute payloads
{
m_pluginInitDone = true;
// qWarning() << this << "done!! executing payloads!";
executePayloads();
// do not unlock mutex here as we are done with initialization and another call to this would not be good
return;
}
std::shared_ptr<GuiPluginBase::Interface> ifc = i.value();
if (ifc->availableInPartition(partitionType()))
{
m_currentInitIfc = ifc.get();
// qWarning() << "set m_currentInitIfc to" << m_currentInitIfc;
// qWarning() << "initializing" << i.key() << (void *)ifc.get();
ifc->init();
if (!ifc->m_hasInit) // workaround for ifcs without init method (which needs quitting by signals)
{
// qWarning() << "resetting m_currentInitIfc to nullptr";
m_currentInitIfc = nullptr;
QTimer::singleShot(0, this, &LtsSession::slotPluginInitDone);
}
}
else // do not initialize plugins that are not available in partition x
{
m_currentInitIfc = nullptr;
QTimer::singleShot(0, this, &LtsSession::slotPluginInitDone);
}
m_initializeThesePlugins.erase(i);
m_slotPluginInitDoneMutex = false; // unlock
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::slotExecuteNextPayload()
{
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(); // show wait dialog again
/* there is currently a problem when executing a secondary event loop,
* which leads to resending already sent signals, as they might not be
* marked as executed by Qt itself. So this is a workaround.. */
// if (m_ignoreSignalInLoop)
// return;
// m_ignoreSignalInLoop = true;
// execute in order
auto it1 = m_payloadPriorityMap.begin(); // largest key (see qt doc)
if (it1 != m_payloadPriorityMap.end())
{
std::shared_ptr<GuiPluginBase::Interface> ifc = (*it1);
m_payloadPriorityMap.erase(
it1); // delete first, as executePayload can be stuck here when the connection is not queued !
DEBUG_LOG(m_logger) << "Executing priorized Payload in Partition " << partitionId() << ", Type "
<< partitionType();
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done(); // don't interrupt payload uis with the wait dialog
if (m_blub)
{
m_blub->stop();
m_blub->deleteLater();
// qWarning() << "killing blub";
}
m_blub = new QTimer(this);
m_blub2 = 0;
QString name(QString::fromUtf8(typeid(ifc.get()).name()));
connect(m_blub, &QObject::destroyed, this, [name]() {
// qWarning() << "prio-payload for" << name << "DESTROYED!!!!";
});
connect(m_blub, &QTimer::timeout, this, [this, name]() {
m_blub2++;
// qWarning() << "prio-payload for" << name << "running since" << m_blub2 << "seconds";
});
m_blub->start(1000);
ifc->executePayload(m_mainBackground);
}
else // no priority payloads left, check for unpriorized payloads
{
auto it2 = m_payloadList.begin();
if (it2 != m_payloadList.end())
{
std::shared_ptr<GuiPluginBase::Interface> ifc = (*it2);
m_payloadList.erase(
it2); // delete first, as executePayload can be stuck here when the connection is not queued !
DEBUG_LOG(m_logger) << "Executing unpriorized Payload in Partition " << partitionId() << ", Type "
<< partitionType();
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done(); // don't interrupt payload uis with the wait dialog
if (m_blub)
{
m_blub->stop();
m_blub->deleteLater();
// qWarning() << "killing blub";
}
m_blub = new QTimer(this);
m_blub2 = 0;
QString name(QString::fromUtf8(typeid(ifc.get()).name()));
connect(m_blub, &QObject::destroyed, this, [name]() {
// qWarning() << "prio-payload for" << name << "DESTROYED!!!!";
});
connect(m_blub, &QTimer::timeout, this, [this, name]() {
m_blub2++;
// qWarning() << "prio-payload for" << name << "running since" << m_blub2 << "seconds";
});
m_blub->start(1000);
ifc->executePayload(m_mainBackground);
}
else // no payloads left, delete background widget(s) and say that all plugins have been loaded
{
Q_ASSERT(m_payloadsDone == false);
m_payloadsDone = true;
m_mainBackground = nullptr; // as it was parented to m_hiddenWidget
if (m_blub)
{
m_blub->stop();
m_blub->deleteLater();
// qWarning() << "killing blub - no payloads left";
m_blub = nullptr;
}
// qWarning() << "no payloads left";
doneInitializingSession();
}
}
// m_ignoreSignalInLoop = false; // executing payload is done, clear the ignore-flag
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::executePayloads()
{
// look for gui plugins (needed to get execution priority and run payloads)
if (!m_payloadPriorityMap.isEmpty() || !m_payloadList.isEmpty())
{
// DEBUG_LOG(m_logger) << m_payloadPriorityMap.count() << " priorized payload(s), " << m_payloadList.count() <<
// " unpriorized payload(s) - " << m_payloadPriorityMap.count() + m_payloadList.count() << " total.";
// QMetaObject::invokeMethod(this, &LtsSession::slotExecuteNextPayload);
LtsWidgets::LtsGlobalWaitDialog::getInstance()
->done(); // ugly workaround: as the next method says wait even if we call it the first time (LtsSession
// c_tor called wait already)
slotExecuteNextPayload();
}
else
{
// qWarning() << "this session has no payloads assigned!!";
DEBUG_LOG(m_logger) << "no payloads";
if (partitionType() == IDL::PartitionType::Global)
{
m_hasBaseLayout =
true; // admin session has no payloads, so show base layout, otherwise there is nothing to show..
}
doneInitializingSession();
}
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::clearDataPluginInterfaces()
{
QMap<QString, std::weak_ptr<DataPluginBase::Interface>> weakDataPluginInterfaces;
for (auto i = m_dataPluginInterfaces.cbegin(); i != m_dataPluginInterfaces.cend(); ++i)
{
// i.value()->clearInterfaces();
weakDataPluginInterfaces.insert(i.key(), i.value());
}
DEBUG_LOG(m_logger) << "Clearing data plugin interfaces for " << partitionType() << " - " << this;
m_dataPluginInterfaces.clear();
#ifdef LTS_DEBUG
// in global plugins somehow are not unloaded
if (partitionType() != IDL::PartitionType::Global)
{
for (auto i = weakDataPluginInterfaces.cbegin(); i != weakDataPluginInterfaces.cend(); ++i)
{
std::shared_ptr<DataPluginBase::Interface> sp = i.value().lock();
if (!sp)
continue;
WARNING_LOG(m_logger) << "still referenced Data Plugin '" << i.key() << "' in partition type "
<< partitionType() << " (use_count=" << sp.use_count() << ")"
<< " - application may crash on exit! " << this;
}
}
#endif
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
void LtsSession::clearGuiPluginInterfaces()
{
bool bInClearPluginInterfaces = true;
auto cbCheckEventLoop = [this, &bInClearPluginInterfaces]() {
if (bInClearPluginInterfaces)
{
ERROR_LOG(m_logger) << "QEventLoop was called within clearGuiPluginInterfaces which is not allowed!";
Q_ASSERT(false);
}
};
QTimer::singleShot(0, this, cbCheckEventLoop);
m_ohvIfc = nullptr;
QMap<QString, std::weak_ptr<GuiPluginBase::Interface>> weakGuiPluginInterfaces;
for (auto i = m_guiPluginInterfaces.cbegin(); i != m_guiPluginInterfaces.cend(); ++i)
{
i.value()->clearInterfaces();
weakGuiPluginInterfaces.insert(i.key(), i.value());
}
bInClearPluginInterfaces = false;
DEBUG_LOG(m_logger) << "Clearing gui plugin interfaces for " << partitionType() << " - " << this;
m_guiPluginInterfaces.clear();
#ifdef LTS_DEBUG
// in global plugins somehow are not unloaded
if (partitionType() != IDL::PartitionType::Global)
{
for (auto i = weakGuiPluginInterfaces.cbegin(); i != weakGuiPluginInterfaces.cend(); ++i)
{
std::shared_ptr<GuiPluginBase::Interface> sp = i.value().lock();
if (!sp)
continue;
WARNING_LOG(m_logger) << "still referenced Gui Plugin '" << i.key() << "'in partition type "
<< partitionType() << " (use_count=" << sp.use_count() << ")"
<< " Gui Plugin '" << i.key() << "'"
<< " - application may crash on exit! " << this;
}
}
#endif
}
#endif // BUILD_RTI
#ifdef BUILD_RTI
LtsSessionManager* LtsSession::getSessionManager()
{
return m_sessionManager;
}
#endif
} // namespace LtsSession