296 lines
8.4 KiB
C++
Executable File
296 lines
8.4 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "handler_menu_struct.h"
|
|
#include "main_handler.h"
|
|
#include "dds_handler.h"
|
|
#include "object_menu_struct.h"
|
|
#include "audio_video_handler_impl.h"
|
|
#include <AudioVideoManagement/avm_dts.h>
|
|
#include <QVector>
|
|
#include <tuple>
|
|
|
|
namespace
|
|
{
|
|
|
|
|
|
AudioVideoManagement::MenuStruct toDdsToplevel(const AudioVideoManagement::Database::AvmMenuStruct &dbEntry)
|
|
{
|
|
Q_ASSERT(dbEntry.parentId == 0);
|
|
Q_ASSERT(dbEntry.isGroup);
|
|
Q_ASSERT(dbEntry.name.isValid());
|
|
|
|
AudioVideoManagement::MenuStruct ms;
|
|
ms.id(dbEntry.id);
|
|
ms.name(dbEntry.name.toString().toStdString());
|
|
ms.isAudio(dbEntry.isAudio);
|
|
|
|
return ms;
|
|
}
|
|
|
|
void insertChildren(std::vector<AudioVideoManagement::AvMenuEntry>& contToAdd,
|
|
int parentId,
|
|
const QVector<AudioVideoManagement::Database::AvmMenuStruct> &vecMenuStructs)
|
|
{
|
|
using namespace AudioVideoManagement;
|
|
|
|
for (const Database::AvmMenuStruct &ms : vecMenuStructs)
|
|
if (ms.parentId == parentId)
|
|
contToAdd.push_back(HandlerMenuStruct::toDds(ms));
|
|
}
|
|
|
|
bool lessToplevel(const AudioVideoManagement::AvMenuEntry &a,
|
|
const AudioVideoManagement::AvMenuEntry &b)
|
|
{
|
|
return a.id() < b.id();
|
|
}
|
|
|
|
bool lessSublevel(const AudioVideoManagement::AvMenuEntry &a,
|
|
const AudioVideoManagement::AvMenuEntry &b)
|
|
{
|
|
return std::make_tuple(a.parentId(), a.rowId(), a.id()) < std::make_tuple(b.parentId(), b.rowId(), b.id());
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
namespace AudioVideoManagement
|
|
{
|
|
|
|
AvMenuEntry HandlerMenuStruct::toDds(const Database::AvmMenuStruct &dbEntry)
|
|
{
|
|
Q_ASSERT(dbEntry.parentId > 0);
|
|
|
|
AvMenuEntry ddsItem;
|
|
|
|
ddsItem.id(dbEntry.id);
|
|
ddsItem.parentId(dbEntry.parentId);
|
|
ddsItem.isGroup(dbEntry.isGroup);
|
|
ddsItem.rowId(dbEntry.rowid);
|
|
if (dbEntry.isGroup)
|
|
{
|
|
Q_ASSERT(dbEntry.name.isValid());
|
|
ddsItem.name().set(dbEntry.name.toString().toStdString());
|
|
}
|
|
else
|
|
{
|
|
// If it's not a group it represents a stream for a given MountignPoint.
|
|
// For the name we then use the internal stream name for that MountingPoint.
|
|
// That name is not saved in the DB.
|
|
// Using the internal stream name here makes it easy for clients to directly
|
|
// use those when communicating with AVS.
|
|
Q_ASSERT(dbEntry.mountingPointId.isValid());
|
|
ddsItem.mountingPointId(dbEntry.mountingPointId.toInt());
|
|
ddsItem.name().set(AudioVideoHandlerImpl::internalStreamName(dbEntry.mountingPointId.toInt()).toStdString());
|
|
}
|
|
|
|
return ddsItem;
|
|
}
|
|
|
|
void HandlerMenuStruct::sortEntries(MenuStruct &menu)
|
|
{
|
|
auto isToplevel = [&menu] (const AvMenuEntry& entry) { return entry.parentId() == menu.id(); };
|
|
auto sublevelStart = std::partition(menu.menuEntries().begin(), menu.menuEntries().end(), isToplevel);
|
|
|
|
std::sort(menu.menuEntries().begin(), sublevelStart, lessToplevel);
|
|
std::sort(sublevelStart, menu.menuEntries().end(), lessSublevel);
|
|
}
|
|
|
|
HandlerMenuStruct::HandlerMenuStruct(Interface::Dts *dts, Interface::Fts *fts, DatabaseInterface *db)
|
|
: Interface::Fts::ModifyMenuStructRequestHandler(nullptr)
|
|
, Interface::Fts::RemoveMenuStructRequestHandler(nullptr)
|
|
, m_dts(dts)
|
|
, m_fts(fts)
|
|
, m_db(db)
|
|
, m_logger(getLogger("HandlerMenuStruct"))
|
|
{
|
|
Q_ASSERT(dts);
|
|
Q_ASSERT(fts);
|
|
Q_ASSERT(db);
|
|
m_fts->setModifyMenuStructRequestHandler(this);
|
|
m_fts->setRemoveMenuStructRequestHandler(this);
|
|
|
|
connect(m_db, &DatabaseInterface::notifyDeleteAvmMenuStruct, this, &HandlerMenuStruct::onDbDeletedAvmMenuStruct);
|
|
}
|
|
|
|
HandlerMenuStruct::~HandlerMenuStruct()
|
|
{
|
|
m_fts->setModifyMenuStructRequestHandler(nullptr);
|
|
m_fts->setRemoveMenuStructRequestHandler(nullptr);
|
|
qDeleteAll(m_objMap);
|
|
}
|
|
|
|
bool HandlerMenuStruct::init()
|
|
{
|
|
return initObjects();
|
|
}
|
|
|
|
bool HandlerMenuStruct::initObjects()
|
|
{
|
|
bool status = false;
|
|
const QList<MenuStruct> dbItems = loadFromDb(status);
|
|
if (!status)
|
|
return false;
|
|
|
|
for (const auto &ms : dbItems)
|
|
{
|
|
ObjectMenuStruct *objMs = new ObjectMenuStruct(m_dts, m_db);
|
|
objMs->createFromDb(ms);
|
|
m_objMap.insert(objMs->getId(), objMs);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Will be called whenever a row from avm.menu_struct is removed.
|
|
* The remove-operation itself can be a result of the following:
|
|
* 1. we ourselves are about to remove a row as a result of a RemoveRequest
|
|
* 2. one of our foreign key dependencies was removed (mounting_point) and our row
|
|
* was removed as a result of a cascading delete
|
|
* 3. someone removed the row by hand.
|
|
*/
|
|
void HandlerMenuStruct::reload()
|
|
{
|
|
bool status = false;
|
|
const QList<MenuStruct> dbItems = loadFromDb(status);
|
|
if (!status)
|
|
return;
|
|
|
|
for (const auto &ms : dbItems)
|
|
{
|
|
auto found = m_objMap.find(ms.id());
|
|
Q_ASSERT(found != m_objMap.end());
|
|
(*found)->updateFromDb(ms);
|
|
}
|
|
}
|
|
|
|
QList<MenuStruct> HandlerMenuStruct::loadFromDb(bool &status)
|
|
{
|
|
status = false;
|
|
|
|
QVector<Database::AvmMenuStruct> vecMenuStruct;
|
|
if (!m_db->select(vecMenuStruct))
|
|
return {};
|
|
|
|
auto isToplevel = [] (const Database::AvmMenuStruct& dbEntry) { return dbEntry.parentId == 0; };
|
|
auto sublevelStart = std::partition(vecMenuStruct.begin(), vecMenuStruct.end(), isToplevel);
|
|
|
|
QMap<qint32, MenuStruct> msMap;
|
|
for (auto dbEntry = vecMenuStruct.begin(); dbEntry != sublevelStart; ++dbEntry)
|
|
{
|
|
MenuStruct ms = toDdsToplevel(*dbEntry);
|
|
msMap.insert(ms.id(), ms);
|
|
}
|
|
|
|
// Go over all non-toplevel entries and create AvMenuEntries for those
|
|
// and connect them to their parent MenuStruct.
|
|
for (auto dbEntry = sublevelStart; dbEntry != vecMenuStruct.end(); ++dbEntry)
|
|
{
|
|
auto it = msMap.find(dbEntry->parentId);
|
|
if (it == msMap.end())
|
|
continue; // this entry is probably not a direct child of a toplevel entry.
|
|
|
|
MenuStruct &parent = it.value();
|
|
|
|
AudioVideoManagement::AvMenuEntry me = toDds(*dbEntry);
|
|
parent.menuEntries().push_back(me);
|
|
|
|
insertChildren(parent.menuEntries(), me.id(), vecMenuStruct);
|
|
}
|
|
|
|
|
|
// For each MenuStruct sort its entries.
|
|
// Also: Consistency check that for each dbEntry there was created an element.
|
|
// Or in other words that the hierarchy is consistent.
|
|
int totalCount = msMap.size();
|
|
for (auto &ms : msMap)
|
|
{
|
|
sortEntries(ms);
|
|
totalCount += ms.menuEntries().size();
|
|
}
|
|
Q_ASSERT(totalCount == vecMenuStruct.size());
|
|
|
|
status = true;
|
|
return msMap.values();
|
|
}
|
|
|
|
|
|
void HandlerMenuStruct::onModifyMenuStructRequest(const rti::core::SampleIdentity &cookie,
|
|
const MenuStruct &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onModifyMenuStructRequest: " << request;
|
|
auto ret = request.id() > 0 ? modifyMenuStructRequest(request) : createMenuStructRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_fts->modifyMenuStructReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerMenuStruct::createMenuStructRequest(const MenuStruct &request)
|
|
{
|
|
ObjectMenuStruct *ifs = new ObjectMenuStruct(m_dts, m_db);
|
|
|
|
DEBUG_LOG(m_logger) << "request.menuEntries.size() : " << request.menuEntries().size();
|
|
Core::FunctionReplyObject ret = ifs->createFromDds(request);
|
|
|
|
if (ret.error())
|
|
delete ifs;
|
|
else
|
|
m_objMap.insert(ifs->getId(), ifs);
|
|
|
|
return ret;
|
|
}
|
|
|
|
Core::FunctionReplyObject HandlerMenuStruct::modifyMenuStructRequest(const MenuStruct &request)
|
|
{
|
|
ObjectMenuStruct *ifs = m_objMap.value(request.id());
|
|
if (ifs == nullptr)
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "MenuStruct with id %1 not found")).arg(request.id());
|
|
|
|
auto ret = ifs->updateFromDds(request);
|
|
if (ret.error())
|
|
return ret;
|
|
|
|
Q_ASSERT(ifs->getId() == request.id());
|
|
return ret;
|
|
}
|
|
|
|
void HandlerMenuStruct::onRemoveMenuStructRequest(const rti::core::SampleIdentity &cookie,
|
|
const Core::RemoveElementRequest &request)
|
|
{
|
|
Core::FunctionReplyObject ret;
|
|
|
|
INFO_LOG(m_logger) << "onRemoveMenuStructRequest id = " << request.id();
|
|
|
|
ObjectMenuStruct *ifs = m_objMap.value(request.id());
|
|
if (ifs == nullptr)
|
|
{
|
|
ret = Core::FunctionReplyObject(request.id(), tr_lts("dds", "MenuStruct with id %1 not found")).arg(request.id());
|
|
}
|
|
else
|
|
{
|
|
ret = ifs->remove();
|
|
|
|
if (!ret.error())
|
|
{
|
|
m_objMap.remove(request.id());
|
|
delete ifs;
|
|
}
|
|
}
|
|
|
|
m_fts->removeMenuStructReply(cookie, ret);
|
|
}
|
|
|
|
void HandlerMenuStruct::onDbDeletedAvmMenuStruct(const QVariant &id_)
|
|
{
|
|
int id = id_.toInt();
|
|
DEBUG_LOG(m_logger) << "DB deleted AvmMenuStruct with id: " << id;
|
|
reload();
|
|
}
|
|
|
|
} // namespace AudioVideoManagement
|