Salome HOME
Merge from V5_1_main branch 24/11/2010
[modules/smesh.git] / src / SMESH_I / SMESH_DumpPython.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File    : SMESH_Gen_i_DumpPython.cxx
24 // Created : Thu Mar 24 17:17:59 2005
25 // Author  : Julia DOROVSKIKH
26 // Module  : SMESH
27 // $Header : $
28 //
29 #include "SMESH_PythonDump.hxx"
30 #include "SMESH_Gen_i.hxx"
31 #include "SMESH_Filter_i.hxx"
32 #include "SMESH_MeshEditor_i.hxx"
33 #include "SMESH_2smeshpy.hxx"
34
35 #include <TColStd_HSequenceOfInteger.hxx>
36 #include <TCollection_AsciiString.hxx>
37 #include <SMESH_Comment.hxx>
38
39
40 #ifdef _DEBUG_
41 static int MYDEBUG = 0;
42 #else
43 static int MYDEBUG = 0;
44 #endif
45
46 static TCollection_AsciiString NotPublishedObjectName()
47 {
48   return "__NOT__Published__Object__";
49 }
50
51 namespace SMESH
52 {
53
54   size_t TPythonDump::myCounter = 0;
55
56   TPythonDump::
57   TPythonDump()
58   {
59     ++myCounter;
60   }
61   TPythonDump::
62   ~TPythonDump()
63   {
64     if(--myCounter == 0){
65       SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
66       std::string aString = myStream.str();
67       TCollection_AsciiString aCollection(Standard_CString(aString.c_str()));
68       SALOMEDS::Study_ptr aStudy = aSMESHGen->GetCurrentStudy();
69       if(!aStudy->_is_nil() && !aCollection.IsEmpty()){
70         aSMESHGen->AddToPythonScript(aStudy->StudyId(),aCollection);
71         if(MYDEBUG) MESSAGE(aString);
72       }
73     }
74   }
75
76   TPythonDump& 
77   TPythonDump::
78   operator<<(long int theArg){
79     myStream<<theArg;
80     return *this;
81   }
82
83   TPythonDump& 
84   TPythonDump::
85   operator<<(int theArg){
86     myStream<<theArg;
87     return *this;
88   }
89
90   TPythonDump& 
91   TPythonDump::
92   operator<<(double theArg){
93     myStream<<theArg;
94     return *this;
95   }
96
97   TPythonDump& 
98   TPythonDump::
99   operator<<(float theArg){
100     myStream<<theArg;
101     return *this;
102   }
103
104   TPythonDump& 
105   TPythonDump::
106   operator<<(const void* theArg){
107     myStream<<theArg;
108     return *this;
109   }
110
111   TPythonDump& 
112   TPythonDump::
113   operator<<(const char* theArg){
114     if ( theArg )
115       myStream<<theArg;
116     return *this;
117   }
118
119   TPythonDump& 
120   TPythonDump::
121   operator<<(const SMESH::ElementType& theArg)
122   {
123     myStream<<"SMESH.";
124     switch(theArg){
125     case ALL:   myStream<<"ALL";break;
126     case NODE:  myStream<<"NODE";break;
127     case EDGE:  myStream<<"EDGE";break;
128     case FACE:  myStream<<"FACE";break;
129     case VOLUME:myStream<<"VOLUME";break;
130     }
131     return *this;
132   }
133
134   TPythonDump&
135   TPythonDump::
136   operator<<(const SMESH::GeometryType& theArg)
137   {
138     myStream<<"SMESH.";
139     switch(theArg){
140     case Geom_POINT:      myStream<<"Geom_POINT";      break;
141     case Geom_EDGE:       myStream<<"Geom_EDGE";       break;
142     case Geom_TRIANGLE:   myStream<<"Geom_TRIANGLE";   break;
143     case Geom_QUADRANGLE: myStream<<"Geom_QUADRANGLE"; break;
144     case Geom_POLYGON:    myStream<<"Geom_POLYGON";    break;
145     case Geom_TETRA:      myStream<<"Geom_TETRA";      break;
146     case Geom_PYRAMID:    myStream<<"Geom_PYRAMID";    break;
147     case Geom_HEXA:       myStream<<"Geom_HEXA";       break;
148     case Geom_PENTA:      myStream<<"Geom_PENTA";      break;
149     case Geom_POLYHEDRA:  myStream<<"Geom_POLYHEDRA";  break;
150    }
151     return *this;
152   }
153
154   template<class TArray>
155   void DumpArray(const TArray& theArray, TPythonDump & theStream)
156   {
157     theStream << "[ ";
158     for (int i = 1; i <= theArray.length(); i++) {
159       theStream << theArray[i-1];
160       if ( i < theArray.length() )
161         theStream << ", ";
162     }
163     theStream << " ]";
164   }
165
166   TPythonDump& 
167   TPythonDump::operator<<(const SMESH::long_array& theArg)
168   {
169     DumpArray( theArg, *this );
170     return *this;
171   }
172
173   TPythonDump& 
174   TPythonDump::operator<<(const SMESH::double_array& theArg)
175   {
176     DumpArray( theArg, *this );
177     return *this;
178   }
179
180   TPythonDump& 
181   TPythonDump::
182   operator<<(SALOMEDS::SObject_ptr aSObject)
183   {
184     if ( !aSObject->_is_nil() )
185       myStream << aSObject->GetID();
186     else
187       myStream << NotPublishedObjectName();
188     return *this;
189   }
190
191   TPythonDump& 
192   TPythonDump::
193   operator<<(CORBA::Object_ptr theArg)
194   {
195     SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
196     SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy();
197     SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg);
198     if(!aSObject->_is_nil()) {
199       CORBA::String_var id = aSObject->GetID();
200       myStream << id;
201     } else if ( !CORBA::is_nil(theArg)) {
202       if ( aSMESHGen->CanPublishInStudy( theArg )) // not published SMESH object
203         myStream << "smeshObj_" << size_t(theArg);
204       else
205         myStream << NotPublishedObjectName();
206     }
207     else
208       myStream << "None";
209     return *this;
210   }
211
212   TPythonDump& 
213   TPythonDump::
214   operator<<(SMESH::SMESH_Hypothesis_ptr theArg)
215   {
216     SALOMEDS::Study_var aStudy = SMESH_Gen_i::GetSMESHGen()->GetCurrentStudy();
217     SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg);
218     if(aSObject->_is_nil() && !CORBA::is_nil(theArg))
219       myStream << "hyp_" << theArg->GetId();
220     else
221       *this << CORBA::Object_ptr( theArg );
222     return *this;
223   }
224
225   TPythonDump& 
226   TPythonDump::
227   operator<<(SMESH::SMESH_IDSource_ptr theArg)
228   {
229     SMESH_Gen_i* aSMESHGen = SMESH_Gen_i::GetSMESHGen();
230     SALOMEDS::Study_var aStudy = aSMESHGen->GetCurrentStudy();
231     SALOMEDS::SObject_var aSObject = SMESH_Gen_i::ObjectToSObject(aStudy,theArg);
232     if(!aSObject->_is_nil() || CORBA::is_nil( theArg ))
233       return *this << aSObject;
234     SMESH::long_array_var anElementsId = theArg->GetIDs();
235     return *this << anElementsId;
236   }
237
238   TPythonDump& 
239   TPythonDump::
240   operator<<(SMESH::FilterLibrary_i* theArg)
241   {
242     myStream<<"aFilterLibrary"<<theArg;
243     return *this;
244   }
245
246   TPythonDump& 
247   TPythonDump::
248   operator<<(SMESH::FilterManager_i* theArg)
249   {
250     myStream<<"aFilterManager";
251     return *this;
252   }
253
254   TPythonDump& 
255   TPythonDump::
256   operator<<(SMESH::Filter_i* theArg)
257   {
258     myStream<<"aFilter"<<theArg;
259     return *this;
260   }
261
262   TPythonDump& 
263   TPythonDump::
264   operator<<(SMESH::Functor_i* theArg)
265   {
266     if ( theArg ) {
267       FunctorType aFunctorType = theArg->GetFunctorType();
268       switch(aFunctorType){
269       case FT_AspectRatio:      myStream<< "anAspectRatio";     break;
270       case FT_AspectRatio3D:    myStream<< "anAspectRatio3D";   break;
271       case FT_Warping:          myStream<< "aWarping";          break;
272       case FT_MinimumAngle:     myStream<< "aMinimumAngle";     break;
273       case FT_Taper:            myStream<< "aTaper";            break;
274       case FT_Skew:             myStream<< "aSkew";             break;
275       case FT_Area:             myStream<< "aArea";             break;
276       case FT_Volume3D:         myStream<< "aVolume3D";         break;
277       case FT_MaxElementLength2D:myStream<< "aMaxElementLength2D";break;
278       case FT_MaxElementLength3D:myStream<< "aMaxElementLength3D";break;
279       case FT_FreeBorders:      myStream<< "aFreeBorders";      break;
280       case FT_FreeEdges:        myStream<< "aFreeEdges";        break;
281       case FT_FreeNodes:        myStream<< "aFreeNodes";        break;
282       case FT_FreeFaces:        myStream<< "aFreeFaces";        break;
283       case FT_MultiConnection:  myStream<< "aMultiConnection";  break;
284       case FT_MultiConnection2D:myStream<< "aMultiConnection2D";break;
285       case FT_Length:           myStream<< "aLength";           break;
286       case FT_Length2D:         myStream<< "aLength";           break;
287       case FT_BelongToGeom:     myStream<< "aBelongToGeom";     break;
288       case FT_BelongToPlane:    myStream<< "aBelongToPlane";    break;
289       case FT_BelongToCylinder: myStream<< "aBelongToCylinder"; break;
290       case FT_BelongToGenSurface:myStream<<"aBelongToGenSurface";break;
291       case FT_LyingOnGeom:      myStream<< "aLyingOnGeom";      break;
292       case FT_CoplanarFaces:    myStream<< "aCoplanarFaces";    break;
293       case FT_RangeOfIds:       myStream<< "aRangeOfIds";       break;
294       case FT_BadOrientedVolume:myStream<< "aBadOrientedVolume";break;
295       case FT_LinearOrQuadratic:myStream<< "aLinearOrQuadratic";break;
296       case FT_GroupColor:       myStream<< "aGroupColor";       break;
297       case FT_ElemGeomType:     myStream<< "anElemGeomType";    break;
298       case FT_LessThan:         myStream<< "aLessThan";         break;
299       case FT_MoreThan:         myStream<< "aMoreThan";         break;
300       case FT_EqualTo:          myStream<< "anEqualTo";         break;
301       case FT_LogicalNOT:       myStream<< "aLogicalNOT";       break;
302       case FT_LogicalAND:       myStream<< "aLogicalAND";       break;
303       case FT_LogicalOR:        myStream<< "aLogicalOR";        break;
304       case FT_Undefined:
305       default:                  myStream<< "anUndefined";       break;
306       }
307       myStream<<theArg;
308     }
309     return *this;
310   }
311
312   TPythonDump& 
313   TPythonDump::
314   operator<<(SMESH::Measurements_i* theArg)
315   {
316     myStream<<"aMeasurements";
317     return *this;
318   }
319
320
321   TPythonDump& TPythonDump:: operator<<(SMESH_Gen_i* theArg)
322   {
323     myStream << SMESHGenName(); return *this;
324   }
325
326   TPythonDump& TPythonDump::operator<<(SMESH_MeshEditor_i* theArg)
327   {
328     myStream << MeshEditorName() << "_" << ( theArg ? theArg->GetMeshId() : -1 ); return *this;
329   }
330
331   TPythonDump& TPythonDump::operator<<(const TCollection_AsciiString & theStr)
332   {
333     myStream << theStr; return *this;
334   }
335
336
337   TPythonDump& TPythonDump::operator<<(SMESH::MED_VERSION theVersion)
338   {
339     switch (theVersion) {
340     case SMESH::MED_V2_1: myStream << "SMESH.MED_V2_1"; break;
341     case SMESH::MED_V2_2: myStream << "SMESH.MED_V2_2"; break;
342     default: myStream << theVersion;
343     }
344     return *this;
345   }
346
347   TPythonDump& TPythonDump::operator<<(const SMESH::AxisStruct & theAxis)
348   {
349     myStream << "SMESH.AxisStruct( "
350              << theAxis.x  << ", "
351              << theAxis.y  << ", "
352              << theAxis.z  << ", "
353              << theAxis.vx << ", "
354              << theAxis.vy << ", "
355              << theAxis.vz << " )";
356     return *this;
357   }
358
359   TPythonDump& TPythonDump::operator<<(const SMESH::DirStruct & theDir)
360   {
361     const SMESH::PointStruct & P = theDir.PS;
362     myStream << "SMESH.DirStruct( SMESH.PointStruct ( "
363              << P.x  << ", "
364              << P.y  << ", "
365              << P.z  << " ))";
366     return *this;
367   }
368
369   TPythonDump& TPythonDump::operator<<(const SMESH::ListOfGroups& theList)
370   {
371     DumpArray( theList, *this );
372     return *this;
373   }
374   TPythonDump& TPythonDump::operator<<(const SMESH::ListOfIDSources& theList)
375   {
376     DumpArray( theList, *this );
377     return *this;
378   }
379
380   TCollection_AsciiString myLongStringStart( "TPythonDump::LongStringStart" );
381   TCollection_AsciiString myLongStringEnd  ( "TPythonDump::LongStringEnd" );
382
383   //================================================================================
384   /*!
385    * \brief Return marker of long string literal beginning
386    * \param type - a name of functionality producing the string literal 
387    * \retval TCollection_AsciiString - the marker string to be written into
388    * a raw python script
389    */
390   //================================================================================
391
392   TCollection_AsciiString TPythonDump::LongStringStart(const char* type)
393   {
394     return
395       myLongStringStart +
396       (Standard_Integer) strlen(type) +
397       " " +
398       (char*) type;
399   }
400
401   //================================================================================
402   /*!
403      * \brief Return marker of long string literal end
404       * \retval TCollection_AsciiString - the marker string to be written into
405       * a raw python script
406    */
407   //================================================================================
408
409   TCollection_AsciiString TPythonDump::LongStringEnd()
410   {
411     return myLongStringEnd;
412   }
413
414   //================================================================================
415   /*!
416      * \brief Cut out a long string literal from a string
417       * \param theText - text possibly containing string literals
418       * \param theFrom - position in the text to search from
419       * \param theLongString - the retrieved literal
420       * \param theStringType - a name of functionality produced the literal
421       * \retval bool - true if a string literal found
422      * 
423      * The literal is removed from theText; theFrom points position right after
424      * the removed literal
425    */
426   //================================================================================
427
428   bool  TPythonDump::CutoutLongString( TCollection_AsciiString & theText,
429                                        int                     & theFrom,
430                                        TCollection_AsciiString & theLongString,
431                                        TCollection_AsciiString & theStringType)
432   {
433     if ( theFrom < 1 || theFrom > theText.Length() )
434       return false;
435
436     // ...script \  beg marker    \ \ type \       literal              \  end marker  \ script...
437     //  "theText myLongStringStart7 Pattern!!! SALOME Mesh Pattern file myLongStringEndtextEnd"
438     //  012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
439     //  0         1         2         3         4         5         6         7         8
440
441     theFrom = theText.Location( myLongStringStart, theFrom, theText.Length() ); // = 09
442     if ( !theFrom )
443       return false;
444
445     // find where literal begins
446     int literalBeg = theFrom + myLongStringStart.Length(); // = 26
447     char* typeLenStr = (char*) theText.ToCString() + literalBeg - 1; // = "7 Pattern!!! SALO...."
448     int typeLen = atoi ( typeLenStr ); // = 7
449     while ( *typeLenStr != ' ' ) { // look for ' ' after typeLen
450       literalBeg++; // 26 -> 27
451       typeLenStr++;
452     }
453     literalBeg += typeLen + 1; // = 35
454     if ( literalBeg > theText.Length() )
455       return false;
456
457     // where literal ends (i.e. end marker begins)
458     int literalEnd = theText.Location( myLongStringEnd, literalBeg, theText.Length() ); // = 64
459     if ( !literalEnd )
460       literalEnd = theText.Length();
461
462     // literal
463     theLongString = theText.SubString( literalBeg, literalEnd - 1); // "!!! SALOME Mesh Pattern file "
464     // type
465     theStringType = theText.SubString( literalBeg - typeLen, literalBeg - 1 ); // "Pattern"
466     // cut off literal
467     literalEnd += myLongStringEnd.Length(); // = 79
468     TCollection_AsciiString textEnd = theText.SubString( literalEnd, theText.Length() ); // "textE..."
469     theText = theText.SubString( 1, theFrom - 1 ) + textEnd;
470
471     return true;
472   }
473 }
474
475 //=======================================================================
476 //function : DumpPython
477 //purpose  : 
478 //=======================================================================
479 Engines::TMPFile* SMESH_Gen_i::DumpPython (CORBA::Object_ptr theStudy,
480                                            CORBA::Boolean isPublished,
481                                            CORBA::Boolean& isValidScript)
482 {
483   SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(theStudy);
484   if (CORBA::is_nil(aStudy))
485     return new Engines::TMPFile(0);
486
487   SALOMEDS::SObject_var aSO = aStudy->FindComponent(ComponentDataType());
488   if (CORBA::is_nil(aSO))
489     return new Engines::TMPFile(0);
490
491   // Map study entries to object names
492   Resource_DataMapOfAsciiStringAsciiString aMap;
493   Resource_DataMapOfAsciiStringAsciiString aMapNames;
494   //TCollection_AsciiString s ("qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_");
495
496   SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO);
497   for (Itr->InitEx(true); Itr->More(); Itr->Next()) {
498     SALOMEDS::SObject_var aValue = Itr->Value();
499     CORBA::String_var anID = aValue->GetID();
500     CORBA::String_var aName = aValue->GetName();
501     TCollection_AsciiString aGUIName ( (char*) aName.in() );
502     TCollection_AsciiString anEnrty ( (char*) anID.in() );
503     if (aGUIName.Length() > 0) {
504       aMapNames.Bind( anEnrty, aGUIName );
505       aMap.Bind( anEnrty, aGUIName );
506     }
507   }
508
509   // Get trace of restored study
510   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
511   SALOMEDS::StudyBuilder_var aStudyBuilder = aStudy->NewBuilder();
512   SALOMEDS::GenericAttribute_var anAttr =
513     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
514
515   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
516   TCollection_AsciiString aSavedTrace (oldValue);
517
518   // Add trace of API methods calls and replace study entries by names
519   TCollection_AsciiString aScript;
520   aScript += DumpPython_impl(aStudy, aMap, aMapNames,
521                              isPublished, isValidScript, aSavedTrace);
522
523   int aLen = aScript.Length(); 
524   unsigned char* aBuffer = new unsigned char[aLen+1];
525   strcpy((char*)aBuffer, aScript.ToCString());
526
527   CORBA::Octet* anOctetBuf =  (CORBA::Octet*)aBuffer;
528   Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aLen+1, aLen+1, anOctetBuf, 1); 
529
530   bool hasNotPublishedObjects = aScript.Location( NotPublishedObjectName(), 1, aLen);
531   isValidScript = isValidScript && !hasNotPublishedObjects;
532
533   return aStreamFile._retn(); 
534 }
535
536 //=============================================================================
537 /*!
538  *  AddToPythonScript
539  */
540 //=============================================================================
541 void SMESH_Gen_i::AddToPythonScript (int theStudyID, const TCollection_AsciiString& theString)
542 {
543   if (myPythonScripts.find(theStudyID) == myPythonScripts.end()) {
544     myPythonScripts[theStudyID] = new TColStd_HSequenceOfAsciiString;
545   }
546   myPythonScripts[theStudyID]->Append(theString);
547 }
548
549 //=============================================================================
550 /*!
551  *  RemoveLastFromPythonScript
552  */
553 //=============================================================================
554 void SMESH_Gen_i::RemoveLastFromPythonScript (int theStudyID)
555 {
556   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
557     int aLen = myPythonScripts[theStudyID]->Length();
558     myPythonScripts[theStudyID]->Remove(aLen);
559   }
560 }
561
562 //=======================================================================
563 //function : SavePython
564 //purpose  : 
565 //=======================================================================
566 void SMESH_Gen_i::SavePython (SALOMEDS::Study_ptr theStudy)
567 {
568   // Dump trace of API methods calls
569   TCollection_AsciiString aScript = GetNewPythonLines(theStudy->StudyId());
570
571   // Check contents of PythonObject attribute
572   SALOMEDS::SObject_var aSO = theStudy->FindComponent(ComponentDataType());
573   //SALOMEDS::SObject_var aSO = SMESH_Gen_i::ObjectToSObject(theStudy, _this());
574   SALOMEDS::StudyBuilder_var aStudyBuilder = theStudy->NewBuilder();
575   SALOMEDS::GenericAttribute_var anAttr =
576     aStudyBuilder->FindOrCreateAttribute(aSO, "AttributePythonObject");
577
578   char* oldValue = SALOMEDS::AttributePythonObject::_narrow(anAttr)->GetObject();
579   TCollection_AsciiString oldScript (oldValue);
580
581   if (oldScript.Length() > 0) {
582     oldScript += "\n";
583     oldScript += aScript;
584   } else {
585     oldScript = aScript;
586   }
587
588   // Store in PythonObject attribute
589   SALOMEDS::AttributePythonObject::_narrow(anAttr)->SetObject(oldScript.ToCString(), 1);
590
591   // Clean trace of API methods calls
592   CleanPythonTrace(theStudy->StudyId());
593 }
594
595
596 // impl
597
598
599 //=============================================================================
600 /*!
601  *  FindEntries: Returns a sequence of start/end positions of entries in the string
602  */
603 //=============================================================================
604 Handle(TColStd_HSequenceOfInteger) FindEntries (TCollection_AsciiString& theString)
605 {
606   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
607   Standard_Integer aLen = theString.Length();
608   Standard_Boolean isFound = Standard_False;
609
610   char* arr = (char*) theString.ToCString();
611   Standard_Integer i = 0, j;
612
613   while(i < aLen) {
614     int c = (int)arr[i];
615     j = i+1;
616     if ( isdigit( c )) { //Is digit?
617  
618       isFound = Standard_False;
619       while((j < aLen) && ( isdigit(c) || c == ':' )) { //Check if it is an entry
620         c = (int)arr[j++];  
621         if(c == ':') isFound = Standard_True;
622       }
623
624       if (isFound) {
625         int prev = (i < 1) ? 0 : (int)arr[i - 1];
626         // to distinguish from a sketcher command:
627         // last char should be a digit, not ":",
628         // previous char should not be '"'.
629         if (arr[j-2] != ':' && prev != '"') {
630           aSeq->Append(i+1); // +1 because AsciiString starts from 1
631           aSeq->Append(j-1);
632         }
633       }
634     }
635
636     i = j;
637   }
638
639   return aSeq;
640 }
641
642 namespace {
643
644   //================================================================================
645   /*!
646    * \brief Make a string be a valid python name
647     * \param aName - a string to fix
648     * \retval bool - true if aName was not modified
649    */
650   //================================================================================
651
652   bool fixPythonName(TCollection_AsciiString & aName )
653   {
654     const TCollection_AsciiString allowedChars =
655       "qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_";
656     bool isValidName = true;
657     int p=1; // replace not allowed chars with underscore
658     while (p <= aName.Length() &&
659            (p = aName.FirstLocationNotInSet(allowedChars, p, aName.Length())))
660     {
661       if ( p == 1 || p == aName.Length() || aName.Value(p-1) == '_')
662         aName.Remove( p, 1 ); // remove double _ and from the start and the end
663       else
664         aName.SetValue(p, '_');
665       isValidName = false;
666     }
667     if ( aName.IsIntegerValue() ) { // aName must not start with a digit
668       aName.Insert( 1, 'a' );
669       isValidName = false;
670     }
671     return isValidName;
672   }
673 }
674
675 //=============================================================================
676 /*!
677  *  DumpPython
678  */
679 //=============================================================================
680 TCollection_AsciiString SMESH_Gen_i::DumpPython_impl
681                         (SALOMEDS::Study_ptr theStudy, 
682                          Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
683                          Resource_DataMapOfAsciiStringAsciiString& theNames,
684                          bool isPublished, 
685                          bool& aValidScript,
686                          const TCollection_AsciiString& theSavedTrace)
687 {
688   int aStudyID = theStudy->StudyId();
689
690   TCollection_AsciiString helper; // to comfortably concatenate C strings
691   TCollection_AsciiString aSmeshpy( SMESH_2smeshpy::SmeshpyName() );
692   TCollection_AsciiString aSMESHGen( SMESH_2smeshpy::GenName() );
693   TCollection_AsciiString anOldGen( SMESH::TPythonDump::SMESHGenName() );
694
695   TCollection_AsciiString aScript;
696   aScript = "def RebuildData(theStudy):\n\t";
697   aScript += helper + "aFilterManager = " + aSMESHGen + ".CreateFilterManager()\n\t";
698   aScript += helper + "aMeasurements = " + aSMESHGen + ".CreateMeasurements()\n\t";
699   if ( isPublished )
700     aScript += aSMESHGen + ".SetCurrentStudy(theStudy)";
701   else
702     aScript += aSMESHGen + ".SetCurrentStudy(None)";
703
704   // import python files corresponding to plugins
705   set<string> moduleNameSet;
706   map<string, GenericHypothesisCreator_i*>::iterator hyp_creator = myHypCreatorMap.begin();
707   for ( ; hyp_creator != myHypCreatorMap.end(); ++hyp_creator ) {
708     string moduleName = hyp_creator->second->GetModuleName();
709     bool newModule = moduleNameSet.insert( moduleName ).second;
710     if ( newModule )
711       aScript += helper + "\n\t" + "import " + (char*) moduleName.c_str();
712   }
713
714   // Dump trace of restored study
715   if (theSavedTrace.Length() > 0) {
716     // For the convertion of IDL API calls -> smesh.py API, "smesh" standing for SMESH_Gen
717     // was replaces with "smeshgen" (==TPythonDump::SMESHGenName()).
718     // Change "smesh" -> "smeshgen" in the trace saved before passage to smesh.py API
719     bool isNewVersion =
720       theSavedTrace.Location( anOldGen + ".", 1, theSavedTrace.Length() );
721     if ( !isNewVersion ) {
722       TCollection_AsciiString aSavedTrace( theSavedTrace );
723       TCollection_AsciiString aSmeshCall ( "smesh." ), gen( "gen" );
724       int beg, end = aSavedTrace.Length(), from = 1;
725       while ( from < end && ( beg = aSavedTrace.Location( aSmeshCall, from, end ))) {
726         char charBefore = ( beg == 1 ) ? ' ' : aSavedTrace.Value( beg - 1 );
727         if ( isspace( charBefore ) || charBefore == '=' ) { // "smesh." is not a part of a long word
728           aSavedTrace.Insert( beg + aSmeshCall.Length() - 1, gen );// "smesh" -> "smeshgen"
729           end += gen.Length();
730         }
731         from = beg + aSmeshCall.Length();
732       }
733       aScript += helper + "\n" + aSavedTrace;
734     }
735     else
736       // append a saved trace to the script
737       aScript += helper + "\n" + theSavedTrace;
738   }
739
740   // Dump trace of API methods calls
741   TCollection_AsciiString aNewLines = GetNewPythonLines(aStudyID);
742   if (aNewLines.Length() > 0) {
743     aScript += helper + "\n" + aNewLines;
744   }
745
746   // Convert IDL API calls into smesh.py API.
747   // Some objects are wrapped with python classes and
748   // Resource_DataMapOfAsciiStringAsciiString holds methods returning wrapped objects
749   Resource_DataMapOfAsciiStringAsciiString anEntry2AccessorMethod;
750   aScript = SMESH_2smeshpy::ConvertScript( aScript, anEntry2AccessorMethod, theObjectNames );
751
752   // Find entries to be replaced by names
753   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
754   Standard_Integer aLen = aSeq->Length();
755
756   if (aLen == 0)
757     return aScript;
758
759   // Replace entries by the names
760   GEOM::GEOM_Gen_ptr geom = GetGeomEngine();
761   TColStd_SequenceOfAsciiString seqRemoved;
762   Resource_DataMapOfAsciiStringAsciiString mapRemoved;
763   Standard_Integer objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
764   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("smeshObj_");
765
766   // Collect names of GEOM objects to exclude same names for SMESH objects
767   GEOM::string_array_var aGeomNames = geom->GetAllDumpNames();
768   int ign = 0, nbgn = aGeomNames->length();
769   for (; ign < nbgn; ign++) {
770     aName = aGeomNames[ign];
771     theObjectNames.Bind(aName, "1");
772   }
773
774   bool importGeom = false;
775   for (Standard_Integer i = 1; i <= aLen; i += 2) {
776     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i) - 1);
777     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
778     // is a GEOM object?
779     aName = geom->GetDumpName( anEntry.ToCString() );
780     if (aName.IsEmpty()) {
781       // is a SMESH object
782       if (theObjectNames.IsBound(anEntry)) {
783         // The Object is in Study
784         aName = theObjectNames.Find(anEntry);
785         // check validity of aName
786         bool isValidName = fixPythonName( aName );
787         if (theObjectNames.IsBound(aName) && anEntry != theObjectNames(aName)) {
788           // diff objects have same name - make a new name by appending a digit
789           TCollection_AsciiString aName2;
790           Standard_Integer i = 0;
791           do {
792             aName2 = aName + "_" + ++i;
793           } while (theObjectNames.IsBound(aName2) && anEntry != theObjectNames(aName2));
794           aName = aName2;
795           isValidName = false;
796         }
797         if ( !isValidName )
798           theObjectNames(anEntry) = aName;
799
800       } else {
801         // Removed Object
802         do {
803           aName = aBaseName + (++objectCounter);
804         } while (theObjectNames.IsBound(aName));
805         seqRemoved.Append(aName);
806         mapRemoved.Bind(anEntry, "1");
807         theObjectNames.Bind(anEntry, aName);
808       }
809       theObjectNames.Bind(aName, anEntry); // to detect same name of diff objects
810     }
811     else
812     {
813       importGeom = true;
814     }
815     anUpdatedScript += aName;
816     aStart = aSeq->Value(i + 1) + 1;
817   }
818
819   // set initial part of aSript
820   TCollection_AsciiString initPart = "import salome, SMESH, SALOMEDS\n";
821   initPart += helper + "import " + aSmeshpy + "\n\n";
822   if ( importGeom )
823   {
824     initPart += ("## import GEOM dump file ## \n"
825                  "import string, os, sys, re\n"
826                  "sys.path.insert( 0, os.path.dirname(__file__) )\n"
827                  "exec(\"from \"+re.sub(\"SMESH$\",\"GEOM\",__name__)+\" import *\")\n\n");
828   }
829   anUpdatedScript.Insert ( 1, initPart );
830
831   // add final part of aScript
832   if (aSeq->Value(aLen) < aScriptLength)
833     anUpdatedScript += aScript.SubString(aSeq->Value(aLen) + 1, aScriptLength);
834
835   // Set colors
836   SALOMEDS::SObject_var aComp = theStudy->FindComponent(ComponentDataType());
837   if( !CORBA::is_nil(aComp) )
838   {
839     SALOMEDS::ChildIterator_var Itr = theStudy->NewChildIterator(aComp);
840     for( Itr->InitEx(true); Itr->More(); Itr->Next() )
841     {
842       SALOMEDS::SObject_var aSObj = Itr->Value();
843       SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( SObjectToObject( aSObj ) );
844       // mesh auto color
845       if( !CORBA::is_nil(aMesh) && aMesh->GetAutoColor() )
846       {
847         CORBA::String_var anEntry = aSObj->GetID();
848         anUpdatedScript +=
849           SMESH_Comment("\n\t") << theObjectNames(anEntry.inout()) << ".SetAutoColor(1)";
850       }
851       SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( SObjectToObject(aSObj));
852       if( !CORBA::is_nil(aGroup) )
853       {
854         SALOMEDS::Color aColor = aGroup->GetColor();
855         if ( aColor.R >= 0 || aColor.G >= 0 || aColor.B >= 0 )
856         {
857           CORBA::String_var anEntry = aSObj->GetID();
858           anUpdatedScript += SMESH_Comment("\n\t")
859             << theObjectNames(anEntry.inout()) << ".SetColor(SALOMEDS.Color("
860             << aColor.R <<", "<< aColor.G <<", "<< aColor.B <<" ))";
861         }
862       }
863     }
864   }
865
866   // Remove removed objects
867   if ( seqRemoved.Length() > 0 ) {
868     anUpdatedScript += "\n\t## some objects were removed";
869     anUpdatedScript += "\n\taStudyBuilder = theStudy.NewBuilder()";
870   }
871   for (int ir = 1; ir <= seqRemoved.Length(); ir++) {
872     anUpdatedScript += "\n\tSO = theStudy.FindObjectIOR(theStudy.ConvertObjectToIOR(";
873     anUpdatedScript += seqRemoved.Value(ir);
874     // for object wrapped by class of smesh.py
875     anEntry = theObjectNames( seqRemoved.Value(ir) );
876     if ( anEntry2AccessorMethod.IsBound( anEntry ) )
877       anUpdatedScript += helper + "." + anEntry2AccessorMethod( anEntry );
878     anUpdatedScript += "))\n\tif SO is not None: aStudyBuilder.RemoveObjectWithChildren(SO)";
879   }
880
881   // Set object names
882   anUpdatedScript += "\n\t## set object names";
883 //   anUpdatedScript += "\n\t\tsmeshgui = salome.ImportComponentGUI(\"SMESH\")";
884 //   anUpdatedScript += "\n\t\tsmeshgui.Init(theStudy._get_StudyId())";
885 //   anUpdatedScript += "\n";
886
887   TCollection_AsciiString aGUIName;
888   Resource_DataMapOfAsciiStringAsciiString mapEntries;
889   for (Standard_Integer i = 1; i <= aLen; i += 2)
890   {
891     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i + 1));
892     aName = geom->GetDumpName( anEntry.ToCString() );
893     if (aName.IsEmpty() && // Not a GEOM object
894         theNames.IsBound(anEntry) &&
895         !mapEntries.IsBound(anEntry) && // Not yet processed
896         !mapRemoved.IsBound(anEntry)) // Was not removed
897     {
898       aName = theObjectNames.Find(anEntry);
899       aGUIName = theNames.Find(anEntry);
900       mapEntries.Bind(anEntry, aName);
901       anUpdatedScript += helper + "\n\t" + aSMESHGen + ".SetName(" + aName;
902       if ( anEntry2AccessorMethod.IsBound( anEntry ) )
903         anUpdatedScript += helper + "." + anEntry2AccessorMethod( anEntry );
904       anUpdatedScript += helper + ", '" + aGUIName + "')";
905     }
906   }
907   anUpdatedScript += "\n\tif salome.sg.hasDesktop():";
908   anUpdatedScript += "\n\t\tsalome.sg.updateObjBrowser(0)";
909
910   // -----------------------------------------------------------------
911   // store visual properties of displayed objects
912   // -----------------------------------------------------------------
913
914   if (isPublished)
915   {
916     //Output the script that sets up the visual parameters.
917     char* script = theStudy->GetDefaultScript(ComponentDataType(), "\t");
918     if (script && strlen(script) > 0) {
919       anUpdatedScript += "\n\n\t### Store presentation parameters of displayed objects\n";
920       anUpdatedScript += script;
921       CORBA::string_free(script);
922     }
923   }
924   anUpdatedScript += "\n\n\tpass\n";
925
926   // -----------------------------------------------------------------
927   // put string literals describing patterns into separate functions
928   // -----------------------------------------------------------------
929
930   TCollection_AsciiString aLongString, aFunctionType;
931   int where = 1;
932   set< string > functionNameSet;
933   while ( SMESH::TPythonDump::CutoutLongString( anUpdatedScript, where, aLongString, aFunctionType ))
934   {
935     // make a python string literal
936     aLongString.Prepend(":\n\treturn '''\n");
937     aLongString += "\n\t'''\n\tpass\n";
938
939     TCollection_AsciiString functionName;
940
941     // check if the function returning this literal is already defined
942     int posAlready = anUpdatedScript.Location( aLongString, where, anUpdatedScript.Length() );
943     if ( posAlready ) // already defined
944     {
945       // find the function name
946       int functBeg = posAlready;
947       char* script = (char*) anUpdatedScript.ToCString() + posAlready - 1; // look at ":" after "def fuction()"
948       while ( *script != ' ' ) {
949         script--;
950         functBeg--;
951       }
952       functBeg++; // do not take ' '
953       posAlready--; // do not take ':'
954       functionName = anUpdatedScript.SubString( functBeg, posAlready );
955     }
956     else // not defined yet
957     {
958       // find a unique function name
959       fixPythonName( aFunctionType );
960       Standard_Integer nb = 0;
961       do functionName = aFunctionType + "_" + ( nb++ ) + "()";
962       while ( !functionNameSet.insert( functionName.ToCString() ).second );
963
964       anUpdatedScript += helper + "\n\ndef " + functionName + aLongString; // define function
965     }
966     anUpdatedScript.InsertBefore( where, functionName ); // call function
967   }
968
969   aValidScript = true;
970
971   return anUpdatedScript;
972 }
973
974 //=============================================================================
975 /*!
976  *  GetNewPythonLines
977  */
978 //=============================================================================
979 TCollection_AsciiString SMESH_Gen_i::GetNewPythonLines (int theStudyID)
980 {
981   TCollection_AsciiString aScript;
982
983   // Dump trace of API methods calls
984   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
985     Handle(TColStd_HSequenceOfAsciiString) aPythonScript = myPythonScripts[theStudyID];
986     Standard_Integer istr, aLen = aPythonScript->Length();
987     for (istr = 1; istr <= aLen; istr++) {
988       aScript += "\n\t";
989       aScript += aPythonScript->Value(istr);
990     }
991     aScript += "\n";
992   }
993
994   return aScript;
995 }
996
997 //=============================================================================
998 /*!
999  *  CleanPythonTrace
1000  */
1001 //=============================================================================
1002 void SMESH_Gen_i::CleanPythonTrace (int theStudyID)
1003 {
1004   TCollection_AsciiString aScript;
1005
1006   // Clean trace of API methods calls
1007   if (myPythonScripts.find(theStudyID) != myPythonScripts.end()) {
1008     myPythonScripts[theStudyID]->Clear();
1009   }
1010 }