/** * @RDE_HEADER@ * Manages all the Sessions * $Id$ * $HeadURL$ * $Author$ * * Created by Mike Wille, SLSE, 2016-05-15 */ #include "lts_session_manager.h" #include "lts_session.h" #include #include #include #include #include #include #include #include #include namespace LtsSession { LtsSessionManager::LtsSessionManager() : QObject() , m_appId(LtsAppDescriptor::App::Login) , m_headless(false) , m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("LtsSession.Manager")) {} LtsSessionManager::~LtsSessionManager() { // qCritical() << "~LtsSessionManager"; for (auto i = m_sessionMap.begin(); i != m_sessionMap.end(); ++i) { LtsSession *session = i.value(); session->setInactive(); session->deleteLater(); } } bool LtsSessionManager::init(const DdsConnectionParams &connParams, const QVector &dataPluginList, const QVector &guiPluginList, LtsAppDescriptor::App appId, const QString &workspaceId, bool headless, bool hidden) // TODO: what to return ? { // TODO: check if maps empty? m_dataPluginList = dataPluginList; m_guiPluginList = guiPluginList; m_appId = appId; m_headless = headless; // shortcut: on first login etc. we go through ExerciseChooser to select an exercise // but when we're already in the exercise and starting an app from within, // we don't want to have the exercise chooser a second time -> directly go through app // and show the base layout // ????? Der Kommentar stimmt leider nicht. Loest leider nicht das Problem. bool bHasBaseLayout = connParams.exerciseId > 0; LtsSession *session = createSession(connParams, bHasBaseLayout, true, hidden); // start Admin Session (for login, etc.) session->setWorkspaceId(workspaceId); return session; } QVector LtsSessionManager::sessions() { return m_sessionMap.values().toVector(); // QVector result; // for (auto i = m_sessionMap.begin(); i != m_sessionMap.end(); ++i) // result.append(i.value()); // return result; } void LtsSessionManager::softQuit() { for (auto i = m_sessionMap.begin(); i != m_sessionMap.end(); ++i) { LtsSession *session = *i; session->aboutToClose(); session->setInactive(); session->deleteLater(); } m_sessionMap.clear(); emit hideAllOtherBLWs(nullptr); // for tablet mode! shows another hidden session from some other app or maybe the same app, after the visible one was hidden QMetaObject::invokeMethod(this, &LtsSessionManager::signalQuit, Qt::QueuedConnection); // wait until all Session's deleteLater is done } LtsSession *LtsSessionManager::createSession(const DdsConnectionParams &connParams, bool hasBaseLayout, bool payloads, bool hidden) { LtsSession *session = getSession(connParams.partitionType, connParams.partitionId); if (session != nullptr) { WARNING_LOG(m_logger) << "Tried to create a Session that already exists"; return nullptr; } session = new LtsSession(this); connect(session, &LtsSession::signalQuit, this, &LtsSessionManager::signalQuit); // QueuedConnection since Qt5.9.1 seems to send the buttonRelease event again when entering an // eventloop within this slot. Not yet clear why this happens connect(session, &LtsSession::signalClose, this, &LtsSessionManager::slotCloseSession, Qt::QueuedConnection); connect(session, &LtsSession::signalLogout, this, &LtsSessionManager::signalLogout); connect(session, &LtsSession::signalInitializationAborted, this, &LtsSessionManager::signalInitializationAborted); connect(session, &LtsSession::hideAllOtherBLWs, this, &LtsSessionManager::hideAllOtherBLWs); connect(session, &LtsSession::taskSwitch, this, &LtsSessionManager::taskSwitch); #ifdef LTS_DEBUG connect(session, &LtsSession::signalStillAlive, this, [this]() { LtsSession *session = qobject_cast(sender()); for (auto i = m_sessionMap.constBegin(); i != m_sessionMap.constEnd(); ++i) { if (i.value() == session) return; } WARNING_LOG(m_logger) << "Previously deleted Session " << session->partitionId() << "/" << session->partitionType() << " is still alive!"; }); #endif if (hasBaseLayout) session->setBaseLayoutVisible(); // after payloads are done (if any), the base layout will be created if (payloads) session->setPayloadsEnabled(); m_sessionMap[SessionKey(connParams.partitionType, connParams.partitionId)] = session; LtsSession *globSession = getSession(IDL::PartitionType::Global, 0); if (globSession && globSession->ddsConnector() && globSession->domainId() == connParams.domainId) { dds::domain::DomainParticipant dp = globSession->ddsConnector()->getDomainParticipant(); if (!session->init(dp, connParams, m_dataPluginList, m_guiPluginList)) // init not successful? return invalid ptr { session->deleteLater(); return nullptr; } } else { /* * init SOLLTE asynchron ablaufen. * init läuft aber synchron, da die Payloads der Plugins DIrectConnections benutzen. * AUf QueuedCOnnections umbauen ist schwerer, da init mit einem SessionCount von 0 rechnet, da init blocking ist und es daher nicht zum aufruf m_sessionMap[...] = ...; kommt...... */ if (!session->init(connParams, m_dataPluginList, m_guiPluginList, hidden)) // init not successful? return invalid ptr { session->deleteLater(); return nullptr; } } if (session->isInitializationDone()) QMetaObject::invokeMethod(this, &LtsSessionManager::signalInitializationFinished, Qt::QueuedConnection); else connect(session, &LtsSession::signalDoneInitializingSession, this, &LtsSessionManager::signalInitializationFinished, Qt::QueuedConnection); return session; } void LtsSessionManager::slotCloseSession() { LtsSession *session = qobject_cast(QObject::sender()); if (!session) { FATAL_LOG(m_logger) << "LtsSessionManager: slot called without object - so it cannot be deleted from the session list!"; return; } bool found = false; for (auto i = m_sessionMap.begin(); i != m_sessionMap.end(); ++i) { if (i.value() == session) { const auto key = i.key(); session->aboutToClose(); session->setInactive(); session->deleteLater(); m_sessionMap.remove(key); // when destruction takes a long time, a new session may have been added which invalidated the iterator found = true; break; } } if (!found) FATAL_LOG(m_logger) << "LtsSessionManager: Cannot find Session in map!"; emit hideAllOtherBLWs(nullptr); // for tablet mode! shows another hidden session from some other app or maybe the same app, after the visible one was hidden if (m_sessionMap.isEmpty()) // quit app if all sessions closed emit signalQuit(); } LtsSession *LtsSessionManager::getSession(IDL::PartitionType partitionType, int partitionId) { auto it = m_sessionMap.find(SessionKey(partitionType, partitionId)); if (it != m_sessionMap.end()) // session found? return it! return it.value(); return nullptr; // not found } } // namespace LtsSession