1 // Copyright (C) 2014-2022 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <ExchangePlugin_ExportPart.h>
22 #include <ModelAPI_AttributeSelectionList.h>
23 #include <ModelAPI_AttributeString.h>
24 #include <ModelAPI_ResultConstruction.h>
25 #include <ModelAPI_Session.h>
26 #include <ModelAPI_Validator.h>
28 #include <ConstructionPlugin_Axis.h>
29 #include <ConstructionPlugin_Plane.h>
30 #include <ConstructionPlugin_Point.h>
32 #include <Events_InfoMessage.h>
34 #include <PartSetPlugin_Part.h>
38 // Obtain all features to be exported to get the list of selected results.
39 static void collectFeatures(DocumentPtr theDocument,
40 AttributeSelectionListPtr theSelected,
41 std::list<FeaturePtr>& theExport);
42 // Obtain all constuction elements of the document.
43 static void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport);
44 // Check features could be exported. The following features cannot be exported:
45 // * non-construction result (Part) when exporting the PartSet;
46 // * features, which refer to objects from another document.
47 // Returns true if all features can be exported.
48 static bool verifyExport(const std::list<FeaturePtr>& theFeatures,
49 std::list<FeaturePtr>& theExternalReferences,
50 std::list<FeaturePtr>& theExportedParts,
51 std::list<FeaturePtr>& theReferredParts);
52 // Collect names of features as a single string
53 static std::wstring namesOfFeatures(const std::list<FeaturePtr>& theFeatures);
56 ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
60 void ExchangePlugin_ExportPart::initAttributes()
62 data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
63 data()->addAttribute(FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId());
64 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FILE_FORMAT_ID());
65 data()->addAttribute(SELECTION_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
66 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SELECTION_LIST_ID());
69 void ExchangePlugin_ExportPart::execute()
71 AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
72 std::string aFilename = aFilePathAttr->value();
73 if (aFilename.empty()) {
74 setError("File name is empty.");
78 std::list<FeaturePtr> aFeaturesToExport;
80 DocumentPtr anExportDoc = document();
81 DocumentPtr aPartSetDoc = ModelAPI_Session::get()->moduleDocument();
82 AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID());
83 if (aSelected && aSelected->size() == 0 && anExportDoc == aPartSetDoc) {
84 // no result is selected, thus have to export all features of the current document,
85 // but the document is a PartSet; and it is forbidden to copy results of Parts,
86 // thus copy construction elements only
87 collectConstructions(anExportDoc, aFeaturesToExport);
90 collectFeatures(anExportDoc, aSelected, aFeaturesToExport);
92 if (aFeaturesToExport.empty()) {
93 Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send();
97 // remove 'ExportPart' feature if any
98 if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
99 aFeaturesToExport.pop_back();
101 std::list<FeaturePtr> anExternalLinks, anExportedParts, aReferredParts;
102 if (!verifyExport(aFeaturesToExport, anExternalLinks, anExportedParts, aReferredParts)) {
103 if (!anExternalLinks.empty()) {
104 std::wstring aListOfFeatures = namesOfFeatures(anExternalLinks);
106 std::string aMessage = "The selected results were created using external references "
107 "outside of this Part from features %1. "
108 "Please, remove these references or select another "
109 "sub-set of results to be able to export.";
110 Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures).send();
112 if (!aReferredParts.empty()) {
113 std::wstring aListOfParts = namesOfFeatures(aReferredParts);
115 std::string aMessage = "The selected results were created using references "
116 "to the results of Parts: %1. Please, remove these references "
117 "or select another sub-set of results to be able to export.";
118 Events_InfoMessage(getKind(), aMessage).arg(aListOfParts).send();
120 if (!anExportedParts.empty()) {
121 std::wstring aListOfParts = namesOfFeatures(anExportedParts);
123 std::string aMessage = "The export of Part's result is forbidden (%1).";
124 Events_InfoMessage(getKind(), aMessage).arg(aListOfParts).send();
126 // should not export anything
127 aFeaturesToExport.clear();
130 if (!aFeaturesToExport.empty()) {
132 if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport))
133 setError("Cannot save the document.");
138 // ================================ Auxiliary functions ===================================
140 static bool isCoordinate(FeaturePtr theFeature)
142 return !theFeature->isInHistory() &&
143 (theFeature->getKind() == ConstructionPlugin_Point::ID() ||
144 theFeature->getKind() == ConstructionPlugin_Axis::ID() ||
145 theFeature->getKind() == ConstructionPlugin_Plane::ID());
148 static void allReferencedFeatures(const std::set<FeaturePtr>& theFeatures,
149 std::set<FeaturePtr>& theReferencedFeatures)
151 std::set<FeaturePtr> aReferences;
152 for (std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin();
153 anIt != theFeatures.end(); ++anIt) {
154 theReferencedFeatures.insert(*anIt);
156 std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
157 (*anIt)->data()->referencesToObjects(aRefs);
159 for (std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
160 aRIt != aRefs.end(); ++aRIt) {
161 for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
162 anObjIt != aRIt->second.end(); ++anObjIt) {
163 FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
164 if (aFeature && !isCoordinate(aFeature) &&
165 theReferencedFeatures.find(aFeature) == theReferencedFeatures.end())
166 aReferences.insert(aFeature);
171 if (!aReferences.empty())
172 allReferencedFeatures(aReferences, theReferencedFeatures);
175 void collectFeatures(DocumentPtr theDocument,
176 AttributeSelectionListPtr theSelected,
177 std::list<FeaturePtr>& theExport)
179 theExport = theDocument->allFeatures();
181 // remove all features after the current one
182 FeaturePtr aCurrentFeature = theDocument->currentFeature(false);
183 std::list<FeaturePtr>::iterator anIt = theExport.begin();
184 for (; anIt != theExport.end(); ++anIt)
185 if (*anIt == aCurrentFeature) {
186 theExport.erase(++anIt, theExport.end());
190 if (!theSelected || theSelected->size() == 0) {
191 // nothing is selected, return all features of the document
195 // collect initial list of features basing on the selected results
196 std::set<FeaturePtr> aFeaturesToExport;
197 for (int anIndex = 0, aSize = theSelected->size(); anIndex < aSize; ++anIndex) {
198 AttributeSelectionPtr aCurrent = theSelected->value(anIndex);
199 FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurrent->context());
201 aFeaturesToExport.insert(aCurFeature);
203 // recursively collect all features used for the selected results
204 allReferencedFeatures(aFeaturesToExport, aFeaturesToExport);
206 // remove the features which are not affect the selected results
207 anIt = theExport.begin();
208 while (anIt != theExport.end()) {
209 if (aFeaturesToExport.find(*anIt) == aFeaturesToExport.end()) {
210 std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
211 theExport.erase(aRemoveIt);
218 void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport)
220 theExport = theDocument->allFeatures();
221 // keep constructions only
222 std::list<FeaturePtr>::iterator anIt = theExport.begin();
223 while (anIt != theExport.end()) {
224 FeaturePtr aCurFeature = *anIt;
225 ResultPtr aCurResult = aCurFeature->lastResult();
228 (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) &&
229 !isCoordinate(aCurFeature);
234 std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
235 theExport.erase(aRemoveIt);
240 bool verifyExport(const std::list<FeaturePtr>& theFeatures,
241 std::list<FeaturePtr>& theExternalReferences,
242 std::list<FeaturePtr>& theExportedParts,
243 std::list<FeaturePtr>& theReferredParts)
245 for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
246 anIt != theFeatures.end(); ++anIt) {
247 // full part should not be exported
248 if ((*anIt)->getKind() == PartSetPlugin_Part::ID())
249 theExportedParts.push_back(*anIt);
251 DocumentPtr aDoc = (*anIt)->document();
253 std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
254 (*anIt)->data()->referencesToObjects(aRefs);
255 std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
256 for (; aRIt != aRefs.end(); ++aRIt) {
257 for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
258 anObjIt != aRIt->second.end(); ++anObjIt) {
259 FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
261 // feature refers to external entity,
262 // which is neither the Origin nor coordinate axis or plane
263 if (aFeature->document() != aDoc && !isCoordinate(aFeature))
264 theExternalReferences.push_back(*anIt);
265 // feature refers to result of a part
266 if (aFeature->getKind() == PartSetPlugin_Part::ID())
267 theReferredParts.push_back(*anIt);
273 return theExternalReferences.empty() && theExportedParts.empty() && theReferredParts.empty();
276 std::wstring namesOfFeatures(const std::list<FeaturePtr>& theFeatures)
278 std::wostringstream aListOfFeatures;
279 for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
280 anIt != theFeatures.end(); ++anIt) {
281 if (anIt != theFeatures.begin())
282 aListOfFeatures << ", ";
283 aListOfFeatures << "'" << (*anIt)->name() << "'";
285 return aListOfFeatures.str();