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