/** * @RDE_HEADER@ * AvsMenus * $Id$ * $HeadURL$ * $Author$ * Created by Christian Fröbel, NLSE, 2018-03-19 */ #include "avs_menus.h" #include #include #include #include #include #include #include #include #include #include #include namespace { QString toMenuDef(const AudioVideoManagement::AvMenuEntry &menuEntry, const std::vector &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 &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 &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 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 &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 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