Salome HOME
DumpPython Filter / Controls
[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   TCollection_AsciiString globalVars;
498
499   // Dump trace of restored study
500   if (theSavedTrace.Length() > 0) {
501     aScript += "\n";
502     aScript += theSavedTrace;
503   }
504
505   // Dump trace of API methods calls
506   TCollection_AsciiString aNewLines = GetNewPythonLines(theStudyID);
507   if (aNewLines.Length() > 0) {
508     aScript += "\n";
509     aScript += aNewLines;
510   }
511
512   // Find entries to be replaced by names
513   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
514   Standard_Integer aLen = aSeq->Length();
515
516   if (aLen == 0)
517     return aScript;
518
519   // Replace entries by the names
520   GEOM::GEOM_Gen_ptr geom = GetGeomEngine();
521   TColStd_SequenceOfAsciiString seqRemoved;
522   Resource_DataMapOfAsciiStringAsciiString mapRemoved;
523   Resource_DataMapOfAsciiStringAsciiString aNames;
524   Standard_Integer objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
525   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("smeshObj_");
526
527   for (Standard_Integer i = 1; i <= aLen; i += 2) {
528     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i) - 1);
529     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
530     if (theObjectNames.IsBound(anEntry)) {
531       aName = theObjectNames.Find(anEntry);
532       if (theObjectNames.IsBound(aName) && anEntry != theObjectNames(aName)) {
533         // diff objects have same name - make a new name
534         TCollection_AsciiString aName2;
535         Standard_Integer i = 0;
536         do {
537           aName2 = aName + "_" + ++i;
538         } while (theObjectNames.IsBound(aName2) && anEntry != theObjectNames(aName2));
539         aName = aName2;
540         theObjectNames(anEntry) = aName;
541       }
542     } else {
543       // is a GEOM object?
544       aName = geom->GetDumpName( anEntry.ToCString() );
545       if ( aName.IsEmpty() ) {
546       // ? Removed Object ?
547         do {
548           aName = aBaseName + TCollection_AsciiString(++objectCounter);
549         } while (theObjectNames.IsBound(aName));
550         seqRemoved.Append(aName);
551         mapRemoved.Bind(anEntry, "1");
552       }
553       theObjectNames.Bind(anEntry, aName);
554     }
555     theObjectNames.Bind(aName, anEntry); // to detect same name of diff objects
556
557     anUpdatedScript += aName;
558     aNames.Bind(aName, "1");
559     aStart = aSeq->Value(i + 1) + 1;
560   }
561
562   // add final part of aScript
563   if (aSeq->Value(aLen) < aScriptLength)
564     anUpdatedScript += aScript.SubString(aSeq->Value(aLen) + 1, aScriptLength);
565
566   // Remove removed objects
567   anUpdatedScript += "\n\taStudyBuilder = theStudy.NewBuilder()";
568   for (int ir = 1; ir <= seqRemoved.Length(); ir++) {
569     anUpdatedScript += "\n\tSO = theStudy.FindObjectIOR(theStudy.ConvertObjectToIOR(";
570     anUpdatedScript += seqRemoved.Value(ir);
571     anUpdatedScript += "))\n\tif SO is not None: aStudyBuilder.RemoveObjectWithChildren(SO)";
572   }
573
574   // Set object names
575   anUpdatedScript += "\n\n\tisGUIMode = ";
576   anUpdatedScript += isPublished;
577   anUpdatedScript += "\n\tif isGUIMode:";
578   anUpdatedScript += "\n\t\tsmeshgui = salome.ImportComponentGUI(\"SMESH\")";
579   anUpdatedScript += "\n\t\tsmeshgui.Init(theStudy._get_StudyId())";
580   anUpdatedScript += "\n";
581
582   TCollection_AsciiString aGUIName;
583   Resource_DataMapOfAsciiStringAsciiString mapEntries;
584   for (Standard_Integer i = 1; i <= aLen; i += 2) {
585     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
586     aName = geom->GetDumpName( anEntry.ToCString() );
587     if (aName.IsEmpty() && // Not a GEOM object
588         theNames.IsBound(anEntry) &&
589         !mapEntries.IsBound(anEntry) && // Not yet processed
590         !mapRemoved.IsBound(anEntry)) { // Was not removed
591       aName = theObjectNames.Find(anEntry);
592       aGUIName = theNames.Find(anEntry);
593       mapEntries.Bind(anEntry, aName);
594       anUpdatedScript += "\n\t\tsmeshgui.SetName(salome.ObjectToID(";
595       anUpdatedScript += aName + "), \"" + aGUIName + "\")";
596     }
597   }
598   anUpdatedScript += "\n\n\t\tsalome.sg.updateObjBrowser(0)";
599
600   anUpdatedScript += "\n\n\tpass\n";
601
602   aValidScript = true;
603
604   return anUpdatedScript;
605 }
606
607 //=============================================================================
608 /*!
609  *  GetNewPythonLines
610  */
611 //=============================================================================
612 TCollection_AsciiString SMESH_Gen_i::GetNewPythonLines (int theStudyID)
613 {
614   TCollection_AsciiString aScript;
615
616   // Dump trace of API methods calls
617   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
618     Handle(TColStd_HSequenceOfAsciiString) aPythonScript = myPythonScripts[theStudyID];
619     Standard_Integer istr, aLen = aPythonScript->Length();
620     for (istr = 1; istr <= aLen; istr++) {
621       aScript += "\n\t";
622       aScript += aPythonScript->Value(istr);
623     }
624     aScript += "\n";
625   }
626
627   return aScript;
628 }
629
630 //=============================================================================
631 /*!
632  *  CleanPythonTrace
633  */
634 //=============================================================================
635 void SMESH_Gen_i::CleanPythonTrace (int theStudyID)
636 {
637   TCollection_AsciiString aScript;
638
639   // Clean trace of API methods calls
640   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
641     myPythonScripts[theStudyID]->Clear();
642   }
643 }