From 6c57aa471dd153536b871671855d25cbaf5e137c Mon Sep 17 00:00:00 2001 From: dish Date: Wed, 27 Nov 2024 00:39:46 +0000 Subject: [PATCH] Compiles --- src/SUIT/SUIT_ShortcutMgr.cxx | 267 +++++++++++------- src/SUIT/SUIT_ShortcutMgr.h | 71 +++++ .../action_id_evolution_schemas.json | 11 - src/SUIT/resources/action_id_mutations.json | 11 + 4 files changed, 244 insertions(+), 116 deletions(-) delete mode 100644 src/SUIT/resources/action_id_evolution_schemas.json create mode 100644 src/SUIT/resources/action_id_mutations.json diff --git a/src/SUIT/SUIT_ShortcutMgr.cxx b/src/SUIT/SUIT_ShortcutMgr.cxx index 3afa8cb7c..bea9f2685 100644 --- a/src/SUIT/SUIT_ShortcutMgr.cxx +++ b/src/SUIT/SUIT_ShortcutMgr.cxx @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -3378,157 +3379,213 @@ QString SUIT_ActionSearcher::toString() const +const QString SECTION_NAME_ACTION_ID_MUTATION_FILE_PATHS = "actionID_mutations"; -class SUIT_EXPORT SUIT_ActionIDEvolver +/*static*/ const std::vector SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION = {"shortcuts_vA1.0", "shortcuts"}; + +/*static*/ const QString SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_MUTATIONS = "mutations"; +/*static*/ const QString SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_PREFIX_OLD = "sectionPrefixOld"; +/*static*/ const QString SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_PREFIX_NEW = "sectionPrefixNew"; +/*static*/ const QString SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_NEW_TO_OLD_ACTION_ID_MAP = "newToOldActionIDMap"; + +/*static*/ bool SUIT_ShortcutHistorian::AIDSMutation::isPairOfNewAndOldActionIDsValid(const QString& theSectionPrefixNew, const QString& theSectionPrefixOld) { -public: - struct SUIT_EXPORT Schema - { - bool fromJSON(const QJsonObject& theJsonObject); + if (theSectionPrefixNew == theSectionPrefixOld) { + Warning("SUIT_ShortcutHistorian::AIDSMutation: new section prefix is the same as old one - \"" + theSectionPrefixNew + "\"."); + return false; + } +} - QString sectionPrefix_evolutionFrom; - QString sectionPrefix_evolutionInto; +SUIT_ShortcutHistorian::AIDSMutation::AIDSMutation(const QString& theSectionPrefixNew, const QString& theSectionPrefixOld) +{ + if (!SUIT_ShortcutHistorian::AIDSMutation::isPairOfNewAndOldActionIDsValid(theSectionPrefixNew, theSectionPrefixOld)) + throw std::invalid_argument("AIDSMutation::AIDSMutation: invalid prefixes."); - /** 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; - }; + mySectionPrefixOld = theSectionPrefixOld; + mySectionPrefixNew = theSectionPrefixNew; +} - /** {sectionPrefix_evolutionFrom}[]. Defined from newest to oldest. */ - static const std::vector evolutionChronology; +SUIT_ShortcutHistorian::AIDSMutation::AIDSMutation(const QJsonObject& theJsonObject, const bool theParseMap) +{ + mySectionPrefixOld = theJsonObject[SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_PREFIX_OLD].toString(); + mySectionPrefixNew = theJsonObject[SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_PREFIX_NEW].toString(); + if (!SUIT_ShortcutHistorian::AIDSMutation::isPairOfNewAndOldActionIDsValid(mySectionPrefixNew, mySectionPrefixOld)) + throw std::invalid_argument("AIDSMutation::AIDSMutation: invalid prefixes."); - /*! - \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; + if (!theParseMap) + return; -private: - void parseSchemas(); - std::pair getUserDefinedKeySequenceInOldSection(const QString& theActionID, const QString& theSectionPrefix) const; + const auto actionIDMapJSONObject = theJsonObject[SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_NEW_TO_OLD_ACTION_ID_MAP].toObject(); + for (const QString& newActionID : actionIDMapJSONObject.keys()) { + if (!SUIT_ShortcutMgr::isActionIDValid(newActionID)) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::fromJSON: invalid action ID \"" + newActionID + "\" has been encountered."); + continue; + } -private: - /** {sectionPrefix_evolutionFrom, {schema}[] }[]. Sorted from newest to oldest. */ - std::list>> schemas; -}; + const QString oldActionID = actionIDMapJSONObject[newActionID].toString(); + if (!SUIT_ShortcutMgr::isActionIDValid(oldActionID)) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::fromJSON: invalid action ID \"" + oldActionID + "\" has been encountered."); + continue; + } + + if (myOldToNewActionIDMap.find(oldActionID) != myOldToNewActionIDMap.end()) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::fromJSON: old action ID \"" + oldActionID + "\" is not unique within mutation. Ignored."); + continue; + } + + if (myNewToOldActionIDMap.find(newActionID) != myNewToOldActionIDMap.end()) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::fromJSON: new action ID \"" + newActionID + "\" is not unique within mutation. Ignored."); + continue; + } + + myOldToNewActionIDMap.emplace(oldActionID, newActionID); + myNewToOldActionIDMap.emplace(newActionID, oldActionID); + } +} + +bool SUIT_ShortcutHistorian::AIDSMutation::isConcurrent(const AIDSMutation& theOther) const +{ + return mySectionPrefixOld == theOther.mySectionPrefixOld && mySectionPrefixNew == theOther.mySectionPrefixNew; +} -const QString SECTION_NAME_ACTION_ID_MIGRATION_SCHEMA_FILE_PATHS = "TODO"; +bool SUIT_ShortcutHistorian::AIDSMutation::merge(const AIDSMutation& theOther) +{ + if (!isConcurrent(theOther)) + return false; -static const std::vector SUIT_ActionIDEvolver::evolutionChronology = {"shortcuts_vA1.0", "shortcuts"}; + bool areMutationMapsExtended = false; + for (const auto& newAndOldActionIDOfOther : theOther.myNewToOldActionIDMap) { + const QString& newActionIDOfOther = newAndOldActionIDOfOther.first; + const QString& oldActionIDOfOther = newAndOldActionIDOfOther.second; + + if (myOldToNewActionIDMap.find(oldActionIDOfOther) != myOldToNewActionIDMap.end()) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::merge: old action ID \"" + oldActionIDOfOther + "\" is not unique within mutation. Ignored."); + continue; + } + if (myNewToOldActionIDMap.find(newActionIDOfOther) != myNewToOldActionIDMap.end()) { + Warning("SUIT_ShortcutHistorian::AIDSMutation::merge: new action ID \"" + newActionIDOfOther + "\" is not unique within mutation. Ignored."); + continue; + } -void SUIT_ActionIDEvolver::parseSchemas() { - ShCutDbg() && ShCutDbg("Parsing action ID evolution schemas."); + myOldToNewActionIDMap.emplace(oldActionIDOfOther, newActionIDOfOther); + myNewToOldActionIDMap.emplace(newActionIDOfOther, oldActionIDOfOther); + areMutationMapsExtended = true; + } - if (SUIT_ActionIDEvolver::evolutionChronology.size() < 2) { - Warning("SUIT_ActionIDEvolver: evolution chronology is not sufficient."); + return areMutationMapsExtended; +} + + +std::pair SUIT_ShortcutHistorian::getOldUserDefinedKeySequence(const QString& theActionID) const +{ + auto result = std::pair(false, QKeySequence()); + + /** ID of the same action before a mutation (migration) happened. */ + QString oldActionID = theActionID; + for (const auto& oldPrefixAndMutation : myOldPrefixToMutationList) { + const auto& mutation = oldPrefixAndMutation.second; + const auto itNewAndOldActionIDs = mutation.getNewToOldActionIDMap().find(theActionID); + if (itNewAndOldActionIDs != mutation.getNewToOldActionIDMap().end()) + oldActionID = itNewAndOldActionIDs->second; + + std::pair oldKeySequence = getUserDefinedKeySequenceInSection(oldActionID, mutation.getSectionPrefixOld()); + if (oldKeySequence.first) { + // The old shortcut is defined in the old section. No need to dig deeper into action ID evolution. + return result; + } + } + return result; +} + +void SUIT_ShortcutHistorian::parseMutations() +{ + ShCutDbg() && ShCutDbg("Parsing action ID mutation files."); + + if (SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION.size() < 2) { + Warning("SUIT_ShortcutHistorian: shortcut settings' preference section name evolution is too short."); 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."); + if (SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION.front() != SECTION_NAME_PREFIX) { + Warning("SUIT_ShortcutHistorian: shortcut settings' preference section name evolution starts with a prefix, which differs from the actual one."); return; } - for (size_t idx = 0; idx < SUIT_ActionIDEvolver::evolutionChronology.size() - 1; idx++) { - schemas.emplace(SUIT_ActionIDEvolver::evolutionChronology[idx], std::set>); + for (size_t idx = 0; idx < SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION.size() - 1; idx++) { + const QString& newPrefix = SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION[idx]; + const QString& oldPrefix = SUIT_ShortcutHistorian::SECTION_PREFIX_EVOLUTION[idx + 1]; + myOldPrefixToMutationList.emplace_back(std::pair(oldPrefix, SUIT_ShortcutHistorian::AIDSMutation(newPrefix, oldPrefix))); } SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr(); if (!resMgr) { - Warning("SUIT_ActionIDEvolver can't retrieve resource manager!"); + Warning("SUIT_ShortcutHistorian can't retrieve resource manager!"); return; } - QStringList schemaFilePaths = resMgr->parameters(SECTION_NAME_ACTION_ID_MIGRATION_SCHEMA_FILE_PATHS); + QStringList mutationFilePaths = resMgr->parameters(SECTION_NAME_ACTION_ID_MUTATION_FILE_PATHS); #ifdef SHORTCUT_MGR_DBG - ShCutDbg("Action ID evolution schema files: " + schemaFilePaths.join(", ") + "."); + ShCutDbg("Action ID mutation files: " + mutationFilePaths.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 + "\"!"); + for (const QString& mutationFilePath : mutationFilePaths) { + const QString path = ::SUIT_tools::substituteVars(mutationFilePath); + ShCutDbg("Parsing action ID mutation file \"" + path + "\"."); + QFile mutationFile(path); + if (!mutationFile.open(QIODevice::ReadOnly)) { + Warning("SUIT_ShortcutHistorian can't open action ID mutation file \"" + path + "\"!"); continue; } QJsonParseError jsonError; - QJsonDocument document = QJsonDocument::fromJson(schemaFile.readAll(), &jsonError); - schemaFile.close(); + QJsonDocument document = QJsonDocument::fromJson(mutationFile.readAll(), &jsonError); + mutationFile.close(); if (jsonError.error != QJsonParseError::NoError) { - Warning("SUIT_ShortcutMgr: error during parsing of action ID evolution file \"" + path + "\"!"); + Warning("SUIT_ShortcutHistorian: error during parsing of action ID mutation file \"" + path + "\"!"); continue; } if (document.isObject()) { - QJsonObject documentJSONObject = document.object(); - for (const QString& key : documentJSONObject.keys()) { - if (key != "schemas") // TODO - continue; + const QJsonObject documentJSONObject = document.object(); + const auto itMutationsJSONVal = documentJSONObject.find(SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_MUTATIONS); + if (itMutationsJSONVal == documentJSONObject.end()) { + Warning("Action ID mutation file \"" + path + "\" does not contain \"" + SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_MUTATIONS + "\" array."); + continue; + } - const auto& schemasJSONValue = documentJSONObject[key]; - if (!schemasJSONValue.isArray()) { - ShCutDbg("Action ID evolution file \"" + path + "\" does not contain array \"" + key + "\"."); + const auto& mutationsJSONVal = itMutationsJSONVal.value(); + if (!mutationsJSONVal.isArray()) { + Warning("Action ID mutation file \"" + path + "\" has a property \"" + SUIT_ShortcutHistorian::AIDSMutation::PROP_ID_MUTATIONS + "\", but it is not array."); + continue; + } + + const auto& mutationsJSONArray = mutationsJSONVal.toArray(); + for (const auto& mutationJSONVal : mutationsJSONArray) { + auto mutation = std::unique_ptr(nullptr); + try { + mutation.reset(new SUIT_ShortcutHistorian::AIDSMutation(mutationJSONVal.toObject())); + } + catch (const std::invalid_argument& e) { + Warning(e.what()); 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); + const auto predicate = [&mutation] (const std::pair& thePair) { return thePair.first == mutation->getSectionPrefixOld(); }; + const auto itOldPrefixToMutationList = std::find_if(myOldPrefixToMutationList.begin(), myOldPrefixToMutationList.end(), predicate); + if (itOldPrefixToMutationList == myOldPrefixToMutationList.end() || !mutation->isConcurrent(itOldPrefixToMutationList->second)) { + Warning("Action ID mutation file \"" + path + "\" contains a Mutation, which is not concurrent with mutations from evolution. Old prefix \"" + mutation->getSectionPrefixOld() + "\"; new prefix \"" + mutation->getSectionPrefixNew() + "\"."); + continue; } + + itOldPrefixToMutationList->second.merge(*mutation); } } } } -std::pair SUIT_ActionIDEvolver::getUserDefinedKeySequence(const QString& theActionID) const { +std::pair SUIT_ShortcutHistorian::getUserDefinedKeySequenceInSection(const QString& theActionID, const QString& theSectionPrefix) 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 + "\"."); - } - } - } + // TODO + return result; } \ No newline at end of file diff --git a/src/SUIT/SUIT_ShortcutMgr.h b/src/SUIT/SUIT_ShortcutMgr.h index 228de4067..f319dd5a1 100644 --- a/src/SUIT/SUIT_ShortcutMgr.h +++ b/src/SUIT/SUIT_ShortcutMgr.h @@ -793,6 +793,77 @@ private: }; +/*! \brief Sometimes developers change IDs of actions. And at the moment of release of these changes +users may already have cutomized shortcuts. This class assits with user defined shorcut settings' migrations. +It retrieves keysequences, assigned by user using older Salome versions, +which operated with old action ID sets. "Action ID set" is also referred as AIDS for brevity. */ +class SUIT_EXPORT SUIT_ShortcutHistorian +{ +public: + /** {name prefix of a section in user preference files}[]. Sorted from the newest to the oldest. + * The list is hardcoded. Update it every time, a new AIDS and appropriate AIDSMutation are added. */ + static const std::vector SECTION_PREFIX_EVOLUTION; + +private: + /*! \brief Describes how action IDs evolved between consequtive versions of action ID sets. + PS. Once upon a time I also wanted to cure AIDS. But instead I spawned new ones. With mutations. */ + class SUIT_EXPORT AIDSMutation + { + public: + static const QString PROP_ID_MUTATIONS; + static const QString PROP_ID_PREFIX_OLD; + static const QString PROP_ID_PREFIX_NEW; + static const QString PROP_ID_NEW_TO_OLD_ACTION_ID_MAP; + + static bool isPairOfNewAndOldActionIDsValid(const QString& theSectionPrefixNew, const QString& theSectionPrefixOld); + + AIDSMutation(const QString& theSectionPrefixNew, const QString& theSectionPrefixOld); + AIDSMutation(const QJsonObject& theJsonObject, const bool theParseMap = true); + + const QString& getSectionPrefixOld() const { return mySectionPrefixOld; }; + const QString& getSectionPrefixNew() const { return mySectionPrefixNew; }; + const std::map& getNewToOldActionIDMap() const { return myNewToOldActionIDMap; }; + + /*! \returns True, if both old and new prefixes are the same as ones of theOther. */ + bool isConcurrent(const AIDSMutation& theOther) const; + + /*! \returns True. if mutation maps are extended. */ + bool merge(const AIDSMutation& theOther); + + private: + /** Old name prefix of a section in user preference files. */ + QString mySectionPrefixOld; + + /** New name prefix of a section in user preference files. */ + QString mySectionPrefixNew; + + /** The map only keeps changes between AIDS versions. It means, there is no need to add entries like {theSameActionID, theSameActionID}. */ + std::map myNewToOldActionIDMap; + + /** The map only keeps changes between AIDS versions. It means, there is no need to add entries like {theSameActionID, theSameActionID}. */ + std::map myOldToNewActionIDMap; + }; + +public: + /*! + \param theActionID Action ID in latest version (as elsewhere in ShortcutMgr code). + \returns {false, _ }, if shortcut is not defined in any outdated shortcut section of user preference files. */ + std::pair getOldUserDefinedKeySequence(const QString& theActionID) const; + +private: + void parseMutations(); + + /*! + \param theSectionPrefix User preferences' section name with shortcuts. + \returns {false, _ }, is the shortcut is not defined in the section. */ + std::pair getUserDefinedKeySequenceInSection(const QString& theActionID, const QString& theSectionPrefix) const; + +private: + /** {sectionNamePrefixOld, mutation}[]. Sorted from the newest to the oldest. */ + std::list> myOldPrefixToMutationList; +}; + + namespace SUIT_tools { class SUIT_SentenceMatcher; } diff --git a/src/SUIT/resources/action_id_evolution_schemas.json b/src/SUIT/resources/action_id_evolution_schemas.json deleted file mode 100644 index 1a3cb19ea..000000000 --- a/src/SUIT/resources/action_id_evolution_schemas.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "schemas": [ - { - "sectionPrefix_evolutionFrom": "shortcuts", - "sectionPrefix_evolutionInto": "shortcuts_vA1.0", - "newActionID_to_oldActionID_map": { - - } - } - ] -} \ No newline at end of file diff --git a/src/SUIT/resources/action_id_mutations.json b/src/SUIT/resources/action_id_mutations.json new file mode 100644 index 000000000..eec74dc08 --- /dev/null +++ b/src/SUIT/resources/action_id_mutations.json @@ -0,0 +1,11 @@ +{ + "mutations": [ + { + "sectionPrefixOld": "shortcuts", + "sectionPrefixNew": "shortcuts_vA1.0", + "newToOldActionIDMap": { + + } + } + ] +} \ No newline at end of file -- 2.39.2