]> SALOME platform Git repositories - modules/kernel.git/blob - src/Notebook/SALOME_Notebook.cxx
Salome HOME
42074647c04e6bed6447259aa1a5511d9b9ae4dc
[modules/kernel.git] / src / Notebook / SALOME_Notebook.cxx
1 //  Copyright (C) 2007-2008  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 //  File   : SALOME_Notebook.cxx
23 //  Author : Alexandre SOLOVYOV
24 //  Module : SALOME
25 //
26
27 #include <SALOME_Notebook.hxx>
28 #include <SALOME_Parameter.hxx>
29 #include <SALOME_EvalParser.hxx>
30
31 std::string arg( const std::string& theStr, const std::string& theArg1 )
32 {
33   std::string aRes = theStr;
34   while( true )
35   {
36     int aPos = aRes.find( "%1" );
37     if( aPos >= 0 )
38       aRes.replace( aPos, 2, theArg1 );
39     else
40       break;
41   }
42   return aRes;
43 }
44
45 std::string arg( const std::string& theStr, const std::string& theArg1, const std::string& theArg2 )
46 {
47   std::string aRes = theStr;
48   while( true )
49   {
50     int aPos = aRes.find( "%1" );
51     if( aPos >= 0 )
52       aRes.replace( aPos, 2, theArg1 );
53     else
54     {
55       aPos = aRes.find( "%2" );
56       if( aPos >= 0 )
57         aRes.replace( aPos, 2, theArg2 );
58       else
59         break;
60     }
61   }
62   return aRes;
63 }
64
65 std::vector<std::string> split( const std::string& theData, const std::string& theSeparator, bool theIsKeepEmpty )
66 {
67   std::vector<std::string> aParts;
68   int aPrev = 0, anInd = 0;
69   while( anInd<theData.length() )
70   {
71     anInd = theData.find( theSeparator, aPrev );
72     if( anInd < 0 )
73       anInd = theData.length();
74
75     std::string aPart = theData.substr( aPrev, anInd - aPrev );
76     if( aPart.length() > 0 || theIsKeepEmpty )
77       aParts.push_back( aPart );
78
79     aPrev = anInd + 1;
80   }
81   return aParts;
82 }
83
84 void save( FILE* theFile, const std::string& theData )
85 {
86   short len = theData.length();
87   fwrite( &len, 1, sizeof( short ), theFile );
88   fwrite( theData.c_str(), 1, len, theFile );
89 }
90
91 void save( FILE* theFile, int theData )
92 {
93   fwrite( &theData, 1, sizeof( int ), theFile );
94 }
95
96 bool load( FILE* theFile, std::string& theData )
97 {
98   short len;
99   int rlen = fread( &len, 1, sizeof( short ), theFile );
100   if( rlen < sizeof( short ) )
101     return false;
102
103   char buf[1024];
104   rlen = fread( buf, 1, len, theFile );
105   if( rlen < len )
106     return false;
107
108   buf[len] = 0;
109   theData = buf;
110   //printf( "load: %s\n", theData.c_str() );
111   return true;
112 }
113
114 bool load( FILE* theFile, int& theData )
115 {
116   int rlen = fread( &theData, 1, sizeof( int ), theFile );
117   if( rlen < sizeof( int ) )
118     return false;
119
120   //printf( "load: %i\n", theData );
121   return true;
122 }
123
124
125
126
127
128
129
130
131 SALOME_Notebook::KeyHelper::KeyHelper( const std::string& theKey, const SALOME_Notebook* theNotebook )
132 : myKey( theKey ), myNotebook( theNotebook )
133 {
134 }
135
136 std::string SALOME_Notebook::KeyHelper::key() const
137 {
138   return myKey;
139 }
140
141 bool SALOME_Notebook::KeyHelper::operator < ( const KeyHelper& theKH ) const
142 {
143   bool ok;
144   if( myNotebook->HasDependency( myKey, theKH.myKey ) )
145     ok = false;
146   else if( myNotebook->HasDependency( theKH.myKey, myKey ) )
147     ok = true;
148   else
149   {
150     SALOME::ParameterizedObject_var anObj1 = myNotebook->FindObject( myKey );
151     SALOME::ParameterizedObject_var anObj2 = myNotebook->FindObject( theKH.myKey );
152     SALOME::Parameter_var aParamV1 = SALOME::Parameter::_narrow( anObj1 );
153     SALOME::Parameter_var aParamV2 = SALOME::Parameter::_narrow( anObj2 );
154     if( CORBA::is_nil( aParamV1 ) )
155       if( CORBA::is_nil( aParamV2 ) )
156         ok = myKey < theKH.myKey;
157       else
158         ok = false;
159     else
160       if( CORBA::is_nil( aParamV2 ) )
161         ok = true;
162       else
163       {
164         SALOME_Parameter* aParam1 = myNotebook->GetParameterPtr( aParamV1->GetEntry() );
165         SALOME_Parameter* aParam2 = myNotebook->GetParameterPtr( aParamV2->GetEntry() );
166         ok = aParam1->GetId() < aParam2->GetId();
167       }
168   }
169
170   //printf( "%s < %s ? %i\n", myKey.c_str(), theKH.myKey.c_str(), ok );
171   return ok;
172 }
173
174 bool SALOME_Notebook::KeyHelper::operator == ( const std::string& theKey ) const
175 {
176   return myKey == theKey;
177 }
178
179
180
181
182
183
184 SALOME_Notebook::SALOME_Notebook( PortableServer::POA_ptr thePOA, SALOMEDS::Study_ptr theStudy )
185 : SALOME::GenericObj_i( thePOA ), myUpdateOnlyParameters( false ), myMaxId( -1 )
186 {
187   myStudy = SALOMEDS::Study::_duplicate( theStudy );
188 }
189
190 void SALOME_Notebook::AddDependency( SALOME::ParameterizedObject_ptr theObj, SALOME::ParameterizedObject_ptr theRef )
191 {
192   AddDependency( GetKey( theObj ), GetKey( theRef ) );
193 }
194
195 void SALOME_Notebook::RemoveDependency( SALOME::ParameterizedObject_ptr theObj, SALOME::ParameterizedObject_ptr theRef )
196 {
197   //Utils_Locker lock( &myMutex );
198
199   std::string anObjKey = GetKey( theObj ), aRefKey = GetKey( theRef );
200   std::map< std::string, std::list<std::string> >::iterator it = myDependencies.find( anObjKey );
201   if( it == myDependencies.end() )
202     ThrowError( arg( "Dependency between '%1' and '%2' is not found", theObj->GetEntry(), theObj->GetEntry() ) );
203   else
204     it->second.remove( aRefKey );
205 }
206
207 void SALOME_Notebook::ClearDependencies( SALOME::ParameterizedObject_ptr theObj, SALOME::DependenciesType theType )
208 {
209   ClearDependencies( GetKey( theObj ), theType );
210 }
211
212 void SALOME_Notebook::SetToUpdate( SALOME::ParameterizedObject_ptr theObj )
213 {
214   //Utils_Locker lock( &myMutex );
215
216   //printf( "SetToUpdate: %s\n", GetKey( theObj ).c_str() );
217
218   SALOME::Parameter_var aParam = SALOME::Parameter::_narrow( theObj );
219   if( !CORBA::is_nil( aParam ) )
220   {
221     std::string anEntry = aParam->GetEntry();
222     std::map< std::string, SALOME_Parameter* >::const_iterator pit = myParameters.find( anEntry );
223     if( pit == myParameters.end() )
224       return;
225
226     SALOME_Parameter* aParamPtr = pit->second;
227     std::string aKey = GetKey( anEntry );
228     ClearDependencies( aKey, SALOME::All );
229     AddDependencies( aParamPtr );
230   }
231
232   /*
233   printf( "Dependencies:\n" );
234   std::map< std::string, std::list<std::string> >::const_iterator mit = myDependencies.begin(), mlast = myDependencies.end();
235   for( ; mit!=mlast; mit++ )
236   {
237     printf( "%s -> [ ", mit->first.c_str() );
238     std::list<std::string>::const_iterator lit = mit->second.begin(), llast = mit->second.end();
239     for( ; lit!=llast; lit++ )
240       printf( "%s ", (*lit).c_str() );
241     printf( "]\n" );
242   }
243   */
244
245   std::string anObjKey = GetKey( theObj );
246   std::list<std::string> aDeps = GetAllDependingOn( anObjKey );
247   std::list<std::string>::const_iterator it = aDeps.begin(), last = aDeps.end();
248   for( ; it!=last; it++ )
249     if( find( myToUpdate.begin(), myToUpdate.end(), *it ) == myToUpdate.end() )
250       myToUpdate.push_back( KeyHelper( *it, this ) );
251
252   Sort( myToUpdate );
253
254   /*
255   uit = myToUpdate.begin(); ulast = myToUpdate.end();
256   for( ; uit!=ulast; uit++ )
257     printf( "To update: %s\n", (*uit).key().c_str() );
258   */
259
260   //printf( "Dump after SetToUpdate:\n" );
261   //printf( Dump() );
262 }
263
264 bool SALOME_Notebook::CanUpdate( SALOME::ParameterizedObject_ptr theObj ) const
265 {
266   if( CORBA::is_nil( theObj ) )
267     return false;
268
269   SALOME::Parameter_var aParam = SALOME::Parameter::_narrow( theObj );
270   return !myUpdateOnlyParameters || !CORBA::is_nil( aParam );
271 }
272
273 void SALOME_Notebook::Update()
274 {
275   Update( false );
276 }
277
278 void SALOME_Notebook::Update( bool theOnlyParameters )
279 {
280   myUpdateOnlyParameters = theOnlyParameters;
281   //Utils_Locker lock( &myMutex );
282
283   //1. Simple recompute
284   std::list< KeyHelper > aPostponedUpdate;
285   std::list<KeyHelper>::const_iterator it = myToUpdate.begin(), last = myToUpdate.end();
286   for( ; it!=last; it++ )
287   {
288     std::string aKey = (*it).key();
289     //printf( "key = %s\n", aKey.c_str() );
290     SALOME::ParameterizedObject_var anObj = FindObject( aKey );
291     if( CanUpdate( anObj ) )
292       anObj->Update( _this() );
293     else
294       aPostponedUpdate.push_back( *it );
295   }
296   myToUpdate = aPostponedUpdate;
297
298   //2. Substitutions
299   std::list<SubstitutionInfo>::iterator sit = mySubstitutions.begin(), slast = mySubstitutions.end(), sremove;
300   for( ; sit!=slast; )
301   {
302     if( Substitute( *sit ) )
303     {
304       sremove = sit;
305       sit++;
306       mySubstitutions.erase( sremove );
307     }
308     else
309       sit++;
310   }
311 }
312
313 bool SALOME_Notebook::Substitute( SubstitutionInfo& theSubstitution )
314 {
315   std::list< KeyHelper > aPostponedUpdate;
316   std::string
317     anOldName = theSubstitution.myName,
318     aNewName =  theSubstitution.myExpr;
319   bool isRename = theSubstitution.myIsRename;
320   SALOME_EvalExpr anExpr;
321   anExpr.setExpression( theSubstitution.myExpr );
322
323   std::list<KeyHelper>::const_iterator it = theSubstitution.myObjects.begin(), last = theSubstitution.myObjects.end();
324   for( ; it!=last; it++ )
325   {
326     SALOME::ParameterizedObject_var anObj = FindObject( it->key() );
327     if( !CanUpdate( anObj ) )
328     {
329       aPostponedUpdate.push_back( *it );
330       continue;
331     }
332
333     SALOME::Parameter_var aParam = SALOME::Parameter::_narrow( anObj );
334     if( CORBA::is_nil( aParam ) )
335     {
336       //it is real object
337       SALOME::StringArray_var aParams = anObj->GetParameters();
338       int n = aParams->length();
339       //printf( "get params: %i\n", n );
340       for( int i=0; i<n; i++ )
341       {
342         //printf( "\t%s\n", aParams[i].in() );
343         if( anOldName == aParams[i].in() )
344         {
345           if( !isRename )
346             AddExpression( aNewName.c_str() );
347           aParams[i] = CORBA::string_dup( aNewName.c_str() );
348         }
349       }
350       anObj->SetParameters( _this(), aParams );
351     }
352     else
353     {
354       std::string
355         aName    = aParam->GetEntry(),
356         anOldKey = GetKey( aName ),
357         aNewKey  = GetKey( aNewName );
358       SALOME_Parameter* aParamPtr = myParameters[aName];
359
360       aParamPtr->Substitute( anOldName, aNewName );
361       if( aName == anOldName )
362       {
363         //it is renamed parameter
364
365         //1. update parameters map
366         if( isRename )
367         {
368           std::list<std::string> aDeps = myDependencies[anOldKey];
369           myDependencies.erase( anOldKey );
370           if( aDeps.size() > 0 )
371             myDependencies[aNewKey] = aDeps;
372           
373           myParameters.erase( anOldName );
374           myParameters[aNewName] = aParamPtr;
375         }
376         else
377         {
378           ClearDependencies( anOldKey, SALOME::All );
379           myParameters.erase( aName );
380         }
381
382         //2. update dependencies map
383         std::map< std::string, std::list<std::string> >::iterator it = myDependencies.begin(), last = myDependencies.end();
384         for( ; it!=last; it++ )
385         {
386           std::list<std::string>::iterator dit = it->second.begin(), dlast = it->second.end(), dremove;
387           for( ; dit!=dlast; )
388             if( *dit == anOldKey )
389             {
390               if( isRename )
391               {
392                 *dit = aNewKey;
393                 dit++;
394               }
395               else
396               {
397                 dremove = dit;
398                 dit++;
399                 it->second.erase( dremove );
400               }
401             }
402             else
403               dit++;
404         }
405       }
406     }
407   }
408   theSubstitution.myObjects = aPostponedUpdate;
409   return theSubstitution.myObjects.size() == 0;
410 }
411
412 void SALOME_Notebook::AddExpression( const char* theExpr )
413 {
414   AddParameter( new SALOME_Parameter( this, theExpr ) );
415 }
416
417 void SALOME_Notebook::AddNamedExpression( const char* theName, const char* theExpr )
418 {
419   AddParameter( new SALOME_Parameter( this, theName, theExpr, true ) );
420 }
421
422 void SALOME_Notebook::AddBoolean( const char* theName, CORBA::Boolean theValue )
423 {
424   AddParameter( new SALOME_Parameter( this, theName, theValue ) );
425 }
426
427 void SALOME_Notebook::AddInteger( const char* theName, CORBA::Long theValue )
428 {
429   AddParameter( new SALOME_Parameter( this, theName, (int)theValue ) );
430 }
431
432 void SALOME_Notebook::AddReal( const char* theName, CORBA::Double theValue )
433 {
434   AddParameter( new SALOME_Parameter( this, theName, theValue ) );
435 }
436
437 void SALOME_Notebook::AddString( const char* theName, const char* theValue )
438 {
439   AddParameter( new SALOME_Parameter( this, theName, theValue, false ) );
440 }
441
442 SALOME_Notebook::SubstitutionInfo SALOME_Notebook::CreateSubstitution( const std::string& theName, const std::string& theExpr, bool theIsRename ) const
443 {
444   SubstitutionInfo anInfo;
445   anInfo.myName = theName;
446   anInfo.myExpr = theExpr;
447   anInfo.myIsRename = theIsRename;
448   std::list<std::string> aDeps = GetAllDependingOn( GetKey( theName ) );
449   anInfo.myObjects.clear();
450   std::list<std::string>::const_iterator dit = aDeps.begin(), dlast = aDeps.end();
451   for( ; dit!=dlast; dit++ )
452     anInfo.myObjects.push_back( KeyHelper( *dit, this ) );
453   Sort( anInfo.myObjects );
454   return anInfo;
455 }
456
457 void SALOME_Notebook::AddSubstitution( const std::string& theName, const std::string& theExpr, bool theIsRename )
458 {
459   mySubstitutions.push_back( CreateSubstitution( theName, theExpr, theIsRename ) );
460 }
461
462 void SALOME_Notebook::Rename( const char* theOldName, const char* theNewName )
463 {
464   SALOME_Parameter* aParam = GetParameterPtr( theOldName );
465   std::string aMsg;
466   if( !aParam )
467     aMsg = arg( "Name '%1' does not exist", theOldName );
468   else if( aParam->IsAnonymous() )
469     aMsg = arg( "Parameter '%1' is anonymous", theOldName );
470   else if( GetParameterPtr( theNewName ) )
471     aMsg = arg( "New name '%1' is already used", theNewName );
472
473   CheckParamName( theNewName, aMsg );
474
475   if( aMsg.length() == 0 )
476   {
477     AddSubstitution( theOldName, theNewName, true );
478     Update( true );
479   }
480   else
481     ThrowError( aMsg );
482 }
483
484 void SALOME_Notebook::Remove( const char* theParamName )
485 {
486   SALOME_Parameter* aParam = GetParameterPtr( theParamName );
487   if( aParam )
488   {
489     std::string anExpr;
490     if( aParam->IsCalculable() )
491       anExpr = aParam->GetExpression( false );
492     else
493       anExpr = aParam->AsString();
494     AddSubstitution( theParamName, anExpr, false );
495     Update( true );
496   }
497   else
498     ThrowError( arg( "The parameter '%1' is not found", theParamName ) );
499 }
500
501 void SALOME_Notebook::UpdateAnonymous( const std::string& theOldName, const std::string& theNewName )
502 {
503   SubstitutionInfo anInfo = CreateSubstitution( theOldName, theNewName, true );
504   Substitute( anInfo );
505 }
506
507 SALOME::StringArray* SALOME_Notebook::GenerateList( const std::list<std::string>& theList ) const
508 {
509   SALOME::StringArray_var aRes = new SALOME::StringArray();
510   aRes->length( theList.size() );
511   std::list<std::string>::const_iterator nit = theList.begin(), nlast = theList.end();
512   for( int i=0; nit!=nlast; nit++, i++ )
513     aRes[i] = CORBA::string_dup( nit->c_str() );
514     
515   return aRes._retn();
516 }
517
518 class ParameterRank
519 {
520 public:
521   ParameterRank( SALOME_Parameter* theParam )
522   {
523     myName = theParam->GetEntry();
524     myId = theParam->GetId();
525   }
526
527   bool operator < ( const ParameterRank& theRank )
528   {
529     return myId < theRank.myId;
530   }
531     
532   bool operator == ( const ParameterRank& theRank )
533   {
534     return myId == theRank.myId && myName == theRank.myName;
535   }
536
537   std::string name() const
538   {
539     return myName;
540   }
541
542 private:
543   std::string myName;
544   int         myId;
545 };
546
547 std::list<std::string> SALOME_Notebook::Parameters( bool theWithAnonymous ) const
548 {
549   std::list<ParameterRank> aParams;
550   std::map< std::string, SALOME_Parameter* >::const_iterator it = myParameters.begin(), last = myParameters.end();
551   for( ; it!=last; it++ )
552   {
553     ParameterRank aRank( it->second );
554     if( ( theWithAnonymous || !it->second->IsAnonymous() ) &&
555         find( aParams.begin(), aParams.end(), aRank ) == aParams.end() )
556       aParams.push_back( aRank );
557   }
558   aParams.sort();
559
560   std::list<std::string> aNames;
561   std::list<ParameterRank>::const_iterator pit = aParams.begin(), plast = aParams.end();
562   for( ; pit!=plast; pit++ )
563     aNames.push_back( pit->name() );
564
565   return aNames;
566 }
567
568 SALOME::StringArray* SALOME_Notebook::Parameters()
569 {
570   //Utils_Locker lock( &myMutex );
571
572   return GenerateList( Parameters( false ) );
573 }
574
575 SALOME::StringArray* SALOME_Notebook::AbsentParameters( const char* theExpr )
576 {
577   //Utils_Locker lock( &myMutex );
578
579   std::list<std::string> anAbsents;
580
581   SALOME_EvalExpr anExpr( theExpr );
582   if( anExpr.parser()->error() == EvalExpr_OK )
583   {
584     std::list<std::string> aParams = anExpr.parser()->parameters();
585     std::list<std::string>::const_iterator it = aParams.begin(), last = aParams.end();
586     for( ; it!=last; it++ )
587       if( !GetParameterPtr( it->c_str() ) &&
588           find( anAbsents.begin(), anAbsents.end(), *it ) == anAbsents.end() )
589         anAbsents.push_back( *it );
590   }
591
592   anAbsents.sort();
593   return GenerateList( anAbsents );
594 }
595
596 SALOME::Parameter_ptr SALOME_Notebook::GetParameter( const char* theParamName )
597 {
598   //printf( "Param, name = %s\n", theParamName );
599   SALOME_Parameter* aParam = GetParameterPtr( theParamName );
600   //printf( "Result = %i\n", (int)aParam );
601   SALOME::Parameter_var aRes;
602   if( aParam )
603     aRes = aParam->_this();
604   return aRes._retn();
605 }
606
607 SALOME_Parameter* SALOME_Notebook::GetParameterPtr( const char* theParamName ) const
608 {
609   //Utils_Locker lock( const_cast<Utils_Mutex*>( &myMutex ) );
610
611   std::map< std::string, SALOME_Parameter* >::const_iterator it = myParameters.find( theParamName );
612   return it==myParameters.end() ? 0 : it->second;
613 }
614
615 void SALOME_Notebook::AddParameter( SALOME_Parameter* theParam, bool theAddDependencies )
616 {
617   //Utils_Locker lock( &myMutex );
618
619   std::string anEntry = theParam->GetEntry(), aMsg;
620   if( !theParam->IsAnonymous() && !CheckParamName( anEntry, aMsg ) )
621     ThrowError( aMsg );
622
623   //printf( "Add param: %s\n", anEntry.c_str() );
624
625   std::map< std::string, SALOME_Parameter* >::const_iterator it = myParameters.find( anEntry );
626   bool exists = it!=myParameters.end();
627   if( exists )
628     ThrowError( arg( "The parameter '%1' already exists", anEntry ) );
629
630   try
631   {
632     myParameters[anEntry] = theParam;
633     if( theAddDependencies && !exists )
634       AddDependencies( theParam );
635   }
636   catch( const SALOME::NotebookError& ex )
637   {
638     Remove( anEntry.c_str() );
639     throw ex;
640   }
641 }
642
643 void SALOME_Notebook::AddDependencies( SALOME_Parameter* theParam )
644 {
645   //Utils_Locker lock( &myMutex );
646
647   //printf( "Dependencies search\n" );
648   std::string anEntry = theParam->GetEntry();
649   std::string aParamKey = GetKey( anEntry );
650   SALOME_StringList aDeps = theParam->Dependencies();
651   SALOME_StringList::const_iterator dit = aDeps.begin(), dlast = aDeps.end();
652   for( ; dit!=dlast; dit++ )
653   {
654     std::string aKey = GetKey( *dit );
655     AddDependency( aParamKey, aKey );
656     //printf( "add dep to %s, res = %i\n", aKey.c_str(), ok );
657   }
658 }
659
660 void SALOME_Notebook::AddDependency( const std::string& theObjKey, const std::string& theRefKey )
661 {
662   //Utils_Locker lock( &myMutex );
663   std::string anObjName, aRefName;
664   GetComponent( theObjKey, anObjName );
665   GetComponent( theRefKey, aRefName );
666
667   std::list<std::string> aDeps = GetAllDependingOn( theObjKey );
668   if( find( aDeps.begin(), aDeps.end(), theRefKey ) != aDeps.end () )
669     ThrowError( arg( "Dependency %1 -> %2 creates a cyclic dependency", anObjName, aRefName ) );
670     //after creation a cyclic dependency could appear
671
672   std::list<std::string>& aList = myDependencies[theObjKey];
673   bool ok = find( aList.begin(), aList.end(), theRefKey ) == aList.end();
674   if( ok )
675     aList.push_back( theRefKey );
676   //else
677   //  ThrowError( arg( "Dependency %1 -> %2 is already created", anObjName, aRefName ) );
678 }
679
680 void SALOME_Notebook::ClearDependencies( const std::string& theObjKey, SALOME::DependenciesType theType )
681 {
682   //Utils_Locker lock( &myMutex );
683
684   //printf( "Clear dependencies: %s\n", theObjKey.c_str() );
685
686   std::map< std::string, std::list<std::string> >::iterator it = myDependencies.find( theObjKey );
687   if( it == myDependencies.end() )
688     return;
689
690   std::list<std::string> aNewDeps;
691   if( theType != SALOME::All )
692   {
693     std::list<std::string>::const_iterator dit = it->second.begin(), dlast = it->second.end();
694     for( ; dit!=dlast; dit++ )
695     {
696       SALOME::ParameterizedObject_var anObj = FindObject( *dit );
697       SALOME::Parameter_var aParam = SALOME::Parameter::_narrow( anObj );
698       if( ( !CORBA::is_nil( aParam ) && theType == SALOME::Objects ) || theType == SALOME::Parameters )
699         aNewDeps.push_back( *dit );
700     }
701   }
702
703   if( aNewDeps.size() == 0 )
704     myDependencies.erase( theObjKey );
705   else
706     it->second = aNewDeps;
707 }
708
709 std::string SALOME_Notebook::GetKey( SALOME::ParameterizedObject_ptr theObj ) const
710 {
711   return GetKey( theObj->GetComponent(), theObj->GetEntry() );
712 }
713
714 std::string SALOME_Notebook::GetKey( const std::string& theComponent, const std::string& theEntry ) const
715 {
716   return arg( "%1#%2", theComponent, theEntry );
717 }
718
719 std::string SALOME_Notebook::GetKey( const std::string& theParamName ) const
720 {
721   return GetKey( PARAM_COMPONENT, theParamName );
722 }
723
724 std::list<std::string> SALOME_Notebook::GetAllDependingOn( const std::string& theKey ) const
725 {
726   //Utils_Locker lock( &myMutex );
727
728   std::list<std::string> aDeps, aCurrents, aNewCurrents;
729   aCurrents.push_back( theKey );
730   aDeps.push_back( theKey );
731   while( aCurrents.size() > 0 )
732   {
733     aNewCurrents.clear();
734     std::list<std::string>::const_iterator cit = aCurrents.begin(), clast = aCurrents.end();
735     for( ; cit!=clast; cit++ )
736     {
737       //printf( "Check of %s:\n", (*cit).c_str() );
738       std::map< std::string, std::list<std::string> >::const_iterator dit = myDependencies.begin(), dlast = myDependencies.end();
739       for( ; dit!=dlast; dit++ )
740       {
741         std::string k = dit->first;
742         //printf( "\t%s\n", k.c_str() );
743         if( find( dit->second.begin(), dit->second.end(), *cit ) != dit->second.end() &&
744             find( aDeps.begin(), aDeps.end(), k ) == aDeps.end() )
745         {
746           //printf( "\t\tadd\n" );
747           aNewCurrents.push_back( k );
748           aDeps.push_back( k );
749         }
750       }
751     }
752
753     aCurrents = aNewCurrents;
754   }
755   return aDeps;
756 }
757
758 std::string SALOME_Notebook::GetComponent( const std::string& theKey, std::string& theEntry ) const
759 {
760   int aPos = theKey.find( "#" );
761   theEntry = theKey.substr( aPos+1, theKey.length()-aPos-1 );
762   return theKey.substr( 0, aPos );
763 }
764
765 SALOME::ParameterizedObject_ptr SALOME_Notebook::FindObject( const std::string& theKey ) const
766 {
767   SALOME::ParameterizedObject_var aPObj;
768   std::string anEntry, aComponent = GetComponent( theKey, anEntry );
769   if( aComponent == PARAM_COMPONENT ) {
770     SALOME_Notebook* that = const_cast<SALOME_Notebook*>( this );
771     aPObj = that->GetParameter( anEntry.c_str() );
772   }
773   else {
774     SALOME::GenericObj_var anObject = myStudy->FindObjectByInternalEntry( aComponent.c_str(), anEntry.c_str() );
775     aPObj = SALOME::ParameterizedObject::_narrow( anObject );
776   }
777   return aPObj._retn();
778 }
779
780 CORBA::Boolean SALOME_Notebook::Save( const char* theFileName )
781 {
782   //printf( "SALOME_Notebook::Save into %s\n", theFileName );
783
784   FILE* aFile = fopen( theFileName, "w" );
785   if( !aFile )
786     return false;
787
788   save( aFile, "notebook" );
789
790   //1. Save dependencies
791   save( aFile, "dependencies" );
792   std::map< std::string, std::list<std::string> >::const_iterator dit = myDependencies.begin(), dlast = myDependencies.end();
793   for( ; dit!=dlast; dit++ )
794   {
795     save( aFile, dit->first );
796     std::list<std::string>::const_iterator it = dit->second.begin(), last = dit->second.end();
797     for( ; it!=last; it++ )
798       save( aFile, *it );
799     save( aFile, "end" );
800   }
801
802   //2. Save parameters
803   save( aFile, "parameters" );
804   std::list<std::string> aNames = Parameters( true );
805   std::list<std::string>::const_iterator pit = aNames.begin(), plast = aNames.end();
806   for( ; pit!=plast; pit++ )
807     myParameters[*pit]->Save( aFile );
808
809   //3. Save update list
810   save( aFile, "recompute list" );
811   std::list< KeyHelper >::const_iterator uit = myToUpdate.begin(), ulast = myToUpdate.end();
812   for( ; uit!=ulast; uit++ )
813     save( aFile, uit->key() );
814
815   //4. Save substitutions list
816   save( aFile, "substitutions" );
817   std::list<SubstitutionInfo>::const_iterator sit = mySubstitutions.begin(), slast = mySubstitutions.end();
818   for( ; sit!=slast; sit++ )
819     Save( aFile, *sit );
820
821   fclose( aFile );
822   return true;
823 }
824
825 bool SALOME_Notebook::Save( FILE* theFile, const SubstitutionInfo& theSubstitution ) const
826 {
827   save( theFile, theSubstitution.myName );
828   save( theFile, theSubstitution.myExpr );
829   save( theFile, theSubstitution.myIsRename );
830   std::list< KeyHelper >::const_iterator it = theSubstitution.myObjects.begin(), last = theSubstitution.myObjects.end();
831   for( ; it!=last; it++ )
832     save( theFile, it->key() );
833   save( theFile, "end" );
834   return true;
835 }
836
837 SALOME_Notebook::SubstitutionInfo SALOME_Notebook::Load( FILE* theFile, const std::string& theFirstLine ) const
838 {
839   SubstitutionInfo aSubstitution;
840   aSubstitution.myName = theFirstLine;
841   load( theFile, aSubstitution.myExpr );
842   int isRename; load( theFile, isRename );
843   aSubstitution.myIsRename = isRename;
844
845   std::string aLine;
846   while( true )
847   {
848     load( theFile, aLine );
849     if( aLine == "end" )
850       break;
851     aSubstitution.myObjects.push_back( KeyHelper( aLine, this ) );
852   }
853   return aSubstitution;
854 }
855
856 namespace State
857 {
858   typedef enum { Start, Title, Dependencies, Parameters, Recompute, Substitute } LoadState;
859 }
860
861 CORBA::Boolean SALOME_Notebook::Load( const char* theFileName )
862 {
863   State::LoadState aState = State::Start;
864   FILE* aFile = fopen( theFileName, "r" );
865   if( !aFile )
866     return false;
867
868   bool ok = true;
869   std::string aLine;
870   try
871   {
872     while( true )
873     {
874       if( !load( aFile, aLine ) )
875         break;
876
877       if( aState == State::Start && aLine == "notebook" )
878         aState = State::Title;
879       else if( aLine == "dependencies" )
880         aState = State::Dependencies;
881       else if( aLine == "parameters" )
882         aState = State::Parameters;     
883       else if( aLine == "recompute list" )
884         aState = State::Recompute;
885       else if( aLine == "substitutions" )
886         aState = State::Substitute;
887
888       else switch( aState )
889            {
890            case State::Start:
891            case State::Title:
892              ok = false;
893              break;
894
895            case State::Dependencies:
896              ParseDependencies( aFile, aLine );
897              break;
898
899            case State::Parameters:
900            {
901              SALOME_Parameter* aParam = SALOME_Parameter::Load( this, aFile, aLine );
902              if( aParam )
903                AddParameter( aParam, false );
904              else
905                return false;
906              break;
907            }
908
909            case State::Recompute:
910              myToUpdate.push_back( KeyHelper( aLine, this ) );
911              break;
912
913            case State::Substitute:
914              mySubstitutions.push_back( Load( aFile, aLine ) );
915              break;
916            }
917     }
918   }
919   catch( const SALOME::NotebookError& ex )
920   {
921     printf( "Exception: %s\n", ex.Reason.in() );
922     ok = false;
923   }
924
925   fclose( aFile );
926   return ok;
927 }
928
929 void SALOME_Notebook::ParseDependencies( FILE* theFile, const std::string& theFirstLine )
930 {
931   std::string aKey = theFirstLine, aLine;
932   while( true )
933   {
934     load( theFile, aLine );
935     if( aLine == "end" )
936       break;
937     AddDependency( aKey, aLine );
938   }
939 }
940
941 char* SALOME_Notebook::DumpPython()
942 {
943   std::string aRes;
944   
945   aRes = "from salome_notebook import *\n\n";
946   std::list< KeyHelper > aParams;
947   //printf( "%i\n", myParameters.size() );
948   std::map< std::string, SALOME_Parameter* >::const_iterator it = myParameters.begin(), last = myParameters.end();
949   for( ; it!=last; it++ )
950     aParams.push_back( KeyHelper( it->first, this ) );
951
952   printf( "%i\n", aParams.size() );
953   Sort( aParams );
954   printf( "%i\n", aParams.size() );
955   std::list< KeyHelper >::const_iterator pit = aParams.begin(), plast = aParams.end();
956   std::string anEntry;
957   for( ; pit!=plast; pit++ )
958   {
959     GetComponent( pit->key(), anEntry );
960
961     SALOME_Parameter* aParam = GetParameterPtr( anEntry.c_str() );
962     if( !aParam || aParam->IsAnonymous() )
963       continue;
964
965     aRes += "notebook.set( ";
966     aRes += "\"";
967     aRes += anEntry;
968     aRes += "\", ";
969     if( aParam->IsCalculable() )
970     {
971       aRes += "\"";
972       aRes += aParam->GetExpression( false );
973       aRes += "\"";
974     }
975     else
976       aRes += aParam->AsString();
977
978     aRes += " )\n";
979   }
980
981   return CORBA::string_dup( aRes.c_str() );
982 }
983
984 bool SALOME_Notebook::CheckParamName( const std::string& theParamName, std::string& theMsg ) const
985 {
986   int len = theParamName.length();
987   if( len == 0 )
988   {
989     theMsg = "The name should not be empty";
990     return false;
991   }
992
993   if( isdigit( theParamName[0] ) )
994   {
995     theMsg = "The name should not start by a digit";
996     return false;
997   }
998
999   for( int i=0, n=theParamName.length(); i<n; i++ )
1000     if( isspace( theParamName[i] ) )
1001     {
1002       theMsg = "The name should not contain white symbols";
1003       return false;
1004     }
1005
1006   SALOME_EvalExpr anExpr( theParamName );
1007   bool ok = anExpr.parser()->isMonoParam();
1008   if( !ok )
1009     theMsg = "The name should not be expression";
1010   return ok;
1011 }
1012
1013 void SALOME_Notebook::Sort( std::list< KeyHelper >& theList ) const
1014 {
1015   std::list<KeyHelper>::iterator uit = theList.begin(), uit1, ulast = theList.end();
1016   for( ; uit!=ulast; uit++ )
1017     for( uit1=uit, uit1++; uit1!=ulast; uit1++ )
1018       if( *uit1 < *uit )
1019       {
1020         KeyHelper tmp = *uit1;
1021         *uit1 = *uit;
1022         *uit = tmp;
1023       }
1024 }
1025
1026 char* SALOME_Notebook::Dump()
1027 {
1028   std::string aStr;
1029
1030   //1. Dependencies
1031   aStr += "==========================\n";
1032   aStr += "===   NOTEBOOK Dump:   ===\n";
1033   aStr += "==========================\n\n";
1034   aStr += "Dependencies:\n";
1035   std::map< std::string, std::list<std::string> >::const_iterator dit = myDependencies.begin(), dlast = myDependencies.end();
1036   for( ; dit!=dlast; dit++ )
1037   {
1038     aStr += dit->first;
1039     aStr += " -> ";
1040     std::list<std::string>::const_iterator it = dit->second.begin(), last = dit->second.end();
1041     for( ; it!=last; it++ )
1042       aStr += *it + " ";
1043     aStr += "\n";
1044   }
1045   aStr += "\n";
1046
1047   //2. Parameters
1048   aStr += "Parameters:\n";
1049   std::list<std::string> aNames = Parameters( true );
1050   std::list<std::string>::const_iterator pit = aNames.begin(), plast = aNames.end();
1051   for( ; pit!=plast; pit++ )
1052   {
1053     SALOME_Parameter* p = myParameters[*pit];
1054     aStr += *pit + " (" + p->GetEntry() + "): ";
1055
1056     char buf[16]; sprintf( buf, "%i", p->GetId() );
1057     aStr += arg( "[%1] ", buf );
1058
1059     if( p->IsAnonymous() )
1060       aStr += "[A] ";
1061     if( p->IsCalculable() )
1062       aStr += std::string( p->GetExpression( false ) ) + " (val=" + p->AsString() + ")";
1063     else
1064       aStr += p->AsString();
1065     aStr += "\n";
1066   }
1067   aStr += "\n";
1068
1069   //3. Update lists
1070   aStr += "Update lists:\n";
1071   aStr += "\tSimple recompute:\n";
1072   std::list< KeyHelper >::const_iterator uit = myToUpdate.begin(), ulast = myToUpdate.end();
1073   for( ; uit!=ulast; uit++ )
1074     aStr += "\t" + uit->key() + "\n";
1075
1076   aStr += "\tSubstitutions:\n";
1077   std::list<SubstitutionInfo>::const_iterator sit = mySubstitutions.begin(), slast = mySubstitutions.end();
1078   for( ; sit!=slast; sit++ )
1079   {
1080     aStr += "\t" + sit->myName;
1081     aStr += " -> " + sit->myExpr + ": ";
1082     std::list< KeyHelper >::const_iterator oit = sit->myObjects.begin(), olast = sit->myObjects.end();
1083     for( ; oit!=olast; oit++ )
1084       aStr += oit->key() + " ";
1085     aStr += "\n";
1086   }
1087
1088   return CORBA::string_dup( aStr.c_str() );
1089 }
1090
1091 void SALOME_Notebook::ThrowError( const std::string& theErrorMsg ) const
1092 {
1093   SALOME::NotebookError anError;
1094   anError.Reason = CORBA::string_dup( theErrorMsg.c_str() );
1095   throw anError;
1096 }
1097
1098 SALOME::StringArray* SALOME_Notebook::GetObjectParameters( const char* theComponent, const char* theEntry )
1099 {
1100   std::list<std::string> aDeps;
1101   std::string aKey = GetKey( theComponent, theEntry ), aComponent, aName;
1102   std::map< std::string, std::list<std::string> >::const_iterator it = myDependencies.find( aKey );
1103   if( it!=myDependencies.end() )
1104   {
1105     std::list<std::string>::const_iterator dit = it->second.begin(), dlast = it->second.end();
1106     for( ; dit!=dlast; dit++ )
1107     {
1108       aComponent = GetComponent( *dit, aName );
1109       if( aComponent==PARAM_COMPONENT )
1110         aDeps.push_back( aName );
1111     }
1112   }
1113
1114   return GenerateList( aDeps );
1115 }
1116
1117 SALOME::StringArray* SALOME_Notebook::GetParameters( const char* theParamName )
1118 {
1119   return GetObjectParameters( PARAM_COMPONENT.c_str(), theParamName );
1120 }
1121
1122 int SALOME_Notebook::GetNewId()
1123 {
1124   return ++myMaxId;
1125 }
1126
1127 bool SALOME_Notebook::HasDependency( const std::string& theObjKey, const std::string& theRefKey ) const
1128 {
1129   std::map< std::string, std::list<std::string> >::const_iterator it = myDependencies.find( theObjKey );
1130   return it==myDependencies.end() ? false : find( it->second.begin(), it->second.end(), theRefKey ) != it->second.end();
1131 }
1132
1133 SALOME::Parameter_ptr SALOME_Notebook::Calculate( const char* theExpr )
1134 {
1135   if( CORBA::is_nil( myTmpParam ) )
1136   {
1137     SALOME_Parameter* aParam = new SALOME_Parameter( this, "__tmp__", 0.0 );
1138     myTmpParam = aParam->_this();
1139   }
1140
1141   myTmpParam->SetExpression( theExpr );
1142   myTmpParam->Update( _this() );
1143   return myTmpParam.in();
1144 }
1145
1146 void SALOME_Notebook::ParseOldStyleParam( const std::string& theName, const std::string& theType, const std::string& theValue )
1147 {
1148   int aType;
1149   if( sscanf( theType.c_str(), "%i", &aType ) != 1 )
1150     return;
1151
1152   switch( aType )
1153   {
1154   case 0:
1155     {
1156       double aValue;
1157       if( sscanf( theValue.c_str(), "%lf", &aValue ) != 1 )
1158         return;
1159
1160       AddReal( theName.c_str(), aValue );
1161       break;
1162     }
1163   case 1:
1164     {
1165       int aValue;
1166       if( sscanf( theValue.c_str(), "%i", &aValue ) != 1 )
1167         return;
1168
1169       AddInteger( theName.c_str(), aValue );
1170       break;
1171     }
1172   case 2:
1173     {
1174       int aValue;
1175       if( sscanf( theValue.c_str(), "%i", &aValue ) != 1 )
1176         return;
1177
1178       AddBoolean( theName.c_str(), aValue );
1179       break;
1180     }
1181   case 3:
1182     {
1183       std::string aValue = theValue;
1184       for( int i = 0, n = aValue.length(); i < n; i++ )
1185         if( aValue[i]=='"' )
1186           aValue[i] = ' ';
1187
1188       AddNamedExpression( theName.c_str(), aValue.c_str() );
1189       break;
1190     }
1191   }
1192 }
1193
1194 void SALOME_Notebook::ParseOldStyleObject( const std::string& theComponent, const std::string& theEntry, const std::string& theData )
1195 {
1196   //printf( "ParseOldStyleObject: %s\n", theData.c_str() );
1197   std::string anObjKey = GetKey( theComponent, theEntry );
1198   std::vector<std::string> aParts = split( theData, "|", false ), anItems;
1199   for( int i=0, n=aParts.size(); i<n; i++ )
1200   {
1201     //printf( "part: %s\n", aParts[i].c_str() );
1202     anItems = split( aParts[i], ":", false );
1203     //printf( "size = %i\n", anItems.size() );
1204     for( int j=0, m=anItems.size(); j<m; j++ )
1205     {
1206       std::string aRefKey = GetKey( anItems[j] );
1207       //printf( "key = %s\n", aRefKey.c_str() );
1208       if( !HasDependency( anObjKey, aRefKey ) )
1209         AddDependency( anObjKey, aRefKey );
1210     }
1211   }
1212   myEntriesToRebuild.push_back( theEntry );
1213 }
1214
1215 void SALOME_Notebook::RebuildLinks()
1216 {
1217   printf( "Rebuild links\n" );
1218
1219   SALOMEDS::StudyBuilder_var aBuilder = myStudy->NewBuilder();
1220   std::list<std::string> aNewEntriesToRebuild;
1221   std::list<std::string>::const_iterator it = myEntriesToRebuild.begin(), last = myEntriesToRebuild.end();
1222   for( ; it!=last; it++ )
1223   {
1224     std::string aGlobalEntry = *it;
1225     SALOMEDS::SObject_var anObj = myStudy->FindObjectID( aGlobalEntry.c_str() );
1226     if( !CORBA::is_nil( anObj ) )
1227     {
1228       SALOMEDS::GenericAttribute_var anAttr;
1229       if( aBuilder->FindAttribute( anObj._retn(), anAttr, "AttributeIOR" ) )
1230       {
1231         /*SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow( anAttr );
1232         CORBA::Object_var aRealObj = _orb->string_to_object( anIOR.Value() );
1233         SALOME::ParameterizedObject_var aParamObj = SALOME::ParameterizedObject::_narrow( aRealObj );
1234         if( !CORBA::is_nil( aParamObj ) )
1235         {
1236           std::string
1237             anOldKey = GetKey( aParamObj->GetComponent(), aGlobalEntry ),
1238             aKey = GetKey( aParamObj );
1239           std::map< std::string, std::list<std::string> >::iterator it = myDependencies.find( anOldKey );
1240           if( it!=myDependencies.end() )
1241           {
1242             std::list<std::string> aValue = it->second;
1243             myDependencies.remove( anOldKey );
1244             myDependencies.insert( aKey, aValue );
1245           }
1246           continue;
1247         }*/
1248       }
1249     }
1250     aNewEntriesToRebuild.push_back( aGlobalEntry );
1251   }
1252
1253   myEntriesToRebuild = aNewEntriesToRebuild;
1254 }