/** * @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 #include #include #include #include #include #include #include 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 &entries_, int32_t toplevelId) { std::vector entries = entries_; auto isToplevel = [toplevelId] (const AudioVideoManagement::AvMenuEntry &entry) { return entry.parentId() == toplevelId; }; auto sublevelStart = std::partition(entries.begin(), entries.end(), isToplevel); std::set ids; std::set 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 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& entries, std::vector &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