From 9117ba9dbee136ccaebacd854e289616049deca1 Mon Sep 17 00:00:00 2001 From: nds Date: Thu, 19 May 2016 11:24:33 +0300 Subject: [PATCH] Issue #1489 Multi-rotation problem if there is a reference to copied objects --- src/Model/Model_Objects.cpp | 2 +- src/ModelAPI/ModelAPI_Tools.cpp | 236 ++++++++++++++ src/ModelAPI/ModelAPI_Tools.h | 42 +++ src/ModuleBase/ModuleBase_IModule.h | 2 +- src/ModuleBase/ModuleBase_Tools.cpp | 293 ++++++------------ src/ModuleBase/ModuleBase_Tools.h | 73 ++--- .../ParametersPlugin_WidgetParamsMgr.cpp | 29 +- src/PartSet/PartSet_ExternalObjectsMgr.cpp | 10 +- src/PartSet/PartSet_Module.cpp | 4 +- src/PartSet/PartSet_Module.h | 2 +- src/PartSet/PartSet_SketcherMgr.cpp | 4 +- src/PartSet/PartSet_SketcherMgr.h | 2 +- src/PartSet/PartSet_WidgetSketchCreator.cpp | 2 +- .../SketchPlugin_MultiRotation.cpp | 17 +- src/XGUI/XGUI_Workshop.cpp | 251 +++------------ src/XGUI/XGUI_Workshop.h | 26 +- 16 files changed, 481 insertions(+), 514 deletions(-) diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index fa6991582..44ab4cf59 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -240,7 +240,7 @@ void Model_Objects::removeFeature(FeaturePtr theFeature) for(; aRefIter != aRefs.end(); aRefIter++) { std::shared_ptr aComposite = std::dynamic_pointer_cast(*aRefIter); - if (aComposite.get()) { + if (aComposite.get() && aComposite->isSub(theFeature)) { aComposite->removeFeature(theFeature); } } diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index 20073da7c..658def2ef 100755 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -14,6 +14,52 @@ #include #include #include +#include + +#include +#include + +//#define DEBUG_REMOVE_FEATURES + +#ifdef DEBUG_REMOVE_FEATURES +void printMapInfo(const std::map >& theMainList, + const std::string& thePrefix) +{ + std::map >::const_iterator aMainIt = theMainList.begin(), + aMainLast = theMainList.end(); + std::string anInfo; + for (; aMainIt != aMainLast; aMainIt++) { + FeaturePtr aMainListFeature = aMainIt->first; + std::set aMainRefList = aMainIt->second; + std::set::const_iterator anIt = aMainRefList.begin(), aLast = aMainRefList.end(); + std::string aRefsInfo; + for (; anIt != aLast; anIt++) { + aRefsInfo += (*anIt)->name().c_str(); + if (anIt != aLast) + aRefsInfo += ", "; + } + if (!aRefsInfo.empty()) { + anInfo = anInfo + aMainListFeature->name().c_str() + ": " + aRefsInfo + "\n"; + } + } + std::cout << thePrefix.c_str() << ": " << anInfo.c_str() << std::endl; +} + +void printListInfo(const std::set& theMainList, + const std::string& thePrefix) +{ + std::set::const_iterator aMainIt = theMainList.begin(), + aMainLast = theMainList.end(); + std::string anInfo; + for (; aMainIt != aMainLast; aMainIt++) { + FeaturePtr aRefFeature = *aMainIt; + anInfo += aRefFeature->name().c_str(); + if (aMainIt != aMainLast) + anInfo += ", "; + } + std::cout << thePrefix.c_str() << ": " << anInfo.c_str() << std::endl; +} +#endif namespace ModelAPI_Tools { @@ -312,6 +358,196 @@ void allResults(const FeaturePtr& theFeature, std::list& theResults) } } +bool removeFeaturesAndReferences(const std::set& theFeatures, + const bool theFlushRedisplay, + const bool theUseComposite, + const bool theUseRecursion) +{ +#ifdef DEBUG_REMOVE_FEATURES + printListInfo(theFeatures, "selection: "); +#endif + + std::map > aReferences; + ModelAPI_Tools::findAllReferences(theFeatures, aReferences, theUseComposite, theUseRecursion); +#ifdef DEBUG_REMOVE_FEATURES + printMapInfo(aReferences, "allDependencies: "); +#endif + + std::set aFeaturesRefsTo; + ModelAPI_Tools::findRefsToFeatures(theFeatures, aReferences, aFeaturesRefsTo); +#ifdef DEBUG_REMOVE_FEATURES + printListInfo(aFeaturesRefsTo, "references: "); +#endif + + std::set aFeatures = theFeatures; + if (!aFeaturesRefsTo.empty()) + aFeatures.insert(aFeaturesRefsTo.begin(), aFeaturesRefsTo.end()); +#ifdef DEBUG_REMOVE_FEATURES + printListInfo(aFeatures, "removeFeatures: "); +#endif + + return ModelAPI_Tools::removeFeatures(aFeatures, false); +} + +bool removeFeatures(const std::set& theFeatures, + const bool theFlushRedisplay) +{ + bool isDone = false; + std::set::const_iterator anIt = theFeatures.begin(), + aLast = theFeatures.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (aFeature.get()) { + DocumentPtr aDoc = aFeature->document(); + // flush REDISPLAY signal after remove feature + aDoc->removeFeature(aFeature); + isDone = true; + } + } + if (isDone && theFlushRedisplay) { + // the redisplay signal should be flushed in order to erase the feature presentation in the viewer + // if should be done after removeFeature() of document + Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)); + } + return true; +} + +// Fills the references list by all references of the feature from the references map. +// This is a recusive method to find references by next found feature in the map of references. +// \param theFeature a feature to find references +// \param theReferencesMap a map of references +// \param theReferences an out container of references +void addRefsToFeature(const FeaturePtr& theFeature, + const std::map >& theReferencesMap, + std::set& theReferences) +{ + if (theReferencesMap.find(theFeature) == theReferencesMap.end()) + return; // this feature is not in the selection list, so exists without references to it + std::set aMainReferences = theReferencesMap.at(theFeature); + + std::set::const_iterator anIt = aMainReferences.begin(), + aLast = aMainReferences.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aRefFeature = *anIt; + if (theReferences.find(aRefFeature) == theReferences.end()) + theReferences.insert(aRefFeature); + addRefsToFeature(aRefFeature, theReferencesMap, theReferences); + } +} + +// For each feature from the feature list it searches references to the feature and append them +// to the references map. This is a recusive method. +// \param theFeature a feature to find references +// \param theReferencesMap a map of references +// \param theReferences an out container of references +void findReferences(const std::set& theFeatures, + std::map >& theReferences, + const bool theUseComposite, const bool theUseRecursion) +{ + std::set::const_iterator anIt = theFeatures.begin(), + aLast = theFeatures.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (aFeature.get() && theReferences.find(aFeature) == theReferences.end()) { + DocumentPtr aSelFeatureDoc = aFeature->document(); + std::set aSelRefFeatures; + aSelFeatureDoc->refsToFeature(aFeature, aSelRefFeatures, false/*do not emit signals*/); + if (theUseComposite) { // do not filter selection + theReferences[aFeature] = aSelRefFeatures; + } + else { // filter references to skip composition features of the current feature + std::set aFilteredFeatures; + std::set::const_iterator anIt = aSelRefFeatures.begin(), + aLast = aSelRefFeatures.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aCFeature = *anIt; + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aCFeature); + if (aComposite.get() && aComposite->isSub(aFeature)) + continue; /// composite of the current feature should be skipped + aFilteredFeatures.insert(aCFeature); + } + theReferences[aFeature] = aFilteredFeatures; + } + if (theUseRecursion) + findReferences(aSelRefFeatures, theReferences, theUseComposite, theUseRecursion); + } + } +} + +void findAllReferences(const std::set& theFeatures, + std::map >& theReferences, + const bool theUseComposite, + const bool theUseRecursion) +{ + // For dependencies, find main_list: + // sk_1(ext_1, vertex_1) + // ext_1(bool_1, sk_3) + // vertex_1() + // sk_2(ext_2) + // ext_2(bool_2) + // sk_3() + // Information: bool_1 is not selected, ext_2(bool_2) exists + // find all referenced features + std::map > aMainList; + findReferences(theFeatures, aMainList, theUseComposite, theUseRecursion); + +#ifdef DEBUG_REMOVE_FEATURES + printMapInfo(aMainList, "firstDependencies"); +#endif + // find all dependencies for each object: + // sk_1(ext_1, vertex_1) + (sk_3, bool_1) + // ext_1(bool_1, sk_3) + // vertex_1() + // sk_2(ext_2) + (bool_1) + // ext_2(bool_1) + // sk_3() + std::map >::const_iterator aMainIt = aMainList.begin(), + aMainLast = aMainList.end(); + for (; aMainIt != aMainLast; aMainIt++) { + FeaturePtr aMainListFeature = aMainIt->first; + //std::string aName = aMainListFeature->name(); + std::set aMainRefList = aMainIt->second; + std::set anAddRefFeatures; + + std::set::const_iterator anIt = aMainRefList.begin(), + aLast = aMainRefList.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + addRefsToFeature(aFeature, aMainList, aMainRefList); + } + theReferences[aMainListFeature] = aMainRefList; + } + +#ifdef DEBUG_REMOVE_FEATURES + printMapInfo(theReferences, "allDependencies"); +#endif +} + +void findRefsToFeatures(const std::set& theFeatures, + const std::map >& theReferences, + std::set& theFeaturesRefsTo) +{ + std::set::const_iterator anIt = theFeatures.begin(), + aLast = theFeatures.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (theReferences.find(aFeature) == theReferences.end()) + continue; + std::set aRefList = theReferences.at(aFeature); + std::set::const_iterator aRefIt = aRefList.begin(), aRefLast = aRefList.end(); + for (; aRefIt != aRefLast; aRefIt++) { + FeaturePtr aRefFeature = *aRefIt; + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aRefFeature); + if (aComposite.get() && aComposite->isSub(aFeature)) + continue; /// composite of the current feature should not be removed + + if (theFeatures.find(aRefFeature) == theFeatures.end() && // it is not selected + theFeaturesRefsTo.find(aRefFeature) == theFeaturesRefsTo.end()) // it is not added + theFeaturesRefsTo.insert(aRefFeature); + } + } +} + } // namespace ModelAPI_Tools diff --git a/src/ModelAPI/ModelAPI_Tools.h b/src/ModelAPI/ModelAPI_Tools.h index 02090e516..9085e6d77 100755 --- a/src/ModelAPI/ModelAPI_Tools.h +++ b/src/ModelAPI/ModelAPI_Tools.h @@ -19,6 +19,8 @@ #include #include +#include +#include namespace ModelAPI_Tools { /// Returns shape from the given Result object @@ -98,6 +100,46 @@ MODELAPI_EXPORT bool hasSubResults(const ResultPtr& theResult); */ MODELAPI_EXPORT void allResults(const FeaturePtr& theFeature, std::list& theResults); + +/*! Removes features from the document +* \param theFeatures a list of features to be removed +* \param theFlushRedisplay a boolean value if the redisplay signal should be flushed +* \return true if at least one feature is removed +*/ +MODELAPI_EXPORT bool removeFeaturesAndReferences(const std::set& theFeatures, + const bool theFlushRedisplay = false, + const bool theUseComposite = false, + const bool theUseRecursion = true); + +/*! Removes features from the document +* \param theFeatures a list of features to be removed +* \param theFlushRedisplay a boolean value if the redisplay signal should be flushed +* \return true if at least one feature is removed +*/ +MODELAPI_EXPORT bool removeFeatures(const std::set& theFeatures, + const bool theFlushRedisplay); + +/*! Build a map of references for the given set of features +* \param theFeatures a list of features +* \param theReferences a map of all references to the features +* \param theUseComposite state if the composite features of the reference should be in the map +* \param theUseRecursion state if references for features out of the sources feature + list are put into the result container. E.g. if theFeatures contains "Sketch_2", map will + contain references to this feature also. +*/ +MODELAPI_EXPORT void findAllReferences(const std::set& theFeatures, + std::map >& theReferences, + const bool theUseComposite = true, + const bool theUseRecursion = true); + +/*! In the map of references find all features referenced to the source feature +* \param theFeatures a list of features to find references +* \param theReferences a map of all references to the features +* \param theFeaturesRefsTo an out list of referenced features +*/ +MODELAPI_EXPORT void findRefsToFeatures(const std::set& aFeatures, + const std::map >& aReferences, + std::set& aFeaturesRefsTo); } #endif diff --git a/src/ModuleBase/ModuleBase_IModule.h b/src/ModuleBase/ModuleBase_IModule.h index 769af80dc..f9b5868b7 100755 --- a/src/ModuleBase/ModuleBase_IModule.h +++ b/src/ModuleBase/ModuleBase_IModule.h @@ -176,7 +176,7 @@ class MODULEBASE_EXPORT ModuleBase_IModule : public QObject /// Make some functionality after the objects are hidden in viewer /// \param theObjects a list of hidden objects - virtual void processHiddenObject(const std::list& theObjects) {}; + //virtual void processHiddenObject(const std::list& theObjects) {}; /// Returns true if selection for the object can be activate. /// By default a result or feature of the current operation can not be activated diff --git a/src/ModuleBase/ModuleBase_Tools.cpp b/src/ModuleBase/ModuleBase_Tools.cpp index 3211a935a..a3a62f4e2 100755 --- a/src/ModuleBase/ModuleBase_Tools.cpp +++ b/src/ModuleBase/ModuleBase_Tools.cpp @@ -657,144 +657,6 @@ QString wrapTextByWords(const QString& theValue, QWidget* theWidget, return aResult; } -void findReferences(const QObjectPtrList& theList, - std::set& aDirectRefFeatures, - std::set& aIndirectRefFeatures) -{ - foreach (ObjectPtr aDeletedObj, theList) { - std::set alreadyProcessed; - refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, theList, aDirectRefFeatures, - aIndirectRefFeatures, alreadyProcessed); - std::set aDifference; - std::set_difference(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end(), - aDirectRefFeatures.begin(), aDirectRefFeatures.end(), - std::inserter(aDifference, aDifference.begin())); - aIndirectRefFeatures = aDifference; - } -} - -//************************************************************** -void refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject, - const QObjectPtrList& theIgnoreList, - std::set& theDirectRefFeatures, - std::set& theIndirectRefFeatures, - std::set& theAlreadyProcessed) -{ - refsDirectToFeatureInAllDocuments(theSourceObject, theObject, theIgnoreList, theDirectRefFeatures, - theAlreadyProcessed); - - // Run recursion. It is possible recursive dependency, like the following: plane, extrusion uses plane, - // axis is built on extrusion. Delete of a plane should check the dependency from the axis also. - std::set::const_iterator aFeatureIt = theDirectRefFeatures.begin(); - for (; aFeatureIt != theDirectRefFeatures.end(); ++aFeatureIt) { - std::set aRecursiveRefFeatures; - refsToFeatureInAllDocuments(theSourceObject, *aFeatureIt, theIgnoreList, - aRecursiveRefFeatures, aRecursiveRefFeatures, theAlreadyProcessed); - theIndirectRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end()); - } - -} - - - -//************************************************************** -void refsDirectToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject, - const QObjectPtrList& theIgnoreList, - std::set& theDirectRefFeatures, - std::set& theAlreadyProcessed) -{ - FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); - if (!aFeature.get()) - return; - if (theAlreadyProcessed.find(aFeature) != theAlreadyProcessed.end()) - return; - theAlreadyProcessed.insert(aFeature); - - //convert ignore object list to containt sub-features if the composite feature is in the list - QObjectPtrList aFullIgnoreList; - QObjectPtrList::const_iterator anIIt = theIgnoreList.begin(), anILast = theIgnoreList.end(); - for (; anIIt != anILast; anIIt++) { - aFullIgnoreList.append(*anIIt); - CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(*anIIt); - // if the current feature is aborted, the composite is removed and has invalid data - if (aComposite.get() && aComposite->data()->isValid()) { - int aNbSubs = aComposite->numberOfSubs(); - for (int aSub = 0; aSub < aNbSubs; aSub++) { - aFullIgnoreList.append(aComposite->subFeature(aSub)); - } - } - } - - // 1. find references in the current document - std::set aRefFeatures; - refsToFeatureInFeatureDocument(theObject, aRefFeatures); - std::set::const_iterator anIt = aRefFeatures.begin(), - aLast = aRefFeatures.end(); - for (; anIt != aLast; anIt++) { - // composite feature should not be deleted when the sub feature is to be deleted - if (!isSubOfComposite(theSourceObject, *anIt) && !aFullIgnoreList.contains(*anIt)) - theDirectRefFeatures.insert(*anIt); - } - - // 2. find references in all documents if the document of the feature is - // "PartSet". Features of this document can be used in all other documents - DocumentPtr aFeatureDoc = aFeature->document(); - - SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aModuleDoc = aMgr->moduleDocument(); - if (aFeatureDoc == aModuleDoc) { - // the feature and results of the feature should be found in references - std::list aObjects; - aObjects.push_back(aFeature); - typedef std::list > ResultsList; - const ResultsList& aResults = aFeature->results(); - ResultsList::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - ResultPtr aRes = *aRIter; - if (aRes.get()) - aObjects.push_back(aRes); - } - // get all opened documents; found features in the documents; - // get a list of objects where a feature refers; - // search in these objects the deleted objects. - SessionPtr aMgr = ModelAPI_Session::get(); - std::list anOpenedDocs = aMgr->allOpenedDocuments(); - std::list::const_iterator anIt = anOpenedDocs.begin(), - aLast = anOpenedDocs.end(); - std::list > > aRefs; - for (; anIt != aLast; anIt++) { - DocumentPtr aDocument = *anIt; - if (aDocument == aFeatureDoc) - continue; // this document has been already processed in 1.1 - - int aFeaturesCount = aDocument->size(ModelAPI_Feature::group()); - for (int aId = 0; aId < aFeaturesCount; aId++) { - ObjectPtr anObject = aDocument->object(ModelAPI_Feature::group(), aId); - FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); - if (!aFeature.get()) - continue; - - aRefs.clear(); - aFeature->data()->referencesToObjects(aRefs); - std::list > >::iterator aRef = aRefs.begin(); - bool aHasReferenceToObject = false; - for(; aRef != aRefs.end() && !aHasReferenceToObject; aRef++) { - std::list::iterator aRefObj = aRef->second.begin(); - for(; aRefObj != aRef->second.end() && !aHasReferenceToObject; aRefObj++) { - std::list::const_iterator aObjIt = aObjects.begin(); - for(; aObjIt != aObjects.end() && !aHasReferenceToObject; aObjIt++) { - aHasReferenceToObject = *aObjIt == *aRefObj; - } - } - } - if (aHasReferenceToObject && !isSubOfComposite(theSourceObject, aFeature) && - !theIgnoreList.contains(aFeature)) - theDirectRefFeatures.insert(aFeature); - } - } - } -} - //************************************************************** void refsToFeatureInFeatureDocument(const ObjectPtr& theObject, std::set& theRefFeatures) { @@ -840,49 +702,84 @@ bool isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature) return isSub; } +//************************************************************** +bool isFeatureOfResult(const FeaturePtr& theFeature, const std::string& theGroupOfResult) +{ + bool isResult = false; + + if (!theFeature->data()->isValid()) + return isResult; + + ResultPtr aFirstResult = theFeature->firstResult(); + if (!aFirstResult.get()) + return isResult; + + return aFirstResult->groupName() == theGroupOfResult; +} //************************************************************** -bool isDeleteFeatureWithReferences(const QObjectPtrList& theList, - const std::set& aDirectRefFeatures, - const std::set& aIndirectRefFeatures, - QWidget* theParent, - bool& doDeleteReferences) -{ - doDeleteReferences = true; - - QString aDirectNames, aIndirectNames; - if (!aDirectRefFeatures.empty()) { - QStringList aDirectRefNames; - foreach (const FeaturePtr& aFeature, aDirectRefFeatures) - aDirectRefNames.append(aFeature->name().c_str()); - aDirectNames = aDirectRefNames.join(", "); - - QStringList aIndirectRefNames; - foreach (const FeaturePtr& aFeature, aIndirectRefFeatures) - aIndirectRefNames.append(aFeature->name().c_str()); - aIndirectNames = aIndirectRefNames.join(", "); - } - - bool aCanReplaceParameters = !aDirectRefFeatures.empty(); - QStringList aPartFeatureNames; - foreach (ObjectPtr aObj, theList) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); - // invalid feature data means that the feature is already removed in model, - // we needn't process it. E.g. delete of feature from create operation. The operation abort - // will delete the operation - if (!aFeature->data()->isValid()) - continue; - ResultPtr aFirstResult = aFeature->firstResult(); - if (!aFirstResult.get()) +bool askToDelete(const std::set theFeatures, + const std::map >& theReferences, + QWidget* theParent, + std::set& theReferencesToDelete) +{ + std::set aFeaturesRefsTo; + std::set aFeaturesRefsToParameter; + std::set aParameterFeatures; + std::set::const_iterator anIt = theFeatures.begin(), + aLast = theFeatures.end(); + // separate features to references to parameter features and references to others + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (theReferences.find(aFeature) == theReferences.end()) continue; - std::string aResultGroupName = aFirstResult->groupName(); - if (aResultGroupName == ModelAPI_ResultPart::group()) - aPartFeatureNames.append(aFeature->name().c_str()); - if (aCanReplaceParameters && aResultGroupName != ModelAPI_ResultParameter::group()) - aCanReplaceParameters = false; + std::set aRefFeatures; + std::set aRefList = theReferences.at(aFeature); + std::set::const_iterator aRefIt = aRefList.begin(), aRefLast = aRefList.end(); + for (; aRefIt != aRefLast; aRefIt++) { + FeaturePtr aRefFeature = *aRefIt; + if (theFeatures.find(aRefFeature) == theFeatures.end() && // it is not selected + aRefFeatures.find(aRefFeature) == aRefFeatures.end()) // it is not added + aRefFeatures.insert(aRefFeature); + } + + if (isFeatureOfResult(aFeature, ModelAPI_ResultParameter::group())) { + aFeaturesRefsToParameter.insert(aRefFeatures.begin(), aRefFeatures.end()); + aParameterFeatures.insert(aFeature); + } + else { + theReferencesToDelete.insert(aRefFeatures.begin(), aRefFeatures.end()); + } + } + + std::set aFeaturesRefsToParameterOnly; + anIt = aFeaturesRefsToParameter.begin(); + aLast = aFeaturesRefsToParameter.end(); + // separate features to references to parameter features and references to others + QStringList aParamFeatureNames; + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (theReferencesToDelete.find(aFeature) == theReferencesToDelete.end()) { + aFeaturesRefsToParameterOnly.insert(aFeature); + aParamFeatureNames.append(aFeature->name().c_str()); + } + } + aParamFeatureNames.sort(); + QStringList aPartFeatureNames, anOtherFeatureNames; + anIt = theReferencesToDelete.begin(); + aLast = theReferencesToDelete.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = *anIt; + if (isFeatureOfResult(aFeature, ModelAPI_ResultPart::group())) + aPartFeatureNames.append(aFeature->name().c_str()); + else + anOtherFeatureNames.append(aFeature->name().c_str()); } - QString aPartNames = aPartFeatureNames.join(", "); + aPartFeatureNames.sort(); + anOtherFeatureNames.sort(); + + bool aCanReplaceParameters = !aFeaturesRefsToParameterOnly.empty(); QMessageBox aMessageBox(theParent); aMessageBox.setWindowTitle(QObject::tr("Delete features")); @@ -891,21 +788,17 @@ bool isDeleteFeatureWithReferences(const QObjectPtrList& theList, aMessageBox.setDefaultButton(QMessageBox::No); QString aText; - if (!aDirectNames.isEmpty() || !aIndirectNames.isEmpty()) { - if (aCanReplaceParameters) { - aText = QString(QObject::tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\nOr parameters could be replaced by their values.\n") - .arg(aDirectNames)); - if (!aIndirectNames.isEmpty()) - aText += QString(QObject::tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames); - QPushButton *aReplaceButton = aMessageBox.addButton(QObject::tr("Replace"), QMessageBox::ActionRole); - } else { - aText = QString(QObject::tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n")).arg(aDirectNames); - if (!aIndirectNames.isEmpty()) - aText += QString(QObject::tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames); - } + QString aSep = ", "; + if (!aPartFeatureNames.empty()) + aText += QString(QObject::tr("The following parts will be deleted: %1.\n")).arg(aPartFeatureNames.join(aSep)); + if (!anOtherFeatureNames.empty()) + aText += QString(QObject::tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n")) + .arg(anOtherFeatureNames.join(aSep)); + if (!aParamFeatureNames.empty()) { + aText += QString(QObject::tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\nOr parameters could be replaced by their values.\n")) + .arg(aParamFeatureNames.join(aSep)); + QPushButton *aReplaceButton = aMessageBox.addButton(QObject::tr("Replace"), QMessageBox::ActionRole); } - if (!aPartNames.isEmpty()) - aText += QString(QObject::tr("The following parts will be deleted: %1.\n")).arg(aPartNames); if (!aText.isEmpty()) { aText += "Would you like to continue?"; @@ -917,14 +810,30 @@ bool isDeleteFeatureWithReferences(const QObjectPtrList& theList, return false; if (aButtonRole == QMessageBox::ActionRole) { - foreach (ObjectPtr aObj, theList) + foreach (FeaturePtr aObj, aParameterFeatures) ModelAPI_ReplaceParameterMessage::send(aObj, 0); - doDeleteReferences = false; } + else + theReferencesToDelete.insert(aFeaturesRefsToParameterOnly.begin(), aFeaturesRefsToParameterOnly.end()); } return true; } +//************************************************************** +void convertToFeatures(const QObjectPtrList& theObjects, std::set& theFeatures) +{ + QObjectPtrList::const_iterator anIt = theObjects.begin(), aLast = theObjects.end(); + for(; anIt != aLast; anIt++) { + ObjectPtr anObject = *anIt; + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + // for parameter result, use the corresponded reature to be removed + if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) { + aFeature = ModelAPI_Feature::feature(anObject); + } + theFeatures.insert(aFeature); + } +} + } // namespace ModuleBase_Tools diff --git a/src/ModuleBase/ModuleBase_Tools.h b/src/ModuleBase/ModuleBase_Tools.h index a9b38bd80..d053d279b 100755 --- a/src/ModuleBase/ModuleBase_Tools.h +++ b/src/ModuleBase/ModuleBase_Tools.h @@ -21,6 +21,8 @@ #include +#include + class QWidget; class QLayout; class QDoubleSpinBox; @@ -229,42 +231,6 @@ MODULEBASE_EXPORT void blockUpdateViewer(const bool theValue); MODULEBASE_EXPORT QString wrapTextByWords(const QString& theValue, QWidget* theWidget, int theMaxLineInPixels = 150); -//! Find all referenced features. Return direct and indirect lists of referenced object -//! \param theList an objects to be checked -//! \param aDirectRefFeatures a list of direct reference features -//! \param aIndirectRefFeatures a list of features which depend on the feature through others -MODULEBASE_EXPORT void findReferences(const QObjectPtrList& theList, - std::set& aDirectRefFeatures, - std::set& aIndirectRefFeatures); -/*! - Returns a container of references feature to the source object. The search happens in the object - document and in other Part documents if the object belongs to the PartSet. The search is recursive, - in other words it is applyed to set of the found objects until it is possible. - It do not returns the referenced features to the object if this references is a composite feature - which has the object as a sub object. - \param theSourceObject an object, which references are searched - \param theObject an intermediate recursive object, should be set in the source object - \param theIgnoreList an ignore list, the found referernces which coincide with the objects are ignored - \param theDirectRefFeatures direct references - \param theIndirectRefFeatures indirect references. These are features that refers to the direct features - \param theAlreadyProcessed set of processed elements, used for optimization (do not reanalyse processed) - \return a boolean value - */ -void MODULEBASE_EXPORT refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, - const ObjectPtr& theObject, - const QObjectPtrList& theIgnoreList, - std::set& theDirectRefFeatures, - std::set& theIndirectRefFeatures, - std::set& theAlreadyProcessed); - -/*! -*/ -void MODULEBASE_EXPORT refsDirectToFeatureInAllDocuments(const ObjectPtr& theSourceObject, - const ObjectPtr& theObject, - const QObjectPtrList& theIgnoreList, - std::set& theDirectRefFeatures, - std::set& theAlreadyProcessed); - /*! Returns a container of referenced feature to the current object in the object document. \param theObject an object, which will be casted to a feature type @@ -293,19 +259,28 @@ bool MODULEBASE_EXPORT isSubOfComposite(const ObjectPtr& theObject, const Featur bool MODULEBASE_EXPORT isSubOfComposite(const ObjectPtr& theObject); -//! Shows a dialog box about references. Ask whether they should be also removed. -//! \param theList an objects to be checked -//! \param aDirectRefFeatures a list of direct reference features -//! \param aIndirectRefFeatures a list of features which depend on the feature through others -//! \param theParent a parent widget for the question message box -//! \param doDeleteReferences if there are parameters between features, ask if they should be -//! replaced to their meaning without corresponded features remove -//! \return true if in message box answer is Yes -bool MODULEBASE_EXPORT isDeleteFeatureWithReferences(const QObjectPtrList& theList, - const std::set& aDirectRefFeatures, - const std::set& aIndirectRefFeatures, - QWidget* theParent, - bool& doDeleteReferences); +/*! +* Shows a dialog box about references. Ask whether they should be also removed. +* \param theFeatures a list of features +* \param theReferences a map of all references to the features +* \param theParent a parent widget for the question message box +* \param theReferencesToDelete an out set for references features to be removed +* \return true if in message box answer is Yes +*/ +bool MODULEBASE_EXPORT askToDelete(const std::set aFeatures, + const std::map >& theReferences, + QWidget* theParent, + std::set& theReferencesToDelete); + +/*! +* Converts a list of objects to set of corresponded features. If object is result, it is ingored +* because the feauture only might be removed. But if result is in a parameter group, the feature +* of this parameter is to be removed +* \param theObjects a list of objects +* \param theFeatures an out conteiner of features +*/ +void MODULEBASE_EXPORT convertToFeatures(const QObjectPtrList& theObjects, std::set& theFeatures); + } #endif diff --git a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp index 679d42896..26f185358 100644 --- a/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp +++ b/src/ParametersPlugin/ParametersPlugin_WidgetParamsMgr.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -588,26 +589,16 @@ void ParametersPlugin_WidgetParamsMgr::onRemove() QObjectPtrList anObjects; anObjects.append(aCurFeature); - std::set aDirectRefFeatures, aIndirectRefFeatures; - ModuleBase_Tools::findReferences(anObjects, aDirectRefFeatures, aIndirectRefFeatures); + std::map > aReferences; + std::set aFeatures; + ModuleBase_Tools::convertToFeatures(anObjects, aFeatures); + ModelAPI_Tools::findAllReferences(aFeatures, aReferences); - bool doDeleteReferences = true; - if (ModuleBase_Tools::isDeleteFeatureWithReferences(anObjects, aDirectRefFeatures, - aIndirectRefFeatures, this, doDeleteReferences)) { - - std::set aFeaturesToDelete; - if (doDeleteReferences) { - aFeaturesToDelete = aDirectRefFeatures; - aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); - } - aDoc->removeFeature(aCurFeature); - std::set::const_iterator anIt = aFeaturesToDelete.begin(), - aLast = aFeaturesToDelete.end(); - for (; anIt != aLast; anIt++) { - FeaturePtr aFeature = (*anIt); - DocumentPtr aDoc = aFeature->document(); - aDoc->removeFeature(aFeature); - } + std::set aFeatureRefsToDelete; + if (ModuleBase_Tools::askToDelete(aFeatures, aReferences, this, aFeatureRefsToDelete)) { + if (!aFeatureRefsToDelete.empty()) + aFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end()); + ModelAPI_Tools::removeFeatures(aFeatures, false); Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)); Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)); diff --git a/src/PartSet/PartSet_ExternalObjectsMgr.cpp b/src/PartSet/PartSet_ExternalObjectsMgr.cpp index 54608476b..98bcf3d1c 100755 --- a/src/PartSet/PartSet_ExternalObjectsMgr.cpp +++ b/src/PartSet/PartSet_ExternalObjectsMgr.cpp @@ -78,14 +78,8 @@ void PartSet_ExternalObjectsMgr::removeExternalObject(const ObjectPtr& theObject if (aFeature.get() != NULL) { QObjectPtrList anObjects; anObjects.append(aFeature); - // the external feature should be removed with all references, sketch feature should be ignored - std::set anIgnoredFeatures; - // the current feature should be ignored, because it can use the external feature in the - // attributes and, therefore have a references to it. So, the delete functionality tries - // to delete this feature. Test case is creation of a constraint on external point, - // use in this control after an external point, the point of the sketch. - anIgnoredFeatures.insert(theFeature); - workshop(theWorkshop)->deleteFeatures(anObjects, anIgnoredFeatures); + // the external feature should be removed with all references, composite sketch feature will be ignored + workshop(theWorkshop)->deleteFeatures(anObjects); } } } diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index ab3bca3ca..2c127173d 100755 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -466,10 +466,10 @@ bool PartSet_Module::canDisplayObject(const ObjectPtr& theObject) const return mySketchMgr->canDisplayObject(theObject); } -void PartSet_Module::processHiddenObject(const std::list& theObjects) +/*void PartSet_Module::processHiddenObject(const std::list& theObjects) { mySketchMgr->processHiddenObject(theObjects); -} +}*/ bool PartSet_Module::canActivateSelection(const ObjectPtr& theObject) const { diff --git a/src/PartSet/PartSet_Module.h b/src/PartSet/PartSet_Module.h index eb5e317c2..bca62aaa9 100755 --- a/src/PartSet/PartSet_Module.h +++ b/src/PartSet/PartSet_Module.h @@ -164,7 +164,7 @@ public: /// Make some functionality after the objects are hidden in viewer /// \param theObjects a list of hidden objects - virtual void processHiddenObject(const std::list& theObjects); + //virtual void processHiddenObject(const std::list& theObjects); /// Returns true if selection for the object can be activate. /// For sketch operation allow the selection activation if the operation is edit, for other diff --git a/src/PartSet/PartSet_SketcherMgr.cpp b/src/PartSet/PartSet_SketcherMgr.cpp index c6746b0cd..1a07384b7 100755 --- a/src/PartSet/PartSet_SketcherMgr.cpp +++ b/src/PartSet/PartSet_SketcherMgr.cpp @@ -1212,7 +1212,7 @@ bool PartSet_SketcherMgr::canDisplayConstraint(const FeaturePtr& theFeature, return aSwitchedOn; } -void PartSet_SketcherMgr::processHiddenObject(const std::list& theObjects) +/*void PartSet_SketcherMgr::processHiddenObject(const std::list& theObjects) { ModuleBase_OperationFeature* aFOperation = dynamic_cast (getCurrentOperation()); @@ -1288,7 +1288,7 @@ will be hidden: %1. Would you like to delete them?") } } } -} +}*/ bool PartSet_SketcherMgr::canDisplayCurrentCreatedFeature() const { diff --git a/src/PartSet/PartSet_SketcherMgr.h b/src/PartSet/PartSet_SketcherMgr.h index c739c2852..ed60f1ae1 100644 --- a/src/PartSet/PartSet_SketcherMgr.h +++ b/src/PartSet/PartSet_SketcherMgr.h @@ -190,7 +190,7 @@ public: /// Check the given objects either there are some results of the current sketch. If so, /// it suggests to delete them as there are no functionality to show back hidden sketch objects /// \param theObjects a list of hidden objects - virtual void processHiddenObject(const std::list& theObjects); + //virtual void processHiddenObject(const std::list& theObjects); /// Returns true if the mouse is over viewer or property panel value is changed /// \return boolean result diff --git a/src/PartSet/PartSet_WidgetSketchCreator.cpp b/src/PartSet/PartSet_WidgetSketchCreator.cpp index d42cc1ee0..2f5d4bf7b 100644 --- a/src/PartSet/PartSet_WidgetSketchCreator.cpp +++ b/src/PartSet/PartSet_WidgetSketchCreator.cpp @@ -404,7 +404,7 @@ void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp) anObjects.append(aSketchFeature); XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop()); - aWorkshop->deleteFeatures(anObjects, std::set()); + aWorkshop->deleteFeatures(anObjects); aMgr->finishOperation(); #endif diff --git a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp index fcfd02624..4737cd172 100755 --- a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -106,6 +107,7 @@ void SketchPlugin_MultiRotation::execute() std::list::iterator anInitIter = anInitialList.begin(); std::list::iterator aTargetIter = aTargetList.begin(); std::vector::iterator aUsedIter = isUsed.begin(); + std::set aFeaturesToBeRemoved; for (; aUsedIter != isUsed.end(); aUsedIter++) { if (!(*aUsedIter)) { aRefListOfShapes->remove(*anInitIter); @@ -118,7 +120,8 @@ void SketchPlugin_MultiRotation::execute() DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr(); FeaturePtr aFeature = aDoc ? aDoc->feature(aRC) : FeaturePtr(); if (aFeature) - aDoc->removeFeature(aFeature); + aFeaturesToBeRemoved.insert(aFeature); + //aDoc->removeFeature(aFeature); } } else { for (int i = 0; i <= aNbCopies && aTargetIter != aTargetList.end(); i++) @@ -127,6 +130,7 @@ void SketchPlugin_MultiRotation::execute() if (anInitIter != anInitialList.end()) anInitIter++; } + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved); // change number of copies if (aCurrentNbCopies != 0 && aNbCopies != aCurrentNbCopies) { bool isAdd = aNbCopies > aCurrentNbCopies; @@ -137,6 +141,7 @@ void SketchPlugin_MultiRotation::execute() aTargetList = aRefListOfRotated->list(); aTargetIter = aTargetList.begin(); ObjectPtr anObjToCopy = *aTargetIter; + std::set aFeaturesToBeRemoved; while (aTargetIter != aTargetList.end()) { aRefListOfRotated->remove(*aTargetIter); aTargetIter++; @@ -159,7 +164,8 @@ void SketchPlugin_MultiRotation::execute() DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr(); FeaturePtr aFeature = aDoc ? aDoc->feature(aRC) : FeaturePtr(); if (aFeature) - aDoc->removeFeature(aFeature); + aFeaturesToBeRemoved.insert(aFeature); + //aDoc->removeFeature(aFeature); } ind++; } @@ -168,6 +174,7 @@ void SketchPlugin_MultiRotation::execute() anObjToCopy = *aTargetIter; } } + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved); for (aTargetIter = aTargetList.begin(); aTargetIter != aTargetList.end(); aTargetIter++) aRefListOfRotated->append(*aTargetIter); @@ -331,6 +338,7 @@ void SketchPlugin_MultiRotation::attributeChanged(const std::string& theID) data()->attribute(SketchPlugin_Constraint::ENTITY_B())); std::list aTargetList = aRefListOfRotated->list(); std::list::iterator aTargetIter = aTargetList.begin(); + std::set aFeaturesToBeRemoved; while (aTargetIter != aTargetList.end()) { aTargetIter++; for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) { @@ -341,9 +349,12 @@ void SketchPlugin_MultiRotation::attributeChanged(const std::string& theID) DocumentPtr aDoc = aRC ? aRC->document() : DocumentPtr(); FeaturePtr aFeature = aDoc ? aDoc->feature(aRC) : FeaturePtr(); if (aFeature) - aDoc->removeFeature(aFeature); + aFeaturesToBeRemoved.insert(aFeature); + //aDoc->removeFeature(aFeature); } } + ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved); + aRefListOfRotated->clear(); std::dynamic_pointer_cast( data()->attribute(SketchPlugin_Constraint::ENTITY_A()))->clear(); diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index ec47de524..8e8b92f5f 100755 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -98,8 +98,6 @@ #include -//#define DEBUG_CLEAN_HISTORY - #ifdef _DEBUG #include #include @@ -111,11 +109,11 @@ #include #endif - QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end"); //#define DEBUG_DELETE //#define DEBUG_FEATURE_NAME +//#define DEBUG_CLEAN_HISTORY XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) : QObject(), @@ -1268,12 +1266,11 @@ void XGUI_Workshop::activateObjectsSelection(const QObjectPtrList& theList) myDisplayer->activateObjects(aModes, theList); } - //************************************************************** void XGUI_Workshop::deleteObjects() { ModuleBase_IModule* aModule = module(); - // 1. allow the module to delete objects, do nothing if it has succeed + // allow the module to delete objects, do nothing if it has succeed if (aModule->deleteObjects()) { updateCommandStatus(); return; @@ -1294,32 +1291,34 @@ void XGUI_Workshop::deleteObjects() if (!(hasFeature || hasParameter)) return; - // 3. delete objects - std::set anIgnoredFeatures; - std::set aDirectRefFeatures, aIndirectRefFeatures; - ModuleBase_Tools::findReferences(anObjects, aDirectRefFeatures, aIndirectRefFeatures); - - bool doDeleteReferences = true; - if (ModuleBase_Tools::isDeleteFeatureWithReferences(anObjects, aDirectRefFeatures, - aIndirectRefFeatures, desktop(), doDeleteReferences)) { - // start operation - QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1"; - aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); - ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); - operationMgr()->startOperation(anOpAction); + // delete objects + std::map > aReferences; + std::set aFeatures; + ModuleBase_Tools::convertToFeatures(anObjects, aFeatures); + ModelAPI_Tools::findAllReferences(aFeatures, aReferences); + + bool aDone = false; + QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1"; + aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); + ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); + + operationMgr()->startOperation(anOpAction); + std::set aFeatureRefsToDelete; + if (ModuleBase_Tools::askToDelete(aFeatures, aReferences, desktop(), aFeatureRefsToDelete)) { // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree // It is necessary to clear selection in order to avoid selection changed event during // deletion and negative consequences connected with processing of already deleted items mySelector->clearSelection(); - // delete and commit/abort operation in model - if (deleteFeaturesInternal(anObjects, aDirectRefFeatures, aIndirectRefFeatures, - anIgnoredFeatures, doDeleteReferences)) - operationMgr()->commitOperation(); - else - operationMgr()->abortOperation(operationMgr()->currentOperation()); + if (!aFeatureRefsToDelete.empty()) + aFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end()); + aDone = ModelAPI_Tools::removeFeatures(aFeatures, false); } + if (aDone) + operationMgr()->commitOperation(); + else + operationMgr()->abortOperation(operationMgr()->currentOperation()); } //************************************************************** @@ -1343,24 +1342,6 @@ void addRefsToFeature(const FeaturePtr& theFeature, } } -void printMapInfo(const std::map >& theMainList, - const QString& thePrefix) -{ - std::map >::const_iterator aMainIt = theMainList.begin(), - aMainLast = theMainList.end(); - QStringList aMapInfo; - for (; aMainIt != aMainLast; aMainIt++) { - QStringList anInfo; - FeaturePtr aMainListFeature = aMainIt->first; - std::set aMainRefList = aMainIt->second; - foreach (FeaturePtr aRefFeature, aMainRefList) { - anInfo.append(aRefFeature->name().c_str()); - } - aMapInfo.append(QString("%1: %2\n").arg(aMainListFeature->name().c_str()).arg(anInfo.join(","))); - } - qDebug(QString("%1: %2\n%3").arg(thePrefix).arg(aMapInfo.size()).arg(aMapInfo.join("\n")).toStdString().c_str()); -} - //************************************************************** void XGUI_Workshop::cleanHistory() { @@ -1368,19 +1349,12 @@ void XGUI_Workshop::cleanHistory() return; QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); - QObjectPtrList aFeatures; - foreach (ObjectPtr anObject, anObjects) { - FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); - // for parameter result, use the corresponded reature to be removed - if (!aFeature.get() && anObject->groupName() == ModelAPI_ResultParameter::group()) { - aFeature = ModelAPI_Feature::feature(anObject); - } - aFeatures.append(aFeature); - } + std::set aFeatures; + ModuleBase_Tools::convertToFeatures(anObjects, aFeatures); #ifdef DEBUG_CLEAN_HISTORY - QObjectPtrList::const_iterator aFIt; QStringList anInfo; + std::set::const_iterator aFIt; for (aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) { FeaturePtr aFeature = ModelAPI_Feature::feature(*aFIt); anInfo.append(aFeature->name().c_str()); @@ -1389,56 +1363,8 @@ void XGUI_Workshop::cleanHistory() qDebug(QString("cleanHistory for: [%1] - %2").arg(aFeatures.size()).arg(anInfoStr).toStdString().c_str()); #endif - // For dependencies, find main_list: - // sk_1(ext_1, vertex_1) - // ext_1(bool_1, sk_3) - // vertex_1() - // sk_2(ext_2) - // ext_2(bool_2) - // sk_3() - // Information: bool_1 is not selected - // find all referenced features - std::map > aMainList; - foreach(ObjectPtr anObject, aFeatures) { - FeaturePtr aSelFeature = std::dynamic_pointer_cast(anObject); - /// composite ??? see refsDirectToFeatureInAllDocuments - /// other documents ??? - if (aSelFeature.get()) { - DocumentPtr aSelFeatureDoc = aSelFeature->document(); - std::set aSelRefFeatures; - // 1. find references in the current document - aSelFeatureDoc->refsToFeature(aSelFeature, aSelRefFeatures, false/*do not emit signals*/); - //if (aMainList.find(aSelFeature) != aMainList.end()) - aMainList[aSelFeature] = aSelRefFeatures; - } - } -#ifdef DEBUG_CLEAN_HISTORY - printMapInfo(aMainList, "firstDependencies"); -#endif - // find all dependencies for each object: - // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - // ext_1(bool_1, sk_3) - // vertex_1() - // sk_2(ext_2) + (bool_1) - // ext_2(bool_1) - // sk_3() - std::map > anExtendedMainList; - std::map >::const_iterator aMainIt = aMainList.begin(), - aMainLast = aMainList.end(); - for (; aMainIt != aMainLast; aMainIt++) { - FeaturePtr aMainListFeature = aMainIt->first; - //std::string aName = aMainListFeature->name(); - std::set aMainRefList = aMainIt->second; - std::set anAddRefFeatures; - foreach (FeaturePtr aRefFeature, aMainRefList) { - addRefsToFeature(aRefFeature, aMainList, aMainRefList); - } - anExtendedMainList[aMainListFeature] = aMainRefList; - } - -#ifdef DEBUG_CLEAN_HISTORY - printMapInfo(anExtendedMainList, "allDependencies"); -#endif + std::map > aReferences; + ModelAPI_Tools::findAllReferences(aFeatures, aReferences, true, false); // find for each object whether all reference values are in the map as key, that means that there is // no other reference in the model to this object, so it might be removed by cleaning history // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - cann't be deleted, dependency to bool_1 @@ -1448,8 +1374,9 @@ void XGUI_Workshop::cleanHistory() // ext_2(bool_1) - cann't be deleted, dependency to bool_1 // sk_3() // Information: bool_1 is not selected - QList anUnusedObjects; - aMainIt = anExtendedMainList.begin(), aMainLast = anExtendedMainList.end(); + std::set anUnusedObjects; + std::map >::const_iterator aMainIt = aReferences.begin(), + aMainLast = aReferences.end(); for (; aMainIt != aMainLast; aMainIt++) { FeaturePtr aMainListFeature = aMainIt->first; std::set aMainRefList = aMainIt->second; @@ -1457,16 +1384,16 @@ void XGUI_Workshop::cleanHistory() bool aFeatureOutOfTheList = false; for (; aRefIt != aRefLast && !aFeatureOutOfTheList; aRefIt++) { FeaturePtr aRefFeature = *aRefIt; - aFeatureOutOfTheList = anExtendedMainList.find(aRefFeature) == anExtendedMainList.end(); + aFeatureOutOfTheList = aReferences.find(aRefFeature) == aReferences.end(); } if (!aFeatureOutOfTheList) - anUnusedObjects.append(aMainListFeature); + anUnusedObjects.insert(aMainListFeature); } #ifdef DEBUG_CLEAN_HISTORY anInfo.clear(); for (aFIt = anUnusedObjects.begin(); aFIt != anUnusedObjects.end(); ++aFIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*aFIt); + FeaturePtr aFeature = *aFIt; anInfo.append(aFeature->name().c_str()); } qDebug(QString("unused objects: [%1] - %2").arg(anInfo.size()).arg(anInfo.join(";\t")).toStdString().c_str()); @@ -1475,10 +1402,10 @@ void XGUI_Workshop::cleanHistory() // warn about the references remove, break the delete operation if the user chose it if (!anUnusedObjects.empty()) { QStringList aNames; - foreach (const ObjectPtr& anObject, anUnusedObjects) { - FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + foreach (const FeaturePtr& aFeature, anUnusedObjects) { aNames.append(aFeature->name().c_str()); } + aNames.sort(); QString anUnusedNames = aNames.join(", "); QString anActionId = "CLEAN_HISTORY_CMD"; @@ -1507,7 +1434,7 @@ void XGUI_Workshop::cleanHistory() mySelector->clearSelection(); std::set anIgnoredFeatures; - if (removeFeatures(anUnusedObjects, anIgnoredFeatures, anActionId, true)) { + if (ModelAPI_Tools::removeFeatures(anUnusedObjects, true)) { operationMgr()->commitOperation(); } else { @@ -1572,107 +1499,13 @@ void XGUI_Workshop::moveObjects() } //************************************************************** -bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theFeatures, - const std::set& theIgnoredFeatures) -{ - std::set aDirectRefFeatures, aIndirectRefFeatures; - ModuleBase_Tools::findReferences(theFeatures, aDirectRefFeatures, aIndirectRefFeatures); - return deleteFeaturesInternal(theFeatures, aDirectRefFeatures, aIndirectRefFeatures, - theIgnoredFeatures); -} - -bool XGUI_Workshop::deleteFeaturesInternal(const QObjectPtrList& theList, - const std::set& aDirectRefFeatures, - const std::set& aIndirectRefFeatures, - const std::set& theIgnoredFeatures, - const bool doDeleteReferences) -{ - bool isDone = false; - if (doDeleteReferences) { - std::set aFeaturesToDelete = aDirectRefFeatures; - aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); - std::set::const_iterator anIt = aFeaturesToDelete.begin(), - aLast = aFeaturesToDelete.end(); -#ifdef DEBUG_DELETE - QStringList anInfo; -#endif - for (; anIt != aLast; anIt++) { - FeaturePtr aFeature = (*anIt); - DocumentPtr aDoc = aFeature->document(); - if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { - // flush REDISPLAY signal after remove feature - aDoc->removeFeature(aFeature); - isDone = true; -#ifdef DEBUG_DELETE - anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str()); -#endif - } - } -#ifdef DEBUG_DELETE - qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str()); - anInfo.clear(); -#endif - } - - QString anActionId = "DELETE_CMD"; - isDone = removeFeatures(theList, theIgnoredFeatures, anActionId, false) || isDone; - - if (isDone) { - // the redisplay signal should be flushed in order to erase the feature presentation in the viewer - // if should be done after removeFeature() of document - Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)); - } - return isDone; -} - -//************************************************************** -bool XGUI_Workshop::removeFeatures(const QObjectPtrList& theList, - const std::set& theIgnoredFeatures, - const QString& theActionId, - const bool theFlushRedisplay) +bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theObjects) { - bool isDone = false; - - QString anId = QString::fromStdString(theActionId.toStdString().c_str()); - QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId); - // 4. remove the parameter features - foreach (ObjectPtr aObj, theList) { - // features and parameters can be removed here, - // the results are removed only by a corresponded feature remove - std::string aGroupName = aObj->groupName(); - if (!anObjectGroups.contains(aGroupName.c_str())) - continue; - - FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); - if (aFeature) { - /*// TODO: to learn the workshop to delegate the Part object deletion to the PartSet module - // part features are removed in the PartSet module. This condition should be moved there - if (aFeature->getKind() == "Part") - continue; - */ - DocumentPtr aDoc = aObj->document(); - if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { -#ifdef DEBUG_DELETE - QString anInfoStr = ModuleBase_Tools::objectInfo(aFeature); - anInfo.append(anInfoStr); - qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str()); -#endif - // flush REDISPLAY signal after remove feature - aDoc->removeFeature(aFeature); - isDone = true; - } - } - } - if (isDone && theFlushRedisplay) { - // the redisplay signal should be flushed in order to erase the feature presentation in the viewer - // if should be done after removeFeature() of document - Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)); - } + std::map > aReferences; + std::set aFeatures; + ModuleBase_Tools::convertToFeatures(theObjects, aFeatures); -#ifdef DEBUG_DELETE - qDebug(QString("remove features:%1").arg(anInfo.join("; ")).toStdString().c_str()); -#endif - return true; + return ModelAPI_Tools::removeFeaturesAndReferences(aFeatures); } bool hasResults(QObjectPtrList theObjects, const std::set& theTypes) diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index 74269e898..c969da8c0 100755 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -249,9 +249,7 @@ Q_OBJECT //! Delete features. Delete the referenced features. There can be a question with a list of //! referenced objects. //! \param theFeatures a list of objects to be deleted - //! \param theIgnoredFeatures a list of features to be ignored during delete - bool deleteFeatures(const QObjectPtrList& theFeatures, - const std::set& theIgnoredFeatures = std::set()); + bool deleteFeatures(const QObjectPtrList& theFeatures); /// Deactivates the object, if it is active and the module returns that the activation /// of selection for the object is not possible currently(the current operation uses it) @@ -391,17 +389,6 @@ signals: /// \param theOperation an operation void setGrantedFeatures(ModuleBase_Operation* theOperation); - //! \param theIgnoredFeatures a list of features to be ignored during delete - //! \param theList an objects to be checked - //! \param aDirectRefFeatures a list of direct reference features - //! \param aIndirectRefFeatures a list of features which depend on the feature through others - //! \param doDeleteReferences flag if referenced features should be removed also - bool deleteFeaturesInternal(const QObjectPtrList& theList, - const std::set& aDirectRefFeatures, - const std::set& aIndirectRefFeatures, - const std::set& theIgnoredFeatures, - const bool doDeleteReferences = true); - private: /// Display all results //void displayAllResults(); @@ -485,17 +472,6 @@ private: //! \param theSlot - onUndo(int) or onRedo(int) SLOT void addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot); - - /// Calls removeFeature of the document for each object in the list - //! \param theList an objects to be deleted - //! \param theIgnoredFeatures a list of features to be ignored during delete - //! \param theActionId an action command key to find context menu object types enabled for remove - //! \param theFlushRedisplay a boolean value if the redisplay signal should be flushed - bool removeFeatures(const QObjectPtrList& theList, - const std::set& theIgnoredFeatures, - const QString& theActionId, - const bool theFlushRedisplay); - //! Creates list of actions (commands) by given history list from session QList processHistoryList(const std::list&) const; -- 2.39.2