Adds initial intermediate qt6 porting state
This commit is contained in:
11247 files changed
+1891537
No files matched your search
+63
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Christian Ehrlicher, SLSE, 2016-02-29
|
||||
#
|
||||
|
||||
IF(${CMAKE_VERSION} VERSION_LESS "3.6.0")
|
||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS system) # system wird nicht gebraucht, aber ohne Komponente wird das Boost::boost imported Target nicht angelegt (cmake <= 3.5.2)
|
||||
ELSE()
|
||||
FIND_PACKAGE(Boost REQUIRED)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(Data)
|
||||
ADD_SUBDIRECTORY(Gui)
|
||||
ADD_SUBDIRECTORY(Shared)
|
||||
|
||||
|
||||
#
|
||||
# Menu Edit Gui Plugin Interface
|
||||
#
|
||||
ADD_INTERFACE_LIBRARY(AvmMenuEditGuiPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/avm_menu_edit_gui_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
GuiPluginInterface TopicReplayInterface TopicEditorInterface Qt5::Core AvmShared Boost::boost
|
||||
)
|
||||
|
||||
#
|
||||
# Combat Net Radio Gui Plugin Interface
|
||||
#
|
||||
ADD_INTERFACE_LIBRARY(AvmCombatNetRadioGuiPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/avm_combat_net_radio_gui_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
GuiPluginInterface Qt5::Core
|
||||
)
|
||||
|
||||
#
|
||||
# Eloka Gui Plugin Interface
|
||||
#
|
||||
ADD_INTERFACE_LIBRARY(AvmElokaGuiPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/avm_eloka_gui_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
GuiPluginInterface
|
||||
)
|
||||
|
||||
#
|
||||
# MVS Gui Plugin Interface
|
||||
#
|
||||
ADD_INTERFACE_LIBRARY(AvmMvsVideoTeamGuiPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/avm_mvs_video_team_gui_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
GuiPluginInterface
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Data Plugin 'Interface' - needs export for moc (signals)
|
||||
#
|
||||
ADD_INTERFACE_LIBRARY(AvmDataPluginInterface
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/avm_data_plugin_interface.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
DataPluginInterface svcAvmCommon Qt5::Core IsmDataPluginInterface
|
||||
)
|
||||
+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)
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
||||
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 );
|
||||
else
|
||||
liveVideoApp->show();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
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(); }
|
||||
|
||||
|
||||
|
||||
|
||||
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(); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
VdSession *vdSession() override;
|
||||
|
||||
|
||||
|
||||
StreamNameMapping *streamNameMapping() override;
|
||||
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+160
@@ -0,0 +1,160 @@
|
||||
|
||||
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (m_activeContexts.empty())
|
||||
return;
|
||||
|
||||
Q_ASSERT(m_activeContexts.size() == 1);
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
|
||||
class AvmExerciseContextManager
|
||||
{
|
||||
public:
|
||||
struct ExerciseContext;
|
||||
|
||||
~AvmExerciseContextManager();
|
||||
|
||||
|
||||
|
||||
|
||||
ExerciseContext *acquire(int exerciseId, LtsSession::LtsSessionDataDds *session);
|
||||
void release(int exerciseId, ExerciseContext *composite);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class AvmExerciseContextHandle
|
||||
{
|
||||
public:
|
||||
AvmExerciseContextHandle();
|
||||
AvmExerciseContextHandle(AvmExerciseContextManager *context, int exerciseId, LtsSession::LtsSessionDataDds *session);
|
||||
|
||||
operator bool() const { return m_context.get(); }
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+187
@@ -0,0 +1,187 @@
|
||||
|
||||
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
|
||||
class AvsSessionContext
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
struct Composite;
|
||||
|
||||
AvsSessionContext();
|
||||
~AvsSessionContext();
|
||||
|
||||
|
||||
|
||||
bool canAcquire(int exerciseId) const;
|
||||
|
||||
|
||||
|
||||
|
||||
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};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+167
@@ -0,0 +1,167 @@
|
||||
|
||||
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "operator_settings_observer.moc"
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
|
||||
|
||||
|
||||
#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 ExerciseManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class Exercise;
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class OperatorSettings;
|
||||
}
|
||||
|
||||
|
||||
enum class DataModification;
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+150
@@ -0,0 +1,150 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
|
||||
|
||||
|
||||
#include "audio_settings_avail_streams_model.h"
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
#include <QFont>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
QDataStream &operator<<(QDataStream &ds, const StreamData &sd)
|
||||
{
|
||||
ds << sd.topicId << sd.name << sd.bIsCnr;
|
||||
return ds;
|
||||
}
|
||||
QDataStream &operator>>(QDataStream &ds, StreamData &sd)
|
||||
{
|
||||
ds >> sd.topicId >> sd.name >> sd.bIsCnr ;
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AvailStreamsModel::AvailStreamsModel(Interface::Dtc *avmDtc,
|
||||
int32_t exerciseId,
|
||||
QObject *parent)
|
||||
: NGLTreeModel(parent, new NGLTreeItem(QVariant()), {tr("Available")})
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_cnrRoot(new NGLTreeItem(QVariant()))
|
||||
, m_tvcRoot(new NGLTreeItem(QVariant()))
|
||||
, m_changes(false)
|
||||
, m_logger(getLogger("AudioSettingsAvailStreamsModel"))
|
||||
{
|
||||
Q_ASSERT(avmDtc);
|
||||
|
||||
qRegisterMetaTypeStreamOperators<StreamData>();
|
||||
|
||||
setMimeType(StreamData::mimeType());
|
||||
|
||||
StreamData data;
|
||||
data.name = tr("CNR");
|
||||
data.bIsCnr = true;
|
||||
m_cnrRoot->setData(QVariant::fromValue(data));
|
||||
m_rootItem->appendChild(m_cnrRoot);
|
||||
|
||||
data.name = tr("TVC");
|
||||
data.bIsCnr = false;
|
||||
m_tvcRoot->setData(QVariant::fromValue(data));
|
||||
m_rootItem->appendChild(m_tvcRoot);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AvailStreamsModel::setStreamChanged(const QVector<StreamData> &streams)
|
||||
{
|
||||
for (const StreamData &d : streams)
|
||||
if (!m_changedStreams.contains(QPair<bool,int>(d.bIsCnr, d.topicId)))
|
||||
m_changedStreams += QPair<bool,int>(d.bIsCnr, d.topicId);
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
|
||||
bool AvailStreamsModel::initModel()
|
||||
{
|
||||
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::cnrConfigChanged,
|
||||
this, &AvailStreamsModel::onCnrConfigChanged, Qt::UniqueConnection);
|
||||
m_avmDtc->cnrConfigs([this](const AudioVideoManagement::CnrConfig & ch) { onCnrConfigChanged(ch, DataModification::eAdded); });
|
||||
|
||||
#if 0
|
||||
AudioVideoManagement::CnrConfig data;
|
||||
data.exerciseId(42);
|
||||
|
||||
data.id(1);
|
||||
data.radioCircuit(QStringLiteral("test1").toStdString());
|
||||
onCnrConfigChanged(data, DataModification::eAdded);
|
||||
|
||||
data.id(2);
|
||||
data.radioCircuit(QStringLiteral("test2").toStdString());
|
||||
onCnrConfigChanged(data, DataModification::eAdded);
|
||||
|
||||
AudioVideoManagement::TvcConfig data2;
|
||||
data2.id(1);
|
||||
data2.radioCircuit(QStringLiteral("test3 (tvc)").toStdString());
|
||||
onTvcConfigChanged(data2, DataModification::eAdded);
|
||||
#endif
|
||||
|
||||
connect(m_avmDtc, &AudioVideoManagement::Interface::Dtc::tvcConfigChanged,
|
||||
this, &AvailStreamsModel::onTvcConfigChanged, Qt::UniqueConnection);
|
||||
m_avmDtc->tvcConfigs([this](const AudioVideoManagement::TvcConfig & ch) { onTvcConfigChanged(ch, DataModification::eAdded); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags AvailStreamsModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags f = NGLTreeModel::flags(index) | Qt::ItemIsDropEnabled;
|
||||
if (!index.parent().isValid())
|
||||
f &= ~Qt::ItemIsDragEnabled;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QVariant AvailStreamsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
StreamData data = item->data().value<StreamData>();
|
||||
DEBUG_LOG(m_logger) << data.name;
|
||||
return data.name;
|
||||
}
|
||||
|
||||
case Qt::FontRole:
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
StreamData data = item->data().value<StreamData>();
|
||||
if (!m_changedStreams.contains(QPair<bool,int>(data.bIsCnr, data.topicId)))
|
||||
return {};
|
||||
QFont f;
|
||||
f.setBold(true);
|
||||
return f;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGLTreeModel::data(index, role);
|
||||
}
|
||||
|
||||
bool AvailStreamsModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(row);
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(parent);
|
||||
if (action != supportedDropActions())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AvailStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
Q_UNUSED(action);
|
||||
Q_UNUSED(row);
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
const QVector<NGLTreeItem *> droppedItems = getMimeDataItems(data, m_mimeType);
|
||||
QVector<StreamData> streams;
|
||||
streams.reserve(droppedItems.size());
|
||||
for (const NGLTreeItem *item : droppedItems)
|
||||
streams += item->data().value<StreamData>();
|
||||
qDeleteAll(droppedItems);
|
||||
emit droppedStreamNames(streams);
|
||||
m_changes = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AvailStreamsModel::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType)
|
||||
{
|
||||
insertUpdateData(data, modType, m_cnrRoot);
|
||||
}
|
||||
|
||||
void AvailStreamsModel::onTvcConfigChanged(const AudioVideoManagement::TvcConfig &data, DataModification modType)
|
||||
{
|
||||
insertUpdateData(data, modType, m_tvcRoot);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AvailStreamsModel::insertUpdateData(const T &config, DataModification modType, NGLTreeItem *parent)
|
||||
{
|
||||
DataModification action = modType;
|
||||
if (modType == DataModification::eModified)
|
||||
{
|
||||
|
||||
|
||||
if (config.exerciseId().is_set() && config.exerciseId().get() != m_exerciseId)
|
||||
action = DataModification::eRemoved;
|
||||
}
|
||||
|
||||
StreamData newData(config);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
if (config.exerciseId().is_set() && config.exerciseId().get() != m_exerciseId)
|
||||
break;
|
||||
Q_FALLTHROUGH();
|
||||
case DataModification::eModified:
|
||||
{
|
||||
bool bFound = false;
|
||||
for (int i = 0; i < parent->childCount(); ++i)
|
||||
{
|
||||
NGLTreeItem *child = parent->child(i);
|
||||
StreamData data = child->data().value<StreamData>();
|
||||
if (data == newData)
|
||||
{
|
||||
bFound = true;
|
||||
setItemData(indexFromItem(child), QVariant::fromValue(newData), child->icon());
|
||||
emit updateEntry(newData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bFound)
|
||||
{
|
||||
NGLTreeItem *child = new NGLTreeItem(QVariant::fromValue(newData));
|
||||
insertRow(parent->childCount(), indexFromItem(parent), child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataModification::eRemoved:
|
||||
{
|
||||
for (int i = 0; i < parent->childCount(); ++i)
|
||||
{
|
||||
NGLTreeItem *child = parent->child(i);
|
||||
StreamData data = child->data().value<StreamData>();
|
||||
if (data == newData)
|
||||
{
|
||||
removeRows(i, 1, indexFromItem(parent));
|
||||
emit removeEntry(newData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AvailStreamsFilter::AvailStreamsFilter(AvailStreamsModel *sourceModel, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_sourceModel(sourceModel)
|
||||
{
|
||||
Q_ASSERT(sourceModel);
|
||||
setSourceModel(m_sourceModel);
|
||||
}
|
||||
|
||||
void AvailStreamsFilter::addAllocatedStreams(const QVector<StreamData> &streams)
|
||||
{
|
||||
m_allocatedStreams.insert(streams.begin(), streams.end());
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void AvailStreamsFilter::setAllocatedStreams(const QVector<StreamData> &streams)
|
||||
{
|
||||
m_allocatedStreams.clear();
|
||||
m_allocatedStreams.insert(streams.begin(), streams.end());
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void AvailStreamsFilter::removeAllocatedStreams(const QVector<StreamData> &streams)
|
||||
{
|
||||
for (const StreamData &stream : streams)
|
||||
m_allocatedStreams.erase(stream);
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool AvailStreamsFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
if (!m_sourceModel || !source_parent.isValid())
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
|
||||
NGLTreeItem *parent = m_sourceModel->privateData(source_parent);
|
||||
if (!parent)
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
NGLTreeItem *child = parent->child(source_row);
|
||||
if (!child)
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
|
||||
StreamData data = child->data().value<StreamData>();
|
||||
return m_allocatedStreams.count(data) == 0;
|
||||
}
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <nglwidgets/ngltreemodel.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QVector>
|
||||
#include "audio_stream_type.h"
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class AvailStreamsModel final : public NGLTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AvailStreamsModel(AudioVideoManagement::Interface::Dtc *avmDtc, int32_t exerciseId,
|
||||
QObject *parent = nullptr);
|
||||
~AvailStreamsModel() = default;
|
||||
bool getChangeState() {bool result = m_changes; m_changes = false; return result;}
|
||||
void resetChangeState() {m_changes = false;m_changedStreams.clear();}
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
|
||||
Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }
|
||||
Qt::DropActions supportedDragActions() const override { return Qt::CopyAction; }
|
||||
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction, int, int, const QModelIndex &) override;
|
||||
void setStreamChanged(const QVector<StreamData> &streams);
|
||||
|
||||
bool initModel();
|
||||
|
||||
signals:
|
||||
void droppedStreamNames(const QVector<AudioVideoManagement::StreamData> &streamNamesDropped);
|
||||
void updateEntry(const AudioVideoManagement::StreamData &stream);
|
||||
void removeEntry(const AudioVideoManagement::StreamData &stream);
|
||||
|
||||
private slots:
|
||||
void onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType);
|
||||
void onTvcConfigChanged(const AudioVideoManagement::TvcConfig &data, DataModification modType);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void insertUpdateData(const T &data, DataModification modType, NGLTreeItem *parent);
|
||||
|
||||
int32_t m_exerciseId;
|
||||
AudioVideoManagement::Interface::Dtc *m_avmDtc;
|
||||
NGLTreeItem *m_cnrRoot;
|
||||
NGLTreeItem *m_tvcRoot;
|
||||
bool m_changes;
|
||||
QVector<QPair<bool , int> > m_changedStreams;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
class AvailStreamsFilter final : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AvailStreamsFilter(AvailStreamsModel *sourceModel, QObject *parent);
|
||||
|
||||
void addAllocatedStreams(const QVector<StreamData> &streams);
|
||||
void setAllocatedStreams(const QVector<StreamData> &streams);
|
||||
void removeAllocatedStreams(const QVector<StreamData> &streams);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
|
||||
using QSortFilterProxyModel::setSourceModel;
|
||||
|
||||
AvailStreamsModel *m_sourceModel;
|
||||
std::set<StreamData> m_allocatedStreams;
|
||||
};
|
||||
|
||||
}
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
|
||||
|
||||
|
||||
#include "audio_settings_dialog.h"
|
||||
#include "ui_audio_settings_dialog.h"
|
||||
#include "audio_settings_avail_streams_model.h"
|
||||
#include "audio_settings_used_streams_model.h"
|
||||
#include "audio_stream_type.h"
|
||||
#include <LtsWidgets/lts_message_dialog.h>
|
||||
#include <LtsSession/lts_session_data_dds.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <AudioVideoManagement/avm_ftc_types.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
AudioSettingsDialog::AudioSettingsDialog(QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_ui(new Ui::AudioSettingsDialog)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_logger(getLogger("AudioSettingsDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Voice_Communication_Access"));
|
||||
}
|
||||
|
||||
AudioSettingsDialog::~AudioSettingsDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool AudioSettingsDialog::init(OperatorManagement::Interface::Dtc *opmDtc,
|
||||
Interface::Dtc *avmDtc,
|
||||
Interface::Ftc *avmFtc,
|
||||
LtsSession::LtsSessionDataDds *session)
|
||||
{
|
||||
Q_ASSERT(opmDtc);
|
||||
Q_ASSERT(avmDtc);
|
||||
Q_ASSERT(avmFtc);
|
||||
Q_ASSERT(session);
|
||||
|
||||
setUnchangeable(true);
|
||||
|
||||
m_session = session;
|
||||
m_avmDtc = avmDtc;
|
||||
m_avmFtc = avmFtc;
|
||||
|
||||
|
||||
|
||||
m_modelAvailable = new AvailStreamsModel(avmDtc, m_session->exerciseId(), this);
|
||||
if (!m_modelAvailable->initModel())
|
||||
return false;
|
||||
|
||||
m_filterAvailable = new AvailStreamsFilter(m_modelAvailable, this);
|
||||
m_modelAllocated = new AllocatedStreamsModel(this);
|
||||
|
||||
connect(m_modelAvailable, &AvailStreamsModel::droppedStreamNames, this, &AudioSettingsDialog::onDroppedInAvailable);
|
||||
connect(m_modelAllocated, &AllocatedStreamsModel::droppedStreamNames, this, &AudioSettingsDialog::onDroppedInAllocated);
|
||||
|
||||
connect(m_modelAvailable, &AvailStreamsModel::updateEntry, m_modelAllocated, &AllocatedStreamsModel::updateEntry);
|
||||
connect(m_modelAvailable, &AvailStreamsModel::removeEntry, this, &AudioSettingsDialog::onEntryRemoved);
|
||||
|
||||
|
||||
m_ui->treeViewAvailable->setModel(m_filterAvailable);
|
||||
m_ui->treeViewAvailable->expandAll();
|
||||
m_ui->treeViewAllocated->setModel(m_modelAllocated);
|
||||
|
||||
|
||||
connect(opmDtc, &OperatorManagement::Interface::Dtc::userChanged,
|
||||
this, &AudioSettingsDialog::onOperatorChanged);
|
||||
auto cbOperator = [this](const OperatorManagement::User & u)
|
||||
{
|
||||
onOperatorChanged(u, DataModification::eAdded);
|
||||
};
|
||||
opmDtc->users(cbOperator);
|
||||
|
||||
fillOperatorBox();
|
||||
|
||||
connect(m_avmDtc, &Interface::Dtc::cnrTvcProfileChanged,
|
||||
this, &AudioSettingsDialog::onCnrTvcProfileChanged);
|
||||
auto cbRadioCircuits = [this](const CnrTvcProfile & rc)
|
||||
{
|
||||
onCnrTvcProfileChanged(rc, DataModification::eAdded);
|
||||
};
|
||||
m_avmDtc->cnrTvcProfiles(cbRadioCircuits);
|
||||
|
||||
connect(m_ui->pushButtonUp, &QPushButton::clicked, this, &AudioSettingsDialog::onUpButtonClicked);
|
||||
connect(m_ui->pushButtonDown, &QPushButton::clicked, this, &AudioSettingsDialog::onDownButtonClicked);
|
||||
connect(m_ui->operatorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AudioSettingsDialog::onSelectionOperatorChanged);
|
||||
connect(m_ui->treeViewAllocated->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AudioSettingsDialog::onSelectionChangedAllocation);
|
||||
|
||||
|
||||
m_ui->treeViewAllocated->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||
m_ui->treeViewAvailable->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||
|
||||
m_ui->treeViewAllocated->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_ui->treeViewAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
|
||||
|
||||
|
||||
|
||||
m_ui->pushButtonUp->setEnabled(false);
|
||||
m_ui->pushButtonDown->setEnabled(false);
|
||||
|
||||
m_avmFtc->enableAll();
|
||||
|
||||
int opId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
|
||||
if (m_ui->operatorComboBox->currentIndex() != m_ui->operatorComboBox->findData(opId))
|
||||
m_ui->operatorComboBox->setCurrentIndex(m_ui->operatorComboBox->findData(opId));
|
||||
else
|
||||
onSelectionOperatorChanged(0);
|
||||
setUnchangeable(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Voice Communication Access"));
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onOperatorChanged(const OperatorManagement::User &data, DataModification modType)
|
||||
{
|
||||
|
||||
DEBUG_LOG(m_logger) << "************** onOperatorChanged ";
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eRemoved:
|
||||
{
|
||||
Q_ASSERT(m_operatorMap.contains(data.id()));
|
||||
|
||||
|
||||
if (m_ui->operatorComboBox->currentData().toInt() == data.id())
|
||||
{
|
||||
__unchange__();
|
||||
m_modelAllocated->resetChangeState();
|
||||
m_modelAvailable->resetChangeState();
|
||||
m_filterAvailable->invalidate();
|
||||
}
|
||||
|
||||
m_operatorMap.remove(data.id());
|
||||
m_ui->operatorComboBox->removeItem(m_ui->operatorComboBox->findData(data.id()));
|
||||
break;
|
||||
}
|
||||
|
||||
case DataModification::eAdded:
|
||||
{
|
||||
Q_ASSERT(!m_operatorMap.contains(data.id()));
|
||||
const QString operatorName = QString::fromStdString(data.name());
|
||||
m_operatorMap.insert(data.id(), operatorName);
|
||||
m_ui->operatorComboBox->addItem(operatorName, data.id());
|
||||
m_ui->operatorComboBox->model()->sort(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case DataModification::eModified:
|
||||
{
|
||||
Q_ASSERT(m_operatorMap.contains(data.id()));
|
||||
const QString operatorName = QString::fromStdString(data.name());
|
||||
m_operatorMap.insert(data.id(), operatorName);
|
||||
int i = m_ui->operatorComboBox->findData(data.id());
|
||||
Q_ASSERT(i != -1);
|
||||
m_ui->operatorComboBox->setItemText(i, operatorName);
|
||||
m_ui->operatorComboBox->model()->sort(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onCnrTvcProfileChanged(const CnrTvcProfile &data, DataModification modType)
|
||||
{
|
||||
if (m_session->exerciseId() == data.exerciseId())
|
||||
{
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
m_cnrTvcProfileMap.remove(data.id());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cnrTvcProfileMap.insert(data.id(), data);
|
||||
fillOperatorList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::fillOperatorList()
|
||||
{
|
||||
QVector<StreamData> newStreamData;
|
||||
|
||||
for (const auto &rc : qAsConst(m_cnrTvcProfileMap))
|
||||
{
|
||||
if ((rc.exerciseId() != m_session->exerciseId())
|
||||
|| (rc.operatorId() != m_ui->operatorComboBox->currentData().toInt()))
|
||||
continue;
|
||||
|
||||
|
||||
newStreamData.reserve(rc.data().size());
|
||||
for (const CnrTvcProfileData &profileEntry : rc.data())
|
||||
newStreamData += toStreamData(profileEntry);
|
||||
|
||||
break;
|
||||
}
|
||||
m_modelAllocated->setNewStreamData(newStreamData);
|
||||
m_filterAvailable->setAllocatedStreams(newStreamData);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::fillOperatorBox()
|
||||
{
|
||||
m_ui->operatorComboBox->clear();
|
||||
QMap<int, QString>::iterator i = m_operatorMap.begin();
|
||||
while (i != m_operatorMap.end())
|
||||
{
|
||||
m_ui->operatorComboBox->addItem(i.value(), i.key());
|
||||
++i;
|
||||
}
|
||||
m_ui->operatorComboBox->model()->sort(0);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onUpButtonClicked()
|
||||
{
|
||||
const QModelIndexList mil = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
||||
if (mil.isEmpty())
|
||||
return;
|
||||
m_modelAllocated->changeOrder(mil.first(), true);
|
||||
|
||||
if (mil.first().row() > 0)
|
||||
{
|
||||
const QModelIndex newRow = m_modelAllocated->index(mil.first().row() - 1, 0);
|
||||
m_ui->treeViewAllocated->setCurrentIndex(newRow);
|
||||
}
|
||||
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onDownButtonClicked()
|
||||
{
|
||||
const QModelIndexList mil = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
||||
if (mil.isEmpty())
|
||||
return;
|
||||
m_modelAllocated->changeOrder(mil.first(), false);
|
||||
const QModelIndex newRow = m_modelAllocated->index(mil.first().row() + 1, 0);
|
||||
m_ui->treeViewAllocated->setCurrentIndex(newRow);
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onSelectionChangedAllocation(const QItemSelection &selected, const QItemSelection &deselected)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "onSelectionChangedAllocation selected.isEmpty()=" << selected.isEmpty();
|
||||
Q_UNUSED(deselected);
|
||||
QModelIndex first = m_ui->treeViewAllocated->model()->index(0, 0);
|
||||
int rowCnt = m_ui->treeViewAllocated->model()->rowCount();
|
||||
QModelIndex last = m_ui->treeViewAllocated->model()->index(rowCnt - 1, 0);
|
||||
QModelIndexList selectedRows = m_ui->treeViewAllocated->selectionModel()->selectedIndexes();
|
||||
const int cntSelectedRows = selectedRows.size();
|
||||
if (cntSelectedRows > 1)
|
||||
{
|
||||
m_ui->pushButtonUp->setEnabled(false);
|
||||
m_ui->pushButtonDown->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
if (selected.size() > 0)
|
||||
{
|
||||
m_ui->pushButtonUp->setEnabled(selected.first().indexes().first() != first);
|
||||
m_ui->pushButtonDown->setEnabled(selected.first().indexes().first() != last);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool AudioSettingsDialog::apply()
|
||||
{
|
||||
if (m_modelAllocated->getStreamDataVector().isEmpty())
|
||||
applyRemove();
|
||||
else
|
||||
applyModify();
|
||||
m_modelAllocated->resetChangeState();
|
||||
m_modelAvailable->resetChangeState();
|
||||
m_filterAvailable->invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioSettingsDialog::applyRemove()
|
||||
{
|
||||
RemoveCnrTvcProfileRequest removeRequest;
|
||||
DEBUG_LOG(m_logger) << "AudioSettingsDialog::applyRemove";
|
||||
|
||||
for (const auto &profile : qAsConst(m_cnrTvcProfileMap))
|
||||
{
|
||||
if (profile.operatorId() != m_operatorId)
|
||||
continue;
|
||||
removeRequest.id(profile.id());
|
||||
break;
|
||||
}
|
||||
if (removeRequest.id() <= 0)
|
||||
return true;
|
||||
|
||||
m_requestHelper->startSingleRequest([this, removeRequest]()
|
||||
{
|
||||
return m_avmFtc->removeCnrTvcProfileRequest(removeRequest, this);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioSettingsDialog::applyModify()
|
||||
{
|
||||
ModifyCnrTvcProfileRequest modifyRequest;
|
||||
DEBUG_LOG(m_logger) << "AudioSettingsDialog::applyModify";
|
||||
|
||||
for (const auto &profile : qAsConst(m_cnrTvcProfileMap))
|
||||
{
|
||||
if (profile.operatorId() != m_operatorId)
|
||||
continue;
|
||||
modifyRequest.id(profile.id());
|
||||
break;
|
||||
}
|
||||
|
||||
modifyRequest.exerciseId(m_session->exerciseId());
|
||||
modifyRequest.operatorId(m_operatorId);
|
||||
|
||||
const QVector<StreamData> allocatedList = m_modelAllocated->getStreamDataVector();
|
||||
modifyRequest.data().reserve(allocatedList.size());
|
||||
for (const StreamData &stream : allocatedList)
|
||||
{
|
||||
CnrTvcProfileData circuitData;
|
||||
circuitData.radioSystemId(stream.bIsCnr ? RadioSystem::Cnr : RadioSystem::Tvc);
|
||||
circuitData.radioCircuitId(stream.topicId);
|
||||
modifyRequest.data().push_back(std::move(circuitData));
|
||||
}
|
||||
|
||||
m_requestHelper->startSingleRequest([this, modifyRequest]()
|
||||
{
|
||||
return m_avmFtc->modifyCnrTvcProfileRequest(modifyRequest, this);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onModifyCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
__unchange__();
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onRemoveCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
__unchange__();
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
|
||||
void AudioSettingsDialog::onSelectionOperatorChanged(const int index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
if (hasUnsavedChanges() ||
|
||||
m_modelAllocated->getChangeState() ||
|
||||
m_modelAvailable->getChangeState())
|
||||
{
|
||||
switch (askApplyDiscardCancel())
|
||||
{
|
||||
case LtsWidgets::Button::Apply:
|
||||
if (!apply())
|
||||
return;
|
||||
break;
|
||||
case LtsWidgets::Button::Cancel:
|
||||
{
|
||||
|
||||
|
||||
|
||||
{
|
||||
QSignalBlocker blockSignals(m_ui->operatorComboBox);
|
||||
m_ui->operatorComboBox->setCurrentIndex(m_ui->operatorComboBox->findData(m_operatorId));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case LtsWidgets::Button::Discard:
|
||||
__unchange__();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_ui->pushButtonUp->setEnabled(false);
|
||||
m_ui->pushButtonDown->setEnabled(false);
|
||||
m_operatorId = m_ui->operatorComboBox->currentData().toInt();
|
||||
DEBUG_LOG(m_logger) << "onSelectionOperatorChanged" << " operatorStr=" << m_ui->operatorComboBox->currentText() << " m_operatorId= " << m_operatorId;
|
||||
fillOperatorList();
|
||||
m_modelAllocated->resetChangeState();
|
||||
m_modelAvailable->resetChangeState();
|
||||
m_filterAvailable->invalidate();
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onDroppedInAllocated(const QVector<StreamData> &streams)
|
||||
{
|
||||
slotChangesMade();
|
||||
m_filterAvailable->addAllocatedStreams(streams);
|
||||
m_modelAllocated->setStreamChanged(streams);
|
||||
m_modelAvailable->setStreamChanged(streams);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onDroppedInAvailable(const QVector<StreamData> &streams)
|
||||
{
|
||||
slotChangesMade();
|
||||
m_filterAvailable->removeAllocatedStreams(streams);
|
||||
m_modelAllocated->setStreamChanged(streams);
|
||||
m_modelAvailable->setStreamChanged(streams);
|
||||
}
|
||||
|
||||
void AudioSettingsDialog::onEntryRemoved(const StreamData &stream)
|
||||
{
|
||||
m_modelAllocated->removeEntry(stream);
|
||||
m_filterAvailable->removeAllocatedStreams({stream});
|
||||
}
|
||||
|
||||
StreamData AudioSettingsDialog::toStreamData(const CnrTvcProfileData &profileEntry) const
|
||||
{
|
||||
int configId = profileEntry.radioCircuitId();
|
||||
StreamData streamData;
|
||||
streamData.topicId = configId;
|
||||
|
||||
if (profileEntry.radioSystemId() == RadioSystem::Cnr)
|
||||
{
|
||||
streamData.name = QString::fromStdString(m_avmDtc->cnrConfig(configId).radioCircuit());
|
||||
streamData.bIsCnr = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
streamData.name = QString::fromStdString(m_avmDtc->tvcConfig(configId).radioCircuit());
|
||||
streamData.bIsCnr = false;
|
||||
}
|
||||
|
||||
return streamData;
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <OperatorManagement/opm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <QVector>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AudioSettingsDialog;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSessionDataDds;
|
||||
}
|
||||
|
||||
class QItemSelection;
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
struct StreamData;
|
||||
class AvailStreamsModel;
|
||||
class AvailStreamsFilter;
|
||||
class AllocatedStreamsModel;
|
||||
|
||||
|
||||
class AudioSettingsDialog : public LtsWidgets::LtsDialog
|
||||
, protected AudioVideoManagement::Interface::Ftc::ModifyCnrTvcProfileReplyHandler
|
||||
, protected AudioVideoManagement::Interface::Ftc::RemoveCnrTvcProfileReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AudioSettingsDialog(QWidget *parent = nullptr);
|
||||
~AudioSettingsDialog();
|
||||
|
||||
bool init(OperatorManagement::Interface::Dtc *opmDtc,
|
||||
AudioVideoManagement::Interface::Dtc *avmDtc,
|
||||
AudioVideoManagement::Interface::Ftc *avmFtc,
|
||||
LtsSession::LtsSessionDataDds *session);
|
||||
|
||||
void onModifyCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
void onRemoveCnrTvcProfileReply(const Core::FunctionReplyObject &replyObject) override;
|
||||
|
||||
private:
|
||||
enum class CircuitChoice
|
||||
{
|
||||
None,
|
||||
Cnr,
|
||||
Tvc
|
||||
};
|
||||
|
||||
void retranslate() override;
|
||||
bool apply() override final;
|
||||
bool applyModify();
|
||||
bool applyRemove();
|
||||
void fillOperatorBox();
|
||||
void fillOperatorList();
|
||||
|
||||
private slots:
|
||||
void onOperatorChanged(const OperatorManagement::User &data, DataModification modType);
|
||||
void onCnrTvcProfileChanged(const AudioVideoManagement::CnrTvcProfile &data, DataModification modType);
|
||||
void onUpButtonClicked();
|
||||
void onDownButtonClicked();
|
||||
void onSelectionChangedAllocation(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void onSelectionOperatorChanged(const int index);
|
||||
void onDroppedInAllocated(const QVector<StreamData> &streams);
|
||||
void onDroppedInAvailable(const QVector<StreamData> &streams);
|
||||
void onEntryRemoved(const StreamData &stream);
|
||||
|
||||
private:
|
||||
StreamData toStreamData(const CnrTvcProfileData &profileEntry) const;
|
||||
|
||||
AudioVideoManagement::Interface::Dtc *m_avmDtc{nullptr};
|
||||
AudioVideoManagement::Interface::Ftc *m_avmFtc{nullptr};
|
||||
|
||||
int m_operatorId{-1};
|
||||
QMap<int, QString> m_operatorMap;
|
||||
QMap<int, AudioVideoManagement::CnrTvcProfile> m_cnrTvcProfileMap;
|
||||
|
||||
AvailStreamsModel *m_modelAvailable{nullptr};
|
||||
AvailStreamsFilter *m_filterAvailable{nullptr};
|
||||
AllocatedStreamsModel *m_modelAllocated{nullptr};
|
||||
|
||||
Ui::AudioSettingsDialog *m_ui{nullptr};
|
||||
LtsUtils::RequestHelper *m_requestHelper{nullptr};
|
||||
LtsSession::LtsSessionDataDds *m_session{nullptr};
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AudioSettingsDialog</class>
|
||||
<widget class="QWidget" name="AudioSettingsDialog">
|
||||
<property name="windowTitle">
|
||||
<string>Voice Communication Access</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" rowspan="5">
|
||||
<widget class="QTreeView" name="treeViewAvailable">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::MoveAction</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" rowspan="5">
|
||||
<widget class="QTreeView" name="treeViewAllocated">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::CopyAction</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerCascadingSectionResizes">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="headerShowSortIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="pushButtonUp">
|
||||
<property name="text">
|
||||
<string notr="true">↑ </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="pushButtonDown">
|
||||
<property name="text">
|
||||
<string notr="true">↓</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>89</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbxOperator">
|
||||
<property name="text">
|
||||
<string>Operator:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsComboBox" name="operatorComboBox">
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>operatorComboBox</tabstop>
|
||||
<tabstop>treeViewAvailable</tabstop>
|
||||
<tabstop>treeViewAllocated</tabstop>
|
||||
<tabstop>pushButtonUp</tabstop>
|
||||
<tabstop>pushButtonDown</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
|
||||
|
||||
|
||||
#include "audio_settings_used_streams_model.h"
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
#include <QMimeData>
|
||||
#include <QFont>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
AllocatedStreamsModel::AllocatedStreamsModel(QObject *parent)
|
||||
: NGLTreeModel(parent, new NGLTreeItem(QVariant(QLatin1String("root"))), { tr("Allocated") })
|
||||
, m_logger(getLogger("AudioSettingsUsedStreamsModel"))
|
||||
{
|
||||
setMimeType(StreamData::mimeType());
|
||||
}
|
||||
|
||||
Qt::ItemFlags AllocatedStreamsModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
return NGLTreeModel::flags(index) | Qt::ItemIsDropEnabled;
|
||||
}
|
||||
|
||||
QVariant AllocatedStreamsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
StreamData data = item->data().value<StreamData>();
|
||||
DEBUG_LOG(m_logger) << data.name;
|
||||
return data.name;
|
||||
}
|
||||
|
||||
case Qt::FontRole:
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
StreamData data = item->data().value<StreamData>();
|
||||
if (!m_changedStreams.contains(QPair<bool,int>(data.bIsCnr, data.topicId)))
|
||||
return {};
|
||||
QFont f;
|
||||
f.setBold(true);
|
||||
return f;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGLTreeModel::data(index, role);
|
||||
}
|
||||
|
||||
|
||||
void AllocatedStreamsModel::setStreamChanged(const QVector<StreamData> &streams)
|
||||
{
|
||||
for (const StreamData &d : streams)
|
||||
if (!m_changedStreams.contains(QPair<bool,int>(d.bIsCnr, d.topicId)))
|
||||
m_changedStreams += QPair<bool,int>(d.bIsCnr, d.topicId);
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
|
||||
bool AllocatedStreamsModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
Q_UNUSED(row);
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(parent);
|
||||
if (action != supportedDropActions())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AllocatedStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
Q_UNUSED(row);
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
const QVector<NGLTreeItem *> droppedItems = getMimeDataItems(data, m_mimeType);
|
||||
QVector<StreamData> streams;
|
||||
streams.reserve(droppedItems.size());
|
||||
for (const NGLTreeItem *item : droppedItems)
|
||||
streams += item->data().value<StreamData>();
|
||||
qDeleteAll(droppedItems);
|
||||
emit droppedStreamNames(streams);
|
||||
m_changes = true;
|
||||
DEBUG_LOG(m_logger) << data->data(QStringLiteral("NGLTreeModel/dragDrop"));
|
||||
return NGLTreeModel::dropMimeData(data, action, row, 0, QModelIndex());
|
||||
}
|
||||
|
||||
|
||||
void AllocatedStreamsModel::setNewStreamData(const QVector<StreamData> &newData)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "set new stream data, count: " << newData.size();
|
||||
resetModel();
|
||||
for (const StreamData &sd : newData)
|
||||
m_rootItem->appendChild(new NGLTreeItem(QVariant::fromValue(sd)));
|
||||
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
QVector<StreamData> AllocatedStreamsModel::getStreamDataVector() const
|
||||
{
|
||||
QVector<StreamData> result;
|
||||
result.reserve(m_rootItem->childCount());
|
||||
for (int i = 0; i < m_rootItem->childCount(); i++)
|
||||
{
|
||||
const NGLTreeItem *item = m_rootItem->child(i);
|
||||
const StreamData sd = item->data().value<StreamData>();
|
||||
result.append(sd);
|
||||
DEBUG_LOG(m_logger) << "result.append(sd.name):" << sd.name;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "getStreamDataVector() size: " << result.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
void AllocatedStreamsModel::changeOrder(const QModelIndex &idx, bool up)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "changeOrder "
|
||||
<< " index = " << idx.row()
|
||||
<< " up = " << up
|
||||
<< " m_rootItem->childCount()= " << m_rootItem->childCount();
|
||||
if (up)
|
||||
{
|
||||
moveRow(idx.parent(), idx.row(),
|
||||
idx.parent(), idx.row() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveRow(idx.parent(), idx.row(),
|
||||
idx.parent(), idx.row() + 1);
|
||||
}
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
|
||||
void AllocatedStreamsModel::updateEntry(const StreamData &stream)
|
||||
{
|
||||
for (int i = 0; i < m_rootItem->childCount(); i++)
|
||||
{
|
||||
NGLTreeItem *child = m_rootItem->child(i);
|
||||
StreamData data = child->data().value<StreamData>();
|
||||
|
||||
if (data == stream)
|
||||
{
|
||||
setItemData(indexFromItem(child), QVariant::fromValue(stream), child->icon());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
|
||||
void AllocatedStreamsModel::removeEntry(const StreamData &stream)
|
||||
{
|
||||
for (int i = 0; i < m_rootItem->childCount(); i++)
|
||||
{
|
||||
NGLTreeItem *child = m_rootItem->child(i);
|
||||
StreamData data = child->data().value<StreamData>();
|
||||
if (data == stream)
|
||||
{
|
||||
removeRows(i, 1, indexFromItem(m_rootItem));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nglwidgets/ngltreemodel.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include "audio_stream_type.h"
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AllocatedStreamsModel final : public NGLTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AllocatedStreamsModel(QObject *parent = nullptr);
|
||||
|
||||
bool getChangeState() {bool result = m_changes; m_changes = false; return result;}
|
||||
void resetChangeState() {m_changes = false;m_changedStreams.clear();}
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
Qt::DropActions supportedDropActions() const override { return Qt::CopyAction; }
|
||||
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
|
||||
bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) override;
|
||||
void setStreamChanged(const QVector<StreamData> &streams);
|
||||
|
||||
void setNewStreamData(const QVector<StreamData> &newData);
|
||||
|
||||
QVector<StreamData> getStreamDataVector() const;
|
||||
|
||||
void changeOrder(const QModelIndex &idx, bool up);
|
||||
void updateEntry(const StreamData &stream);
|
||||
void removeEntry(const StreamData &stream);
|
||||
|
||||
signals:
|
||||
void droppedStreamNames(const QVector<AudioVideoManagement::StreamData> &streamNamesDropped);
|
||||
|
||||
private:
|
||||
bool m_changes{false};
|
||||
QVector<QPair<bool , int> > m_changedStreams;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <boost/operators.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
struct StreamData : boost::totally_ordered<StreamData>
|
||||
{
|
||||
StreamData() = default;
|
||||
|
||||
explicit StreamData(const TvcConfig &tvcConfig)
|
||||
: name(QString::fromStdString(tvcConfig.radioCircuit()))
|
||||
, topicId(tvcConfig.id())
|
||||
, bIsCnr(false)
|
||||
{}
|
||||
|
||||
explicit StreamData(const CnrConfig &cnrConfig)
|
||||
: name(QString::fromStdString(cnrConfig.radioCircuit()))
|
||||
, topicId(cnrConfig.id())
|
||||
, bIsCnr(true)
|
||||
{}
|
||||
|
||||
QString name;
|
||||
int topicId = 0;
|
||||
bool bIsCnr = false;
|
||||
|
||||
static QString mimeType() { return QStringLiteral("AVM/StreamData"); }
|
||||
|
||||
bool operator<(const StreamData &other) const { return asPair() < other.asPair(); }
|
||||
bool operator==(const StreamData &other) const { return asPair() == other.asPair(); }
|
||||
|
||||
private:
|
||||
std::pair<bool, int> asPair() const { return {bIsCnr, topicId}; }
|
||||
};
|
||||
|
||||
}
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::StreamData);
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Patric Karwat, SLSE, 2016-10-05
|
||||
#
|
||||
|
||||
SET(avm_menu_edit_gui_SRCS
|
||||
avm_menu_edit_gui_plugin.cpp
|
||||
avm_menu_edit_gui_plugin.h
|
||||
avm_menu_edit_view.cpp
|
||||
avm_menu_edit_view.h
|
||||
avm_menu_edit.cpp
|
||||
avm_menu_edit.h
|
||||
avm_menu_view_model.cpp
|
||||
avm_menu_view_model.h
|
||||
avm_available_streams_model.cpp
|
||||
avm_available_streams_model.h
|
||||
avm_choose_menu.cpp
|
||||
avm_choose_menu.h
|
||||
avm_new_menu_struct.cpp
|
||||
avm_new_menu_struct.h
|
||||
avm_used_streams_model.cpp
|
||||
avm_used_streams_model.h
|
||||
avm_playback_menu.cpp
|
||||
avm_playback_menu.h
|
||||
avm_playback_menu_dialog.cpp
|
||||
avm_playback_menu_dialog.h
|
||||
TopicEditor/topic_editor.cpp
|
||||
TopicEditor/topic_editor.h
|
||||
TopicEditor/avm_sequence_model.cpp
|
||||
TopicEditor/avm_sequence_model.h
|
||||
interval_model.cpp
|
||||
interval_model.h
|
||||
topic_replay.cpp
|
||||
topic_replay.h
|
||||
|
||||
AudioSettings/audio_settings_dialog.cpp
|
||||
AudioSettings/audio_settings_dialog.h
|
||||
AudioSettings/audio_stream_type.h
|
||||
AudioSettings/audio_settings_avail_streams_model.cpp
|
||||
AudioSettings/audio_settings_avail_streams_model.h
|
||||
AudioSettings/audio_settings_used_streams_model.cpp
|
||||
AudioSettings/audio_settings_used_streams_model.h
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(avm_menu_edit_gui_SRCS
|
||||
avm_menu_edit_view.ui
|
||||
avm_menu_edit.ui
|
||||
avm_choose_menu.ui
|
||||
avm_new_menu_struct.ui
|
||||
avm_playback_menu.ui
|
||||
avm_playback_menu_dialog.ui
|
||||
TopicEditor/topic_editor.ui
|
||||
AudioSettings/audio_settings_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS avmMenuEditGuiPlugin MODULE ${avm_menu_edit_gui_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(avmMenuEditGuiPlugin
|
||||
AvmDataPluginInterface
|
||||
AvmMenuEditGuiPluginInterface
|
||||
AvmShared
|
||||
FlmDataPluginInterface
|
||||
IsmDataPluginInterface
|
||||
LtsDataView
|
||||
LtsPrinting
|
||||
LtsScriptTimeline
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
LtsUtilsGuiDds
|
||||
LtsUtilsCore
|
||||
LtsWidgets
|
||||
LtsUtilsSettings
|
||||
nglsettings
|
||||
MrkCommon
|
||||
MrkDataPluginInterface
|
||||
NGLLogger
|
||||
ngltools
|
||||
nglwidgets
|
||||
OpmDataPluginInterface
|
||||
Qt5::Widgets
|
||||
TopicEditorBase
|
||||
Boost::boost
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(avmMenuEditGuiPlugin)
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_sequence_model.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QColor>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
AvmSequenceModel::AvmSequenceModel(QObject *parent)
|
||||
: LtsWidgets::LtsAbstractTableModel<AvsSequence>({QLatin1String("Order"),
|
||||
tr("Start"),
|
||||
tr("End"),
|
||||
tr("Duration [s]"),
|
||||
tr("Stream"),
|
||||
tr("Speed"),
|
||||
tr("Volume"),
|
||||
tr("Description")},
|
||||
parent)
|
||||
, m_logger(getLogger("AvmSequenceModel"))
|
||||
{}
|
||||
|
||||
void AvmSequenceModel::setTimezoneHoursOffset(int timezoneHoursOffset)
|
||||
{
|
||||
m_timezoneHoursOffset = timezoneHoursOffset;
|
||||
emit dataChanged(index(0, Start), index(rowCount()-1, End), {Qt::DisplayRole});
|
||||
}
|
||||
|
||||
void AvmSequenceModel::moveUp(const QModelIndex &idx)
|
||||
{
|
||||
|
||||
int row = idx.row();
|
||||
auto it = std::find_if(m_highlightedRows.begin(), m_highlightedRows.end(), [row](int currentRow)
|
||||
{
|
||||
return (row == currentRow);
|
||||
});
|
||||
|
||||
if (it != m_highlightedRows.end())
|
||||
(*it)--;
|
||||
|
||||
moveRows(idx.parent(), idx.row(), 1, idx.parent(), idx.row() - 1);
|
||||
}
|
||||
|
||||
void AvmSequenceModel::moveDown(const QModelIndex &idx)
|
||||
{
|
||||
|
||||
int row = idx.row();
|
||||
auto it = std::find_if(m_highlightedRows.begin(), m_highlightedRows.end(), [row](int currentRow)
|
||||
{
|
||||
return (row == currentRow);
|
||||
});
|
||||
|
||||
if (it != m_highlightedRows.end())
|
||||
(*it)++;
|
||||
moveRows(idx.parent(), idx.row(), 1, idx.parent(), idx.row() + 1);
|
||||
}
|
||||
|
||||
bool AvmSequenceModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
|
||||
{
|
||||
Q_UNUSED(count)
|
||||
if(sourceRow > m_vecData.size() -1 || sourceRow < 0 ||
|
||||
destinationChild > m_vecData.size() -1 || destinationChild < 0)
|
||||
return false;
|
||||
|
||||
int moveTo = destinationChild;
|
||||
if (destinationChild > sourceRow)
|
||||
moveTo++;
|
||||
|
||||
beginMoveRows(sourceParent, sourceRow, sourceRow, destinationParent, moveTo);
|
||||
m_vecData.move(sourceRow, destinationChild);
|
||||
endMoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline std::chrono::milliseconds fromJsonValue(const QJsonValue &val)
|
||||
{
|
||||
qint64 d = static_cast<qint64>(val.toDouble());
|
||||
return std::chrono::milliseconds(d);
|
||||
}
|
||||
|
||||
bool AvmSequenceModel::initModel(const QJsonArray &data)
|
||||
{
|
||||
m_highlightedRows.clear();
|
||||
clear();
|
||||
|
||||
AvsSequence seq;
|
||||
for (const auto &ele : data)
|
||||
{
|
||||
const QJsonObject &seqObj = ele.toObject();
|
||||
if (seqObj.isEmpty())
|
||||
continue;
|
||||
seq.internalStreamName = seqObj.value(QStringLiteral("stream")).toString();
|
||||
seq.speed = seqObj.value(QStringLiteral("speed")).toInt();
|
||||
seq.volume = seqObj.value(QStringLiteral("volume")).toInt();
|
||||
seq.start = AvaTimePoint(std::chrono::duration_cast<AvaDuration>(fromJsonValue(seqObj.value(QStringLiteral("start")))));
|
||||
seq.duration = std::chrono::duration_cast<AvaDuration>(fromJsonValue(seqObj.value(QStringLiteral("duration"))));
|
||||
seq.pint = seqObj.value(QStringLiteral("pint")).toBool();
|
||||
seq.description = seqObj.value(QStringLiteral("description")).toString();
|
||||
insertRow(seq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonArray AvmSequenceModel::getSequencesAsJsonArray() const
|
||||
{
|
||||
QJsonArray ret;
|
||||
|
||||
if (m_vecData.size() <= 0)
|
||||
return ret;
|
||||
|
||||
for (int i = 0; i < m_vecData.size(); ++i)
|
||||
{
|
||||
const AvsSequence &seq = m_vecData.at(i);
|
||||
QJsonObject seqJson;
|
||||
seqJson.insert(QLatin1String("pos"), i);
|
||||
seqJson.insert(QLatin1String("description"), seq.description);
|
||||
|
||||
seqJson.insert(QLatin1String("start"), static_cast<qint64>(std::chrono::milliseconds(seq.start.time_since_epoch()).count()));
|
||||
seqJson.insert(QLatin1String("duration"), static_cast<qint64>(std::chrono::milliseconds(seq.duration).count()));
|
||||
seqJson.insert(QLatin1String("speed"), static_cast<int>(seq.speed));
|
||||
seqJson.insert(QLatin1String("stream"), seq.internalStreamName);
|
||||
seqJson.insert(QLatin1String("volume"), static_cast<int>(seq.volume));
|
||||
seqJson.insert(QLatin1String("pint"), seq.pint);
|
||||
ret.append(seqJson);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
QString AvmSequenceModel::dateTimeToStringx(const QDateTime &dt) const
|
||||
{
|
||||
return QDateTime::fromMSecsSinceEpoch(dt.toMSecsSinceEpoch() + (m_timezoneHoursOffset * 3600 * 1000)).toString(QStringLiteral("dd.MM.yy HH:mm:ss.zzz"));
|
||||
}
|
||||
|
||||
|
||||
QString AvmSequenceModel::msecsSinceEpochToStringx(qint64 msecs) const
|
||||
{
|
||||
return dateTimeToStringx(QDateTime::fromMSecsSinceEpoch(msecs));
|
||||
}
|
||||
|
||||
|
||||
QVariant AvmSequenceModel::data(const QModelIndex &idx, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole && role != Qt::BackgroundRole)
|
||||
return QVariant();
|
||||
|
||||
if (!indexIsValid(idx))
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const AvsSequence &seq = m_vecData.at(idx.row());
|
||||
switch (idx.column())
|
||||
{
|
||||
case Order:
|
||||
return idx.row() + 1;
|
||||
case Start:
|
||||
return msecsSinceEpochToStringx(std::chrono::milliseconds(seq.start.time_since_epoch()).count());
|
||||
case End:
|
||||
return msecsSinceEpochToStringx(std::chrono::milliseconds((seq.start+seq.duration).time_since_epoch()).count());
|
||||
case Duration:
|
||||
{
|
||||
qint64 duration = std::chrono::milliseconds(seq.duration).count();
|
||||
qint64 durationDisplay = duration / seq.speed * 100;
|
||||
|
||||
qint64 secs = durationDisplay / 1000;
|
||||
qint64 msecs = (durationDisplay % 1000);
|
||||
|
||||
return QStringLiteral("%1.%2").arg(secs).arg(msecs, 3, 10, QLatin1Char('0'));
|
||||
}
|
||||
case Description:
|
||||
return seq.description;
|
||||
case Streams:
|
||||
return seq.internalStreamName;
|
||||
case Volume:
|
||||
return QVariant(seq.volume);
|
||||
case Speed:
|
||||
return QVariant(seq.speed);
|
||||
}
|
||||
}
|
||||
else if (role == Qt::BackgroundRole)
|
||||
{
|
||||
if (m_highlightedRows.contains(idx.row()))
|
||||
return QColor(Qt::green);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void AvmSequenceModel::setHighlightedRow(int highlighted, bool reset)
|
||||
{
|
||||
QVector<int> oldSelected = m_highlightedRows;
|
||||
|
||||
if (highlighted < 0)
|
||||
m_highlightedRows.clear();
|
||||
else if (reset)
|
||||
m_highlightedRows = { highlighted };
|
||||
else
|
||||
m_highlightedRows += highlighted;
|
||||
|
||||
if (m_highlightedRows == oldSelected)
|
||||
return;
|
||||
|
||||
QVector<int> changedRows;
|
||||
changedRows.reserve(oldSelected.size() + m_highlightedRows.size());
|
||||
|
||||
if (m_highlightedRows.isEmpty() || reset)
|
||||
for (int row : qAsConst(oldSelected))
|
||||
changedRows += row;
|
||||
|
||||
for (int row : qAsConst(m_highlightedRows))
|
||||
changedRows += row;
|
||||
|
||||
for (int row : qAsConst(changedRows))
|
||||
emit dataChanged(index(row, 0), index(row, Description), { Qt::BackgroundRole });
|
||||
}
|
||||
|
||||
void AvmSequenceProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
m_sourceModel = qobject_cast<AvmSequenceModel*>(sourceModel);
|
||||
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool AvmSequenceProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (!m_sourceModel ||
|
||||
source_left.column() != source_right.column() ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid())
|
||||
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
|
||||
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
|
||||
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
|
||||
switch (source_left.column())
|
||||
{
|
||||
case AvmSequenceModel::Start:
|
||||
return std::chrono::milliseconds(dataLeft.start.time_since_epoch()).count() < std::chrono::milliseconds(dataRight.start.time_since_epoch()).count();
|
||||
case AvmSequenceModel::End:
|
||||
return std::chrono::milliseconds((dataLeft.start+dataLeft.duration).time_since_epoch()).count() < std::chrono::milliseconds((dataRight.start+dataLeft.duration).time_since_epoch()).count();
|
||||
case AvmSequenceModel::Order:
|
||||
case AvmSequenceModel::Speed:
|
||||
case AvmSequenceModel::Streams:
|
||||
case AvmSequenceModel::Volume:
|
||||
case AvmSequenceModel::Description:
|
||||
break;
|
||||
}
|
||||
|
||||
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvsSequence
|
||||
{
|
||||
public:
|
||||
QString internalStreamName;
|
||||
AvaSpeed speed{100};
|
||||
AvaVolume volume{0};
|
||||
AvaTimePoint start;
|
||||
AvaDuration duration;
|
||||
bool pint = false;
|
||||
QString description;
|
||||
};
|
||||
|
||||
|
||||
class AvmSequenceModel final : public LtsWidgets::LtsAbstractTableModel<AvsSequence>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
Order = 0,
|
||||
Start,
|
||||
End,
|
||||
Duration,
|
||||
Streams,
|
||||
Speed,
|
||||
Volume,
|
||||
Description
|
||||
};
|
||||
|
||||
explicit AvmSequenceModel(QObject *parent = nullptr);
|
||||
void moveUp(const QModelIndex &idx);
|
||||
void moveDown(const QModelIndex &idx);
|
||||
bool initModel(const QJsonArray &data);
|
||||
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
|
||||
QJsonArray getSequencesAsJsonArray() const;
|
||||
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
|
||||
QVector<int> highlightedRows() const { return m_highlightedRows; }
|
||||
void setHighlightedRow(int highlighted, bool reset = true);
|
||||
|
||||
friend class AvmSequenceProxyModel;
|
||||
|
||||
public slots:
|
||||
void setTimezoneHoursOffset(int timezoneHoursOffset);
|
||||
|
||||
private:
|
||||
QString dateTimeToStringx(const QDateTime &dt) const;
|
||||
QString msecsSinceEpochToStringx(qint64 msecs) const;
|
||||
|
||||
QVector<int> m_highlightedRows;
|
||||
int m_timezoneHoursOffset = 0;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
class AvmSequenceProxyModel final : public LtsWidgets::LtsColumnFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
private:
|
||||
AvmSequenceModel *m_sourceModel = nullptr;
|
||||
};
|
||||
}
|
||||
+677
@@ -0,0 +1,677 @@
|
||||
|
||||
|
||||
|
||||
#include "topic_editor.h"
|
||||
#include "ui_topic_editor.h"
|
||||
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <AudioVideoManagement/ava_comm.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
#include <AudioVideoManagement/avs_dialog.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <TopicEditorBase/topic_previewer.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <cmath>
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
|
||||
#include <QScopeGuard>
|
||||
#endif
|
||||
|
||||
|
||||
static constexpr int s_defaultOffset = 10 * 1000;
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
QString dateTimeToStringz(const QDateTime &dt)
|
||||
{
|
||||
return dt.toString(QStringLiteral("dd.MM.yy HH:mm:ss.zzz"));
|
||||
}
|
||||
|
||||
QString msecsSinceEpochToStringz(qint64 msecs)
|
||||
{
|
||||
return dateTimeToStringz(QDateTime::fromMSecsSinceEpoch(msecs));
|
||||
}
|
||||
|
||||
qint64 timePointToMsecs(const AvaTimePoint &atp)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(atp.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
AvaDuration msecsToAvaDuration(qint64 msecs)
|
||||
{
|
||||
return std::chrono::duration_cast<AvaDuration>(std::chrono::milliseconds(msecs));
|
||||
}
|
||||
|
||||
AvaTimePoint msecsToAvaTimePoint(qint64 msecs)
|
||||
{
|
||||
return AvaTimePoint(msecsToAvaDuration(msecs));
|
||||
}
|
||||
|
||||
|
||||
TopicEditor::TopicEditor(LtsSession::LtsSession *session, const TopicEditorBase::TopicData &data, QWidget *parent)
|
||||
: TopicEditorBase::TopicEditor(parent)
|
||||
, m_session(session)
|
||||
, m_avmDataIfc(nullptr)
|
||||
, m_model(new AvmSequenceModel(this))
|
||||
, m_playbackMenu(nullptr)
|
||||
, m_ui(new Ui::AVTopicEditor)
|
||||
, m_logger(getLogger("TopicEditor"))
|
||||
{
|
||||
Q_ASSERT(session);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
m_ui->tvSequences->hideColumn(AvmSequenceModel::Order);
|
||||
init(m_ui->widget);
|
||||
|
||||
m_isAudio = (data.topicType == TopicEditorBase::TopicType::Audio);
|
||||
if (m_isAudio)
|
||||
setOnlineHelpFilename(QStringLiteral("Script_Editor-Add_Audio_Topic"));
|
||||
else
|
||||
setOnlineHelpFilename(QStringLiteral("Script_Editor-Add_Video_Topic"));
|
||||
|
||||
setTopicData(data);
|
||||
m_topicData.properties[QStringLiteral("IsAudio")] = bool(m_topicData.topicType == TopicEditorBase::TopicType::Audio);
|
||||
m_ui->widget->previewer()->setTopicData(m_topicData);
|
||||
|
||||
QJsonArray arr = getTopicVDataAsArray(QLatin1String("Sequences"));
|
||||
m_model->initModel(arr);
|
||||
m_ui->tvSequences->resizeColumnsToContents();
|
||||
refreshDurationText();
|
||||
m_proxyModel = new AvmSequenceProxyModel(this);
|
||||
m_proxyModel->setSourceModel(m_model);
|
||||
m_ui->tvSequences->setModel(m_proxyModel);
|
||||
connect(m_ui->tvSequences, SIGNAL(doubleClicked(QModelIndex)),
|
||||
m_ui->tvSequences->selectionModel(), SLOT(select(QModelIndex, QItemSelectionModel::Toggle)));
|
||||
|
||||
connect(m_ui->tvSequences->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||
this, &TopicEditor::onEnaDisa);
|
||||
connect(m_ui->pbDelete, &QToolButton::clicked,
|
||||
this, &TopicEditor::onDeleteSequences);
|
||||
connect(m_ui->pbUp, &QToolButton::clicked,
|
||||
this, &TopicEditor::onSequenceUp);
|
||||
connect(m_ui->pbDown, &QToolButton::clicked,
|
||||
this, &TopicEditor::onSequenceDown);
|
||||
connect(m_ui->pbPreview, &QPushButton::clicked, this, [this]()
|
||||
{
|
||||
m_playbackMenu->setStreamTime(m_ui->dtStart->msecsSinceEpoch());
|
||||
});
|
||||
|
||||
if (!m_session->getForeignDataInterface_NEW<AudioVideoManagement::DataInterface>(m_avmDataIfc))
|
||||
{
|
||||
playbackDlgNotAvailable(tr("The audio/video interface is not available in this session."));
|
||||
return;
|
||||
}
|
||||
|
||||
PlaybackApp *app = m_isAudio ? m_avmDataIfc->audioPlaybackApp() : m_avmDataIfc->videoPlaybackApp();
|
||||
if (app == nullptr)
|
||||
{
|
||||
playbackDlgNotAvailable(tr("The audio/video interface is currently not available."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->inUse())
|
||||
{
|
||||
playbackDlgNotAvailable(tr("The audio/video interface is already in use by another dialog."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
m_ui->pbApply->setEnabled(false);
|
||||
m_ui->pbDelete->setEnabled(false);
|
||||
m_ui->pbUp->setEnabled(false);
|
||||
m_ui->pbDown->setEnabled(false);
|
||||
|
||||
|
||||
boost::optional<QString> stream = boost::none;
|
||||
if (m_topicData.properties.contains(QStringLiteral("stream")))
|
||||
stream = m_topicData.properties.value(QStringLiteral("stream")).toString();
|
||||
|
||||
|
||||
qint64 startMsecs = 0;
|
||||
boost::optional<AvaTimePoint> start = boost::none;
|
||||
{
|
||||
const QJsonValue jsonValue(getTopicDataValue(QStringLiteral("start")));
|
||||
if (jsonValue.isDouble())
|
||||
{
|
||||
startMsecs = static_cast<qint64>(jsonValue.toDouble());
|
||||
start = boost::optional<AvaTimePoint>(toTimePoint(startMsecs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qint64 endMsecs = 0;
|
||||
{
|
||||
const QJsonValue jsonValue(getTopicDataValue(QStringLiteral("end")));
|
||||
if (jsonValue.isDouble())
|
||||
endMsecs = static_cast<qint64>(jsonValue.toDouble());
|
||||
}
|
||||
|
||||
m_playbackMenu = new AvmPlaybackMenu(this);
|
||||
m_playbackMenu->init(
|
||||
m_session, m_avmDataIfc->avaSession(), PlaybackAppHandle(app), m_avmDataIfc->streamNameMapping(), m_isAudio, true ,
|
||||
stream, start
|
||||
);
|
||||
m_ui->playbackParent->layout()->addWidget(m_playbackMenu);
|
||||
|
||||
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::setTopicButtonStates,
|
||||
this, &TopicEditor::onSetTopicButtonStates);
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::markerSelected,
|
||||
this, &TopicEditor::onMarkerSelected);
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalCurrentStreamChanged, this, [this](const QString &displayName)
|
||||
{
|
||||
m_ui->lblStream->setText(displayName);
|
||||
});
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalSetStart, this, [this](qint64 start)
|
||||
{
|
||||
m_ui->dtStart->setMsecsSinceEpoch(start);
|
||||
if (m_ui->dtEnd->msecsSinceEpoch() < start)
|
||||
m_ui->dtEnd->setMsecsSinceEpoch(start + s_defaultOffset);
|
||||
});
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalSetEnd, this, [this](qint64 end)
|
||||
{
|
||||
m_ui->dtEnd->setMsecsSinceEpoch(end);
|
||||
if (m_ui->dtStart->msecsSinceEpoch() > end)
|
||||
m_ui->dtStart->setMsecsSinceEpoch(end - s_defaultOffset);
|
||||
});
|
||||
m_playbackMenu->show();
|
||||
|
||||
|
||||
|
||||
|
||||
if (m_topicData.startTime > -1)
|
||||
{
|
||||
m_ui->dtStart->setMsecsSinceEpoch(static_cast<qint64>(m_topicData.startTime) * 1000);
|
||||
if (m_topicData.duration > 0)
|
||||
m_ui->dtEnd->setMsecsSinceEpoch(static_cast<qint64>(m_topicData.startTime + m_topicData.duration) * 1000);
|
||||
}
|
||||
|
||||
|
||||
connect(m_ui->tvSequences, &QTableView::doubleClicked,
|
||||
this, &TopicEditor::onEditSequence);
|
||||
connect(m_ui->dtStart, &LtsWidgets::LtsMSecDateTimeEdit::dateTimeChanged,
|
||||
this, &TopicEditor::onTimeChanged);
|
||||
connect(m_ui->dtEnd, &LtsWidgets::LtsMSecDateTimeEdit::dateTimeChanged,
|
||||
this, &TopicEditor::onTimeChanged);
|
||||
connect(m_ui->pbAdd, &QToolButton::clicked,
|
||||
this, &TopicEditor::onAddSequence);
|
||||
connect(m_ui->pbApply, &QToolButton::clicked,
|
||||
this, &TopicEditor::onApplySequence);
|
||||
connect(m_ui->pbEditSequence, &QPushButton::clicked,
|
||||
this, &TopicEditor::onEditSequence);
|
||||
|
||||
|
||||
if (startMsecs > 0 && endMsecs > 0)
|
||||
{
|
||||
m_ui->dtStart->setMsecsSinceEpoch(startMsecs);
|
||||
m_ui->dtEnd->setMsecsSinceEpoch(endMsecs);
|
||||
}
|
||||
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalTimezoneChanged,
|
||||
m_ui->dtStart, &LtsWidgets::LtsMSecDateTimeEdit::setTimezoneHoursOffset);
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalTimezoneChanged,
|
||||
m_ui->dtEnd, &LtsWidgets::LtsMSecDateTimeEdit::setTimezoneHoursOffset);
|
||||
connect(m_playbackMenu, &AvmPlaybackMenu::signalTimezoneChanged,
|
||||
m_model, &AvmSequenceModel::setTimezoneHoursOffset);
|
||||
|
||||
int offset = m_playbackMenu->currentOffset();
|
||||
m_model->setTimezoneHoursOffset(offset);
|
||||
m_ui->dtStart->setTimezoneHoursOffset(offset);
|
||||
m_ui->dtEnd->setTimezoneHoursOffset(offset);
|
||||
}
|
||||
|
||||
TopicEditor::~TopicEditor()
|
||||
{
|
||||
delete m_ui;
|
||||
delete m_model;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void TopicEditor::updateInternalData()
|
||||
{
|
||||
if (hasTopicDataProperties())
|
||||
{
|
||||
m_topicStartTime = getTopicDataValue(QStringLiteral("start")).toDouble();
|
||||
m_topicStreamName = getTopicDataValue(QStringLiteral("stream")).toString();
|
||||
QJsonArray arr = getTopicVDataAsArray(QLatin1String("Sequences"));
|
||||
m_model->initModel(arr);
|
||||
m_ui->tvSequences->resizeColumnsToContents();
|
||||
setDurationText(calcTrackLength(arr));
|
||||
}
|
||||
|
||||
m_ui->pbApply->setEnabled(false);
|
||||
m_ui->pbDelete->setEnabled(false);
|
||||
}
|
||||
|
||||
void TopicEditor::retranslate()
|
||||
{
|
||||
|
||||
translate(m_ui, m_topicData.topicType == TopicEditorBase::TopicType::Audio ? tr("Audio Topic Editor") : tr("Video Topic Editor") );
|
||||
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setText(tr("Apply to topic", "Auf Topic übernehmen"));
|
||||
}
|
||||
|
||||
|
||||
AvsSequence TopicEditor::createSequence(const AvaTimePoint &start, const AvaTimePoint &end) const
|
||||
{
|
||||
AvsSequence seq;
|
||||
|
||||
seq.start = start;
|
||||
seq.duration = end - start;
|
||||
seq.description = m_ui->leDescription->text();
|
||||
|
||||
if (m_playbackMenu != nullptr)
|
||||
{
|
||||
seq.speed = m_playbackMenu->getSpeed();
|
||||
seq.volume = m_playbackMenu->getVolume();
|
||||
seq.internalStreamName = m_playbackMenu->getInternalStreamName();
|
||||
seq.pint = m_playbackMenu->getSkipPause();
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
AvsSequence TopicEditor::createCurrentSequence() const
|
||||
{
|
||||
return createSequence(AvaTimePoint(std::chrono::duration_cast<AvaDuration>(std::chrono::milliseconds(m_ui->dtStart->msecsSinceEpoch()))),
|
||||
AvaTimePoint(std::chrono::duration_cast<AvaDuration>(std::chrono::milliseconds(m_ui->dtEnd->msecsSinceEpoch()))));
|
||||
}
|
||||
|
||||
void TopicEditor::refreshDurationText()
|
||||
{
|
||||
setDurationText(calcTrackLength(m_model->getSequencesAsJsonArray()));
|
||||
}
|
||||
|
||||
void TopicEditor::setDurationText(qint64 length)
|
||||
{
|
||||
if (length > s_durationLimit)
|
||||
m_ui->lblDuration->setText(tr("Playback too long!"));
|
||||
else
|
||||
m_ui->lblDuration->setText(QTime::fromMSecsSinceStartOfDay(length).toString(QStringLiteral("HH:mm:ss.zzz")));
|
||||
}
|
||||
|
||||
qint64 TopicEditor::calcTrackLength(const QJsonArray &arr) const
|
||||
{
|
||||
qint64 length = 0;
|
||||
for (const auto &ele : arr)
|
||||
{
|
||||
const QJsonObject &seqObj = ele.toObject();
|
||||
if (seqObj.isEmpty())
|
||||
continue;
|
||||
|
||||
length += std::ceil(seqObj.value(QLatin1String("duration")).toDouble() / (std::fabs(seqObj.value(QLatin1String("speed")).toDouble(100))) * 100 );
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void TopicEditor::playbackDlgNotAvailable(const QString &msg)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, msg);
|
||||
m_ui->groupBox->hide();
|
||||
m_ui->line->hide();
|
||||
|
||||
|
||||
m_ui->pbEditSequence->hide();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool TopicEditor::apply2()
|
||||
{
|
||||
const QJsonArray &arr = m_model->getSequencesAsJsonArray();
|
||||
qint64 duration = calcTrackLength(arr);
|
||||
|
||||
if (duration > s_durationLimit)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("This topic has exceeded the maximum length of %1 seconds.").arg(s_durationLimit));
|
||||
return false;
|
||||
}
|
||||
|
||||
setDurationText(duration);
|
||||
|
||||
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("AVM.AllowIncompleteTopic")) != QVariant(true))
|
||||
{
|
||||
if (duration <= 0)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(
|
||||
this, tr("The total playback length is less than 1 second long. <br>"
|
||||
"Please verify that you have one or more sequences in the sequences list and that these sequences are of at least 1 second length."),
|
||||
tr("Playback length too short")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 secs = duration / 1000;
|
||||
qint64 msecs = duration - (secs * 1000);
|
||||
qWarning() << "secs" << secs << "msecs" << msecs;
|
||||
|
||||
|
||||
if (msecs >= 500)
|
||||
++secs;
|
||||
qWarning() << "secs now" << secs;
|
||||
m_topicData.duration = secs;
|
||||
}
|
||||
else
|
||||
m_topicData.duration = 10;
|
||||
|
||||
setTopicDataProperty(QStringLiteral("Sequences"), m_model->getSequencesAsJsonArray());
|
||||
setTopicDataProperty(QStringLiteral("ScriptName"), QString(QStringLiteral("S") + QString::number(m_topicData.id)));
|
||||
setTopicDataProperty(QStringLiteral("IsAudio"), bool(m_topicData.topicType == TopicEditorBase::TopicType::Audio));
|
||||
setDescription(m_ui->widget->description());
|
||||
m_ui->widget->previewer()->setTopicData(m_topicData);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void TopicEditor::onEditSequence()
|
||||
{
|
||||
if (!m_playbackMenu)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "slotEditSequence ";
|
||||
const auto selRows = m_ui->tvSequences->selectionModel()->selectedRows();
|
||||
|
||||
if (selRows.size() != 1)
|
||||
{
|
||||
m_model->setHighlightedRow(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
int row = selRows.at(0).row();
|
||||
m_model->setHighlightedRow(row);
|
||||
const AvsSequence selectedSeq = m_model->getRowData(row);
|
||||
|
||||
DEBUG_LOG(m_logger) << "selectedSeq.internalStreamName=" << selectedSeq.internalStreamName;
|
||||
m_playbackMenu->setStreamName(selectedSeq.internalStreamName);
|
||||
|
||||
m_ui->dtStart->setMsecsSinceEpoch(std::chrono::milliseconds(selectedSeq.start.time_since_epoch()).count());
|
||||
m_ui->dtEnd->setMsecsSinceEpoch(std::chrono::milliseconds((selectedSeq.start + selectedSeq.duration).time_since_epoch()).count());
|
||||
|
||||
m_ui->leDescription->setText(selectedSeq.description);
|
||||
m_playbackMenu->setStreamByName(selectedSeq.internalStreamName);
|
||||
m_playbackMenu->setSpeed(selectedSeq.speed);
|
||||
m_playbackMenu->setVolume(selectedSeq.volume);
|
||||
m_playbackMenu->setSkipPause(selectedSeq.pint);
|
||||
m_playbackMenu->setSavedPos(m_ui->dtStart->msecsSinceEpoch());
|
||||
|
||||
m_ui->pbApply->setEnabled(true);
|
||||
}
|
||||
|
||||
void TopicEditor::onTimeChanged()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TopicEditor::onApplySequence()
|
||||
{
|
||||
const auto seq = createCurrentSequence();
|
||||
if (seq.start.time_since_epoch().count() == 0 || seq.duration.count() == 0)
|
||||
return;
|
||||
|
||||
const auto rows = m_model->highlightedRows();
|
||||
|
||||
if (rows.count() != 1)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("Please select a sequence from the sequence list first, then click 'Edit' to edit a sequence in the editor."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->setRowData(rows.first(), seq);
|
||||
|
||||
refreshDurationText();
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void TopicEditor::onAddSequence()
|
||||
{
|
||||
qint64 start = m_ui->dtStart->msecsSinceEpoch();
|
||||
qint64 end = m_ui->dtEnd->msecsSinceEpoch();
|
||||
|
||||
if (start == 0 || end == 0 || end < start)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("Please check if start and end times are set and the end time is not lower than the start time."),
|
||||
tr("The start and/or end time you entered is invalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
AvsSequence seq = createCurrentSequence();
|
||||
|
||||
if (seq.pint)
|
||||
{
|
||||
|
||||
|
||||
AvaTimePoint theStart = msecsToAvaTimePoint(m_ui->dtStart->msecsSinceEpoch());
|
||||
AvaTimePoint theEnd = msecsToAvaTimePoint(m_ui->dtEnd->msecsSinceEpoch());
|
||||
|
||||
QueryTimeline *qt = m_playbackMenu->queryTimeline(theStart, theEnd);
|
||||
|
||||
if (qt == nullptr)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("Currently unable to request sequences from the audio / video system.<br />Please try again later."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setOverlay(new QWidget());
|
||||
|
||||
|
||||
connect(qt, &QueryTimeline::signalTimelineComplete,
|
||||
this, [this, theStart, theEnd](const AvaTimeline &timeline)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
|
||||
auto unchangableReset = qScopeGuard([this] { unsetOverlay(); });
|
||||
#else
|
||||
std::shared_ptr<int> unchangeableReset(nullptr, [this](int *) { unsetOverlay(); });
|
||||
#endif
|
||||
|
||||
static const QString msgTitle(tr("Sequences needed to be determined for audio / video clips with skipped silence"));
|
||||
const QVector<AvaTimelinePart> &parts = timeline.parts();
|
||||
|
||||
if (parts.isEmpty())
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("No sequences could be found inside the specified range. <br />Please select another range that contains audio / video."),
|
||||
msgTitle);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList partsStrings;
|
||||
|
||||
for (const AvaTimelinePart &part : parts)
|
||||
{
|
||||
AvaTimePoint start = part.first;
|
||||
AvaTimePoint end = part.second;
|
||||
|
||||
if (theStart > start)
|
||||
start = theStart;
|
||||
if (theEnd < end)
|
||||
end = theEnd;
|
||||
|
||||
qint64 duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
qint64 secs = duration / 1000;
|
||||
qint64 msecs = (duration % 1000);
|
||||
QString durationString(QStringLiteral("%1.%2").arg(secs).arg(msecs, 3, 10, QLatin1Char('0')));
|
||||
|
||||
partsStrings += QStringLiteral("<span>%1 - %2 (%3 %4)</span>").arg(msecsSinceEpochToStringz(std::chrono::milliseconds(start.time_since_epoch()).count()),
|
||||
msecsSinceEpochToStringz(std::chrono::milliseconds(end.time_since_epoch()).count()),
|
||||
durationString,
|
||||
tr("seconds"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef AskUserSequenceList
|
||||
auto msg = new LtsWidgets::LtsMessageDialogNew(this, tr("The following sequences were determined: <br /> <br /> %1 <br /> <br />Do you want to add the listed sequences to the sequences list?").arg(partsStrings.join(QStringLiteral("<br />"))),
|
||||
msgTitle, LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Yes | LtsWidgets::Button::Cancel, { { LtsWidgets::Button::Yes, tr("Add") } });
|
||||
|
||||
connect(msg, &LtsWidgets::LtsMessageDialogNew::yes,
|
||||
this, [this, parts, theStart, theEnd]()
|
||||
#endif
|
||||
{
|
||||
m_model->setHighlightedRow(-1);
|
||||
|
||||
for (const AvaTimelinePart &part : parts)
|
||||
{
|
||||
AvaTimePoint start = part.first;
|
||||
AvaTimePoint end = part.second;
|
||||
|
||||
if (theStart > start)
|
||||
start = theStart;
|
||||
if (theEnd < end)
|
||||
end = theEnd;
|
||||
|
||||
m_model->insertRow(createSequence(start, end));
|
||||
int row = m_model->rowCount() - 1;
|
||||
QModelIndex idx = m_model->index(row, 0);
|
||||
|
||||
if (!idx.isValid())
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("One or more sequences could not be added to the sequences list. <br />Please try again later."),
|
||||
msgTitle);
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->setHighlightedRow(row, false );
|
||||
m_ui->tvSequences->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
refreshDurationText();
|
||||
m_ui->pbApply->setEnabled(true);
|
||||
slotChangesMade();
|
||||
}
|
||||
#ifdef AskUserSequenceList
|
||||
);
|
||||
#endif
|
||||
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (seq.start.time_since_epoch().count() == 0 || seq.duration.count() == 0)
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("Start and end times are not valid. Please check if your input values are valid."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->insertRow(seq);
|
||||
|
||||
int row = m_model->rowCount() - 1;
|
||||
QModelIndex idx = m_model->index(row, 0);
|
||||
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
m_model->setHighlightedRow(row);
|
||||
m_ui->tvSequences->setCurrentIndex(idx);
|
||||
|
||||
refreshDurationText();
|
||||
m_ui->pbApply->setEnabled(true);
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void TopicEditor::onDeleteSequences()
|
||||
{
|
||||
const auto selRows = m_ui->tvSequences->selectionModel()->selectedRows();
|
||||
QVector<int> rowIds;
|
||||
rowIds.reserve(selRows.size());
|
||||
for (const QModelIndex &idx : selRows)
|
||||
rowIds += idx.row();
|
||||
std::sort(rowIds.begin(), rowIds.end(), std::greater<int>());
|
||||
|
||||
const auto rows = m_model->highlightedRows();
|
||||
int curEditedRow = -1;
|
||||
|
||||
if (rows.count() == 1)
|
||||
curEditedRow = rows.first();
|
||||
|
||||
for (int row : qAsConst(rowIds))
|
||||
{
|
||||
m_model->removeRow(row);
|
||||
if (curEditedRow == row)
|
||||
{
|
||||
curEditedRow = -1;
|
||||
m_model->setHighlightedRow(curEditedRow);
|
||||
m_ui->pbApply->setEnabled(false);
|
||||
onEnaDisa();
|
||||
}
|
||||
if (curEditedRow > row)
|
||||
--curEditedRow;
|
||||
}
|
||||
m_model->setHighlightedRow(curEditedRow);
|
||||
refreshDurationText();
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void TopicEditor::onSequenceUp()
|
||||
{
|
||||
m_model->moveUp(m_ui->tvSequences->currentIndex());
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void TopicEditor::onSequenceDown()
|
||||
{
|
||||
m_model->moveDown(m_ui->tvSequences->currentIndex());
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
void TopicEditor::onSetTopicButtonStates(bool enable)
|
||||
{
|
||||
if (enable && m_topicStartTime)
|
||||
m_ui->dtStart->setMsecsSinceEpoch(m_topicStartTime);
|
||||
}
|
||||
|
||||
void TopicEditor::onEnaDisa()
|
||||
{
|
||||
|
||||
const auto selRows = m_ui->tvSequences->selectionModel()->selectedRows();
|
||||
const bool hasSelection = (selRows.size() != 0);
|
||||
const bool hasSingleSelection = (selRows.size() == 1);
|
||||
|
||||
m_ui->pbEditSequence->setEnabled(hasSingleSelection);
|
||||
m_ui->pbDelete->setEnabled(hasSelection);
|
||||
m_ui->pbDown->setEnabled(hasSingleSelection);
|
||||
m_ui->pbUp->setEnabled(hasSingleSelection);
|
||||
}
|
||||
|
||||
void TopicEditor::onMarkerSelected(const QString &description)
|
||||
{
|
||||
m_ui->leDescription->setText(description);
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "avm_sequence_model.h"
|
||||
#include "../avm_playback_menu.h"
|
||||
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <TopicEditorBase/topic_editor_base.h>
|
||||
|
||||
|
||||
namespace Ui { class AVTopicEditor; }
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class TopicEditor : public TopicEditorBase::TopicEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TopicEditor(LtsSession::LtsSession *session, const TopicEditorBase::TopicData &data, QWidget *parent = nullptr);
|
||||
~TopicEditor();
|
||||
|
||||
private:
|
||||
void updateInternalData() override final;
|
||||
void retranslate() override final;
|
||||
|
||||
AvsSequence createSequence(const AvaTimePoint &start, const AvaTimePoint &end) const;
|
||||
AvsSequence createCurrentSequence() const;
|
||||
void refreshDurationText();
|
||||
void setDurationText(qint64 length);
|
||||
qint64 calcTrackLength(const QJsonArray &arr) const;
|
||||
void playbackDlgNotAvailable(const QString &msg);
|
||||
|
||||
private slots:
|
||||
bool apply2() override final;
|
||||
|
||||
void onEditSequence();
|
||||
void onTimeChanged();
|
||||
void onApplySequence();
|
||||
void onAddSequence();
|
||||
void onDeleteSequences();
|
||||
void onSequenceUp();
|
||||
void onSequenceDown();
|
||||
void onSetTopicButtonStates(bool enable);
|
||||
void onEnaDisa();
|
||||
void onMarkerSelected(const QString &description);
|
||||
|
||||
private:
|
||||
const int s_durationLimit{86400000};
|
||||
|
||||
LtsSession::LtsSession *m_session{nullptr};
|
||||
std::shared_ptr<AudioVideoManagement::DataInterface> m_avmDataIfc{nullptr};
|
||||
|
||||
AvmSequenceModel *m_model{nullptr};
|
||||
AvmSequenceProxyModel *m_proxyModel{nullptr};
|
||||
AvmPlaybackMenu *m_playbackMenu{nullptr};
|
||||
|
||||
bool m_isAudio{false};
|
||||
qint64 m_topicStartTime{0};
|
||||
QString m_topicStreamName;
|
||||
|
||||
Ui::AVTopicEditor *m_ui{nullptr};
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+457
@@ -0,0 +1,457 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AVTopicEditor</class>
|
||||
<widget class="QWidget" name="AVTopicEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1150</width>
|
||||
<height>577</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Script Editor</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="1" rowspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbxSequences">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sequences:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbxTopicDuration">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Topic duration:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblDuration">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="3">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QToolButton" name="pbDown">
|
||||
<property name="toolTip">
|
||||
<string>Sequence Down</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/sort-down.svg</normaloff>:/style/sort-down.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="pbUp">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/sort-up.svg</normaloff>:/style/sort-up.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QPushButton" name="pbDelete">
|
||||
<property name="toolTip">
|
||||
<string>Delete selected sequence from list</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete sequence</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/delete.svg</normaloff>:/style/delete.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QPushButton" name="pbEditSequence">
|
||||
<property name="toolTip">
|
||||
<string>Edit selected sequence from list in the right side of the layout</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit sequence</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/document-edit.svg</normaloff>:/style/document-edit.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="4" colspan="3">
|
||||
<widget class="QTableView" name="tvSequences">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="TopicEditorBase::TopicPreviewWidget" name="widget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Edit / Create sequence</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0,0">
|
||||
<item>
|
||||
<widget class="QWidget" name="playbackParent" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbxStrean">
|
||||
<property name="text">
|
||||
<string>Stream:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="lbxEndTime">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>End Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="8">
|
||||
<widget class="QPushButton" name="pbPreview">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set as current time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="lbxDescription">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbxStartTime">
|
||||
<property name="toolTip">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6">
|
||||
<widget class="LtsWidgets::LtsMSecDateTimeEdit" name="dtEnd"/>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLabel" name="lblStream">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="7">
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="5" colspan="4">
|
||||
<widget class="QLineEdit" name="leDescription"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="LtsWidgets::LtsMSecDateTimeEdit" name="dtStart"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbApply">
|
||||
<property name="text">
|
||||
<string>Apply changes to sequence in list</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/dialog-ok-apply.svg</normaloff>:/style/dialog-ok-apply.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAdd">
|
||||
<property name="text">
|
||||
<string>Append as new sequence to list</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/document-new.svg</normaloff>:/style/document-new.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>TopicEditorBase::TopicPreviewWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>TopicEditorBase/topic_preview_widget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsMSecDateTimeEdit</class>
|
||||
<extends>QDateTimeEdit</extends>
|
||||
<header>LtsWidgets/lts_msec_date_time_edit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tvSequences</tabstop>
|
||||
<tabstop>pbUp</tabstop>
|
||||
<tabstop>pbDown</tabstop>
|
||||
<tabstop>pbDelete</tabstop>
|
||||
<tabstop>pbEditSequence</tabstop>
|
||||
<tabstop>leDescription</tabstop>
|
||||
<tabstop>pbPreview</tabstop>
|
||||
<tabstop>pbApply</tabstop>
|
||||
<tabstop>pbAdd</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_available_streams_model.h"
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <InfrastructureManagement/ism.hpp>
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
|
||||
#include <QSet>
|
||||
#include <QMimeData>
|
||||
#include <QCollator>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isMountingPointOfInterest(const InfrastructureManagement::StructureElement &se, bool isAudio)
|
||||
{
|
||||
if (se.structureElementTypeId() != InfrastructureManagement::StructureElementType::MountingPoint)
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
if (se.mountingPointTypeId() == InfrastructureManagement::MountingPointType::IndoorCamera ||
|
||||
se.mountingPointTypeId() == InfrastructureManagement::MountingPointType::OutdoorCamera)
|
||||
return true;
|
||||
|
||||
if (isAudio && se.mountingPointTypeId() == InfrastructureManagement::MountingPointType::AnnouncementUnit)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
const QString AvailableStreamsModel::s_MimeType = QStringLiteral("AvailStreamsModel/DragDrop");
|
||||
|
||||
|
||||
|
||||
struct sorter
|
||||
{
|
||||
bool operator()(const StreamModelData &i, const StreamModelData &j)
|
||||
{
|
||||
QCollator col;
|
||||
col.setNumericMode(true);
|
||||
return col.compare(j.name, i.name) > 0 ;
|
||||
}
|
||||
} sortStuff;
|
||||
|
||||
|
||||
AvailableStreamsModel::AvailableStreamsModel(const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
LtsSession::LtsSession *session,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
QObject *parent,
|
||||
bool isAudio)
|
||||
: NGLTreeModel(parent, new NGLTreeItem(QVariant(), QIcon()), {tr("Available Streams")})
|
||||
, m_isAudio(isAudio)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_ismDtc(ismDtc)
|
||||
, m_session(session)
|
||||
, m_streamNameMapping(streamNameMapping)
|
||||
, m_logger(getLogger("AvailableStreamsModel"))
|
||||
{
|
||||
Q_ASSERT(ismDtc);
|
||||
Q_ASSERT(streamNameMapping);
|
||||
qRegisterMetaTypeStreamOperators<StreamModelData>("StreamModelData");
|
||||
qRegisterMetaType<StreamModelData>("StreamModelData");
|
||||
|
||||
setMimeType(s_MimeType);
|
||||
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
|
||||
this, [ this]()
|
||||
{
|
||||
initModel();
|
||||
});
|
||||
|
||||
connect(m_streamNameMapping, &StreamNameMapping::changed,
|
||||
this, [ this]()
|
||||
{
|
||||
initModel();
|
||||
});
|
||||
|
||||
if (!m_isAudio)
|
||||
{
|
||||
connect(m_avmDtc.get(), &AudioVideoManagement::Interface::Dtc::videoTeamChanged,
|
||||
this, [ this]()
|
||||
{
|
||||
initModel();
|
||||
});
|
||||
}
|
||||
initModel();
|
||||
}
|
||||
|
||||
QVariant AvailableStreamsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
NGLTreeItem *item = privateData(index);
|
||||
if (!item->data().canConvert<StreamModelData>())
|
||||
return QVariant();
|
||||
|
||||
const StreamModelData availStream = item->data().value<StreamModelData>();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case 0 :
|
||||
return availStream.name;
|
||||
default:
|
||||
return QStringLiteral("??");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
static const QIcon folder(QStringLiteral("icon:evaluation_folder.svg"));
|
||||
static const QIcon camera(QStringLiteral("icon:camera_control.svg"));
|
||||
return availStream.isGroup ? folder : camera;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NGLTreeModel::data(index, role);
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags AvailableStreamsModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = NGLTreeModel::flags(index);
|
||||
NGLTreeItem *item = privateData(index);
|
||||
|
||||
if (item == m_rootItem)
|
||||
return defaultFlags;
|
||||
|
||||
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
||||
}
|
||||
|
||||
|
||||
QMimeData *AvailableStreamsModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
|
||||
QMimeData *pData = NGLTreeModel::mimeData(indexes);
|
||||
pData->setText(data(indexes[0]).toString());
|
||||
return pData;
|
||||
}
|
||||
|
||||
|
||||
bool AvailableStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
INFO_LOG(m_logger) << "dropMimeData: action = " << action
|
||||
<< ", row = " << row
|
||||
<< ", parent: valid = " << parent.isValid();
|
||||
|
||||
if (action == Qt::IgnoreAction)
|
||||
return true;
|
||||
|
||||
if (!data->hasFormat(s_MimeType))
|
||||
return false;
|
||||
|
||||
if ((action != Qt::MoveAction) && (action != Qt::CopyAction))
|
||||
return false;
|
||||
|
||||
return NGLTreeModel::dropMimeData(data, action, row, column, parent);
|
||||
}
|
||||
|
||||
|
||||
void AvailableStreamsModel::initModel()
|
||||
{
|
||||
beginResetModel();
|
||||
INFO_LOG(m_logger) << "initModel";
|
||||
|
||||
|
||||
m_rootItem->removeAllChildren();
|
||||
|
||||
StreamModelData availStream;
|
||||
availStream.id = 0;
|
||||
availStream.name = tr("New group");
|
||||
availStream.parentId = -1;
|
||||
availStream.isGroup = true;
|
||||
|
||||
QVariant data;
|
||||
data.setValue(availStream);
|
||||
m_rootItem->appendChild(new NGLTreeItem(data, QIcon()));
|
||||
|
||||
std::vector<StreamModelData> toAddIndoor;
|
||||
std::vector<StreamModelData> toAddOutdoor;
|
||||
|
||||
std::vector<StreamModelData> toAddMvs;
|
||||
|
||||
|
||||
const auto &mountedAssets = m_ismDtc->mountingPointAssets();
|
||||
const auto &buildings = m_ismDtc->mainStructureElements();
|
||||
for (const auto &building : buildings)
|
||||
{
|
||||
for (const auto &mountingPoint : building.elements())
|
||||
{
|
||||
if (!isMountingPointOfInterest(mountingPoint, m_isAudio))
|
||||
continue;
|
||||
|
||||
|
||||
bool isMounted = false;
|
||||
for (const auto &mountedAsset : mountedAssets)
|
||||
{
|
||||
if (mountedAsset.structureElementId() == mountingPoint.id())
|
||||
{
|
||||
isMounted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMounted)
|
||||
continue;
|
||||
StreamModelData item;
|
||||
item.name = m_streamNameMapping->displayName(mountingPoint.id());
|
||||
item.mountingPointId = mountingPoint.id();
|
||||
item.isGroup = false;
|
||||
|
||||
|
||||
if (mountingPoint.mountingPointTypeId() == InfrastructureManagement::MountingPointType::IndoorCamera)
|
||||
toAddIndoor.push_back(item);
|
||||
else
|
||||
toAddOutdoor.push_back(item);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!m_isAudio)
|
||||
{
|
||||
const auto &mvsStreams = m_avmDtc->videoTeams();
|
||||
for (const auto &videoTeam : mvsStreams)
|
||||
{
|
||||
if (videoTeam.exerciseId() != m_session->exerciseId())
|
||||
continue;
|
||||
DEBUG_LOG(m_logger) << "add new videoteam" << videoTeam;
|
||||
StreamModelData item;
|
||||
item.name = QString::fromStdString(videoTeam.streamName().c_str());
|
||||
item.mountingPointId = -1 * videoTeam.id();
|
||||
item.isGroup = false;
|
||||
|
||||
|
||||
toAddMvs.push_back(item);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::sort(toAddOutdoor.begin(), toAddOutdoor.end(), sortStuff);
|
||||
for (const auto &item : toAddOutdoor)
|
||||
{
|
||||
data.setValue(item);
|
||||
m_rootItem->appendChild(new NGLTreeItem(data, QIcon()));
|
||||
}
|
||||
|
||||
std::sort(toAddIndoor.begin(), toAddIndoor.end(), sortStuff);
|
||||
for (const auto &item : toAddIndoor)
|
||||
{
|
||||
data.setValue(item);
|
||||
m_rootItem->appendChild(new NGLTreeItem(data, QIcon()));
|
||||
}
|
||||
|
||||
std::sort(toAddMvs.begin(), toAddMvs.end(), sortStuff);
|
||||
for (const auto &item : toAddMvs)
|
||||
{
|
||||
data.setValue(item);
|
||||
m_rootItem->appendChild(new NGLTreeItem(data, QIcon()));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
StreamModelData StreamModelData::createFromServiceItem(const AvMenuEntry &entry, StreamNameMapping *streamNameMapping, const QMap<int, VideoTeam> &videoTeamList)
|
||||
{
|
||||
StreamModelData data;
|
||||
data.id = entry.id();
|
||||
data.parentId = entry.parentId();
|
||||
data.isGroup = entry.isGroup();
|
||||
if (entry.isGroup())
|
||||
data.name = QString::fromStdString(entry.name().get());
|
||||
else
|
||||
{
|
||||
if (entry.mountingPointId().is_set() && (entry.mountingPointId().get() > 0))
|
||||
{
|
||||
data.mountingPointId = entry.mountingPointId().get();
|
||||
data.name = streamNameMapping->displayName(entry.mountingPointId().get());
|
||||
}
|
||||
else
|
||||
{
|
||||
data.mountingPointId = entry.mountingPointId().get();
|
||||
data.name = QString::fromStdString(videoTeamList.value(entry.mountingPointId().get() * -1).streamName());
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <nglwidgets/ngltreemodel.h>
|
||||
#include <QDataStream>
|
||||
|
||||
class NGLTreeItem;
|
||||
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class StreamNameMapping;
|
||||
|
||||
|
||||
|
||||
struct StreamModelData
|
||||
{
|
||||
qint64 id = 0;
|
||||
qint64 parentId = 0;
|
||||
bool isGroup = false;
|
||||
QString name;
|
||||
qint32 mountingPointId = 0;
|
||||
|
||||
static StreamModelData createFromServiceItem(const AvMenuEntry &entry, StreamNameMapping *streamNameMapping, const QMap<int, VideoTeam> &videoTeamList);
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out,
|
||||
const StreamModelData &myObj)
|
||||
{
|
||||
out << myObj.id
|
||||
<< myObj.parentId
|
||||
<< myObj.isGroup
|
||||
<< myObj.name
|
||||
<< myObj.mountingPointId;
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in,
|
||||
StreamModelData &myObj)
|
||||
{
|
||||
in >> myObj.id
|
||||
>> myObj.parentId
|
||||
>> myObj.isGroup
|
||||
>> myObj.name
|
||||
>> myObj.mountingPointId;
|
||||
|
||||
return in;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class AvailableStreamsModel : public NGLTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const QString s_MimeType;
|
||||
|
||||
AvailableStreamsModel(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
LtsSession::LtsSession *session,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
QObject *parent,
|
||||
bool isAudio);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) override;
|
||||
|
||||
Qt::DropActions supportedDragActions() const override { return Qt::CopyAction; }
|
||||
|
||||
private:
|
||||
void initModel();
|
||||
|
||||
const bool m_isAudio;
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_avmDtc;
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
LtsSession::LtsSession *m_session;
|
||||
StreamNameMapping *m_streamNameMapping;
|
||||
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
}
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::StreamModelData)
|
||||
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_choose_menu.h"
|
||||
#include "ui_avm_choose_menu.h"
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <AudioVideoManagement/avs_menus.h>
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
ChooseMenu::ChooseMenu(Interface::Dtc *dtc, AvsMenus *avsMenus, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_dtc(dtc)
|
||||
, m_avsMenus(avsMenus)
|
||||
, m_ui(new Ui::ChooseMenuStruct)
|
||||
, m_logger(getLogger("ChooseMenu"))
|
||||
{
|
||||
Q_ASSERT(dtc);
|
||||
Q_ASSERT(avsMenus);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(dtc, &Interface::Dtc::menuStructChanged, this, &ChooseMenu::onMenuStructChanged);
|
||||
m_dtc->menuStructs([this](const MenuStruct & menu) { onMenuStructChanged(menu, DataModification::eAdded);});
|
||||
selectCurrent();
|
||||
|
||||
connect(m_ui->cbAudio, &QComboBox::currentTextChanged, this, &ChooseMenu::slotChangesMade);
|
||||
connect(m_ui->cbVideo, &QComboBox::currentTextChanged, this, &ChooseMenu::slotChangesMade);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Choose_AV_Menu"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
ChooseMenu::~ChooseMenu()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void ChooseMenu::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Choose AV Menu"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ChooseMenu::onMenuStructChanged(const MenuStruct &data, DataModification modType)
|
||||
{
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eAdded:
|
||||
{
|
||||
if (data.isAudio())
|
||||
m_ui->cbAudio->addItem(QString::fromStdString(data.name()), data.id());
|
||||
else
|
||||
m_ui->cbVideo->addItem(QString::fromStdString(data.name()), data.id());
|
||||
break;
|
||||
}
|
||||
|
||||
case DataModification::eRemoved:
|
||||
{
|
||||
if (data.isAudio())
|
||||
{
|
||||
int index = m_ui->cbAudio->findData(data.id());
|
||||
m_ui->cbAudio->removeItem(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = m_ui->cbVideo->findData(data.id());
|
||||
m_ui->cbVideo->removeItem(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataModification::eModified:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ChooseMenu::apply()
|
||||
{
|
||||
int menuId = m_ui->cbAudio->currentData().toInt();
|
||||
INFO_LOG(m_logger) << "MenuId Audio: " << menuId;
|
||||
m_avsMenus->setAnnouncementMenu(menuId);
|
||||
|
||||
menuId = m_ui->cbVideo->currentData().toInt();
|
||||
INFO_LOG(m_logger) << "MenuId Video: " << menuId;
|
||||
m_avsMenus->setVideoMenu(menuId);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void ChooseMenu::selectCurrent()
|
||||
{
|
||||
selectMenu(m_avsMenus->currentAnnouncementMenu(), m_ui->cbAudio);
|
||||
selectMenu(m_avsMenus->currentVideoMenu(), m_ui->cbVideo);
|
||||
}
|
||||
|
||||
void ChooseMenu::selectMenu(int menuId, QComboBox *cb)
|
||||
{
|
||||
Q_ASSERT(cb);
|
||||
|
||||
if (menuId < 0)
|
||||
return;
|
||||
|
||||
int index = cb->findData(menuId);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
cb->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
enum class DataModification;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ChooseMenuStruct;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class MenuStruct;
|
||||
class AvsMenus;
|
||||
|
||||
class ChooseMenu : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChooseMenu(Interface::Dtc *dtc, AvsMenus *avsMenus, QWidget *parent = nullptr);
|
||||
~ChooseMenu() override;
|
||||
|
||||
private slots:
|
||||
void onMenuStructChanged(const MenuStruct &data, DataModification modType);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
bool apply() override final;
|
||||
void selectCurrent();
|
||||
void selectMenu(int menuId, QComboBox *cb);
|
||||
|
||||
Interface::Dtc *m_dtc;
|
||||
AvsMenus *m_avsMenus;
|
||||
Ui::ChooseMenuStruct *m_ui;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ChooseMenuStruct</class>
|
||||
<widget class="QWidget" name="ChooseMenuStruct">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>596</width>
|
||||
<height>102</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Choose Menu</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Choose Audio Menu:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbAudio"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbVideo"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Choose Video Menu:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_menu_edit.h"
|
||||
#include "ui_avm_menu_edit.h"
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
MenuEdit::MenuEdit(QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_ftc(nullptr)
|
||||
, m_ui(new Ui::MenuEdit)
|
||||
, m_availStreamsModel(nullptr)
|
||||
, m_usedStreamsModel(nullptr)
|
||||
, m_isAudio(false)
|
||||
, m_logger(getLogger("AudioVideoManagementEdit"))
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
}
|
||||
|
||||
|
||||
MenuEdit::~MenuEdit()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MenuEdit::retranslate()
|
||||
{
|
||||
if (m_isAudio)
|
||||
translate(m_ui, tr("Edit Audio Menu: %1").arg(m_name));
|
||||
else
|
||||
translate(m_ui, tr("Edit Video Menu: %1").arg(m_name));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool MenuEdit::init(LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
const MenuStruct &ms)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "MenuEdit::init()";
|
||||
|
||||
if (!ftc || !dtc)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "MenuEdit::init() Invalid shared_ptr!";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ftc = ftc;
|
||||
m_isAudio = ms.isAudio();
|
||||
m_name = QString::fromStdString(ms.name());
|
||||
|
||||
m_availStreamsModel = new AvailableStreamsModel(dtc, ismDtc, session, streamNameMapping, this, m_isAudio);
|
||||
m_ui->availTreeView->setModel(m_availStreamsModel);
|
||||
|
||||
m_usedStreamsModel = new UsedStreamsModel(dtc, ismDtc, ms, streamNameMapping, this);
|
||||
m_ui->menuTreeView->setModel(m_usedStreamsModel);
|
||||
m_ui->menuTreeView->expandAll();
|
||||
|
||||
connect(m_ui->menuTreeView, &QTreeView::clicked,
|
||||
this, &MenuEdit::onStreamSelected);
|
||||
connect(m_usedStreamsModel, &UsedStreamsModel::modelDataChanged,
|
||||
this, &MenuEdit::slotChangesMade);
|
||||
|
||||
connect(m_usedStreamsModel, &UsedStreamsModel::modelDataChanged,
|
||||
this, &MenuEdit::onModelDataChanged);
|
||||
|
||||
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Remove);
|
||||
connect(m_buttonBox->getButton(LtsWidgets::DialogButton::Remove), &QPushButton::clicked,
|
||||
this, &MenuEdit::onRemove);
|
||||
|
||||
onStreamSelected(QModelIndex());
|
||||
|
||||
|
||||
if (m_isAudio)
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Audio_Menu"));
|
||||
else
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Video_Menu"));
|
||||
|
||||
if (ms.id() <= 0)
|
||||
m_buttonBox->setButtonVisible(LtsWidgets::DialogButton::Apply, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MenuEdit::apply()
|
||||
{
|
||||
MenuStruct ms = m_usedStreamsModel->getMenuStruct();
|
||||
ms.isAudio(m_isAudio);
|
||||
|
||||
bool ret = m_requestHelper->startSingleRequest([this, ms]()
|
||||
{
|
||||
|
||||
return m_ftc->modifyMenuStructRequest(ms, this);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void MenuEdit::onRemove()
|
||||
{
|
||||
|
||||
|
||||
if (0 == m_ui->menuTreeView->selectionModel()->selectedIndexes().size())
|
||||
{
|
||||
|
||||
QModelIndex index = m_ui->menuTreeView->currentIndex();
|
||||
if (!index.isValid())
|
||||
return;
|
||||
slotChangesMade();
|
||||
|
||||
DEBUG_LOG(m_logger) << "index row: " << index.row();
|
||||
m_usedStreamsModel->removeRow(index.row(), index.parent());
|
||||
}
|
||||
else
|
||||
{
|
||||
while (m_ui->menuTreeView->selectionModel()->selectedIndexes().size() > 0)
|
||||
{
|
||||
QModelIndex index = m_ui->menuTreeView->selectionModel()->selectedIndexes().front();
|
||||
if (!index.isValid())
|
||||
return;
|
||||
slotChangesMade();
|
||||
|
||||
DEBUG_LOG(m_logger) << "index row: " << index.row();
|
||||
m_usedStreamsModel->removeRow(index.row(), index.parent());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuEdit::onModelDataChanged()
|
||||
{
|
||||
INFO_LOG(m_logger) << "onModelDataChanged";
|
||||
m_ui->menuTreeView->expandAll();
|
||||
}
|
||||
|
||||
void MenuEdit::onStreamSelected(const QModelIndex &idx)
|
||||
{
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, idx.isValid());
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "avm_available_streams_model.h"
|
||||
#include "avm_used_streams_model.h"
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <Services/AudioVideoManagement/avm_ftc.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MenuEdit;
|
||||
}
|
||||
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class StreamNameMapping;
|
||||
|
||||
class MenuEdit : public LtsWidgets::LtsDialog,
|
||||
protected AudioVideoManagement::Interface::Ftc::ModifyMenuStructReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MenuEdit(QWidget *parent = nullptr);
|
||||
|
||||
~MenuEdit();
|
||||
|
||||
bool init(LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
const MenuStruct &ms);
|
||||
|
||||
|
||||
void onModifyMenuStructReply(const Core::FunctionReplyObject &replyObject) override { m_requestHelper->requestReply(replyObject); }
|
||||
|
||||
public slots:
|
||||
void onRemove();
|
||||
void onModelDataChanged();
|
||||
void onStreamSelected(const QModelIndex &idx);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
bool apply() override final;
|
||||
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Ftc> m_ftc;
|
||||
Ui::MenuEdit *m_ui;
|
||||
AvailableStreamsModel *m_availStreamsModel;
|
||||
UsedStreamsModel *m_usedStreamsModel;
|
||||
bool m_isAudio;
|
||||
QString m_name;
|
||||
NGL::INGLLogger &m_logger;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
|
||||
AudioVideoManagement::MenuStruct m_lastDdsMenuStruct;
|
||||
AudioVideoManagement::MenuStruct m_modifiedMenuStruct;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MenuEdit</class>
|
||||
<widget class="QWidget" name="MenuEdit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>403</width>
|
||||
<height>256</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Menu Edit</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="availTreeView">
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragOnly</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="menuTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="defaultDropAction">
|
||||
<enum>Qt::CopyAction</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_menu_edit_view.h"
|
||||
#include "avm_menu_edit_gui_plugin.h"
|
||||
#include "avm_menu_edit.h"
|
||||
#include "avm_choose_menu.h"
|
||||
#include "avm_playback_menu_dialog.h"
|
||||
#include "topic_replay.h"
|
||||
#include "TopicEditor/topic_editor.h"
|
||||
#include "AudioSettings/audio_settings_dialog.h"
|
||||
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <LtsScriptTimeline/track_entry.h>
|
||||
#include <AudioVideoManagement/Shared/stream_list_result.h>
|
||||
#include <LtsUtilsSettings/settings.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <Services/AudioVideoManagement/ava_session.h>
|
||||
#include <Services/AudioVideoManagement/ava_control.h>
|
||||
#include <Services/AudioVideoManagement/ava_types.h>
|
||||
#include <Services/AudioVideoManagement/avm_operator_rights.h>
|
||||
#include <Services/AudioVideoManagement/avs_dialog.h>
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
|
||||
{
|
||||
return std::make_shared<InterfaceImpl>(session);
|
||||
}
|
||||
|
||||
|
||||
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
|
||||
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Avm.MenuEdit"))
|
||||
{
|
||||
Q_ASSERT(session);
|
||||
Q_ASSERT(session->partitionType() == IDL::PartitionType::Exercise || session->partitionType() == IDL::PartitionType::Replay);
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::fetchInterfaces()
|
||||
{
|
||||
if (!m_session->getForeignDataInterface_NEW(m_avmDataIfc))
|
||||
return false;
|
||||
|
||||
|
||||
m_dtc = m_avmDataIfc->getDtc();
|
||||
m_ftc = m_avmDataIfc->getFtc();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::clearInterfaces()
|
||||
{
|
||||
|
||||
m_ftc = nullptr;
|
||||
m_dtc = nullptr;
|
||||
m_avmDataIfc = nullptr;
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::menuGroup() const
|
||||
{
|
||||
return tr("Audio / Video");
|
||||
}
|
||||
|
||||
|
||||
QString InterfaceImpl::playbackMenuGroup() const
|
||||
{
|
||||
return tr("Playbacks");
|
||||
}
|
||||
|
||||
|
||||
static inline QString s_avmPlaybackDialogIdentifierVideo() { return QStringLiteral("AvmPlaybackDialogVideo"); }
|
||||
static inline QString s_avmPlaybackDialogIdentifierAudio() { return QStringLiteral("AvmPlaybackDialogAudio"); }
|
||||
static inline QString s_avmVideoFullScreen() { return QStringLiteral("AvmVideoFullscreen"); }
|
||||
|
||||
|
||||
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
||||
{
|
||||
QVector<LtsWidgets::PluginData> actions;
|
||||
|
||||
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
|
||||
const bool enableAudioVideoManagement = ps->value(QStringLiteral("avm"),
|
||||
QStringLiteral("enableAudioVideoManagement")).toBool();
|
||||
const bool enableVideoImport = ps->value(QStringLiteral("avm"),
|
||||
QStringLiteral("enableVideoImport")).toBool();
|
||||
const bool enableAudioVideoPlaybacks = ps->value(QStringLiteral("avm"),
|
||||
QStringLiteral("enableAudioVideoPlaybacks")).toBool();
|
||||
|
||||
|
||||
if (m_session->isExercisePartition() && enableAudioVideoManagement)
|
||||
{
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
plData.menuText = tr("Video Menu");
|
||||
plData.identifier = QLatin1String("avmMenuVideoView");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:video_menu.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvMenuEdit;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowMenuEditVideoView(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
}
|
||||
|
||||
if (m_session->isExercisePartition() && enableAudioVideoManagement)
|
||||
{
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
plData.menuText = tr("Audio Menu");
|
||||
plData.identifier = QLatin1String("avmMenuAudioView");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:announcement_menu.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvMenuEdit;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowMenuEditAudioView(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
}
|
||||
|
||||
|
||||
if (m_session && m_session->app() == LtsAppDescriptor::App::Situation &&
|
||||
m_session->isExercisePartition() && enableAudioVideoManagement)
|
||||
{
|
||||
LtsWidgets::PluginData plData1;
|
||||
plData1.menuGroup = menuGroup();
|
||||
plData1.menuText = tr("Voice Communication Access");
|
||||
plData1.identifier = QLatin1String("_OpmShowAudioSettings");
|
||||
plData1.menuIcon = QIcon(QLatin1String("icon:voice_communication_access.svg"));
|
||||
plData1.exercisePart = LtsWidgets::ExercisePart::ePlanning;
|
||||
plData1.operatorRight = OperatorRights::AudioVideoManagement::AvVoiceCommunicationAccess;
|
||||
|
||||
plData1.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowAudioSettingsDialog(parent);
|
||||
};
|
||||
|
||||
|
||||
|
||||
actions.append(plData1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!m_avmDataIfc->hasAvsSession())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "No avs actions for this session, as it is missing an avs session";
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
||||
if (enableAudioVideoManagement)
|
||||
{
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
plData.menuText = tr("Choose AV Menu");
|
||||
plData.identifier = QLatin1String("avmChooseMenu");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:choose_audio_video_menu.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvMenuShow;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowChooseMenu(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
}
|
||||
|
||||
if (enableAudioVideoPlaybacks)
|
||||
{
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = playbackMenuGroup();
|
||||
plData.menuText = tr("Video Playback");
|
||||
plData.identifier = s_avmPlaybackDialogIdentifierVideo();
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:playback_video.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvPlayback;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowVideoPlayback(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
|
||||
plData.menuText = tr("Audio Playback");
|
||||
plData.identifier = s_avmPlaybackDialogIdentifierAudio();
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:playback_audio.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvPlayback;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowAudioPlayback(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
|
||||
|
||||
if (m_session->isExercisePartition())
|
||||
{
|
||||
plData.menuGroup = menuGroup();
|
||||
plData.menuText = tr("Video Fullscreen");
|
||||
plData.identifier = s_avmVideoFullScreen();
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:video_menu.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvPlayback;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
|
||||
plData.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowVideoFullscreen(parent);
|
||||
};
|
||||
actions.append(plData);
|
||||
|
||||
|
||||
#ifdef LTS_DEBUG
|
||||
LtsWidgets::PluginData plDataD;
|
||||
plDataD.menuGroup = QStringLiteral("[Dev]");
|
||||
plDataD.menuText = QStringLiteral("Video Fullscreen");
|
||||
plDataD.identifier = s_avmVideoFullScreen() + QStringLiteral("DEV");
|
||||
plDataD.createWidgetFunc = [this](QWidget * parent)
|
||||
{
|
||||
return onShowVideoFullscreen(parent);
|
||||
};
|
||||
actions.append(plDataD);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (m_session->isExercisePartition() && enableVideoImport)
|
||||
{
|
||||
LtsWidgets::PluginData plData;
|
||||
plData.menuGroup = menuGroup();
|
||||
plData.menuText = tr("Video Import");
|
||||
plData.identifier = QLatin1String("avmVideoImport");
|
||||
plData.menuIcon = QIcon(QLatin1String("icon:import_video.svg"));
|
||||
plData.operatorRight = OperatorRights::AudioVideoManagement::AvImportVideo;
|
||||
plData.exercisePart = LtsWidgets::ExercisePart::ePlanning;
|
||||
plData.createWidgetFunc = nullptr;
|
||||
plData.directFunc = [this](const LtsWidgets::PluginData &) { showImportDialog(); };
|
||||
actions.append(plData);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TopicEditorBase::TopicEditor *InterfaceImpl::createTopicEditor(const TopicEditorBase::TopicData &data)
|
||||
{
|
||||
return new TopicEditor(m_session, data);
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowMenuEditVideoView(QWidget *parent)
|
||||
{
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
|
||||
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc))
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("The Infrastructure Management is not available!"), tr("Cannot open Menu Edit"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MenuEditView *dialog = new MenuEditView(menuGroup(), m_session, parent);
|
||||
bool isAudio = false;
|
||||
dialog->init(m_dtc, m_ftc, ismDtc, m_avmDataIfc->streamNameMapping(), isAudio);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowMenuEditAudioView(QWidget *parent)
|
||||
{
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
|
||||
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc))
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("The Infrastructure Management is not available!"), tr("Cannot open Menu Edit"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MenuEditView *dialog = new MenuEditView(menuGroup(), m_session, parent);
|
||||
bool isAudio = true;
|
||||
dialog->init(m_dtc, m_ftc, ismDtc, m_avmDataIfc->streamNameMapping(), isAudio);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowChooseMenu(QWidget *parent)
|
||||
{
|
||||
return new ChooseMenu(m_dtc.get(), m_avmDataIfc->menus(), parent);
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::startAudioVideoPlayback(const QString &streamName, qint64 startTime_ms, bool isAudio)
|
||||
{
|
||||
auto dlg = createPlaybackDialog(isAudio, nullptr);
|
||||
|
||||
if (dlg == nullptr)
|
||||
return false;
|
||||
|
||||
const AvaTimePoint startTime(std::chrono::duration_cast<AvaDuration>(std::chrono::milliseconds(startTime_ms)));
|
||||
|
||||
const QString &menuGroupString(playbackMenuGroup());
|
||||
const QString &identifier(isAudio ? s_avmPlaybackDialogIdentifierAudio() : s_avmPlaybackDialogIdentifierVideo());
|
||||
|
||||
dlg->avmPlaybackMenu()->setPlaybackPreset(streamName, startTime, true);
|
||||
|
||||
if (m_session->widgetExists(menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab))
|
||||
{
|
||||
|
||||
return (m_session->focusTab(menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return m_session->addWidget(dlg, menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab);
|
||||
}
|
||||
|
||||
|
||||
bool InterfaceImpl::startMarkerAudioVideoPlayback(int markerId, bool isAudio)
|
||||
{
|
||||
auto dlg = createPlaybackDialog(isAudio, nullptr, false);
|
||||
|
||||
if (dlg == nullptr)
|
||||
return false;
|
||||
|
||||
const QString menuGroupString(playbackMenuGroup());
|
||||
const QString identifier(isAudio ? s_avmPlaybackDialogIdentifierAudio() : s_avmPlaybackDialogIdentifierVideo());
|
||||
|
||||
dlg->avmPlaybackMenu()->setMarkerPreset(markerId, true);
|
||||
|
||||
if (m_session->widgetExists(menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab))
|
||||
{
|
||||
|
||||
return (m_session->focusTab(menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return m_session->addWidget(dlg, menuGroupString, identifier, LtsWidgets::LayoutArea::eDialogTab);
|
||||
}
|
||||
|
||||
|
||||
StreamListResult *InterfaceImpl::getAsyncStreamList(AvaStreamType streamType, AvaStreamSource streamSource)
|
||||
{
|
||||
if (!m_avmDataIfc->hasAvsSession())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No AvsSession available";
|
||||
return nullptr;
|
||||
}
|
||||
auto *streamListResult = new StreamListResult();
|
||||
m_avaSession = m_avmDataIfc->avaSession();
|
||||
|
||||
auto fn = [this, streamListResult, streamType, streamSource]()
|
||||
{
|
||||
m_avaSession->control()->getStreamList(streamType, streamSource, streamListResult, &StreamListResult::onStreamListReceived);
|
||||
};
|
||||
|
||||
if (m_avaSession->isEstablished())
|
||||
fn();
|
||||
else
|
||||
connect(m_avaSession, &AvaSession::sessionEstablished,
|
||||
this, fn);
|
||||
|
||||
return streamListResult;
|
||||
}
|
||||
|
||||
|
||||
StreamClipsResult *InterfaceImpl::getAsyncStreamClips(const QString &streamName, const boost::optional<AvaTimePoint> &start, const boost::optional<AvaTimePoint> &end)
|
||||
{
|
||||
if (!m_avmDataIfc->hasAvsSession())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "No AvsSession available";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_avaSession = m_avmDataIfc->avaSession();
|
||||
|
||||
auto *streamClipsResult = new StreamClipsResult();
|
||||
auto fn = [this, streamClipsResult, streamName, start, end]()
|
||||
{
|
||||
m_avaSession->control()->queryTimeline(streamName, streamClipsResult, &StreamClipsResult::onClipsListReceived, start, end);
|
||||
};
|
||||
|
||||
if (m_avaSession->isEstablished())
|
||||
fn();
|
||||
else
|
||||
connect(m_avaSession, &AvaSession::sessionEstablished,
|
||||
this, fn);
|
||||
|
||||
return streamClipsResult;
|
||||
}
|
||||
|
||||
|
||||
TopicReplay::Interface *InterfaceImpl::createInterface(TopicEditorBase::TopicType topicType)
|
||||
{
|
||||
Q_ASSERT(topicType == TopicEditorBase::TopicType::Audio || topicType == TopicEditorBase::TopicType::Video);
|
||||
bool isAudio = topicType == TopicEditorBase::TopicType::Audio;
|
||||
return new TopicReplay(m_avmDataIfc.get(), isAudio);
|
||||
}
|
||||
|
||||
|
||||
AvmPlaybackMenuDialog *InterfaceImpl::createPlaybackDialog(bool isAudio, QWidget *parent, bool setInitialSearchContentMarkers)
|
||||
{
|
||||
PlaybackApp *app = nullptr;
|
||||
QPointer<AvmPlaybackMenuDialog> &dialogPtr = (isAudio ? m_avmPlaybackMenuDialogAudio : m_avmPlaybackMenuDialogVideo);
|
||||
|
||||
if (dialogPtr)
|
||||
return dialogPtr;
|
||||
|
||||
if (isAudio)
|
||||
app = m_avmDataIfc->audioPlaybackApp();
|
||||
else
|
||||
app = m_avmDataIfc->videoPlaybackApp();
|
||||
|
||||
if (!m_avmDataIfc->hasAvsSession())
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("The audio/video interface is not available in this session."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (app->inUse())
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("The audio/video interface is already in use by another dialog."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dialogPtr = new AvmPlaybackMenuDialog(isAudio, parent);
|
||||
|
||||
if (!dialogPtr->avmPlaybackMenu()->init(m_session, m_avmDataIfc->avaSession(), PlaybackAppHandle(app),
|
||||
m_avmDataIfc->streamNameMapping(), isAudio, false, {}, {}, setInitialSearchContentMarkers))
|
||||
{
|
||||
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("The audio/video interface could not be initialized. Please try again later."));
|
||||
dialogPtr->deleteLater();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
AvmPlaybackMenu *apm = dialogPtr->avmPlaybackMenu();
|
||||
connect(apm, &AvmPlaybackMenu::signalSetOverlay,
|
||||
this, [dialogPtr](QWidget * widget)
|
||||
{
|
||||
dialogPtr->setOverlay(widget);
|
||||
});
|
||||
|
||||
connect(apm, &AvmPlaybackMenu::signalUnsetOverlay,
|
||||
this, [dialogPtr]()
|
||||
{
|
||||
dialogPtr->unsetOverlay();
|
||||
});
|
||||
|
||||
return dialogPtr;
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowVideoPlayback(QWidget *parent)
|
||||
{
|
||||
return createPlaybackDialog(false, parent);
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowAudioPlayback(QWidget *parent)
|
||||
{
|
||||
return createPlaybackDialog(true, parent);
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowAudioSettingsDialog(QWidget *parent)
|
||||
{
|
||||
AudioSettingsDialog *dialogAudio = new AudioSettingsDialog(parent);
|
||||
return LtsWidgets::initDialog(dialogAudio, m_avmDataIfc->getOpmDtc(), m_dtc.get(), m_ftc.get(), m_session);
|
||||
}
|
||||
|
||||
|
||||
LtsWidgets::LtsDialog *InterfaceImpl::onShowVideoFullscreen(QWidget *parent)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
m_avmDataIfc->showOrCloseAvsApp();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void InterfaceImpl::showImportDialog()
|
||||
{
|
||||
const QString &dialogId = AvsDialog::IMPORT;
|
||||
|
||||
if (m_importDialogVisible)
|
||||
{
|
||||
m_avmDataIfc->avaSession()->control()->setVideoDialogProfile(dialogId, AvaVisibility::Hidden);
|
||||
m_avmDataIfc->avaSession()->control()->releaseImport(dialogId);
|
||||
m_importDialogVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *parent = nullptr;
|
||||
QString path = QFileDialog::getExistingDirectory(parent, tr("Choose directory"),
|
||||
QStringLiteral("/mnt"),
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly);
|
||||
if (path.size())
|
||||
{
|
||||
m_avmDataIfc->avaSession()->control()->setVideoDialogProfile(dialogId, AvaVisibility::Visible);
|
||||
m_avmDataIfc->avaSession()->control()->chooseImport(dialogId, path, 1);
|
||||
m_importDialogVisible = true;
|
||||
}
|
||||
else
|
||||
m_avmDataIfc->avaSession()->control()->releaseImport(dialogId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
class Ftc;
|
||||
}
|
||||
|
||||
class AvaControl;
|
||||
class DataInterface;
|
||||
class AvmPlaybackMenuDialog;
|
||||
|
||||
|
||||
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
|
||||
{
|
||||
Q_PLUGIN_METADATA(IID "gui:3:avm.mne")
|
||||
Q_INTERFACES(GuiPluginBase::Plugin)
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
GuiPlugin() = default;
|
||||
~GuiPlugin() = default;
|
||||
|
||||
QString pluginName() override { return QLatin1String("AudioVideoManagementMenuEditGuiPlugin"); }
|
||||
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
|
||||
|
||||
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise || partition == IDL::PartitionType::Replay; }
|
||||
};
|
||||
|
||||
|
||||
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface, public ForeignMenuEditGuiInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InterfaceImpl(LtsSession::LtsSession *session);
|
||||
~InterfaceImpl() = default;
|
||||
|
||||
bool fetchInterfaces() override;
|
||||
void clearInterfaces() override;
|
||||
QString menuGroup() const override;
|
||||
QString playbackMenuGroup() const;
|
||||
QVector<LtsWidgets::PluginData> getActions() override;
|
||||
|
||||
|
||||
TopicEditorBase::TopicEditor *createTopicEditor(const TopicEditorBase::TopicData &data) override;
|
||||
|
||||
bool startAudioVideoPlayback(const QString &streamName, qint64 startTime_ms, bool isAudio) override final;
|
||||
bool startMarkerAudioVideoPlayback(int markerId, bool isAudio) override;
|
||||
|
||||
StreamListResult* getAsyncStreamList(AvaStreamType streamType = AvaStreamType::Video, AvaStreamSource streamSource = AvaStreamSource::Server) override;
|
||||
StreamClipsResult* getAsyncStreamClips(const QString &streamName, const boost::optional<AvaTimePoint> &start = {}, const boost::optional<AvaTimePoint> &end = {}) override;
|
||||
|
||||
TopicReplay::Interface *createInterface(TopicEditorBase::TopicType topicType) override;
|
||||
|
||||
private:
|
||||
class TopicReplayImpl;
|
||||
|
||||
LtsWidgets::LtsDialog *onShowMenuEditVideoView(QWidget *parent);
|
||||
LtsWidgets::LtsDialog *onShowMenuEditAudioView(QWidget *parent);
|
||||
LtsWidgets::LtsDialog *onShowChooseMenu(QWidget *parent);
|
||||
AvmPlaybackMenuDialog *createPlaybackDialog(bool isAudio, QWidget *parent, bool setInitialSearchContentMarkers = true);
|
||||
LtsWidgets::LtsDialog *onShowVideoPlayback(QWidget *parent);
|
||||
LtsWidgets::LtsDialog *onShowAudioPlayback(QWidget *parent);
|
||||
LtsWidgets::LtsDialog *onShowAudioSettingsDialog(QWidget *parent);
|
||||
LtsWidgets::LtsDialog *onShowVideoFullscreen(QWidget *parent);
|
||||
|
||||
void showImportDialog();
|
||||
AvaSession *m_avaSession;
|
||||
|
||||
std::shared_ptr<AudioVideoManagement::DataInterface> m_avmDataIfc;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Ftc> m_ftc;
|
||||
|
||||
bool m_importDialogVisible{false};
|
||||
QPointer<AvmPlaybackMenuDialog> m_avmPlaybackMenuDialogAudio;
|
||||
QPointer<AvmPlaybackMenuDialog> m_avmPlaybackMenuDialogVideo;
|
||||
};
|
||||
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_menu_edit_view.h"
|
||||
#include "ui_avm_menu_edit_view.h"
|
||||
#include "avm_menu_edit.h"
|
||||
#include "avm_new_menu_struct.h"
|
||||
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <QTreeView>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
MenuEditView::MenuEditView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||||
, m_menuGroup(menuGroup)
|
||||
, m_model(nullptr)
|
||||
, m_isAudio(false)
|
||||
, m_dtc(nullptr)
|
||||
, m_ftc(nullptr)
|
||||
, m_session(session)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_ui(new Ui::MenuEditView)
|
||||
, m_logger(getLogger("AudioVideoManagementDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->widget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
|
||||
connect(m_ui->widget, &LtsDataView::LtsDataView::signalSelectionChanged,
|
||||
this, &MenuEditView::onSelectionChanged);
|
||||
|
||||
connect(m_ui->widget, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||||
this, &MenuEditView::onEditMenuStruct);
|
||||
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &MenuEditView::onEditMenuStruct);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &MenuEditView::onRemoveMenuStruct);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &MenuEditView::onAddMenuStruct);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &MenuEditView::onPrint);
|
||||
|
||||
}
|
||||
|
||||
|
||||
MenuEditView::~MenuEditView()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void MenuEditView::retranslate()
|
||||
{
|
||||
if (m_isAudio)
|
||||
translate(m_ui, tr("Audio Menu"));
|
||||
else
|
||||
translate(m_ui, tr("Video Menu"));
|
||||
}
|
||||
|
||||
|
||||
bool MenuEditView::init(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
bool isAudio)
|
||||
{
|
||||
Q_ASSERT(dtc);
|
||||
Q_ASSERT(ftc);
|
||||
Q_ASSERT(ismDtc);
|
||||
Q_ASSERT(streamNameMapping);
|
||||
|
||||
m_dtc = dtc;
|
||||
m_ftc = ftc;
|
||||
m_ismDtc = ismDtc;
|
||||
m_streamNameMapping = streamNameMapping;
|
||||
m_model = new MenuViewModel(this);
|
||||
m_model->initModel(m_dtc, isAudio);
|
||||
m_ui->widget->setModel(m_model);
|
||||
m_isAudio = isAudio;
|
||||
|
||||
#ifndef LTS_DEBUG
|
||||
m_ui->widget->hideColumn(0);
|
||||
#endif
|
||||
|
||||
m_ui->widget->setSortIndicator(1, Qt::AscendingOrder);
|
||||
|
||||
|
||||
m_buttonBox->connectLibraryButton(this,
|
||||
&MenuEditView::onImportButtonClicked,
|
||||
&MenuEditView::onExportButtonClicked);
|
||||
|
||||
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
|
||||
|
||||
if (m_isAudio)
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Audio_Menu"));
|
||||
else
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Video_Menu"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void MenuEditView::onSelectionChanged()
|
||||
{
|
||||
const QModelIndex idx = m_ui->widget->currentIndex();
|
||||
int row = idx.row();
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, (row >= 0));
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, (row >= 0));
|
||||
|
||||
}
|
||||
|
||||
void MenuEditView::onAddMenuStruct()
|
||||
{
|
||||
NewMenuStruct *newDialog = new NewMenuStruct(this);
|
||||
|
||||
connect(newDialog, &NewMenuStruct::newName, this, [this](const QString & name)
|
||||
{
|
||||
MenuStruct ms;
|
||||
ms.name(name.toStdString());
|
||||
ms.isAudio(m_isAudio);
|
||||
MenuEdit *dialog = new MenuEdit(this);
|
||||
dialog->init(m_session, m_dtc, m_ftc, m_ismDtc, m_streamNameMapping, ms);
|
||||
|
||||
addDialog(dialog, m_menuGroup, QLatin1String("avmNewMenu") + name, LtsWidgets::LayoutArea::eDialogTab);
|
||||
});
|
||||
newDialog->show();
|
||||
|
||||
connect(newDialog, &NewMenuStruct::accepted, newDialog, &NewMenuStruct::deleteLater);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MenuEditView::onEditMenuStruct()
|
||||
{
|
||||
const QModelIndex idx = m_ui->widget->currentIndex();
|
||||
|
||||
int row = idx.row();
|
||||
if (row < 0)
|
||||
return;
|
||||
|
||||
AudioVideoManagement::MenuStruct ms = m_model->getRowData(row);
|
||||
ms.isAudio(m_isAudio);
|
||||
|
||||
DEBUG_LOG(m_logger) << "---onEditMenuStruct () "
|
||||
<< " id: " << ms.id()
|
||||
<< " name: " << ms.name();
|
||||
|
||||
MenuEdit *dialog = new MenuEdit(this);
|
||||
dialog->init(m_session, m_dtc, m_ftc, m_ismDtc, m_streamNameMapping, ms);
|
||||
|
||||
addDialog(dialog, m_menuGroup, QLatin1String("avmMenuEdit") + QString::number(ms.id()), LtsWidgets::LayoutArea::eDialogTab);
|
||||
}
|
||||
|
||||
|
||||
void MenuEditView::onRemoveMenuStruct()
|
||||
{
|
||||
const QModelIndex idx = m_ui->widget->currentIndex();
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
const AudioVideoManagement::MenuStruct ms = m_model->getRowData(idx.row());
|
||||
const Core::RemoveElementRequest req(ms.id());
|
||||
m_requestHelper->startSingleRequest([req, this]()
|
||||
{
|
||||
return m_ftc->removeMenuStructRequest(req, this);
|
||||
});
|
||||
|
||||
if (m_model->rowCount() == 0)
|
||||
{
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuEditView::onPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->widget->treeView());
|
||||
}
|
||||
|
||||
void MenuEditView::tableColumnOrganiserSetting()
|
||||
{
|
||||
|
||||
m_ui->widget->setColumnsOrganiserEnabled(identifier(), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MenuEditView::onExportButtonClicked()
|
||||
{
|
||||
const QModelIndex idx = m_ui->widget->currentIndex();
|
||||
|
||||
int row = idx.row();
|
||||
if (row < 0)
|
||||
return;
|
||||
|
||||
QByteArray byteArray = m_model->modelToJson(row);
|
||||
|
||||
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
|
||||
if (fileId > 0)
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
|
||||
}
|
||||
|
||||
void MenuEditView::onImportButtonClicked()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " onImportButtonClicked() ";
|
||||
|
||||
QByteArray content;
|
||||
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::AVMMenuEditView));
|
||||
if (fileId > 0)
|
||||
{
|
||||
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::AVMMenuEditView)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
const QVector<AudioVideoManagement::MenuStruct> menuStructs = m_model->jsonToMenuStructs(content);
|
||||
for (const AudioVideoManagement::MenuStruct &request : menuStructs)
|
||||
{
|
||||
m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_ftc->modifyMenuStructRequest(request, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
INFO_LOG(m_logger) << "--- onImportButtonClicked() ";
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "avm_menu_view_model.h"
|
||||
|
||||
#include <Services/AudioVideoManagement/avm_dtc.h>
|
||||
#include <Services/AudioVideoManagement/avm_ftc.h>
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MenuEditView;
|
||||
}
|
||||
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class StreamNameMapping;
|
||||
|
||||
class MenuEditView : public LtsWidgets::LtsDialog,
|
||||
protected AudioVideoManagement::Interface::Ftc::ModifyMenuStructReplyHandler,
|
||||
protected AudioVideoManagement::Interface::Ftc::RemoveMenuStructReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MenuEditView(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent = nullptr);
|
||||
~MenuEditView();
|
||||
bool init(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc,
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Ftc> &ftc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
bool isAudio);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
void onSelectionChanged();
|
||||
void onAddMenuStruct();
|
||||
void onEditMenuStruct();
|
||||
void onRemoveMenuStruct();
|
||||
|
||||
void onModifyMenuStructReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
void onRemoveMenuStructReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
|
||||
void onPrint();
|
||||
void tableColumnOrganiserSetting() override;
|
||||
|
||||
private slots:
|
||||
void onExportButtonClicked();
|
||||
void onImportButtonClicked();
|
||||
|
||||
private:
|
||||
QString m_menuGroup;
|
||||
MenuViewModel *m_model;
|
||||
bool m_isAudio;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Ftc> m_ftc;
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
StreamNameMapping *m_streamNameMapping{nullptr};
|
||||
LtsSession::LtsSession *m_session;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
Ui::MenuEditView *m_ui;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/AudioVideoManagement/Gui/AVMenuEdit/avm_menu_edit_view.ui
Executable
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MenuEditView</class>
|
||||
<widget class="QWidget" name="MenuEditView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>455</width>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Menu Edit View</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="widget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>250</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_menu_view_model.h"
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MenuViewModel::MenuViewModel(QObject *parent)
|
||||
: LtsWidgets::LtsAbstractTableModel<AudioVideoManagement::MenuStruct>({tr("Id"),
|
||||
tr("Name")},
|
||||
parent)
|
||||
, m_isAudio(false)
|
||||
, m_dtc(nullptr)
|
||||
, m_logger(getLogger("MenuViewModel"))
|
||||
{}
|
||||
|
||||
|
||||
bool MenuViewModel::initModel(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc, bool isAudio)
|
||||
{
|
||||
m_isAudio = isAudio;
|
||||
m_dtc = dtc;
|
||||
|
||||
connect(m_dtc.get(), &AudioVideoManagement::Interface::Dtc::menuStructChanged,
|
||||
this, &MenuViewModel::onDataChanged);
|
||||
|
||||
|
||||
m_dtc->menuStructs([this](const AudioVideoManagement::MenuStruct &ms) { insertRow(ms); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QVariant MenuViewModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole || !indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
const AudioVideoManagement::MenuStruct &ms = m_vecData.at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case 0:
|
||||
return ms.id();
|
||||
case 1:
|
||||
return QString::fromStdString(ms.name());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool MenuViewModel::isFiltered(const MenuStruct &data, DataModification modType) const
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (data.isAudio() != m_isAudio)
|
||||
return true;
|
||||
if (data.isDefault())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray MenuViewModel::modelToJson(int row) const
|
||||
{
|
||||
if (row < 0 || row >= m_vecData.size())
|
||||
return QByteArray("{}");
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::AVMMenuEditView);
|
||||
|
||||
DEBUG_LOG(m_logger) << "row =" << ": " << row;
|
||||
const AudioVideoManagement::MenuStruct &menuStruct = m_vecData.at(row);
|
||||
|
||||
obj[QStringLiteral("id")] = 0;
|
||||
obj[QStringLiteral("isAudio")] = menuStruct.isAudio();
|
||||
obj[QStringLiteral("isDefault")] = menuStruct.isDefault();
|
||||
obj[QStringLiteral("name")] = QString::fromStdString(menuStruct.name());
|
||||
|
||||
|
||||
QJsonArray arrData;
|
||||
for (const AudioVideoManagement::AvMenuEntry &avMenuEntry : menuStruct.menuEntries())
|
||||
{
|
||||
QJsonObject innerData;
|
||||
innerData[QStringLiteral("id")] = avMenuEntry.id();
|
||||
innerData[QStringLiteral("isGroup")] = avMenuEntry.isGroup();
|
||||
if (avMenuEntry.mountingPointId().is_set())
|
||||
innerData[QStringLiteral("mountingPointId")] = avMenuEntry.mountingPointId().get();
|
||||
if (avMenuEntry.name().is_set())
|
||||
innerData[QStringLiteral("name")] = QString::fromStdString(avMenuEntry.name().get());
|
||||
innerData[QStringLiteral("parentId")] = avMenuEntry.parentId();
|
||||
innerData[QStringLiteral("rowId")] = avMenuEntry.rowId();
|
||||
|
||||
arrData += innerData;
|
||||
}
|
||||
obj[QStringLiteral("menuEntries")] = arrData;
|
||||
QJsonDocument doc(obj);
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
QVector<AudioVideoManagement::MenuStruct> MenuViewModel::jsonToMenuStructs(const QByteArray &content) const
|
||||
{
|
||||
|
||||
QVector<AudioVideoManagement::MenuStruct> result;
|
||||
AudioVideoManagement::MenuStruct menuStruct;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(content));
|
||||
const QJsonObject obj(doc.object());
|
||||
menuStruct.id(0);
|
||||
menuStruct.isAudio(obj[QStringLiteral("isAudio")].toBool());
|
||||
menuStruct.isDefault(obj[QStringLiteral("isDefault")].toBool());
|
||||
menuStruct.name(obj[QStringLiteral("name")].toString().toStdString());
|
||||
|
||||
|
||||
|
||||
const QJsonArray arrEntry(obj.value(QStringLiteral("menuEntries")).toArray());
|
||||
menuStruct.menuEntries().resize(arrEntry.size());
|
||||
INFO_LOG(m_logger) << "arrEntry.size()=" << arrEntry.size();
|
||||
for (int j = 0; j < arrEntry.size(); ++j)
|
||||
{
|
||||
const QJsonObject objEntry(arrEntry.at(j).toObject());
|
||||
AudioVideoManagement::AvMenuEntry avMenuEntry;
|
||||
|
||||
avMenuEntry.id(-10000000 + objEntry[QStringLiteral("id")].toInt());
|
||||
avMenuEntry.isGroup(objEntry[QStringLiteral("isGroup")].toBool());
|
||||
avMenuEntry.mountingPointId(objEntry[QStringLiteral("mountingPointId")].toInt());
|
||||
if (objEntry.contains(QStringLiteral("name")))
|
||||
avMenuEntry.name().set(objEntry[QStringLiteral("name")].toString().toStdString());
|
||||
if (objEntry[QStringLiteral("isGroup")].toBool())
|
||||
avMenuEntry.parentId(0);
|
||||
else
|
||||
avMenuEntry.parentId(-10000000 + objEntry[QStringLiteral("parentId")].toInt());
|
||||
avMenuEntry.rowId(objEntry[QStringLiteral("rowId")].toInt());
|
||||
|
||||
menuStruct.menuEntries()[j] = avMenuEntry;
|
||||
}
|
||||
|
||||
result.append(menuStruct);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/AudioVideoManagement/Gui/AVMenuEdit/avm_menu_view_model.h
Executable
+35
@@ -0,0 +1,35 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
class MenuViewModel final : public LtsWidgets::LtsAbstractTableModel<AudioVideoManagement::MenuStruct>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MenuViewModel(QObject *parent = nullptr);
|
||||
|
||||
bool initModel(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc, bool isAudio);
|
||||
QVariant data(const QModelIndex &, int) const override final;
|
||||
QByteArray modelToJson(int row) const;
|
||||
QVector<AudioVideoManagement::MenuStruct> jsonToMenuStructs(const QByteArray &content) const;
|
||||
protected:
|
||||
bool isFiltered(const MenuStruct &data, DataModification modType) const override final;
|
||||
|
||||
private:
|
||||
bool m_isAudio;
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_new_menu_struct.h"
|
||||
#include "ui_avm_new_menu_struct.h"
|
||||
|
||||
|
||||
#include <LtsSession/lts_session_manager.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
NewMenuStruct::NewMenuStruct(QWidget *parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
|
||||
, m_ui(new Ui::NewMenuStruct)
|
||||
, m_logger(getLogger("NewMenu"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
|
||||
m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Apply)->hide();
|
||||
connect(m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &LtsWidgets::LtsFramelessDialog::accept);
|
||||
m_ui->ltsDialogButtonBox->connectButton(LtsWidgets::DialogButton::Add, this, &NewMenuStruct::onSetNewName);
|
||||
}
|
||||
|
||||
NewMenuStruct::~NewMenuStruct()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NewMenuStruct::onSetNewName()
|
||||
{
|
||||
if (m_ui->leName->text().isEmpty())
|
||||
return;
|
||||
emit newName(m_ui->leName->text());
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/AudioVideoManagement/Gui/AVMenuEdit/avm_new_menu_struct.h
Executable
+36
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
#include <LtsWidgets/lts_frameless_dialog.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class NewMenuStruct;
|
||||
}
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class NewMenuStruct : public LtsWidgets::LtsFramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewMenuStruct(QWidget *parent = nullptr);
|
||||
~NewMenuStruct();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onSetNewName();
|
||||
|
||||
Q_SIGNALS:
|
||||
void newName(const QString &);
|
||||
|
||||
private:
|
||||
Ui::NewMenuStruct *m_ui;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewMenuStruct</class>
|
||||
<widget class="QWidget" name="NewMenuStruct">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>596</width>
|
||||
<height>118</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create New Menu</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>New Menu:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="leName"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsDialogButtonBox" name="ltsDialogButtonBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsDialogButtonBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsWidgets/lts_dialog_button_box.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
qt6-after/qt6-migrated-legatus/Lts/Plugins/AudioVideoManagement/Gui/AVMenuEdit/avm_playback_menu.cpp
Executable
+1677
File diff suppressed because it is too large.
Load diff
Executable
+217
@@ -0,0 +1,217 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_avm_playback_menu.h"
|
||||
#include "interval_model.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <MarkerManagement/mrk_ftc.h>
|
||||
#include <QString>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace MarkerManagement
|
||||
{
|
||||
class MarkerManagementDialogModel;
|
||||
class MarkerSortFilterProxyModel;
|
||||
class ForeignDataInterface;
|
||||
}
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class RequestHelper;
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvaSession;
|
||||
class AvaControl;
|
||||
class AvsSequence;
|
||||
class StreamNameMapping;
|
||||
class AvmPlaybackMenu;
|
||||
|
||||
|
||||
class QueryTimeline : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
friend class AvmPlaybackMenu;
|
||||
|
||||
QueryTimeline(const AvaStream &stream, const AvaTimePoint &start, const AvaTimePoint &end, AvaControl *control);
|
||||
|
||||
AvaControl *m_avaCtrl { nullptr };
|
||||
|
||||
private slots:
|
||||
|
||||
|
||||
signals:
|
||||
void signalTimelineComplete(const AvaTimeline &timeline);
|
||||
};
|
||||
|
||||
|
||||
class AvmPlaybackMenu : public QWidget,
|
||||
protected MarkerManagement::Interface::Ftc::MarkerModifyReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AvmPlaybackMenu(QWidget *parent = nullptr);
|
||||
~AvmPlaybackMenu();
|
||||
|
||||
bool init(LtsSession::LtsSession *session, AvaSession *avaSession, PlaybackAppHandle &&appHandle,
|
||||
StreamNameMapping* streamNameMapping, bool isAudio, bool insideTopicEditor,
|
||||
const boost::optional<QString> &streamName = boost::none,
|
||||
const boost::optional<AvaTimePoint> &startTime = boost::none, bool setInitialSearchContentMarkers = true);
|
||||
|
||||
void setPlaybackPreset(const QString &streamName, const AvaTimePoint &startTime, bool autostartPresetAfterInit);
|
||||
void setMarkerPreset(int markerId, bool autostartPresetAfterInit);
|
||||
|
||||
QueryTimeline *queryTimeline(const AvaTimePoint &start, const AvaTimePoint &end);
|
||||
|
||||
void onMarkerModifyReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
|
||||
void retranslate();
|
||||
|
||||
|
||||
void setStreamTime(qint64 time);
|
||||
void hideStreamSelection();
|
||||
qint64 getCurrentTime() const;
|
||||
AvaSpeed getSpeed() const;
|
||||
void setSpeed(AvaSpeed newSpeed);
|
||||
int getVolume() const;
|
||||
void setVolume(int newVolume);
|
||||
void setStreamByName(const QString &name);
|
||||
|
||||
QString getInternalStreamName() const;
|
||||
void setStreamName(const QString &internalStreamName);
|
||||
bool getSkipPause() const;
|
||||
void setSkipPause(bool bSkip);
|
||||
void startPlayback(bool usePresets = false);
|
||||
void setSavedPos(qint64 msecs);
|
||||
int currentOffset() const { return m_currentOffset; }
|
||||
void selectMarker(const MarkerManagement::Marker &marker);
|
||||
void selectMarker(int markerId);
|
||||
|
||||
signals:
|
||||
void signalSetOverlay(QWidget *widget);
|
||||
void signalUnsetOverlay();
|
||||
|
||||
void setTopicButtonStates(bool enable);
|
||||
void markerSelected(const QString &description);
|
||||
|
||||
|
||||
void signalSetStart(qint64 start);
|
||||
void signalSetEnd(qint64 end);
|
||||
void signalCurrentStreamChanged(const QString &displayName);
|
||||
void signalTimezoneChanged(int timezoneHoursOffset);
|
||||
|
||||
public slots:
|
||||
void onStreamSelectionChanged(const QVector<AvaStream> &selectedStreams);
|
||||
|
||||
private slots:
|
||||
void onSessionEstablished();
|
||||
void onDisconnected();
|
||||
|
||||
void onStreamListReceived(const QVector<AvaStream> &streams);
|
||||
void onTimelineComplete(const AvaTimeline &timeline);
|
||||
void onStreamPositionReceived(const QString &dialogId, const QString &streamName, AvaTimePoint);
|
||||
void onVolumeReceived(AvaVolume db);
|
||||
void onCommandQueueEmpty();
|
||||
|
||||
void onUiTimeChanged(AvaTimePoint t);
|
||||
void onIntervalActivated(const QModelIndex &index);
|
||||
void onMarkerClicked(const QModelIndex &index);
|
||||
void onSetMarkerClicked();
|
||||
void onStartClicked();
|
||||
void onPauseClicked();
|
||||
void onStopClicked();
|
||||
void onSkipPauseClicked();
|
||||
void onAllStreams();
|
||||
void onIntervalBackwardClicked();
|
||||
void onIntervalForwardClicked();
|
||||
void onSpeedChanged();
|
||||
void onVolumeChanged(int percent);
|
||||
void onCurrentIntervalChanged(bool hasPreviousInterval, bool hasNextInterval, const QModelIndex &rowIndex);
|
||||
void onStreamSelected();
|
||||
void onMarkerStreamSelected();
|
||||
void onStreamNameMappingChanged();
|
||||
void onAddStreamClip();
|
||||
void onAddStreamMarker();
|
||||
void onRemoveSelectedStreams();
|
||||
void onTabChanged(int index);
|
||||
void onPauseFromPlaybackApp();
|
||||
void onResumeFromPlaybackApp();
|
||||
|
||||
|
||||
private:
|
||||
enum class ButtonStates
|
||||
{
|
||||
AllOff,
|
||||
Started,
|
||||
Paused,
|
||||
Stopped
|
||||
};
|
||||
|
||||
void processPresets();
|
||||
void preselectStream(const QString &fallbackInternalStreamName);
|
||||
AvaSpeed currentSpeed() const;
|
||||
void setButtonStates(ButtonStates);
|
||||
void enableAll(bool enabled = true);
|
||||
void disableAll() { enableAll(false); }
|
||||
bool trySelectedStreams();
|
||||
void addStream(QComboBox *cb);
|
||||
|
||||
void applyAvsPos();
|
||||
void applyAvsVolume();
|
||||
|
||||
|
||||
PlaybackAppHandle m_playbackApp;
|
||||
bool m_isAudio = false;
|
||||
StreamNameMapping *m_streamNameMapping = nullptr;
|
||||
boost::optional<QString> m_presetStreamName;
|
||||
boost::optional<int> m_markerIdPreset;
|
||||
boost::optional<AvaTimePoint> m_presetStartTime;
|
||||
|
||||
class TimelineBuilder;
|
||||
std::unique_ptr<TimelineBuilder> m_timelineBuilder;
|
||||
|
||||
std::unique_ptr<Ui::Playback> m_ui;
|
||||
|
||||
class TimeControl;
|
||||
std::unique_ptr<TimeControl> m_timeControl;
|
||||
|
||||
boost::optional<QVector<AvaStream>> m_selectedStreams;
|
||||
IntervalModel m_intervalModel;
|
||||
boost::optional<AvaTimePoint> m_savedPos;
|
||||
std::unique_ptr<MarkerManagement::MarkerManagementDialogModel> m_markerModel;
|
||||
std::unique_ptr<MarkerManagement::MarkerSortFilterProxyModel> m_markerProxy;
|
||||
AvaControl *m_avaCtrl = nullptr;
|
||||
LtsSession::LtsSession *m_session = nullptr;
|
||||
bool m_skipEmpty = true;
|
||||
ButtonStates m_currentButtonState;
|
||||
std::shared_ptr<MarkerManagement::ForeignDataInterface> m_mrkDataIfc;
|
||||
boost::optional<AvaTimePoint> m_lastAvsPos;
|
||||
boost::optional<AvaVolume> m_lastAvsVolume;
|
||||
std::unique_ptr<LtsUtils::RequestHelper> m_requestHelper;
|
||||
QVector<AvaStream> m_streams;
|
||||
boost::optional<AvaStream> m_currentStream;
|
||||
bool m_autostartOnce { false };
|
||||
int m_maxSelectedStreams = 12;
|
||||
bool m_queryTimelineActive { false };
|
||||
int m_currentOffset = 0;
|
||||
|
||||
bool m_videoScreenSelectionDone { false };
|
||||
bool m_timelineIsComplete { false };
|
||||
ButtonStates m_buttonStateBeforePlaybackAppPause { ButtonStates::AllOff };
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+697
@@ -0,0 +1,697 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Playback</class>
|
||||
<widget class="QWidget" name="Playback">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>810</width>
|
||||
<height>791</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Playback Menu</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,5,1,0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbAvsConnectionStatus">
|
||||
<property name="text">
|
||||
<string>AVS Connection status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblAvsConnectionStatus">
|
||||
<property name="text">
|
||||
<string notr="true">unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spcAvsConnectionStatus">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Time zone:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="cbTimeZone">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Audio / Video clips</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,999">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblCbStreams">
|
||||
<property name="text">
|
||||
<string>From stream:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAddStreamClip">
|
||||
<property name="text">
|
||||
<string>Add stream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbStreams">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbDebug">
|
||||
<property name="text">
|
||||
<string notr="true">[debug]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tavIntervals">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>Markers</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="tvMarker" native="true">
|
||||
<property name="showColumnCount" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonsVisible" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select stream from marker:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbMarkerStreams">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAddStreamMarker">
|
||||
<property name="text">
|
||||
<string>Add stream</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAllStreams">
|
||||
<property name="text">
|
||||
<string>Show all streams</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="multiStreamWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Selected streams:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lwStreams"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbRemoveSelectedStream">
|
||||
<property name="text">
|
||||
<string>Remove selected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Current Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbSetMarker">
|
||||
<property name="text">
|
||||
<string>Create Marker</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsMSecDateTimeEdit" name="dtCurrentTime">
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="topicEditorEssentialsWidget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Set time as..:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAsStart">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbAsEnd">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblStartSeq">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slSequenceSlider">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::NoTicks</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblEndSeq">
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbIntervalBackward">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Back</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Back</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_previous_track.svg</normaloff>:/style/avm_previous_track.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbStart">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Play</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_start.svg</normaloff>:/style/avm_start.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbPause">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_pause.svg</normaloff>:/style/avm_pause.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbStop">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_stop.svg</normaloff>:/style/avm_stop.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbIntervalForward">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Forward</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Forward</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_next_track.svg</normaloff>:/style/avm_next_track.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbSpeed">
|
||||
<property name="text">
|
||||
<string>Speed [%]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbSpeedValue">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slSpeed">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacerSpeedVolume">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbVolume">
|
||||
<property name="text">
|
||||
<string>Volume [db]:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lbVolumeValue">
|
||||
<property name="text">
|
||||
<string notr="true">-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slVolume">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="const" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="pbSkipPause">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Skip/Show Pause</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/style/avm_pint.svg</normaloff>:/style/avm_pint.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsMSecDateTimeEdit</class>
|
||||
<extends>QDateTimeEdit</extends>
|
||||
<header>LtsWidgets/lts_msec_date_time_edit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tavIntervals</tabstop>
|
||||
<tabstop>cbMarkerStreams</tabstop>
|
||||
<tabstop>pbAddStreamMarker</tabstop>
|
||||
<tabstop>pbAllStreams</tabstop>
|
||||
<tabstop>lwStreams</tabstop>
|
||||
<tabstop>pbRemoveSelectedStream</tabstop>
|
||||
<tabstop>pbSetMarker</tabstop>
|
||||
<tabstop>pbAsStart</tabstop>
|
||||
<tabstop>pbAsEnd</tabstop>
|
||||
<tabstop>slSequenceSlider</tabstop>
|
||||
<tabstop>pbIntervalBackward</tabstop>
|
||||
<tabstop>pbStart</tabstop>
|
||||
<tabstop>pbPause</tabstop>
|
||||
<tabstop>pbStop</tabstop>
|
||||
<tabstop>pbIntervalForward</tabstop>
|
||||
<tabstop>slSpeed</tabstop>
|
||||
<tabstop>slVolume</tabstop>
|
||||
<tabstop>pbSkipPause</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
|
||||
|
||||
#include "avm_playback_menu_dialog.h"
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
AvmPlaybackMenuDialog::AvmPlaybackMenuDialog(bool isAudio, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||||
, m_isAudio(isAudio)
|
||||
, m_ui(new Ui::AvmPlaybackMenuDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
if (m_isAudio)
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Playback_Audio"));
|
||||
else
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Playback_Video"));
|
||||
}
|
||||
|
||||
|
||||
AvmPlaybackMenuDialog::~AvmPlaybackMenuDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
AudioVideoManagement::AvmPlaybackMenu *AvmPlaybackMenuDialog::avmPlaybackMenu()
|
||||
{
|
||||
return m_ui->widget;
|
||||
}
|
||||
|
||||
|
||||
void AvmPlaybackMenuDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, m_isAudio ? tr("Audio Playback") : tr("Video Playback"));
|
||||
m_ui->widget->retranslate();
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ui_avm_playback_menu_dialog.h"
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace Ui {
|
||||
class AvmPlaybackMenuDialog;
|
||||
}
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class AvmPlaybackMenuDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AvmPlaybackMenuDialog(bool isAudio, QWidget *parent);
|
||||
AudioVideoManagement::AvmPlaybackMenu *avmPlaybackMenu();
|
||||
|
||||
~AvmPlaybackMenuDialog();
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
private:
|
||||
bool m_isAudio;
|
||||
Ui::AvmPlaybackMenuDialog *m_ui;
|
||||
|
||||
};
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AvmPlaybackMenuDialog</class>
|
||||
<widget class="QWidget" name="AvmPlaybackMenuDialog">
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="AudioVideoManagement::AvmPlaybackMenu" name="widget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AudioVideoManagement::AvmPlaybackMenu</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>avm_playback_menu.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+676
@@ -0,0 +1,676 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_used_streams_model.h"
|
||||
#include "avm_available_streams_model.h"
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
#include <QMimeData>
|
||||
#include <QSet>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
const QString UsedStreamsModel::s_MimeTypeOI = QStringLiteral("UsedStreamsModel/OrderItem");
|
||||
|
||||
UsedStreamsModel::UsedStreamsModel(const std::shared_ptr<Interface::Dtc> avmDtc, const std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc,
|
||||
const MenuStruct &ms,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
QObject *parent)
|
||||
: NGLTreeModel(parent, nullptr, {tr("Streams")})
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_ismDtc(ismDtc)
|
||||
, m_dummyId(-10000000)
|
||||
, m_menuStruct(ms)
|
||||
, m_streamNameMapping(streamNameMapping)
|
||||
, m_logger(getLogger("UsedStreamsModel"))
|
||||
|
||||
{
|
||||
Q_ASSERT(streamNameMapping);
|
||||
initModel();
|
||||
}
|
||||
|
||||
QVariant UsedStreamsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
NGLTreeItem *item = privateData(index);
|
||||
if (!item->data().canConvert<StreamModelData>())
|
||||
return QVariant();
|
||||
|
||||
const StreamModelData availStream = item->data().value<StreamModelData>();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case 0:
|
||||
return availStream.name;
|
||||
default:
|
||||
return QStringLiteral("??");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
static const QIcon folder(QStringLiteral("icon:evaluation_folder.svg"));
|
||||
static const QIcon camera(QStringLiteral("icon:camera_control.svg"));
|
||||
return availStream.isGroup ? folder : camera;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NGLTreeModel::data(index, role);
|
||||
}
|
||||
|
||||
Qt::ItemFlags UsedStreamsModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags defaultFlags = NGLTreeModel::flags(index);
|
||||
|
||||
if (index.isValid())
|
||||
{
|
||||
defaultFlags ^= Qt::ItemIsDropEnabled;
|
||||
NGLTreeItem *item = privateData(index);
|
||||
if (item->data().canConvert<StreamModelData>())
|
||||
{
|
||||
StreamModelData menuEntry = item->data().value<StreamModelData>();
|
||||
|
||||
|
||||
defaultFlags |= Qt::ItemIsDragEnabled;
|
||||
|
||||
if (menuEntry.isGroup)
|
||||
{
|
||||
defaultFlags |= Qt::ItemIsEditable;
|
||||
defaultFlags |= Qt::ItemIsDropEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
defaultFlags |= Qt::ItemIsDropEnabled;
|
||||
|
||||
return defaultFlags;
|
||||
}
|
||||
|
||||
|
||||
QMimeData *UsedStreamsModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
QString type = AvailableStreamsModel::s_MimeType;
|
||||
for (const QModelIndex &mi : indexes)
|
||||
{
|
||||
if (mimeType(mi) == s_MimeTypeOI)
|
||||
{
|
||||
type = s_MimeTypeOI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return getMimeData(indexes, type);
|
||||
}
|
||||
|
||||
bool UsedStreamsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
|
||||
if (action == Qt::IgnoreAction)
|
||||
return true;
|
||||
|
||||
if (!checkDrop(data, index(row, column), parent, action))
|
||||
return false;
|
||||
|
||||
INFO_LOG(m_logger) << "dropMimeData: action = " << action
|
||||
<< ", row = " << row
|
||||
<< ", parent: valid = " << parent.isValid();
|
||||
|
||||
|
||||
|
||||
int beginRow;
|
||||
QModelIndex parentR;
|
||||
if (row != -1)
|
||||
{
|
||||
|
||||
parentR = parent;
|
||||
beginRow = row;
|
||||
}
|
||||
else if (parent.isValid())
|
||||
{
|
||||
|
||||
|
||||
parentR = parent;
|
||||
|
||||
beginRow = rowCount(parentR);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
parentR = QModelIndex();
|
||||
beginRow = rowCount(parentR);
|
||||
}
|
||||
|
||||
QString mimeType = data->hasFormat(s_MimeTypeOI) ? s_MimeTypeOI : AvailableStreamsModel::s_MimeType;
|
||||
bool ret = insertMimeData(data, mimeType, parentR, beginRow);
|
||||
if (ret)
|
||||
{
|
||||
|
||||
fixUpData(m_rootItem);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool UsedStreamsModel::canDropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (!NGLTreeModel::canDropMimeData(data, action, row, column, parent))
|
||||
return false;
|
||||
|
||||
if (!data->hasFormat(AvailableStreamsModel::s_MimeType) && !data->hasFormat(s_MimeTypeOI))
|
||||
return false;
|
||||
|
||||
if ((action != Qt::MoveAction) && (action != Qt::CopyAction))
|
||||
return false;
|
||||
|
||||
if (!checkDrop(data, parent, parent, action))
|
||||
return false;
|
||||
|
||||
if (!parent.isValid())
|
||||
return true;
|
||||
NGLTreeItem *item = privateData(parent);
|
||||
QVariant v = item->data();
|
||||
StreamModelData ms = v.value<StreamModelData>();
|
||||
if (!ms.isGroup)
|
||||
return false;
|
||||
|
||||
QString mimeType = data->hasFormat(s_MimeTypeOI) ? s_MimeTypeOI : AvailableStreamsModel::s_MimeType;
|
||||
QByteArray encodedData = data->data(mimeType);
|
||||
QDataStream stream(&encodedData, QIODevice::ReadOnly);
|
||||
qint64 idParent, idItem, mountId;
|
||||
bool group;
|
||||
QVariant itemData;
|
||||
|
||||
stream >> idParent >> idItem >> group >> itemData >> mountId;
|
||||
ms = itemData.value<StreamModelData>();
|
||||
INFO_LOG(m_logger) << "Insert:"
|
||||
<< "\n ms.name=" << ms.name
|
||||
<< "\n ms.isGroup=" << ms.isGroup
|
||||
<< "\n ms.parentId=" << ms.parentId
|
||||
<< "\n ms.mountingPointId=" << ms.mountingPointId;
|
||||
|
||||
if (ms.isGroup)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QStringList UsedStreamsModel::mimeTypes() const
|
||||
{
|
||||
return { AvailableStreamsModel::s_MimeType, s_MimeTypeOI };
|
||||
}
|
||||
|
||||
QString UsedStreamsModel::mimeType(const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
QVariant v = item->data();
|
||||
StreamModelData ms = v.value<StreamModelData>();
|
||||
if (ms.parentId == -1)
|
||||
return s_MimeTypeOI;
|
||||
|
||||
return AvailableStreamsModel::s_MimeType;
|
||||
}
|
||||
return s_MimeTypeOI;
|
||||
}
|
||||
|
||||
|
||||
static void getItems(const NGLTreeItem *item,
|
||||
int rowId,
|
||||
int parentId,
|
||||
std::vector<AudioVideoManagement::AvMenuEntry> &contToAdd,
|
||||
int &newId)
|
||||
{
|
||||
if (item->data().canConvert<StreamModelData>())
|
||||
{
|
||||
StreamModelData s = item->data().value<StreamModelData>();
|
||||
|
||||
AvMenuEntry me;
|
||||
me.id(s.id ? s.id : newId++);
|
||||
me.parentId(parentId);
|
||||
me.isGroup(s.isGroup);
|
||||
if (s.isGroup)
|
||||
me.name().set(s.name.toStdString());
|
||||
else
|
||||
me.mountingPointId(s.mountingPointId);
|
||||
me.rowId(rowId);
|
||||
|
||||
contToAdd.push_back(me);
|
||||
|
||||
if (s.isGroup)
|
||||
{
|
||||
for (int row = 0; row < item->childCount(); ++row)
|
||||
getItems(item->child(row), row + 1, me.id(), contToAdd, newId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MenuStruct UsedStreamsModel::getMenuStruct() const
|
||||
{
|
||||
MenuStruct ms;
|
||||
ms.id(m_menuStruct.id());
|
||||
ms.name(m_menuStruct.name());
|
||||
|
||||
int newId = -10000000;
|
||||
for (int row = 0; row < m_rootItem->childCount(); ++row)
|
||||
getItems(m_rootItem->child(row), row + 1, ms.id(), ms.menuEntries(), newId);
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
|
||||
void UsedStreamsModel::insertChildren(NGLTreeItem *parent, int parentId, const std::vector<AudioVideoManagement::AvMenuEntry> &entries)
|
||||
{
|
||||
QVariant data;
|
||||
QMap<int, int> rowIds;
|
||||
for (const AudioVideoManagement::AvMenuEntry &me : entries)
|
||||
{
|
||||
if (me.parentId() != parentId)
|
||||
continue;
|
||||
|
||||
data.setValue(StreamModelData::createFromServiceItem(me, m_streamNameMapping, m_avmDtc->videoTeams()));
|
||||
|
||||
|
||||
NGLTreeItem *treeItem = new NGLTreeItem(data);
|
||||
|
||||
|
||||
auto hierIt = rowIds.insert(me.rowId(), me.rowId());
|
||||
const int rowToInsert = std::distance(rowIds.begin(), hierIt);
|
||||
|
||||
parent->insertChild(rowToInsert, treeItem);
|
||||
|
||||
if (me.isGroup())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "insertChildren"
|
||||
<< me.mountingPointId()
|
||||
<< me.name();
|
||||
insertChildren(treeItem, me.id(), entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NGLTreeItem *UsedStreamsModel::getItemToCheck(const QModelIndex &index, const QModelIndex &parentIndex) const
|
||||
{
|
||||
|
||||
NGLTreeItem *item = privateData(index);
|
||||
QVariant v = item->data();
|
||||
StreamModelData ms = v.value<StreamModelData>();
|
||||
|
||||
NGLTreeItem *itemParent = privateData(parentIndex);
|
||||
const QVariant &variantParent = itemParent->data();
|
||||
NGLTreeItem *itemToCheck = itemParent;
|
||||
const StreamModelData &msParent = variantParent.value<StreamModelData>();
|
||||
|
||||
if (!ms.isGroup && msParent.isGroup)
|
||||
itemToCheck = itemParent;
|
||||
|
||||
if (!ms.isGroup && !msParent.isGroup)
|
||||
itemToCheck = m_rootItem;
|
||||
|
||||
return itemToCheck;
|
||||
}
|
||||
|
||||
bool UsedStreamsModel::checkSingleItem(NGLTreeItem *target, StreamModelData &toCheck) const
|
||||
{
|
||||
bool retValue = true;
|
||||
if (!target)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Nullptr exception";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
StreamModelData msTarget = target->data().value<StreamModelData>();
|
||||
if (msTarget.id == toCheck.parentId)
|
||||
DEBUG_LOG(m_logger) << "Drag&drag in same folder.";
|
||||
else if (msTarget.isGroup && toCheck.isGroup)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Trying to drop folder into folder";
|
||||
retValue = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
const QVector<NGLTreeItem *> &children = target->children();
|
||||
for (const NGLTreeItem *childData : children)
|
||||
{
|
||||
const QVariant &variantCheck = childData->data();
|
||||
const StreamModelData &msChild = variantCheck.value<StreamModelData>();
|
||||
if ((msChild.name == toCheck.name) && (msChild.id != toCheck.id))
|
||||
{
|
||||
retValue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
bool UsedStreamsModel::checkDrop(const QMimeData *data, const QModelIndex &index, const QModelIndex &parentIndex, Qt::DropAction action) const
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
NGLTreeItem *itemToCheck = getItemToCheck(index, parentIndex);
|
||||
|
||||
|
||||
|
||||
QString mimeType = data->hasFormat(s_MimeTypeOI) ? s_MimeTypeOI : AvailableStreamsModel::s_MimeType;
|
||||
QByteArray encodedData = data->data(mimeType);
|
||||
QList<StreamModelData> items;
|
||||
QDataStream stream(&encodedData, QIODevice::ReadOnly);
|
||||
qint64 idParent, idItem;
|
||||
bool containsIcon;
|
||||
QVariant itemData;
|
||||
QIcon tmp;
|
||||
|
||||
stream >> containsIcon;
|
||||
while (!stream.atEnd())
|
||||
{
|
||||
stream >> idParent >> idItem >> itemData;
|
||||
if (containsIcon)
|
||||
stream >> tmp;
|
||||
items.push_back(itemData.value<StreamModelData>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
int countDropped = 0;
|
||||
int countAgainst = 0;
|
||||
const QVector<NGLTreeItem *> &children = itemToCheck->children();
|
||||
for (const auto &item : children)
|
||||
{
|
||||
const QVariant &variantCheck = item->data();
|
||||
const StreamModelData &msCheck = variantCheck.value<StreamModelData>();
|
||||
|
||||
if (msCheck.isGroup)
|
||||
continue;
|
||||
++countAgainst;
|
||||
}
|
||||
|
||||
QList<qint64> movedFolders;
|
||||
bool onlyOneFolder = false;
|
||||
for (StreamModelData &item : items)
|
||||
{
|
||||
|
||||
StreamModelData msToCheck = itemToCheck->data().value<StreamModelData>();
|
||||
if (movedFolders.size() == 0)
|
||||
{
|
||||
|
||||
movedFolders.push_back(item.parentId);
|
||||
}
|
||||
|
||||
if ((item.isGroup) && movedFolders.contains(item.parentId))
|
||||
movedFolders.push_back(item.id);
|
||||
|
||||
else if ((movedFolders.at(0) != item.parentId) && (movedFolders.contains(item.parentId)) && (action == Qt::MoveAction))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Ignoring items in sub folder while moving.";
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (!movedFolders.contains(item.parentId) && (action == Qt::MoveAction))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Only allow items from same folder to be moved.";
|
||||
return false;
|
||||
}
|
||||
if (!checkSingleItem(itemToCheck, item))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Not able to add item with name: " << item.name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.isGroup)
|
||||
{
|
||||
if (!onlyOneFolder)
|
||||
{
|
||||
onlyOneFolder = true;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "More than one folder selected.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((msToCheck.id == item.parentId) && (Qt::MoveAction == action))
|
||||
continue;
|
||||
++countDropped;
|
||||
}
|
||||
|
||||
if (countDropped + countAgainst > 12)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Trying to add to many items to folder";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
QSet<int> UsedStreamsModel::fillTakenCameras(NGLTreeItem *getItem) const
|
||||
{
|
||||
QSet<int> ret;
|
||||
const QVector<NGLTreeItem *> &children = getItem->children();
|
||||
for (const auto &item : qAsConst(children))
|
||||
{
|
||||
if (item->childCount())
|
||||
ret += fillTakenCameras(item);
|
||||
else
|
||||
{
|
||||
const QVariant &variantCheck = item->data();
|
||||
const StreamModelData &msCheck = variantCheck.value<StreamModelData>();
|
||||
|
||||
if (msCheck.isGroup)
|
||||
continue;
|
||||
ret.insert(msCheck.mountingPointId);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool UsedStreamsModel::initModel()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
StreamModelData ms;
|
||||
ms.parentId = -1;
|
||||
ms.id = -2;
|
||||
|
||||
QVariant data;
|
||||
data.setValue(ms);
|
||||
setRootItem(new NGLTreeItem(data));
|
||||
|
||||
insertChildren(m_rootItem, m_menuStruct.id(), m_menuStruct.menuEntries());
|
||||
connect(m_ismDtc.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged,
|
||||
this, &UsedStreamsModel::onDataChanged);
|
||||
connect(m_avmDtc.get(), &AudioVideoManagement::Interface::Dtc::videoTeamChanged,
|
||||
this, &UsedStreamsModel::onDataChangedMvs);
|
||||
|
||||
|
||||
connect(m_streamNameMapping, &StreamNameMapping::changed,
|
||||
this, &UsedStreamsModel::onStreamNameDataChanged);
|
||||
endResetModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
NGLTreeItem *UsedStreamsModel::createItem(const QVariant &data, const QIcon &icon) const
|
||||
{
|
||||
StreamModelData s = data.value<StreamModelData>();
|
||||
|
||||
s.id = 0;
|
||||
s.parentId = 0;
|
||||
QVariant newData;
|
||||
newData.setValue(s);
|
||||
return new NGLTreeItem(newData, icon);
|
||||
}
|
||||
|
||||
|
||||
bool UsedStreamsModel::setData(const QModelIndex &idx, const QVariant &value, int role)
|
||||
{
|
||||
Q_UNUSED(role);
|
||||
|
||||
if (idx.isValid())
|
||||
{
|
||||
QVariant data;
|
||||
NGLTreeItem *ti = privateData(idx);
|
||||
StreamModelData ms = ti->data().value<StreamModelData>();
|
||||
if (idx.column() == 0)
|
||||
ms.name = value.toString();
|
||||
data.setValue(ms);
|
||||
ti->setData(data);
|
||||
emit dataChanged(index(idx.row(), 0), index(idx.row(), columnCount(QModelIndex()) - 1));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UsedStreamsModel::onDataChanged(const InfrastructureManagement::MainStructureElement &data,
|
||||
const DataModification modType)
|
||||
{
|
||||
beginResetModel();
|
||||
INFO_LOG(m_logger) << "onDataChanged m_rootItem->childCount()" << m_rootItem->childCount()
|
||||
<< " data.elements().size()=" << data.elements().size();
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eRemoved:
|
||||
break;
|
||||
case DataModification::eModified:
|
||||
case DataModification::eAdded:
|
||||
for (const InfrastructureManagement::StructureElement &se : data.elements())
|
||||
{
|
||||
INFO_LOG(m_logger) << "se.id()" << se.id()
|
||||
<< " se.displayName()" << se.displayName()
|
||||
<< " m_rootItem->childCount()" << m_rootItem->childCount();
|
||||
const QString newName = QString::fromStdString(se.displayName());
|
||||
updateStreamNames(se.id(), newName, m_rootItem);
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
void UsedStreamsModel::onDataChangedMvs(const VideoTeam &data, const DataModification modType)
|
||||
{
|
||||
|
||||
beginResetModel();
|
||||
INFO_LOG(m_logger) << "onDataChanged m_rootItem->childCount()" << m_rootItem->childCount();
|
||||
|
||||
switch (modType)
|
||||
{
|
||||
case DataModification::eRemoved:
|
||||
break;
|
||||
case DataModification::eModified:
|
||||
case DataModification::eAdded:
|
||||
|
||||
INFO_LOG(m_logger) << "se.id()" << data.id()
|
||||
<< " se.displayName()" << data.streamName()
|
||||
<< " m_rootItem->childCount()" << m_rootItem->childCount();
|
||||
const QString newName = QString::fromStdString(data.streamName());
|
||||
updateStreamNames(-1 * data.id(), newName, m_rootItem);
|
||||
|
||||
}
|
||||
endResetModel();
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
void UsedStreamsModel::onStreamNameDataChanged(int32_t mountingPointId, const QString &internalName, const QString &displayName)
|
||||
{
|
||||
Q_UNUSED(internalName)
|
||||
|
||||
beginResetModel();
|
||||
INFO_LOG(m_logger) << "onDataChanged m_rootItem->childCount()" << m_rootItem->childCount();
|
||||
INFO_LOG(m_logger) << "se.id()" << mountingPointId
|
||||
<< " se.displayName()" << displayName
|
||||
<< " m_rootItem->childCount()" << m_rootItem->childCount();
|
||||
updateStreamNames(mountingPointId, displayName, m_rootItem);
|
||||
|
||||
endResetModel();
|
||||
emit modelDataChanged();
|
||||
}
|
||||
|
||||
void UsedStreamsModel::updateStreamNames(const int mountingPointId, const QString &newName, NGLTreeItem *item)
|
||||
{
|
||||
INFO_LOG(m_logger) << "updateStreamNames mountingPointId=" << mountingPointId
|
||||
<< " newName=" << newName;
|
||||
|
||||
int childCount = item->childCount();
|
||||
for (int i = 0; i < childCount; ++i)
|
||||
{
|
||||
NGLTreeItem *child = item->child(i);
|
||||
|
||||
if (!child->data().canConvert<StreamModelData>())
|
||||
ERROR_LOG(m_logger) << "Error convert item";
|
||||
|
||||
StreamModelData usedStream = child->data().value<StreamModelData>();
|
||||
INFO_LOG(m_logger) << "i=" << i
|
||||
<< " usedStream.mountingPointId=" << usedStream.mountingPointId
|
||||
<< " usedStream.name=" << usedStream.name
|
||||
<< " mountingPointId=" << mountingPointId
|
||||
<< " newName=" << newName;
|
||||
if (mountingPointId == usedStream.mountingPointId)
|
||||
{
|
||||
INFO_LOG(m_logger) << "Set new DisplayName id=" << usedStream.id
|
||||
<< " mountingPointId=" << usedStream.mountingPointId
|
||||
<< " name=" << usedStream.name
|
||||
<< " new Name =" << newName;
|
||||
|
||||
usedStream.name = newName;
|
||||
|
||||
QVariant dataVar;
|
||||
dataVar.setValue(usedStream);
|
||||
child->setData(dataVar);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
updateStreamNames(mountingPointId, newName, item->child(i));
|
||||
}
|
||||
}
|
||||
|
||||
void UsedStreamsModel::fixUpData(NGLTreeItem *item)
|
||||
{
|
||||
|
||||
const QVector<NGLTreeItem *> &children = item->children();
|
||||
for (NGLTreeItem *child : children)
|
||||
{
|
||||
const StreamModelData parentStream = item->data().value<StreamModelData>();
|
||||
StreamModelData childStream = child->data().value<StreamModelData>();
|
||||
if (childStream.isGroup && childStream.id == 0)
|
||||
childStream.id = m_dummyId++;
|
||||
if (!childStream.isGroup && childStream.id == 0)
|
||||
childStream.id = m_dummyId++;
|
||||
childStream.parentId = parentStream.id;
|
||||
|
||||
QVariant data;
|
||||
data.setValue(childStream);
|
||||
child->setData(data);
|
||||
if (child->childCount() > 0)
|
||||
fixUpData(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <nglwidgets/ngltreemodel.h>
|
||||
#include "avm_available_streams_model.h"
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class MenuStruct;
|
||||
class StreamNameMapping;
|
||||
|
||||
|
||||
|
||||
class UsedStreamsModel final : public NGLTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
UsedStreamsModel(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc,
|
||||
const MenuStruct &ms,
|
||||
StreamNameMapping *streamNameMapping,
|
||||
QObject *parent);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex &idx, const QVariant &value,
|
||||
int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const override;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) override;
|
||||
bool canDropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent) const override;
|
||||
QStringList mimeTypes() const override;
|
||||
Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }
|
||||
|
||||
|
||||
MenuStruct getMenuStruct() const;
|
||||
bool initModel();
|
||||
|
||||
protected:
|
||||
NGLTreeItem *createItem(const QVariant &data, const QIcon &icon) const override;
|
||||
|
||||
private slots:
|
||||
void onDataChanged(const InfrastructureManagement::MainStructureElement &data,
|
||||
const DataModification modType);
|
||||
void onDataChangedMvs(const AudioVideoManagement::VideoTeam &data,
|
||||
const DataModification modType);
|
||||
void onStreamNameDataChanged(int32_t mountingPointId, const QString &internalName, const QString &displayName);
|
||||
private:
|
||||
void updateStreamNames(const int mountingPointId, const QString &newName, NGLTreeItem *item);
|
||||
|
||||
void fixUpData(NGLTreeItem *item);
|
||||
|
||||
static const QString s_MimeTypeOI;
|
||||
QString mimeType(const QModelIndex &index) const;
|
||||
void insertNGLTreeItemChild(NGLTreeItem *item, NGLTreeItem *parent, bool asCopy);
|
||||
void insertChildren(NGLTreeItem *parent, int parentId, const std::vector<AudioVideoManagement::AvMenuEntry> &entries);
|
||||
const std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_avmDtc;
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
NGLTreeItem *getItemToCheck(const QModelIndex &index, const QModelIndex &parentIndex) const;
|
||||
bool checkSingleItem(NGLTreeItem * target, StreamModelData & toCheck) const;
|
||||
bool checkDrop(const QMimeData *data, const QModelIndex &index, const QModelIndex &parentIndex, Qt::DropAction action) const;
|
||||
QSet<int> fillTakenCameras(NGLTreeItem *getItem) const;
|
||||
int m_dummyId;
|
||||
MenuStruct m_menuStruct;
|
||||
StreamNameMapping *m_streamNameMapping;
|
||||
NGL::INGLLogger &m_logger;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+174
@@ -0,0 +1,174 @@
|
||||
|
||||
|
||||
|
||||
#include "interval_model.h"
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QModelIndex>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
IntervalModel::IntervalModel()
|
||||
: LtsAbstractTableModel({tr("Start"), tr("End"), tr("Duration [s]")}, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QString IntervalModel::dateTimeToStringy(const QDateTime &dt) const
|
||||
{
|
||||
return QDateTime::fromMSecsSinceEpoch(dt.toMSecsSinceEpoch() + (m_timezoneHoursOffset * 3600 * 1000)).toString(QStringLiteral("dd.MM.yy HH:mm:ss.zzz"));
|
||||
}
|
||||
|
||||
|
||||
QString IntervalModel::msecsSinceEpochToStringy(qint64 msecs) const
|
||||
{
|
||||
return dateTimeToStringy(QDateTime::fromMSecsSinceEpoch(msecs));
|
||||
}
|
||||
|
||||
|
||||
void IntervalModel::setTimezoneHoursOffset(int timezoneHoursOffset)
|
||||
{
|
||||
m_timezoneHoursOffset = timezoneHoursOffset;
|
||||
emit dataChanged({}, {}, {Qt::DisplayRole});
|
||||
}
|
||||
|
||||
|
||||
QVariant IntervalModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
const AvaTimelinePart &interval = m_vecData.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case Start:
|
||||
return msecsSinceEpochToStringy(toMSecSinceEpoch(interval.first));
|
||||
case End:
|
||||
return msecsSinceEpochToStringy(toMSecSinceEpoch(interval.second));
|
||||
case Duration:
|
||||
{
|
||||
qint64 duration = (toMSecSinceEpoch(interval.second) - toMSecSinceEpoch(interval.first));
|
||||
|
||||
qint64 secs = duration / 1000;
|
||||
qint64 msecs = (duration % 1000);
|
||||
|
||||
return QStringLiteral("%1.%2").arg(secs).arg(msecs, 3, 10, QLatin1Char('0'));
|
||||
}
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::BackgroundRole:
|
||||
{
|
||||
if (m_currentInterval == (2 * index.row()))
|
||||
return QVariant(QColor(Qt::green));
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void IntervalModel::reset()
|
||||
{
|
||||
m_currentPos.reset();
|
||||
m_currentInterval.reset();
|
||||
setData({});
|
||||
emit currentIntervalChanged(false, false, QModelIndex());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IntervalModel::setCurrentPosition(AvaTimePoint pos, bool forceSignal)
|
||||
{
|
||||
if (m_vecData.isEmpty())
|
||||
return;
|
||||
|
||||
HalfIndex newInterval = intervalForPos(pos);
|
||||
bool intervalChanged = newInterval != m_currentInterval;
|
||||
m_currentPos = pos;
|
||||
m_currentInterval = newInterval;
|
||||
if (!intervalChanged && !forceSignal)
|
||||
return;
|
||||
|
||||
bool hasPrev = newInterval >= 0;
|
||||
bool hasNext = newInterval < 2 * (m_vecData.size() - 1);
|
||||
QModelIndex rowIndex;
|
||||
if (newInterval % 2 == 0)
|
||||
rowIndex = index(newInterval / 2, 0);
|
||||
emit currentIntervalChanged(hasPrev, hasNext, rowIndex);
|
||||
|
||||
QModelIndex topLeft = index(0, 0);
|
||||
QModelIndex bottomRight = index(rowCount() - 1, columnCount() - 1);
|
||||
emit dataChanged(topLeft, bottomRight, {Qt::BackgroundRole});
|
||||
}
|
||||
|
||||
const AvaTimelinePart &IntervalModel::previousInterval() const
|
||||
{
|
||||
Q_ASSERT(m_currentInterval);
|
||||
Q_ASSERT(*m_currentInterval != -1);
|
||||
|
||||
bool withinInterval = *m_currentInterval % 2 == 0;
|
||||
int intervalIndex = *m_currentInterval / 2;
|
||||
|
||||
if (!withinInterval)
|
||||
return m_vecData.at(intervalIndex);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (intervalIndex == 0)
|
||||
return m_vecData.at(intervalIndex);
|
||||
|
||||
const AvaTimelinePart &interval = m_vecData.at(intervalIndex);
|
||||
if (*m_currentPos > interval.first + std::chrono::seconds(2))
|
||||
return interval;
|
||||
else
|
||||
return m_vecData.at(intervalIndex - 1);
|
||||
}
|
||||
|
||||
const AvaTimelinePart &IntervalModel::nextInterval() const
|
||||
{
|
||||
Q_ASSERT(m_currentInterval);
|
||||
int intervalIndex = (*m_currentInterval + 2) / 2;
|
||||
return m_vecData.at(intervalIndex);
|
||||
}
|
||||
|
||||
IntervalModel::HalfIndex IntervalModel::intervalForPos(AvaTimePoint pos) const
|
||||
{
|
||||
Q_ASSERT(!m_vecData.isEmpty());
|
||||
|
||||
for (int i = 0; i < m_vecData.size(); ++i)
|
||||
{
|
||||
const AvaTimelinePart &interval = m_vecData.at(i);
|
||||
|
||||
if (pos < interval.first)
|
||||
{
|
||||
|
||||
return 2 * i - 1;
|
||||
}
|
||||
|
||||
if (pos >= interval.first && pos <= interval.second)
|
||||
{
|
||||
|
||||
return 2 * i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 2 * m_vecData.size() - 1;
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
|
||||
|
||||
class IntervalModel : public LtsWidgets::LtsAbstractTableModel<AvaTimelinePart>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
Start = 0,
|
||||
End,
|
||||
Duration,
|
||||
};
|
||||
|
||||
IntervalModel();
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
void reset();
|
||||
|
||||
bool isEmpty() const { return m_vecData.isEmpty(); }
|
||||
|
||||
void setCurrentPosition(AvaTimePoint pos, bool forceSignal = false);
|
||||
boost::optional<AvaTimePoint> currentPosition() const { return m_currentPos; }
|
||||
|
||||
|
||||
|
||||
const AvaTimelinePart &previousInterval() const;
|
||||
const AvaTimelinePart &nextInterval() const;
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
void currentIntervalChanged(bool hasPreviousInterval, bool hasNextInterval, const QModelIndex &rowIndex);
|
||||
|
||||
public slots:
|
||||
void setTimezoneHoursOffset(int timezoneHoursOffset);
|
||||
|
||||
private:
|
||||
QString dateTimeToStringy(const QDateTime &dt) const;
|
||||
QString msecsSinceEpochToStringy(qint64 msecs) const;
|
||||
|
||||
|
||||
|
||||
using HalfIndex = int;
|
||||
HalfIndex intervalForPos(AvaTimePoint pos) const;
|
||||
|
||||
boost::optional<AvaTimePoint> m_currentPos;
|
||||
boost::optional<HalfIndex> m_currentInterval;
|
||||
|
||||
int m_timezoneHoursOffset = 0;
|
||||
};
|
||||
|
||||
}
|
||||
Executable
+465
@@ -0,0 +1,465 @@
|
||||
|
||||
|
||||
|
||||
#include "topic_replay.h"
|
||||
#include <AudioVideoManagement/ava_types.h>
|
||||
#include <AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
#include <AudioVideoManagement/vd_control.h>
|
||||
#include <AudioVideoManagement/vd_session.h>
|
||||
#include <TopicEditorBase/topic_editor_base.h>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
#include <nglsettings/nglsettings_settings.h>
|
||||
#include <QWidget>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QDir>
|
||||
#include <QtGlobal>
|
||||
#include <QRect>
|
||||
#include <QDebug>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class TopicReplay::ExportScript : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportScript(const QString &topLevelExportDir, TopicEditorBase::ExportNotifier *exportStep);
|
||||
|
||||
public slots:
|
||||
void avScriptFinished(const QString &exportDir, AvaStreamType streamType, bool success);
|
||||
|
||||
private:
|
||||
QString audioVideoPlaylistErstellen(const QString &dir, AvaStreamType streamType);
|
||||
bool writeFile(const QByteArray &data, const QString &fileName);
|
||||
|
||||
QString m_topLevelExportDir;
|
||||
TopicEditorBase::ExportNotifier *m_exportStep;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TopicReplay::TopicReplay(DataInterface *dataIfc, bool isAudio)
|
||||
: m_isAudio(isAudio)
|
||||
, m_dataIfc(dataIfc)
|
||||
, m_logger(getLogger("TopicReplay"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::TopicReplay()";
|
||||
Q_ASSERT(dataIfc);
|
||||
}
|
||||
|
||||
TopicReplay::~TopicReplay()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::~TopicReplay()";
|
||||
|
||||
if (m_isPlaying)
|
||||
playbackStop();
|
||||
}
|
||||
|
||||
QWidget *TopicReplay::createWidget()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::createWidget()";
|
||||
Q_ASSERT(!m_screenPlacementHelper);
|
||||
|
||||
if (m_isAudio)
|
||||
return nullptr;
|
||||
|
||||
m_screenPlacementHelper.reset(new ScreenPlacementHelper());
|
||||
connect(m_screenPlacementHelper.data(), &ScreenPlacementHelper::widgetPlaced, this, &TopicReplay::onWidgetPlaced);
|
||||
return m_screenPlacementHelper.data();
|
||||
}
|
||||
|
||||
|
||||
void TopicReplay::slotSetScriptResponse(const AudioVideoManagement::AvaStreamInfo &streamInfo, AudioVideoManagement::AvaStreamState streamState)
|
||||
{
|
||||
if (streamState == AudioVideoManagement::AvaStreamState::NotPossible)
|
||||
ERROR_LOG(m_logger) << "Script could not be set";
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Script set!";
|
||||
|
||||
ERROR_LOG(m_logger) << "streamInfo: start" << streamInfo.duration.count();
|
||||
ERROR_LOG(m_logger) << "streamState: " << static_cast<int>(streamState);
|
||||
}
|
||||
|
||||
|
||||
bool TopicReplay::playbackInit(const QJsonObject &attributes)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::playbackInit()";
|
||||
DEBUG_LOG(m_logger) << QJsonDocument(attributes).toJson();
|
||||
|
||||
if (m_screenPlacementHelper && !m_isAudio)
|
||||
m_screenPlacementHelper->show();
|
||||
|
||||
m_playbackAttributes = attributes;
|
||||
|
||||
|
||||
AvaControl *ctrl = getAvaControl();
|
||||
if (ctrl == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no ava control!";
|
||||
return false;
|
||||
}
|
||||
|
||||
AvaTopicData topicData(m_playbackAttributes);
|
||||
|
||||
if (!topicData.isValid)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "topicData is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_scriptName = topicData.scriptName();
|
||||
|
||||
Q_ASSERT(topicData.isAudio() == m_isAudio);
|
||||
|
||||
PlaybackApp *app = m_isAudio ? m_dataIfc->audioPresentationApp() : m_dataIfc->videoPresentationApp();
|
||||
if (app == nullptr || app->inUse())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "app invalid or in use!";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!m_dialogGeometry)
|
||||
{
|
||||
if (m_isAudio)
|
||||
m_appHandle = PlaybackAppHandle(app);
|
||||
else
|
||||
m_appHandle = PlaybackAppHandle(app, QRect(0, 0, 0, 0));
|
||||
}
|
||||
else
|
||||
m_appHandle = PlaybackAppHandle(app, *m_dialogGeometry);
|
||||
|
||||
if (!m_appHandle)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "appHandle: missing app after creating appHandle!";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
NGL::Settings s({});
|
||||
bool isLocal = s.isDatabaseConnectionLocal();
|
||||
|
||||
DEBUG_LOG(m_logger) << "isLocal? " << isLocal;
|
||||
|
||||
AvaScriptSource source;
|
||||
if (isLocal)
|
||||
{
|
||||
if (m_isAudio)
|
||||
source = AvaScriptSource::LocalAudio;
|
||||
else
|
||||
source = AvaScriptSource::LocalVideo;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_isAudio)
|
||||
source = AvaScriptSource::ServerAudio;
|
||||
else
|
||||
source = AvaScriptSource::ServerVideo;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "source: " << static_cast<int>(source);
|
||||
|
||||
ctrl->setScript(m_appHandle.dialogId(), m_scriptName,
|
||||
source, topicData.streamList(),
|
||||
LtsUtils::createConnection(ctrl, &AudioVideoManagement::AvaControl::setScriptResponse,
|
||||
this, &TopicReplay::slotSetScriptResponse));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TopicReplay::playbackStart(int secondsOffset)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::playbackStart()";
|
||||
|
||||
if (m_screenPlacementHelper && !m_isAudio)
|
||||
m_screenPlacementHelper->show();
|
||||
|
||||
AvaControl *ctrl = getAvaControl();
|
||||
if (ctrl == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ctrl == nullptr";
|
||||
return false;
|
||||
}
|
||||
|
||||
AvaTimePoint p{AvaDuration{std::chrono::seconds(secondsOffset)}};
|
||||
|
||||
if (!m_appHandle)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "appHandle: missing app!";
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl->setAbsPositionScript(m_appHandle.dialogId(), m_scriptName, p);
|
||||
ctrl->startScript(m_appHandle.dialogId(), m_scriptName);
|
||||
|
||||
m_isPlaying = true;
|
||||
DEBUG_LOG(m_logger) << "m_isPlaying = true";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TopicReplay::playbackPause()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::playbackPause()";
|
||||
|
||||
if (m_screenPlacementHelper)
|
||||
m_screenPlacementHelper->hide();
|
||||
|
||||
if (!m_isPlaying)
|
||||
return true;
|
||||
|
||||
AvaControl *ctrl = getAvaControl();
|
||||
if (ctrl == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no ctrl!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_appHandle)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "appHandle: missing app!";
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl->pauseScript(m_appHandle.dialogId(), m_scriptName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TopicReplay::playbackStop()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "TopicReplay::playbackStop()";
|
||||
|
||||
if (m_screenPlacementHelper)
|
||||
m_screenPlacementHelper->hide();
|
||||
|
||||
if (!m_isPlaying)
|
||||
return true;
|
||||
|
||||
AvaControl *ctrl = getAvaControl();
|
||||
if (ctrl == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "no ctrl!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_appHandle)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "appHandle: missing app!";
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl->stopScript(m_appHandle.dialogId(), m_scriptName);
|
||||
ctrl->releaseScript(m_appHandle.dialogId(), m_scriptName);
|
||||
|
||||
m_isPlaying = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TopicReplay::exportTopic(const QJsonObject &attributes,
|
||||
const QString &folderPath,
|
||||
TopicEditorBase::ExportNotifier *exportNotifier)
|
||||
{
|
||||
Q_ASSERT(!m_exportScript);
|
||||
|
||||
VdControl *ctrl = getVdControl();
|
||||
if (ctrl == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ctrl missing!";
|
||||
exportNotifier->setExportFailed();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_exportScript.reset(new ExportScript(folderPath, exportNotifier));
|
||||
|
||||
AvaTopicData topicData(attributes);
|
||||
m_scriptName = topicData.scriptName();
|
||||
|
||||
if (!topicData.isValid)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "topicData is invalid";
|
||||
exportNotifier->setExportFailed();
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fileInfo(QDir(folderPath).filePath(topicData.scriptName()));
|
||||
|
||||
Q_ASSERT(topicData.isAudio() == m_isAudio);
|
||||
|
||||
ctrl->vdSetScript(m_scriptName,
|
||||
m_isAudio ? AvaStreamType::Audio : AvaStreamType::Video,
|
||||
0, topicData.streamList(), fileInfo.baseName(), fileInfo.absolutePath(),
|
||||
this, &TopicReplay::avScriptFinished);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TopicReplay::onWidgetPlaced(const QRect &geometry)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "TopicReplay::onWidgetPlaced() - geo: " << geometry.x() << "/" << geometry.y()
|
||||
<< " m_isAudio=" << m_isAudio;
|
||||
|
||||
m_dialogGeometry = geometry;
|
||||
|
||||
if (m_isAudio)
|
||||
return;
|
||||
|
||||
PlaybackApp *app = m_isAudio ? m_dataIfc->audioPresentationApp() : m_dataIfc->videoPresentationApp();
|
||||
if (app == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "app missing!";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!app->inUse())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "app not in use - waiting for playbackInit to aquire it";
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "setGeometry";
|
||||
app->setGeometry(*m_dialogGeometry);
|
||||
}
|
||||
|
||||
AvaControl *TopicReplay::getAvaControl()
|
||||
{
|
||||
if (!m_dataIfc->hasAvsSession())
|
||||
return nullptr;
|
||||
|
||||
AvaSession *avaSession = m_dataIfc->avaSession();
|
||||
if (!avaSession->isEstablished())
|
||||
return nullptr;
|
||||
|
||||
return avaSession->control();
|
||||
}
|
||||
|
||||
VdControl *TopicReplay::getVdControl()
|
||||
{
|
||||
if (!m_dataIfc->hasAvsSession())
|
||||
return nullptr;
|
||||
|
||||
VdSession *vdSession = m_dataIfc->vdSession();
|
||||
if (!vdSession->isEstablished())
|
||||
return nullptr;
|
||||
|
||||
return vdSession->control();
|
||||
}
|
||||
|
||||
void TopicReplay::avScriptFinished(const QString &exportDir, AvaStreamType streamType, bool success)
|
||||
{
|
||||
VdControl *ctrl = getVdControl();
|
||||
ctrl->vdReleaseScript(m_scriptName);
|
||||
m_exportScript->avScriptFinished(exportDir, streamType, success);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
TopicReplay::ExportScript::ExportScript(const QString &topLevelExportDir, TopicEditorBase::ExportNotifier *exportStep)
|
||||
: m_topLevelExportDir(topLevelExportDir)
|
||||
, m_exportStep(exportStep)
|
||||
{
|
||||
connect(exportStep, &QObject::destroyed, this, [this]()
|
||||
{
|
||||
if (static_cast<TopicEditorBase::ExportNotifier *>(sender()) != m_exportStep)
|
||||
return;
|
||||
m_exportStep = nullptr;
|
||||
});
|
||||
Q_ASSERT(exportStep);
|
||||
}
|
||||
|
||||
void TopicReplay::ExportScript::avScriptFinished(const QString &exportDir, AvaStreamType streamType, bool success)
|
||||
{
|
||||
QString absPathToPlaylist = audioVideoPlaylistErstellen(exportDir, streamType);
|
||||
|
||||
QDir toplevelExportDir(m_topLevelExportDir);
|
||||
QString relativePathToPlaylist = toplevelExportDir.relativeFilePath(absPathToPlaylist);
|
||||
|
||||
if (m_exportStep == nullptr)
|
||||
return;
|
||||
|
||||
if (success)
|
||||
m_exportStep->setExportSuccessful(relativePathToPlaylist);
|
||||
else
|
||||
m_exportStep->setExportFailed();
|
||||
}
|
||||
|
||||
QString TopicReplay::ExportScript::audioVideoPlaylistErstellen(const QString &dir, AvaStreamType streamType)
|
||||
{
|
||||
QDir avDir(dir);
|
||||
const QFileInfoList dateienList = avDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
|
||||
QByteArray dataForFile;
|
||||
QString data;
|
||||
dataForFile.append("[playlist]\n");
|
||||
|
||||
int numberOfEntries = 0;
|
||||
int i = 1;
|
||||
const QString tmpl1(QStringLiteral("File %1=%2\n"));
|
||||
const QString tmpl2(QStringLiteral("# File %1=%2\n"));
|
||||
for (const QFileInfo &fileInfo : dateienList)
|
||||
{
|
||||
if (streamType == AvaStreamType::Video && fileInfo.suffix() == QLatin1String(".wav"))
|
||||
{
|
||||
data += tmpl2.arg(QString::number(i), fileInfo.fileName());
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
data += tmpl1.arg(QString::number(i), fileInfo.fileName());
|
||||
numberOfEntries++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
QString numberOfEntriesString = QStringLiteral("NumberOfEntries=") + QString::number(numberOfEntries) + QStringLiteral("\n");
|
||||
dataForFile.append(numberOfEntriesString.toUtf8());
|
||||
dataForFile.append(data.toUtf8());
|
||||
|
||||
QString fileName;
|
||||
switch (streamType)
|
||||
{
|
||||
case AvaStreamType::Audio:
|
||||
fileName = avDir.filePath(QStringLiteral("audio.pls"));
|
||||
break;
|
||||
|
||||
case AvaStreamType::Video:
|
||||
fileName = avDir.filePath(QStringLiteral("video.pls"));
|
||||
break;
|
||||
}
|
||||
|
||||
writeFile(dataForFile, fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
bool TopicReplay::ExportScript::writeFile(const QByteArray &data, const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
return false;
|
||||
|
||||
if (file.write(data) == -1)
|
||||
{
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#include "topic_replay.moc"
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/Shared/playback_app.h>
|
||||
#include <PluginInterfaces/topic_replay_interface.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QVector>
|
||||
#include <QWidget>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
#include <AudioVideoManagement/ava_control.h>
|
||||
#include <AudioVideoManagement/ava_session.h>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
enum class AvaStreamType;
|
||||
|
||||
|
||||
|
||||
class ScreenPlacementHelper : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScreenPlacementHelper(QWidget *parent = nullptr)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setWindowTitle(QStringLiteral("Topic Replay Screen Placement Helper"));
|
||||
|
||||
|
||||
|
||||
|
||||
setWindowFlags(Qt::FramelessWindowHint);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
activateWindow();
|
||||
show();
|
||||
}
|
||||
|
||||
protected:
|
||||
void moveEvent(QMoveEvent *) override
|
||||
{
|
||||
emitNewGeometry();
|
||||
}
|
||||
|
||||
void resizeEvent(QResizeEvent *) override
|
||||
{
|
||||
emitNewGeometry();
|
||||
}
|
||||
|
||||
void emitNewGeometry()
|
||||
{
|
||||
|
||||
emit widgetPlaced(geometry());
|
||||
}
|
||||
|
||||
signals:
|
||||
void widgetPlaced(const QRect &geometry);
|
||||
};
|
||||
|
||||
|
||||
class DataInterface;
|
||||
class AvaControl;
|
||||
class VdControl;
|
||||
struct AvaScriptEntry;
|
||||
|
||||
|
||||
class TopicReplay final : public QObject, public ::TopicReplay::Interface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TopicReplay(DataInterface *dataIfc, bool isAudio);
|
||||
~TopicReplay();
|
||||
|
||||
|
||||
|
||||
QWidget *createWidget() override;
|
||||
|
||||
|
||||
bool playbackInit(const QJsonObject &attributes) override;
|
||||
bool playbackStart(int secondsOffset) override;
|
||||
bool playbackPause() override;
|
||||
bool playbackStop() override;
|
||||
|
||||
bool exportTopic(const QJsonObject &attributes,
|
||||
const QString &folderPath,
|
||||
TopicEditorBase::ExportNotifier *pExportNotifier) override;
|
||||
|
||||
private slots:
|
||||
void onWidgetPlaced(const QRect &geometry);
|
||||
void avScriptFinished(const QString &exportDir, AvaStreamType streamType, bool success);
|
||||
void slotSetScriptResponse(const AvaStreamInfo &, AvaStreamState);
|
||||
|
||||
private:
|
||||
AvaControl* getAvaControl();
|
||||
VdControl* getVdControl();
|
||||
|
||||
|
||||
class ExportScript;
|
||||
|
||||
const bool m_isAudio;
|
||||
PlaybackAppHandle m_appHandle;
|
||||
DataInterface *m_dataIfc;
|
||||
QString m_scriptName;
|
||||
bool m_isPlaying{false};
|
||||
QScopedPointer<ScreenPlacementHelper> m_screenPlacementHelper;
|
||||
boost::optional<QRect> m_dialogGeometry;
|
||||
QScopedPointer<ExportScript> m_exportScript;
|
||||
LOGGER_T m_logger;
|
||||
QJsonObject m_playbackAttributes;
|
||||
};
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
ADD_SUBDIRECTORY(AVMenuEdit)
|
||||
ADD_SUBDIRECTORY(CombatNetRadio)
|
||||
ADD_SUBDIRECTORY(Eloka)
|
||||
ADD_SUBDIRECTORY(TrainingVoiceCommunication)
|
||||
ADD_SUBDIRECTORY(MobileVideoSystem)
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
# Created by Hannes Baeuerle, SLSE, 2017-08-18
|
||||
#
|
||||
|
||||
SET(avm_combat_net_radio_gui_SRCS
|
||||
CombatNetRadioConfiguration/avm_cnr_json_helper.h
|
||||
CombatNetRadioConfiguration/avm_cnr_json_helper.cpp
|
||||
CombatNetRadioConfiguration/avm_combat_net_radio_dialog.h
|
||||
CombatNetRadioConfiguration/avm_combat_net_radio_dialog.cpp
|
||||
CombatNetRadioConfiguration/avm_combat_net_radio_dialog_model.h
|
||||
CombatNetRadioConfiguration/avm_combat_net_radio_dialog_model.cpp
|
||||
CombatNetRadioConfiguration/avm_edit_combat_net_radio_dialog.h
|
||||
CombatNetRadioConfiguration/avm_edit_combat_net_radio_dialog.cpp
|
||||
CombatNetRadioConfiguration/avm_load_combat_net_radio_dialog.h
|
||||
CombatNetRadioConfiguration/avm_load_combat_net_radio_dialog.cpp
|
||||
CombatNetRadioConfiguration/avm_load_combat_net_radio_dialog_model.h
|
||||
CombatNetRadioConfiguration/avm_load_combat_net_radio_dialog_model.cpp
|
||||
|
||||
FrequencyPlanning/avm_edit_frequency_planning_dialog.h
|
||||
FrequencyPlanning/avm_edit_frequency_planning_dialog.cpp
|
||||
FrequencyPlanning/avm_edit_frequency_planning_frequency_data_model.h
|
||||
FrequencyPlanning/avm_edit_frequency_planning_frequency_data_model.cpp
|
||||
|
||||
FrequencyPlanning/avm_edit_frequency_planning_resource_dialog.h
|
||||
FrequencyPlanning/avm_edit_frequency_planning_resource_dialog.cpp
|
||||
FrequencyPlanning/avm_frequency_planning_widget.h
|
||||
FrequencyPlanning/avm_frequency_planning_widget.cpp
|
||||
FrequencyPlanning/avm_edit_frequency_planning_set_resource_dialog.h
|
||||
FrequencyPlanning/avm_edit_frequency_planning_set_resource_dialog.cpp
|
||||
FrequencyPlanning/avm_edit_frequency_planning_resource_data_model.h
|
||||
FrequencyPlanning/avm_edit_frequency_planning_resource_data_model.cpp
|
||||
|
||||
FrequencyPlanning/avm_init_frequency_planning_dialog.h
|
||||
FrequencyPlanning/avm_init_frequency_planning_dialog.cpp
|
||||
FrequencyPlanning/avm_frequency_planning_dialog.h
|
||||
FrequencyPlanning/avm_frequency_planning_dialog.cpp
|
||||
FrequencyPlanning/avm_frequency_planning_dialog_model.h
|
||||
FrequencyPlanning/avm_frequency_planning_dialog_model.cpp
|
||||
FrequencyPlanning/avm_frequency_planning_helper.h
|
||||
FrequencyPlanning/avm_frequency_planning_helper.cpp
|
||||
avm_combat_net_radio_gui_plugin.h
|
||||
avm_combat_net_radio_gui_plugin.cpp
|
||||
|
||||
FrequencyPlanning/avm_radio_specifica_widget.cpp
|
||||
FrequencyPlanning/avm_radio_specifica_widget.h
|
||||
FrequencyPlanning/avm_radio_specifica_hf_widget.cpp
|
||||
FrequencyPlanning/avm_radio_specifica_hf_widget.h
|
||||
FrequencyPlanning/avm_radio_specifica_uhf_widget.cpp
|
||||
FrequencyPlanning/avm_radio_specifica_uhf_widget.h
|
||||
FrequencyPlanning/avm_radio_specifica_vhf_widget.cpp
|
||||
FrequencyPlanning/avm_radio_specifica_vhf_widget.h
|
||||
|
||||
FrequencyPlanning/avm_load_frequency_planning_dialog.cpp
|
||||
FrequencyPlanning/avm_load_frequency_planning_dialog.h
|
||||
FrequencyPlanning/avm_load_frequency_planning_dialog_model.cpp
|
||||
FrequencyPlanning/avm_load_frequency_planning_dialog_model.h
|
||||
)
|
||||
|
||||
NGL_WRAP_UI(avm_combat_net_radio_gui_SRCS
|
||||
CombatNetRadioConfiguration/avm_combat_net_radio_dialog.ui
|
||||
CombatNetRadioConfiguration/avm_edit_combat_net_radio_dialog.ui
|
||||
CombatNetRadioConfiguration/avm_load_combat_net_radio_dialog.ui
|
||||
FrequencyPlanning/avm_edit_frequency_planning_dialog.ui
|
||||
FrequencyPlanning/avm_edit_frequency_planning_resource_dialog.ui
|
||||
FrequencyPlanning/avm_frequency_planning_widget.ui
|
||||
FrequencyPlanning/avm_edit_frequency_planning_set_resource_dialog.ui
|
||||
FrequencyPlanning/avm_init_frequency_planning_dialog.ui
|
||||
FrequencyPlanning/avm_frequency_planning_dialog.ui
|
||||
FrequencyPlanning/avm_radio_specifica_hf_widget.ui
|
||||
FrequencyPlanning/avm_radio_specifica_uhf_widget.ui
|
||||
FrequencyPlanning/avm_radio_specifica_vhf_widget.ui
|
||||
FrequencyPlanning/avm_load_frequency_planning_dialog.ui
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY(WS avmCombatNetRadioGuiPlugin MODULE ${avm_combat_net_radio_gui_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(avmCombatNetRadioGuiPlugin
|
||||
svcCnrHelper
|
||||
LtsPrinting
|
||||
nglwidgets
|
||||
NGLLogger
|
||||
ngltools
|
||||
LtsSession
|
||||
LtsSessionData
|
||||
AvmDataPluginInterface
|
||||
ExmDataPluginInterface
|
||||
PpmDataPluginInterface
|
||||
FlmDataPluginInterface
|
||||
svcAvmCommon
|
||||
AvmShared
|
||||
svcExmClient
|
||||
Qt5::Widgets
|
||||
LtsWidgets
|
||||
LtsDataView
|
||||
LtsUtilsGuiDds
|
||||
LtsUtilsSettings
|
||||
)
|
||||
|
||||
NGL_INSTALL_TARGET(avmCombatNetRadioGuiPlugin)
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_cnr_json_helper.h"
|
||||
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
QByteArray cnrConfigVectorToJson(const QVector<CnrConfig> &configVector, int32_t exerciseId)
|
||||
{
|
||||
const bool isGlobal = exerciseId == 0;
|
||||
QJsonObject obj;
|
||||
QJsonArray arr;
|
||||
|
||||
for (const CnrConfig &config : qAsConst(configVector))
|
||||
{
|
||||
if((isGlobal && config.exerciseId().is_set())
|
||||
|| (!isGlobal && !config.exerciseId().is_set()))
|
||||
continue;
|
||||
|
||||
arr += cnrConfigToJson(config);
|
||||
}
|
||||
|
||||
obj.insert(JsonKeys::XML_TYPE(), FileManagement::toString(FileManagement::XmlType::AVMCombatNetRadio));
|
||||
obj.insert(JsonKeys::CNR_CONFIGURATION(), arr);
|
||||
|
||||
const QJsonDocument doc(obj);
|
||||
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
QJsonObject cnrConfigToJson(const CnrConfig &config)
|
||||
{
|
||||
QJsonObject cnrObj;
|
||||
|
||||
using namespace JsonKeys;
|
||||
|
||||
cnrObj.insert(CALL_SIGN(), QString::fromStdString(config.callSign()));
|
||||
cnrObj.insert(CNR_CHANNEL_ID(), config.cnrChannelId());
|
||||
cnrObj.insert(IS_GLOBAL(), !config.exerciseId().is_set());
|
||||
cnrObj.insert(RADIO_CIRCUIT(), QString::fromStdString(config.radioCircuit()));
|
||||
cnrObj.insert(IS_ACTIVE(), config.isActive());
|
||||
cnrObj.insert(RECORDING(), config.recording());
|
||||
|
||||
return cnrObj;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T jsonToCnr(const QJsonObject &cnrJson)
|
||||
{
|
||||
T cnrConfigRequest;
|
||||
|
||||
using namespace JsonKeys ;
|
||||
|
||||
cnrConfigRequest.callSign(cnrJson.value(CALL_SIGN()).toString().toStdString());
|
||||
cnrConfigRequest.cnrChannelId(cnrJson.value(CNR_CHANNEL_ID()).toInt());
|
||||
cnrConfigRequest.id(0);
|
||||
cnrConfigRequest.radioCircuit(cnrJson.value(RADIO_CIRCUIT()).toString().toStdString());
|
||||
|
||||
cnrConfigRequest.recording(cnrJson.value(RECORDING()).toBool());
|
||||
|
||||
return cnrConfigRequest;
|
||||
}
|
||||
|
||||
QVector<CnrConfig> jsonToCnrConfigVector(const QByteArray &data)
|
||||
{
|
||||
using namespace JsonKeys;
|
||||
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(data));
|
||||
const QJsonObject obj(doc.object());
|
||||
const QJsonArray arr(obj.value(CNR_CONFIGURATION()).toArray());
|
||||
QVector<CnrConfig> result;
|
||||
result.reserve(arr.size());
|
||||
|
||||
for (const auto &elem : arr)
|
||||
{
|
||||
const QJsonObject obj(elem.toObject());
|
||||
|
||||
result.append(jsonToCnr<CnrConfig>(obj));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
namespace JsonKeys
|
||||
{
|
||||
inline QString CALL_SIGN() { return QLatin1String("callSign"); }
|
||||
inline QString CNR_CHANNEL_ID() { return QLatin1String("cnrChannelId"); }
|
||||
inline QString CNR_CONFIGURATION() { return QLatin1String("cnrConfiguration"); }
|
||||
inline QString IS_ACTIVE() { return QLatin1String("isActive"); }
|
||||
inline QString IS_GLOBAL() { return QLatin1String("isGlobal"); }
|
||||
inline QString RADIO_CIRCUIT() { return QLatin1String("radioCircuit"); }
|
||||
inline QString RECORDING() { return QLatin1String("recording"); }
|
||||
inline QString XML_TYPE() { return QLatin1String("XmlType"); }
|
||||
}
|
||||
|
||||
QByteArray cnrConfigVectorToJson(const QVector<CnrConfig> &configVector, int32_t exerciseId);
|
||||
QJsonObject cnrConfigToJson(const CnrConfig &config);
|
||||
|
||||
QVector<CnrConfig> jsonToCnrConfigVector(const QByteArray &data);
|
||||
|
||||
template <typename T>
|
||||
T jsonToCnr(const QJsonObject &cnrJson);
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_combat_net_radio_dialog.h"
|
||||
#include "ui_avm_combat_net_radio_dialog.h"
|
||||
#include "avm_combat_net_radio_dialog_model.h"
|
||||
#include "avm_edit_combat_net_radio_dialog.h"
|
||||
#include "avm_cnr_json_helper.h"
|
||||
#include "avm_load_combat_net_radio_dialog.h"
|
||||
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
CombatNetRadioDialog::CombatNetRadioDialog(LtsSession::LtsSession *session, const QString &menuGroup, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||||
, m_session(session)
|
||||
, m_ui(new Ui::CombatNetRadioDialog)
|
||||
, m_menuGroup(menuGroup)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_logger(getLogger("CombatNetRadioDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setUnchangeable(true);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &CombatNetRadioDialog::onPrint);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Combat_Net_Radio_Configuration"));
|
||||
}
|
||||
|
||||
CombatNetRadioDialog::~CombatNetRadioDialog() = default;
|
||||
|
||||
void CombatNetRadioDialog::retranslate()
|
||||
{
|
||||
translate(m_ui.get(), tr("Configure Combat Net Radio"));
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::tableColumnOrganiserSetting()
|
||||
{
|
||||
|
||||
m_ui->dataView->setColumnsOrganiserEnabled(identifier(), true);
|
||||
}
|
||||
|
||||
bool CombatNetRadioDialog::init(const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc)
|
||||
{
|
||||
if (!(avmDtc->enableCnrChannel() &&
|
||||
avmDtc->enableCnrConfig() &&
|
||||
ppmDtc->enableParty() &&
|
||||
ppmDtc->enableParticipant() &&
|
||||
ppmDtc->enableType() &&
|
||||
avmFtc->enableModifyCnrConfig() &&
|
||||
avmFtc->enableRemoveCnrConfig()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not enable topics";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_model.reset(new CombatNetRadioDialogModel(m_session->exerciseId(), this));
|
||||
m_filter.reset(new CombatNetRadioDialogFilter(m_session->exerciseId(), m_model.get()));
|
||||
|
||||
m_avmDtc = avmDtc;
|
||||
m_avmFtc = avmFtc;
|
||||
m_ppmDtc = ppmDtc;
|
||||
m_exmDtc = exmDtc;
|
||||
|
||||
m_avmDtc->waitForHistoricalDataCnrChannel(3000);
|
||||
m_ppmDtc->waitForHistoricalDataParty(3000);
|
||||
|
||||
if (!m_model->init(avmDtc, ppmDtc))
|
||||
{
|
||||
m_filter.reset();
|
||||
m_model.reset();
|
||||
ERROR_LOG(m_logger) << "Could not init model";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ui->dataView->setModel(m_filter.get());
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &CombatNetRadioDialog::onAddClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &CombatNetRadioDialog::onEditClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &CombatNetRadioDialog::onRemoveClicked);
|
||||
|
||||
connect(m_ui->dataView, &LtsDataView::LtsDataView::signalSelectionChanged,
|
||||
this, &CombatNetRadioDialog::onSelectionChanged);
|
||||
|
||||
onSelectionChanged();
|
||||
|
||||
connect(m_ui->dataView, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||||
this, &CombatNetRadioDialog::onEditClicked);
|
||||
|
||||
|
||||
m_buttonBox->connectLibraryButton(this,
|
||||
&CombatNetRadioDialog::onImportButtonClicked,
|
||||
&CombatNetRadioDialog::onExportButtonClicked);
|
||||
|
||||
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onRemoveCnrConfigReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onModifyCnrConfigReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onAddClicked()
|
||||
{
|
||||
EditCombatNetRadioDialog *dialog = new EditCombatNetRadioDialog(m_session->exerciseId(), m_session, m_ppmDtc, m_avmDtc, m_avmFtc, m_exmDtc, this);
|
||||
addDialog(dialog, m_menuGroup, QStringLiteral("NewCNRConfig"), LtsWidgets::LayoutArea::eDialogTab);
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onEditClicked()
|
||||
{
|
||||
|
||||
if (!m_buttonBox->isButtonEnabled(LtsWidgets::DialogButton::Edit))
|
||||
return;
|
||||
|
||||
QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
CnrConfig config = m_model->data(currentIndex, Qt::UserRole).value<CnrConfig>();
|
||||
|
||||
EditCombatNetRadioDialog *dialog = new EditCombatNetRadioDialog(config,
|
||||
m_session->exerciseId(),
|
||||
m_session,
|
||||
m_ppmDtc,
|
||||
m_avmDtc,
|
||||
m_avmFtc,
|
||||
m_exmDtc,
|
||||
this);
|
||||
|
||||
addDialog(dialog, m_menuGroup, QStringLiteral("EditCNRConfig%1").arg(config.id()), LtsWidgets::LayoutArea::eDialogTab);
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onRemoveClicked()
|
||||
{
|
||||
QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
Core::RemoveElementRequest request(m_model->data(currentIndex, Qt::UserRole).value<CnrConfig>().id());
|
||||
|
||||
m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->removeCnrConfigRequest(request, this);
|
||||
});
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onSelectionChanged()
|
||||
{
|
||||
bool rowSelected = m_ui->dataView->selectionModel()->selectedRows().size() > 0;
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, rowSelected);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, rowSelected);
|
||||
|
||||
QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
CnrConfig config = m_model->data(currentIndex, Qt::UserRole).value<CnrConfig>();
|
||||
bool enabled = rowSelected && (config.exerciseId().is_set() || m_session->partitionType() == IDL::PartitionType::Global);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, enabled);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, enabled);
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->dataView->treeView());
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onExportButtonClicked()
|
||||
{
|
||||
QByteArray byteArray = m_filter->modelToJson();
|
||||
|
||||
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
|
||||
if (fileId > 0)
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
}
|
||||
|
||||
void CombatNetRadioDialog::onImportButtonClicked()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " onImportButtonClicked() ";
|
||||
|
||||
QByteArray content;
|
||||
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::AVMCombatNetRadio));
|
||||
|
||||
if (fileId > 0)
|
||||
{
|
||||
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::AVMCombatNetRadio)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadCombatNetRadioDialog loadingDialog(content, m_session) ;
|
||||
loadingDialog.exec();
|
||||
|
||||
if (loadingDialog.isApplied())
|
||||
{
|
||||
const QVector<Core::RemoveElementRequest> removeRequests = loadingDialog.removeRequests();
|
||||
|
||||
for (const auto &removeRequest : removeRequests)
|
||||
{
|
||||
m_requestHelper->addRequest([this, removeRequest]()
|
||||
{
|
||||
return m_avmFtc->removeCnrConfigRequest(removeRequest, this);
|
||||
});
|
||||
}
|
||||
|
||||
const QVector<ModifyCnrConfigRequest> modifyRequests = loadingDialog.modifyRequests();
|
||||
|
||||
for (const auto &modifyRequest : modifyRequests)
|
||||
{
|
||||
m_requestHelper->addRequest([this, modifyRequest]()
|
||||
{
|
||||
return m_avmFtc->modifyCnrConfigRequest(modifyRequest, this);
|
||||
});
|
||||
}
|
||||
|
||||
if (modifyRequests.size() || removeRequests.size())
|
||||
(void) m_requestHelper->startRequests();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class CombatNetRadioDialog;
|
||||
}
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class RequestHelper;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class CombatNetRadioDialogModel;
|
||||
class CombatNetRadioDialogFilter;
|
||||
|
||||
class CombatNetRadioDialog
|
||||
: public LtsWidgets::LtsDialog
|
||||
, protected Interface::Ftc::RemoveCnrConfigReplyHandler
|
||||
, protected Interface::Ftc::ModifyCnrConfigReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CombatNetRadioDialog(LtsSession::LtsSession *session, const QString &menuGroup, QWidget *parent = nullptr);
|
||||
~CombatNetRadioDialog();
|
||||
|
||||
bool init(const std::shared_ptr<Interface::Dtc> &avmDtc, const std::shared_ptr<Interface::Ftc> &avmFtc, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, ExerciseManagement::Interface::Dtc *exmDtc);
|
||||
|
||||
void onRemoveCnrConfigReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onModifyCnrConfigReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onAddClicked();
|
||||
void onEditClicked();
|
||||
void onRemoveClicked();
|
||||
void onSelectionChanged();
|
||||
void onPrint();
|
||||
void onExportButtonClicked();
|
||||
void onImportButtonClicked();
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
void tableColumnOrganiserSetting() override;
|
||||
|
||||
private:
|
||||
LtsSession::LtsSession *m_session;
|
||||
std::unique_ptr<CombatNetRadioDialogModel> m_model;
|
||||
std::unique_ptr<CombatNetRadioDialogFilter> m_filter;
|
||||
std::unique_ptr<Ui::CombatNetRadioDialog> m_ui;
|
||||
QString m_menuGroup;
|
||||
std::unique_ptr<LtsUtils::RequestHelper> m_requestHelper;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<Interface::Ftc> m_avmFtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
ExerciseManagement::Interface::Dtc *m_exmDtc{nullptr};
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CombatNetRadioDialog</class>
|
||||
<widget class="QWidget" name="CombatNetRadioDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>692</width>
|
||||
<height>262</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="LtsDataView::LtsDataView" name="dataView" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_combat_net_radio_dialog_model.h"
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include "avm_cnr_json_helper.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
CombatNetRadioDialogModel::CombatNetRadioDialogModel(int32_t exerciseId, QObject *parent)
|
||||
: LtsAbstractTableModel<CnrConfig>(
|
||||
{
|
||||
tr("Channel Number"),
|
||||
tr("Radio Circuit"),
|
||||
tr("Code Word"),
|
||||
tr("Party"),
|
||||
tr("Unit"),
|
||||
tr("Global")
|
||||
}, parent)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_logger(getLogger("CombatNetRadioDialogModel"))
|
||||
{
|
||||
}
|
||||
|
||||
QVariant CombatNetRadioDialogModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if ((role != Qt::BackgroundRole &&role != Qt::DisplayRole && role != Qt::UserRole) || !indexIsValid(index))
|
||||
return {};
|
||||
|
||||
const CnrConfig &config = m_vecData.at(index.row());
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case CHANNEL:
|
||||
INFO_LOG(m_logger)<<"CombatNetRadioDialogModel::data role =" << role
|
||||
<< " row = " << index.row();
|
||||
return QString::fromStdString(m_cnrChannels.value(config.cnrChannelId()).name());
|
||||
case RADIO_CIRCUIT:
|
||||
return QString::fromStdString(config.radioCircuit());
|
||||
case CALL_SIGN:
|
||||
return QString::fromStdString(config.callSign());
|
||||
case PARTY:
|
||||
if(config.exerciseId().is_set() || config.partyId() > 0)
|
||||
return ParticipantManagement::trPartyName(m_parties.value(config.partyId()).name());
|
||||
else
|
||||
return QStringLiteral("-");
|
||||
case UNIT:
|
||||
{
|
||||
if (!config.unitId().is_set())
|
||||
return {};
|
||||
const int unitId = config.unitId().get();
|
||||
const auto unit = m_units.value(config.unitId().get());
|
||||
if (unit.id() != unitId)
|
||||
return {};
|
||||
|
||||
INFO_LOG(m_logger) << " config.unitId()=" << unitId
|
||||
<< " Str=" << unit.name();
|
||||
|
||||
QString unitStr;
|
||||
if (unit.designator().size() > 0)
|
||||
unitStr = QString::fromStdString(unit.designator()) + QLatin1Char('/');
|
||||
unitStr.append(QString::fromStdString(unit.tacticalIdentifier()));
|
||||
INFO_LOG(m_logger) << "unitStr = " << unitStr;
|
||||
|
||||
return unitStr;
|
||||
}
|
||||
case GLOBAL:
|
||||
return config.exerciseId().is_set() ? tr("No") : tr("Yes");
|
||||
}
|
||||
}
|
||||
else if (role == Qt::BackgroundRole)
|
||||
{
|
||||
if (config.exerciseId().is_set() && config.exerciseId().get() == m_exerciseId)
|
||||
return {};
|
||||
if (!config.exerciseId().is_set() && m_exerciseId <= 0)
|
||||
return {};
|
||||
return QColor(Qt::gray);
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
return QVariant::fromValue(config);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CombatNetRadioDialogModel::init(const std::shared_ptr<Interface::Dtc> &avmDtc, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc)
|
||||
{
|
||||
m_avmDtc = avmDtc;
|
||||
|
||||
m_cnrChannels = avmDtc->cnrChannels();
|
||||
|
||||
if (!ppmDtc->visibleParties(m_parties, LtsSessionData::LtsSessionData::getInstance()->getVisibleParties(m_exerciseId)))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not retrieve visible Parties!";
|
||||
return false;
|
||||
}
|
||||
m_units = ppmDtc->units();
|
||||
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::cnrConfigChanged, this, &CombatNetRadioDialogModel::onDataChanged);
|
||||
m_avmDtc->cnrConfigs([this](const CnrConfig &c) { insertRow(c); });
|
||||
|
||||
return true;
|
||||
}
|
||||
bool CombatNetRadioDialogModel::onlyGlobals()
|
||||
{
|
||||
for(const CnrConfig &config : qAsConst(m_vecData))
|
||||
{
|
||||
if(config.exerciseId().is_set() && config.exerciseId().get() == m_exerciseId)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QByteArray CombatNetRadioDialogFilter::modelToJson() const
|
||||
{
|
||||
QVector<CnrConfig> configs;
|
||||
configs.reserve(rowCount());
|
||||
|
||||
for (int row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
int sourceRow = mapToSource(index(row, 0)).row();
|
||||
configs.append(m_sourceModel->getRowData(sourceRow));
|
||||
}
|
||||
|
||||
return cnrConfigVectorToJson(configs, m_exerciseId);
|
||||
}
|
||||
|
||||
CombatNetRadioDialogFilter::CombatNetRadioDialogFilter(int32_t exerciseId, CombatNetRadioDialogModel *sourceModel)
|
||||
: m_exerciseId(exerciseId)
|
||||
, m_sourceModel(sourceModel)
|
||||
{
|
||||
Q_ASSERT(sourceModel);
|
||||
setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool CombatNetRadioDialogFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
CnrConfig cnrConfig = m_sourceModel->getRowData(sourceRow);
|
||||
|
||||
if (cnrConfig.exerciseId().is_set() && cnrConfig.exerciseId().get() != m_exerciseId)
|
||||
return false;
|
||||
|
||||
return LtsColumnFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class CombatNetRadioDialogModel final
|
||||
: public LtsWidgets::LtsAbstractTableModel<CnrConfig>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
CHANNEL,
|
||||
RADIO_CIRCUIT,
|
||||
CALL_SIGN,
|
||||
PARTY,
|
||||
UNIT,
|
||||
GLOBAL
|
||||
};
|
||||
|
||||
explicit CombatNetRadioDialogModel(int32_t exerciseId, QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool init(const std::shared_ptr<Interface::Dtc> &avmDtc, const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc);
|
||||
bool onlyGlobals();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
int32_t m_exerciseId;
|
||||
QMap<int32_t, CnrChannel> m_cnrChannels;
|
||||
QMap<int32_t, ParticipantManagement::Party> m_parties;
|
||||
QMap<int32_t, ParticipantManagement::Participant> m_units;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CombatNetRadioDialogFilter : public LtsWidgets::LtsColumnFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit CombatNetRadioDialogFilter(int32_t exerciseId, CombatNetRadioDialogModel *sourceModel);
|
||||
|
||||
QByteArray modelToJson() const;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
|
||||
private:
|
||||
|
||||
using LtsWidgets::LtsColumnFilterProxyModel::setSourceModel;
|
||||
|
||||
int32_t m_exerciseId;
|
||||
CombatNetRadioDialogModel *m_sourceModel;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::CnrConfig)
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::FrequencyPlanningData)
|
||||
+598
@@ -0,0 +1,598 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_combat_net_radio_dialog.h"
|
||||
#include "ui_avm_edit_combat_net_radio_dialog.h"
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <AudioVideoManagement/Shared/project_settings.h>
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QStandardItemModel>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
CnrConfig toConfig(const ModifyCnrConfigRequest &modifyRequest)
|
||||
{
|
||||
return {modifyRequest.id(), modifyRequest.cnrChannelId(), modifyRequest.exerciseId(), modifyRequest.radioCircuit(),
|
||||
modifyRequest.partyId(), modifyRequest.unitId(), modifyRequest.recording(), modifyRequest.callSign(), false};
|
||||
}
|
||||
|
||||
const QString &NO_CHANNEL()
|
||||
{
|
||||
static const QString noChannel = QStringLiteral("---");
|
||||
return noChannel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
EditCombatNetRadioDialog::EditCombatNetRadioDialog(int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent)
|
||||
: EditCombatNetRadioDialog(boost::none, exerciseId, session, ppmDtc, avmDtc, avmFtc, exmDtc, parent)
|
||||
{
|
||||
m_ui->chkRecording->setChecked(true);
|
||||
m_isGlobal = session->partitionType() == IDL::PartitionType::Global;
|
||||
|
||||
if(m_isGlobal)
|
||||
setUiValuesForGlobal();
|
||||
|
||||
initCbChannelsForCreate();
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Combat_Net_Radio_Configuration"));
|
||||
}
|
||||
|
||||
EditCombatNetRadioDialog::EditCombatNetRadioDialog(const CnrConfig &cnrConfig,
|
||||
int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent)
|
||||
: EditCombatNetRadioDialog(cnrConfig.id(), exerciseId, session, ppmDtc, avmDtc, avmFtc, exmDtc, parent)
|
||||
{
|
||||
m_channelId = cnrConfig.cnrChannelId();
|
||||
m_isGlobal = session->partitionType() == IDL::PartitionType::Global;
|
||||
setUiValues(cnrConfig);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Combat_Net_Radio_Configuration"));
|
||||
}
|
||||
|
||||
EditCombatNetRadioDialog::EditCombatNetRadioDialog(const boost::optional<int32_t> &id,
|
||||
int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_ui(new Ui::EditCombatNetRadioDialog)
|
||||
, m_id(id)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_ppmDtc(ppmDtc)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_avmFtc(avmFtc)
|
||||
, m_exmDtc(exmDtc)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_logger(getLogger("EditCombatNetRadioDialog"))
|
||||
{
|
||||
Q_ASSERT(ppmDtc);
|
||||
Q_ASSERT(avmDtc);
|
||||
Q_ASSERT(avmFtc);
|
||||
Q_ASSERT(exmDtc);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
if (ProjectSettings::isAlwaysRecording())
|
||||
{
|
||||
m_ui->chkRecording->setChecked(true);
|
||||
m_ui->chkRecording->setEnabled(false);
|
||||
m_ui->chkRecording->hide();
|
||||
m_ui->lbRecording->hide();
|
||||
}
|
||||
init(session);
|
||||
}
|
||||
|
||||
EditCombatNetRadioDialog::~EditCombatNetRadioDialog() = default;
|
||||
|
||||
void EditCombatNetRadioDialog::retranslate()
|
||||
{
|
||||
translate(m_ui.get(), QString(), !m_id.is_initialized(), tr("Combat Net Radio"));
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::setUiValues(const CnrConfig &cnrConfig)
|
||||
{
|
||||
if(m_isGlobal)
|
||||
setUiValuesForGlobal();
|
||||
|
||||
m_ui->chkGlobal->setChecked(m_isGlobal);
|
||||
initCbChannels(cnrConfig.cnrChannelId());
|
||||
bool disableParty = (m_avmDtc->cnrChannel(cnrConfig.cnrChannelId()).frequencyBand() == FrequencyBand_def::REL) || m_isGlobal;
|
||||
if (!disableParty)
|
||||
{
|
||||
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(cnrConfig.partyId()));
|
||||
int unitId = cnrConfig.unitId().is_set() ? cnrConfig.unitId().get() : 0;
|
||||
m_ui->cbUnit->setCurrentIndex(m_ui->cbUnit->findData(unitId));
|
||||
}
|
||||
m_ui->leCallSign->setText(QString::fromStdString(cnrConfig.callSign()));
|
||||
m_ui->chkRecording->setChecked(cnrConfig.recording());
|
||||
m_ui->leRadioCircuit->setText(QString::fromStdString(cnrConfig.radioCircuit()));
|
||||
onPartyIndexChanged(cnrConfig.partyId());
|
||||
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::setUiValuesForGlobal()
|
||||
{
|
||||
m_ui->chkGlobal->setChecked(true);
|
||||
m_ui->cbUnit->setEnabled(false);
|
||||
m_ui->lbUnit->setEnabled(false);
|
||||
|
||||
|
||||
m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(1));
|
||||
m_ui->cbParty->setEnabled(false);
|
||||
m_ui->lbParty->setEnabled(false);
|
||||
}
|
||||
|
||||
ModifyCnrConfigRequest EditCombatNetRadioDialog::createRequest()
|
||||
{
|
||||
ModifyCnrConfigRequest request;
|
||||
|
||||
request.id(m_id.get_value_or(0));
|
||||
request.callSign(m_ui->leCallSign->text().toStdString());
|
||||
request.cnrChannelId(m_ui->cbChannel->currentData().toInt());
|
||||
request.radioCircuit(m_ui->leRadioCircuit->text().toStdString());
|
||||
request.recording(m_ui->chkRecording->isChecked());
|
||||
request.partyId(m_ui->cbParty->currentData().toInt());
|
||||
if (!m_isGlobal)
|
||||
request.exerciseId(m_exerciseId);
|
||||
if (m_ui->cbUnit->currentIndex() > 0)
|
||||
request.unitId().set(m_ui->cbUnit->currentIndex());
|
||||
return request;
|
||||
}
|
||||
|
||||
bool EditCombatNetRadioDialog::apply()
|
||||
{
|
||||
ModifyCnrConfigRequest request = createRequest();
|
||||
|
||||
if (m_ui->cbUnit->currentIndex() > 0)
|
||||
{
|
||||
request.unitId().set(m_ui->cbUnit->currentData().toInt());
|
||||
INFO_LOG(m_logger)<< "currentIndex="<<m_ui->cbUnit->currentIndex()
|
||||
<< " unitId ="<<request.unitId().get();
|
||||
}
|
||||
|
||||
return m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->modifyCnrConfigRequest(request, this);
|
||||
});
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::init(LtsSession::LtsSession *session)
|
||||
{
|
||||
m_units = m_ppmDtc->units();
|
||||
|
||||
QMap<qint32, ParticipantManagement::Party> parties;
|
||||
if (!m_ppmDtc->visibleParties(parties, LtsSessionData::LtsSessionData::getInstance()->getVisibleParties(m_exerciseId)))
|
||||
ERROR_LOG(m_logger) << "Could not retrieve visible Parties!";
|
||||
|
||||
for (const ParticipantManagement::Party &party : qAsConst(parties))
|
||||
m_ui->cbParty->addItem(ParticipantManagement::trPartyName(party.name()), party.id());
|
||||
|
||||
connect(m_ui->cbParty, QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &EditCombatNetRadioDialog::onPartyIndexChanged);
|
||||
connect(m_ui->cbChannel, QOverload<int>::of(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &EditCombatNetRadioDialog::onChannelChanged);
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::cnrConfigChanged, this, &EditCombatNetRadioDialog::updateFreeChannelsAndTakenNames);
|
||||
connect(m_exmDtc, &ExerciseManagement::Interface::Dtc::exerciseChanged, this, &EditCombatNetRadioDialog::updateFreeChannelsAndTakenNames);
|
||||
|
||||
onPartyIndexChanged(m_ui->cbParty->currentIndex());
|
||||
|
||||
|
||||
m_buttonBox->connectLibraryButton(this,
|
||||
&EditCombatNetRadioDialog::onImportButtonClicked,
|
||||
&EditCombatNetRadioDialog::onExportButtonClicked);
|
||||
|
||||
if (!session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
|
||||
|
||||
|
||||
m_uiRequirements->addRequirement({m_ui->lbRadioCircuit, [this] () { return isNameValid(m_ui->leRadioCircuit->text()); }, tr("name invalid")});
|
||||
m_uiRequirements->addRequirement({m_ui->lbChannel, [this] () { return m_ui->cbChannel->currentData().toInt() > 0; }, tr("channel invalid")});
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::initCbChannelsForCreate()
|
||||
{
|
||||
Q_ASSERT(!m_id.is_initialized());
|
||||
Q_ASSERT(m_ui->cbChannel->count() == 0);
|
||||
updateFreeChannelsAndTakenNames();
|
||||
if (m_ui->cbChannel->count())
|
||||
m_ui->cbChannel->setCurrentIndex(0);
|
||||
else
|
||||
m_ui->cbChannel->addItem(NO_CHANNEL(), -1);
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::initCbChannels(int channelId)
|
||||
{
|
||||
m_ui->cbChannel->clear();
|
||||
updateFreeChannelsAndTakenNames();
|
||||
m_ui->cbChannel->setCurrentIndex(m_ui->cbChannel->findData(channelId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EditCombatNetRadioDialog::updateFreeChannelsAndTakenNames()
|
||||
{
|
||||
const auto exercisesConsider = exercisesToConsider();
|
||||
const auto exercisesIgnore = exercisesToIgnore();
|
||||
|
||||
m_takenNames.clear();
|
||||
|
||||
QVector<int> freeChannels = m_avmDtc->cnrChannels().keys().toVector();
|
||||
QMap<int, QString> channelsToDisable;
|
||||
QMap<int, QString> exerciseNameCache;
|
||||
const auto allCnrConfigs = m_avmDtc->cnrConfigs();
|
||||
const ExerciseManagement::Exercise ownExercise = m_exmDtc->exercise(m_exerciseId);
|
||||
ExerciseManagement::ExerciseState ownState = m_exmDtc->exercise(m_exerciseId).state();
|
||||
|
||||
for (const AudioVideoManagement::CnrConfig &cnrConfig : allCnrConfigs)
|
||||
{
|
||||
if (m_id.is_initialized() && *m_id == cnrConfig.id())
|
||||
continue;
|
||||
|
||||
if (ownExercise.state() == ExerciseManagement::ExerciseState::Created && cnrConfig.exerciseId() != m_exerciseId)
|
||||
{
|
||||
if (ownExercise.linkedExerciseId() < 1 || cnrConfig.exerciseId() != ownExercise.linkedExerciseId())
|
||||
continue;
|
||||
|
||||
if (!exerciseNameCache.contains(ownExercise.linkedExerciseId()))
|
||||
exerciseNameCache.insert(ownExercise.linkedExerciseId(), QString::fromStdString(m_exmDtc->exercise(ownExercise.linkedExerciseId()).name()));
|
||||
|
||||
channelsToDisable.insert(cnrConfig.cnrChannelId(), tr("(already taken in %1)").arg(exerciseNameCache.value(ownExercise.linkedExerciseId())));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ownExercise.state() == ExerciseManagement::ExerciseState::Started || ownExercise.state() == ExerciseManagement::ExerciseState::Paused)
|
||||
{
|
||||
if (cnrConfig.exerciseId().is_set())
|
||||
{
|
||||
int cnrExerciseId = cnrConfig.exerciseId().get();
|
||||
|
||||
if (exercisesConsider.contains(cnrExerciseId) && cnrExerciseId != m_exerciseId)
|
||||
{
|
||||
if (!exerciseNameCache.contains(cnrExerciseId))
|
||||
exerciseNameCache.insert(cnrExerciseId, QString::fromStdString(m_exmDtc->exercise(cnrExerciseId).name()));
|
||||
|
||||
channelsToDisable.insert(cnrConfig.cnrChannelId(), tr("(already taken in %1)").arg(exerciseNameCache.value(cnrExerciseId)));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_isGlobal)
|
||||
{
|
||||
if (cnrConfig.exerciseId().is_set() && !exercisesConsider.contains(cnrConfig.exerciseId().get()))
|
||||
continue;
|
||||
|
||||
if (!cnrConfig.exerciseId().is_set() && ownState != ExerciseManagement::ExerciseState::Created)
|
||||
{
|
||||
channelsToDisable.insert(cnrConfig.cnrChannelId(), tr("(already taken in global exercise)"));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_isGlobal && cnrConfig.exerciseId().is_set() && exercisesConsider.contains(cnrConfig.exerciseId().get()))
|
||||
{
|
||||
int exerciseId = cnrConfig.exerciseId().get();
|
||||
|
||||
if (!exerciseNameCache.contains(exerciseId))
|
||||
exerciseNameCache.insert(exerciseId, QString::fromStdString(m_exmDtc->exercise(exerciseId).name()));
|
||||
|
||||
channelsToDisable.insert(cnrConfig.cnrChannelId(), tr("(already taken in %1)").arg(exerciseNameCache.value(exerciseId)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cnrConfig.exerciseId().is_set() && exercisesIgnore.contains(cnrConfig.exerciseId().get()))
|
||||
continue;
|
||||
|
||||
m_takenNames.push_back(QString::fromStdString(cnrConfig.radioCircuit()));
|
||||
|
||||
freeChannels.removeOne(cnrConfig.cnrChannelId());
|
||||
}
|
||||
|
||||
if (m_id.is_initialized())
|
||||
{
|
||||
if (freeChannels.contains(*m_channelId))
|
||||
updateCbChannels({*m_channelId}, {});
|
||||
else
|
||||
updateCbChannels({},{});
|
||||
}
|
||||
else
|
||||
updateCbChannels(std::move(freeChannels), std::move(channelsToDisable));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EditCombatNetRadioDialog::updateCbChannels(QVector<int> &&freeChannels, QMap<int, QString> &&channelsToDisable)
|
||||
{
|
||||
const auto allChannels = m_avmDtc->cnrChannels();
|
||||
|
||||
const auto byName = [&allChannels] (int leftChannelId, int rightChannelId) { return QLatin1String(allChannels[leftChannelId].name().c_str()) < QLatin1String(allChannels[rightChannelId].name().c_str()); };
|
||||
std::sort(freeChannels.begin(), freeChannels.end(), byName);
|
||||
|
||||
bool bOk;
|
||||
int currentlySelectedChannelId = m_ui->cbChannel->currentData().toInt(&bOk);
|
||||
|
||||
if (!bOk)
|
||||
{
|
||||
currentlySelectedChannelId = -1;
|
||||
|
||||
if (freeChannels.count() && channelsToDisable.contains(freeChannels.at(0)))
|
||||
{
|
||||
currentlySelectedChannelId = freeChannels.at(0);
|
||||
|
||||
while (channelsToDisable.contains(currentlySelectedChannelId))
|
||||
{
|
||||
int channelIndex = freeChannels.indexOf(currentlySelectedChannelId);
|
||||
|
||||
if (channelIndex == freeChannels.size() - 1)
|
||||
{
|
||||
currentlySelectedChannelId = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
currentlySelectedChannelId = freeChannels.at(channelIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->cbChannel->clear();
|
||||
for (const auto &channelId : freeChannels)
|
||||
{
|
||||
QString channelName = QString::fromStdString(allChannels[channelId].name());
|
||||
|
||||
if (channelsToDisable.contains(channelId))
|
||||
{
|
||||
QString text = QLatin1String("%1 %2").arg(channelName).arg(channelsToDisable.value(channelId));
|
||||
m_ui->cbChannel->addItem(text, channelId);
|
||||
|
||||
auto * model = qobject_cast<QStandardItemModel*>(m_ui->cbChannel->model());
|
||||
|
||||
if(!model)
|
||||
continue;
|
||||
|
||||
auto * item = model->item(m_ui->cbChannel->count() - 1);
|
||||
|
||||
if(!item)
|
||||
continue;
|
||||
|
||||
item->setEnabled(false);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
m_ui->cbChannel->addItem(channelName, channelId);
|
||||
}
|
||||
|
||||
if (!m_ui->cbChannel->count())
|
||||
m_ui->cbChannel->addItem(NO_CHANNEL(), -1);
|
||||
else if (freeChannels.size() == 1)
|
||||
m_ui->cbChannel->setCurrentIndex(m_ui->cbChannel->findData(currentlySelectedChannelId));
|
||||
else if (currentlySelectedChannelId != -1)
|
||||
QTimer::singleShot(100, this, [this, currentlySelectedChannelId] () { m_ui->cbChannel->setCurrentIndex(m_ui->cbChannel->findData(currentlySelectedChannelId)); });
|
||||
}
|
||||
|
||||
|
||||
|
||||
QVector<int> EditCombatNetRadioDialog::exercisesToConsider() const
|
||||
{
|
||||
auto isActive = [](ExerciseManagement::ExerciseState state) -> bool
|
||||
{
|
||||
return (state == ExerciseManagement::ExerciseState::Started ||
|
||||
state == ExerciseManagement::ExerciseState::Paused);
|
||||
};
|
||||
|
||||
const auto allExercises = m_exmDtc->exercises();
|
||||
const ExerciseManagement::Exercise ¤tExercise = allExercises.value(m_exerciseId);
|
||||
QVector<int> toBeConsidered;
|
||||
toBeConsidered.reserve(allExercises.size());
|
||||
|
||||
if (!m_isGlobal && currentExercise.state() == ExerciseManagement::ExerciseState::Created)
|
||||
{
|
||||
toBeConsidered.append(currentExercise.id());
|
||||
|
||||
if (currentExercise.linkedExerciseId() > 0)
|
||||
toBeConsidered.append(currentExercise.linkedExerciseId());
|
||||
|
||||
return toBeConsidered;
|
||||
}
|
||||
|
||||
if (!m_isGlobal && !isActive(allExercises[m_exerciseId].state()))
|
||||
return {m_exerciseId};
|
||||
|
||||
for (const auto &exercise : allExercises)
|
||||
{
|
||||
if (isActive(exercise.state()))
|
||||
toBeConsidered.append(exercise.id());
|
||||
}
|
||||
|
||||
return toBeConsidered;
|
||||
}
|
||||
|
||||
QVector<int> EditCombatNetRadioDialog::exercisesToIgnore() const
|
||||
{
|
||||
const auto allExercises = m_exmDtc->exercises();
|
||||
|
||||
auto canBeIgnored = [this] (const ExerciseManagement::Exercise &ex) -> bool
|
||||
{
|
||||
if (m_isGlobal)
|
||||
{
|
||||
return (ex.state() == ExerciseManagement::ExerciseState::Created ||
|
||||
ex.state() == ExerciseManagement::ExerciseState::Stopped ||
|
||||
ex.state() == ExerciseManagement::ExerciseState::Terminated ||
|
||||
ex.isDeleted());
|
||||
}
|
||||
return (ex.state() == ExerciseManagement::ExerciseState::Stopped ||
|
||||
ex.state() == ExerciseManagement::ExerciseState::Terminated ||
|
||||
ex.isDeleted());
|
||||
};
|
||||
|
||||
QVector<int> exercisesToIgnore;
|
||||
for (const auto &ex : allExercises)
|
||||
{
|
||||
if (canBeIgnored(ex))
|
||||
exercisesToIgnore += ex.id();
|
||||
}
|
||||
return exercisesToIgnore;
|
||||
}
|
||||
|
||||
|
||||
bool EditCombatNetRadioDialog::isNameValid(const QString &name) const
|
||||
{
|
||||
if (!isStreamNameValid(name))
|
||||
return false;
|
||||
if (m_takenNames.contains(name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::onPartyIndexChanged(int index)
|
||||
{
|
||||
m_ui->cbUnit->clear();
|
||||
|
||||
m_ui->cbUnit->addItem(QLatin1String("-"), QVariant::fromValue(0));
|
||||
|
||||
int32_t partyId = m_ui->cbParty->itemData(index).toInt();
|
||||
|
||||
for (const ParticipantManagement::Participant &unit : qAsConst(m_units))
|
||||
{
|
||||
QString unitStr;
|
||||
if (unit.partyId() == partyId)
|
||||
{
|
||||
if (unit.designator().size() > 0)
|
||||
{
|
||||
unitStr = QString::fromStdString(unit.designator()) + QLatin1Char('/');
|
||||
INFO_LOG(m_logger)<<"Designator != leer: unitStr = " << unitStr;
|
||||
}
|
||||
unitStr += QString::fromStdString(unit.tacticalIdentifier());
|
||||
INFO_LOG(m_logger) << "unitStr =" << unitStr
|
||||
<< " id =" << unit.id();
|
||||
|
||||
m_ui->cbUnit->addItem(unitStr, unit.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::onChannelChanged(int index)
|
||||
{
|
||||
int channelId = m_ui->cbChannel->itemData(index).toInt();
|
||||
|
||||
bool disableParty = (m_avmDtc->cnrChannel(channelId).frequencyBand() == FrequencyBand_def::REL) || m_isGlobal;
|
||||
m_ui->cbUnit->setDisabled(disableParty);
|
||||
m_ui->lbUnit->setDisabled(disableParty);
|
||||
m_ui->cbParty->setDisabled(disableParty);
|
||||
m_ui->lbParty->setDisabled(disableParty);
|
||||
if(disableParty && !m_isGlobal)
|
||||
{
|
||||
m_ui->cbParty->addItem(QStringLiteral("-"));
|
||||
m_ui->cbParty->setCurrentText(QStringLiteral("-"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QByteArray EditCombatNetRadioDialog::cnrConfigRequestToJson()
|
||||
{
|
||||
ModifyCnrConfigRequest req = createRequest();
|
||||
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("id")] = req.id();
|
||||
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::AVMEditCombatNetRadio);
|
||||
obj[QStringLiteral("callSign")] = QString::fromStdString(req.callSign());
|
||||
obj[QStringLiteral("cnrChannelId")] = req.cnrChannelId();
|
||||
obj[QStringLiteral("radioCircuit")] = QString::fromStdString(req.radioCircuit());
|
||||
obj[QStringLiteral("recording")] = req.recording();
|
||||
obj[QStringLiteral("partyId")] = req.partyId();
|
||||
obj[QStringLiteral("isGlobal")] = !req.exerciseId().is_set();
|
||||
if (req.unitId().is_set())
|
||||
obj[QStringLiteral("unitId")] = req.unitId().get();
|
||||
QJsonDocument doc(obj);
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
ModifyCnrConfigRequest EditCombatNetRadioDialog::jsonToModifyCnrConfig(const QByteArray &content)
|
||||
{
|
||||
ModifyCnrConfigRequest result;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(content));
|
||||
const QJsonObject obj(doc.object());
|
||||
|
||||
result.id(obj[QStringLiteral("id")].toInt());
|
||||
result.callSign(obj[QStringLiteral("callSign")].toString().toStdString());
|
||||
result.cnrChannelId(obj[QStringLiteral("cnrChannelId")].toInt());
|
||||
result.radioCircuit(obj[QStringLiteral("radioCircuit")].toString().toStdString());
|
||||
result.recording(obj[QStringLiteral("recording")].toInt());
|
||||
result.partyId(obj[QStringLiteral("partyId")].toInt());
|
||||
if (!obj.contains(QLatin1String("isGlobal")) || !obj[QLatin1String("isGlobal")].toBool())
|
||||
result.exerciseId(m_exerciseId);
|
||||
if (obj.contains(QStringLiteral("unitId")))
|
||||
result.unitId(obj[QStringLiteral("unitId")].toInt());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::onExportButtonClicked()
|
||||
{
|
||||
QByteArray byteArray = cnrConfigRequestToJson();
|
||||
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_exerciseId, byteArray);
|
||||
if (fileId > 0)
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
}
|
||||
|
||||
void EditCombatNetRadioDialog::onImportButtonClicked()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " onImportButtonClicked() ";
|
||||
|
||||
QByteArray content;
|
||||
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_exerciseId, FileManagement::toString(FileManagement::XmlType::AVMEditCombatNetRadio));
|
||||
if (fileId > 0)
|
||||
{
|
||||
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::AVMEditCombatNetRadio)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModifyCnrConfigRequest req = jsonToModifyCnrConfig(content);
|
||||
setUiValues(toConfig(req));
|
||||
INFO_LOG(m_logger) << "--- onImportButtonClicked() ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditCombatNetRadioDialog;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class EditCombatNetRadioDialog
|
||||
: public LtsWidgets::LtsDialog
|
||||
, protected Interface::Ftc::ModifyCnrConfigReplyHandler
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
explicit EditCombatNetRadioDialog(int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent);
|
||||
|
||||
|
||||
|
||||
explicit EditCombatNetRadioDialog(const CnrConfig &cnrConfig,
|
||||
int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent);
|
||||
|
||||
~EditCombatNetRadioDialog();
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
void onModifyCnrConfigReply(const Core::FunctionReplyObject &replyObject) override final { m_requestHelper->requestReply(replyObject); }
|
||||
|
||||
protected:
|
||||
bool apply() override;
|
||||
|
||||
private:
|
||||
EditCombatNetRadioDialog(const boost::optional<int32_t> &id,
|
||||
int32_t exerciseId,
|
||||
LtsSession::LtsSession *session,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent);
|
||||
|
||||
void init(LtsSession::LtsSession *session);
|
||||
|
||||
void initCbChannelsForCreate();
|
||||
void initCbChannels(int channelId);
|
||||
void updateFreeChannelsAndTakenNames();
|
||||
void updateCbChannels(QVector<int> &&freeChannels, QMap<int, QString> &&channelsToDisable);
|
||||
QVector<int> exercisesToConsider() const;
|
||||
QVector<int> exercisesToIgnore() const;
|
||||
bool isNameValid(const QString &name) const;
|
||||
|
||||
QByteArray cnrConfigRequestToJson();
|
||||
ModifyCnrConfigRequest createRequest();
|
||||
ModifyCnrConfigRequest jsonToModifyCnrConfig(const QByteArray &content);
|
||||
void setUiValues(const CnrConfig &cnrConfig);
|
||||
void setUiValuesForGlobal();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPartyIndexChanged(int index);
|
||||
void onExportButtonClicked();
|
||||
void onImportButtonClicked();
|
||||
void onChannelChanged(int index);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::EditCombatNetRadioDialog> m_ui;
|
||||
boost::optional<int32_t> m_id;
|
||||
int32_t m_exerciseId;
|
||||
boost::optional<int32_t> m_channelId;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<Interface::Ftc> m_avmFtc;
|
||||
ExerciseManagement::Interface::Dtc *m_exmDtc;
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
|
||||
QMap<int32_t, ParticipantManagement::Participant> m_units;
|
||||
QVector<QString> m_takenNames;
|
||||
std::unique_ptr<LtsUtils::RequestHelper> m_requestHelper;
|
||||
bool m_isGlobal;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditCombatNetRadioDialog</class>
|
||||
<widget class="QWidget" name="EditCombatNetRadioDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>459</width>
|
||||
<height>275</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Asset Stocks</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbChannel">
|
||||
<property name="text">
|
||||
<string>Channel Number:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbChannel"/>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="4">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="lbRecording">
|
||||
<property name="text">
|
||||
<string>Recording:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QCheckBox" name="chkRecording">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbRadioCircuit">
|
||||
<property name="text">
|
||||
<string>Radio Circuit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="leRadioCircuit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Radio Circuit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="lbParty">
|
||||
<property name="text">
|
||||
<string>Party:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbParty">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbCallSign">
|
||||
<property name="text">
|
||||
<string>Code Word:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="leCallSign">
|
||||
<property name="toolTip">
|
||||
<string>Code Word</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="lbUnit">
|
||||
<property name="text">
|
||||
<string>Unit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbUnit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lbGlobal">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Global:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="chkGlobal">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>cbChannel</tabstop>
|
||||
<tabstop>leRadioCircuit</tabstop>
|
||||
<tabstop>leCallSign</tabstop>
|
||||
<tabstop>cbParty</tabstop>
|
||||
<tabstop>cbUnit</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_load_combat_net_radio_dialog.h"
|
||||
#include "ui_avm_load_combat_net_radio_dialog.h"
|
||||
|
||||
#include "avm_cnr_json_helper.h"
|
||||
#include "avm_load_combat_net_radio_dialog_model.h"
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
LoadCombatNetRadioDialog::LoadCombatNetRadioDialog(const QByteArray &data,
|
||||
LtsSession::LtsSession *session,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
|
||||
, m_ui(new Ui::LoadCombatNetRadioDialog)
|
||||
, m_model(new LoadCombatNetRadioDialogModel(data, session))
|
||||
, m_logger(getLogger("LoadCombatNetRadioDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->dataView->setModel(m_model);
|
||||
m_ui->cbAll->setChecked(m_model->allChecked());
|
||||
|
||||
connect(m_ui->cbAll, &QCheckBox::clicked,
|
||||
m_model, &LoadCombatNetRadioDialogModel::setCheckState);
|
||||
connect(m_model, &LoadCombatNetRadioDialogModel::dataChanged,
|
||||
this, [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
|
||||
{
|
||||
if (!roles.contains(Qt::CheckStateRole)
|
||||
|| topLeft.column() != 0
|
||||
|| bottomRight.column() != 0
|
||||
|| m_ui->cbAll->isChecked() == m_model->allChecked())
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker(m_ui->cbAll);
|
||||
|
||||
Q_UNUSED(blocker);
|
||||
|
||||
m_ui->cbAll->setChecked(!m_ui->cbAll->isChecked());
|
||||
});
|
||||
connect(m_ui->pbOk, &QPushButton::clicked,
|
||||
this, &LoadCombatNetRadioDialog::onOk);
|
||||
connect(m_ui->pbCancel, &QPushButton::clicked,
|
||||
this, &LoadCombatNetRadioDialog::close);
|
||||
}
|
||||
|
||||
QVector<Core::RemoveElementRequest> LoadCombatNetRadioDialog::removeRequests() const
|
||||
{
|
||||
if (m_isApplied)
|
||||
return m_model->removeRequests();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QVector<ModifyCnrConfigRequest> LoadCombatNetRadioDialog::modifyRequests() const
|
||||
{
|
||||
if (m_isApplied)
|
||||
return m_model->modifyRequests();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialog::isApplied() const
|
||||
{
|
||||
return m_isApplied;
|
||||
}
|
||||
|
||||
void LoadCombatNetRadioDialog::onOk()
|
||||
{
|
||||
m_isApplied = true;
|
||||
close();
|
||||
}
|
||||
|
||||
LoadCombatNetRadioDialog::~LoadCombatNetRadioDialog() = default;
|
||||
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_frameless_dialog.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class LoadCombatNetRadioDialog;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class LoadCombatNetRadioDialogModel;
|
||||
|
||||
class LoadCombatNetRadioDialog
|
||||
: public LtsWidgets::LtsFramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LoadCombatNetRadioDialog(const QByteArray &data,
|
||||
LtsSession::LtsSession *session,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
~LoadCombatNetRadioDialog();
|
||||
|
||||
QVector<Core::RemoveElementRequest> removeRequests() const;
|
||||
QVector<ModifyCnrConfigRequest> modifyRequests() const;
|
||||
|
||||
bool isApplied() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onOk();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::LoadCombatNetRadioDialog> m_ui;
|
||||
LoadCombatNetRadioDialogModel *m_model;
|
||||
bool m_isApplied = false;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LoadCombatNetRadioDialog</class>
|
||||
<widget class="QWidget" name="LoadCombatNetRadioDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>922</width>
|
||||
<height>376</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Load Cnr Configs</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbAll">
|
||||
<property name="text">
|
||||
<string>Check/Uncheck all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="dataView" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbOk">
|
||||
<property name="text">
|
||||
<string>Ok</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbCancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_load_combat_net_radio_dialog_model.h"
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <Core/core.hpp>
|
||||
|
||||
#include <FileManagement/flm_translation.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include "avm_cnr_json_helper.h"
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <ExerciseManagement/exm_data_plugin_interface.h>
|
||||
#include <AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
LoadCombatNetRadioDialogModel::LoadCombatNetRadioDialogModel(const QByteArray &data,
|
||||
LtsSession::LtsSession *session,
|
||||
QObject *parent)
|
||||
: LtsAbstractTableModel<CnrConfig>(
|
||||
{
|
||||
tr("Include"),
|
||||
tr("Channel"),
|
||||
tr("Radio Circuit"),
|
||||
tr("Code Word"),
|
||||
tr("Conflict(s)")
|
||||
}, parent)
|
||||
, m_exerciseId(session == nullptr ? 0 : session->exerciseId())
|
||||
, m_logger(getLogger("LoadCombatNetRadioDialogModel"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "Own exercise id: " << m_exerciseId;
|
||||
|
||||
if (session != nullptr)
|
||||
{
|
||||
std::shared_ptr<AudioVideoManagement::Interface::Dtc> avmDtc;
|
||||
|
||||
if (!session->getDtc<AudioVideoManagement::DataInterface>(avmDtc)
|
||||
|| !avmDtc->enableCnrChannel()
|
||||
|| !avmDtc->enableCnrConfig())
|
||||
ERROR_LOG(m_logger) << "Could not get AVM data";
|
||||
else
|
||||
{
|
||||
m_cnrChannels = avmDtc->cnrChannels();
|
||||
m_cnrConfigs = avmDtc->cnrConfigs();
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "cnrconfigs: " << m_cnrConfigs.size();
|
||||
DEBUG_LOG(m_logger) << "ownExerciseId: " << m_exerciseId;
|
||||
|
||||
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
|
||||
|
||||
if (!session->getDtc<ExerciseManagement::DataInterface>(exmDtc)
|
||||
|| !exmDtc->enableExercise())
|
||||
ERROR_LOG(m_logger) << "Could not get EXM data";
|
||||
else
|
||||
m_exercises = exmDtc->exercises();
|
||||
|
||||
DEBUG_LOG(m_logger) << "exercises: " << m_exercises.size();
|
||||
}
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Got invalid session.";
|
||||
|
||||
m_vecData = jsonToCnrConfigVector(data);
|
||||
|
||||
m_includeStates.reserve(m_vecData.size());
|
||||
m_conflicts.reserve(m_vecData.size());
|
||||
|
||||
for (int32_t idxCounter = 0; idxCounter < m_vecData.size(); ++idxCounter)
|
||||
{
|
||||
Conflicts conflicts = getConflicts(idxCounter, m_vecData.at(idxCounter));
|
||||
|
||||
m_conflicts.append(conflicts);
|
||||
m_includeStates.append(conflicts == NO_CONFLICT ? Qt::Checked : Qt::Unchecked);
|
||||
|
||||
if (conflicts & CHANNEL_TAKEN_IN_GLOBAL || conflicts & RADIO_CIRCUIT_TAKEN_IN_GLOBAL)
|
||||
m_disabledRows.append(idxCounter);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags LoadCombatNetRadioDialogModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (indexIsValid(index) && m_disabledRows.contains(index.row()))
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
if (index.column() > 0)
|
||||
return LtsAbstractTableModel::flags(index);
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | LtsAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (indexIsValid(index)
|
||||
&& role == Qt::CheckStateRole
|
||||
&& index.column() == 0
|
||||
&& value.canConvert<Qt::CheckState>())
|
||||
{
|
||||
m_includeStates[index.row()] = value.value<Qt::CheckState>();
|
||||
|
||||
emit dataChanged(index, index, {role});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return QAbstractTableModel::setData(index, value, role);
|
||||
}
|
||||
|
||||
QVariant LoadCombatNetRadioDialogModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
const CnrConfig &config = m_vecData.at(index.row());
|
||||
switch (index.column())
|
||||
{
|
||||
case CHANNEL:
|
||||
return QString::fromStdString(m_cnrChannels.value(config.cnrChannelId()).name());
|
||||
case RADIO_CIRCUIT:
|
||||
return QString::fromStdString(config.radioCircuit());
|
||||
case CALL_SIGN:
|
||||
return QString::fromStdString(config.callSign());
|
||||
case CONFLICTS:
|
||||
return conflictsText(m_conflicts.at(index.row()));
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::CheckStateRole:
|
||||
if (index.column() != 0)
|
||||
return QVariant();
|
||||
return m_includeStates.at(index.row());
|
||||
case Qt::BackgroundRole:
|
||||
return getConflictsRowColor(m_conflicts.at(index.row()));
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::allChecked() const
|
||||
{
|
||||
for (int32_t row = 0; row < m_includeStates.size(); ++row)
|
||||
{
|
||||
if (m_disabledRows.contains(row))
|
||||
continue;
|
||||
|
||||
if (m_includeStates.at(row) == Qt::Unchecked)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadCombatNetRadioDialogModel::setCheckState(bool isChecked)
|
||||
{
|
||||
const QVariant data = QVariant(isChecked ? Qt::Checked : Qt::Unchecked);
|
||||
const int role = Qt::CheckStateRole;
|
||||
|
||||
for (int32_t row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
if (m_disabledRows.contains(row))
|
||||
continue;
|
||||
|
||||
setData(createIndex(row, 0), data, role);
|
||||
}
|
||||
}
|
||||
|
||||
LoadCombatNetRadioDialogModel::Conflicts LoadCombatNetRadioDialogModel::getConflicts(int32_t row, const CnrConfig &config)
|
||||
{
|
||||
Conflicts conflicts = NO_CONFLICT;
|
||||
|
||||
for (auto it = m_cnrConfigs.constBegin(); it != m_cnrConfigs.constEnd(); ++it)
|
||||
{
|
||||
if (!(conflicts & RADIO_CIRCUIT_TAKEN_IN_OWN_CONFIG) && isRadioCircuitTakenInOwnConfig(config, it.value()))
|
||||
{
|
||||
conflicts |= RADIO_CIRCUIT_TAKEN_IN_OWN_CONFIG;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & RADIO_CIRCUIT_TAKEN_IN_ANOTHER_EXERCISE) && isRadioCircuitTakenInAnotherExercise(config, it.value()))
|
||||
{
|
||||
conflicts |= RADIO_CIRCUIT_TAKEN_IN_ANOTHER_EXERCISE;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & CHANNEL_TAKEN_IN_ACTIVE_EXERCISE) && isChannelTakenInActiveExercise(config, it.value()))
|
||||
{
|
||||
conflicts |= CHANNEL_TAKEN_IN_ACTIVE_EXERCISE;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & CHANNEL_TAKEN_IN_LINKED_EXERCISE) && isChannelTakenInLinkedExercise(config, it.value()))
|
||||
{
|
||||
conflicts |= CHANNEL_TAKEN_IN_LINKED_EXERCISE;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & CHANNEL_TAKEN_IN_OWN_CONFIG) && isChannelTakenInOwnConfig(config, it.value()))
|
||||
{
|
||||
conflicts |= CHANNEL_TAKEN_IN_OWN_CONFIG;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & CHANNEL_TAKEN_IN_GLOBAL) && isChannelTakenInGlobal(config, it.value()))
|
||||
{
|
||||
conflicts |= CHANNEL_TAKEN_IN_GLOBAL;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
|
||||
if (!(conflicts & RADIO_CIRCUIT_TAKEN_IN_GLOBAL) && isRadioCircuitTakenInGlobal(config, it.value()))
|
||||
{
|
||||
conflicts |= RADIO_CIRCUIT_TAKEN_IN_GLOBAL;
|
||||
addConflictedCnr(row, it.value().id());
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
QString LoadCombatNetRadioDialogModel::conflictsText(Conflicts conflicts) const
|
||||
{
|
||||
QStringList conflictTexts;
|
||||
|
||||
if (conflicts & RADIO_CIRCUIT_TAKEN_IN_OWN_CONFIG)
|
||||
conflictTexts.append(tr("Radio Circuit is already taken in own config."));
|
||||
|
||||
if (conflicts & RADIO_CIRCUIT_TAKEN_IN_ANOTHER_EXERCISE)
|
||||
conflictTexts.append(tr("Radio Circuit is already taken in another exercise."));
|
||||
|
||||
if (conflicts & CHANNEL_TAKEN_IN_ACTIVE_EXERCISE)
|
||||
conflictTexts.append(tr("Channel already taken in active exercise."));
|
||||
|
||||
if (conflicts & CHANNEL_TAKEN_IN_LINKED_EXERCISE)
|
||||
conflictTexts.append(tr("Channel already taken in linked exercise."));
|
||||
|
||||
if (conflicts & CHANNEL_TAKEN_IN_OWN_CONFIG)
|
||||
conflictTexts.append(tr("Channel is already taken in own Cnr Config."));
|
||||
|
||||
if (conflicts & CHANNEL_TAKEN_IN_GLOBAL)
|
||||
conflictTexts.append(tr("Channel already taken in global Cnr Config."));
|
||||
|
||||
if (conflicts & RADIO_CIRCUIT_TAKEN_IN_GLOBAL)
|
||||
conflictTexts.append(tr("Radio Circuit already taken in global Cnr Config."));
|
||||
|
||||
return conflictTexts.isEmpty() ? QLatin1String("-") : conflictTexts.join(QLatin1Char('\n'));
|
||||
}
|
||||
|
||||
void LoadCombatNetRadioDialogModel::addConflictedCnr(int32_t row, int32_t cnrConfigId)
|
||||
{
|
||||
m_conflictedCnrIds[row].append(cnrConfigId);
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isActiveExercise(int32_t exerciseId) const
|
||||
{
|
||||
if (exerciseId == 0)
|
||||
return true;
|
||||
|
||||
using namespace ExerciseManagement;
|
||||
|
||||
ExerciseState exerciseState = m_exercises.value(exerciseId).state();
|
||||
|
||||
return exerciseState == ExerciseState::Started || exerciseState == ExerciseState::Paused;
|
||||
}
|
||||
|
||||
QColor LoadCombatNetRadioDialogModel::getConflictsRowColor(Conflicts conflicts) const
|
||||
{
|
||||
if (conflicts >= CHANNEL_TAKEN_IN_GLOBAL)
|
||||
return QColor(Qt::red).lighter();
|
||||
|
||||
if (conflicts > NO_CONFLICT)
|
||||
return QColor(Qt::yellow).lighter();
|
||||
|
||||
return QColor(Qt::green).lighter();
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isRadioCircuitTakenInOwnConfig(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
if (m_exerciseId == 0)
|
||||
return !existingConfig.exerciseId().is_set() && existingConfig.radioCircuit() == loadConfig.radioCircuit();
|
||||
|
||||
if (!existingConfig.exerciseId().is_set()
|
||||
|| existingConfig.exerciseId().get() != m_exerciseId
|
||||
|| existingConfig.radioCircuit() != loadConfig.radioCircuit())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isRadioCircuitTakenInAnotherExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
if (!isActiveExercise(m_exerciseId)
|
||||
|| !existingConfig.exerciseId().is_set()
|
||||
|| !isActiveExercise(existingConfig.exerciseId().get())
|
||||
|| existingConfig.exerciseId().get() == m_exerciseId
|
||||
|| existingConfig.radioCircuit() != loadConfig.radioCircuit())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isChannelTakenInActiveExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
int32_t exerciseId = existingConfig.exerciseId().is_set() ? existingConfig.exerciseId().get() : 0;
|
||||
|
||||
if (!isActiveExercise(m_exerciseId)
|
||||
|| exerciseId == 0
|
||||
|| exerciseId == m_exerciseId
|
||||
|| !isActiveExercise(exerciseId)
|
||||
|| existingConfig.cnrChannelId() != loadConfig.cnrChannelId()
|
||||
|| !isActiveExercise(exerciseId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isChannelTakenInLinkedExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
if (m_exerciseId == 0 || m_exercises.value(m_exerciseId).linkedExerciseId() == 0)
|
||||
return false;
|
||||
|
||||
int32_t linkedExerciseId = m_exercises.value(m_exerciseId).linkedExerciseId();
|
||||
|
||||
int32_t exerciseId = existingConfig.exerciseId().is_set() ? existingConfig.exerciseId().get() : 0;
|
||||
|
||||
if (exerciseId != linkedExerciseId || existingConfig.cnrChannelId() != loadConfig.cnrChannelId())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isChannelTakenInOwnConfig(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
int32_t exerciseId = existingConfig.exerciseId().is_set() ? existingConfig.exerciseId().get() : 0;
|
||||
|
||||
return existingConfig.cnrChannelId() == loadConfig.cnrChannelId() && exerciseId == m_exerciseId;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isChannelTakenInGlobal(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
if (!isActiveExercise(m_exerciseId)
|
||||
|| m_exerciseId == 0
|
||||
|| existingConfig.exerciseId().is_set()
|
||||
|| existingConfig.cnrChannelId() != loadConfig.cnrChannelId())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCombatNetRadioDialogModel::isRadioCircuitTakenInGlobal(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const
|
||||
{
|
||||
if (!isActiveExercise(m_exerciseId)
|
||||
|| m_exerciseId == 0
|
||||
|| existingConfig.exerciseId().is_set()
|
||||
|| existingConfig.radioCircuit() != loadConfig.radioCircuit())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<Core::RemoveElementRequest> LoadCombatNetRadioDialogModel::removeRequests() const
|
||||
{
|
||||
QVector<Core::RemoveElementRequest> removeRequestsVec;
|
||||
|
||||
for (int32_t idxCounter = 0; idxCounter < m_includeStates.size(); ++idxCounter)
|
||||
{
|
||||
if (m_includeStates.at(idxCounter) == Qt::Checked && m_conflicts.at(idxCounter) != NO_CONFLICT)
|
||||
{
|
||||
if (!m_conflictedCnrIds.contains(idxCounter))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Tried to get remove request for row " << idxCounter << " but it is not present.";
|
||||
continue;
|
||||
}
|
||||
|
||||
const QVector<int32_t> cnrConfigIds = m_conflictedCnrIds.value(idxCounter);
|
||||
|
||||
for (int32_t cnrConfigId : cnrConfigIds)
|
||||
{
|
||||
Core::RemoveElementRequest removeRequest(cnrConfigId);
|
||||
|
||||
if (!removeRequestsVec.contains(removeRequest))
|
||||
removeRequestsVec.append(removeRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return removeRequestsVec;
|
||||
}
|
||||
|
||||
QVector<ModifyCnrConfigRequest> LoadCombatNetRadioDialogModel::modifyRequests() const
|
||||
{
|
||||
const dds::core::optional<int32_t> exerciseId = m_exerciseId == 0 ? dds::core::optional<int32_t>() : dds::core::optional<int32_t>(m_exerciseId);
|
||||
const int32_t partyId = m_exerciseId == 0 ? 1 : 0;
|
||||
QVector<ModifyCnrConfigRequest> modifyRequestsVec;
|
||||
|
||||
modifyRequestsVec.reserve(m_includeStates.size());
|
||||
|
||||
for (int32_t row = 0; row < m_includeStates.size(); ++row)
|
||||
{
|
||||
if (m_includeStates.at(row) != Qt::Checked)
|
||||
continue;
|
||||
|
||||
const CnrConfig &cnrConfig = m_vecData.at(row);
|
||||
|
||||
modifyRequestsVec.append({0,
|
||||
cnrConfig.cnrChannelId(),
|
||||
exerciseId,
|
||||
cnrConfig.radioCircuit(),
|
||||
cnrConfig.recording(),
|
||||
{},
|
||||
partyId,
|
||||
cnrConfig.callSign()});
|
||||
}
|
||||
|
||||
return modifyRequestsVec;
|
||||
}
|
||||
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class RemoveElementRequest;
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class LoadCombatNetRadioDialogModel final
|
||||
: public LtsWidgets::LtsAbstractTableModel<CnrConfig>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
INCLUDE,
|
||||
CHANNEL,
|
||||
RADIO_CIRCUIT,
|
||||
CALL_SIGN,
|
||||
CONFLICTS
|
||||
};
|
||||
|
||||
enum Conflict
|
||||
{
|
||||
NO_CONFLICT = 0,
|
||||
RADIO_CIRCUIT_TAKEN_IN_OWN_CONFIG = 0b00000001,
|
||||
RADIO_CIRCUIT_TAKEN_IN_ANOTHER_EXERCISE = 0b00000010,
|
||||
CHANNEL_TAKEN_IN_ACTIVE_EXERCISE = 0b00000100,
|
||||
CHANNEL_TAKEN_IN_LINKED_EXERCISE = 0b00001000,
|
||||
CHANNEL_TAKEN_IN_OWN_CONFIG = 0b00010000,
|
||||
|
||||
|
||||
CHANNEL_TAKEN_IN_GLOBAL = 0b00100000,
|
||||
RADIO_CIRCUIT_TAKEN_IN_GLOBAL = 0b01000000,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Conflicts, Conflict)
|
||||
|
||||
explicit LoadCombatNetRadioDialogModel(const QByteArray &data,
|
||||
LtsSession::LtsSession *session,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
bool allChecked() const;
|
||||
|
||||
QVector<Core::RemoveElementRequest> removeRequests() const;
|
||||
QVector<AudioVideoManagement::ModifyCnrConfigRequest> modifyRequests() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCheckState(bool isChecked);
|
||||
|
||||
private:
|
||||
|
||||
LoadCombatNetRadioDialogModel::Conflicts getConflicts(int32_t row, const CnrConfig &config);
|
||||
QString conflictsText(Conflicts conflicts) const;
|
||||
|
||||
bool isRadioCircuitTakenInOwnConfig(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isRadioCircuitTakenInAnotherExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isChannelTakenInActiveExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isChannelTakenInLinkedExercise(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isChannelTakenInOwnConfig(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isChannelTakenInGlobal(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
bool isRadioCircuitTakenInGlobal(const CnrConfig &loadConfig, const CnrConfig &existingConfig) const;
|
||||
|
||||
void addConflictedCnr(int32_t row, int32_t cnrConfigId);
|
||||
|
||||
bool isActiveExercise(int32_t exerciseId) const;
|
||||
|
||||
QColor getConflictsRowColor(Conflicts conflicts) const;
|
||||
|
||||
private:
|
||||
int32_t m_exerciseId;
|
||||
QMap<int32_t, CnrChannel> m_cnrChannels;
|
||||
QMap<int32_t, CnrConfig> m_cnrConfigs;
|
||||
QMap<int32_t, ExerciseManagement::Exercise> m_exercises;
|
||||
QMap<int32_t, QVector<int32_t> > m_conflictedCnrIds;
|
||||
QVector<Qt::CheckState> m_includeStates;
|
||||
QVector<int32_t> m_disabledRows;
|
||||
QVector<Conflicts> m_conflicts;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_frequency_planning_dialog.h"
|
||||
#include "ui_avm_edit_frequency_planning_dialog.h"
|
||||
#include "avm_edit_frequency_planning_frequency_data_model.h"
|
||||
|
||||
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <ExerciseManagement/exm_dtc.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <LtsDataView/lts_data_view.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include "avm_load_frequency_planning_dialog.h"
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <QTreeView>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isActive(ExerciseManagement::ExerciseState state)
|
||||
{
|
||||
return (state == ExerciseManagement::ExerciseState::Started ||
|
||||
state == ExerciseManagement::ExerciseState::Paused);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
EditFrequencyPlanningDialog::EditFrequencyPlanningDialog(LtsSession::LtsSession *session,
|
||||
const QString &menuGroup,
|
||||
const QString &freqPlanningDialogIdentifier,
|
||||
const FrequencyPlanning &planning,
|
||||
const bool copy,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
|
||||
, m_session(session)
|
||||
, m_menuGroup(menuGroup)
|
||||
, m_freqPlanningDialogIdentifier(freqPlanningDialogIdentifier)
|
||||
, m_ui(new Ui::EditFrequencyPlanningDialog)
|
||||
, m_planning(planning)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_avmFtc(avmFtc)
|
||||
, m_ppmDtc(ppmDtc)
|
||||
, m_ismDtc(ismDtc)
|
||||
, m_exmDtc(exmDtc)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_frequencyDataModel(new EditFrequencyPlanningFrequencyDataModel(planning, m_session->exerciseId(), avmDtc, ismDtc, ppmDtc, this))
|
||||
, m_frequencyPlanningId(copy ? 0 : planning.id())
|
||||
, m_exerciseId(session->exerciseId())
|
||||
, m_isEdit(EditFrequencyPlanningSetResourceDialog::DialogMode::Assign)
|
||||
, m_activeFrequencyPlanningStatus(0)
|
||||
, m_logger(getLogger("EditFrequencyPlanningDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->leName->setText(QString::fromStdString(m_planning.name()));
|
||||
m_ui->lbDate->setText(DTG::toStringMSec(m_planning.date()));
|
||||
|
||||
|
||||
m_uiRequirements->addRequirement( { m_ui->label, [this]() { return !m_ui->leName->text().isEmpty(); } });
|
||||
|
||||
FPFDelegate *treeDelegate = new FPFDelegate(m_frequencyDataModel);
|
||||
m_ui->dvFrequencyData->treeView()->setItemDelegateForColumn(EditFrequencyPlanningFrequencyDataModel::Columns::PROPERTIES, treeDelegate);
|
||||
|
||||
m_ui->dvFrequencyData->setModel(m_frequencyDataModel);
|
||||
m_ui->dvFrequencyData->expandAll();
|
||||
#ifndef LTS_DEBUG
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::RADIO_CIRCUIT_ID);
|
||||
|
||||
#endif
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::AKW_BUNDLE);
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::AKW_RADIO_CIRCUIT);
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::FSB_BUNDLE);
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::COMSEC);
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::DEVICE);
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningFrequencyDataModel::Columns::PILOTTON);
|
||||
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &EditFrequencyPlanningDialog::onAddClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &EditFrequencyPlanningDialog::onRemoveClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &EditFrequencyPlanningDialog::onPrint);
|
||||
|
||||
connect(m_ui->dvFrequencyData, &LtsDataView::LtsDataView::signalSelectionChanged,
|
||||
this, &EditFrequencyPlanningDialog::enableSelectedUnassignButton);
|
||||
|
||||
connect(m_ui->dvFrequencyData, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||||
this, &EditFrequencyPlanningDialog::onAddClicked);
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
|
||||
|
||||
if (m_frequencyPlanningId == 0)
|
||||
slotChangesMade();
|
||||
|
||||
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Add, tr("Assign"));
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Remove, tr("Unassign"));
|
||||
|
||||
|
||||
m_buttonBox->connectLibraryButton(this,
|
||||
&EditFrequencyPlanningDialog::onImportButtonClicked,
|
||||
&EditFrequencyPlanningDialog::onExportButtonClicked);
|
||||
|
||||
if (!session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Frequency_Planning"));
|
||||
}
|
||||
|
||||
EditFrequencyPlanningDialog::~EditFrequencyPlanningDialog()
|
||||
|
||||
{
|
||||
emit aboutToCloseMe(m_frequencyPlanningId);
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::retranslate()
|
||||
{
|
||||
translate(m_ui.get(), m_avmDtc->frequencyPlanning(m_frequencyPlanningId), tr("Frequency Planning"));
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onRemoveFrequencyPlanningReply(const Core::FunctionReplyObject &reply)
|
||||
{
|
||||
if (reply.error())
|
||||
ERROR_LOG(m_logger) << reply.str();
|
||||
m_requestHelper->requestReply(reply);
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onModifyFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
if (!replyObject.error())
|
||||
m_frequencyDataModel->setFrequencePlanningId(replyObject.id());
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
|
||||
bool EditFrequencyPlanningDialog::apply()
|
||||
{
|
||||
if (!m_frequencyDataModel->checkResourceAssignments())
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Multiple assignments with the same resource are not possible. Please correct the selected entries."));
|
||||
return false;
|
||||
}
|
||||
ModifyFrequencyPlanningRequest request = m_frequencyDataModel->modifyFrequencyPlanningRequest();
|
||||
|
||||
request.date(m_session->partitionTime());
|
||||
m_ui->lbDate->setText(DTG::toStringMSec(request.date()));
|
||||
m_planning.date() = request.date();
|
||||
request.id(m_frequencyPlanningId);
|
||||
request.name(m_ui->leName->text().toStdString());
|
||||
|
||||
return m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->modifyFrequencyPlanningRequest(request, this);
|
||||
});
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onAddClicked()
|
||||
{
|
||||
|
||||
|
||||
QModelIndex idx = m_ui->dvFrequencyData->currentIndex();
|
||||
int row = idx.row();
|
||||
if (row < 0)
|
||||
return;
|
||||
|
||||
CnrConfig cnrConfigRow = m_frequencyDataModel->itemData(idx).cnrConfig;
|
||||
int cnrConfigId = cnrConfigRow.id();
|
||||
if (cnrConfigId <= 0)
|
||||
return;
|
||||
|
||||
DEBUG_LOG(m_logger) << "---RessourceDialog aufrufen...."
|
||||
<< " cnrConfigId: " << cnrConfigId
|
||||
<< " radioCircuit: " << cnrConfigRow.radioCircuit()
|
||||
<< " FrequencySetId: " << m_frequencyDataModel->getFrequencySetId();
|
||||
|
||||
FrequencyPlanningData fpd = m_frequencyDataModel->getfrequencyPlanningData(cnrConfigId);
|
||||
if (!fpd.cnrConfigId())
|
||||
{
|
||||
fpd.cnrConfigId(cnrConfigId);
|
||||
}
|
||||
|
||||
|
||||
EditFrequencyPlanningResourceDialog *frequencyPlanningResourceDialog
|
||||
= new EditFrequencyPlanningResourceDialog(m_frequencyDataModel->getFrequencySetId(),
|
||||
m_isEdit,
|
||||
this );
|
||||
|
||||
frequencyPlanningResourceDialog->init(m_session, fpd, m_frequencyDataModel->getAllocatedFrequencyPlanningSetIds());
|
||||
|
||||
connect(this, &QObject::destroyed,
|
||||
frequencyPlanningResourceDialog, &QObject::deleteLater);
|
||||
|
||||
addDialog(frequencyPlanningResourceDialog, m_menuGroup, QLatin1String("avmFrequencyPlanning") + QString::number(cnrConfigId), LtsWidgets::LayoutArea::eDialogTab);
|
||||
|
||||
connect(frequencyPlanningResourceDialog, &EditFrequencyPlanningResourceDialog::signalAssignRadioCircuit,
|
||||
this, &EditFrequencyPlanningDialog::onAssignRadioCircuit);
|
||||
m_ui->dvFrequencyData->expandAll();
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onRemoveClicked()
|
||||
{
|
||||
QModelIndex idx = m_ui->dvFrequencyData->currentIndex();
|
||||
int row = idx.row();
|
||||
if (row < 0)
|
||||
return;
|
||||
|
||||
CnrConfig cnrConfigRow = m_frequencyDataModel->itemData(idx).cnrConfig;
|
||||
int cnrConfigId = cnrConfigRow.id();
|
||||
if (cnrConfigId <= 0)
|
||||
return;
|
||||
unassignRadioCircuit(cnrConfigId);
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::enableSelectedUnassignButton()
|
||||
{
|
||||
QModelIndex idx = m_ui->dvFrequencyData->currentIndex();
|
||||
int row = idx.row();
|
||||
if (row < 0)
|
||||
return;
|
||||
|
||||
auto itemData = m_frequencyDataModel->itemData(idx);
|
||||
CnrConfig cnrConfigRow = itemData.cnrConfig;
|
||||
int cnrConfigId = cnrConfigRow.id();
|
||||
if (cnrConfigId <= 0)
|
||||
return;
|
||||
|
||||
|
||||
FrequencyPlanningData fpd = m_frequencyDataModel->getfrequencyPlanningData(cnrConfigId);
|
||||
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(fpd.properties());
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, true);
|
||||
|
||||
if( (!cnrConfigRow.exerciseId().is_set()
|
||||
&& m_planning.exerciseId().is_set())
|
||||
||
|
||||
itemData.readOnly
|
||||
)
|
||||
{
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Add, tr("Show"));
|
||||
m_isEdit = EditFrequencyPlanningSetResourceDialog::DialogMode::Show;
|
||||
if (circuits.size() == 0)
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
|
||||
}
|
||||
else if (circuits.size() > 0)
|
||||
{
|
||||
m_isEdit = EditFrequencyPlanningSetResourceDialog::DialogMode::Edit;
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Add, tr("Edit"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isEdit = EditFrequencyPlanningSetResourceDialog::DialogMode::Assign;
|
||||
m_buttonBox->setText(LtsWidgets::DialogButton::Add, tr("Assign"));
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "---enableAssignUnassignButtons()...."
|
||||
<< " cnrConfigId: " << cnrConfigId
|
||||
<< " radioCircuitId: " << cnrConfigRow.radioCircuit();
|
||||
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, !itemData.readOnly && m_isEdit == EditFrequencyPlanningSetResourceDialog::DialogMode::Edit);
|
||||
|
||||
qDeleteAll(circuits);
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onAssignRadioCircuit(const FrequencyPlanningData &fpd)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---onAssignRadioCircuit()...."
|
||||
<< "CnrConfigId: " << fpd.cnrConfigId();
|
||||
|
||||
m_frequencyDataModel->setFrequencyPlanningData(fpd);
|
||||
|
||||
if (!m_frequencyDataModel->checkResourceAssignments())
|
||||
{
|
||||
|
||||
focusDialog(m_menuGroup, m_freqPlanningDialogIdentifier, LtsWidgets::LayoutArea::eDialogTab);
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Multiple assignments with the same resource are not possible. Please correct the selected entries."));
|
||||
return;
|
||||
}
|
||||
enableSelectedUnassignButton();
|
||||
slotChangesMade();
|
||||
m_ui->dvFrequencyData->repaint();
|
||||
m_ui->dvFrequencyData->expandAll();
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->dvFrequencyData->treeView() );
|
||||
}
|
||||
|
||||
int32_t EditFrequencyPlanningDialog::currentFrequencySetId() const
|
||||
{
|
||||
QModelIndex currentFrequencySetDataIndex = m_ui->dvFrequencyData->currentIndex();
|
||||
|
||||
if (!currentFrequencySetDataIndex.isValid())
|
||||
return -1;
|
||||
|
||||
return m_frequencyDataModel->data(currentFrequencySetDataIndex, Qt::UserRole).toInt();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QVector<int> EditFrequencyPlanningDialog::otherActiveExercises() const
|
||||
{
|
||||
const auto allExercises_ = m_exmDtc->exercises();
|
||||
|
||||
Q_ASSERT(::isActive(allExercises_[m_exerciseId].state()));
|
||||
|
||||
|
||||
auto allExercises = allExercises_.values();
|
||||
auto newEnd = std::remove_if(allExercises.begin(), allExercises.end(), [] (const ExerciseManagement::Exercise &ex) { return ex.isDeleted(); });
|
||||
allExercises.erase(newEnd, allExercises.end());
|
||||
|
||||
QVector<int> toBeConsidered;
|
||||
for (const auto &exercise : qAsConst(allExercises))
|
||||
{
|
||||
if (exercise.id() == m_exerciseId)
|
||||
continue;
|
||||
|
||||
if (::isActive(exercise.state()))
|
||||
toBeConsidered.append(exercise.id());
|
||||
}
|
||||
return toBeConsidered;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QVector<int> EditFrequencyPlanningDialog::otherActivePlans() const
|
||||
{
|
||||
QVector<int> result;
|
||||
QVector<int> exercises = otherActiveExercises();
|
||||
|
||||
const auto activePlans = m_avmDtc->activeFrequencyPlannings();
|
||||
for (const auto &activePlan : activePlans)
|
||||
{
|
||||
if (exercises.contains(activePlan.exerciseId()))
|
||||
result.append(activePlan.frequencyPlanningId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::unassignRadioCircuit(int32_t cnrConfigId)
|
||||
{
|
||||
m_frequencyDataModel->unassignRadioCircuit(cnrConfigId);
|
||||
enableSelectedUnassignButton();
|
||||
slotChangesMade();
|
||||
m_ui->dvFrequencyData->expandAll();
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onExportButtonClicked()
|
||||
{
|
||||
QByteArray byteArray = m_frequencyDataModel->uiToJson();
|
||||
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
|
||||
if (fileId > 0)
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningDialog::onImportButtonClicked()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "--- onImportButtonClicked() ";
|
||||
|
||||
QByteArray content;
|
||||
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::AVMEditFrequencyPlanning));
|
||||
if (fileId > 0)
|
||||
{
|
||||
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::AVMEditFrequencyPlanning)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadFrequencyPlanningDialog loadingDialog(content, m_frequencyDataModel->toFrequencyPlanning(), m_avmDtc, m_ismDtc) ;
|
||||
loadingDialog.exec();
|
||||
|
||||
if (loadingDialog.isApplied())
|
||||
{
|
||||
const QVector<int> unassignments = loadingDialog.unassignments();
|
||||
|
||||
for (int idToUnassign : unassignments)
|
||||
m_frequencyDataModel->unassignRadioCircuit(idToUnassign);
|
||||
|
||||
const QVector<FrequencyPlanningData> planningData = loadingDialog.newPlanningData();
|
||||
|
||||
for (const FrequencyPlanningData ¤tData : planningData)
|
||||
m_frequencyDataModel->setFrequencyPlanningData(currentData);
|
||||
|
||||
slotChangesMade();
|
||||
m_ui->dvFrequencyData->expandAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include "avm_edit_frequency_planning_resource_dialog.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditFrequencyPlanningDialog;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class RequestHelper;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class EditFrequencyPlanningFrequencyDataModel;
|
||||
class EditFrequencyPlanningResourceDialog;
|
||||
|
||||
class EditFrequencyPlanningDialog : public LtsWidgets::LtsDialog
|
||||
, protected Interface::Ftc::RemoveFrequencyPlanningReplyHandler
|
||||
, protected Interface::Ftc::ModifyFrequencyPlanningReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit EditFrequencyPlanningDialog(LtsSession::LtsSession *session,
|
||||
const QString &menuGroup,
|
||||
const QString &freqPlanningDialogIdentifier,
|
||||
const FrequencyPlanning &planning,
|
||||
const bool copy,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc,
|
||||
QWidget *parent);
|
||||
|
||||
~EditFrequencyPlanningDialog();
|
||||
void retranslate() override;
|
||||
void onExportButtonClicked();
|
||||
void onImportButtonClicked();
|
||||
|
||||
protected:
|
||||
void onRemoveFrequencyPlanningReply(const Core::FunctionReplyObject &reply) override final;
|
||||
void onModifyFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
bool apply() override;
|
||||
|
||||
private slots:
|
||||
void onAddClicked();
|
||||
void onRemoveClicked();
|
||||
void enableSelectedUnassignButton();
|
||||
void onPrint();
|
||||
void onAssignRadioCircuit(const FrequencyPlanningData &fpd);
|
||||
|
||||
signals:
|
||||
void aboutToCloseMe(int);
|
||||
|
||||
private:
|
||||
int32_t currentFrequencySetId() const;
|
||||
|
||||
QVector<int> otherActiveExercises() const;
|
||||
QVector<int> otherActivePlans() const;
|
||||
|
||||
void unassignRadioCircuit(int32_t cnrConfigId);
|
||||
bool isCriteriumEditDialog(const QByteArray &content);
|
||||
|
||||
LtsSession::LtsSession *m_session;
|
||||
QString m_menuGroup;
|
||||
QString m_freqPlanningDialogIdentifier;
|
||||
std::unique_ptr<Ui::EditFrequencyPlanningDialog> m_ui;
|
||||
FrequencyPlanning m_planning;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<Interface::Ftc> m_avmFtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
ExerciseManagement::Interface::Dtc *m_exmDtc;
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
|
||||
std::unique_ptr<LtsUtils::RequestHelper> m_requestHelper;
|
||||
EditFrequencyPlanningFrequencyDataModel *m_frequencyDataModel;
|
||||
int m_frequencyPlanningId;
|
||||
int m_exerciseId;
|
||||
EditFrequencyPlanningSetResourceDialog::DialogMode m_isEdit;
|
||||
int m_activeFrequencyPlanningStatus;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditFrequencyPlanningDialog</class>
|
||||
<widget class="QWidget" name="EditFrequencyPlanningDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>655</width>
|
||||
<height>528</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Asset Stocks</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QLabel" name="lbDate">
|
||||
<property name="text">
|
||||
<string notr="true"><DATE></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leName">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Date:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>264</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="4">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="4">
|
||||
<widget class="LtsDataView::LtsDataView" name="dvFrequencyData">
|
||||
<property name="rootIsDecorated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+951
@@ -0,0 +1,951 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_frequency_planning_frequency_data_model.h"
|
||||
|
||||
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_translation.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <LtsUtilsCore/json_object.h>
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
void EditFrequencyPlanningFrequencyDataModel::onFrequencyPlanningChanged(const FrequencyPlanning &planning, DataModification dm)
|
||||
{
|
||||
|
||||
if (planning.id() != m_initPlan.id() && planning.exerciseId().is_set())
|
||||
return;
|
||||
|
||||
|
||||
if (dm == DataModification::eRemoved)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
for (NGLTreeItem* item : m_rootItem->constChildren())
|
||||
{
|
||||
if (!item->data().canConvert<ItemData>())
|
||||
continue;
|
||||
|
||||
ItemData data = item->data().value<ItemData>();
|
||||
delete data.radioCircuit;
|
||||
data.radioCircuit = nullptr;
|
||||
item->setData(QVariant::fromValue(data));
|
||||
}
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
QHash<int, FrequencyPlanningData> fpdMap;
|
||||
for(const auto &elem : planning.data())
|
||||
fpdMap.insert(elem.cnrConfigId(), elem);
|
||||
for (NGLTreeItem* item : m_rootItem->constChildren())
|
||||
{
|
||||
if (!item->data().canConvert<ItemData>())
|
||||
continue;
|
||||
|
||||
ItemData itemData = item->data().value<ItemData>();
|
||||
if (itemData.cnrConfig.exerciseId().is_set() && itemData.cnrConfig.exerciseId().get() != m_exerciseId)
|
||||
continue;
|
||||
|
||||
if (!itemData.cnrConfig.exerciseId().is_set() && 0 != m_exerciseId)
|
||||
continue;
|
||||
|
||||
if (fpdMap.contains(itemData.cnrConfig.id()))
|
||||
{
|
||||
|
||||
const FrequencyPlanningData &fpd = fpdMap[itemData.cnrConfig.id()];
|
||||
|
||||
if (item->childCount())
|
||||
{
|
||||
beginRemoveRows(indexFromItem(item),0,item->childCount()-1);
|
||||
item->removeAllChildren();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
delete itemData.radioCircuit;
|
||||
itemData.radioCircuit = nullptr;
|
||||
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(fpd.properties());
|
||||
if (circuits.size() > 1)
|
||||
{
|
||||
for (RadioCircuit *circuit : qAsConst(circuits))
|
||||
{
|
||||
itemData.radioCircuit = circuit;
|
||||
ConfigTreeItem *childItem = new ConfigTreeItem(QVariant::fromValue(itemData));
|
||||
insertRow(item->childCount(), indexFromItem(item), childItem);
|
||||
}
|
||||
}
|
||||
else if (circuits.size() == 1)
|
||||
{
|
||||
itemData.radioCircuit = circuits[0];
|
||||
item->setData(QVariant::fromValue(itemData));
|
||||
}
|
||||
m_frequencyPlanningData[fpd.cnrConfigId()] = fpd;
|
||||
fpdMap.remove(itemData.cnrConfig.id());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (item->childCount())
|
||||
{
|
||||
beginRemoveRows(indexFromItem(item),0,item->childCount()-1);
|
||||
item->removeAllChildren();
|
||||
endRemoveRows();
|
||||
}
|
||||
delete itemData.radioCircuit;
|
||||
itemData.radioCircuit = nullptr;
|
||||
item->setData(QVariant::fromValue(itemData));
|
||||
m_frequencyPlanningData.remove(itemData.cnrConfig.id());
|
||||
}
|
||||
}
|
||||
|
||||
for (const FrequencyPlanningData &item : qAsConst(fpdMap))
|
||||
{
|
||||
setFrequencyPlanningData(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EditFrequencyPlanningFrequencyDataModel::EditFrequencyPlanningFrequencyDataModel(const FrequencyPlanning &initPlanning,
|
||||
int exerciseId,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
QObject *parent)
|
||||
: NGLTreeModel(parent, new ConfigTreeItem(QVariant()),
|
||||
{
|
||||
tr("Channel Number"),
|
||||
tr("RC id"),
|
||||
tr("Radio Circuit"),
|
||||
tr("Party"),
|
||||
tr("Unit"),
|
||||
tr("Radio Station"),
|
||||
tr("Frequency"),
|
||||
tr("Function"),
|
||||
tr("Device"),
|
||||
tr("AKW Bundle"),
|
||||
tr("FSB Bundle"),
|
||||
tr("AKW Radio Circuit"),
|
||||
tr("COMSEC"),
|
||||
tr("Pilotton"),
|
||||
tr("Operating Mode"),
|
||||
tr("Properties"),
|
||||
tr("Channel Spacing"),
|
||||
tr("Squelch"),
|
||||
tr("Global"),
|
||||
})
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_ismDtc(ismDtc)
|
||||
, m_ppmDtc(ppmDtc)
|
||||
, m_initPlan(initPlanning)
|
||||
, m_logger(getLogger("EditFrequencyPlanningDataModel"))
|
||||
{
|
||||
Q_ASSERT(avmDtc);
|
||||
Q_ASSERT(ppmDtc);
|
||||
DEBUG_LOG(m_logger) << "---EditFrequencyPlanningDataMod m_frequencyPlanningData[c.id()];el() ";
|
||||
|
||||
int frequencySetId = initPlanning.frequencySetId();
|
||||
std::vector<FrequencySetDataWithId> fsdVec = m_avmDtc->frequencySet(frequencySetId).data();
|
||||
for(FrequencySetDataWithId fsd : fsdVec)
|
||||
m_freqSetData.insert(fsd.id(), fsd);
|
||||
|
||||
m_units = m_ppmDtc->units();
|
||||
|
||||
QVector<CnrConfig> dataVec;
|
||||
const auto &cnrConfigs = m_avmDtc->cnrConfigs();
|
||||
for (const CnrConfig &cnrConfig : cnrConfigs)
|
||||
{
|
||||
|
||||
if (cnrConfig.exerciseId().is_set() && cnrConfig.exerciseId().get() != m_exerciseId)
|
||||
continue;
|
||||
dataVec.append(cnrConfig);
|
||||
}
|
||||
setCnrConfigs(dataVec);
|
||||
m_avmDtc->activeFrequencyPlannings([this](const ActiveFrequencyPlanning &afp)
|
||||
{
|
||||
if (afp.exerciseId() <= 0)
|
||||
{
|
||||
onFrequencyPlanningChanged(m_avmDtc->frequencyPlanning(afp.frequencyPlanningId()), DataModification::eAdded);
|
||||
}
|
||||
});
|
||||
onFrequencyPlanningChanged(initPlanning, DataModification::eAdded);
|
||||
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::cnrConfigChanged, this, &EditFrequencyPlanningFrequencyDataModel::onCnrConfigChanged);
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::frequencyPlanningChanged, this, &EditFrequencyPlanningFrequencyDataModel::onFrequencyPlanningChanged);
|
||||
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningFrequencyDataModel::setCnrConfigs(const QVector<CnrConfig> &dataVec)
|
||||
{
|
||||
m_cnrConfigs.clear();
|
||||
for(const CnrConfig &c : dataVec)
|
||||
{
|
||||
m_cnrConfigs.insert(c.id(), c);
|
||||
ItemData id(c);
|
||||
if (m_frequencyPlanningData.contains(c.id()))
|
||||
{
|
||||
FrequencyPlanningData fpd = m_frequencyPlanningData[c.id()];
|
||||
id.readOnly = isReadOnly(fpd.properties());
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(fpd.properties());
|
||||
if (circuits.size() > 1)
|
||||
{
|
||||
ConfigTreeItem *configItem = new ConfigTreeItem(QVariant::fromValue(id));
|
||||
insertRow(m_rootItem->childCount(), indexFromItem(m_rootItem), configItem);
|
||||
for (RadioCircuit *circuit : qAsConst(circuits))
|
||||
{
|
||||
id.radioCircuit = circuit;
|
||||
ConfigTreeItem *childItem = new ConfigTreeItem(QVariant::fromValue(id));
|
||||
insertRow(configItem->childCount(), indexFromItem(configItem), childItem);
|
||||
}
|
||||
}
|
||||
else if (circuits.size() == 1)
|
||||
{
|
||||
id.radioCircuit = circuits[0];
|
||||
ConfigTreeItem *configItem = new ConfigTreeItem(QVariant::fromValue(id));
|
||||
insertRow(m_rootItem->childCount(), indexFromItem(m_rootItem), configItem);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigTreeItem *configItem = new ConfigTreeItem(QVariant::fromValue(id));
|
||||
insertRow(m_rootItem->childCount(), indexFromItem(m_rootItem), configItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditFrequencyPlanningFrequencyDataModel::ItemData EditFrequencyPlanningFrequencyDataModel::itemData(const QModelIndex &index)
|
||||
{
|
||||
NGLTreeItem *item = privateData(index);
|
||||
if (!item->data().canConvert<ItemData>())
|
||||
return {};
|
||||
|
||||
return item->data().value<ItemData>();
|
||||
}
|
||||
|
||||
QVariant EditFrequencyPlanningFrequencyDataModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole && role != Qt::ToolTipRole && role != Qt::UserRole && role != Qt::TextColorRole && role != Qt::BackgroundRole) || !index.isValid())
|
||||
return NGLTreeModel::data(index, role);
|
||||
ConfigTreeItem *item = static_cast<ConfigTreeItem *>(privateData(index));
|
||||
|
||||
if (!item->data().canConvert<ItemData>())
|
||||
return NGLTreeModel::data(index, role);
|
||||
|
||||
ItemData id = item->data().value<ItemData>();
|
||||
|
||||
const CnrConfig &setData = id.cnrConfig;
|
||||
RadioCircuit *rc = id.radioCircuit;
|
||||
|
||||
if (role == Qt::ToolTipRole)
|
||||
{
|
||||
if (index.column() != PROPERTIES)
|
||||
return {};
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
if (rcVhf && !isAkwMode(rcVhf->operatingMode))
|
||||
return tr("Pilot Tone: %1")
|
||||
.arg(rcVhf->pilotTone ? tr("On") : tr("Off"));
|
||||
RadioCircuitUHF *rcUhf = dynamic_cast<RadioCircuitUHF*>(rc);
|
||||
if (rcUhf)
|
||||
return tr("Clipper: %1, AGC: %2, Modulation Type: %3")
|
||||
.arg(rcUhf->clipper ? tr("On") : tr("Off"),
|
||||
rcUhf->agc ? tr("On") : tr("Off"),
|
||||
toString(rcUhf->modulationType));
|
||||
RadioCircuitHF *rcHf = dynamic_cast<RadioCircuitHF*>(rc);
|
||||
if (rcHf)
|
||||
return tr("Channel Spacing: %1, Squelch: %2")
|
||||
.arg(toString(rcHf->channelSpacing),
|
||||
rcHf->squelch > 0 ? QString::number(rcHf->squelch) : tr("Off"));
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
|
||||
case RADIO_CIRCUIT_ID:
|
||||
return setData.id();
|
||||
case FUNCTION:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
return QString::fromStdString(m_freqSetData[rc->frequencySetDataId()].function());
|
||||
}
|
||||
case DEVICE:
|
||||
{
|
||||
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
if (!rcVhf)
|
||||
return QStringLiteral("-");
|
||||
return toString(m_freqSetData[rc->frequencySetDataId()].frequencyBand().underlying());
|
||||
}
|
||||
case FREQUENCY:
|
||||
{
|
||||
QLocale locale(QLocale::German);
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
if (rc->frequencySetDataId() > 0)
|
||||
{
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
if (rcVhf && isAkwMode(rcVhf->operatingMode))
|
||||
return QStringLiteral("-");
|
||||
return tr("%1 MHz").arg(locale.toString(m_freqSetData[rc->frequencySetDataId()].frequency() / 1000., 'f', 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
RadioCircuitUHF *rcUhf = dynamic_cast<RadioCircuitUHF*>(rc);
|
||||
RadioCircuitHF *rcHf = dynamic_cast<RadioCircuitHF*>(rc);
|
||||
|
||||
if (rcUhf)
|
||||
return tr("%1 MHz").arg(locale.toString(rcUhf->frequency / 1000000., 'f', 3));
|
||||
if (rcHf)
|
||||
return tr("%1 MHz").arg(locale.toString(rcHf->frequency / 1000000., 'f', 3));
|
||||
|
||||
return QStringLiteral("-");
|
||||
}
|
||||
}
|
||||
case AKW_BUNDLE:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
if (rc->frequencySetDataId() <= 0)
|
||||
return QStringLiteral("-");
|
||||
if (!m_freqSetData[rc->frequencySetDataId()].akwBundle().is_set())
|
||||
return QStringLiteral("-");
|
||||
|
||||
return m_freqSetData[rc->frequencySetDataId()].akwBundle().get();
|
||||
}
|
||||
case FSB_BUNDLE:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
if (rc->frequencySetDataId() <= 0)
|
||||
return QStringLiteral("-");
|
||||
if (!m_freqSetData[rc->frequencySetDataId()].fsbBundle().is_set())
|
||||
return QStringLiteral("-");
|
||||
|
||||
return m_freqSetData[rc->frequencySetDataId()].fsbBundle().get();
|
||||
}
|
||||
case AKW_RADIO_CIRCUIT:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
if (rc->frequencySetDataId() <= 0)
|
||||
return QStringLiteral("-");
|
||||
if (!m_freqSetData[rc->frequencySetDataId()].akwRadioCircuit().is_set())
|
||||
return QStringLiteral("-");
|
||||
|
||||
return m_freqSetData[rc->frequencySetDataId()].akwRadioCircuit().get();
|
||||
}
|
||||
case COMSEC:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
if (rc->frequencySetDataId() <= 0)
|
||||
return QStringLiteral("-");
|
||||
if (!m_freqSetData[rc->frequencySetDataId()].comsec().is_set())
|
||||
return QStringLiteral("-");
|
||||
|
||||
return m_freqSetData[rc->frequencySetDataId()].comsec().get();
|
||||
}
|
||||
|
||||
case RADIO_CIRCUIT:
|
||||
{
|
||||
if (!rc)
|
||||
return QString::fromStdString(setData.radioCircuit());
|
||||
|
||||
return id.name();
|
||||
}
|
||||
case PARTY:
|
||||
{
|
||||
ParticipantManagement::Party party = m_ppmDtc->party(setData.partyId());
|
||||
|
||||
return ParticipantManagement::trPartyName(party.name());
|
||||
}
|
||||
case UNIT:
|
||||
{
|
||||
if (!setData.unitId().is_set())
|
||||
return {};
|
||||
const int unitId = setData.unitId().get();
|
||||
if (!m_units.contains(unitId))
|
||||
return QStringLiteral("-");
|
||||
const auto unit = m_units[unitId];
|
||||
|
||||
INFO_LOG(m_logger) << " config.unitId()=" << unitId
|
||||
<< " Str=" << unit.name();
|
||||
|
||||
QString unitStr;
|
||||
if (unit.designator().size() > 0)
|
||||
unitStr = QString::fromStdString(unit.designator()) + QLatin1Char('/');
|
||||
unitStr.append(QString::fromStdString(unit.tacticalIdentifier()));
|
||||
INFO_LOG(m_logger) << "unitStr = " << unitStr;
|
||||
|
||||
return unitStr;
|
||||
}
|
||||
case RADIO_STATION:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
|
||||
if (rc->radioStationId == 0)
|
||||
return tr("Automatic");
|
||||
else
|
||||
return QString::fromStdString(m_ismDtc->mainStructureElement(rc->radioStationId).name());
|
||||
}
|
||||
case PILOTTON:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
if (!rcVhf)
|
||||
return QStringLiteral("-");
|
||||
|
||||
return rcVhf->pilotTone ? tr("On") : tr("Off");
|
||||
}
|
||||
case OPERATING_MODE:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
if (!rcVhf)
|
||||
return QStringLiteral("-");
|
||||
|
||||
return toString(rcVhf->operatingMode);
|
||||
}
|
||||
case CHANNEL:
|
||||
{
|
||||
CnrChannel channel = m_avmDtc->cnrChannel(setData.cnrChannelId());
|
||||
return QString::fromStdString(channel.name());
|
||||
}
|
||||
case GLOBAL:
|
||||
{
|
||||
return setData.exerciseId().is_set() ? tr("No") : tr("Yes");
|
||||
}
|
||||
case PROPERTIES:
|
||||
{
|
||||
if (!rc)
|
||||
return QStringLiteral("-");
|
||||
else
|
||||
{
|
||||
RadioCircuitUHF *rcUhf = dynamic_cast<RadioCircuitUHF*>(rc);
|
||||
RadioCircuitHF *rcHf = dynamic_cast<RadioCircuitHF*>(rc);
|
||||
RadioCircuitVHF *rcVhf = dynamic_cast<RadioCircuitVHF*>(rc);
|
||||
QStringList sl;
|
||||
if (rcUhf)
|
||||
{
|
||||
sl << createIcon(ICON_CLIPPER, rcUhf->clipper );
|
||||
sl << createIcon(ICON_AGC, rcUhf->agc );
|
||||
sl << createIcon(ICON_MODULATION_TYPE, 0, rcUhf->modulationType);
|
||||
return sl.join(QStringLiteral(" "));
|
||||
}
|
||||
if (rcVhf && !isAkwMode(rcVhf->operatingMode))
|
||||
{
|
||||
sl << createIcon(ICON_PILOTTON, rcVhf->pilotTone > 0);
|
||||
return sl.join(QStringLiteral(" "));
|
||||
}
|
||||
if (rcHf)
|
||||
{
|
||||
return sl.join(QStringLiteral(" "));
|
||||
}
|
||||
return QStringLiteral("-");
|
||||
}
|
||||
}
|
||||
case CHANNEL_SPACING:
|
||||
{
|
||||
RadioCircuitUHF *rcUhf = dynamic_cast<RadioCircuitUHF*>(rc);
|
||||
RadioCircuitHF *rcHf = dynamic_cast<RadioCircuitHF*>(rc);
|
||||
if (rcUhf)
|
||||
return toString(rcUhf->channelSpacing);
|
||||
if (rcHf)
|
||||
return toString(rcHf->channelSpacing);
|
||||
return {};
|
||||
}
|
||||
case SQUELCH:
|
||||
{
|
||||
RadioCircuitUHF *rcUhf = dynamic_cast<RadioCircuitUHF*>(rc);
|
||||
RadioCircuitHF *rcHf = dynamic_cast<RadioCircuitHF*>(rc);
|
||||
if (rcUhf)
|
||||
return rcUhf->squelchDB > 0 ? tr("%1 dB").arg(rcUhf->squelchDB) : QVariant();
|
||||
if (rcHf)
|
||||
return rcHf->squelch > 0 ? QString::number(rcHf->squelch) : QVariant();
|
||||
return {};
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (role == Qt::UserRole)
|
||||
return setData.id();
|
||||
|
||||
if (role == Qt::TextColorRole)
|
||||
{
|
||||
|
||||
for (int id : m_multipleAssignedCnrIds)
|
||||
{
|
||||
if (id == setData.id())
|
||||
return QColor(Qt::red);
|
||||
}
|
||||
}
|
||||
if (role == Qt::BackgroundRole)
|
||||
{
|
||||
if (setData.exerciseId().is_set() && setData.exerciseId().get() == m_exerciseId)
|
||||
return NGLTreeModel::data(index, role);
|
||||
if (!setData.exerciseId().is_set() && m_exerciseId <= 0)
|
||||
return NGLTreeModel::data(index, role);
|
||||
return QColor(Qt::gray);
|
||||
}
|
||||
|
||||
return NGLTreeModel::data(index, role);
|
||||
}
|
||||
|
||||
QString EditFrequencyPlanningFrequencyDataModel::createIcon(PropertyData propertyDataType, bool on, ModulationType type) const
|
||||
{
|
||||
QString imgHeader = QStringLiteral("<img src=\"%1\" height=\"32\" title=\"%2\" image-rendering=\"optimizeQuality\">");
|
||||
|
||||
switch(propertyDataType)
|
||||
{
|
||||
case ICON_PILOTTON:
|
||||
return imgHeader
|
||||
.arg(on ?
|
||||
QStringLiteral(":/style/pilotton-on.svg")
|
||||
: QStringLiteral(":/style/pilotton-off.svg"),
|
||||
on ?
|
||||
tr("Pilot Tone: On")
|
||||
: tr("Pilot Tone: Off"));
|
||||
case ICON_MODULATION_TYPE:
|
||||
return imgHeader
|
||||
.arg(type == ModulationType::AM ?
|
||||
QStringLiteral(":/style/AM.svg")
|
||||
: QStringLiteral(":/style/FM.svg"),
|
||||
on ?
|
||||
tr("Modulation Type: AM")
|
||||
: tr("Modulation Type: FM"));
|
||||
case ICON_SQUELCH:
|
||||
return imgHeader
|
||||
.arg(on ?
|
||||
QStringLiteral(":/style/squelch-on.svg")
|
||||
: QStringLiteral(":/style/squelch-off.svg"),
|
||||
on ?
|
||||
tr("Squelch: On")
|
||||
: tr("Squelch: Off"));
|
||||
case ICON_CLIPPER:
|
||||
return imgHeader
|
||||
.arg(on ?
|
||||
QStringLiteral(":/style/clipper-on.svg")
|
||||
: QStringLiteral(":/style/clipper-off.svg"),
|
||||
on ?
|
||||
tr("Clipper: On")
|
||||
: tr("Clipper: Off"));
|
||||
case ICON_AGC:
|
||||
return imgHeader
|
||||
.arg(on ?
|
||||
QStringLiteral(":/style/agc-on.svg")
|
||||
: QStringLiteral(":/style/agc-off.svg"),
|
||||
on ?
|
||||
tr("Automatic Gain Control (AGC): On")
|
||||
: tr("Automatic Gain Control (AGC): Off"));
|
||||
case ICON_CHANNEL_SPACING:
|
||||
return imgHeader
|
||||
.arg(QStringLiteral(":/style/channel-spacing-on.svg"),
|
||||
tr("Channel Spacing"));
|
||||
case ICON_SPACER:
|
||||
return imgHeader
|
||||
.arg(QStringLiteral(":/style/line_style_solid_v.svg"),
|
||||
tr("Channel Spacing"));
|
||||
default:
|
||||
return QStringLiteral("-");
|
||||
}
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningFrequencyDataModel::unassignRadioCircuit(int32_t cnrConfigId)
|
||||
{
|
||||
if (cnrConfigId < 0)
|
||||
return false;
|
||||
|
||||
|
||||
m_multipleAssignedCnrIds.erase(
|
||||
std::remove(m_multipleAssignedCnrIds.begin(), m_multipleAssignedCnrIds.end(), cnrConfigId),
|
||||
m_multipleAssignedCnrIds.end());
|
||||
|
||||
beginResetModel();
|
||||
m_frequencyPlanningData.remove(cnrConfigId);
|
||||
ConfigTreeItem* item = searchCnrConfig(m_rootItem, cnrConfigId);
|
||||
if(!item)
|
||||
return false;
|
||||
ItemData id = item->data().value<ItemData>();
|
||||
id.clearRadioCircuit();
|
||||
item->setData(QVariant::fromValue(id));
|
||||
item->removeAllChildren();
|
||||
endResetModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void EditFrequencyPlanningFrequencyDataModel::setFrequencePlanningId(int id)
|
||||
{
|
||||
if (m_initPlan.id() == id)
|
||||
return;
|
||||
if (m_initPlan.id() <= 0)
|
||||
{
|
||||
m_initPlan.id(id);
|
||||
return;
|
||||
}
|
||||
WARNING_LOG(m_logger) << "Trying to set a new frequency planning id but there is alreay an id set ("
|
||||
<< m_initPlan.id() << " - " << id << ")";
|
||||
}
|
||||
|
||||
ModifyFrequencyPlanningRequest EditFrequencyPlanningFrequencyDataModel::modifyFrequencyPlanningRequest() const
|
||||
{
|
||||
std::vector<FrequencyPlanningData> planningDataVec;
|
||||
planningDataVec.reserve(m_frequencyPlanningData.size());
|
||||
|
||||
for (const auto &keyValue : overKeyValue(m_frequencyPlanningData))
|
||||
{
|
||||
Q_ASSERT(keyValue.first > 0);
|
||||
CnrConfig config = m_avmDtc->cnrConfig(keyValue.second.cnrConfigId());
|
||||
if(( config.exerciseId().is_set() && config.exerciseId().get() == m_exerciseId) ||
|
||||
(!config.exerciseId().is_set() && m_exerciseId == 0))
|
||||
{
|
||||
FrequencyPlanningData fpd = keyValue.second;
|
||||
fpd.frequencyPlanningId() = m_initPlan.id();
|
||||
planningDataVec.push_back(fpd);
|
||||
}
|
||||
}
|
||||
|
||||
return { m_initPlan.id(),
|
||||
m_initPlan.exerciseId().is_set() ? m_initPlan.exerciseId().get() : 0,
|
||||
m_initPlan.name(),
|
||||
m_initPlan.date(),
|
||||
m_initPlan.frequencySetId(),
|
||||
planningDataVec};
|
||||
}
|
||||
|
||||
FrequencyPlanning EditFrequencyPlanningFrequencyDataModel::toFrequencyPlanning() const
|
||||
{
|
||||
std::vector<FrequencyPlanningData> planningDataVec;
|
||||
planningDataVec.reserve(m_frequencyPlanningData.size());
|
||||
|
||||
for (const auto &keyValue : overKeyValue(m_frequencyPlanningData))
|
||||
{
|
||||
Q_ASSERT(keyValue.first > 0);
|
||||
CnrConfig config = m_avmDtc->cnrConfig(keyValue.second.cnrConfigId());
|
||||
if(( config.exerciseId().is_set() && config.exerciseId().get() == m_exerciseId) ||
|
||||
(!config.exerciseId().is_set() && m_exerciseId == 0))
|
||||
{
|
||||
FrequencyPlanningData fpd = keyValue.second;
|
||||
fpd.frequencyPlanningId() = m_initPlan.id();
|
||||
planningDataVec.push_back(fpd);
|
||||
}
|
||||
}
|
||||
|
||||
FrequencyPlanning frequencyPlanning = m_initPlan;
|
||||
frequencyPlanning.data(planningDataVec);
|
||||
|
||||
return frequencyPlanning;
|
||||
}
|
||||
|
||||
int EditFrequencyPlanningFrequencyDataModel::findCnrConfigByName(const QString &name) const
|
||||
{
|
||||
int id = -1;
|
||||
std::function<bool(const CnrConfig &)> findByNameInExercise = [this, &name, &id] (const CnrConfig &cnrConfig)
|
||||
{
|
||||
if (cnrConfig.exerciseId().is_set() && cnrConfig.exerciseId() != m_initPlan.exerciseId())
|
||||
return false;
|
||||
if (QString::fromStdString(cnrConfig.radioCircuit()) != name)
|
||||
return false;
|
||||
|
||||
id = cnrConfig.id();
|
||||
return true;
|
||||
};
|
||||
|
||||
m_avmDtc->cnrConfigs(findByNameInExercise);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QByteArray EditFrequencyPlanningFrequencyDataModel::uiToJson() const
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::AVMEditFrequencyPlanning);
|
||||
obj[QStringLiteral("frequencySetId")] = m_initPlan.frequencySetId();
|
||||
|
||||
QJsonArray arr;
|
||||
for (const auto &keyValue : overKeyValue(m_frequencyPlanningData))
|
||||
{
|
||||
QJsonObject inner;
|
||||
const FrequencyPlanningData &info = keyValue.second;
|
||||
|
||||
inner[QStringLiteral("cnrChannelId")] = m_avmDtc->cnrConfig(info.cnrConfigId()).cnrChannelId();
|
||||
inner[QStringLiteral("properties")] = QString::fromStdString(info.properties());
|
||||
|
||||
arr.append(inner);
|
||||
}
|
||||
|
||||
obj[QStringLiteral("planningInfos")] = arr;
|
||||
|
||||
QJsonDocument doc(obj);
|
||||
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
|
||||
void EditFrequencyPlanningFrequencyDataModel::setFrequencyPlanningData(const FrequencyPlanningData &fpd)
|
||||
{
|
||||
ConfigTreeItem* item = searchCnrConfig(m_rootItem, fpd.cnrConfigId());
|
||||
if(!item)
|
||||
{
|
||||
if (!m_cnrConfigs.contains(fpd.cnrConfigId()))
|
||||
return;
|
||||
beginResetModel();
|
||||
ItemData data(m_cnrConfigs[fpd.cnrConfigId()]);
|
||||
data.readOnly = isReadOnly(fpd.properties());
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(fpd.properties());
|
||||
if (circuits.size() > 1)
|
||||
{
|
||||
ConfigTreeItem *configItem = new ConfigTreeItem(QVariant::fromValue(data));
|
||||
insertRow(m_rootItem->childCount(), indexFromItem(m_rootItem), configItem);
|
||||
for (RadioCircuit *circuit : qAsConst(circuits))
|
||||
{
|
||||
data.radioCircuit = circuit;
|
||||
ConfigTreeItem *childItem = new ConfigTreeItem(QVariant::fromValue(data));
|
||||
insertRow(configItem->childCount(), indexFromItem(configItem), childItem);
|
||||
}
|
||||
}
|
||||
else if (circuits.size() == 1)
|
||||
{
|
||||
data.radioCircuit = circuits[0];
|
||||
ConfigTreeItem *configItem = new ConfigTreeItem(QVariant::fromValue(data));
|
||||
insertRow(m_rootItem->childCount(), indexFromItem(m_rootItem), configItem);
|
||||
}
|
||||
m_frequencyPlanningData[fpd.cnrConfigId()] = fpd;
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(fpd.properties());
|
||||
ItemData data = item->data().value<ItemData>();
|
||||
item->removeAllChildren();
|
||||
|
||||
if (circuits.size() == 1)
|
||||
{
|
||||
data.radioCircuit = circuits[0];
|
||||
item->setData(QVariant::fromValue(data));
|
||||
m_frequencyPlanningData.insert(fpd.cnrConfigId(), fpd);
|
||||
}
|
||||
if (circuits.size() <= 1)
|
||||
return;
|
||||
|
||||
for (RadioCircuit *circuit : qAsConst(circuits))
|
||||
{
|
||||
data.radioCircuit = circuit;
|
||||
ConfigTreeItem *childItem = new ConfigTreeItem(QVariant::fromValue(data));
|
||||
insertRow(item->childCount(), indexFromItem(item), childItem);
|
||||
}
|
||||
m_frequencyPlanningData.insert(fpd.cnrConfigId(), fpd);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningFrequencyDataModel::checkResourceAssignments()
|
||||
{
|
||||
bool bOk = true;
|
||||
|
||||
m_multipleAssignedCnrIds.clear();
|
||||
for (auto it = m_frequencyPlanningData.constBegin(); it != m_frequencyPlanningData.constEnd();)
|
||||
{
|
||||
const FrequencyPlanningData &p = it.value();
|
||||
|
||||
QSet<int> fsdIdsOuter = frequencySetDataIds(p.properties());
|
||||
|
||||
for (auto startSearchIt = ++it; startSearchIt != m_frequencyPlanningData.constEnd();++startSearchIt)
|
||||
{
|
||||
const FrequencyPlanningData &pI= startSearchIt.value();
|
||||
QSet<int> fsdIdsInner = frequencySetDataIds(pI.properties());
|
||||
for (int inner : qAsConst(fsdIdsInner))
|
||||
{
|
||||
for (int outer : qAsConst(fsdIdsOuter))
|
||||
{
|
||||
if (inner != outer)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---ist ungleich cnrConfigId(A): " << p.cnrConfigId()
|
||||
<< " (B): " << pI.cnrConfigId();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---ist gleich cnrConfigId(A): " << p.cnrConfigId()
|
||||
<< " (B): " << pI.cnrConfigId();
|
||||
if (!m_multipleAssignedCnrIds.contains(p.cnrConfigId()) )
|
||||
m_multipleAssignedCnrIds.append(p.cnrConfigId());
|
||||
|
||||
if (!m_multipleAssignedCnrIds.contains(pI.cnrConfigId()) )
|
||||
m_multipleAssignedCnrIds.append(pI.cnrConfigId());
|
||||
bOk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef LTS_DEBUG
|
||||
QString qs;
|
||||
for (int id : qAsConst(m_multipleAssignedCnrIds))
|
||||
{
|
||||
qs.append(QString::number(id));
|
||||
qs.append(QStringLiteral(", "));
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "---Number of multiple assigned frequency set data: " << m_multipleAssignedCnrIds.size()
|
||||
<< " cnrConfigIds: " << qs;
|
||||
#endif
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningFrequencyDataModel::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType)
|
||||
{
|
||||
ConfigTreeItem* item = searchCnrConfig(m_rootItem, data.id());
|
||||
|
||||
if (modType == DataModification::eRemoved)
|
||||
{
|
||||
|
||||
if (!item)
|
||||
return true;
|
||||
m_cnrConfigs.remove(data.id());
|
||||
m_frequencyPlanningData.remove(data.id());
|
||||
return removeRow(item->row());
|
||||
}
|
||||
|
||||
|
||||
if (modType == DataModification::eAdded ||
|
||||
(!item && data.exerciseId().is_set() && m_exerciseId == data.exerciseId().get())
|
||||
)
|
||||
{
|
||||
Q_ASSERT(!item);
|
||||
|
||||
m_cnrConfigs.insert(data.id(), data);
|
||||
ConfigTreeItem *newItem = new ConfigTreeItem(QVariant::fromValue(ItemData(data)));
|
||||
m_rootItem->setModified(true);
|
||||
insertRow(0, indexFromItem(m_rootItem), newItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (item && data.exerciseId().is_set() && m_exerciseId != data.exerciseId().get())
|
||||
return removeRow(item->row());
|
||||
|
||||
|
||||
if(item)
|
||||
{
|
||||
ItemData id = item->data().value<ItemData>();
|
||||
id.cnrConfig = data;
|
||||
item->setData(QVariant::fromValue(id));
|
||||
|
||||
|
||||
if(id.radioCircuit)
|
||||
id.radioCircuit->name = QString::fromStdString(data.radioCircuit());
|
||||
|
||||
item->setModified(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EditFrequencyPlanningFrequencyDataModel::ConfigTreeItem* EditFrequencyPlanningFrequencyDataModel::searchCnrConfig(const NGLTreeItem *parentItem, int cnrConfigId) const
|
||||
{
|
||||
const int rowCount = parentItem->childCount();
|
||||
for (int r = 0; r < rowCount; ++r)
|
||||
{
|
||||
ConfigTreeItem *child = static_cast<ConfigTreeItem *>(parentItem->child(r));
|
||||
if (child->data().value<ItemData>().cnrConfig.id() == cnrConfigId)
|
||||
return child;
|
||||
child = searchCnrConfig(child, cnrConfigId);
|
||||
if (child)
|
||||
return child;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QSet<int> EditFrequencyPlanningFrequencyDataModel::getAllocatedFrequencyPlanningSetIds()
|
||||
{
|
||||
QSet<int> result;
|
||||
for (const auto &fpd : qAsConst(m_frequencyPlanningData))
|
||||
{
|
||||
result += AudioVideoManagement::frequencySetDataIds(fpd.properties());
|
||||
}
|
||||
|
||||
if(m_exerciseId == 0)
|
||||
{
|
||||
QMap<qint32,AudioVideoManagement::FrequencyPlanning> frequencyPlannings = m_avmDtc->frequencyPlannings();
|
||||
for(const auto &frequencyPlanning : qAsConst(frequencyPlannings))
|
||||
{
|
||||
if(!frequencyPlanning.exerciseId().is_set())
|
||||
continue;
|
||||
|
||||
for(const auto &frequencyPlanningData : frequencyPlanning.data())
|
||||
{
|
||||
result += AudioVideoManagement::frequencySetDataIds(frequencyPlanningData.properties());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FPFDelegate::FPFDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
void FPFDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() == EditFrequencyPlanningFrequencyDataModel::Columns::PROPERTIES)
|
||||
{
|
||||
QStyleOptionViewItem options = option;
|
||||
initStyleOption(&options, index);
|
||||
|
||||
painter->save();
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(options.text);
|
||||
|
||||
options.text = QString();
|
||||
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
|
||||
|
||||
painter->translate(options.rect.left(), options.rect.top());
|
||||
QRect clip(0, 0, options.rect.width(), options.rect.height());
|
||||
doc.drawContents(painter, clip);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
else
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
|
||||
QSize FPFDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const
|
||||
{
|
||||
QStyleOptionViewItem options = option;
|
||||
initStyleOption(&options, index);
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(options.text);
|
||||
doc.setTextWidth(options.rect.width());
|
||||
return QSize(doc.idealWidth(), doc.size().height());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nglwidgets/ngltreeitem.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include "avm_frequency_planning_helper.h"
|
||||
#include <nglwidgets/ngltreemodel.h>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
|
||||
class CnrConfig;
|
||||
|
||||
class FPFDelegate
|
||||
: public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FPFDelegate(QObject *parent = nullptr);
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QSize sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
|
||||
|
||||
};
|
||||
|
||||
class EditFrequencyPlanningFrequencyDataModel
|
||||
: public NGLTreeModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
CHANNEL,
|
||||
RADIO_CIRCUIT_ID,
|
||||
RADIO_CIRCUIT,
|
||||
PARTY,
|
||||
UNIT,
|
||||
RADIO_STATION,
|
||||
FREQUENCY,
|
||||
FUNCTION,
|
||||
DEVICE,
|
||||
AKW_BUNDLE,
|
||||
FSB_BUNDLE,
|
||||
AKW_RADIO_CIRCUIT,
|
||||
COMSEC,
|
||||
PILOTTON,
|
||||
OPERATING_MODE,
|
||||
PROPERTIES,
|
||||
CHANNEL_SPACING,
|
||||
SQUELCH,
|
||||
GLOBAL,
|
||||
COUNT,
|
||||
};
|
||||
|
||||
enum PropertyData
|
||||
{
|
||||
ICON_PILOTTON,
|
||||
ICON_MODULATION_TYPE,
|
||||
ICON_SQUELCH,
|
||||
ICON_CLIPPER,
|
||||
ICON_AGC,
|
||||
ICON_CHANNEL_SPACING,
|
||||
ICON_SPACER,
|
||||
ICON_COUNT,
|
||||
};
|
||||
|
||||
struct ItemData
|
||||
{
|
||||
CnrConfig cnrConfig;
|
||||
RadioCircuit* radioCircuit = nullptr;
|
||||
QString _name;
|
||||
bool readOnly = false;
|
||||
|
||||
ItemData() = default;
|
||||
ItemData(const CnrConfig &_cnrConfig, const QString &itemName = {}, RadioCircuit* _rc = nullptr)
|
||||
: cnrConfig(_cnrConfig)
|
||||
, radioCircuit(_rc)
|
||||
, _name(itemName)
|
||||
{}
|
||||
|
||||
QString name() const { return radioCircuit ? radioCircuit->name : _name; }
|
||||
void setName(const QString &itemName) { _name = itemName; }
|
||||
void setName(const std::string &itemName) { setName(QString::fromStdString(itemName)); }
|
||||
void clearRadioCircuit() { delete radioCircuit; radioCircuit = nullptr; }
|
||||
};
|
||||
|
||||
class ConfigTreeItem final : public NGLTreeItem
|
||||
{
|
||||
public:
|
||||
using NGLTreeItem::NGLTreeItem;
|
||||
};
|
||||
|
||||
explicit EditFrequencyPlanningFrequencyDataModel(const FrequencyPlanning &initPlanning,
|
||||
int exerciseId,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override final;
|
||||
ItemData itemData(const QModelIndex &index);
|
||||
|
||||
void setFrequencePlanningId(int id);
|
||||
|
||||
bool unassignRadioCircuit(int32_t cnrConfigId);
|
||||
|
||||
int32_t getFrequencySetId() const { return m_initPlan.frequencySetId(); }
|
||||
QSet<int> getAllocatedFrequencyPlanningSetIds();
|
||||
|
||||
ModifyFrequencyPlanningRequest modifyFrequencyPlanningRequest() const;
|
||||
|
||||
FrequencyPlanning toFrequencyPlanning() const;
|
||||
|
||||
QByteArray uiToJson() const;
|
||||
|
||||
FrequencyPlanningData getfrequencyPlanningData(int cnrConfigId) { return m_frequencyPlanningData.value(cnrConfigId); }
|
||||
|
||||
bool checkResourceAssignments();
|
||||
void setFrequencyPlanningData(const FrequencyPlanningData &fpd);
|
||||
|
||||
private slots:
|
||||
void onFrequencyPlanningChanged(const FrequencyPlanning &planning, DataModification dm);
|
||||
|
||||
private:
|
||||
void removeCnrId(int32_t cnrId);
|
||||
int findCnrConfigByName(const QString &name) const;
|
||||
void setCnrConfigs(const QVector<CnrConfig> &dataVec);
|
||||
|
||||
bool onCnrConfigChanged(const AudioVideoManagement::CnrConfig &data, DataModification modType);
|
||||
EditFrequencyPlanningFrequencyDataModel::ConfigTreeItem* searchCnrConfig(const NGLTreeItem *parentItem, int cnrConfigId) const;
|
||||
QString createIcon(PropertyData PropertyDataType, bool on = true, ModulationType type = ModulationType::AM) const;
|
||||
|
||||
int m_exerciseId;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
FrequencyPlanning m_initPlan;
|
||||
QMap<int, FrequencySetDataWithId> m_freqSetData;
|
||||
QMap<int, ParticipantManagement::Participant> m_units;
|
||||
QMap<int, FrequencyPlanningData> m_frequencyPlanningData;
|
||||
QMap<int, CnrConfig> m_cnrConfigs;
|
||||
QVector<int> m_multipleAssignedCnrIds;
|
||||
int32_t m_frequencySetId;
|
||||
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::EditFrequencyPlanningFrequencyDataModel::ItemData)
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_frequency_planning_resource_data_model.h"
|
||||
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
|
||||
#include <AudioVideoManagement/avm_translation.h>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
EditFrequencyPlanningResourceDataModel::EditFrequencyPlanningResourceDataModel(const QSet<int> &assignedFrequencySetDataIds,
|
||||
const FrequencyBand frequencyBand,
|
||||
QObject *parent)
|
||||
: LtsAbstractTableModel<FrequencySetDataWithId>(
|
||||
{
|
||||
tr("FSD id"),
|
||||
tr("Function"),
|
||||
tr("Device"),
|
||||
tr("Frequency"),
|
||||
tr("AKW Bundle"),
|
||||
tr("FSB Bundle"),
|
||||
tr("AKW Radio Circuit"),
|
||||
tr("COMSEC"),
|
||||
}, parent)
|
||||
, m_assignedFrequencySetDataIds(assignedFrequencySetDataIds)
|
||||
, m_frequencyBand(frequencyBand)
|
||||
, m_logger(getLogger("EditFrequencyPlanningResourceDataModel"))
|
||||
{
|
||||
}
|
||||
|
||||
QVariant EditFrequencyPlanningResourceDataModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole && role != Qt::UserRole) || !indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
const FrequencySetDataWithId &setData = m_vecData.at(index.row());
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
QLocale locale(QLocale::German);
|
||||
switch (index.column())
|
||||
{
|
||||
case FREQ_SET_DATA_ID:
|
||||
return setData.id();
|
||||
case FUNCTION:
|
||||
return QString::fromStdString(setData.function());
|
||||
case DEVICE:
|
||||
return toString(setData.frequencyBand());
|
||||
case FREQUENCY:
|
||||
return tr("%1 MHz").arg(locale.toString(setData.frequency() / 1000., 'f', 3));
|
||||
case AKW_BUNDLE:
|
||||
if (setData.akwBundle().is_set())
|
||||
return setData.akwBundle().get();
|
||||
return QStringLiteral("-");
|
||||
case FSB_BUNDLE:
|
||||
if (setData.fsbBundle().is_set())
|
||||
return setData.fsbBundle().get();
|
||||
return QStringLiteral("-");
|
||||
case AKW_RADIO_CIRCUIT:
|
||||
if (setData.akwRadioCircuit())
|
||||
return setData.akwRadioCircuit().get();
|
||||
return QStringLiteral("-");
|
||||
case COMSEC:
|
||||
if (setData.comsec().is_set())
|
||||
return setData.comsec().get();
|
||||
return QStringLiteral("-");
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
return setData.id();
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningResourceDataModel::isFiltered(const AudioVideoManagement::FrequencySetDataWithId &data, DataModification modType) const
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (m_frequencyBand != FrequencyBand_def::REL &&
|
||||
data.frequencyBand() != m_frequencyBand)
|
||||
return true;
|
||||
|
||||
|
||||
if(m_frequencyBand == FrequencyBand_def::REL &&
|
||||
data.frequencyBand() != FrequencyBand_def::VHF)
|
||||
return true;
|
||||
|
||||
Q_UNUSED(modType);
|
||||
|
||||
if (m_assignedFrequencySetDataIds.contains(data.id()))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---m_assignments.size(): " << m_assignedFrequencySetDataIds.size()
|
||||
<< " frequencySetDataId: " << data.id() << " ist bereits enthalten";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class EditFrequencyPlanningResourceDataModel
|
||||
: public LtsWidgets::LtsAbstractTableModel<FrequencySetDataWithId>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
FREQ_SET_DATA_ID,
|
||||
FUNCTION,
|
||||
DEVICE,
|
||||
FREQUENCY,
|
||||
AKW_BUNDLE,
|
||||
FSB_BUNDLE,
|
||||
AKW_RADIO_CIRCUIT,
|
||||
COMSEC,
|
||||
RADIO_CIRCUIT,
|
||||
PARTY,
|
||||
UNIT,
|
||||
RADIO_STATION,
|
||||
PILOTTON,
|
||||
OPERATING_MODE,
|
||||
COUNT
|
||||
};
|
||||
|
||||
explicit EditFrequencyPlanningResourceDataModel(const QSet<int> &assignedFrequencySetDataIds,
|
||||
const FrequencyBand frequencyBand,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override final;
|
||||
|
||||
protected:
|
||||
bool isFiltered(const AudioVideoManagement::FrequencySetDataWithId &data, DataModification modType) const override;
|
||||
|
||||
private:
|
||||
QSet<int> m_assignedFrequencySetDataIds;
|
||||
FrequencyBand m_frequencyBand;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_frequency_planning_frequency_data_model.h"
|
||||
#include "avm_edit_frequency_planning_resource_dialog.h"
|
||||
#include "ui_avm_edit_frequency_planning_resource_dialog.h"
|
||||
#include "avm_frequency_planning_widget.h"
|
||||
#include <LtsWidgets/lts_combo_box.h>
|
||||
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <ParticipantManagement/ppm_translation.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <AudioVideoManagement/avm_translation.h>
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <LtsDataView/lts_data_view.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
|
||||
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
|
||||
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
|
||||
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <QTreeView>
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
EditFrequencyPlanningResourceDialog::EditFrequencyPlanningResourceDialog(int frequencySetId,
|
||||
const EditFrequencyPlanningSetResourceDialog::DialogMode dialogMode,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkCancel)
|
||||
, m_ui(new Ui::EditFrequencyPlanningResourceDialog)
|
||||
, m_frequencySetId(frequencySetId)
|
||||
, m_dialogMode(dialogMode)
|
||||
, m_logger(getLogger("EditFrequencyPlanningResourceDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Frequency_Planning"));
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningResourceDialog::init(LtsSession::LtsSession *session, const FrequencyPlanningData &planningData, const QSet<int> &assignedFrequencySetDataIds)
|
||||
{
|
||||
bool succ = true;
|
||||
m_session = session;
|
||||
m_planningData = planningData;
|
||||
m_assignedFrequencySetDataIds = assignedFrequencySetDataIds;
|
||||
|
||||
succ &= m_session->getDtc<AudioVideoManagement::DataInterface>(m_avmDtc);
|
||||
succ &= m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc);
|
||||
succ &= m_session->getDtc<InfrastructureManagement::DataInterface>(m_ismDtc);
|
||||
|
||||
if(!succ)
|
||||
return succ;
|
||||
|
||||
m_units = m_ppmDtc->units();
|
||||
m_config = m_avmDtc->cnrConfig(m_planningData.cnrConfigId());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
m_radioCircuitName = QString::fromStdString(m_config.radioCircuit());
|
||||
CnrChannel channel = m_avmDtc->cnrChannel(m_config.cnrChannelId());
|
||||
m_frequencyBand = channel.frequencyBand();
|
||||
|
||||
QVector<RadioCircuit*> circuits = AudioVideoManagement::fromJson(planningData.properties());
|
||||
bool readOnly = isReadOnly(planningData.properties());
|
||||
for (RadioCircuit *circuit : qAsConst(circuits))
|
||||
{
|
||||
addMemberWidget(circuit, readOnly);
|
||||
}
|
||||
if (circuits.count() < 2 && m_frequencyBand == FrequencyBand::REL)
|
||||
addMemberWidget();
|
||||
if (circuits.count() < 1)
|
||||
addMemberWidget();
|
||||
|
||||
|
||||
setLbRadioCiruit(m_config);
|
||||
|
||||
connect(m_avmDtc.get(), &AudioVideoManagement::Interface::Dtc::cnrConfigChanged,
|
||||
this, &EditFrequencyPlanningResourceDialog::onCnrConfigChanged);
|
||||
connect(m_ui->tswFrequencyMember, &LtsWidgets::LtsTabSequenceWidget::addMember,
|
||||
this, &EditFrequencyPlanningResourceDialog::addMemberWidgetEmpty);
|
||||
|
||||
qDeleteAll(circuits);
|
||||
|
||||
return succ;
|
||||
}
|
||||
|
||||
EditFrequencyPlanningResourceDialog::~EditFrequencyPlanningResourceDialog() = default;
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::retranslate()
|
||||
{
|
||||
|
||||
if (m_dialogMode == EditFrequencyPlanningSetResourceDialog::DialogMode::Edit)
|
||||
{
|
||||
translate(m_ui.get(), m_avmDtc->cnrConfig(m_planningData.cnrConfigId()), m_radioCircuitName, tr("Radio Circuit"));
|
||||
}
|
||||
else
|
||||
{
|
||||
QString qs = tr("Assign Radio Circuit: %1").arg(m_radioCircuitName);
|
||||
translate(m_ui.get(), qs);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditFrequencyPlanningResourceDialog::apply()
|
||||
{
|
||||
QJsonArray array;
|
||||
for(int memberCount = 0; memberCount < m_ui->tswFrequencyMember->getMemberlistSize(); memberCount++)
|
||||
{
|
||||
FrequencyPlanningWidget *planningWidget = qobject_cast<FrequencyPlanningWidget*>(m_ui->tswFrequencyMember->getWidget(memberCount));
|
||||
if(!planningWidget)
|
||||
continue;
|
||||
|
||||
array.append(planningWidget->toJson());
|
||||
}
|
||||
QJsonDocument doc;
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("subCircuits"), array);
|
||||
doc.setObject(obj);
|
||||
|
||||
FrequencyPlanningData fpd;
|
||||
fpd.properties(doc.toJson().toStdString());
|
||||
fpd.cnrConfigId() = m_config.id();
|
||||
|
||||
emit signalAssignRadioCircuit(fpd);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::onEnableOkButton()
|
||||
{
|
||||
slotChangesMade();
|
||||
}
|
||||
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::addMemberWidget(RadioCircuit *radioCircuit, bool readOnly)
|
||||
{
|
||||
FrequencyPlanningWidget *widget = new FrequencyPlanningWidget(m_avmDtc, m_assignedFrequencySetDataIds, this);
|
||||
widget->init(m_session,
|
||||
radioCircuit,
|
||||
m_config,
|
||||
m_frequencySetId,
|
||||
m_frequencyBand);
|
||||
connect(widget, &FrequencyPlanningWidget::onNameChanged,
|
||||
this, &EditFrequencyPlanningResourceDialog::onNameChanged);
|
||||
|
||||
widget->setDisabled(readOnly || m_dialogMode == EditFrequencyPlanningSetResourceDialog::DialogMode::Show);
|
||||
|
||||
widget->setObjectName((radioCircuit && m_frequencyBand == FrequencyBand::REL) ? radioCircuit->name : m_radioCircuitName);
|
||||
widget->setName( (radioCircuit && m_frequencyBand == FrequencyBand::REL) ? radioCircuit->name : m_radioCircuitName);
|
||||
|
||||
const auto &reqs = widget->requirements();
|
||||
for (const auto &req : reqs)
|
||||
m_uiRequirements->addRequirement({req.first, req.second});
|
||||
|
||||
m_ui->tswFrequencyMember->addWidget(widget, true, false);
|
||||
|
||||
for (int i=0 ; i< m_ui->tswFrequencyMember->getMemberlistSize(); ++i)
|
||||
{
|
||||
FrequencyPlanningWidget *w = qobject_cast<FrequencyPlanningWidget*>(m_ui->tswFrequencyMember->getWidget(i));
|
||||
if (!w)
|
||||
continue;
|
||||
w->setNameDisabled(m_ui->tswFrequencyMember->getMemberlistSize() == 1);
|
||||
w->setRelaisRestrictions(m_ui->tswFrequencyMember->getMemberlistSize() > 1);
|
||||
}
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &config, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (m_config.id() == config.id())
|
||||
{
|
||||
setLbRadioCiruit(config);
|
||||
m_radioCircuitName = QString::fromStdString(config.radioCircuit());
|
||||
retranslate();
|
||||
}
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::setLbRadioCiruit(const AudioVideoManagement::CnrConfig &config)
|
||||
{
|
||||
|
||||
ParticipantManagement::Party party = m_ppmDtc->party(config.partyId());
|
||||
QString partyName = ParticipantManagement::trPartyName(party.name());
|
||||
|
||||
QString unitString;
|
||||
if (config.unitId().is_set())
|
||||
{
|
||||
int unitId = config.unitId().get();
|
||||
auto unit = m_units.value(unitId);
|
||||
if (unit.id() == unitId)
|
||||
{
|
||||
if (unit.designator().size() > 0)
|
||||
unitString = QString::fromStdString(unit.designator()) + QLatin1Char('/');
|
||||
unitString.append(QString::fromStdString(unit.tacticalIdentifier()));
|
||||
}
|
||||
}
|
||||
m_ui->lblUnit->setText(unitString);
|
||||
CnrChannel channel = m_avmDtc->cnrChannel(m_config.cnrChannelId());
|
||||
m_ui->lblChannel->setText(QString::fromStdString(channel.name()));
|
||||
m_ui->lblFrequencyBand->setText(toString(m_frequencyBand));
|
||||
m_ui->lblRadioCircuit->setText(m_radioCircuitName);
|
||||
m_ui->lblParty->setText(partyName);
|
||||
}
|
||||
|
||||
void EditFrequencyPlanningResourceDialog::onNameChanged(const QString &name)
|
||||
{
|
||||
m_ui->tswFrequencyMember->changeTabName(name);
|
||||
if (m_ui->tswFrequencyMember->getMemberlistSize() > 1)
|
||||
return;
|
||||
m_radioCircuitName = name;
|
||||
m_ui->lblRadioCircuit->setText(m_radioCircuitName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
#include "avm_frequency_planning_helper.h"
|
||||
#include "avm_edit_frequency_planning_set_resource_dialog.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditFrequencyPlanningResourceDialog;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
namespace LtsWidgets
|
||||
{
|
||||
class LtsComboBox;
|
||||
}
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class EditFrequencyPlanningResourceDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
explicit EditFrequencyPlanningResourceDialog(int frequencySetId,
|
||||
const EditFrequencyPlanningSetResourceDialog::DialogMode dialogMode,
|
||||
QWidget *parent);
|
||||
|
||||
~EditFrequencyPlanningResourceDialog();
|
||||
void retranslate() override;
|
||||
bool init(LtsSession::LtsSession *session, const FrequencyPlanningData &planningData, const QSet<int> &assignedFrequencySetDataIds);
|
||||
|
||||
protected:
|
||||
bool apply() override;
|
||||
|
||||
signals:
|
||||
void signalAssignRadioCircuit(const FrequencyPlanningData &doc);
|
||||
|
||||
private slots:
|
||||
void onEnableOkButton();
|
||||
void onCnrConfigChanged(const AudioVideoManagement::CnrConfig &config, DataModification modType);
|
||||
void setLbRadioCiruit(const CnrConfig &config);
|
||||
void addMemberWidget(RadioCircuit *radioCircuit = nullptr, bool readOnly = false);
|
||||
void addMemberWidgetEmpty() { addMemberWidget(); }
|
||||
void onNameChanged(const QString &name);
|
||||
|
||||
private:
|
||||
QMap<int32_t, ParticipantManagement::Participant> m_units;
|
||||
|
||||
std::unique_ptr<Ui::EditFrequencyPlanningResourceDialog> m_ui;
|
||||
int m_frequencySetId;
|
||||
FrequencyPlanningData m_planningData;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
int m_exerciseId;
|
||||
CnrConfig m_config;
|
||||
EditFrequencyPlanningSetResourceDialog::DialogMode m_dialogMode;
|
||||
FrequencyBand m_frequencyBand;
|
||||
QString m_radioCircuitName;
|
||||
QSet<int> m_assignedFrequencySetDataIds;
|
||||
LtsSession::LtsSession *m_session;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditFrequencyPlanningResourceDialog</class>
|
||||
<widget class="QWidget" name="EditFrequencyPlanningResourceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>542</width>
|
||||
<height>284</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Select Function</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lblFrequencyBand">
|
||||
<property name="text">
|
||||
<string notr="true"><RadioCircuit></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" rowspan="6">
|
||||
<widget class="LtsWidgets::LtsTabSequenceWidget" name="tswFrequencyMember"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="lbxUnit">
|
||||
<property name="text">
|
||||
<string>Unit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbxRadioCircuit">
|
||||
<property name="text">
|
||||
<string>Radio Circuit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="lblRadioCircuit">
|
||||
<property name="text">
|
||||
<string notr="true"><SET></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="lbxParty">
|
||||
<property name="text">
|
||||
<string>Party:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="lblParty">
|
||||
<property name="text">
|
||||
<string notr="true"><PARTY></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="lblUnit">
|
||||
<property name="text">
|
||||
<string notr="true"><UNIT></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbxFrequencyBand">
|
||||
<property name="text">
|
||||
<string>Frequency Band:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>13</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>171</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbxChannel">
|
||||
<property name="text">
|
||||
<string>Channel:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="lblChannel">
|
||||
<property name="text">
|
||||
<string notr="true"><CHANNEL></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsTabSequenceWidget</class>
|
||||
<extends>QGroupBox</extends>
|
||||
<header>LtsWidgets/lts_tab_sequence_widget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_edit_frequency_planning_frequency_data_model.h"
|
||||
#include "avm_edit_frequency_planning_set_resource_dialog.h"
|
||||
#include "ui_avm_edit_frequency_planning_set_resource_dialog.h"
|
||||
#include "avm_edit_frequency_planning_resource_data_model.h"
|
||||
|
||||
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <LtsDataView/lts_data_view.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
EditFrequencyPlanningSetResourceDialog::EditFrequencyPlanningSetResourceDialog(
|
||||
const QSet<int> &assignedFrequencySetDataIds,
|
||||
const RcOperatingMode operatingMode,
|
||||
int32_t frequencySetId,
|
||||
const int &cnrConfigId,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
QWidget *parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
|
||||
, m_ui(new Ui::EditFrequencyPlanningSetResourceDialog)
|
||||
, m_frequencySetId(frequencySetId)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_frequencyResourceDataModel(nullptr)
|
||||
, m_config(m_avmDtc->cnrConfig(cnrConfigId))
|
||||
, m_logger(getLogger("EditFrequencyPlanningSetResourceDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
CnrChannel channel = m_avmDtc->cnrChannel(m_config.cnrChannelId());
|
||||
|
||||
|
||||
|
||||
m_frequencyResourceDataModel = new EditFrequencyPlanningResourceDataModel(assignedFrequencySetDataIds, channel.frequencyBand(), this);
|
||||
|
||||
std::vector<FrequencySetDataWithId> dataVec = m_avmDtc->frequencySet(m_frequencySetId).data();
|
||||
|
||||
for (const auto &it : dataVec)
|
||||
{
|
||||
if((operatingMode == RcOperatingMode_def::AkwEncEccm ||
|
||||
operatingMode == RcOperatingMode_def::AkwEncNone)
|
||||
&& it.akwRadioCircuit() == 0)
|
||||
continue;
|
||||
if((operatingMode != RcOperatingMode_def::AkwEncEccm &&
|
||||
operatingMode != RcOperatingMode_def::AkwEncNone)
|
||||
&& it.akwRadioCircuit() != 0)
|
||||
continue;
|
||||
m_frequencyResourceDataModel->insertRow(it);
|
||||
}
|
||||
m_ui->dvFrequencyData->setModel(m_frequencyResourceDataModel);
|
||||
|
||||
#ifndef LTS_DEBUG
|
||||
m_ui->dvFrequencyData->hideColumn(EditFrequencyPlanningResourceDataModel::Columns::FREQ_SET_DATA_ID);
|
||||
#endif
|
||||
|
||||
|
||||
connect(m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked,
|
||||
this, &EditFrequencyPlanningSetResourceDialog::accept);
|
||||
connect(m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked,
|
||||
this, &EditFrequencyPlanningSetResourceDialog::reject);
|
||||
connect(m_ui->dvFrequencyData, &LtsDataView::LtsDataView::doubleClicked,
|
||||
this, &EditFrequencyPlanningSetResourceDialog::accept);
|
||||
|
||||
}
|
||||
|
||||
EditFrequencyPlanningSetResourceDialog::~EditFrequencyPlanningSetResourceDialog() = default;
|
||||
|
||||
void EditFrequencyPlanningSetResourceDialog::accept()
|
||||
{
|
||||
LtsWidgets::LtsFramelessDialog::accept();
|
||||
|
||||
const QModelIndex idx = m_ui->dvFrequencyData->currentIndex();
|
||||
if (!idx.isValid())
|
||||
return;
|
||||
|
||||
emit onSelectedFrequencySet(m_frequencyResourceDataModel->getRowData(idx.row()).id());
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_frameless_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_enums.hpp>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditFrequencyPlanningSetResourceDialog;
|
||||
}
|
||||
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class EditFrequencyPlanningResourceDataModel;
|
||||
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
class EditFrequencyPlanningSetResourceDialog : public LtsWidgets::LtsFramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum DialogMode
|
||||
{
|
||||
Edit,
|
||||
Assign,
|
||||
Show
|
||||
};
|
||||
|
||||
explicit EditFrequencyPlanningSetResourceDialog(const QSet<int> &assignedFrequencySetDataIds,
|
||||
const RcOperatingMode operatingMode,
|
||||
int32_t frequencySetId,
|
||||
const int &cnrConfigId,
|
||||
const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
QWidget *parent);
|
||||
|
||||
|
||||
~EditFrequencyPlanningSetResourceDialog();
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
|
||||
signals:
|
||||
void onSelectedFrequencySet(int frequencySetDataId);
|
||||
private:
|
||||
|
||||
std::unique_ptr<Ui::EditFrequencyPlanningSetResourceDialog> m_ui;
|
||||
int32_t m_frequencySetId;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
EditFrequencyPlanningResourceDataModel *m_frequencyResourceDataModel;
|
||||
CnrConfig m_config;
|
||||
DialogMode m_dialogMode;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditFrequencyPlanningSetResourceDialog</class>
|
||||
<widget class="QWidget" name="EditFrequencyPlanningSetResourceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>933</width>
|
||||
<height>587</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Asset Stocks</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblDataView">
|
||||
<property name="text">
|
||||
<string>To assign select an entry:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsDataView::LtsDataView" name="dvFrequencyData"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LtsWidgets::LtsDialogButtonBox" name="ltsDialogButtonBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsDialogButtonBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsWidgets/lts_dialog_button_box.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+492
@@ -0,0 +1,492 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_frequency_planning_dialog.h"
|
||||
#include "ui_avm_frequency_planning_dialog.h"
|
||||
#include "avm_frequency_planning_dialog_model.h"
|
||||
#include "avm_edit_frequency_planning_dialog.h"
|
||||
#include "avm_init_frequency_planning_dialog.h"
|
||||
|
||||
#include <InfrastructureManagement/ism_dtc.h>
|
||||
#include <LtsUtilsGuiDds/request_helper.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <PluginInterfaces/gui_plugin_interface.h>
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include <ParticipantManagement/ppm_dtc.h>
|
||||
#include <AudioVideoManagement/avm_translation.h>
|
||||
|
||||
#include <LtsWidgets/lts_base_layout_widget.h>
|
||||
#include <LtsPrinting/printing.h>
|
||||
#include <QTreeView>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
FrequencyPlanningDialog::FrequencyPlanningDialog(LtsSession::LtsSession *session, const QString &menuGroup, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||||
, m_ui(new Ui::FrequencyPlanningDialog)
|
||||
, m_menuGroup(menuGroup)
|
||||
, m_copy(false)
|
||||
, m_session(session)
|
||||
, m_model(nullptr)
|
||||
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
||||
, m_activePlanning( { -1, -1 })
|
||||
, m_avmDtc(nullptr)
|
||||
, m_avmFtc(nullptr)
|
||||
, m_ppmDtc(nullptr)
|
||||
, m_ismDtc(nullptr)
|
||||
, m_flmGui(nullptr)
|
||||
, m_activeFrequencyPlanningStatus(0)
|
||||
, m_logger(getLogger("FrequencyPlanningDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
DEBUG_LOG(m_logger) << "---FrequencyPlanningDialog() ";
|
||||
m_ui->dataView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_ui->dataView->treeView()->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &FrequencyPlanningDialog::onPrint);
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Frequency_Planning"));
|
||||
}
|
||||
|
||||
FrequencyPlanningDialog::~FrequencyPlanningDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("Frequency Planning"));
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::unsetActiveFrequencyPlanning()
|
||||
{
|
||||
m_ui->lbActiveFrequencyPlanning->setText(tr("No Frequency Planning set"));
|
||||
m_activePlanning = { -1, -1 };
|
||||
m_model->unsetActivePlanning();
|
||||
onSelectionChanged();
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::setActiveFrequencyPlanning(const ActiveFrequencyPlanning &activePlanning)
|
||||
{
|
||||
m_ui->lbActiveFrequencyPlanning->setText(QString::fromStdString(m_avmDtc->frequencyPlanning(activePlanning.frequencyPlanningId()).name()));
|
||||
m_activePlanning = activePlanning;
|
||||
m_model->setActivePlanning(m_activePlanning.frequencyPlanningId());
|
||||
onSelectionChanged();
|
||||
}
|
||||
|
||||
bool FrequencyPlanningDialog::init(const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc)
|
||||
{
|
||||
if (!(ppmDtc->enableParty() &&
|
||||
ppmDtc->enableParticipant() &&
|
||||
ppmDtc->enableType() &&
|
||||
avmDtc->enableCnrConfig() &&
|
||||
avmDtc->enableFrequencyPlanning() &&
|
||||
avmDtc->enableFrequencySet() &&
|
||||
avmDtc->enableActiveFrequencyPlanning() &&
|
||||
ismDtc->enableMainStructureElement()))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Could not enable topics";
|
||||
return false;
|
||||
}
|
||||
|
||||
delete m_model;
|
||||
m_model = new FrequencyPlanningDialogModel(m_session->exerciseId(), this);
|
||||
|
||||
m_avmDtc = avmDtc;
|
||||
m_avmFtc = avmFtc;
|
||||
m_ppmDtc = ppmDtc;
|
||||
m_ismDtc = ismDtc;
|
||||
m_exmDtc = exmDtc;
|
||||
|
||||
if (!m_model->init(avmDtc))
|
||||
{
|
||||
delete m_model;
|
||||
m_model = nullptr;
|
||||
ERROR_LOG(m_logger) << "Could not init model";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_proxyModel = new FrequencyPlanningDialogProxyModel(this);
|
||||
m_proxyModel->setSourceModel(m_model);
|
||||
m_ui->dataView->setModel(m_proxyModel);
|
||||
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &FrequencyPlanningDialog::onAddClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &FrequencyPlanningDialog::onEditClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &FrequencyPlanningDialog::onRemoveClicked);
|
||||
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save, this, &FrequencyPlanningDialog::onActivateDeactivatePlanningClicked);
|
||||
|
||||
connect(m_ui->dataView, &LtsDataView::LtsDataView::signalSelectionChanged,
|
||||
this, &FrequencyPlanningDialog::onSelectionChanged);
|
||||
|
||||
unsetActiveFrequencyPlanning();
|
||||
|
||||
|
||||
connect(m_ui->dataView, &LtsDataView::LtsDataView::signalDoubleClicked,
|
||||
this, &FrequencyPlanningDialog::onEditClicked);
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::activeFrequencyPlanningChanged,
|
||||
this, &FrequencyPlanningDialog::onActiveFrequencyPlanningChanged);
|
||||
|
||||
m_ui->dataView->hideColumn(FrequencyPlanningDialogModel::Columns::SET);
|
||||
|
||||
m_avmDtc->activeFrequencyPlannings([this](const ActiveFrequencyPlanning & data)
|
||||
{
|
||||
onActiveFrequencyPlanningChanged(data, DataModification::eAdded);
|
||||
});
|
||||
onSelectionChanged();
|
||||
|
||||
setStatus(tr("No active Radio Controller connected."), {}, time(0) * 1000, TransmissionReason::TR_Unknown, Qt::red);
|
||||
for(auto &elem : m_avmDtc->frequencyPlanningStatuss())
|
||||
{
|
||||
if (!elem.isActive())
|
||||
continue;
|
||||
m_activeFrequencyPlanningStatus = elem.id();
|
||||
onFrequencyPlanningStatusChanged(elem, DataModification::eAdded);
|
||||
}
|
||||
connect(m_avmDtc.get(), &Interface::Dtc::frequencyPlanningStatusChanged, this, &FrequencyPlanningDialog::onFrequencyPlanningStatusChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onFrequencyPlanningStatusChanged(const AudioVideoManagement::FrequencyPlanningStatus &data, DataModification modType)
|
||||
{
|
||||
if (modType == DataModification::eModified)
|
||||
{
|
||||
if (data.id() != m_activeFrequencyPlanningStatus)
|
||||
return;
|
||||
}
|
||||
else if (modType == DataModification::eRemoved)
|
||||
{
|
||||
if (data.id() != m_activeFrequencyPlanningStatus)
|
||||
return;
|
||||
|
||||
m_activeFrequencyPlanningStatus = 0;
|
||||
setStatus(tr("No active Radio Controller connected."), {}, time(0) * 1000, TransmissionReason::TR_Unknown, Qt::red);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!data.isActive())
|
||||
return;
|
||||
m_activeFrequencyPlanningStatus = data.id();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (data.activated().is_set())
|
||||
{
|
||||
setStatus(tr("Activated"), QString::fromStdString(data.requester()), data.activated().get(), data.reason(), Qt::green);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.received().is_set())
|
||||
{
|
||||
setStatus(tr("In Progress"), QString::fromStdString(data.requester()), data.received().get(), data.reason(), Qt::yellow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.sent().is_set())
|
||||
{
|
||||
setStatus(tr("Sent"), QString::fromStdString(data.requester()), data.sent().get(), TransmissionReason::TR_Unknown, Qt::yellow);
|
||||
return;
|
||||
}
|
||||
setStatus(tr("Connection established, status unknown."), {}, time(0) * 1000, TransmissionReason::TR_Unknown, Qt::yellow);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::setStatus(const QString &statusText, const QString &requester, qint64 timeStampMsecs, TransmissionReason reason, Qt::GlobalColor color)
|
||||
{
|
||||
m_ui->lblStatus->setText(statusText);
|
||||
m_ui->lblStatusTime->setText(DTG::toStringMSec(timeStampMsecs));
|
||||
m_ui->lblStatus->setToolTip(toString(reason));
|
||||
m_ui->lblStatusTime->setToolTip(requester);
|
||||
setBackgroundColor(m_ui->lblStatus, color, color != Qt::black);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::tableColumnOrganiserSetting()
|
||||
{
|
||||
|
||||
m_ui->dataView->setColumnsOrganiserEnabled(identifier(), true);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::setBackgroundColor(QWidget *w, Qt::GlobalColor color, bool bSetColor)
|
||||
{
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
if (bSetColor)
|
||||
{
|
||||
QPalette pal = QApplication::palette(w);
|
||||
pal.setColor(QPalette::Window, color);
|
||||
w->setPalette(pal);
|
||||
w->setAutoFillBackground(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
w->setPalette(QApplication::palette(w));
|
||||
w->setAutoFillBackground(false);
|
||||
}
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onModifyFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onRemoveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onRemoveActiveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onModifyActiveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject)
|
||||
{
|
||||
m_requestHelper->requestReply(replyObject);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onAddClicked()
|
||||
{
|
||||
const QModelIndexList selectedRows = m_ui->dataView->selectedRows();
|
||||
Q_ASSERT(selectedRows.empty() || selectedRows.size() == 1);
|
||||
QMap<int32_t, FrequencySet> frequencySets = m_avmDtc->frequencySets();
|
||||
if (selectedRows.empty())
|
||||
{
|
||||
if(frequencySets.size() == 1)
|
||||
{
|
||||
FrequencyPlanning planning;
|
||||
|
||||
planning.id(0);
|
||||
if(m_session->exerciseId() != 0)
|
||||
planning.exerciseId(m_session->exerciseId());
|
||||
planning.frequencySetId(frequencySets.first().id());
|
||||
planning.date(m_session->partitionTime());
|
||||
showEditDialog(planning);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitFrequencyPlanningDialog *initDialog = new InitFrequencyPlanningDialog(m_session, m_avmDtc, this);
|
||||
|
||||
connect(initDialog, &InitFrequencyPlanningDialog::newInitFrequencyPlanning,
|
||||
this, &FrequencyPlanningDialog::showEditDialog);
|
||||
|
||||
m_copy = false;
|
||||
addDialog(initDialog, m_menuGroup, QStringLiteral("NewFrequencyPlanning"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_copy = true;
|
||||
qint64 dateOfCreation = m_session->partitionTime();
|
||||
FrequencyPlanning planning = m_model->data(selectedRows.constFirst(), Qt::UserRole).value<FrequencyPlanning>();
|
||||
planning.date(dateOfCreation);
|
||||
showEditDialog(planning);
|
||||
}
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onEditClicked()
|
||||
{
|
||||
QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
const FrequencyPlanning &fp = m_model->data(currentIndex, Qt::UserRole).value<FrequencyPlanning>();
|
||||
DEBUG_LOG(m_logger) << "---onEditClicked() FrequencyPlanningId: " << fp.id() << " FrequencySetDataId: " << fp.frequencySetId();
|
||||
|
||||
m_copy = false;
|
||||
showEditDialog(m_model->data(currentIndex, Qt::UserRole).value<FrequencyPlanning>());
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onRemoveClicked()
|
||||
{
|
||||
const QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
int planningId = m_model->data(currentIndex, Qt::UserRole).value<FrequencyPlanning>().id();
|
||||
|
||||
if (m_editDlgMap.contains(planningId))
|
||||
{
|
||||
m_editDlgMap.value(planningId)->deleteLater();
|
||||
m_editDlgMap.remove(planningId);
|
||||
}
|
||||
|
||||
Core::RemoveElementRequest req;
|
||||
|
||||
req.id(planningId);
|
||||
|
||||
m_requestHelper->startSingleRequest([this, req]()
|
||||
{
|
||||
return m_avmFtc->removeFrequencyPlanningRequest(req, this);
|
||||
});
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onSelectionChanged()
|
||||
{
|
||||
const QModelIndexList selectedRows = m_ui->dataView->selectedRows();
|
||||
bool hasSelection = !selectedRows.empty();
|
||||
bool selectedIsActive = false;
|
||||
if (hasSelection)
|
||||
{
|
||||
const QModelIndex currentIndex = selectedRows.constFirst();
|
||||
selectedIsActive = m_model->data(currentIndex, Qt::UserRole).value<FrequencyPlanning>().id() == m_activePlanning.frequencyPlanningId();
|
||||
}
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, hasSelection);
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, hasSelection && !selectedIsActive);
|
||||
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, hasSelection && m_session->exerciseId() && m_session->exerciseState() == LtsWidgets::ExcState::eStarted);
|
||||
|
||||
if (selectedIsActive)
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->setText(tr("Deactivate"));
|
||||
else
|
||||
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->setText(tr("Activate"));
|
||||
|
||||
bool disableGlobalPlanning = m_session->exerciseId() == 0 && m_proxyModel->rowCount() !=0;
|
||||
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, !disableGlobalPlanning);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onActivateDeactivatePlanningClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Frequency Planning"), tr("Are you sure you want to switch the active frequency planning?"),
|
||||
QMessageBox::StandardButtons(QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No))
|
||||
== QMessageBox::StandardButton::No)
|
||||
return;
|
||||
|
||||
QModelIndex currentIndex = m_ui->dataView->currentIndex();
|
||||
|
||||
if (!currentIndex.isValid())
|
||||
return;
|
||||
|
||||
int32_t planningId = m_model->data(currentIndex, Qt::UserRole).value<FrequencyPlanning>().id();
|
||||
|
||||
bool isActive = planningId == m_activePlanning.frequencyPlanningId();
|
||||
if (!isActive)
|
||||
{
|
||||
ModifyActiveFrequencyPlanningRequest request(m_session->exerciseId(), planningId);
|
||||
|
||||
m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->modifyActiveFrequencyPlanningRequest(request, this);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveActiveFrequencyPlanningRequest request(m_session->exerciseId());
|
||||
|
||||
m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->removeActiveFrequencyPlanningRequest(request, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::showEditDialog(const FrequencyPlanning &planning)
|
||||
{
|
||||
QString widgetIdentifier(QStringLiteral("FrequencyPlanning%1").arg(QString::number(planning.id())));
|
||||
if (m_copy)
|
||||
widgetIdentifier.append(QStringLiteral("Copy"));
|
||||
|
||||
if (baseLayoutWidget()->focusTab(menuGroup(), widgetIdentifier, LtsWidgets::LayoutArea::eDialogTab))
|
||||
return;
|
||||
EditFrequencyPlanningDialog *dlg = new EditFrequencyPlanningDialog(m_session, m_menuGroup, widgetIdentifier, planning, m_copy, m_avmDtc, m_avmFtc, m_ppmDtc, m_ismDtc, m_exmDtc, this);
|
||||
connect(dlg, &EditFrequencyPlanningDialog::aboutToCloseMe, this , [this](int planningId)
|
||||
{
|
||||
if (planningId <= 0 || !m_editDlgMap.contains(planningId))
|
||||
return;
|
||||
m_editDlgMap.remove(planningId);
|
||||
});
|
||||
|
||||
|
||||
addDialog(dlg, m_menuGroup, widgetIdentifier);
|
||||
|
||||
if (!m_copy)
|
||||
{
|
||||
m_editDlgMap.insert(planning.id(), dlg);
|
||||
}
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onActiveFrequencyPlanningChanged(const ActiveFrequencyPlanning &data, DataModification modType)
|
||||
{
|
||||
if (data.exerciseId() != m_session->exerciseId())
|
||||
return;
|
||||
|
||||
if (modType == DataModification::eRemoved)
|
||||
unsetActiveFrequencyPlanning();
|
||||
else
|
||||
setActiveFrequencyPlanning(data);
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onPrint()
|
||||
{
|
||||
LtsPrinting::printView(m_session, this, m_ui->dataView->treeView() );
|
||||
}
|
||||
|
||||
|
||||
void FrequencyPlanningDialog::onExportButtonClicked()
|
||||
{
|
||||
QByteArray byteArray = m_model->modelToJson();
|
||||
|
||||
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
|
||||
if (fileId > 0)
|
||||
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
|
||||
else
|
||||
ERROR_LOG(m_logger) << "Could not save file in library ";
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialog::onImportButtonClicked()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << " onImportButtonClicked() ";
|
||||
if (m_model->rowCount() > 0)
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Only available if the list is empty."),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray content;
|
||||
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::AVMFrequencyPlanning));
|
||||
if (fileId > 0)
|
||||
{
|
||||
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::AVMFrequencyPlanning)))
|
||||
{
|
||||
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this,
|
||||
tr("Invalid xml file content"),
|
||||
windowTitle(),
|
||||
LtsWidgets::Behaviour::Modal,
|
||||
LtsWidgets::Button::Yes,
|
||||
texts);
|
||||
}
|
||||
else
|
||||
{
|
||||
const QVector<ModifyFrequencyPlanningRequest> requests = m_model->jsonToFrequencyPlanningVector(content);
|
||||
for (const auto &request : requests)
|
||||
{
|
||||
m_requestHelper->startSingleRequest([this, request]()
|
||||
{
|
||||
return m_avmFtc->modifyFrequencyPlanningRequest(request, this);
|
||||
});
|
||||
}
|
||||
INFO_LOG(m_logger) << "--- onImportButtonClicked() ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_ftc.h>
|
||||
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <memory>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class FrequencyPlanningDialog;
|
||||
}
|
||||
|
||||
namespace LtsUtils
|
||||
{
|
||||
class RequestHelper;
|
||||
}
|
||||
|
||||
namespace ParticipantManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ExerciseManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
namespace Interface
|
||||
{
|
||||
class Dtc;
|
||||
}
|
||||
class FrequencyPlanningDialogModel;
|
||||
class FrequencyPlanningDialogProxyModel;
|
||||
class EditFrequencyPlanningDialog;
|
||||
|
||||
class FrequencyPlanningDialog
|
||||
: public LtsWidgets::LtsDialog
|
||||
, protected Interface::Ftc::ModifyFrequencyPlanningReplyHandler
|
||||
, protected Interface::Ftc::RemoveFrequencyPlanningReplyHandler
|
||||
, protected Interface::Ftc::ModifyActiveFrequencyPlanningReplyHandler
|
||||
, protected Interface::Ftc::RemoveActiveFrequencyPlanningReplyHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FrequencyPlanningDialog(LtsSession::LtsSession *session, const QString &menuGroup, QWidget *parent = nullptr);
|
||||
~FrequencyPlanningDialog();
|
||||
|
||||
bool init(const std::shared_ptr<Interface::Dtc> &avmDtc,
|
||||
const std::shared_ptr<Interface::Ftc> &avmFtc,
|
||||
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
||||
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
||||
ExerciseManagement::Interface::Dtc *exmDtc);
|
||||
|
||||
void onModifyFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onRemoveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onRemoveActiveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
void onModifyActiveFrequencyPlanningReply(const Core::FunctionReplyObject &replyObject) override final;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onAddClicked();
|
||||
void onEditClicked();
|
||||
void onRemoveClicked();
|
||||
void onSelectionChanged();
|
||||
void onActivateDeactivatePlanningClicked();
|
||||
void showEditDialog(const FrequencyPlanning &planning);
|
||||
void onActiveFrequencyPlanningChanged(const ActiveFrequencyPlanning &data, DataModification modType);
|
||||
void onFrequencyPlanningStatusChanged(const FrequencyPlanningStatus &data, DataModification modType);
|
||||
void onPrint();
|
||||
void onExportButtonClicked();
|
||||
void onImportButtonClicked();
|
||||
signals:
|
||||
void aboutToCloseMe(int);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
void unsetActiveFrequencyPlanning();
|
||||
void setActiveFrequencyPlanning(const ActiveFrequencyPlanning &activePlanning);
|
||||
void setButtonSetActivePlanningEnabled();
|
||||
static void setBackgroundColor(QWidget *w, Qt::GlobalColor color, bool bSetColor);
|
||||
void setStatus(const QString &statusText, const QString &requester, qint64 timeStampMsecs, TransmissionReason reason = TransmissionReason_def::TR_Unknown, Qt::GlobalColor color = Qt::black);
|
||||
void tableColumnOrganiserSetting() override;
|
||||
|
||||
private:
|
||||
Ui::FrequencyPlanningDialog *m_ui;
|
||||
QString m_menuGroup;
|
||||
bool m_copy;
|
||||
LtsSession::LtsSession *m_session;
|
||||
FrequencyPlanningDialogModel *m_model;
|
||||
FrequencyPlanningDialogProxyModel *m_proxyModel;
|
||||
LtsUtils::RequestHelper *m_requestHelper;
|
||||
ActiveFrequencyPlanning m_activePlanning;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
std::shared_ptr<Interface::Ftc> m_avmFtc;
|
||||
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
|
||||
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
ExerciseManagement::Interface::Dtc *m_exmDtc;
|
||||
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
|
||||
QMap<int, EditFrequencyPlanningDialog*> m_editDlgMap;
|
||||
int m_activeFrequencyPlanningStatus;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FrequencyPlanningDialog</class>
|
||||
<widget class="QWidget" name="FrequencyPlanningDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>692</width>
|
||||
<height>524</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="4">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>321</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbxStatus">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbxActiveFrequencyPlanning">
|
||||
<property name="text">
|
||||
<string>Active Frequency Planning:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="5">
|
||||
<widget class="LtsDataView::LtsDataView" name="dataView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="5">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="lblStatus">
|
||||
<property name="text">
|
||||
<string notr="true">[STATUS]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="lblStatusTime">
|
||||
<property name="text">
|
||||
<string notr="true">[TIME]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QLabel" name="lbActiveFrequencyPlanning">
|
||||
<property name="text">
|
||||
<string notr="true"><ACTIVE PLANNING></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsDataView::LtsDataView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>LtsDataView/lts_data_view.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_frequency_planning_dialog_model.h"
|
||||
#include <FileManagement/flm_translation.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
FrequencyPlanningDialogModel::FrequencyPlanningDialogModel(int32_t exerciseId, QObject *parent)
|
||||
: LtsAbstractTableModel<FrequencyPlanning>(
|
||||
{
|
||||
tr("Name"),
|
||||
tr("Date"),
|
||||
tr("Set"),
|
||||
tr("Active")
|
||||
}, parent)
|
||||
, m_exerciseId(exerciseId)
|
||||
, m_logger(getLogger("FrequencyPlanningDialogModel"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---FrequencyPlanningDialogModel() ";
|
||||
}
|
||||
|
||||
QVariant FrequencyPlanningDialogModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole && role != Qt::UserRole) || !indexIsValid(index))
|
||||
return QVariant();
|
||||
|
||||
const FrequencyPlanning &planning = m_vecData.at(index.row());
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case NAME:
|
||||
return QString::fromStdString(planning.name());
|
||||
case DATE:
|
||||
return QDateTime::fromMSecsSinceEpoch(planning.date());
|
||||
case SET:
|
||||
{
|
||||
const FrequencySet frequencySet = m_avmDtc->frequencySet(planning.frequencySetId());
|
||||
return QString::fromStdString(frequencySet.name());
|
||||
}
|
||||
case ACTIVE:
|
||||
return planning.id() == m_activePlanningId ? tr("Active") : QStringLiteral("-");
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
return QVariant::fromValue(planning);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool FrequencyPlanningDialogModel::init(const std::shared_ptr<Interface::Dtc> &avmDtc)
|
||||
{
|
||||
m_avmDtc = avmDtc;
|
||||
|
||||
m_frequencySets = m_avmDtc->frequencySets();
|
||||
|
||||
connect(m_avmDtc.get(), &AudioVideoManagement::Interface::Dtc::frequencyPlanningChanged,
|
||||
this, &FrequencyPlanningDialogModel::onFrequencyPlanningChanged);
|
||||
|
||||
m_avmDtc->frequencyPlannings([this](const FrequencyPlanning & p)
|
||||
{
|
||||
if (p.exerciseId().is_set() && p.exerciseId().get() == m_exerciseId)
|
||||
insertRow(p);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FrequencySet FrequencyPlanningDialogModel::frequencySetByIndex(const QModelIndex &index) const
|
||||
{
|
||||
if (!indexIsValid(index))
|
||||
return FrequencySet();
|
||||
|
||||
return m_frequencySets.value(m_vecData.at(index.row()).frequencySetId());
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialogModel::onFrequencyPlanningChanged(const FrequencyPlanning &data, DataModification modType)
|
||||
{
|
||||
INFO_LOG(m_logger) << "onFrequencyPlanningChanged "
|
||||
<< " data.exerciseId()" << data.exerciseId()
|
||||
<< " m_exerciseId=" << m_exerciseId;
|
||||
if ((data.exerciseId().is_set() && data.exerciseId().get() != m_exerciseId)
|
||||
|| (!data.exerciseId().is_set() && m_exerciseId != 0))
|
||||
return;
|
||||
|
||||
onDataChanged(data, modType);
|
||||
}
|
||||
|
||||
QByteArray FrequencyPlanningDialogModel::modelToJson()
|
||||
{
|
||||
QJsonObject obj;
|
||||
QJsonArray arr;
|
||||
QJsonArray arrData;
|
||||
|
||||
for (int row = 0; row < rowCount(); row++)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "row =" << ": " << row;
|
||||
QJsonObject inner;
|
||||
const FrequencyPlanning &planning = m_vecData.at(row);
|
||||
|
||||
inner[QStringLiteral("id")] = planning.id();
|
||||
inner[QStringLiteral("name")] = QString::fromStdString(planning.name());
|
||||
inner[QStringLiteral("dateOfCreation")] = planning.date();
|
||||
if(planning.exerciseId().is_set())
|
||||
{
|
||||
inner[QStringLiteral("exerciseId")] = planning.exerciseId().get();
|
||||
}
|
||||
inner[QStringLiteral("frequencySetId")] = planning.frequencySetId();
|
||||
|
||||
arrData = {};
|
||||
for (const FrequencyPlanningData &planningData : planning.data())
|
||||
{
|
||||
QJsonObject innerData;
|
||||
innerData[QStringLiteral("cnrConfigId")] = planningData.cnrConfigId();
|
||||
innerData[QStringLiteral("properties")] = QString::fromStdString(planningData.properties());
|
||||
arrData += innerData;
|
||||
}
|
||||
inner[QStringLiteral("data")] = arrData;
|
||||
arr += inner;
|
||||
}
|
||||
|
||||
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::AVMFrequencyPlanning);
|
||||
obj[QStringLiteral("FrequencyPlanning")] = arr;
|
||||
QJsonDocument doc(obj);
|
||||
return doc.toJson(QJsonDocument::Compact);
|
||||
|
||||
}
|
||||
|
||||
QVector<ModifyFrequencyPlanningRequest> FrequencyPlanningDialogModel::jsonToFrequencyPlanningVector(const QByteArray &content)
|
||||
{
|
||||
QVector<ModifyFrequencyPlanningRequest> result;
|
||||
const QJsonDocument doc(QJsonDocument::fromJson(content));
|
||||
const QJsonObject toplevelObj(doc.object());
|
||||
const QJsonArray arr(toplevelObj.value(QStringLiteral("FrequencyPlanning")).toArray());
|
||||
for (const auto &ele : arr)
|
||||
{
|
||||
const QJsonObject obj(ele.toObject());
|
||||
ModifyFrequencyPlanningRequest frequencyPlanning;
|
||||
frequencyPlanning.date(obj[QStringLiteral("dateOfCreation")].toDouble());
|
||||
frequencyPlanning.exerciseId(m_exerciseId);
|
||||
frequencyPlanning.frequencySetId(obj[QStringLiteral("frequencySetId")].toInt());
|
||||
frequencyPlanning.id(0);
|
||||
frequencyPlanning.name(obj[QStringLiteral("name")].toString().toStdString());
|
||||
|
||||
|
||||
const QJsonArray arrData = (obj.value(QStringLiteral("data")).toArray());
|
||||
frequencyPlanning.data().reserve(arrData.size());
|
||||
for (const auto &eleData : arrData)
|
||||
{
|
||||
const QJsonObject objData(eleData.toObject());
|
||||
FrequencyPlanningData frequencyPlanningData;
|
||||
frequencyPlanningData.cnrConfigId(objData[QStringLiteral("cnrConfigId")].toInt());
|
||||
frequencyPlanningData.properties(objData[QStringLiteral("properties")].toString().toStdString());
|
||||
frequencyPlanning.data().push_back(frequencyPlanningData);
|
||||
}
|
||||
|
||||
|
||||
result.push_back(std::move(frequencyPlanning));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void FrequencyPlanningDialogProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
|
||||
{
|
||||
m_sourceModel = qobject_cast<FrequencyPlanningDialogModel*>(sourceModel);
|
||||
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool FrequencyPlanningDialogProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if (!m_sourceModel ||
|
||||
source_left.column() != source_right.column() ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid())
|
||||
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
|
||||
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
|
||||
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
|
||||
switch (source_left.column())
|
||||
{
|
||||
case FrequencyPlanningDialogModel::DATE:
|
||||
return dataLeft.date() < dataRight.date();
|
||||
case FrequencyPlanningDialogModel::NAME:
|
||||
case FrequencyPlanningDialogModel::SET:
|
||||
case FrequencyPlanningDialogModel::ACTIVE:
|
||||
case FrequencyPlanningDialogModel::COUNT:
|
||||
break;
|
||||
}
|
||||
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_abstract_table_model.h>
|
||||
#include <LtsWidgets/lts_column_filter_proxy_model.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
class FrequencyPlanningDialogModel final
|
||||
: public LtsWidgets::LtsAbstractTableModel<FrequencyPlanning>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Columns
|
||||
{
|
||||
NAME,
|
||||
DATE,
|
||||
SET,
|
||||
ACTIVE,
|
||||
COUNT
|
||||
};
|
||||
|
||||
explicit FrequencyPlanningDialogModel(int32_t exerciseId, QObject *parent = nullptr);
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override final;
|
||||
|
||||
bool init(const std::shared_ptr<Interface::Dtc> &avmDtc);
|
||||
|
||||
void setActivePlanning(int activePlanningId) { m_activePlanningId = activePlanningId; }
|
||||
void unsetActivePlanning() { m_activePlanningId.reset(); }
|
||||
|
||||
FrequencySet frequencySetByIndex(const QModelIndex &index) const;
|
||||
QByteArray modelToJson();
|
||||
QVector<ModifyFrequencyPlanningRequest> jsonToFrequencyPlanningVector(const QByteArray &content);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onFrequencyPlanningChanged(const FrequencyPlanning &data, DataModification modType);
|
||||
|
||||
private:
|
||||
int32_t m_exerciseId;
|
||||
boost::optional<int> m_activePlanningId;
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
|
||||
QMap<int32_t, FrequencySet> m_frequencySets;
|
||||
|
||||
friend class FrequencyPlanningDialogProxyModel;
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
class FrequencyPlanningDialogProxyModel final : public LtsWidgets::LtsColumnFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
|
||||
private:
|
||||
FrequencyPlanningDialogModel *m_sourceModel = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
Q_DECLARE_METATYPE(AudioVideoManagement::FrequencyPlanning)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_frequency_planning_helper.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
QString getOperatingModeText(int operatingMode)
|
||||
{
|
||||
switch (operatingMode)
|
||||
{
|
||||
case 0:
|
||||
return QObject::tr("Fixed frequency, no encryption");
|
||||
case 1:
|
||||
return QObject::tr("Fixed frequency, encryption: HW_KR");
|
||||
case 2:
|
||||
return QObject::tr("Fixed frequency, encryption: HW_KR_KL");
|
||||
case 3:
|
||||
return QObject::tr("AKW, no encryption");
|
||||
case 4:
|
||||
return QObject::tr("AKW, encryption: ECCM");
|
||||
default:
|
||||
return QObject::tr("Unknown Operating Mode");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
#include "../CombatNetRadioConfiguration/avm_combat_net_radio_dialog_model.h"
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
QString getOperatingModeText(int operatingMode);
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
template<typename Key, typename T, class Iterator>
|
||||
class QKeyValueIterator
|
||||
{
|
||||
public:
|
||||
typedef typename Iterator::iterator_category iterator_category;
|
||||
typedef typename Iterator::difference_type difference_type;
|
||||
typedef std::pair<Key, T> value_type;
|
||||
typedef const value_type *pointer;
|
||||
typedef const value_type &reference;
|
||||
|
||||
QKeyValueIterator() = default;
|
||||
Q_DECL_CONSTEXPR explicit QKeyValueIterator(Iterator o) Q_DECL_NOEXCEPT_EXPR(std::is_nothrow_move_constructible<Iterator>::value)
|
||||
: i(std::move(o)) {}
|
||||
|
||||
std::pair<Key, T> operator*() const {
|
||||
return std::pair<Key, T>(i.key(), i.value());
|
||||
}
|
||||
|
||||
friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i == rhs.i; }
|
||||
friend bool operator!=(QKeyValueIterator lhs, QKeyValueIterator rhs) Q_DECL_NOEXCEPT { return lhs.i != rhs.i; }
|
||||
|
||||
inline QKeyValueIterator &operator++() { ++i; return *this; }
|
||||
inline QKeyValueIterator operator++(int) { return QKeyValueIterator(i++); }
|
||||
inline QKeyValueIterator &operator--() { --i; return *this; }
|
||||
inline QKeyValueIterator operator--(int) { return QKeyValueIterator(i--); }
|
||||
Iterator base() const { return i; }
|
||||
|
||||
private:
|
||||
Iterator i;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template<class Key, class T>
|
||||
class OverKeyValue
|
||||
{
|
||||
public:
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
using const_iterator_tmp = typename QMap<Key, T>::const_iterator;
|
||||
using const_key_value_iterator = QKeyValueIterator<const Key&, const T&, const_iterator_tmp>;
|
||||
using const_iterator = typename OverKeyValue<Key, T>::const_key_value_iterator;
|
||||
#else
|
||||
using const_iterator = typename QMap<Key, T>::const_key_value_iterator;
|
||||
#endif
|
||||
|
||||
explicit OverKeyValue(const QMap<Key, T> &map)
|
||||
: m_map(map)
|
||||
{}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
const_iterator begin() const { return const_key_value_iterator(m_map.begin()); }
|
||||
const_iterator end() const { return const_key_value_iterator(m_map.end()); }
|
||||
#else
|
||||
const_iterator begin() const { return m_map.keyValueBegin(); }
|
||||
const_iterator end() const { return m_map.keyValueEnd(); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
const QMap<Key, T> &m_map;
|
||||
};
|
||||
|
||||
template<class Key, class T>
|
||||
OverKeyValue<Key, T> overKeyValue(const QMap<Key, T> &map)
|
||||
{
|
||||
return OverKeyValue<Key, T>(map);
|
||||
}
|
||||
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_frequency_planning_widget.h"
|
||||
#include <LtsWidgets/lts_spinbox.h>
|
||||
#include "ui_avm_frequency_planning_widget.h"
|
||||
#include "avm_edit_frequency_planning_set_resource_dialog.h"
|
||||
#include "avm_radio_specifica_hf_widget.h"
|
||||
#include "avm_radio_specifica_vhf_widget.h"
|
||||
#include "avm_radio_specifica_uhf_widget.h"
|
||||
|
||||
#include <AudioVideoManagement/avm_translation.h>
|
||||
#include <InfrastructureManagement/Gui/IsmComboBox/ism_combobox_gui_plugin.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
FrequencyPlanningWidget::FrequencyPlanningWidget(const std::shared_ptr<Interface::Dtc> &avmDtc, QSet<int> &allocatedDataSets, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::FrequencyPlanningWidget)
|
||||
, m_assignedFrequencySetDataIds(allocatedDataSets)
|
||||
, m_avmDtc(avmDtc)
|
||||
, m_logger(getLogger("EditFrequencyPlanningResourceDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_ui->cbFrequencyBand->addItem(toString(FrequencyBand_def::VHF), FrequencyBand_def::VHF);
|
||||
m_ui->cbFrequencyBand->addItem(toString(FrequencyBand_def::HF), FrequencyBand_def::HF);
|
||||
m_ui->cbFrequencyBand->addItem(toString(FrequencyBand_def::UHF), FrequencyBand_def::UHF);
|
||||
|
||||
connect(m_ui->leName, &QLineEdit::textChanged,
|
||||
this, &FrequencyPlanningWidget::onNameChanged);
|
||||
connect(m_ui->cbFrequencyBand, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this, &FrequencyPlanningWidget::onFrequencyBandChanged);
|
||||
connect(m_avmDtc.get(), &AudioVideoManagement::Interface::Dtc::cnrConfigChanged,
|
||||
this, &FrequencyPlanningWidget::onCnrConfigChanged);
|
||||
}
|
||||
|
||||
bool FrequencyPlanningWidget::init(LtsSession::LtsSession *session, RadioCircuit *data, const CnrConfig &cnrConfigId, int frequencySetId, FrequencyBand ft)
|
||||
{
|
||||
m_frequencySetId = frequencySetId;
|
||||
m_cnrConfigId = cnrConfigId.id();
|
||||
m_hasParty = cnrConfigId.partyId() != 0;
|
||||
|
||||
if (!session->getForeignGuiInterface<InfrastructureManagement::ForeignGuiComboboxInterface>(m_ismCbxIfc))
|
||||
return false;
|
||||
|
||||
m_ui->cbFrequencyBand->setCurrentIndex(m_ui->cbFrequencyBand->findData(ft.underlying()));
|
||||
m_ui->cbFrequencyBand->setVisible(false);
|
||||
m_ui->lbxFrequencyBand->setVisible(false);
|
||||
|
||||
switch (ft.underlying())
|
||||
{
|
||||
|
||||
case FrequencyBand_def::HF:
|
||||
{
|
||||
createHFWidget(data);
|
||||
break;
|
||||
}
|
||||
case FrequencyBand_def::UHF:
|
||||
{
|
||||
createUHFWidget(data);
|
||||
break;
|
||||
}
|
||||
case FrequencyBand_def::VHF:
|
||||
{
|
||||
createVHFWidget(data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ft = data ? data->freqBand : FrequencyBand::VHF;
|
||||
m_isRelay = true;
|
||||
|
||||
m_ui->cbFrequencyBand->setCurrentIndex(m_ui->cbFrequencyBand->findData(ft.underlying()));
|
||||
m_ui->cbFrequencyBand->setVisible(true);
|
||||
m_ui->lbxFrequencyBand->setVisible(true);
|
||||
switch (ft.underlying())
|
||||
{
|
||||
case FrequencyBand_def::HF:
|
||||
createHFWidget(data);
|
||||
break;
|
||||
case FrequencyBand_def::UHF:
|
||||
createUHFWidget(data);
|
||||
break;
|
||||
case FrequencyBand_def::VHF:
|
||||
createVHFWidget(data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_ismCbxIfc->fillRadioStationsComboBox(m_ui->cbRadioStation, ft.underlying());
|
||||
if (m_hasParty && !m_isRelay)
|
||||
m_ui->cbRadioStation->addItem(tr("Automatic"), 0);
|
||||
if (!data)
|
||||
m_ui->leName->clear();
|
||||
else
|
||||
{
|
||||
m_ui->leName->setText(data->name);
|
||||
m_ui->cbRadioStation->setCurrentIndex(m_ui->cbRadioStation->findData(data->radioStationId));
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::setNameDisabled(bool disable)
|
||||
{
|
||||
m_ui->leName->setDisabled(disable);
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::setName(const QString &name)
|
||||
{
|
||||
m_ui->leName->setText(name);
|
||||
}
|
||||
|
||||
|
||||
void FrequencyPlanningWidget::setRelaisRestrictions(bool restrict)
|
||||
{
|
||||
if (restrict)
|
||||
{
|
||||
m_ui->cbFrequencyBand->setCurrentIndex(m_ui->cbFrequencyBand->findData(FrequencyBand_def::VHF));
|
||||
m_ui->cbFrequencyBand->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->cbFrequencyBand->setEnabled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QJsonObject FrequencyPlanningWidget::toJson() const
|
||||
{
|
||||
return frequencyPlanningJson(m_radioSpecificaWidget->toJson(),
|
||||
m_ui->leName->text(),
|
||||
static_cast<FrequencyBand::inner_enum>(m_ui->cbFrequencyBand->currentData().toInt()),
|
||||
m_ui->cbRadioStation->currentData().toInt());
|
||||
}
|
||||
|
||||
QVector<QPair<QLabel *, const std::function<bool ()> > > FrequencyPlanningWidget::requirements() const
|
||||
{
|
||||
return m_radioSpecificaWidget->requirements();
|
||||
}
|
||||
|
||||
FrequencyPlanningWidget::~FrequencyPlanningWidget()
|
||||
{
|
||||
if(m_radioSpecificaWidget)
|
||||
{
|
||||
delete m_radioSpecificaWidget;
|
||||
m_radioSpecificaWidget = nullptr;
|
||||
}
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::onFrequencyBandChanged()
|
||||
{
|
||||
switch (m_ui->cbFrequencyBand->currentData().toInt())
|
||||
{
|
||||
case FrequencyBand_def::HF:
|
||||
createHFWidget();
|
||||
break;
|
||||
case FrequencyBand_def::UHF:
|
||||
createUHFWidget();
|
||||
break;
|
||||
case FrequencyBand_def::VHF:
|
||||
createVHFWidget();
|
||||
break;
|
||||
}
|
||||
|
||||
m_ui->cbRadioStation->clear();
|
||||
m_ismCbxIfc->fillRadioStationsComboBox(m_ui->cbRadioStation, m_ui->cbFrequencyBand->currentData().toInt());
|
||||
if(m_hasParty && !m_isRelay)
|
||||
m_ui->cbRadioStation->addItem(tr("Automatic"), 0);
|
||||
|
||||
if(m_radioSpecificaWidget)
|
||||
m_ui->gridLayout->addWidget(m_radioSpecificaWidget,5,0,1,2);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::createHFWidget(RadioCircuit* circuit)
|
||||
{
|
||||
if(m_radioSpecificaWidget)
|
||||
{
|
||||
delete m_radioSpecificaWidget;
|
||||
m_radioSpecificaWidget = nullptr;
|
||||
}
|
||||
m_radioSpecificaWidget = new RadioSpecificaHfWidget(m_ui->radioSpecificaWidget);
|
||||
if(!circuit)
|
||||
return;
|
||||
RadioCircuitHF *dataHf = dynamic_cast<RadioCircuitHF*>(circuit);
|
||||
m_radioSpecificaWidget->setValues(dataHf);
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::createUHFWidget(RadioCircuit* circuit)
|
||||
{
|
||||
if(m_radioSpecificaWidget)
|
||||
{
|
||||
delete m_radioSpecificaWidget;
|
||||
m_radioSpecificaWidget = nullptr;
|
||||
}
|
||||
m_radioSpecificaWidget = new RadioSpecificaUhfWidget(m_ui->radioSpecificaWidget);
|
||||
if(!circuit)
|
||||
return;
|
||||
RadioCircuitUHF* dataUhf = dynamic_cast<RadioCircuitUHF*>(circuit);
|
||||
m_radioSpecificaWidget->setValues(dataUhf);
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::createVHFWidget(RadioCircuit* circuit)
|
||||
{
|
||||
if(m_radioSpecificaWidget)
|
||||
{
|
||||
delete m_radioSpecificaWidget;
|
||||
m_radioSpecificaWidget = nullptr;
|
||||
}
|
||||
auto *widget = new RadioSpecificaVhfWidget(m_assignedFrequencySetDataIds, m_ui->radioSpecificaWidget);
|
||||
widget->init(m_frequencySetId, m_avmDtc, m_cnrConfigId);
|
||||
m_radioSpecificaWidget = widget;
|
||||
|
||||
if(!circuit)
|
||||
return;
|
||||
RadioCircuitVHF* dataVhf = dynamic_cast<RadioCircuitVHF*>(circuit);
|
||||
m_radioSpecificaWidget->setValues(dataVhf);
|
||||
}
|
||||
|
||||
void FrequencyPlanningWidget::onCnrConfigChanged(const AudioVideoManagement::CnrConfig &config, DataModification modType)
|
||||
{
|
||||
Q_UNUSED(modType);
|
||||
if (m_cnrConfigId == config.id())
|
||||
{
|
||||
m_ui->leName->setText(QString::fromStdString(config.radioCircuit()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <AudioVideoManagement/avm.hpp>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
#include <Proxies/CombatNetRadio/Helper/cnr_frequency_planning_helper.h>
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
|
||||
class QLabel;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class FrequencyPlanningWidget;
|
||||
}
|
||||
|
||||
namespace InfrastructureManagement
|
||||
{
|
||||
class ForeignGuiComboboxInterface;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace LtsWidgets
|
||||
{
|
||||
class LtsSpinBox;
|
||||
class LtsComboBox;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class RadioSpecificaWidget;
|
||||
|
||||
|
||||
class FrequencyPlanningWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
FrequencyPlanningWidget(const std::shared_ptr<Interface::Dtc> &avmDtc, QSet<int> &allocatedDataSets, QWidget *parent = nullptr);
|
||||
~FrequencyPlanningWidget();
|
||||
|
||||
bool init(LtsSession::LtsSession *session, RadioCircuit *data, const CnrConfig &cnrConfigId, int frequencySetId = -1, FrequencyBand ft = FrequencyBand_def::VHF);
|
||||
void setNameDisabled(bool disable);
|
||||
void setName(const QString& name);
|
||||
void setRelaisRestrictions(bool restrict);
|
||||
QJsonObject toJson() const;
|
||||
|
||||
QVector< QPair<QLabel*, const std::function<bool()> > > requirements() const;
|
||||
|
||||
signals:
|
||||
void onNameChanged(const QString&);
|
||||
|
||||
private slots:
|
||||
void onFrequencyBandChanged();
|
||||
void onCnrConfigChanged(const AudioVideoManagement::CnrConfig &config, DataModification modType);
|
||||
|
||||
private:
|
||||
Ui::FrequencyPlanningWidget *m_ui {nullptr};
|
||||
RadioSpecificaWidget *m_radioSpecificaWidget {nullptr};
|
||||
int m_frequencySetId {0};
|
||||
int m_cnrConfigId {0};
|
||||
QSet<int> &m_assignedFrequencySetDataIds;
|
||||
std::shared_ptr<InfrastructureManagement::ForeignGuiComboboxInterface> m_ismCbxIfc;
|
||||
bool m_hasParty;
|
||||
bool m_isRelay {false};
|
||||
|
||||
std::shared_ptr<Interface::Dtc> m_avmDtc;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
|
||||
void createHFWidget(RadioCircuit* circuit = nullptr);
|
||||
void createUHFWidget(RadioCircuit* circuit = nullptr);
|
||||
void createVHFWidget(RadioCircuit* circuit = nullptr);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FrequencyPlanningWidget</class>
|
||||
<widget class="QWidget" name="FrequencyPlanningWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>561</width>
|
||||
<height>526</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lbxName">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leName"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lbxFrequencyBand">
|
||||
<property name="text">
|
||||
<string>Frequenzband:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cbFrequencyBand"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lbxRadioStation">
|
||||
<property name="text">
|
||||
<string>Funkstation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbRadioStation"/>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QWidget" name="radioSpecificaWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_init_frequency_planning_dialog.h"
|
||||
#include "ui_avm_init_frequency_planning_dialog.h"
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
InitFrequencyPlanningDialog::InitFrequencyPlanningDialog(LtsSession::LtsSession *session, const std::shared_ptr<Interface::Dtc> &avmDtc, QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkCancel)
|
||||
, m_ui(new Ui::InitFrequencyPlanningDialog)
|
||||
, m_dateOfCreation(session->partitionTime())
|
||||
, m_session(session)
|
||||
, m_logger(getLogger("InitFrequencyPlanningDialog"))
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---InitFrequencyPlanningDialog() ";
|
||||
m_ui->setupUi(this);
|
||||
|
||||
QMap<int32_t, FrequencySet> frequencySets = avmDtc->frequencySets();
|
||||
|
||||
for (auto it = frequencySets.constBegin(); it != frequencySets.constEnd(); ++it)
|
||||
m_ui->cbFrequencySets->addItem(QString::fromStdString(it.value().name()), QVariant::fromValue(it.key()));
|
||||
|
||||
m_ui->tbTime->setText(DTG::toStringMSec(m_dateOfCreation));
|
||||
|
||||
connect(m_ui->tbTime, &QToolButton::clicked, this, [this]()
|
||||
{
|
||||
m_dateOfCreation = m_session->partitionTime();
|
||||
m_ui->tbTime->setText(DTG::toStringMSec(m_dateOfCreation));
|
||||
});
|
||||
|
||||
m_uiRequirements->addRequirement( { m_ui->lblName, [this]() { return !m_ui->leName->text().isEmpty(); } });
|
||||
m_uiRequirements->addRequirement( { m_ui->lblFrequencySets, [this]() { return !m_ui->cbFrequencySets->currentText().isEmpty(); } });
|
||||
|
||||
setOnlineHelpFilename(QStringLiteral("Situation-Frequency_Planning"));
|
||||
}
|
||||
|
||||
|
||||
InitFrequencyPlanningDialog::~InitFrequencyPlanningDialog()
|
||||
{
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
|
||||
void InitFrequencyPlanningDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, tr("New Frequency Planning"));
|
||||
}
|
||||
|
||||
|
||||
bool InitFrequencyPlanningDialog::apply()
|
||||
{
|
||||
FrequencyPlanning planning;
|
||||
|
||||
planning.id(0);
|
||||
if(m_session->exerciseId() != 0)
|
||||
planning.exerciseId(m_session->exerciseId());
|
||||
planning.frequencySetId(m_ui->cbFrequencySets->currentData().toInt());
|
||||
planning.name(m_ui->leName->text().toStdString());
|
||||
planning.date(m_dateOfCreation);
|
||||
|
||||
emit newInitFrequencyPlanning(planning);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LtsWidgets/lts_dialog.h>
|
||||
|
||||
#include <AudioVideoManagement/logger.h>
|
||||
#include <AudioVideoManagement/avm_dtc.h>
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class InitFrequencyPlanningDialog;
|
||||
}
|
||||
|
||||
namespace LtsSession
|
||||
{
|
||||
class LtsSession;
|
||||
}
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
class InitFrequencyPlanningDialog : public LtsWidgets::LtsDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InitFrequencyPlanningDialog(LtsSession::LtsSession *session, const std::shared_ptr<Interface::Dtc> &avmDtc, QWidget *parent);
|
||||
|
||||
~InitFrequencyPlanningDialog();
|
||||
|
||||
signals:
|
||||
void newInitFrequencyPlanning(const FrequencyPlanning &);
|
||||
|
||||
private:
|
||||
void retranslate() override;
|
||||
bool apply() override;
|
||||
|
||||
Ui::InitFrequencyPlanningDialog *m_ui;
|
||||
qint64 m_dateOfCreation;
|
||||
LtsSession::LtsSession *m_session;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
};
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>InitFrequencyPlanningDialog</class>
|
||||
<widget class="QWidget" name="InitFrequencyPlanningDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>427</width>
|
||||
<height>228</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Asset Stocks</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblName">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="leName">
|
||||
<property name="toolTip">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Date of Creation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QToolButton" name="tbTime">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true"><TIME></string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::NoArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="lblFrequencySets">
|
||||
<property name="text">
|
||||
<string>Frequency Set:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="LtsWidgets::LtsComboBox" name="cbFrequencySets"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LtsWidgets::LtsComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>LtsWidgets/lts_combo_box.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
|
||||
#include "avm_load_frequency_planning_dialog.h"
|
||||
#include "ui_avm_load_frequency_planning_dialog.h"
|
||||
|
||||
#include "avm_load_frequency_planning_dialog_model.h"
|
||||
#include <QTreeView>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
LoadFrequencyPlanningDialog::LoadFrequencyPlanningDialog(const QByteArray &data, const FrequencyPlanning &initPlan, const std::shared_ptr<Interface::Dtc> &avmDtc, const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc, QWidget *parent)
|
||||
: LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal)
|
||||
, m_ui(new Ui::LoadFrequencyPlanningDialog)
|
||||
, m_model(new LoadFrequencyPlanningDialogModel(initPlan, avmDtc, ismDtc, this))
|
||||
, m_logger(getLogger("LoadFrequencyPlanningDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
DrawDelegate *treeDelegate = new DrawDelegate(m_model);
|
||||
m_ui->dataView->treeView()->setItemDelegateForColumn(LoadFrequencyPlanningDialogModel::Columns::PROPERTIES, treeDelegate);
|
||||
m_model->setData(data);
|
||||
|
||||
m_ui->dataView->setModel(m_model);
|
||||
|
||||
connect(m_ui->pbOk, &QPushButton::clicked,
|
||||
this, &LoadFrequencyPlanningDialog::onOk);
|
||||
connect(m_ui->pbCancel, &QPushButton::clicked,
|
||||
this, &LoadFrequencyPlanningDialog::close);
|
||||
connect(m_ui->cbAll, &QCheckBox::clicked,
|
||||
m_model, &LoadFrequencyPlanningDialogModel::checkAll);
|
||||
|
||||
m_ui->dataView->expandAll();
|
||||
}
|
||||
|
||||
QVector<int32_t> LoadFrequencyPlanningDialog::unassignments() const
|
||||
{
|
||||
return m_model->unassignments();
|
||||
}
|
||||
|
||||
QVector<FrequencyPlanningData> LoadFrequencyPlanningDialog::newPlanningData() const
|
||||
{
|
||||
return m_model->planningData();
|
||||
}
|
||||
|
||||
|
||||
bool LoadFrequencyPlanningDialog::isApplied() const
|
||||
{
|
||||
return m_isApplied;
|
||||
}
|
||||
|
||||
void LoadFrequencyPlanningDialog::onOk()
|
||||
{
|
||||
m_isApplied = true;
|
||||
close();
|
||||
}
|
||||
|
||||
LoadFrequencyPlanningDialog::~LoadFrequencyPlanningDialog() = default;
|
||||
|
||||
}
|
||||
Loaded 100 of 11247 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user