]> SALOME platform Git repositories - modules/shaper.git/blob - src/ExchangePlugin/ExchangePlugin_ExportPart.cpp
Salome HOME
Merge branch 'V9_4_BR'
[modules/shaper.git] / src / ExchangePlugin / ExchangePlugin_ExportPart.cpp
1 // Copyright (C) 2014-2019  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
52
53 ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
54 {
55 }
56
57 void ExchangePlugin_ExportPart::initAttributes()
58 {
59   data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
60   data()->addAttribute(FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId());
61   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FILE_FORMAT_ID());
62   data()->addAttribute(SELECTION_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
63   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SELECTION_LIST_ID());
64 }
65
66 void ExchangePlugin_ExportPart::execute()
67 {
68   AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
69   std::string aFilename = aFilePathAttr->value();
70   if (aFilename.empty()) {
71     setError("File name is empty.");
72     return;
73   }
74
75   std::list<FeaturePtr> aFeaturesToExport;
76
77   DocumentPtr anExportDoc = document();
78   DocumentPtr aPartSetDoc = ModelAPI_Session::get()->moduleDocument();
79   AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID());
80   if (aSelected && aSelected->size() == 0 && anExportDoc == aPartSetDoc) {
81     // no result is selected, thus have to export all features of the current document,
82     // but the document is a PartSet; and it is forbidden to copy results of Parts,
83     // thus copy construction elements only
84     collectConstructions(anExportDoc, aFeaturesToExport);
85   }
86   else
87     collectFeatures(anExportDoc, aSelected, aFeaturesToExport);
88
89   if (aFeaturesToExport.empty()) {
90     Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send();
91     return;
92   }
93
94   // remove 'ExportPart' feature if any
95   if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
96     aFeaturesToExport.pop_back();
97
98   std::list<FeaturePtr> anExternalLinks, aReferredParts;
99   if (!verifyExport(aFeaturesToExport, anExternalLinks, aReferredParts)) {
100     if (!anExternalLinks.empty()) {
101       // collect names of features as a string
102       std::ostringstream aListOfFeatures;
103       for (std::list<FeaturePtr>::iterator anIt = anExternalLinks.begin();
104            anIt != anExternalLinks.end(); ++anIt) {
105         if (anIt != anExternalLinks.begin())
106           aListOfFeatures << ", ";
107         aListOfFeatures << "'" << (*anIt)->name() << "'";
108       }
109
110       std::string aMessage = "The selected results were created using external references "
111                              "outside of this Part from features %1. "
112                              "Please, remove these references or select another "
113                              "sub-set of results to be able to export.";
114       Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures.str()).send();
115     }
116     if (!aReferredParts.empty()) {
117       // collect names of parts as a string
118       std::ostringstream aListOfParts;
119       for (std::list<FeaturePtr>::iterator anIt = aReferredParts.begin();
120            anIt != aReferredParts.end(); ++anIt) {
121         if (anIt != aReferredParts.begin())
122           aListOfParts << ", ";
123         aListOfParts << "'" << (*anIt)->name() << "'";
124       }
125
126       std::string aMessage = "The selected results were created using references "
127                              "to results of Parts %1. Please, remove these references "
128                              "or select another sub-set of results to be able to export.";
129       Events_InfoMessage(getKind(), aMessage).arg(aListOfParts.str()).send();
130     }
131     // should not export anything
132     aFeaturesToExport.clear();
133   }
134
135   if (!aFeaturesToExport.empty()) {
136     // save the document
137     if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport))
138       setError("Cannot save the document.");
139   }
140 }
141
142
143 // ================================     Auxiliary functions     ===================================
144
145 static bool isCoordinate(FeaturePtr theFeature)
146 {
147   return !theFeature->isInHistory() &&
148           (theFeature->getKind() == ConstructionPlugin_Point::ID() ||
149            theFeature->getKind() == ConstructionPlugin_Axis::ID() ||
150            theFeature->getKind() == ConstructionPlugin_Plane::ID());
151 }
152
153 static void allReferencedFeatures(const std::set<FeaturePtr>& theFeatures,
154                                   std::set<FeaturePtr>& theReferencedFeatures)
155 {
156   std::set<FeaturePtr> aReferences;
157   for (std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin();
158        anIt != theFeatures.end(); ++anIt) {
159     theReferencedFeatures.insert(*anIt);
160
161     std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
162     (*anIt)->data()->referencesToObjects(aRefs);
163
164     for (std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
165          aRIt != aRefs.end(); ++aRIt) {
166       for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
167            anObjIt != aRIt->second.end(); ++anObjIt) {
168         FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
169         if (aFeature && !isCoordinate(aFeature) &&
170             theReferencedFeatures.find(aFeature) == theReferencedFeatures.end())
171           aReferences.insert(aFeature);
172       }
173     }
174   }
175
176   if (!aReferences.empty())
177     allReferencedFeatures(aReferences, theReferencedFeatures);
178 }
179
180 void collectFeatures(DocumentPtr theDocument,
181                      AttributeSelectionListPtr theSelected,
182                      std::list<FeaturePtr>& theExport)
183 {
184   theExport = theDocument->allFeatures();
185
186   // remove all features after the current one
187   FeaturePtr aCurrentFeature = theDocument->currentFeature(false);
188   std::list<FeaturePtr>::iterator anIt = theExport.begin();
189   for (; anIt != theExport.end(); ++anIt)
190     if (*anIt == aCurrentFeature) {
191       theExport.erase(++anIt, theExport.end());
192       break;
193     }
194
195   if (!theSelected || theSelected->size() == 0) {
196     // nothing is selected, return all features of the document
197     return;
198   }
199
200   // collect initial list of features basing on the selected results
201   std::set<FeaturePtr> aFeaturesToExport;
202   for (int anIndex = 0, aSize = theSelected->size(); anIndex < aSize; ++anIndex) {
203     AttributeSelectionPtr aCurrent = theSelected->value(anIndex);
204     FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aCurrent->context());
205     if (aCurrentFeature)
206       aFeaturesToExport.insert(aCurrentFeature);
207   }
208   // recursively collect all features used for the selected results
209   allReferencedFeatures(aFeaturesToExport, aFeaturesToExport);
210
211   // remove the features which are not affect the selected results
212   anIt = theExport.begin();
213   while (anIt != theExport.end()) {
214     if (aFeaturesToExport.find(*anIt) == aFeaturesToExport.end()) {
215       std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
216       theExport.erase(aRemoveIt);
217     }
218     else
219       ++anIt;
220   }
221 }
222
223 void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport)
224 {
225   theExport = theDocument->allFeatures();
226   // keep constructions only
227   std::list<FeaturePtr>::iterator anIt = theExport.begin();
228   while (anIt != theExport.end()) {
229     FeaturePtr aCurFeature = *anIt;
230     ResultPtr aCurResult = aCurFeature->lastResult();
231
232     bool isApplicable =
233         (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) &&
234         !isCoordinate(aCurFeature);
235
236     if (isApplicable)
237       ++anIt;
238     else {
239       std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
240       theExport.erase(aRemoveIt);
241     }
242   }
243 }
244
245 bool verifyExport(const std::list<FeaturePtr>& theFeatures,
246                   std::list<FeaturePtr>& theExternalReferences,
247                   std::list<FeaturePtr>& theExportedParts)
248 {
249   for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
250        anIt != theFeatures.end(); ++anIt) {
251     // full part should not be exported
252     if ((*anIt)->getKind() == PartSetPlugin_Part::ID())
253       theExportedParts.push_back(*anIt);
254
255     DocumentPtr aDoc = (*anIt)->document();
256
257     std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
258     (*anIt)->data()->referencesToObjects(aRefs);
259     std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
260     for (;  aRIt != aRefs.end(); ++aRIt) {
261       for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
262            anObjIt != aRIt->second.end(); ++anObjIt) {
263         FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
264         if (aFeature) {
265           // feature refers to external entity,
266           // which is neither the Origin nor coordinate axis or plane
267           if (aFeature->document() != aDoc && !isCoordinate(aFeature))
268             theExternalReferences.push_back(*anIt);
269           // feature refers to result of a part
270           if (aFeature->getKind() == PartSetPlugin_Part::ID())
271             theExportedParts.push_back(*anIt);
272         }
273       }
274     }
275   }
276
277   return theExternalReferences.empty() && theExportedParts.empty();
278 }