]> SALOME platform Git repositories - modules/shaper.git/blob - src/ModelHighAPI/ModelHighAPI_Dumper.cpp
Salome HOME
4bfd11a38132c4ee088dd6ee41b1751db0814f07
[modules/shaper.git] / src / ModelHighAPI / ModelHighAPI_Dumper.cpp
1 // Copyright (C) 2016-20xx CEA/DEN, EDF R&D -->
2
3 // File:        ModelHighAPI_Dumper.cpp
4 // Created:     1 August 2016
5 // Author:      Artem ZHIDKOV
6
7 //--------------------------------------------------------------------------------------
8 #include "ModelHighAPI_Dumper.h"
9
10 #include <GeomAPI_Pnt.h>
11 #include <GeomAPI_Dir.h>
12
13 #include <GeomDataAPI_Dir.h>
14 #include <GeomDataAPI_Point.h>
15 #include <GeomDataAPI_Point2D.h>
16
17 #include <ModelAPI_AttributeBoolean.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeInteger.h>
20 #include <ModelAPI_AttributeRefAttr.h>
21 #include <ModelAPI_AttributeRefAttrList.h>
22 #include <ModelAPI_AttributeReference.h>
23 #include <ModelAPI_AttributeRefList.h>
24 #include <ModelAPI_AttributeSelection.h>
25 #include <ModelAPI_AttributeSelectionList.h>
26 #include <ModelAPI_AttributeString.h>
27 #include <ModelAPI_CompositeFeature.h>
28 #include <ModelAPI_Document.h>
29 #include <ModelAPI_Entity.h>
30 #include <ModelAPI_Feature.h>
31 #include <ModelAPI_Result.h>
32 #include <ModelAPI_ResultPart.h>
33
34 #include <PartSetPlugin_Part.h>
35
36 #include <OSD_OpenFile.hxx>
37
38 #include <fstream>
39
40 static int gCompositeStackDepth = 0;
41
42 ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
43
44 ModelHighAPI_Dumper::ModelHighAPI_Dumper()
45 {
46   clear();
47 }
48
49 void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper)
50 {
51   if (mySelf == 0)
52     mySelf = theDumper;
53 }
54
55 ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance()
56 {
57   return mySelf;
58 }
59
60 void ModelHighAPI_Dumper::clear(bool bufferOnly)
61 {
62   myDumpBuffer.str("");
63   myDumpBuffer << std::setprecision(16);
64
65   clearNotDumped();
66
67   if (!bufferOnly) {
68     myFullDump.str("");
69     myFullDump << std::setprecision(16);
70
71     myNames.clear();
72     myModules.clear();
73     myFeatureCount.clear();
74     while (!myEntitiesStack.empty())
75       myEntitiesStack.pop();
76   }
77 }
78
79 void ModelHighAPI_Dumper::clearNotDumped()
80 {
81   myNotDumpedEntities.clear();
82 }
83
84 const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, bool theSaveNotDumped)
85 {
86   EntityNameMap::const_iterator aFound = myNames.find(theEntity);
87   if (aFound != myNames.end())
88     return aFound->second.first;
89
90   // entity is not found, store it
91   std::string aName;
92   std::ostringstream aDefaultName;
93   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
94   if (aFeature) {
95     aName = aFeature->name();
96     const std::string& aKind = aFeature->getKind();
97     DocumentPtr aDoc = aFeature->document();
98     int& aNbFeatures = myFeatureCount[aDoc][aKind];
99     aNbFeatures += 1;
100
101     size_t anIndex = aName.find(aKind);
102     if (anIndex == 0 && aName[aKind.length()] == '_') { // name starts with "FeatureKind_"
103       std::string anIdStr = aName.substr(aKind.length() + 1);
104       int anId = std::stoi(anIdStr);
105
106       // Check number of already registered objects of such kind. Index of current object
107       // should be the same to identify feature's name as automatically generated.
108       if (aNbFeatures == anId) {
109         // name is not user-defined
110         aName.clear();
111       }
112     }
113
114     // obtain default name for the feature
115     int aFullIndex = 0;
116     NbFeaturesMap::const_iterator aFIt = myFeatureCount.begin();
117     for (; aFIt != myFeatureCount.end(); ++aFIt) {
118       std::map<std::string, int>::const_iterator aFound = aFIt->second.find(aKind);
119       if (aFound != aFIt->second.end())
120         aFullIndex += aFound->second;
121     }
122     aDefaultName << aKind << "_" << aFullIndex;
123
124     // store names of results
125     saveResultNames(aFeature);
126   }
127
128   myNames[theEntity] = std::pair<std::string, std::string>(aDefaultName.str(), aName);
129   if (theSaveNotDumped)
130     myNotDumpedEntities.insert(theEntity);
131   return myNames[theEntity].first;
132 }
133
134 const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity)
135 {
136   const std::set<AttributePtr>& aRefs = theEntity->data()->refsToMe();
137   std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
138   for (; aRefIt != aRefs.end(); ++aRefIt) {
139     CompositeFeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(
140         ModelAPI_Feature::feature((*aRefIt)->owner()));
141     if (anOwner)
142       return name(anOwner);
143   }
144
145   static const std::string DUMMY;
146   return DUMMY;
147 }
148
149 void ModelHighAPI_Dumper::saveResultNames(const FeaturePtr& theFeature)
150 {
151   std::string aFeatureName = theFeature->name();
152   const std::list<ResultPtr>& aResults = theFeature->results();
153   std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
154   for (int i = 1; aResIt != aResults.end(); ++aResIt, ++i) {
155     bool isUserDefined = true;
156     std::string aResName = (*aResIt)->data()->name();
157     size_t anIndex = aResName.find(aFeatureName);
158     if (anIndex == 0) {
159       std::string aSuffix = aResName.substr(aFeatureName.length());
160       if (aSuffix.empty() && i == 1) // first result may not constain index in the name
161         isUserDefined = false;
162       else {
163         if (aSuffix[0] == '_' && std::stoi(aSuffix.substr(1)) == i)
164           isUserDefined = false;
165       }
166     }
167
168     myNames[*aResIt] = std::pair<std::string, std::string>(aResName,
169         isUserDefined ? aResName : std::string());
170   }
171 }
172
173 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc,
174                                   const std::string& theFileName)
175 {
176   // dump top level document feature
177   static const std::string aDocName("partSet");
178   myNames[theDoc] = std::pair<std::string, std::string>(aDocName, std::string());
179   *this << aDocName << " = model.moduleDocument()" << std::endl;
180
181   // dump subfeatures and store result to file
182   return process(theDoc) && exportTo(theFileName);
183 }
184
185 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
186 {
187   bool isOk = true;
188   std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
189   std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
190   // firstly, dump all parameters
191   for (; aFeatIt != aFeatures.end(); ++ aFeatIt)
192     dumpParameter(*aFeatIt);
193   // dump all other features
194   for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) {
195     CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
196     if (aCompFeat) // iteratively process composite features
197       isOk = process(aCompFeat) && isOk;
198     else if (!isDumped(*aFeatIt)) // dump common feature 
199       dumpFeature(*aFeatIt);
200   }
201   return isOk;
202 }
203
204 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite, bool isForce)
205 {
206   // increase composite features stack
207   ++gCompositeStackDepth;
208   // dump composite itself
209   if (!isDumped(theComposite) || isForce)
210     dumpFeature(theComposite, isForce);
211
212   // sub-part is processed independently, because it provides separate document
213   if (theComposite->getKind() == PartSetPlugin_Part::ID()) {
214     // decrease composite features stack because we run into separate document
215     --gCompositeStackDepth;
216
217     ResultPartPtr aPartResult =
218         std::dynamic_pointer_cast<ModelAPI_ResultPart>(theComposite->lastResult());
219     if (!aPartResult)
220       return false;
221     DocumentPtr aSubDoc = aPartResult->partDoc();
222     if (!aSubDoc)
223       return false;
224     // set name of document
225     const std::string& aPartName = myNames[theComposite].first;
226     std::string aDocName = aPartName + "_doc";
227     myNames[aSubDoc] = std::pair<std::string, std::string>(aDocName, std::string());
228
229     // dump document in a separate line
230     *this << aDocName << " = " << aPartName << ".document()" << std::endl;
231     // dump features in the document
232     return process(aSubDoc);
233   }
234
235   // dump sub-features
236   bool isOk = processSubs(theComposite);
237   // decrease composite features stack
238   --gCompositeStackDepth;
239
240   return isOk;
241 }
242
243 bool ModelHighAPI_Dumper::processSubs(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
244                                       bool theDumpModelDo)
245 {
246   bool isOk = true;
247   // dump all sub-features;
248   int aNbSubs = theComposite->numberOfSubs();
249   for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) {
250     FeaturePtr aFeature = theComposite->subFeature(anIndex);
251     if (isDumped(aFeature))
252       continue;
253
254     CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
255     if (aCompFeat) // iteratively process composite features
256       isOk = process(aCompFeat) && isOk;
257     else
258       dumpFeature(aFeature, true);
259   }
260
261   bool isDumpSetName = !myEntitiesStack.empty() &&
262       myEntitiesStack.top().myEntity == EntityPtr(theComposite);
263   bool isForceModelDo = isDumpSetName &&
264       (myEntitiesStack.top().myUserName || !myEntitiesStack.top().myResultsWithName.empty());
265   // It is necessary for the sketch to create its result when complete (command "model.do()").
266   // This option is set by flat theDumpModelDo.
267   // However, nested sketches are rebuilt by parent feature, so, they do not need
268   // explicit call of "model.do()". This will be controlled by the depth of the stack.
269   if (isForceModelDo || (theDumpModelDo && gCompositeStackDepth <= 1))
270     *this << "model.do()" << std::endl;
271
272   // dump "setName" for composite feature
273   if (isDumpSetName)
274     dumpEntitySetName();
275   return isOk;
276 }
277
278 bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName)
279 {
280   std::ofstream aFile;
281   OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out);
282   if (!aFile.is_open())
283     return false;
284
285   // standard header
286   for (ModulesMap::const_iterator aModIt = myModules.begin();
287        aModIt != myModules.end(); ++aModIt) {
288     aFile << "from " << aModIt->first << " import ";
289     if (aModIt->second.empty() || 
290         aModIt->second.find(std::string()) != aModIt->second.end())
291       aFile << "*"; // import whole module
292     else {
293       // import specific features
294       std::set<std::string>::const_iterator anObjIt = aModIt->second.begin();
295       aFile << *anObjIt;
296       for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt)
297         aFile << ", " << *anObjIt;
298     }
299     aFile << std::endl;
300   }
301   if (!myModules.empty())
302     aFile << std::endl;
303
304   aFile << "import model" << std::endl << std::endl;
305   aFile << "model.begin()" << std::endl;
306
307   // dump collected data
308   aFile << myFullDump.str();
309   aFile << myDumpBuffer.str();
310
311   // standard footer
312   aFile << "model.end()" << std::endl;
313
314   aFile.close();
315   clear();
316
317   return true;
318 }
319
320 void ModelHighAPI_Dumper::importModule(const std::string& theModuleName,
321                                        const std::string& theObject)
322 {
323   myModules[theModuleName].insert(theObject);
324 }
325
326 void ModelHighAPI_Dumper::dumpEntitySetName()
327 {
328   const LastDumpedEntity& aLastDumped = myEntitiesStack.top();
329
330   // dump "setName" for the entity
331   if (aLastDumped.myUserName) {
332     std::pair<std::string, std::string> anEntityNames = myNames[aLastDumped.myEntity];
333     if (!anEntityNames.second.empty())
334       myDumpBuffer << anEntityNames.first << ".setName(\"" << anEntityNames.second << "\")" << std::endl;
335     anEntityNames.second.clear(); // don't dump "setName" for the entity twice
336   }
337   // dump "setName" for results
338   std::list<ResultPtr>::const_iterator aResIt = aLastDumped.myResultsWithName.begin();
339   std::list<ResultPtr>::const_iterator aResEnd = aLastDumped.myResultsWithName.end();
340   for (; aResIt != aResEnd; ++aResIt) {
341     std::pair<std::string, std::string> anEntityNames = myNames[*aResIt];
342     if (!anEntityNames.second.empty()) {
343       *this << *aResIt;
344       myDumpBuffer << ".result().data().setName(\"" << anEntityNames.second << "\")" << std::endl;
345       anEntityNames.second.clear(); // don't dump "setName" for the entity twice
346     }
347   }
348
349   myEntitiesStack.pop();
350 }
351
352 bool ModelHighAPI_Dumper::isDumped(const EntityPtr& theEntity) const
353 {
354   EntityNameMap::const_iterator aFound = myNames.find(theEntity);
355   return aFound != myNames.end();
356 }
357
358 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
359 {
360   myDumpBuffer << theChar;
361   return *this;
362 }
363
364 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString)
365 {
366   myDumpBuffer << theString;
367   return *this;
368 }
369
370 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString)
371 {
372   myDumpBuffer << theString;
373   return *this;
374 }
375
376 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const bool theValue)
377 {
378   myDumpBuffer << (theValue ? "True" : "False");
379   return *this;
380 }
381
382 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue)
383 {
384   myDumpBuffer << theValue;
385   return *this;
386 }
387
388 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue)
389 {
390   myDumpBuffer << theValue;
391   return *this;
392 }
393
394 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
395 {
396   importModule("GeomAPI", "GeomAPI_Pnt");
397   myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", "
398                << thePoint->y() << ", " << thePoint->z() << ")";
399   return *this;
400 }
401
402 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Dir>& theDir)
403 {
404   importModule("GeomAPI", "GeomAPI_Dir");
405   myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", "
406                << theDir->y() << ", " << theDir->z() << ")";
407   return *this;
408 }
409
410 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
411     const std::shared_ptr<GeomDataAPI_Dir>& theDir)
412 {
413   myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z();
414   return *this;
415 }
416
417 static void dumpArray(std::ostringstream& theOutput, int theSize,
418                       double* theValues, std::string* theTexts)
419 {
420   for (int i = 0; i < theSize; ++i) {
421     if (i > 0)
422       theOutput << ", ";
423     if (theTexts[i].empty())
424       theOutput << theValues[i];
425     else
426       theOutput << "\"" << theTexts[i] << "\"";
427   }
428 }
429
430 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
431     const std::shared_ptr<GeomDataAPI_Point>& thePoint)
432 {
433   static const int aSize = 3;
434   double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()};
435   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()};
436   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
437   return *this;
438 }
439
440 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
441     const std::shared_ptr<GeomDataAPI_Point2D>& thePoint)
442 {
443   static const int aSize = 2;
444   double aValues[aSize] = {thePoint->x(), thePoint->y()};
445   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()};
446   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
447   return *this;
448 }
449
450 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
451     const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
452 {
453   myDumpBuffer << (theAttrBool->value() ? "True" : "False");
454   return *this;
455 }
456
457 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
458     const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt)
459 {
460   std::string aText = theAttrInt->text();
461   if (aText.empty())
462     myDumpBuffer << theAttrInt->value();
463   else
464     myDumpBuffer << "\"" << aText << "\"";
465   return *this;
466 }
467
468 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
469     const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal)
470 {
471   std::string aText = theAttrReal->text();
472   if (aText.empty())
473     myDumpBuffer << theAttrReal->value();
474   else
475     myDumpBuffer << "\"" << aText << "\"";
476   return *this;
477 }
478
479 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
480     const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
481 {
482   myDumpBuffer << "\"" << theAttrStr->value() << "\"";
483   return *this;
484 }
485
486 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity)
487 {
488   myDumpBuffer << name(theEntity);
489
490   bool isUserDefindName = !myNames[theEntity].second.empty();
491   // store results if they have user-defined names
492   std::list<ResultPtr> aResultsWithUserName;
493   const std::list<ResultPtr>& aResults = theEntity->results();
494   std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
495   for (; aResIt != aResults.end(); ++aResIt)
496     if (!myNames[*aResIt].second.empty())
497       aResultsWithUserName.push_back(*aResIt);
498   // store just dumped entity to stack
499   myEntitiesStack.push(LastDumpedEntity(theEntity, isUserDefindName, aResultsWithUserName));
500
501   // remove entity from the list of not dumped items
502   myNotDumpedEntities.erase(theEntity);
503   return *this;
504 }
505
506 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult)
507 {
508   FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
509   int anIndex = 0;
510   std::list<ResultPtr> aResults = aFeature->results();
511   for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin(); anIt != aResults.cend(); ++anIt, ++anIndex) {
512     if(theResult->isSame(*anIt)) {
513       break;
514     }
515   }
516   myDumpBuffer << name(aFeature) << ".result()[" << anIndex << "]";
517   return *this;
518 }
519
520 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject)
521 {
522   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
523   if(aFeature.get()) {
524     myDumpBuffer << name(aFeature);
525     return *this;
526   }
527
528   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
529   if(aResult.get()) {
530     *this << aResult;
531     return *this;
532   }
533
534   return *this;
535 }
536
537 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr)
538 {
539   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttr->owner());
540   myDumpBuffer << name(anOwner) << "." << attributeGetter(anOwner, theAttr->id()) << "()";
541   return *this;
542 }
543
544 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
545     const std::shared_ptr<ModelAPI_AttributeRefAttr>& theRefAttr)
546 {
547   if (theRefAttr->isObject())
548     *this << theRefAttr->object();
549   else
550     *this << theRefAttr->attr();
551   return *this;
552 }
553
554 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
555     const std::shared_ptr<ModelAPI_AttributeRefAttrList>& theRefAttrList)
556 {
557   myDumpBuffer << "[";
558   std::list<std::pair<ObjectPtr, AttributePtr> > aList = theRefAttrList->list();
559   bool isAdded = false;
560   std::list<std::pair<ObjectPtr, AttributePtr> >::const_iterator anIt = aList.begin();
561   for (; anIt != aList.end(); ++anIt) {
562     if (isAdded)
563       myDumpBuffer << ", ";
564     else
565       isAdded = true;
566     if (anIt->first)
567       *this << anIt->first;
568     else if (anIt->second)
569       * this << anIt->second;
570   }
571   myDumpBuffer << "]";
572   return *this;
573 }
574
575 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
576     const std::shared_ptr<ModelAPI_AttributeReference>& theReference)
577 {
578   *this << theReference->value();
579   return *this;
580 }
581
582 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
583     const std::shared_ptr<ModelAPI_AttributeRefList>& theRefList)
584 {
585   static const int aThreshold = 2;
586   // if number of elements in the list if greater than a threshold,
587   // dump it in a separate line with specific name
588   std::string aDumped = myDumpBuffer.str();
589   if (aDumped.empty() || theRefList->size() <= aThreshold) {
590     myDumpBuffer << "[";
591     std::list<ObjectPtr> aList = theRefList->list();
592     bool isAdded = false;
593     std::list<ObjectPtr>::const_iterator anIt = aList.begin();
594     for (; anIt != aList.end(); ++anIt) {
595       if (isAdded)
596         myDumpBuffer << ", ";
597       else
598         isAdded = true;
599
600       *this << *anIt;
601     }
602     myDumpBuffer << "]";
603   } else {
604     // clear buffer and store list "as is"
605     myDumpBuffer.str("");
606     *this << theRefList;
607     // save buffer and clear it again
608     std::string aDumpedList = myDumpBuffer.str();
609     myDumpBuffer.str("");
610     // obtain name of list
611     FeaturePtr anOwner = ModelAPI_Feature::feature(theRefList->owner());
612     std::string aListName = name(anOwner) + "_objects";
613     // store all previous data
614     myDumpBuffer << aListName << " = " << aDumpedList << std::endl
615                  << aDumped << aListName;
616   }
617   return *this;
618 }
619
620 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
621     const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
622 {
623   myDumpBuffer << "model.selection(";
624
625   if(!theAttrSelect->isInitialized()) {
626     myDumpBuffer << ")";
627     return *this;
628   }
629
630   GeomShapePtr aShape = theAttrSelect->value();
631   if(!aShape.get()) {
632     aShape = theAttrSelect->context()->shape();
633   }
634
635   if(!aShape.get()) {
636     myDumpBuffer << ")";
637     return *this;
638   }
639
640   myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << theAttrSelect->namingName() << "\")";
641   return *this;
642 }
643
644 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
645     const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
646 {
647   myDumpBuffer << "[";
648
649   GeomShapePtr aShape;
650   std::string aShapeTypeStr;
651
652   bool isAdded = false;
653
654   for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
655     AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
656     aShape = anAttribute->value();
657     if(!aShape.get()) {
658       aShape = anAttribute->context()->shape();
659     }
660
661     if(!aShape.get()) {
662       continue;
663     }
664
665     if(isAdded) {
666       myDumpBuffer << ", ";
667     } else {
668       isAdded = true;
669     }
670     myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
671   }
672
673   myDumpBuffer << "]";
674   return *this;
675 }
676
677 /// Dump std::endl
678 MODELHIGHAPI_EXPORT
679 ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
680                                 std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
681 {
682   theDumper.myDumpBuffer << theEndl;
683
684   if (!theDumper.myEntitiesStack.empty()) {
685     // Name for composite feature is dumped when all sub-entities are dumped
686     // (see method ModelHighAPI_Dumper::processSubs).
687     const ModelHighAPI_Dumper::LastDumpedEntity& aLastDumped = theDumper.myEntitiesStack.top();
688     CompositeFeaturePtr aComposite =
689         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aLastDumped.myEntity);
690     if (!aComposite)
691       theDumper.dumpEntitySetName();
692   }
693
694   // store all not-dumped entities first
695   std::set<EntityPtr> aNotDumped = theDumper.myNotDumpedEntities;
696   std::string aBufCopy = theDumper.myDumpBuffer.str();
697   theDumper.clear(true);
698   std::set<EntityPtr>::const_iterator anIt = aNotDumped.begin();
699   for (; anIt != aNotDumped.end(); ++anIt) {
700     // if the feature is composite, dump it with all subs
701     CompositeFeaturePtr aCompFeat =
702         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*anIt);
703     if (aCompFeat)
704       theDumper.process(aCompFeat, true);
705     else {
706       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
707       theDumper.dumpFeature(aFeature, true);
708     }
709   }
710
711   // avoid multiple empty lines
712   size_t anInd = std::string::npos;
713   while ((anInd = aBufCopy.find("\n\n\n")) != std::string::npos)
714     aBufCopy.erase(anInd, 1);
715   // then store currently dumped string
716   theDumper.myFullDump << aBufCopy;
717
718   return theDumper;
719 }