Salome HOME
Bug IPAL8742. Add comments into generated files of DumpPython
[modules/smesh.git] / src / SMESH_I / SMESH_DumpPython.cxx
1 // File    : SMESH_Gen_i_DumpPython.cxx
2 // Created : Thu Mar 24 17:17:59 2005
3 // Author  : Julia DOROVSKIKH
4 // Module  : SMESH
5 // $Header : $
6
7 #include "SMESH_PythonDump.hxx"
8 #include "SMESH_Gen_i.hxx"
9 #include "SMESH_Filter_i.hxx"
10 #include "SALOMEDSImpl_Study.hxx"
11
12 #include <TColStd_HSequenceOfInteger.hxx>
13 #include <TCollection_AsciiString.hxx>
14
15
16 #ifdef _DEBUG_
17 static int MYDEBUG = 0;
18 #else
19 static int MYDEBUG = 0;
20 #endif
21
22 static TCollection_AsciiString NotPublishedObjectName()
23 {
24   return "__NOT__Published__Object__";
25 }
26
27 namespace SMESH
28 {
29
30   size_t TPythonDump::myCounter = 0;
31
32   TPythonDump::
33   TPythonDump()
34   {
35     ++myCounter;
36   }
37   TPythonDump::
38   ~TPythonDump()
39   {
40     if(--myCounter == 0){
41       SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
42       SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy();
43       if(!aStudy->_is_nil()){
44         std::string aString = myStream.str();
45         TCollection_AsciiString aCollection(Standard_CString(aString.c_str()));
46         aSMESHGen->AddToPythonScript(aStudy->StudyId(),aCollection);
47         if(MYDEBUG) MESSAGE(aString);
48       }
49     }
50   }
51
52   TPythonDump& 
53   TPythonDump::
54   operator<<(long int theArg){
55     myStream<<theArg;
56     return *this;
57   }
58
59   TPythonDump& 
60   TPythonDump::
61   operator<<(int theArg){
62     myStream<<theArg;
63     return *this;
64   }
65
66   TPythonDump& 
67   TPythonDump::
68   operator<<(double theArg){
69     myStream<<theArg;
70     return *this;
71   }
72
73   TPythonDump& 
74   TPythonDump::
75   operator<<(float theArg){
76     myStream<<theArg;
77     return *this;
78   }
79
80   TPythonDump& 
81   TPythonDump::
82   operator<<(const void* theArg){
83     myStream<<theArg;
84     return *this;
85   }
86
87   TPythonDump& 
88   TPythonDump::
89   operator<<(const char* theArg){
90     myStream<<theArg;
91     return *this;
92   }
93
94   TPythonDump& 
95   TPythonDump::
96   operator<<(const SMESH::ElementType& theArg)
97   {
98     myStream<<"SMESH.";
99     switch(theArg){
100     case ALL: 
101       myStream<<"ALL"; 
102       break;
103     case NODE: 
104       myStream<<"NODE"; 
105       break;
106     case EDGE: 
107       myStream<<"EDGE"; 
108       break;
109     case FACE: 
110       myStream<<"FACE"; 
111       break;
112     case VOLUME: 
113       myStream<<"VOLUME"; 
114       break;
115     }
116     return *this;
117   }
118
119
120   TPythonDump& 
121   TPythonDump::
122   operator<<(const SMESH::long_array& theArg)
123   {
124     myStream<<"[ ";
125     CORBA::Long i = 1, iEnd = theArg.length();
126     for(; i <= iEnd; i++) {
127       myStream<<theArg[i-1];
128       if(i < iEnd)
129         myStream<< ", ";
130     }
131     myStream<<" ]";
132     return *this;
133   }
134
135
136   TPythonDump& 
137   TPythonDump::
138   operator<<(CORBA::Object_ptr theArg)
139   {
140     TCollection_AsciiString aString("None");
141     SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
142     SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy();
143     SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg);
144     if(!aSObject->_is_nil()){
145       aString = aSObject->GetID();
146     }else if(!CORBA::is_nil(theArg)){
147       aString = "smeshObj_";
148       if ( aSMESHGen->CanPublishInStudy( theArg )) // not published SMESH object
149         aString += (int) theArg;
150       else
151         aString = NotPublishedObjectName();
152     }
153     myStream<<aString.ToCString();
154     return *this;
155   }
156
157   TPythonDump& 
158   TPythonDump::
159   operator<<(SMESH::FilterLibrary_i* theArg)
160   {
161     myStream<<"aFilterLibrary"<<theArg;
162     return *this;
163   }
164
165   TPythonDump& 
166   TPythonDump::
167   operator<<(SMESH::FilterManager_i* theArg)
168   {
169     myStream<<"aFilterManager";
170     return *this;
171   }
172
173   TPythonDump& 
174   TPythonDump::
175   operator<<(SMESH::Filter_i* theArg)
176   {
177     myStream<<"aFilter"<<theArg;
178     return *this;
179   }
180
181   TPythonDump& 
182   TPythonDump::
183   operator<<(SMESH::Functor_i* theArg)
184   {
185     FunctorType aFunctorType = theArg->GetFunctorType();
186     switch(aFunctorType){
187     case FT_AspectRatio:
188       myStream<<"anAspectRatio";
189       break;
190     case FT_AspectRatio3D:
191       myStream<<"anAspectRatio3D";
192       break;
193     case FT_Warping:
194       myStream<<"aWarping";
195       break;
196     case FT_MinimumAngle:
197       myStream<<"aMinimumAngle";
198       break;
199     case FT_Taper:
200       myStream<<"aTaper";
201       break;
202     case FT_Skew:
203       myStream<<"aSkew";
204       break;
205     case FT_Area:
206       myStream<<"aArea";
207       break;
208     case FT_FreeBorders:
209       myStream<<"aFreeBorders";
210       break;
211     case FT_FreeEdges:
212       myStream<<"aFreeEdges";
213       break;
214     case FT_MultiConnection:
215       myStream<<"aMultiConnection";
216       break;
217     case FT_MultiConnection2D:
218       myStream<<"aMultiConnection2D";
219       break;
220     case FT_Length:
221       myStream<<"aLength";
222       break;
223     case FT_Length2D:
224       myStream<<"aLength";
225       break;
226     case FT_BelongToGeom:
227       myStream<<"aBelongToGeom";
228       break;
229     case FT_BelongToPlane:
230       myStream<<"aBelongToPlane";
231       break;
232     case FT_BelongToCylinder:
233       myStream<<"aBelongToCylinder";
234       break;
235     case FT_LyingOnGeom:
236       myStream<<"aLyingOnGeom";
237       break;
238     case FT_RangeOfIds:
239       myStream<<"aRangeOfIds";
240       break;
241     case FT_BadOrientedVolume:
242       myStream<<"aBadOrientedVolume";
243       break;
244     case FT_LessThan:
245       myStream<<"aLessThan";
246       break;
247     case FT_MoreThan:
248       myStream<<"aMoreThan";
249       break;
250     case FT_EqualTo:
251       myStream<<"anEqualTo";
252       break;
253     case FT_LogicalNOT:
254       myStream<<"aLogicalNOT";
255       break;
256     case FT_LogicalAND:
257       myStream<<"aLogicalAND";
258       break;
259     case FT_LogicalOR:
260       myStream<<"aLogicalOR";
261       break;
262     case FT_Undefined:
263       myStream<<"anUndefined";
264       break;
265     }
266     myStream<<theArg;
267     return *this;
268   }
269 }
270
271 //=======================================================================
272 //function : DumpPython
273 //purpose  : 
274 //=======================================================================
275 Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Object_ptr theStudy,
276                                            CORBA::Boolean isPublished,
277                                            CORBA::Boolean& isValidScript)
278 {
279   SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(theStudy);
280   if (CORBA::is_nil(aStudy))
281     return new Engines::TMPFile(0);
282
283   SALOMEDS::SObject_var aSO = aStudy->FindComponent(ComponentDataType());
284   if (CORBA::is_nil(aSO))
285     return new Engines::TMPFile(0);
286
287   // Map study entries to object names
288   Resource_DataMapOfAsciiStringAsciiString aMap;
289   Resource_DataMapOfAsciiStringAsciiString aMapNames;
290   TCollection_AsciiString s ("qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_");
291
292   SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO);
293   for (Itr->InitEx(true); Itr->More(); Itr->Next()) {
294     SALOMEDS::SObject_var aValue = Itr->Value();
295
296     TCollection_AsciiString aName (aValue->GetName());
297     TCollection_AsciiString aGUIName (aName);
298     if (aName.Length() > 0) {
299       aMapNames.Bind(TCollection_AsciiString(aValue->GetID()), aGUIName);
300       int p, p2 = 1, e = aName.Length();
301       while ((p = aName.FirstLocationNotInSet(s, p2, e))) {
302         aName.SetValue(p, '_');
303         p2 = p;
304       }
305       aMap.Bind(TCollection_AsciiString(aValue->GetID()), aName);
306     }
307   }
308
309   // Get trace of restored study
310   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
311   SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
312   SALOMEDS::GenericAttribute_var anAttr =
313     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
314
315   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
316   TCollection_AsciiString aSavedTrace (oldValue);
317
318   // Add trace of API methods calls and replace study entries by names
319   TCollection_AsciiString aScript =
320     SALOMEDSImpl_Study::GetDumpStudyComment("SMESH") + "\n\n" +
321       DumpPython_impl(aStudy->StudyId(), aMap, aMapNames, isPublished, isValidScript, aSavedTrace);
322
323   int aLen = aScript.Length(); 
324   unsigned char* aBuffer = new unsigned char[aLen+1];
325   strcpy((char*)aBuffer, aScript.ToCString());
326
327   CORBA::Octet* anOctetBuf =  (CORBA::Octet*)aBuffer;
328   Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aLen+1, aLen+1, anOctetBuf, 1); 
329
330   bool hasNotPublishedObjects = aScript.Location( NotPublishedObjectName(), 1, aLen);
331   isValidScript = isValidScript && !hasNotPublishedObjects;
332
333   return aStreamFile._retn(); 
334 }
335
336 //=============================================================================
337 /*!
338  *  AddToPythonScript
339  */
340 //=============================================================================
341 void SMESH_Gen_i::AddToPythonScript (int theStudyID, const TCollection_AsciiString& theString)
342 {
343   if (myPythonScripts.find(theStudyID) == myPythonScripts.end()) {
344     myPythonScripts[theStudyID] = new TColStd_HSequenceOfAsciiString;
345   }
346   myPythonScripts[theStudyID]->Append(theString);
347 }
348
349 //=============================================================================
350 /*!
351  *  RemoveLastFromPythonScript
352  */
353 //=============================================================================
354 void SMESH_Gen_i::RemoveLastFromPythonScript (int theStudyID)
355 {
356   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
357     int aLen = myPythonScripts[theStudyID]->Length();
358     myPythonScripts[theStudyID]->Remove(aLen);
359   }
360 }
361
362 //=======================================================================
363 //function : AddToCurrentPyScript
364 //purpose  : 
365 //=======================================================================
366
367 void SMESH_Gen_i::AddToCurrentPyScript (const TCollection_AsciiString& theString)
368 {
369   SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
370   SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy();
371   if (aStudy->_is_nil()) return;
372   aSMESHGen->AddToPythonScript(aStudy->StudyId(), theString);
373 }
374
375
376 //=======================================================================
377 //function : AddObject
378 //purpose  : add object to script string
379 //=======================================================================
380
381 TCollection_AsciiString& SMESH_Gen_i::AddObject(TCollection_AsciiString& theStr,
382                                                 CORBA::Object_ptr        theObject)
383 {
384   TCollection_AsciiString aString("None");
385   SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
386   SALOMEDS::SObject_var aSObject =
387     aSMESHGen->ObjectToSObject(aSMESHGen->GetCurrentStudy(), theObject);
388   if ( !aSObject->_is_nil() ) {
389     aString = aSObject->GetID();
390   } else if ( !CORBA::is_nil( theObject )) {
391     aString = "smeshObj_";
392     if ( aSMESHGen->CanPublishInStudy( theObject )) // not published SMESH object
393       aString += (int) theObject;
394     else
395       aString = NotPublishedObjectName();
396   }
397   theStr += aString;
398   return theStr;
399 }
400
401 //=======================================================================
402 //function : SavePython
403 //purpose  : 
404 //=======================================================================
405 void SMESH_Gen_i::SavePython (SALOMEDS::Study_ptr theStudy)
406 {
407   // Dump trace of API methods calls
408   TCollection_AsciiString aScript = GetNewPythonLines(theStudy->StudyId());
409
410   // Check contents of PythonObject attribute
411   SALOMEDS::SObject_var aSO = theStudy->FindComponent(ComponentDataType());
412   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
413   SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder();
414   SALOMEDS::GenericAttribute_var anAttr =
415     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
416
417   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
418   TCollection_AsciiString oldScript (oldValue);
419
420   if (oldScript.Length() > 0) {
421     oldScript += "\n";
422     oldScript += aScript;
423   } else {
424     oldScript = aScript;
425   }
426
427   // Store in PythonObject attribute
428   SALOMEDS::AttributePythonObject::_narrow(anAttr)->SetObject(oldScript.ToCString(), 1);
429
430   // Clean trace of API methods calls
431   CleanPythonTrace(theStudy->StudyId());
432 }
433
434
435 // impl
436
437
438 //=============================================================================
439 /*!
440  *  FindEntries: Returns a sequence of start/end positions of entries in the string
441  */
442 //=============================================================================
443 Handle(TColStd_HSequenceOfInteger) FindEntries (TCollection_AsciiString& theString)
444 {
445   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
446   Standard_Integer aLen = theString.Length();
447   Standard_Boolean isFound = Standard_False;
448
449   char* arr = theString.ToCString();
450   Standard_Integer i = 0, j;
451
452   while(i < aLen) {
453     int c = (int)arr[i];
454     j = i+1;
455     if(c >= 48 && c <= 57) { //Is digit?
456  
457       isFound = Standard_False;
458       while((j < aLen) && ((c >= 48 && c <= 57) || c == 58) ) { //Check if it is an entry
459         c = (int)arr[j++];  
460         if(c == 58) isFound = Standard_True;
461       }
462
463       if (isFound) {
464         int prev = (i < 1) ? 0 : (int)arr[i - 1];
465         // last char should be a diggit,
466         // previous char should not be '"'.
467         if (arr[j-2] != 58 && prev != 34) {
468           aSeq->Append(i+1); // +1 because AsciiString starts from 1
469           aSeq->Append(j-1);
470         }
471       }
472     }
473
474     i = j;
475   }
476
477   return aSeq;
478 }
479
480 //=============================================================================
481 /*!
482  *  DumpPython
483  */
484 //=============================================================================
485 TCollection_AsciiString SMESH_Gen_i::DumpPython_impl
486                         (int theStudyID, 
487                          Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
488                          Resource_DataMapOfAsciiStringAsciiString& theNames,
489                          bool isPublished, 
490                          bool& aValidScript,
491                          const TCollection_AsciiString& theSavedTrace)
492 {
493   TCollection_AsciiString aScript;
494   aScript = "def RebuildData(theStudy):";
495   aScript += "\n\tsmesh = salome.lcc.FindOrLoadComponent(\"FactoryServer\", \"SMESH\")";
496   aScript += "\n\taFilterManager = smesh.CreateFilterManager()";
497   if ( isPublished )
498     aScript += "\n\tsmesh.SetCurrentStudy(theStudy)";
499   else
500     aScript += "\n\tsmesh.SetCurrentStudy(None)";
501
502   // Dump trace of restored study
503   if (theSavedTrace.Length() > 0) {
504     aScript += "\n";
505     aScript += theSavedTrace;
506   }
507
508   // Dump trace of API methods calls
509   TCollection_AsciiString aNewLines = GetNewPythonLines(theStudyID);
510   if (aNewLines.Length() > 0) {
511     aScript += "\n";
512     aScript += aNewLines;
513   }
514
515   // Find entries to be replaced by names
516   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
517   Standard_Integer aLen = aSeq->Length();
518
519   if (aLen == 0)
520     return aScript;
521
522   // Replace entries by the names
523   GEOM::GEOM_Gen_ptr geom = GetGeomEngine();
524   TColStd_SequenceOfAsciiString seqRemoved;
525   Resource_DataMapOfAsciiStringAsciiString mapRemoved;
526   Standard_Integer objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
527   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("smeshObj_");
528
529   // Collect names of GEOM objects to exclude same names for SMESH objects
530   GEOM::string_array_var aGeomNames = geom->GetAllDumpNames();
531   int ign = 0, nbgn = aGeomNames->length();
532   for (; ign < nbgn; ign++) {
533     aName = aGeomNames[ign];
534     theObjectNames.Bind(aName, "1");
535   }
536
537   bool importGeom = false;
538   for (Standard_Integer i = 1; i <= aLen; i += 2) {
539     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i) - 1);
540     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
541     // is a GEOM object?
542     aName = geom->GetDumpName( anEntry.ToCString() );
543     if (aName.IsEmpty()) {
544       // is a SMESH object
545       if (theObjectNames.IsBound(anEntry)) {
546         // The Object is in Study
547         aName = theObjectNames.Find(anEntry);
548         if ( aName.IsIntegerValue() ) // aName must not start with a digit
549           aName.Insert( 1, 'a' );
550         if (theObjectNames.IsBound(aName) && anEntry != theObjectNames(aName)) {
551           // diff objects have same name - make a new name
552           TCollection_AsciiString aName2;
553           Standard_Integer i = 0;
554           do {
555             aName2 = aName + "_" + ++i;
556           } while (theObjectNames.IsBound(aName2) && anEntry != theObjectNames(aName2));
557           aName = aName2;
558           theObjectNames(anEntry) = aName;
559         }
560       } else {
561         // Removed Object
562         do {
563           aName = aBaseName + TCollection_AsciiString(++objectCounter);
564         } while (theObjectNames.IsBound(aName));
565         seqRemoved.Append(aName);
566         mapRemoved.Bind(anEntry, "1");
567         theObjectNames.Bind(anEntry, aName);
568       }
569       theObjectNames.Bind(aName, anEntry); // to detect same name of diff objects
570     }
571     else
572     {
573       importGeom = true;
574     }
575     anUpdatedScript += aName;
576     aStart = aSeq->Value(i + 1) + 1;
577   }
578
579   // set initial part of aSript
580   TCollection_AsciiString initPart = "import salome, SMESH, StdMeshers\n\n";
581   if ( importGeom )
582   {
583     initPart += ("import string, os, sys, re\n"
584                  "sys.path.insert( 0, os.path.dirname(__file__) )\n"
585                  "exec(\"from \"+re.sub(\"SMESH$\",\"GEOM\",__name__)+\" import *\")\n\n");
586   }
587   anUpdatedScript.Insert ( 1, initPart );
588
589   // add final part of aScript
590   if (aSeq->Value(aLen) < aScriptLength)
591     anUpdatedScript += aScript.SubString(aSeq->Value(aLen) + 1, aScriptLength);
592
593   // Remove removed objects
594   anUpdatedScript += "\n\taStudyBuilder = theStudy.NewBuilder()";
595   for (int ir = 1; ir <= seqRemoved.Length(); ir++) {
596     anUpdatedScript += "\n\tSO = theStudy.FindObjectIOR(theStudy.ConvertObjectToIOR(";
597     anUpdatedScript += seqRemoved.Value(ir);
598     anUpdatedScript += "))\n\tif SO is not None: aStudyBuilder.RemoveObjectWithChildren(SO)";
599   }
600
601   // Set object names
602   anUpdatedScript += "\n\n\tisGUIMode = ";
603   anUpdatedScript += isPublished;
604   anUpdatedScript += "\n\tif isGUIMode:";
605   anUpdatedScript += "\n\t\tsmeshgui = salome.ImportComponentGUI(\"SMESH\")";
606   anUpdatedScript += "\n\t\tsmeshgui.Init(theStudy._get_StudyId())";
607   anUpdatedScript += "\n";
608
609   TCollection_AsciiString aGUIName;
610   Resource_DataMapOfAsciiStringAsciiString mapEntries;
611   for (Standard_Integer i = 1; i <= aLen; i += 2) {
612     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
613     aName = geom->GetDumpName( anEntry.ToCString() );
614     if (aName.IsEmpty() && // Not a GEOM object
615         theNames.IsBound(anEntry) &&
616         !mapEntries.IsBound(anEntry) && // Not yet processed
617         !mapRemoved.IsBound(anEntry)) { // Was not removed
618       aName = theObjectNames.Find(anEntry);
619       aGUIName = theNames.Find(anEntry);
620       mapEntries.Bind(anEntry, aName);
621       anUpdatedScript += "\n\t\tsmeshgui.SetName(salome.ObjectToID(";
622       anUpdatedScript += aName + "), \"" + aGUIName + "\")";
623     }
624   }
625   anUpdatedScript += "\n\n\t\tsalome.sg.updateObjBrowser(0)";
626
627   anUpdatedScript += "\n\n\tpass\n";
628
629   aValidScript = true;
630
631   return anUpdatedScript;
632 }
633
634 //=============================================================================
635 /*!
636  *  GetNewPythonLines
637  */
638 //=============================================================================
639 TCollection_AsciiString SMESH_Gen_i::GetNewPythonLines (int theStudyID)
640 {
641   TCollection_AsciiString aScript;
642
643   // Dump trace of API methods calls
644   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
645     Handle(TColStd_HSequenceOfAsciiString) aPythonScript = myPythonScripts[theStudyID];
646     Standard_Integer istr, aLen = aPythonScript->Length();
647     for (istr = 1; istr <= aLen; istr++) {
648       aScript += "\n\t";
649       aScript += aPythonScript->Value(istr);
650     }
651     aScript += "\n";
652   }
653
654   return aScript;
655 }
656
657 //=============================================================================
658 /*!
659  *  CleanPythonTrace
660  */
661 //=============================================================================
662 void SMESH_Gen_i::CleanPythonTrace (int theStudyID)
663 {
664   TCollection_AsciiString aScript;
665
666   // Clean trace of API methods calls
667   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
668     myPythonScripts[theStudyID]->Clear();
669   }
670 }