Salome HOME
updated copyright message
[modules/shaper.git] / src / ExchangePlugin / ExchangePlugin_ExportPart.cpp
1 // Copyright (C) 2014-2023  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <ExchangePlugin_ExportPart.h>
21
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>
27
28 #include <ConstructionPlugin_Axis.h>
29 #include <ConstructionPlugin_Plane.h>
30 #include <ConstructionPlugin_Point.h>
31
32 #include <Events_InfoMessage.h>
33
34 #include <PartSetPlugin_Part.h>
35
36 #include <sstream>
37
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);
54
55
56 ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
57 {
58 }
59
60 void ExchangePlugin_ExportPart::initAttributes()
61 {
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());
67 }
68
69 void ExchangePlugin_ExportPart::execute()
70 {
71   AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
72   std::string aFilename = aFilePathAttr->value();
73   if (aFilename.empty()) {
74     setError("File name is empty.");
75     return;
76   }
77
78   std::list<FeaturePtr> aFeaturesToExport;
79
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);
88   }
89   else
90     collectFeatures(anExportDoc, aSelected, aFeaturesToExport);
91
92   if (aFeaturesToExport.empty()) {
93     Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send();
94     return;
95   }
96
97   // remove 'ExportPart' feature if any
98   if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
99     aFeaturesToExport.pop_back();
100
101   std::list<FeaturePtr> anExternalLinks, anExportedParts, aReferredParts;
102   if (!verifyExport(aFeaturesToExport, anExternalLinks, anExportedParts, aReferredParts)) {
103     if (!anExternalLinks.empty()) {
104       std::wstring aListOfFeatures = namesOfFeatures(anExternalLinks);
105
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();
111     }
112     if (!aReferredParts.empty()) {
113       std::wstring aListOfParts = namesOfFeatures(aReferredParts);
114
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();
119     }
120     if (!anExportedParts.empty()) {
121       std::wstring aListOfParts = namesOfFeatures(anExportedParts);
122
123       std::string aMessage = "The export of Part's result is forbidden (%1).";
124       Events_InfoMessage(getKind(), aMessage).arg(aListOfParts).send();
125     }
126     // should not export anything
127     aFeaturesToExport.clear();
128   }
129
130   if (!aFeaturesToExport.empty()) {
131     // save the document
132     if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport))
133       setError("Cannot save the document.");
134   }
135 }
136
137
138 // ================================     Auxiliary functions     ===================================
139
140 static bool isCoordinate(FeaturePtr theFeature)
141 {
142   return !theFeature->isInHistory() &&
143           (theFeature->getKind() == ConstructionPlugin_Point::ID() ||
144            theFeature->getKind() == ConstructionPlugin_Axis::ID() ||
145            theFeature->getKind() == ConstructionPlugin_Plane::ID());
146 }
147
148 static void allReferencedFeatures(const std::set<FeaturePtr>& theFeatures,
149                                   std::set<FeaturePtr>& theReferencedFeatures)
150 {
151   std::set<FeaturePtr> aReferences;
152   for (std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin();
153        anIt != theFeatures.end(); ++anIt) {
154     theReferencedFeatures.insert(*anIt);
155
156     std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
157     (*anIt)->data()->referencesToObjects(aRefs);
158
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);
167       }
168     }
169   }
170
171   if (!aReferences.empty())
172     allReferencedFeatures(aReferences, theReferencedFeatures);
173 }
174
175 void collectFeatures(DocumentPtr theDocument,
176                      AttributeSelectionListPtr theSelected,
177                      std::list<FeaturePtr>& theExport)
178 {
179   theExport = theDocument->allFeatures();
180
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());
187       break;
188     }
189
190   if (!theSelected || theSelected->size() == 0) {
191     // nothing is selected, return all features of the document
192     return;
193   }
194
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());
200     if (aCurFeature)
201       aFeaturesToExport.insert(aCurFeature);
202   }
203   // recursively collect all features used for the selected results
204   allReferencedFeatures(aFeaturesToExport, aFeaturesToExport);
205
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);
212     }
213     else
214       ++anIt;
215   }
216 }
217
218 void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport)
219 {
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();
226
227     bool isApplicable =
228         (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) &&
229         !isCoordinate(aCurFeature);
230
231     if (isApplicable)
232       ++anIt;
233     else {
234       std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
235       theExport.erase(aRemoveIt);
236     }
237   }
238 }
239
240 bool verifyExport(const std::list<FeaturePtr>& theFeatures,
241                   std::list<FeaturePtr>& theExternalReferences,
242                   std::list<FeaturePtr>& theExportedParts,
243                   std::list<FeaturePtr>& theReferredParts)
244 {
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);
250
251     DocumentPtr aDoc = (*anIt)->document();
252
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);
260         if (aFeature) {
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);
268         }
269       }
270     }
271   }
272
273   return theExternalReferences.empty() && theExportedParts.empty() && theReferredParts.empty();
274 }
275
276 std::wstring namesOfFeatures(const std::list<FeaturePtr>& theFeatures)
277 {
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() << "'";
284   }
285   return aListOfFeatures.str();
286 }