Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+45
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
#
|
||||
|
||||
#
|
||||
# Data Plugin
|
||||
#
|
||||
SET(avm_SRCS
|
||||
avm_data_plugin.cpp
|
||||
avm_data_plugin.h
|
||||
rt_profile_observer.cpp
|
||||
rt_profile_observer.h
|
||||
avs_session_context.cpp
|
||||
avs_session_context.h
|
||||
avm_exercise_context.cpp
|
||||
avm_exercise_context.h
|
||||
operator_settings_observer.cpp
|
||||
operator_settings_observer.h
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS AvmDataPlugin MODULE ${avm_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(AvmDataPlugin
|
||||
NGLLogger
|
||||
ngltranslator
|
||||
nglsettings
|
||||
LtsSessionDataDds
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
AvmDataPluginInterface
|
||||
svcAvmClient
|
||||
AvmShared
|
||||
svcOpmClient
|
||||
svcExmClient
|
||||
svcIsmClient
|
||||
IsmDataPluginInterface
|
||||
Qt5::Core
|
||||
LtsUtilsGuiStyleManager
|
||||
LtsUtilsGuiConnectDialog
|
||||
LtsUtilsSettings
|
||||
Boost::boost
|
||||
)
|
||||
NGL_INSTALL_TARGET(AvmDataPlugin)
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Data Plugin for AudioVideoSystem
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-08-17
|
||||
*/
|
||||
|
||||
#include "avm_data_plugin.h"
|
||||
#include <AudioVideoManagement/Shared/plugin_settings.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
#include <AudioVideoManagement/ava_state.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <AudioVideoManagement/avs_menus.h>
|
||||
#include <AudioVideoManagement/avs_dialog.h>
|
||||
#include <AudioVideoManagement/vd_session.h>
|
||||
#include <AudioVideoManagement/Shared/avs_app.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <OperatorManagement/opm.hpp>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <QtGlobal>
|
||||
#include <LtsSession/lts_session_data_dds.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <StyleManager/style_manager.h>
|
||||
#include <ngltranslator/ngltranslator.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace AudioVideoManagement;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
AvaGuiStyle determineGuiStyle()
|
||||
{
|
||||
LtsUtils::StyleManager *styleManager = LtsUtils::StyleManager::getInstance();
|
||||
|
||||
if (styleManager->currentStyleName() == QStringLiteral("rme.dark"))
|
||||
return AvaGuiStyle::Dark;
|
||||
|
||||
return AvaGuiStyle::Light;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
DataPlugin::DataPlugin()
|
||||
: m_pluginSettings(new PluginSettings)
|
||||
{}
|
||||
|
||||
DataPlugin::~DataPlugin() = default;
|
||||
|
||||
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
|
||||
{
|
||||
Q_ASSERT(session);
|
||||
|
||||
int exerciseId = session->exerciseId();
|
||||
return std::make_shared<DataInterfaceImpl>(session, AvmExerciseContextHandle(&m_exerciseContext, exerciseId, session), &m_avsSessionContext);
|
||||
}
|
||||
|
||||
|
||||
DataInterfaceImpl::DataInterfaceImpl(LtsSession::LtsSessionDataDds *session, AvmExerciseContextHandle &&exerciseContextHandle, AvsSessionContext *sessionContext)
|
||||
: m_exerciseContextHandle(std::move(exerciseContextHandle))
|
||||
, m_session(qobject_cast<LtsSession::LtsSession *>(session))
|
||||
{
|
||||
Q_ASSERT(session);
|
||||
Q_ASSERT(session->partitionType() == IDL::PartitionType::Exercise ||
|
||||
session->partitionType() == IDL::PartitionType::Replay ||
|
||||
session->partitionType() == IDL::PartitionType::Global);
|
||||
Q_ASSERT(sessionContext);
|
||||
|
||||
if (session->exerciseId() > 0 && sessionContext->canAcquire(session->exerciseId()))
|
||||
{
|
||||
LtsSessionData::LtsSessionData *sessionData = LtsSessionData::LtsSessionData::getInstance();
|
||||
m_avsSessionContextHandle = AvsSessionContextHandle(sessionContext, session->exerciseId(),
|
||||
sessionData->getOperatorId(),
|
||||
QString::fromLatin1(NGL::translationLocale()),
|
||||
determineGuiStyle(), m_exerciseContextHandle);
|
||||
}
|
||||
}
|
||||
|
||||
DataInterfaceImpl::~DataInterfaceImpl() = default;
|
||||
|
||||
AvaSession *DataInterfaceImpl::avaSession()
|
||||
{
|
||||
return m_avsSessionContextHandle.avaSession();
|
||||
}
|
||||
|
||||
AvaState *DataInterfaceImpl::avaState()
|
||||
{
|
||||
return m_avsSessionContextHandle.avaState();
|
||||
}
|
||||
|
||||
StreamNameMapping *DataInterfaceImpl::streamNameMapping()
|
||||
{
|
||||
return m_exerciseContextHandle.streamNameMapping();
|
||||
}
|
||||
|
||||
AvsMenus *DataInterfaceImpl::menus()
|
||||
{
|
||||
return m_avsSessionContextHandle.menus();
|
||||
}
|
||||
|
||||
VdSession *DataInterfaceImpl::vdSession()
|
||||
{
|
||||
return m_avsSessionContextHandle.vdSession();
|
||||
}
|
||||
|
||||
bool DataInterfaceImpl::vdSessionEstablished() const
|
||||
{
|
||||
return m_avsSessionContextHandle.vdSession()->isEstablished();
|
||||
};
|
||||
|
||||
void DataInterfaceImpl::showCamera(QWidget *irreplacableWidget, int mountingPointId)
|
||||
{
|
||||
if (!m_avsSessionContextHandle)
|
||||
return;
|
||||
|
||||
|
||||
// build list of irreplacable widgets by the dependency tree of its dependencies and their dependencies' dependencies
|
||||
QVector<QWidget *> irreplacableWidgets {m_session->baseLayoutWidget(), irreplacableWidget};
|
||||
LtsSession::LtsSession *dependency = m_session->dependency();
|
||||
int runaway = 100;
|
||||
while (dependency && runaway > 0)
|
||||
{
|
||||
irreplacableWidgets += dependency->baseLayoutWidget();
|
||||
dependency = dependency->dependency();
|
||||
runaway--;
|
||||
}
|
||||
|
||||
qWarning() << "irreplacableWidgets count" << irreplacableWidgets.count() << "from" << m_session;
|
||||
|
||||
for (QWidget *w : irreplacableWidgets)
|
||||
qWarning() << "irre" << w;
|
||||
|
||||
m_avsSessionContextHandle.liveVideoApp()->show(irreplacableWidgets);
|
||||
QString streamName = streamNameMapping()->internalName(mountingPointId);
|
||||
m_avsSessionContextHandle.avaSession()->control()->chooseStreamOverview(AvsDialog::VIDEO_1, {streamName});
|
||||
}
|
||||
|
||||
void DataInterfaceImpl::showAnnouncementUnit(int mountingPointId)
|
||||
{
|
||||
if (!m_avsSessionContextHandle)
|
||||
return;
|
||||
|
||||
m_avsSessionContextHandle.menus()->setAnnouncementUnit(mountingPointId);
|
||||
}
|
||||
|
||||
void DataInterfaceImpl::showOrCloseAvsApp()
|
||||
{
|
||||
if (!m_avsSessionContextHandle)
|
||||
return;
|
||||
|
||||
auto liveVideoApp = m_avsSessionContextHandle.liveVideoApp();
|
||||
|
||||
qWarning() << "showOrCloseAvsApp" << liveVideoApp->isVisible();
|
||||
if (liveVideoApp->isActive())
|
||||
liveVideoApp->hide(true /* and close */);
|
||||
else
|
||||
liveVideoApp->show();
|
||||
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* HMI Plugin for AudioVideoSystem
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-08-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include "avm_exercise_context.h"
|
||||
#include "avs_session_context.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace LtsSession { class LtsSession; }
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvaSession;
|
||||
class AvaState;
|
||||
class PlaybackApp;
|
||||
class PluginSettings;
|
||||
class StreamNameMapping;
|
||||
|
||||
class DataPlugin final : public QObject, public DataPluginBase::Plugin
|
||||
{
|
||||
Q_PLUGIN_METADATA(IID "data:3:avm")
|
||||
Q_INTERFACES(DataPluginBase::Plugin)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
DataPlugin();
|
||||
~DataPlugin();
|
||||
|
||||
QString pluginName() const override { return QStringLiteral("AudioVideoManagement"); }
|
||||
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
|
||||
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise || partition == IDL::PartitionType::Replay || partition == IDL::PartitionType::Global; }
|
||||
|
||||
private:
|
||||
AvmExerciseContextManager m_exerciseContext;
|
||||
AvsSessionContext m_avsSessionContext;
|
||||
std::unique_ptr<PluginSettings> m_pluginSettings; //!< the singleton instance
|
||||
};
|
||||
|
||||
|
||||
class DataInterfaceImpl final : public DataInterface
|
||||
{
|
||||
public:
|
||||
DataInterfaceImpl(LtsSession::LtsSessionDataDds *session, AvmExerciseContextHandle &&exerciseContextHandle, AvsSessionContext *sessionContext);
|
||||
~DataInterfaceImpl();
|
||||
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> getDtc() override { return m_exerciseContextHandle.dtc(); }
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Ftc> getFtc() override { return m_exerciseContextHandle.ftc(); }
|
||||
|
||||
ExerciseManagement::Interface::Dtc *getExmDtc() override { return m_exerciseContextHandle.exmDtc(); }
|
||||
OperatorManagement::Interface::Dtc *getOpmDtc() override { return m_exerciseContextHandle.opmDtc(); }
|
||||
|
||||
/**
|
||||
* @name Access to the communication session with AVS_Workstation and related parts.
|
||||
* The getter-methods may only be called when hasAvsSession() returns true.
|
||||
* They always return a valid pointer then.
|
||||
*/
|
||||
///@{
|
||||
bool hasAvsSession() const override { return m_avsSessionContextHandle; }
|
||||
bool vdSessionEstablished() const override;
|
||||
AvaSession *avaSession() override;
|
||||
AvaState *avaState() override;
|
||||
AvsMenus *menus() override;
|
||||
PlaybackApp *videoPlaybackApp() override { return m_avsSessionContextHandle.videoPlaybackApp(); }
|
||||
PlaybackApp *audioPlaybackApp() override { return m_avsSessionContextHandle.audioPlaybackApp(); }
|
||||
PlaybackApp *videoPresentationApp() override { return m_avsSessionContextHandle.videoPresentationApp(); }
|
||||
PlaybackApp *audioPresentationApp() override { return m_avsSessionContextHandle.audioPresentationApp(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @name Access to the communication session with AVS_Export.
|
||||
* The getter-methods may only be called when hasAvsSession() returns true.
|
||||
* They always return a valid pointer then.
|
||||
*/
|
||||
///@{
|
||||
VdSession *vdSession() override;
|
||||
///@}
|
||||
|
||||
/** Only available when not in global partition; must not be called otherwise. */
|
||||
StreamNameMapping *streamNameMapping() override;
|
||||
|
||||
/** No-op when hasAvsSession() == false. */
|
||||
///{@
|
||||
void showCamera(QWidget *irreplacableWidget, int mountingPointId) override;
|
||||
void showAnnouncementUnit(int mountingPointId) override;
|
||||
void showOrCloseAvsApp() override;
|
||||
///@}
|
||||
|
||||
private:
|
||||
AvmExerciseContextHandle m_exerciseContextHandle;
|
||||
AvsSessionContextHandle m_avsSessionContextHandle;
|
||||
LtsSession::LtsSession *m_session;
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvmExerciseContext
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-07-30
|
||||
*/
|
||||
|
||||
#include "avm_exercise_context.h"
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <LtsSession/lts_session_data_dds.h>
|
||||
#include <ConnectDialog/connect_dialog_nt.h>
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <utility>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/**
|
||||
* Small composite that just holds all entities bound to the Exercise context.
|
||||
*/
|
||||
struct AvmExerciseContextManager::ExerciseContext
|
||||
{
|
||||
explicit ExerciseContext(LtsSession::LtsSessionDataDds *session)
|
||||
{
|
||||
static const int TIMEOUT_MS = 1000;
|
||||
|
||||
Q_ASSERT(session);
|
||||
session->createTopicClient(dtc, ftc);
|
||||
opmDtc = OperatorManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
|
||||
exmDtc = ExerciseManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
|
||||
ismDtc = InfrastructureManagement::Interface::Dtc::create(session->ddsConnectorGlobal());
|
||||
if (session->exerciseId() > 0)
|
||||
streamNameMapping.reset(StreamNameMapping::create(dtc.get()));
|
||||
|
||||
opmDtc->enableUser();
|
||||
opmDtc->waitForHistoricalDataUser(TIMEOUT_MS); // TODO: FIXME: solange man hier keinen ConnectingDialogNT benutzen kann, kein Assert
|
||||
|
||||
exmDtc->enableExercise();
|
||||
exmDtc->waitForHistoricalDataExercise(TIMEOUT_MS);
|
||||
|
||||
ismDtc->enableMountingPointAsset();
|
||||
ismDtc->waitForHistoricalDataMountingPointAsset(TIMEOUT_MS);
|
||||
|
||||
dtc->enableCnrConfig();
|
||||
dtc->enableTvcConfig();
|
||||
dtc->enableCnrTvcProfile();
|
||||
dtc->enableMenuStruct();
|
||||
dtc->waitForHistoricalDataCnrConfig(TIMEOUT_MS);
|
||||
dtc->waitForHistoricalDataTvcConfig(TIMEOUT_MS);
|
||||
dtc->waitForHistoricalDataCnrTvcProfile(TIMEOUT_MS);
|
||||
dtc->waitForHistoricalDataMenuStruct(TIMEOUT_MS);
|
||||
}
|
||||
|
||||
std::shared_ptr<Interface::Dtc> dtc;
|
||||
std::shared_ptr<Interface::Ftc> ftc;
|
||||
std::shared_ptr<OperatorManagement::Interface::Dtc> opmDtc;
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
|
||||
std::unique_ptr<StreamNameMapping> streamNameMapping;
|
||||
};
|
||||
|
||||
|
||||
AvmExerciseContextManager::RefCountedContext::RefCountedContext(std::unique_ptr<AvmExerciseContextManager::ExerciseContext> &&context)
|
||||
: context(std::move(context))
|
||||
{}
|
||||
|
||||
AvmExerciseContextManager::RefCountedContext::RefCountedContext(AvmExerciseContextManager::RefCountedContext &&) noexcept = default;
|
||||
|
||||
AvmExerciseContextManager::RefCountedContext::~RefCountedContext() = default;
|
||||
|
||||
|
||||
AvmExerciseContextManager::~AvmExerciseContextManager()
|
||||
{
|
||||
// cfroebel 2018-07-31: Workaround for Bug REGG-4775
|
||||
// All contexts should have been destroyed by now.
|
||||
// But due to the bug there is one last context for Ex 0.
|
||||
|
||||
// Q_ASSERT(m_activeContexts.empty()); TODO: reactivate after fix
|
||||
if (m_activeContexts.empty())
|
||||
return;
|
||||
|
||||
Q_ASSERT(m_activeContexts.size() == 1);
|
||||
//Q_ASSERT(m_activeContexts.begin()->first == 0); TODO: reactivate after fix
|
||||
}
|
||||
|
||||
AvmExerciseContextManager::ExerciseContext *AvmExerciseContextManager::acquire(int exerciseId, LtsSession::LtsSessionDataDds *session)
|
||||
{
|
||||
auto found = m_activeContexts.find(exerciseId);
|
||||
if (found != m_activeContexts.end())
|
||||
{
|
||||
++found->second.refCount;
|
||||
return found->second.context.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<ExerciseContext> composite(new ExerciseContext(session));
|
||||
auto insertResult = m_activeContexts.insert(std::make_pair(exerciseId, RefCountedContext(std::move(composite))));
|
||||
Q_ASSERT(insertResult.second);
|
||||
return insertResult.first->second.context.get();
|
||||
}
|
||||
|
||||
void AvmExerciseContextManager::release(int exerciseId, AvmExerciseContextManager::ExerciseContext *composite)
|
||||
{
|
||||
auto found = m_activeContexts.find(exerciseId);
|
||||
Q_ASSERT(found != m_activeContexts.end());
|
||||
Q_ASSERT(found->second.context.get() == composite);
|
||||
|
||||
--found->second.refCount;
|
||||
if (found->second.refCount == 0)
|
||||
m_activeContexts.erase(found);
|
||||
}
|
||||
|
||||
|
||||
AvmExerciseContextHandle::AvmExerciseContextHandle() = default;
|
||||
|
||||
AvmExerciseContextHandle::AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session)
|
||||
: m_context(context->acquire(exerciseId, session), [exerciseId, context](AvmExerciseContextManager::ExerciseContext *composite) { context->release(exerciseId, composite); })
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
Q_ASSERT(m_context);
|
||||
}
|
||||
|
||||
StreamNameMapping *AvmExerciseContextHandle::streamNameMapping() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
Q_ASSERT(m_context->streamNameMapping);
|
||||
return m_context->streamNameMapping.get();
|
||||
}
|
||||
|
||||
const std::shared_ptr<Interface::Dtc> &AvmExerciseContextHandle::dtc() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
return m_context->dtc;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Interface::Ftc> &AvmExerciseContextHandle::ftc() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
return m_context->ftc;
|
||||
}
|
||||
|
||||
OperatorManagement::Interface::Dtc *AvmExerciseContextHandle::opmDtc() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
return m_context->opmDtc.get();
|
||||
}
|
||||
|
||||
ExerciseManagement::Interface::Dtc *AvmExerciseContextHandle::exmDtc() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
return m_context->exmDtc.get();
|
||||
}
|
||||
|
||||
InfrastructureManagement::Interface::Dtc *AvmExerciseContextHandle::ismDtc() const
|
||||
{
|
||||
Q_ASSERT(m_context);
|
||||
return m_context->ismDtc.get();
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvmExerciseContext
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-07-30
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSessionDataDds;
|
||||
}
|
||||
|
||||
namespace OperatorManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
class Ftc;
|
||||
}
|
||||
|
||||
class StreamNameMapping;
|
||||
|
||||
/**
|
||||
* For each Exercise -- as defined by its Id -- AvmExerciseContextManager manages
|
||||
* an associated ExerciseContext. The ExerciseContext just holds all necessary entities.
|
||||
* The idea is that any number of PluginInterface-instances with the same exerciseId
|
||||
* share the same ExerciseContext.
|
||||
* For example, all PluginInterface-instances for Exercise 42 can share the *same* Dtc or Ftc.
|
||||
* Thus Dtc and Ftc are part of the ExerciseContext.
|
||||
*
|
||||
* The lifetime of an ExerciseContext can be longer than the lifetime of a PluginInterface-instance.
|
||||
* AvsSessionContext uses (references) entities from the ExerciseContext.
|
||||
* This is ok as it is guaranteed that the lifetime of the ExerciseContext is at least as long
|
||||
* as the lifetime of AvsSessionContext.
|
||||
* Actually they have the same lifetime -- if an AvsSessionContext exists.
|
||||
*
|
||||
* The difference is that there can be at most one AvsSessionContext at the same time.
|
||||
* But there can be at most one ExerciseContext *for each* exerciseId at the same time.
|
||||
* For the global exercise (exerciseId 0) there is never an AvsSessionContext.
|
||||
*
|
||||
* The following picuture illustrates the lifetimes:
|
||||
*
|
||||
* App1 (42) --------- ---------
|
||||
* App2 (42) --------- ---------
|
||||
* App3 (35) =========
|
||||
*
|
||||
* ExerciseContext (42) --------- --------------- ---------
|
||||
* ExerciseContext (35) =========
|
||||
*
|
||||
* AvsSessionContext (42) --------- ---------------
|
||||
* AvsSessionContext (35) =========
|
||||
*
|
||||
* PluginInterface-instance 1 (42) ---------
|
||||
* PluginInterface-instance 2 (42) ---------
|
||||
* PluginInterface-instance 3 (42) ---------
|
||||
* PluginInterface-instance 4 (35) =========
|
||||
* PluginInterface-instance 5 (42) ---------
|
||||
*
|
||||
* @see AvsSessionContext
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvmExerciseContextManager
|
||||
{
|
||||
public:
|
||||
struct ExerciseContext;
|
||||
|
||||
~AvmExerciseContextManager();
|
||||
|
||||
/**
|
||||
* Don't use directly; use AvmExerciseContextHandle instead.
|
||||
*/
|
||||
///@{
|
||||
ExerciseContext *acquire(int exerciseId, LtsSession::LtsSessionDataDds *session);
|
||||
void release(int exerciseId, ExerciseContext *composite);
|
||||
///@}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Small internal helper class in order to keep track of the refCount.
|
||||
* Here, the refCount denotes the number of PluginInterface-Instances for the same Exercise.
|
||||
*/
|
||||
struct RefCountedContext
|
||||
{
|
||||
explicit RefCountedContext(std::unique_ptr<ExerciseContext> &&context);
|
||||
RefCountedContext(RefCountedContext &&) noexcept;
|
||||
~RefCountedContext();
|
||||
|
||||
int refCount{1};
|
||||
std::unique_ptr<ExerciseContext> context;
|
||||
};
|
||||
|
||||
using ExerciseId = int;
|
||||
std::map<ExerciseId, RefCountedContext> m_activeContexts;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to automatically call AvmExerciseContextManager::acquire()
|
||||
* and AvmExerciseContextManager::release() in the ctor and dtor respectively.
|
||||
* Instances can be moved but not copied.
|
||||
*
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvmExerciseContextHandle
|
||||
{
|
||||
public:
|
||||
AvmExerciseContextHandle();
|
||||
AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session);
|
||||
|
||||
operator bool() const { return m_context.get(); }
|
||||
|
||||
/** Only available when not in global Exercise */
|
||||
StreamNameMapping *streamNameMapping() const;
|
||||
|
||||
const std::shared_ptr<Interface::Dtc> &dtc() const;
|
||||
const std::shared_ptr<Interface::Ftc> &ftc() const;
|
||||
|
||||
OperatorManagement::Interface::Dtc *opmDtc() const;
|
||||
ExerciseManagement::Interface::Dtc *exmDtc() const;
|
||||
InfrastructureManagement::Interface::Dtc *ismDtc() const;
|
||||
|
||||
|
||||
private:
|
||||
using Releaser = std::function<void (AvmExerciseContextManager::ExerciseContext *)>;
|
||||
std::unique_ptr<AvmExerciseContextManager::ExerciseContext, Releaser> m_context;
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvsSessionContext
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-08-03
|
||||
*/
|
||||
|
||||
#include "avs_session_context.h"
|
||||
#include "avm_exercise_context.h"
|
||||
#include "operator_settings_observer.h"
|
||||
#include "rt_profile_observer.h"
|
||||
#include <AudioVideoManagement/avs_menus.h>
|
||||
#include <AudioVideoManagement/ava_comm.h>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
#include <AudioVideoManagement/ava_state.h>
|
||||
#include <AudioVideoManagement/vd_comm.h>
|
||||
#include <AudioVideoManagement/vd_control.h>
|
||||
#include <AudioVideoManagement/vd_session.h>
|
||||
#include <AudioVideoManagement/avs_dialog.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping_to_ava.h>
|
||||
#include <AudioVideoManagement/Shared/avs_app.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <AudioVideoManagement/Shared/plugin_settings.h>
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include <OperatorManagement/opm.hpp>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <InfrastructureManagement/ism.hpp>
|
||||
|
||||
#include <nglsettings/nglsettings_connections.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/// AvsSessionContext
|
||||
struct AvsSessionContext::Composite
|
||||
{
|
||||
Composite(int exerciseId_, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
|
||||
: exerciseId(exerciseId_)
|
||||
, operator_(exerciseContextHandle.opmDtc()->user(operatorId))
|
||||
, audioPrioObserver(exerciseId_, operatorId, exerciseContextHandle.opmDtc(), exerciseContextHandle.exmDtc())
|
||||
, avaComm(NGL::Connections::hostName(NGL::Connections::eConnection::AVS_WORKSTATION), NGL::Connections::port(NGL::Connections::eConnection::AVS_WORKSTATION))
|
||||
, avaControl(&avaComm, exerciseContextHandle.streamNameMapping(), PluginSettings::instance()->avaTimeout())
|
||||
, avaSession(&avaControl, exerciseId, QString::fromStdString(operator_.name()), langCode, operator_.audioChannelPriority(), audioPrioObserver.timezone(), guiStyle, PluginSettings::instance()->avaKeepAliveEnabled())
|
||||
, avaState(&avaSession)
|
||||
, streamNameMappingToAva(&avaSession, exerciseContextHandle.streamNameMapping())
|
||||
, avsMenus(&avaSession, exerciseContextHandle.dtc().get(), exerciseContextHandle.ismDtc(), avaState.rtState())
|
||||
, rtProfileObserver(exerciseContextHandle.dtc().get(), &avaSession, avaState.rtState(), exerciseId_, operatorId)
|
||||
, vdComm(NGL::Connections::hostName(NGL::Connections::eConnection::AVS_WORKSTATION_VD), NGL::Connections::port(NGL::Connections::eConnection::AVS_WORKSTATION_VD))
|
||||
, vdControl(&vdComm, PluginSettings::instance()->vdTimeout())
|
||||
, vdSession(&vdControl, exerciseId, PluginSettings::instance()->vdKeepAliveEnabled())
|
||||
, liveVideoApp(AvsDialog::VIDEO_1, &avaControl)
|
||||
, videoPlaybackApp(AvsDialog::VIDEO_PLAYBACK, &avaControl, PlaybackApp::AppType::Normal)
|
||||
, audioPlaybackApp(AvsDialog::AUDIO_PLAYBACK, &avaControl, PlaybackApp::AppType::AlwaysHidden)
|
||||
, videoPresentationApp(AvsDialog::VIDEO_PRESENTATION, &avaControl, PlaybackApp::AppType::AutoHide)
|
||||
, audioPresentationApp(AvsDialog::AUDIO_PRESENTATION, &avaControl, PlaybackApp::AppType::AlwaysHidden)
|
||||
{
|
||||
QObject::connect(&audioPrioObserver, &OperatorSettingsObserver::audioPrioChanged, &avaSession, &AvaSession::onAudioPrioChanged);
|
||||
QObject::connect(&audioPrioObserver, &OperatorSettingsObserver::timezoneChanged, &avaSession, &AvaSession::onTimezoneChanged);
|
||||
|
||||
avaComm.start();
|
||||
vdComm.start();
|
||||
}
|
||||
|
||||
int exerciseId;
|
||||
OperatorManagement::User operator_;
|
||||
OperatorSettingsObserver audioPrioObserver;
|
||||
AvaComm avaComm;
|
||||
AvaControl avaControl;
|
||||
AvaSession avaSession;
|
||||
AvaState avaState;
|
||||
StreamNameMappingToAva streamNameMappingToAva;
|
||||
AvsMenus avsMenus;
|
||||
RtProfileObserver rtProfileObserver;
|
||||
VdComm vdComm;
|
||||
VdControl vdControl;
|
||||
VdSession vdSession;
|
||||
AvsApp liveVideoApp;
|
||||
PlaybackApp videoPlaybackApp;
|
||||
PlaybackApp audioPlaybackApp;
|
||||
PlaybackApp videoPresentationApp;
|
||||
PlaybackApp audioPresentationApp;
|
||||
};
|
||||
|
||||
|
||||
AvsSessionContext::AvsSessionContext() = default;
|
||||
|
||||
AvsSessionContext::~AvsSessionContext()
|
||||
{
|
||||
//Q_ASSERT(m_refCount == 0);
|
||||
}
|
||||
|
||||
bool AvsSessionContext::canAcquire(int exerciseId) const
|
||||
{
|
||||
Q_ASSERT(exerciseId > 0);
|
||||
if (!m_composite)
|
||||
return true;
|
||||
return exerciseId == m_composite->exerciseId;
|
||||
}
|
||||
|
||||
AvsSessionContext::Composite *AvsSessionContext::acquire(int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
|
||||
{
|
||||
Q_ASSERT(exerciseId > 0);
|
||||
|
||||
if (m_refCount == 0)
|
||||
m_composite.reset(new Composite(exerciseId, operatorId, langCode, guiStyle, exerciseContextHandle));
|
||||
else
|
||||
Q_ASSERT(exerciseId == m_composite->exerciseId);
|
||||
|
||||
++m_refCount;
|
||||
return m_composite.get();
|
||||
}
|
||||
|
||||
void AvsSessionContext::release(Composite *composite)
|
||||
{
|
||||
Q_ASSERT(composite);
|
||||
Q_ASSERT(composite == m_composite.get());
|
||||
--m_refCount;
|
||||
if (m_refCount == 0)
|
||||
m_composite.reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// AvsSessionContextHandle
|
||||
AvsSessionContextHandle::AvsSessionContextHandle(/*LtsSession::LtsSession *session, */AvsSessionContext *context, int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle guiStyle, const AvmExerciseContextHandle &exerciseContextHandle)
|
||||
: m_composite(context->acquire(exerciseId, operatorId, langCode, guiStyle, exerciseContextHandle), [context](AvsSessionContext::Composite *composite) { context->release(composite); })
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
Q_ASSERT(m_composite);
|
||||
}
|
||||
|
||||
AvaSession *AvsSessionContextHandle::avaSession() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->avaSession;
|
||||
}
|
||||
|
||||
AvaState *AvsSessionContextHandle::avaState() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->avaState;
|
||||
}
|
||||
|
||||
AvsMenus *AvsSessionContextHandle::menus() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->avsMenus;
|
||||
}
|
||||
|
||||
VdSession *AvsSessionContextHandle::vdSession() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->vdSession;
|
||||
}
|
||||
|
||||
AvsApp *AvsSessionContextHandle::liveVideoApp() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->liveVideoApp;
|
||||
}
|
||||
|
||||
PlaybackApp *AvsSessionContextHandle::videoPlaybackApp() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->videoPlaybackApp;
|
||||
}
|
||||
|
||||
PlaybackApp *AvsSessionContextHandle::audioPlaybackApp() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->audioPlaybackApp;
|
||||
}
|
||||
|
||||
PlaybackApp *AvsSessionContextHandle::videoPresentationApp() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->videoPresentationApp;
|
||||
}
|
||||
|
||||
PlaybackApp *AvsSessionContextHandle::audioPresentationApp() const
|
||||
{
|
||||
Q_ASSERT(m_composite);
|
||||
return &m_composite->audioPresentationApp;
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* AvsSessionContext
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-08-03
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace OperatorManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class AvaSession;
|
||||
class AvaState;
|
||||
class StreamNameMapping;
|
||||
class AvsMenus;
|
||||
class VdSession;
|
||||
class AvmExerciseContextHandle;
|
||||
class AvsApp;
|
||||
class PlaybackApp;
|
||||
|
||||
/**
|
||||
* AvsSessionContext ensures that there can only be one communication
|
||||
* channel to AVS_Workstation and AVS_Export with a defined exercise context at
|
||||
* any given time.
|
||||
* AvsSessionContext must not be used with the global exercise (exerciseId 0).
|
||||
*
|
||||
* The application can have many users of the communication channels at the same time.
|
||||
* The reason for this is that the AvmDataPlugin will be instantiated for every
|
||||
* exercise (also live and replay) and possibly multiple times for an exercise.
|
||||
* All these users shall share the same communication channels.
|
||||
* But all parallel users must use the same exercise context.
|
||||
*
|
||||
* AvsSessionContext creates the communication channels (AvaSession, VdSession) when the first user
|
||||
* calls acquire(). Subsequent users can get access to the same channels by also
|
||||
* calling acquire() -- but the exercise context must match.
|
||||
* When a user no longer needs these communication channels it calls release().
|
||||
* When all users released the communication channels, they will be deleted.
|
||||
* After that another user can call acquire() with a different exercise context.
|
||||
*
|
||||
* Use AvsSessionContextHandle to automatically acquire() and release()
|
||||
* the communication channel.
|
||||
*
|
||||
* See AvmExerciseContext for a visualization of lifetimes of Apps, PluginInterface-instances
|
||||
* and ExerciseContext.
|
||||
*
|
||||
* @see AvmExerciseContext
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class AvsSessionContext
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Small helper struct that holds all parts that make up a session.
|
||||
* Only useful for AvsSessionContextHandle in order to access those parts.
|
||||
*/
|
||||
struct Composite;
|
||||
|
||||
AvsSessionContext();
|
||||
~AvsSessionContext();
|
||||
|
||||
/**
|
||||
* Check whether a AvsSessionContext with the given exerciseId can be acquired.
|
||||
* Yields true when no AvsSessionContext was created yet or when the currently active
|
||||
* AvsSessionContext is for the same exericse.
|
||||
*/
|
||||
bool canAcquire(int exerciseId) const;
|
||||
|
||||
/**
|
||||
* Need not to be called directly; use AvsSessionContextHandle instead.
|
||||
*/
|
||||
///@{
|
||||
Composite *acquire(int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle, const AvmExerciseContextHandle &exerciseContextHandle);
|
||||
void release(Composite *composite);
|
||||
///@}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Composite> m_composite;
|
||||
int m_refCount{0};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to automatically call AvsSessionContext::acquire()
|
||||
* and AvsSessionContext::release() in the ctor and dtor respectively.
|
||||
* Instances can be moved but not copied.
|
||||
*/
|
||||
class AvsSessionContextHandle
|
||||
{
|
||||
public:
|
||||
AvsSessionContextHandle() = default;
|
||||
AvsSessionContextHandle(AvsSessionContext *context, int exerciseId, int operatorId, const QString &langCode, AvaGuiStyle, const AvmExerciseContextHandle &exerciseContextHandle);
|
||||
|
||||
operator bool() const { return m_composite.get(); }
|
||||
|
||||
AvaSession *avaSession() const;
|
||||
AvaState *avaState() const;
|
||||
AvsMenus *menus() const;
|
||||
|
||||
VdSession *vdSession() const;
|
||||
|
||||
AvsApp *liveVideoApp() const;
|
||||
PlaybackApp *videoPlaybackApp() const;
|
||||
PlaybackApp *audioPlaybackApp() const;
|
||||
PlaybackApp *videoPresentationApp() const;
|
||||
PlaybackApp *audioPresentationApp() const;
|
||||
|
||||
private:
|
||||
using Releaser = std::function<void (AvsSessionContext::Composite *)>;
|
||||
std::unique_ptr<AvsSessionContext::Composite, Releaser> m_composite;
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* OperatorSettingsObserver
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-04-10
|
||||
*/
|
||||
|
||||
#include "operator_settings_observer.h"
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <ExerciseManagement/exm.hpp>
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include <OperatorManagement/opm.hpp>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/**
|
||||
* Small helper class that calculates the timezone for the current operator
|
||||
* based on the operator's settings and the default timezone for the exercise.
|
||||
*/
|
||||
class OperatorSettingsObserver::TimezoneCalculator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void setDefaultTimezone(QChar timezone)
|
||||
{
|
||||
Q_ASSERT(!timezone.isNull());
|
||||
if (timezone == m_defaultTimezone)
|
||||
return;
|
||||
m_defaultTimezone = timezone;
|
||||
calculateTimezone();
|
||||
}
|
||||
|
||||
void setOperatorTimezone(QChar timezone)
|
||||
{
|
||||
Q_ASSERT(!timezone.isNull());
|
||||
if (timezone == m_operatorTimezone)
|
||||
return;
|
||||
m_operatorTimezone = timezone;
|
||||
calculateTimezone();
|
||||
}
|
||||
|
||||
void unsetOperatorTimezone()
|
||||
{
|
||||
if (!m_operatorTimezone)
|
||||
return;
|
||||
m_operatorTimezone.reset();
|
||||
calculateTimezone();
|
||||
}
|
||||
|
||||
QChar timezone() const { return m_calculatedTimezone; }
|
||||
|
||||
signals:
|
||||
void timezoneChanged(QChar newTimezone);
|
||||
|
||||
private:
|
||||
void calculateTimezone()
|
||||
{
|
||||
QChar calculated = m_operatorTimezone.get_value_or(m_defaultTimezone);
|
||||
if (calculated == m_calculatedTimezone)
|
||||
return;
|
||||
m_calculatedTimezone = calculated;
|
||||
emit timezoneChanged(calculated);
|
||||
}
|
||||
|
||||
QChar m_defaultTimezone = QLatin1Char('Z');
|
||||
boost::optional<QChar> m_operatorTimezone;
|
||||
QChar m_calculatedTimezone = m_defaultTimezone;
|
||||
};
|
||||
|
||||
|
||||
OperatorSettingsObserver::OperatorSettingsObserver(int exerciseId, int operatorId, OperatorManagement::Interface::Dtc *opmDtc, ExerciseManagement::Interface::Dtc *exmDtc)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_operatorId(operatorId)
|
||||
, m_opmDtc(opmDtc)
|
||||
, m_exmDtc(exmDtc)
|
||||
, m_operatorSettings(LtsUtils::OperatorSettings::getInstance())
|
||||
, m_timezoneCalculator(new TimezoneCalculator)
|
||||
{
|
||||
Q_ASSERT(operatorId > 0);
|
||||
Q_ASSERT(opmDtc);
|
||||
Q_ASSERT(exmDtc);
|
||||
|
||||
OperatorManagement::User operator_ = m_opmDtc->user(operatorId);
|
||||
if (operator_.id() == operatorId)
|
||||
m_currentPrio = operator_.audioChannelPriority();
|
||||
|
||||
ExerciseManagement::Exercise exercise = m_exmDtc->exercise(exerciseId);
|
||||
if (exercise.id() == exerciseId)
|
||||
m_timezoneCalculator->setDefaultTimezone(QChar::fromLatin1(exercise.defaultTimeZone()));
|
||||
|
||||
connect(opmDtc, &OperatorManagement::Interface::Dtc::userChanged, this, &OperatorSettingsObserver::onOperatorChanged);
|
||||
connect(exmDtc, &ExerciseManagement::Interface::Dtc::exerciseChanged, this, &OperatorSettingsObserver::onExerciseChanged);
|
||||
connect(m_operatorSettings, &LtsUtils::OperatorSettings::valueChanged, this, &OperatorSettingsObserver::onSettingsValueChanged);
|
||||
connect(m_timezoneCalculator.get(), &TimezoneCalculator::timezoneChanged, this, &OperatorSettingsObserver::timezoneChanged); // signal -> signal
|
||||
}
|
||||
|
||||
QChar OperatorSettingsObserver::timezone() const
|
||||
{
|
||||
return m_timezoneCalculator->timezone();
|
||||
}
|
||||
|
||||
OperatorSettingsObserver::~OperatorSettingsObserver() = default;
|
||||
|
||||
void OperatorSettingsObserver::onOperatorChanged(const OperatorManagement::User &operator_, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
return;
|
||||
|
||||
case DataModification::eModified:
|
||||
{
|
||||
if (operator_.id() != m_operatorId)
|
||||
return;
|
||||
|
||||
AvaAudioPrio prio = operator_.audioChannelPriority();
|
||||
if (prio == m_currentPrio)
|
||||
return;
|
||||
|
||||
m_currentPrio = prio;
|
||||
emit audioPrioChanged(prio);
|
||||
return;
|
||||
}
|
||||
|
||||
case DataModification::eRemoved:
|
||||
return;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void OperatorSettingsObserver::onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType)
|
||||
{
|
||||
if (exercise.id() != m_exerciseId)
|
||||
return;
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eModified:
|
||||
m_timezoneCalculator->setDefaultTimezone(QChar::fromLatin1(exercise.defaultTimeZone()));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OperatorSettingsObserver::onSettingsValueChanged(const QString &group, const QString &identifier, const QVariant &value)
|
||||
{
|
||||
static const QString timeSettingsGroup = QStringLiteral("TimeSettings");
|
||||
static const QString timezoneId = QStringLiteral("TimeZone");
|
||||
|
||||
if (group != timeSettingsGroup)
|
||||
return;
|
||||
if (identifier != timezoneId)
|
||||
return;
|
||||
|
||||
QChar timezone = value.toChar();
|
||||
if (timezone.isNull())
|
||||
m_timezoneCalculator->unsetOperatorTimezone();
|
||||
else
|
||||
m_timezoneCalculator->setOperatorTimezone(timezone);
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
|
||||
#include "operator_settings_observer.moc"
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* OperatorSettingsObserver
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, NLSE, 2018-04-10
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <QChar>
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
|
||||
namespace OperatorManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class User;
|
||||
|
||||
} // namespace OperatorManagement
|
||||
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class Exercise;
|
||||
|
||||
} // namespace ExerciseManagement
|
||||
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class OperatorSettings;
|
||||
}
|
||||
|
||||
|
||||
enum class DataModification;
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
/**
|
||||
* Small helper class to observe the following parts of the Operator's settings:
|
||||
* - audio priority
|
||||
* - timezone
|
||||
*
|
||||
* @author Christian Fröbel
|
||||
*/
|
||||
class OperatorSettingsObserver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OperatorSettingsObserver(int exerciseId, int operatorId, OperatorManagement::Interface::Dtc *opmDtc, ExerciseManagement::Interface::Dtc *exmDtc);
|
||||
~OperatorSettingsObserver();
|
||||
|
||||
QChar timezone() const;
|
||||
|
||||
signals:
|
||||
void audioPrioChanged(AvaAudioPrio newPrio);
|
||||
void timezoneChanged(QChar newTimezone);
|
||||
|
||||
private slots:
|
||||
void onOperatorChanged(const OperatorManagement::User &operator_, DataModification modType);
|
||||
void onExerciseChanged(const ExerciseManagement::Exercise &exercise, DataModification modType);
|
||||
void onSettingsValueChanged(const QString &group, const QString &identifier, const QVariant &value);
|
||||
|
||||
private:
|
||||
class TimezoneCalculator;
|
||||
|
||||
int m_exerciseId;
|
||||
int m_operatorId;
|
||||
OperatorManagement::Interface::Dtc *m_opmDtc;
|
||||
ExerciseManagement::Interface::Dtc *m_exmDtc;
|
||||
LtsUtils::OperatorSettings *m_operatorSettings;
|
||||
std::unique_ptr<TimezoneCalculator> m_timezoneCalculator;
|
||||
boost::optional<AvaAudioPrio> m_currentPrio;
|
||||
};
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* RtProfileObserver
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-08-17
|
||||
*/
|
||||
|
||||
#include "rt_profile_observer.h"
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <QMap>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
RtProfileObserver::RtProfileObserver(Interface::Dtc *dtc, AvaSession *avaSession, RtState *rtState, int exerciseId, int operatorId)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_operatorId(operatorId)
|
||||
, m_dtc(dtc)
|
||||
, m_avaSession(avaSession)
|
||||
, m_avaControl(avaSession->control())
|
||||
, m_rtState(rtState)
|
||||
{
|
||||
Q_ASSERT(dtc);
|
||||
Q_ASSERT(avaSession);
|
||||
Q_ASSERT(rtState);
|
||||
|
||||
connect(m_avaSession, &AvaSession::sessionEstablished, this, &RtProfileObserver::onSessionEstablished);
|
||||
connect(m_dtc, &Interface::Dtc::tvcConfigChanged, this, &RtProfileObserver::onTvcConfigChanged);
|
||||
connect(m_dtc, &Interface::Dtc::cnrConfigChanged, this, &RtProfileObserver::onCnrConfigChanged);
|
||||
connect(m_dtc, &Interface::Dtc::cnrTvcProfileChanged, this, &RtProfileObserver::onCnrTvcProfileChanged);
|
||||
|
||||
m_profile = getProfile();
|
||||
|
||||
if (m_avaSession->isEstablished())
|
||||
onSessionEstablished();
|
||||
}
|
||||
|
||||
void RtProfileObserver::onSessionEstablished()
|
||||
{
|
||||
loadVoiceRadioCommunicationMenu();
|
||||
}
|
||||
|
||||
void RtProfileObserver::loadVoiceRadioCommunicationMenu()
|
||||
{
|
||||
m_avaControl->setRtProfile(m_rtState, defaultRtChannels());
|
||||
}
|
||||
|
||||
void RtProfileObserver::onCnrConfigChanged(const CnrConfig &cnrConfig, DataModification modType)
|
||||
{
|
||||
if (modType != DataModification::eModified)
|
||||
return;
|
||||
if (!isInProfile(cnrConfig))
|
||||
return;
|
||||
m_avaControl->changeRtProfileCircuitName(m_rtState, {RadioSystem::Cnr, cnrConfig.id(), cnrConfig.radioCircuit()});
|
||||
}
|
||||
|
||||
void RtProfileObserver::onTvcConfigChanged(const TvcConfig &tvcConfig, DataModification modType)
|
||||
{
|
||||
if (modType != DataModification::eModified)
|
||||
return;
|
||||
if (!isInProfile(tvcConfig))
|
||||
return;
|
||||
m_avaControl->changeRtProfileCircuitName(m_rtState, {RadioSystem::Tvc, tvcConfig.id(), tvcConfig.radioCircuit()});
|
||||
}
|
||||
|
||||
void RtProfileObserver::onCnrTvcProfileChanged(const CnrTvcProfile &profile, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
|
||||
if (profile.exerciseId() != m_exerciseId || profile.operatorId() != m_operatorId)
|
||||
return;
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
case DataModification::eModified:
|
||||
m_profile = profile;
|
||||
break;
|
||||
case DataModification::eRemoved:
|
||||
m_profile.reset();
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
loadVoiceRadioCommunicationMenu();
|
||||
}
|
||||
|
||||
QVector<RtState::RadioCircuit> RtProfileObserver::defaultRtChannels() const
|
||||
{
|
||||
if (!m_profile)
|
||||
return {};
|
||||
|
||||
const QMap<int, CnrConfig> cnrcs = m_dtc->cnrConfigs();
|
||||
const QMap<int, TvcConfig> tvccs = m_dtc->tvcConfigs();
|
||||
|
||||
QVector<RtState::RadioCircuit> rtChannels;
|
||||
rtChannels.reserve(m_profile->data().size());
|
||||
for (const auto &cnrTvcProfileData : m_profile->data())
|
||||
{
|
||||
std::string circuitName;
|
||||
if (cnrTvcProfileData.radioSystemId() == RadioSystem::Cnr)
|
||||
circuitName = cnrcs.value(cnrTvcProfileData.radioCircuitId()).radioCircuit();
|
||||
else
|
||||
circuitName = tvccs.value(cnrTvcProfileData.radioCircuitId()).radioCircuit();
|
||||
|
||||
rtChannels.push_back({cnrTvcProfileData.radioSystemId(), cnrTvcProfileData.radioCircuitId(), circuitName});
|
||||
}
|
||||
|
||||
return rtChannels;
|
||||
}
|
||||
|
||||
boost::optional<CnrTvcProfile> RtProfileObserver::getProfile() const
|
||||
{
|
||||
boost::optional<CnrTvcProfile> foundProfile;
|
||||
std::function<bool(const CnrTvcProfile &profile)> forUserInExercise = [this, &foundProfile] (const CnrTvcProfile &profile)
|
||||
{
|
||||
if (profile.exerciseId() != m_exerciseId || profile.operatorId() != m_operatorId)
|
||||
return false;
|
||||
foundProfile = profile;
|
||||
return true;
|
||||
};
|
||||
|
||||
m_dtc->cnrTvcProfiles(forUserInExercise);
|
||||
return foundProfile;
|
||||
}
|
||||
|
||||
bool RtProfileObserver::isInProfile(const CnrConfig &cnrConfig) const
|
||||
{
|
||||
return isInProfile(RadioSystem::Cnr, cnrConfig.id());
|
||||
}
|
||||
|
||||
bool RtProfileObserver::isInProfile(const TvcConfig &tvcConfig) const
|
||||
{
|
||||
return isInProfile(RadioSystem::Tvc, tvcConfig.id());
|
||||
}
|
||||
|
||||
bool RtProfileObserver::isInProfile(RadioSystem radioSystem, int32_t id) const
|
||||
{
|
||||
if (!m_profile)
|
||||
return false;
|
||||
|
||||
for (const auto &cnrTvcProfileData : m_profile->data())
|
||||
if (cnrTvcProfileData.radioSystemId() == radioSystem && cnrTvcProfileData.radioCircuitId() == id)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} //namespace AudioVideoManagement
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* RtProfileObserver
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-08-17
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/rt_state.h>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
enum class DataModification;
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class AvaSession;
|
||||
class AvaControl;
|
||||
class TvcConfig;
|
||||
class CnrConfig;
|
||||
class CnrTvcProfile;
|
||||
|
||||
class RtProfileObserver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RtProfileObserver(Interface::Dtc *dtc, AvaSession *avaSession, RtState *rtState, int exerciseId, int operatorId);
|
||||
|
||||
private slots:
|
||||
void onSessionEstablished();
|
||||
void onTvcConfigChanged(const TvcConfig &tvcConfig, DataModification modType);
|
||||
void onCnrConfigChanged(const CnrConfig &cnrConfig, DataModification modType);
|
||||
void onCnrTvcProfileChanged(const CnrTvcProfile &profile, DataModification modType);
|
||||
|
||||
private:
|
||||
void loadVoiceRadioCommunicationMenu();
|
||||
QVector<RtState::RadioCircuit> defaultRtChannels() const;
|
||||
boost::optional<CnrTvcProfile> getProfile() const;
|
||||
bool isInProfile(const CnrConfig &cnrConfig) const;
|
||||
bool isInProfile(const TvcConfig &tvcConfig) const;
|
||||
bool isInProfile(RadioSystem radioSystem, int32_t id) const;
|
||||
|
||||
const int m_exerciseId;
|
||||
const int m_operatorId;
|
||||
boost::optional<CnrTvcProfile> m_profile;
|
||||
Interface::Dtc *m_dtc;
|
||||
AvaSession *m_avaSession;
|
||||
AvaControl *m_avaControl;
|
||||
RtState *m_rtState;
|
||||
};
|
||||
|
||||
} //namespace AudioVideoManagement
|
||||
Reference in new issue
Block a user