Salome HOME
db8721515fd49fe618ca988cc572dac5a0629079
[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   Resource_DataMapOfAsciiStringAsciiString aMapNames;
230   TCollection_AsciiString s ("qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_");
231
232   SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO);
233   for (Itr->InitEx(true); Itr->More(); Itr->Next()) {
234     SALOMEDS::SObject_var aValue = Itr->Value();
235
236     TCollection_AsciiString aName (aValue->GetName());
237     TCollection_AsciiString aGUIName (aName);
238     if (aName.Length() > 0) {
239       aMapNames.Bind(TCollection_AsciiString(aValue->GetID()), aGUIName);
240       int p, p2 = 1, e = aName.Length();
241       while ((p = aName.FirstLocationNotInSet(s, p2, e))) {
242         aName.SetValue(p, '_');
243         p2 = p;
244       }
245       aMap.Bind(TCollection_AsciiString(aValue->GetID()), aName);
246     }
247   }
248
249   // Get trace of restored study
250   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
251   SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
252   SALOMEDS::GenericAttribute_var anAttr =
253     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
254
255   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
256   TCollection_AsciiString aSavedTrace (oldValue);
257
258   // Add trace of API methods calls and replace study entries by names
259   bool aValidScript;
260   TCollection_AsciiString aScript = DumpPython_impl
261     (aStudy->StudyId(), aMap, aMapNames, isPublished, aValidScript, aSavedTrace);
262
263   int aLen = aScript.Length(); 
264   unsigned char* aBuffer = new unsigned char[aLen+1];
265   strcpy((char*)aBuffer, aScript.ToCString());
266
267   CORBA::Octet* anOctetBuf =  (CORBA::Octet*)aBuffer;
268   Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aLen+1, aLen+1, anOctetBuf, 1); 
269   isValidScript = aValidScript;
270
271   return aStreamFile._retn(); 
272 }
273
274 //=============================================================================
275 /*!
276  *  AddToPythonScript
277  */
278 //=============================================================================
279 void SMESH_Gen_i::AddToPythonScript (int theStudyID, const TCollection_AsciiString& theString)
280 {
281   if (myPythonScripts.find(theStudyID) == myPythonScripts.end()) {
282     myPythonScripts[theStudyID] = new TColStd_HSequenceOfAsciiString;
283   }
284   myPythonScripts[theStudyID]->Append(theString);
285 }
286
287 //=============================================================================
288 /*!
289  *  RemoveLastFromPythonScript
290  */
291 //=============================================================================
292 void SMESH_Gen_i::RemoveLastFromPythonScript (int theStudyID)
293 {
294   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
295     int aLen = myPythonScripts[theStudyID]->Length();
296     myPythonScripts[theStudyID]->Remove(aLen);
297   }
298 }
299
300 //=======================================================================
301 //function : AddToCurrentPyScript
302 //purpose  : 
303 //=======================================================================
304
305 void SMESH_Gen_i::AddToCurrentPyScript (const TCollection_AsciiString& theString)
306 {
307   SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
308   SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy();
309   if (aStudy->_is_nil()) return;
310   aSMESHGen->AddToPythonScript(aStudy->StudyId(), theString);
311 }
312
313
314 //=======================================================================
315 //function : AddObject
316 //purpose  : add object to script string
317 //=======================================================================
318
319 TCollection_AsciiString& SMESH_Gen_i::AddObject(TCollection_AsciiString& theStr,
320                                                 CORBA::Object_ptr        theObject)
321 {
322   SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
323   SALOMEDS::SObject_var aSO =
324     aSMESHGen->ObjectToSObject(aSMESHGen->GetCurrentStudy(), theObject);
325   if ( !aSO->_is_nil() )
326     theStr += aSO->GetID();
327   else if ( !CORBA::is_nil( theObject ) )
328     theStr += GetORB()->object_to_string( theObject );
329   else
330     theStr += "None";
331
332   return theStr;
333 }
334
335 //=======================================================================
336 //function : SavePython
337 //purpose  : 
338 //=======================================================================
339 void SMESH_Gen_i::SavePython (SALOMEDS::Study_ptr theStudy)
340 {
341   // Dump trace of API methods calls
342   TCollection_AsciiString aScript = GetNewPythonLines(theStudy->StudyId());
343
344   // Check contents of PythonObject attribute
345   SALOMEDS::SObject_var aSO = theStudy->FindComponent(ComponentDataType());
346   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
347   SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder();
348   SALOMEDS::GenericAttribute_var anAttr =
349     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
350
351   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
352   TCollection_AsciiString oldScript (oldValue);
353
354   if (oldScript.Length() > 0) {
355     oldScript += "\n";
356     oldScript += aScript;
357   } else {
358     oldScript = aScript;
359   }
360
361   // Store in PythonObject attribute
362   SALOMEDS::AttributePythonObject::_narrow(anAttr)->SetObject(oldScript.ToCString(), 1);
363
364   // Clean trace of API methods calls
365   CleanPythonTrace(theStudy->StudyId());
366 }
367
368
369 // impl
370
371
372 //=============================================================================
373 /*!
374  *  FindEntries: Returns a sequence of start/end positions of entries in the string
375  */
376 //=============================================================================
377 Handle(TColStd_HSequenceOfInteger) FindEntries (TCollection_AsciiString& theString)
378 {
379   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
380   Standard_Integer aLen = theString.Length();
381   Standard_Boolean isFound = Standard_False;
382
383   char* arr = theString.ToCString();
384   Standard_Integer i = 0, j;
385
386   while(i < aLen) {
387     int c = (int)arr[i];
388     j = i+1;
389     if(c >= 48 && c <= 57) { //Is digit?
390  
391       isFound = Standard_False;
392       while((j < aLen) && ((c >= 48 && c <= 57) || c == 58) ) { //Check if it is an entry
393         c = (int)arr[j++];  
394         if(c == 58) isFound = Standard_True;
395       }
396
397       if (isFound) {
398         int prev = (i < 1) ? 0 : (int)arr[i - 1];
399         // last char should be a diggit,
400         // previous char should not be '"'.
401         if (arr[j-2] != 58 && prev != 34) {
402           aSeq->Append(i+1); // +1 because AsciiString starts from 1
403           aSeq->Append(j-1);
404         }
405       }
406     }
407
408     i = j;
409   }
410
411   return aSeq;
412 }
413
414 //=============================================================================
415 /*!
416  *  DumpPython
417  */
418 //=============================================================================
419 TCollection_AsciiString SMESH_Gen_i::DumpPython_impl
420                         (int theStudyID, 
421                          Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
422                          Resource_DataMapOfAsciiStringAsciiString& theNames,
423                          bool isPublished, 
424                          bool& aValidScript,
425                          const TCollection_AsciiString& theSavedTrace)
426 {
427   TCollection_AsciiString aScript;
428   aScript += "import salome\n";
429   aScript += "import geompy\n\n";
430   aScript += "import SMESH\n";
431   aScript += "import StdMeshers\n\n";
432   aScript += "#import GEOM module\n";
433   aScript += "import string\n";
434   aScript += "import os\n";
435   aScript += "import sys\n";
436   aScript += "import re\n";
437   aScript += "sys.path.append( os.path.dirname(__file__) )\n";
438   aScript += "exec(\"from \"+re.sub(\"SMESH$\",\"GEOM\",__name__)+\" import *\")\n\n";
439   
440   aScript += "def RebuildData(theStudy):";
441   aScript += "\n\tsmesh = salome.lcc.FindOrLoadComponent(\"FactoryServer\", \"SMESH\")";
442   if ( isPublished )
443     aScript += "\n\tsmesh.SetCurrentStudy(theStudy)";
444   else
445     aScript += "\n\tsmesh.SetCurrentStudy(None)";
446
447   TCollection_AsciiString globalVars;
448
449   // Dump trace of restored study
450   if (theSavedTrace.Length() > 0) {
451     aScript += "\n";
452     aScript += theSavedTrace;
453   }
454
455   // Dump trace of API methods calls
456   TCollection_AsciiString aNewLines = GetNewPythonLines(theStudyID);
457   if (aNewLines.Length() > 0) {
458     aScript += "\n";
459     aScript += aNewLines;
460   }
461
462   // Find entries to be replaced by names
463   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
464   Standard_Integer aLen = aSeq->Length();
465
466   if (aLen == 0)
467     return aScript;
468
469   // Replace entries by the names
470   GEOM::GEOM_Gen_ptr geom = GetGeomEngine();
471   TColStd_SequenceOfAsciiString seqRemoved;
472   Resource_DataMapOfAsciiStringAsciiString mapRemoved;
473   Resource_DataMapOfAsciiStringAsciiString aNames;
474   Standard_Integer objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
475   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("smeshObj_");
476
477   for (Standard_Integer i = 1; i <= aLen; i += 2) {
478     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i) - 1);
479     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
480     if (theObjectNames.IsBound(anEntry)) {
481       aName = theObjectNames.Find(anEntry);
482       if (theObjectNames.IsBound(aName) && anEntry != theObjectNames(aName)) {
483         // diff objects have same name - make a new name
484         TCollection_AsciiString aName2;
485         Standard_Integer i = 0;
486         do {
487           aName2 = aName + "_" + ++i;
488         } while (theObjectNames.IsBound(aName2) && anEntry != theObjectNames(aName2));
489         aName = aName2;
490         theObjectNames(anEntry) = aName;
491       }
492     } else {
493       // is a GEOM object?
494       aName = geom->GetDumpName( anEntry.ToCString() );
495       if ( aName.IsEmpty() ) {
496       // ? Removed Object ?
497         do {
498           aName = aBaseName + TCollection_AsciiString(++objectCounter);
499         } while (theObjectNames.IsBound(aName));
500         seqRemoved.Append(aName);
501         mapRemoved.Bind(anEntry, "1");
502       }
503       theObjectNames.Bind(anEntry, aName);
504     }
505     theObjectNames.Bind(aName, anEntry); // to detect same name of diff objects
506
507     anUpdatedScript += aName;
508     aNames.Bind(aName, "1");
509     aStart = aSeq->Value(i + 1) + 1;
510   }
511
512   // add final part of aScript
513   if (aSeq->Value(aLen) < aScriptLength)
514     anUpdatedScript += aScript.SubString(aSeq->Value(aLen) + 1, aScriptLength);
515
516   // Remove removed objects
517   anUpdatedScript += "\n\taStudyBuilder = theStudy.NewBuilder()";
518   for (int ir = 1; ir <= seqRemoved.Length(); ir++) {
519     anUpdatedScript += "\n\tSO = theStudy.FindObjectIOR(theStudy.ConvertObjectToIOR(";
520     anUpdatedScript += seqRemoved.Value(ir);
521     anUpdatedScript += "))\n\tif SO is not None: aStudyBuilder.RemoveObjectWithChildren(SO)";
522   }
523
524   // Set object names
525   anUpdatedScript += "\n\n\tisGUIMode = ";
526   anUpdatedScript += isPublished;
527   anUpdatedScript += "\n\tif isGUIMode:";
528   anUpdatedScript += "\n\t\tsmeshgui = salome.ImportComponentGUI(\"SMESH\")";
529   anUpdatedScript += "\n\t\tsmeshgui.Init(theStudy._get_StudyId())";
530   anUpdatedScript += "\n";
531
532   TCollection_AsciiString aGUIName;
533   Resource_DataMapOfAsciiStringAsciiString mapEntries;
534   for (Standard_Integer i = 1; i <= aLen; i += 2) {
535     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
536     aName = geom->GetDumpName( anEntry.ToCString() );
537     if (aName.IsEmpty() && // Not a GEOM object
538         theNames.IsBound(anEntry) &&
539         !mapEntries.IsBound(anEntry) && // Not yet processed
540         !mapRemoved.IsBound(anEntry)) { // Was not removed
541       aName = theObjectNames.Find(anEntry);
542       aGUIName = theNames.Find(anEntry);
543       mapEntries.Bind(anEntry, aName);
544       anUpdatedScript += "\n\t\tsmeshgui.SetName(salome.ObjectToID(";
545       anUpdatedScript += aName + "), \"" + aGUIName + "\")";
546     }
547   }
548   anUpdatedScript += "\n\n\t\tsalome.sg.updateObjBrowser(0)";
549
550   anUpdatedScript += "\n\n\tpass\n";
551
552   aValidScript = true;
553
554   return anUpdatedScript;
555 }
556
557 //=============================================================================
558 /*!
559  *  GetNewPythonLines
560  */
561 //=============================================================================
562 TCollection_AsciiString SMESH_Gen_i::GetNewPythonLines (int theStudyID)
563 {
564   TCollection_AsciiString aScript;
565
566   // Dump trace of API methods calls
567   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
568     Handle(TColStd_HSequenceOfAsciiString) aPythonScript = myPythonScripts[theStudyID];
569     Standard_Integer istr, aLen = aPythonScript->Length();
570     for (istr = 1; istr <= aLen; istr++) {
571       aScript += "\n\t";
572       aScript += aPythonScript->Value(istr);
573     }
574     aScript += "\n";
575   }
576
577   return aScript;
578 }
579
580 //=============================================================================
581 /*!
582  *  CleanPythonTrace
583  */
584 //=============================================================================
585 void SMESH_Gen_i::CleanPythonTrace (int theStudyID)
586 {
587   TCollection_AsciiString aScript;
588
589   // Clean trace of API methods calls
590   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
591     myPythonScripts[theStudyID]->Clear();
592   }
593 }