From 9608c990790c2bd2dd788a59f138ec4949ee5585 Mon Sep 17 00:00:00 2001 From: dish Date: Tue, 26 Nov 2024 13:51:12 +0000 Subject: [PATCH] Add SUIT_ActionIDEvolver class. --- src/SUIT/SUIT_ShortcutMgr.cxx | 157 ++++++++++++++++++ .../action_id_evolution_schemas.json | 11 ++ 2 files changed, 168 insertions(+) create mode 100644 src/SUIT/resources/action_id_evolution_schemas.json diff --git a/src/SUIT/SUIT_ShortcutMgr.cxx b/src/SUIT/SUIT_ShortcutMgr.cxx index d22c05a64..3afa8cb7c 100644 --- a/src/SUIT/SUIT_ShortcutMgr.cxx +++ b/src/SUIT/SUIT_ShortcutMgr.cxx @@ -3374,4 +3374,161 @@ QString SUIT_ActionSearcher::toString() const } return res; +} + + + + +class SUIT_EXPORT SUIT_ActionIDEvolver +{ +public: + struct SUIT_EXPORT Schema + { + bool fromJSON(const QJsonObject& theJsonObject); + + QString sectionPrefix_evolutionFrom; + QString sectionPrefix_evolutionInto; + + /** The map only keeps changes between identification schemes. It means, there is no need to add entries like {theSameActionID: theSameActionID}. */ + std::map newActionID_to_oldActionID_map; + }; + + /** {sectionPrefix_evolutionFrom}[]. Defined from newest to oldest. */ + static const std::vector evolutionChronology; + + /*! + \param theActionID Action ID in the latest identification schema (as elsewhere in code). + \returns {false, _ }, if shortcut is not defined in any outdated shortcut section of user preference files. */ + std::pair getUserDefinedKeySequence(const QString& theActionID) const; + +private: + void parseSchemas(); + std::pair getUserDefinedKeySequenceInOldSection(const QString& theActionID, const QString& theSectionPrefix) const; + +private: + /** {sectionPrefix_evolutionFrom, {schema}[] }[]. Sorted from newest to oldest. */ + std::list>> schemas; +}; + +const QString SECTION_NAME_ACTION_ID_MIGRATION_SCHEMA_FILE_PATHS = "TODO"; + +static const std::vector SUIT_ActionIDEvolver::evolutionChronology = {"shortcuts_vA1.0", "shortcuts"}; + + +void SUIT_ActionIDEvolver::parseSchemas() { + ShCutDbg() && ShCutDbg("Parsing action ID evolution schemas."); + + if (SUIT_ActionIDEvolver::evolutionChronology.size() < 2) { + Warning("SUIT_ActionIDEvolver: evolution chronology is not sufficient."); + return; + } + + if (SUIT_ActionIDEvolver::evolutionChronology.front() != SECTION_NAME_PREFIX) { + Warning("SUIT_ActionIDEvolver: evolution chronology starts with a shortcuts' preference section name prefix, which differs from actual one."); + return; + } + + for (size_t idx = 0; idx < SUIT_ActionIDEvolver::evolutionChronology.size() - 1; idx++) { + schemas.emplace(SUIT_ActionIDEvolver::evolutionChronology[idx], std::set>); + } + + SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); + if (!resMgr) { + Warning("SUIT_ActionIDEvolver can't retrieve resource manager!"); + return; + } + + QStringList schemaFilePaths = resMgr->parameters(SECTION_NAME_ACTION_ID_MIGRATION_SCHEMA_FILE_PATHS); +#ifdef SHORTCUT_MGR_DBG + ShCutDbg("Action ID evolution schema files: " + schemaFilePaths.join(", ") + "."); +#endif + for (const QString& schemaFilePath : schemaFilePaths) { + const QString path = ::SUIT_tools::substituteVars(schemaFilePath); + ShCutDbg("Parsing action ID evolution file \"" + path + "\"."); + QFile schemaFile(path); + if (!schemaFile.open(QIODevice::ReadOnly)) { + Warning("SUIT_ActionIDEvolver can't open action ID evolution file \"" + path + "\"!"); + continue; + } + + QJsonParseError jsonError; + QJsonDocument document = QJsonDocument::fromJson(schemaFile.readAll(), &jsonError); + schemaFile.close(); + if (jsonError.error != QJsonParseError::NoError) { + Warning("SUIT_ShortcutMgr: error during parsing of action ID evolution file \"" + path + "\"!"); + continue; + } + + if (document.isObject()) { + QJsonObject documentJSONObject = document.object(); + for (const QString& key : documentJSONObject.keys()) { + if (key != "schemas") // TODO + continue; + + const auto& schemasJSONValue = documentJSONObject[key]; + if (!schemasJSONValue.isArray()) { + ShCutDbg("Action ID evolution file \"" + path + "\" does not contain array \"" + key + "\"."); + continue; + } + + const auto& schemasJSONArray = schemasJSONValue.toArray(); + for (const auto& schemaJSONVal : schemasJSONArray) { + if (!schemaJSONVal.isObject()) { + ShCutDbg("Action ID evolution file \"" + path + "\" contains invalid schema object."); + continue; + } + + auto schema = std::shared_ptr(new SUIT_ActionIDEvolver::Schema()); + if (!schema->fromJSON(schemaJSONVal.toObject())) { + ShCutDbg("Action ID evolution file \"" + path + "\" contains invalid schema object."); + continue; + } + + if (schema->sectionPrefix_evolutionFrom == schema->sectionPrefix_evolutionInto) { + ShCutDbg("Action ID evolution file \"" + path + "\" contains invalid evolution schema (from == into). From/into \"" + schema->sectionPrefix_evolutionFrom + "\"."); + continue; + } + + const auto itEvolutionFrom = std::find(SUIT_ActionIDEvolver::evolutionChronology.begin(), SUIT_ActionIDEvolver::evolutionChronology.end(); schema->sectionPrefix_evolutionFrom); + const auto itEvolutionInto = std::find(SUIT_ActionIDEvolver::evolutionChronology.begin(), SUIT_ActionIDEvolver::evolutionChronology.end(); schema->sectionPrefix_evolutionInto); + if (itEvolutionFrom == SUIT_ActionIDEvolver::evolutionChronology.end() || itEvolutionInto == SUIT_ActionIDEvolver::evolutionChronology.end()) { + ShCutDbg("Action ID evolution file \"" + path + "\" contains evolution schema, which is absent in evolution chronology. From \"" + schema->sectionPrefix_evolutionFrom + "\" into \"" + schema->sectionPrefix_evolutionInto + "\"."); + continue; + } + + { + const auto itEvolutionFromNext = ++itEvolutionFrom; + if (itEvolutionFromNext != itEvolutionInto) { + ShCutDbg("Action ID evolution file \"" + path + "\" contains evolution schema, which is absent in evolution chronology. From \"" + schema->sectionPrefix_evolutionFrom + "\" into \"" + schema->sectionPrefix_evolutionInto + "\"."); + continue; + } + } + + schemas[schema->sectionPrefix_evolutionFrom].insert(schema); + } + } + } + } +} + +std::pair SUIT_ActionIDEvolver::getUserDefinedKeySequence(const QString& theActionID) const { + auto result = std::pair(false, QKeySequence()); + for (const auto& sectionPrefixAndSchemas : schemas) { + const auto& schemasOfCurrentEvolution = sectionPrefixAndSchemas.second; + for (const auto& schemaOfCurrentEvolution : schemasOfCurrentEvolution ) { + const auto it = schemaOfCurrentEvolution.newActionID_to_oldActionID_map.find(theActionID); + if (it == schemaOfCurrentEvolution.newActionID_to_oldActionID_map.end()) + continue; + + const QString& olderActionID = it->second; + std::pair olderKS = getUserDefinedKeySequenceInOldSection(olderActionID, schemaOfCurrentEvolution.sectionPrefix_evolutionFrom); + if (olderKS.first) { + result = SUIT_ShortcutMgr::toKeySequenceIfValid(olderKS.second); + if (result.first) + return result; // Even if there are other + else + ShCutDbg("Old settings file contains invalid key sequence string \"" + olderKS.second + "\". From \"" + schemaOfCurrentEvolution->sectionPrefix_evolutionFrom + "\" into \"" + schemaOfCurrentEvolution->sectionPrefix_evolutionInto + "\"."); + } + } + } } \ No newline at end of file diff --git a/src/SUIT/resources/action_id_evolution_schemas.json b/src/SUIT/resources/action_id_evolution_schemas.json new file mode 100644 index 000000000..1a3cb19ea --- /dev/null +++ b/src/SUIT/resources/action_id_evolution_schemas.json @@ -0,0 +1,11 @@ +{ + "schemas": [ + { + "sectionPrefix_evolutionFrom": "shortcuts", + "sectionPrefix_evolutionInto": "shortcuts_vA1.0", + "newActionID_to_oldActionID_map": { + + } + } + ] +} \ No newline at end of file -- 2.39.2