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