From 3ee6dd7ba9733f4374c1cf370d7a0ee0847659d5 Mon Sep 17 00:00:00 2001 From: azv Date: Wed, 13 Nov 2019 14:59:24 +0300 Subject: [PATCH] Task 5.1.7: To be able to export a part to a file and import it into an existing part (issue #3065) * Verify the list of features before export for referring to external document * Add translations for messages produced by ExportPart/ImportPart features --- .../ExchangePlugin_ExportPart.cpp | 155 ++++++++++++++---- .../ExchangePlugin_ImportPart.cpp | 4 +- src/ExchangePlugin/ExchangePlugin_msg_en.ts | 28 ++++ src/Model/Model_AttributeSelection.cpp | 2 +- 4 files changed, 157 insertions(+), 32 deletions(-) diff --git a/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp index 626f835e8..cc4af14c6 100644 --- a/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp +++ b/src/ExchangePlugin/ExchangePlugin_ExportPart.cpp @@ -29,11 +29,25 @@ #include #include +#include + +#include + +#include + // Obtain all features to be exported to get the list of selected results. -static void collectFeatures(AttributeSelectionListPtr theSelected, +static void collectFeatures(DocumentPtr theDocument, + AttributeSelectionListPtr theSelected, std::list& theExport); // Obtain all constuction elements of the document. static void collectConstructions(DocumentPtr theDocument, std::list& theExport); +// Check features could be exported. The following features cannot be exported: +// * non-construction result (Part) when exporting the PartSet; +// * features, which refer to objects from another document. +// Returns true if all features can be exported. +static bool verifyExport(const std::list& theFeatures, + std::list& theExternalReferences, + std::list& theExportedParts); ExchangePlugin_ExportPart::ExchangePlugin_ExportPart() @@ -54,31 +68,73 @@ void ExchangePlugin_ExportPart::execute() AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID()); std::string aFilename = aFilePathAttr->value(); if (aFilename.empty()) { - setError("File path is empty."); + setError("File name is empty."); return; } std::list aFeaturesToExport; - SessionPtr aSession = ModelAPI_Session::get(); + DocumentPtr anExportDoc = document(); + DocumentPtr aPartSetDoc = ModelAPI_Session::get()->moduleDocument(); AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID()); - DocumentPtr anExportDoc; - if (aSelected && aSelected->size() == 0 && - aSession->activeDocument() == aSession->moduleDocument()) { + if (aSelected && aSelected->size() == 0 && anExportDoc == aPartSetDoc) { // no result is selected, thus have to export all features of the current document, // but the document is a PartSet; and it is forbidden to copy results of Parts, // thus copy construction elements only - collectConstructions(aSession->moduleDocument(), aFeaturesToExport); + collectConstructions(anExportDoc, aFeaturesToExport); } else - collectFeatures(aSelected, aFeaturesToExport); + collectFeatures(anExportDoc, aSelected, aFeaturesToExport); + + if (aFeaturesToExport.empty()) { + Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send(); + return; + } + + // remove 'ExportPart' feature if any + if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID()) + aFeaturesToExport.pop_back(); + + std::list anExternalLinks, aReferredParts; + if (!verifyExport(aFeaturesToExport, anExternalLinks, aReferredParts)) { + if (!anExternalLinks.empty()) { + // collect names of features as a string + std::ostringstream aListOfFeatures; + for (std::list::iterator anIt = anExternalLinks.begin(); + anIt != anExternalLinks.end(); ++anIt) { + if (anIt != anExternalLinks.begin()) + aListOfFeatures << ", "; + aListOfFeatures << "'" << (*anIt)->name() << "'"; + } + + std::string aMessage = "The selected results were created using external references " + "outside of this Part from features %1. " + "Please, remove these references or select another " + "sub-set of results to be able to export."; + Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures.str()).send(); + } + if (!aReferredParts.empty()) { + // collect names of parts as a string + std::ostringstream aListOfParts; + for (std::list::iterator anIt = aReferredParts.begin(); + anIt != aReferredParts.end(); ++anIt) { + if (anIt != aReferredParts.begin()) + aListOfParts << ", "; + aListOfParts << "'" << (*anIt)->name() << "'"; + } + + std::string aMessage = "The selected results were created using references " + "to results of Parts %1. Please, remove these references " + "or select another sub-set of results to be able to export."; + Events_InfoMessage(getKind(), aMessage).arg(aListOfParts.str()).send(); + } + // should not export anything + aFeaturesToExport.clear(); + } if (!aFeaturesToExport.empty()) { - // remove 'ExportPart' feature is any - if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID()) - aFeaturesToExport.pop_back(); // save the document - if (!aSession->activeDocument()->save(aFilename.c_str(), aFeaturesToExport)) + if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport)) setError("Cannot save the document."); } } @@ -86,11 +142,14 @@ void ExchangePlugin_ExportPart::execute() // ================================ Auxiliary functions =================================== -static void allReferencedFeatures(std::set& theFeatures) +static void allReferencedFeatures(const std::set& theFeatures, + std::set& theReferencedFeatures) { std::set aReferences; - for (std::set::iterator anIt = theFeatures.begin(); + for (std::set::const_iterator anIt = theFeatures.begin(); anIt != theFeatures.end(); ++anIt) { + theReferencedFeatures.insert(*anIt); + std::list > > aRefs; (*anIt)->data()->referencesToObjects(aRefs); @@ -99,21 +158,29 @@ static void allReferencedFeatures(std::set& theFeatures) for (std::list::iterator anObjIt = aRIt->second.begin(); anObjIt != aRIt->second.end(); ++anObjIt) { FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt); - if (aFeature) + if (aFeature && theReferencedFeatures.find(aFeature) == theReferencedFeatures.end()) aReferences.insert(aFeature); } } } - if (!aReferences.empty()) { - allReferencedFeatures(aReferences); - theFeatures.insert(aReferences.begin(), aReferences.end()); - } + if (!aReferences.empty()) + allReferencedFeatures(aReferences, theReferencedFeatures); +} + +static bool isCoordinate(FeaturePtr theFeature) +{ + return !theFeature->isInHistory() && + (theFeature->getKind() == ConstructionPlugin_Point::ID() || + theFeature->getKind() == ConstructionPlugin_Axis::ID() || + theFeature->getKind() == ConstructionPlugin_Plane::ID()); } -void collectFeatures(AttributeSelectionListPtr theSelected, std::list& theExport) +void collectFeatures(DocumentPtr theDocument, + AttributeSelectionListPtr theSelected, + std::list& theExport) { - theExport = ModelAPI_Session::get()->activeDocument()->allFeatures(); + theExport = theDocument->allFeatures(); if (!theSelected || theSelected->size() == 0) { // nothing is selected, return all features of the document @@ -129,7 +196,7 @@ void collectFeatures(AttributeSelectionListPtr theSelected, std::list::iterator anIt = theExport.begin(); @@ -153,13 +220,8 @@ void collectConstructions(DocumentPtr theDocument, std::list& theExp ResultPtr aCurResult = aCurFeature->lastResult(); bool isApplicable = - (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()); - - if (isApplicable && !aCurFeature->isInHistory()) { - isApplicable = aCurFeature->getKind() != ConstructionPlugin_Point::ID() && - aCurFeature->getKind() != ConstructionPlugin_Axis::ID() && - aCurFeature->getKind() != ConstructionPlugin_Plane::ID(); - } + (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) && + !isCoordinate(aCurFeature); if (isApplicable) ++anIt; @@ -169,3 +231,38 @@ void collectConstructions(DocumentPtr theDocument, std::list& theExp } } } + +bool verifyExport(const std::list& theFeatures, + std::list& theExternalReferences, + std::list& theExportedParts) +{ + for (std::list::const_iterator anIt = theFeatures.begin(); + anIt != theFeatures.end(); ++anIt) { + // full part should not be exported + if ((*anIt)->getKind() == PartSetPlugin_Part::ID()) + theExportedParts.push_back(*anIt); + + DocumentPtr aDoc = (*anIt)->document(); + + std::list > > aRefs; + (*anIt)->data()->referencesToObjects(aRefs); + std::list > >::iterator aRIt = aRefs.begin(); + for (; aRIt != aRefs.end(); ++aRIt) { + for (std::list::iterator anObjIt = aRIt->second.begin(); + anObjIt != aRIt->second.end(); ++anObjIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt); + if (aFeature) { + // feature refers to external entity, + // which is neither the Origin nor coordinate axis or plane + if (aFeature->document() != aDoc && !isCoordinate(aFeature)) + theExternalReferences.push_back(*anIt); + // feature refers to result of a part + if (aFeature->getKind() == PartSetPlugin_Part::ID()) + theExportedParts.push_back(*anIt); + } + } + } + } + + return theExternalReferences.empty() && theExportedParts.empty(); +} diff --git a/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp b/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp index 11eae6c0d..9522e20bc 100644 --- a/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp +++ b/src/ExchangePlugin/ExchangePlugin_ImportPart.cpp @@ -39,13 +39,13 @@ void ExchangePlugin_ImportPart::execute() AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID()); std::string aFilename = aFilePathAttr->value(); if (aFilename.empty()) { - setError("File path is empty."); + setError("File name is empty."); return; } // load the file into the active document SessionPtr aSession = ModelAPI_Session::get(); - DocumentPtr aDoc = aSession->activeDocument(); + DocumentPtr aDoc = document(); bool isPartSet = aDoc == aSession->moduleDocument(); bool isOk = aDoc->import(aFilename.c_str(), isPartSet); if (!isOk && isPartSet) { diff --git a/src/ExchangePlugin/ExchangePlugin_msg_en.ts b/src/ExchangePlugin/ExchangePlugin_msg_en.ts index 774af05d1..992e2357b 100644 --- a/src/ExchangePlugin/ExchangePlugin_msg_en.ts +++ b/src/ExchangePlugin/ExchangePlugin_msg_en.ts @@ -91,4 +91,32 @@ Attribute %1 is not a string. + + + Export:ExchangePlugin_ExportPart + + Cannot save the document. + Cannot save the document. + + + Selected features cannot be exported from the document. + Selected features cannot be exported from the document. + + + The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export. + The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export. + + + The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export. + The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export. + + + + + Import:ExchangePlugin_ImportPart + + Cannot import the document. + Cannot import the document. + + diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index c37149ede..edec79b6c 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -302,7 +302,7 @@ GeomShapePtr centerByEdge(GeomShapePtr theEdge, ModelAPI_AttributeSelection::Cen std::shared_ptr Model_AttributeSelection::value() { - if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) + if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get()) return std::shared_ptr(); CenterType aType = NOT_CENTER; std::shared_ptr aResult = internalValue(aType); -- 2.39.2