390 lines
10 KiB
C++
Executable File
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
|