Files
qt5-legatus-legacy/Lts/Services/AudioVideoManagement/avs_menus.cpp
T
2026-08-13 18:33:10 +02:00

390 lines
10 KiB
C++
Executable File

/**
* @RDE_HEADER@
* AvsMenus
* $Id$
* $HeadURL$
* $Author$
* Created by Christian Fröbel, NLSE, 2018-03-19
*/
#include "avs_menus.h"
#include <AudioVideoManagement/ava_session.h>
#include <AudioVideoManagement/ava_control.h>
#include <AudioVideoManagement/avm.hpp>
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/avs_dialog.h>
#include <LtsUtilsCore/data_modification_enum.h>
#include <QtGlobal>
#include <QString>
#include <algorithm>
#include <utility>
#include <InfrastructureManagement/ism.hpp>
namespace
{
QString toMenuDef(const AudioVideoManagement::AvMenuEntry &menuEntry,
const std::vector<AudioVideoManagement::AvMenuEntry> &meCont,
bool isAudio)
{
QString prefix1;
QString prefix2;
if (isAudio)
{
constexpr int trennIndex = 15;
prefix1 = QString::number(trennIndex) + QLatin1Char(' ');
prefix2 = prefix1;
}
else
{
constexpr int audioMute = 1; // muted
prefix1 = QString::number(audioMute) + QLatin1Char(' ');
// no prefix2
}
if (!menuEntry.isGroup())
return QStringLiteral("%1{%2}").arg(prefix1, QString::fromStdString(menuEntry.name().get()));
QString def = QStringLiteral("%1{%2:").arg(prefix1, QString::fromStdString(menuEntry.name().get()));
for (const auto &entry : meCont)
{
bool isChildEntry = entry.parentId() == menuEntry.id();
if (!isChildEntry)
continue;
Q_ASSERT(!entry.isGroup());
def += QStringLiteral(" %1{%2}").arg(prefix2, QString::fromStdString(entry.name().get()));
}
def += QLatin1Char('}');
return def;
}
QString toMenuDef(const AudioVideoManagement::MenuStruct &menuStruct)
{
// Hint: MenuStruct-entries are sorted already (done by the Service (HandlerMenuStruct)).
QStringList entries;
entries.reserve(menuStruct.menuEntries().size()); // probably more than needed, but avoid clazy warning
for (const auto &entry : menuStruct.menuEntries())
{
bool isToplevelEntry = entry.parentId() == menuStruct.id();
if (isToplevelEntry)
entries.append(toMenuDef(entry, menuStruct.menuEntries(), menuStruct.isAudio()));
}
return entries.join(QLatin1Char(' '));
}
/**
* Adjusts the list of seleced channels in a way that the stream with the given mountingPointId
* is the first selected stream.
*/
void selectAtFirstPos(const AudioVideoManagement::MenuStruct &menu, QStringList &selection, int mountingPointId)
{
using AudioVideoManagement::AvMenuEntry;
auto withMountingPointId = [mountingPointId] (const AvMenuEntry &entry) { return entry.mountingPointId() && entry.mountingPointId().get() == mountingPointId; };
auto found = std::find_if(menu.menuEntries().begin(), menu.menuEntries().end(), withMountingPointId);
if (found == menu.menuEntries().end())
return;
QString streamName = QString::fromStdString(found->name().get());
auto currentPosInSelection = std::find(selection.begin(), selection.end(), streamName);
if (currentPosInSelection == selection.begin())
return; // already at first position
if (currentPosInSelection == selection.end())
{
selection.removeLast();
selection.prepend(streamName);
return;
}
std::swap(selection[0], *currentPosInSelection);
}
QString toSelectionString(const QStringList &selectedStreams)
{
return QStringLiteral("{%1}").arg(selectedStreams.join(QLatin1String("} {")));
}
} // anonymous namespace
using namespace std::placeholders;
namespace AudioVideoManagement
{
AvsMenus::AvsMenus(AvaSession *session, Interface::Dtc *dtc, InfrastructureManagement::Interface::Dtc *ismDtc, RtState *rtState)
: m_session(session)
, m_dtc(dtc)
, m_ismDtc(ismDtc)
, m_rtState(rtState)
, m_announcementMenu(dtc, ismDtc, std::bind(std::mem_fn(&AvsMenus::sendAnnouncementMenu), this, _1, _2), true)
, m_videoMenu(dtc, ismDtc, std::bind(std::mem_fn(&AvsMenus::sendVideoMenu), this, _1, _2), false)
{
Q_ASSERT(session);
Q_ASSERT(dtc);
Q_ASSERT(ismDtc);
Q_ASSERT(rtState);
connect(m_session, &AvaSession::sessionEstablished, this, &AvsMenus::onSessionEstablished);
connect(m_dtc, &Interface::Dtc::menuStructChanged, this, &AvsMenus::onMenuStructChanged);
m_dtc->menuStructs([this] (const MenuStruct &menu) { onMenuStructChanged(menu, DataModification::eAdded); });
if (m_session->isEstablished())
onSessionEstablished();
}
void AvsMenus::setAnnouncementMenu(int menuId)
{
if (menuId == m_announcementMenu.currentMenu())
return;
m_announcementMenu.setMenu(menuId);
}
void AvsMenus::setVideoMenu(int menuId)
{
if (menuId == m_videoMenu.currentMenu())
return;
m_videoMenu.setMenu(menuId);
}
void AvsMenus::setAnnouncementUnit(int mountingPointId)
{
m_announcementMenu.setAnnouncementUnit(mountingPointId);
}
/**
* Initially set the default menus.
* Otherwise restore the previously active menus.
*/
void AvsMenus::onSessionEstablished()
{
m_announcementMenu.onSessionEstablished();
m_videoMenu.onSessionEstablished();
}
void AvsMenus::onMenuStructChanged(const MenuStruct &menu, DataModification modType)
{
if (menu.isAudio())
m_announcementMenu.onChanged(menu, modType);
else
m_videoMenu.onChanged(menu, modType);
}
/**
* If mountingPointIdOfSelectedStream is given, the corresponding stream shall be pre-selected
* in the first Announcement-ComboBox in AVS_Workstation.
*/
void AvsMenus::sendAnnouncementMenu(const MenuStruct &menu, const boost::optional<int> &mountingPointIdOfSelectedStream)
{
QStringList selection;
QStringList stateList;
selection.reserve(6);
stateList.reserve(6);
int i = 0;
for (const auto &audioEntry : menu.menuEntries())
{
bool isToplevel = audioEntry.parentId() == menu.id();
if (!isToplevel)
break; // only select toplevel entries. Hint: menuEntries are ordered so that all toplevel entries are at the front.
selection.append(QString::fromStdString(audioEntry.name().get()));
int zustand = 1; // wird derzeit nicht gespeichert, also per default auf 1
stateList += QString::number(zustand);
++i;
if (i == 6)
break;
}
for (; i < 6 ; ++i)
{
selection.append(QString());
stateList.append(QString::number(1));
}
if (mountingPointIdOfSelectedStream)
{
selectAtFirstPos(menu, selection, *mountingPointIdOfSelectedStream);
stateList.removeLast();
stateList.prepend(QString::number(2));
}
m_session->control()->setAnnouncementProfile(m_rtState, toMenuDef(menu), toSelectionString(selection), stateList.join(QLatin1Char(' ')));
}
/**
* The dummy parameter is only there to make the signature the same as for sendAnnouncementMenu().
*/
void AvsMenus::sendVideoMenu(const MenuStruct &menu, const boost::optional<int> &dummy)
{
Q_ASSERT(!dummy);
QString menuDef = toMenuDef(menu);
m_session->control()->setVideoProfile(AvsDialog::VIDEO_1, menuDef);
m_session->control()->setVideoProfile(AvsDialog::VIDEO_2, menuDef);
m_session->control()->setVideoProfile(AvsDialog::VIDEO_3, menuDef);
m_session->control()->setVideoProfile(AvsDialog::VIDEO_4, menuDef);
}
//==============================================================================
AvsMenus::Menu::Menu(Interface::Dtc *dtc, InfrastructureManagement::Interface::Dtc *ismDtc, SendMenuCallback cb, bool isAudio)
: m_dtc(dtc)
, m_ismDtc(ismDtc)
, m_sendMenu(std::move(cb))
, m_isAudio(isAudio)
{
Q_ASSERT(dtc);
Q_ASSERT(ismDtc);
}
void AvsMenus::Menu::setMenu(int menuId)
{
Q_ASSERT(menuId > 0);
MenuStruct menu = m_dtc->menuStruct(menuId);
if (menu.id() != menuId)
return;
Q_ASSERT(menu.isAudio() == m_isAudio);
//replace mvs streams
replaceMvsEntries(menu);
setMenu(menu);
}
void AvsMenus::Menu::replaceMvsEntries(MenuStruct &menu) const
{
std::vector<AvMenuEntry> newMenu;
newMenu.reserve(menu.menuEntries().size());
for (auto menuEntry : menu.menuEntries())
{
if (menuEntry.mountingPointId().is_set() && menuEntry.mountingPointId().get() < 0)
menuEntry.name() = m_dtc->videoTeam(menuEntry.mountingPointId().get()*-1).streamName();
newMenu.push_back(std::move(menuEntry));
}
std::swap(menu.menuEntries(), newMenu);
}
void AvsMenus::Menu::setAnnouncementUnit(int mountingPointId)
{
Q_ASSERT(m_isAudio);
if (!m_defaultMenu)
return;
const MenuStruct menu = m_dtc->menuStruct(*m_defaultMenu);
if (menu.id() != *m_defaultMenu)
return;
Q_ASSERT(menu.isAudio() == m_isAudio);
setMenu(menu, mountingPointId);
}
void AvsMenus::Menu::onChanged(const MenuStruct &menu, DataModification modType)
{
switch (modType)
{
case DataModification::eAdded:
onMenuAdded(menu);
break;
case DataModification::eModified:
onMenuChanged(menu);
break;
case DataModification::eRemoved:
onMenuRemoved(menu);
break;
}
}
void AvsMenus::Menu::onSessionEstablished()
{
if (!m_currentMenu)
{
if (m_defaultMenu)
setMenu(*m_defaultMenu);
}
else
setMenu(*m_currentMenu);
}
void AvsMenus::Menu::onMenuAdded(MenuStruct menu)
{
if (!menu.isDefault())
return;
m_defaultMenu = menu.id();
if (!m_currentMenu)
{
replaceMvsEntries(menu);
setMenu(menu);
}
}
void AvsMenus::Menu::onMenuChanged(MenuStruct menu)
{
if (m_currentMenu == menu.id())
{
replaceMvsEntries(menu);
setMenu(menu);
}
}
void AvsMenus::Menu::onMenuRemoved(const MenuStruct &menu)
{
if (m_currentMenu != menu.id())
return;
m_currentMenu.reset();
setMenu(*m_defaultMenu);
}
void AvsMenus::Menu::setMenu(const MenuStruct &menu, const boost::optional<int> &mountingPointIdOfSelectedStream)
{
Q_ASSERT(menu.id() > 0);
Q_ASSERT(m_ismDtc);
m_currentMenu = menu.id();
/*
const auto &mountedAssets = m_ismDtc->mountingPointAssets();
MenuStruct realMenu = menu;
std::vector<AudioVideoManagement::AvMenuEntry> menuEntriesToUse;
for (const auto &entry : realMenu.menuEntries())
{
if (!entry.isGroup() && !entry.mountingPointId().is_set() )
continue;
bool isMounted = false;
if(!entry.isGroup() && entry.mountingPointId().is_set())
{
for (const auto &mountedAsset : mountedAssets)
{
if (mountedAsset.structureElementId() == entry.mountingPointId().get())
{
isMounted = true;
break;
}
}
}
if (entry.isGroup() || isMounted)
menuEntriesToUse.push_back(entry);
}
realMenu.menuEntries(menuEntriesToUse);
*/
m_sendMenu(menu , mountingPointIdOfSelectedStream);
}
} // namespace AudioVideoManagement