263 lines
7.2 KiB
C++
Executable File
263 lines
7.2 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
|
|
#include "object_menu_struct.h"
|
|
#include "handler_menu_struct.h"
|
|
#include "main_handler.h"
|
|
#include "dds_handler.h"
|
|
#include "logger.h"
|
|
#include <AudioVideoManagement/avm_dts.h>
|
|
#include <AudioVideoManagement/avm_db.h>
|
|
#include <Core/function_reply_object.h>
|
|
#include <ngldb/dbtransaction.h>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
AudioVideoManagement::Database::AvmMenuStruct toDb(const AudioVideoManagement::AvMenuEntry &ddsItem, int32_t parentId)
|
|
{
|
|
AudioVideoManagement::Database::AvmMenuStruct dbItem;
|
|
|
|
dbItem.id = ddsItem.id() <= 0 ? 0 : ddsItem.id();
|
|
dbItem.parentId = parentId;
|
|
dbItem.isGroup = ddsItem.isGroup();
|
|
dbItem.rowid = ddsItem.rowId();
|
|
|
|
if (ddsItem.isGroup())
|
|
dbItem.name = QString::fromStdString(ddsItem.name().get());
|
|
else
|
|
dbItem.mountingPointId = ddsItem.mountingPointId().get();
|
|
|
|
return dbItem;
|
|
}
|
|
|
|
void checkHierarchy(const std::vector<AudioVideoManagement::AvMenuEntry> &entries_, int32_t toplevelId)
|
|
{
|
|
std::vector<AudioVideoManagement::AvMenuEntry> entries = entries_;
|
|
|
|
auto isToplevel = [toplevelId] (const AudioVideoManagement::AvMenuEntry &entry) { return entry.parentId() == toplevelId; };
|
|
auto sublevelStart = std::partition(entries.begin(), entries.end(), isToplevel);
|
|
|
|
std::set<int32_t> ids;
|
|
std::set<int32_t> groupIds;
|
|
for (auto entry = entries.begin(); entry != sublevelStart; ++entry)
|
|
{
|
|
auto result = ids.insert(entry->id());
|
|
Q_ASSERT(result.second);
|
|
|
|
if (entry->isGroup())
|
|
groupIds.insert(entry->id());
|
|
}
|
|
|
|
for (auto entry = sublevelStart; entry != entries.end(); ++entry)
|
|
{
|
|
auto result = ids.insert(entry->id());
|
|
Q_ASSERT(result.second);
|
|
|
|
Q_ASSERT(!entry->isGroup());
|
|
Q_ASSERT(groupIds.count(entry->parentId()) > 0);
|
|
}
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
namespace AudioVideoManagement
|
|
{
|
|
|
|
ObjectMenuStruct::ObjectMenuStruct(Interface::Dts *dts, DatabaseInterface *db)
|
|
: m_dts(dts)
|
|
, m_db(db)
|
|
, m_logger(getLogger("ObjectMenuStruct"))
|
|
{
|
|
Q_ASSERT(dts);
|
|
Q_ASSERT(db);
|
|
}
|
|
|
|
ObjectMenuStruct::~ObjectMenuStruct()
|
|
{
|
|
m_dts->removeMenuStructByKey(m_data.id());
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectMenuStruct::createFromDds(const MenuStruct &data)
|
|
{
|
|
Q_ASSERT(data.id() <= 0 && m_data.id() <= 0);
|
|
auto reply = insertUpdateDb(data);
|
|
onPublishData();
|
|
return reply;
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectMenuStruct::updateFromDds(const MenuStruct &data)
|
|
{
|
|
Q_ASSERT(data.id() > 0 && data.id() == m_data.id());
|
|
auto reply = insertUpdateDb(data);
|
|
onPublishData();
|
|
return reply;
|
|
}
|
|
|
|
void ObjectMenuStruct::createFromDb(const MenuStruct &data)
|
|
{
|
|
Q_ASSERT(data.id() > 0 && m_data.id() <= 0);
|
|
checkHierarchy(data.menuEntries(), data.id());
|
|
m_data = data;
|
|
onPublishData();
|
|
}
|
|
|
|
void ObjectMenuStruct::updateFromDb(const MenuStruct &data)
|
|
{
|
|
Q_ASSERT(data.id() > 0 && data.id() == m_data.id());
|
|
if (data == m_data)
|
|
return;
|
|
|
|
checkHierarchy(data.menuEntries(), data.id());
|
|
m_data = data;
|
|
onPublishData();
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectMenuStruct::remove()
|
|
{
|
|
DBTransaction trans(m_db->database());
|
|
|
|
INFO_LOG(m_logger) << "menuEntries.size(): " << m_data.menuEntries().size();
|
|
for (const AudioVideoManagement::AvMenuEntry &me : m_data.menuEntries())
|
|
{
|
|
INFO_LOG(m_logger) << "Remove entries with id/parentId: " << me.id();
|
|
// no recursion needed, only 2 levels allowed
|
|
if (me.isGroup())
|
|
if (!m_db->removeAvmMenuStructByParentId(me.id()))
|
|
return Core::FunctionReplyObject(m_data.id(), "Error while removing menu entries");
|
|
if (!m_db->removeAvmMenuStruct(me.id()))
|
|
return Core::FunctionReplyObject(m_data.id(), "Error while removing menu entries");
|
|
}
|
|
if (!m_db->removeAvmMenuStruct(m_data.id()))
|
|
return Core::FunctionReplyObject(m_data.id(), "Error while removing menu struct");
|
|
|
|
trans.commit();
|
|
|
|
m_dts->removeMenuStructByKey(m_data.id());
|
|
|
|
return Core::FunctionReplyObject(m_data.id());
|
|
}
|
|
|
|
void ObjectMenuStruct::onPublishData()
|
|
{
|
|
|
|
INFO_LOG(m_logger) << "Publish MenuStruct-data to dds (" << m_data.id() << ") ...";
|
|
|
|
if (!m_dts->publish(m_data))
|
|
ERROR_LOG(m_logger) << "Error publishing MenuStruct-data to dds";
|
|
}
|
|
|
|
|
|
Core::FunctionReplyObject ObjectMenuStruct::insertUpdateDb(const MenuStruct &data)
|
|
{
|
|
checkHierarchy(data.menuEntries(), data.id());
|
|
|
|
const auto oldEntries = m_data.menuEntries();
|
|
m_data = data;
|
|
|
|
Database::AvmMenuStruct ms;
|
|
|
|
// Insert Parent
|
|
ms.parentId = 0;
|
|
ms.name = QString::fromStdString(data.name());
|
|
ms.isAudio = data.isAudio();
|
|
ms.isGroup = true;
|
|
|
|
DBTransaction trans(m_db->database());
|
|
|
|
if (m_data.id() > 0)
|
|
{
|
|
ms.id = m_data.id();
|
|
if (!m_db->update(ms))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting AvmMenuStruct-data into database"));
|
|
}
|
|
else
|
|
{
|
|
if (!m_db->insert(ms))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting AvmMenuStruct-data into database"));
|
|
}
|
|
|
|
m_data.id(ms.id);
|
|
const int virtualMenuStructId = data.id();
|
|
const int realMenuStructId = m_data.id();
|
|
|
|
std::vector<AvMenuEntry> newEntries;
|
|
newEntries.reserve(data.menuEntries().size());
|
|
|
|
auto ret = insertUpdateChildren(virtualMenuStructId, realMenuStructId, data.menuEntries(), newEntries);
|
|
if (ret.error())
|
|
return ret;
|
|
|
|
DEBUG_LOG(m_logger) << "old entries: " << m_data;
|
|
for (const AvMenuEntry &me : oldEntries)
|
|
{
|
|
// new entries - ignore
|
|
if (me.id() <= 0)
|
|
continue;
|
|
|
|
auto found = std::find_if(newEntries.begin(), newEntries.end(), [&me] (const AvMenuEntry &newEntry) { return me.id() == newEntry.id(); });
|
|
if (found == newEntries.end())
|
|
{
|
|
DEBUG_LOG(m_logger) << "Menu Entry with id not found - was removed: " << me.id();
|
|
m_db->removeAvmMenuStruct(me.id());
|
|
}
|
|
}
|
|
|
|
m_data.menuEntries(newEntries);
|
|
HandlerMenuStruct::sortEntries(m_data);
|
|
DEBUG_LOG(m_logger) << "new entries: " << m_data;
|
|
|
|
trans.commit();
|
|
return Core::FunctionReplyObject(m_data.id());
|
|
}
|
|
|
|
Core::FunctionReplyObject ObjectMenuStruct::insertUpdateChildren(int virtualParentId,
|
|
int realParentId,
|
|
const std::vector<AudioVideoManagement::AvMenuEntry>& entries,
|
|
std::vector<AudioVideoManagement::AvMenuEntry> &newEntries)
|
|
{
|
|
for(const AudioVideoManagement::AvMenuEntry &ddsItem : entries)
|
|
{
|
|
if (ddsItem.parentId() != virtualParentId)
|
|
continue;
|
|
|
|
Database::AvmMenuStruct dbEntry = ::toDb(ddsItem, realParentId);
|
|
|
|
if (dbEntry.id == 0)
|
|
{
|
|
if (!m_db->insert(dbEntry))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Error inserting AvmMenuStruct-data into database"));
|
|
}
|
|
else
|
|
{
|
|
if (!m_db->update(dbEntry))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Error updating AvmMenuStruct-data into database"));
|
|
}
|
|
|
|
// update database ids in dds data
|
|
newEntries.push_back(HandlerMenuStruct::toDds(dbEntry));
|
|
|
|
if (dbEntry.isGroup)
|
|
{
|
|
const int virtualId = ddsItem.id();
|
|
const int realId = dbEntry.id;
|
|
insertUpdateChildren(virtualId, realId, entries, newEntries);
|
|
}
|
|
}
|
|
|
|
return Core::FunctionReplyObject();
|
|
}
|
|
|
|
} // namespace AudioVideoManagement
|