/** * @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