Salome HOME
Porting to Mandrake 10.1 and new products:
[modules/kernel.git] / src / SALOMEDS / SALOMEDS_StudyManager_i.cxx
1 //  SALOME SALOMEDS : data structure of SALOME and sources of Salome data server 
2 //
3 //  Copyright (C) 2003  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SALOMEDS_StudyManager_i.cxx
25 //  Author : Yves FRICAUD 
26 //  Module : SALOME
27 //  $Header$
28
29 #include <memory>
30 #include <sstream>
31
32 #include <OSD_Process.hxx>
33 #include <Quantity_Date.hxx>
34
35 #include <TDF_Label.hxx>
36 #include <TDataStd_Name.hxx>
37 #include <TDataStd_Comment.hxx>
38 #include <TDataStd_Integer.hxx>
39 #include <TDataStd_TreeNode.hxx>
40 #include <TDataStd_UAttribute.hxx> 
41 #include <TDF_ChildIterator.hxx>
42 #include <TDF_Tool.hxx>
43 #include <TDF_Reference.hxx>
44 #include <TDF_Data.hxx>
45 #include <TDF_RelocationTable.hxx>
46 #include <TDF_AttributeIterator.hxx>
47 #include <TCollection_ExtendedString.hxx>
48 #include <TCollection_AsciiString.hxx>
49
50 #include "SALOMEDS.hxx"
51 #include "SALOMEDS_StudyManager_i.hxx"
52 #include "SALOME_LifeCycleCORBA.hxx"
53
54 #include "SALOMEDS_Study_i.hxx"
55 #include "SALOMEDS_SObject_i.hxx"
56 #include "SALOMEDS_StudyBuilder_i.hxx"
57
58 #include "SALOMEDS_IORAttribute.hxx"
59 #include "SALOMEDS_PersRefAttribute.hxx"
60 #include "SALOMEDS_TargetAttribute.hxx"
61
62 #include "SALOMEDS_Tool.hxx"
63 #include "HDFexplorer.hxx"
64
65 // IDL headers
66 #include <SALOMEconfig.h>
67 #include CORBA_SERVER_HEADER(SALOMEDS_Attributes)
68
69 #include "SALOME_GenericObj_i.hh"
70 #include "Utils_CorbaException.hxx"
71 #include "Utils_ExceptHandlers.hxx"
72
73 UNEXPECT_CATCH(SalomeException,SALOME::SALOME_Exception);
74 UNEXPECT_CATCH(LockProtection, SALOMEDS::StudyBuilder::LockProtection);
75
76 #define USE_CASE_LABEL_ID             "0:2"
77 #define AUTO_SAVE_GUID                "128268A3-71C9-4036-89B1-F81BD6A4FCF2"
78 #define AUTO_SAVE_TAG                 "0:8"
79 #define AUTO_SAVE_TIME_OUT_IN_SECONDS 1200
80
81 #include "utilities.h"
82
83 using namespace std;
84
85 //===========================================================================
86 namespace SALOMEDS{
87
88   CORBA::Object_var 
89   GetObject(const TDF_Label& theLabel, CORBA::ORB_ptr theORB)
90   {
91     try {
92       Handle(SALOMEDS_IORAttribute) anAttr;
93       if(theLabel.FindAttribute(SALOMEDS_IORAttribute::GetID(),anAttr))
94         return theORB->string_to_object(TCollection_AsciiString(anAttr->Get()).ToCString());
95     }catch(...){
96     }
97     return CORBA::Object::_nil();
98   }
99
100
101   PortableServer::ServantBase_var 
102   GetServant(CORBA::Object_ptr theObject, PortableServer::POA_ptr thePOA)
103   {
104     if(CORBA::is_nil(theObject))
105       return NULL;
106     try{
107       return thePOA->reference_to_servant(theObject);
108     }catch(...){
109       return NULL;
110     }
111   }
112
113 }
114
115 //===========================================================================
116 //Function : LoadAttributes
117 //===========================================================================
118 static 
119 void 
120 ReadAttributes(SALOMEDS_Study_i* theStudy,
121                SALOMEDS::SObject_ptr aSO,
122                HDFdataset* hdf_dataset)
123 {
124   hdf_dataset->OpenOnDisk();
125
126   SALOMEDS::GenericAttribute_var anAttr;
127
128   char* current_string = new char[hdf_dataset->GetSize()];
129   hdf_dataset->ReadFromDisk(current_string);
130
131   if (!strcmp(hdf_dataset->GetName(),"COMPONENTDATATYPE")) {
132     anAttr = theStudy->GetBuilder()->FindOrCreateAttribute(aSO, "AttributeComment");
133   } else if (!strcmp(hdf_dataset->GetName(),"Reference")) {
134     theStudy->GetBuilder()->Addreference(aSO, theStudy->CreateObjectID(current_string));
135     delete(current_string);
136     hdf_dataset->CloseOnDisk();
137     return;
138   } else {
139     MESSAGE("Read attribute "<<hdf_dataset->GetName())
140     anAttr = theStudy->GetBuilder()->FindOrCreateAttribute(aSO, hdf_dataset->GetName());
141   }
142
143   if (!CORBA::is_nil(anAttr)) {
144     anAttr->Restore(current_string);
145     MESSAGE("Restoring attribute "<<hdf_dataset->GetName()<<" by string '"<<current_string<<"' done")
146   } else {
147     MESSAGE(hdf_dataset->GetName());
148     MESSAGE("LoadAttributes: unknown types");
149   }
150   delete(current_string);
151   hdf_dataset->CloseOnDisk();
152 }
153
154 //============================================================================
155 //Function : Translate_IOR_to_persistentID
156 //============================================================================
157 static void Translate_IOR_to_persistentID(SALOMEDS_Study_i* theStudy,
158                                           SALOMEDS_StudyBuilder_i* theBuilder,
159                                           SALOMEDS::SObject_ptr theSObject,
160                                           SALOMEDS::Driver_ptr theEngine,
161                                           CORBA::Boolean theIsMultiFile,
162                                           CORBA::Boolean theIsASCII)
163 {
164   MESSAGE("In Translate_IOR_to_persistentID");
165   SALOMEDS_ChildIterator_i anIter = theStudy->GetChildIterator(theSObject);
166   for(; anIter.More(); anIter.Next()){
167     SALOMEDS::GenericAttribute_var anAttr;
168     SALOMEDS::SObject_var aSObject = anIter.Value();
169     if(aSObject->FindAttribute(anAttr,"AttributeIOR")){
170       SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr);
171       CORBA::String_var aString = anIOR->Value();
172       CORBA::String_var aPersistentID = 
173         theEngine->IORToLocalPersistentID(aSObject,aString,theIsMultiFile,theIsASCII);
174       anAttr = theBuilder->FindOrCreateAttribute(aSObject,"AttributePersistentRef");
175       SALOMEDS::AttributePersistentRef_var aPersistentRef = SALOMEDS::AttributePersistentRef::_narrow(anAttr);
176       aPersistentRef->SetValue(aPersistentID);
177       aString = aSObject->GetID();
178     }
179     Translate_IOR_to_persistentID(theStudy,theBuilder,aSObject,theEngine,theIsMultiFile,theIsASCII);
180   }
181 }
182
183 //============================================================================
184 //Function : BuildlTree
185 //============================================================================
186 static 
187 void 
188 BuildTree(SALOMEDS_Study_i* theStudy, HDFgroup* hdf_current_group)
189 {
190   hdf_current_group->OpenOnDisk();
191   
192   SALOMEDS::SObject_var aSO;
193   char* Entry = hdf_current_group->GetName();
194   if (strcmp(Entry,"STUDY_STRUCTURE") == 0) {
195     MESSAGE("find the root of the document");
196     aSO = theStudy->CreateObjectID("0:1");
197   }
198   else {
199     aSO = theStudy->CreateObjectID(Entry);
200     MESSAGE("BuildTree : Create a new label"<<Entry);
201   }
202   char name[HDF_NAME_MAX_LEN+1];
203   Standard_Integer nbsons = hdf_current_group->nInternalObjects(); 
204   
205   for (Standard_Integer i=0; i<nbsons; i++) {
206     hdf_current_group->InternalObjectIndentify(i,name);
207     if (strncmp(name, "INTERNAL_COMPLEX",16) == 0) continue;
208     hdf_object_type type = hdf_current_group->InternalObjectType(name);
209
210     if  (type == HDF_DATASET) {
211       MESSAGE("--> Dataset: Internal Object Name : " << name);
212       HDFdataset* new_dataset = new HDFdataset(name,hdf_current_group);
213       ReadAttributes(theStudy,aSO,new_dataset);      
214       new_dataset = 0; // will be deleted by father destructor
215
216     }
217     else if (type == HDF_GROUP)   {
218       MESSAGE( "--> Group: Internal Object Name : " << name);
219       HDFgroup* new_group = new HDFgroup(name,hdf_current_group);
220       BuildTree(theStudy, new_group);
221       new_group = 0; // will be deleted by father destructor
222     }
223   }
224   hdf_current_group->CloseOnDisk();
225 }
226
227
228 //============================================================================
229 /*! Function : SALOMEDS_StudyManager_i
230  *  Purpose  : SALOMEDS_StudyManager_i constructor 
231  */
232 //============================================================================
233 SALOMEDS_StudyManager_i::SALOMEDS_StudyManager_i(CORBA::ORB_ptr theORB, 
234                                                  PortableServer::POA_ptr thePOA):
235   _orb(CORBA::ORB::_duplicate(theORB)),
236   _poa(PortableServer::POA::_duplicate(thePOA)),
237   _OCAFApp(new SALOMEDS_OCAFApplication()),
238   _name_service(theORB)
239
240   // Study directory creation in the naming service : to register all
241   // open studies in the session
242   _name_service.Create_Directory("/Study");
243   _IDcounter = 0;
244 }
245
246 //============================================================================
247 /*! Function : ~SALOMEDS_StudyManager_i
248  *  Purpose  : SALOMEDS_StudyManager_i destructor
249  */
250 //============================================================================
251 SALOMEDS_StudyManager_i::~SALOMEDS_StudyManager_i()
252 {
253   // Destroy directory to register open studies
254   _name_service.Destroy_Directory("/Study");
255 }
256
257 SALOMEDS_Study_i* 
258 SALOMEDS_StudyManager_i::DownCast(SALOMEDS::Study_ptr theStudy) const
259 {
260   if(!CORBA::is_nil(theStudy)){
261     PortableServer::POA_var aPOA = GetPOA();
262     PortableServer::ServantBase_var aServant = SALOMEDS::GetServant(theStudy,aPOA);
263     if(aServant.in())
264       return dynamic_cast<SALOMEDS_Study_i*>(aServant.in());
265   }
266   return NULL;
267 }
268
269 //============================================================================
270 /*! Function : register_name
271  *  Purpose  : Register the study Manager in the naming service under the  
272  *             context name
273  */
274 //============================================================================
275 void SALOMEDS_StudyManager_i::register_name(char * theName) {
276   SALOMEDS::StudyManager_var aManager(_this());
277   _name_service.Register(aManager.in(),theName);
278 }
279
280
281 //============================================================================
282 /*! Function : NewStudy
283  *  Purpose  : Create a New Study of name study_name
284  */
285 //============================================================================
286 SALOMEDS::Study_ptr SALOMEDS_StudyManager_i::NewStudy(const char* theStudyName) 
287 {
288   SALOMEDS::Locker lock;
289    
290   Handle(TDocStd_Document) aDocument;
291   _OCAFApp->NewDocument("SALOME_STUDY",aDocument); 
292
293   MESSAGE("NewStudy : Creating the CORBA servant holding it... ");
294   SALOMEDS_Study_i* aStudyServant = new SALOMEDS_Study_i(this,aDocument,theStudyName); 
295   SALOMEDS::Study_var aStudy = aStudyServant->_this();
296
297   //Study->StudyId( _OCAFApp->NbDocuments() ); 
298   _IDcounter++;
299   aStudyServant->StudyId( _IDcounter );
300
301   // Register study in the naming service
302   // Path to acces the study
303   if(!_name_service.Change_Directory("/Study")){
304     MESSAGE( "Unable to access the study directory" );
305   }else
306     _name_service.Register(aStudy, theStudyName);
307                                                    
308   // Assign the value of the IOR in the study->root
309   CORBA::String_var anIOR = _orb->object_to_string(aStudy);
310   SALOMEDS_IORAttribute::Set(aDocument->Main().Root(),
311                              const_cast<char*>(anIOR.in()),
312                              aStudyServant);
313
314   // set Study properties
315   SALOMEDS::AttributeStudyProperties_var aProp = aStudyServant->GetProperties();
316   OSD_Process aProcess;
317   Quantity_Date aDate = aProcess.SystemDate();
318   aProp->SetCreationDate(CORBA::Long(aDate.Minute()), 
319                          CORBA::Long(aDate.Hour()), 
320                          CORBA::Long(aDate.Day()),
321                          CORBA::Long(aDate.Month()), 
322                          CORBA::Long(aDate.Year()));
323   aProp->SetCreationMode("from scratch");
324   aProp->SetUserName(aProcess.UserName().ToCString());
325
326   return aStudy._retn();
327 }
328
329 //============================================================================
330 /*! Function : Open
331  *  Purpose  : Open a Study from it's persistent reference
332  */
333 //============================================================================
334 SALOMEDS::Study_ptr  SALOMEDS_StudyManager_i::Open(const char* theURL)
335      throw(SALOME::SALOME_Exception)
336 {
337   SALOMEDS::Locker lock;
338
339   Unexpect aCatch(SalomeException);
340   MESSAGE("Begin of SALOMEDS_StudyManager_i::Open");
341
342   bool isASCII = false;
343   std::ostringstream anURLStream;
344   if (HDFascii::isASCII(theURL)) {
345     isASCII = true;
346     auto_ptr<char> aResultPath(HDFascii::ConvertFromASCIIToHDF(theURL));
347     anURLStream<<aResultPath.get()<<"hdf_from_ascii.hdf";
348   } else {
349     anURLStream<<theURL;
350   }
351   std::string aHDFUrl = anURLStream.str();
352
353   // open the HDFFile (all related hdf objects will be deleted     )
354   auto_ptr<HDFfile> hdf_file(new HDFfile(const_cast<char*>(aHDFUrl.c_str())));
355
356   try {
357     hdf_file->OpenOnDisk(HDF_RDONLY);// mpv: was RDWR, but opened file can be write-protected too
358   }catch(HDFexception){
359     std::ostringstream aStream;
360     aStream<<"Can't open file "<<theURL;
361     std::string eStr = aStream.str();
362     THROW_SALOME_CORBA_EXCEPTION(eStr.c_str(),SALOME::BAD_PARAM);
363   } 
364   MESSAGE("Open : Creating the CORBA servant holding it... ");
365
366   // Temporary aStudyUrl in place of study name
367   Handle(TDocStd_Document) Doc;
368   _OCAFApp->NewDocument("SALOME_STUDY",Doc); 
369
370   SALOMEDS_Study_i* aStudyServant = new SALOMEDS_Study_i(this,Doc,theURL);  
371   SALOMEDS::Study_var aStudy = aStudyServant->_this(); 
372
373   //  aStudy->StudyId( _OCAFApp->NbDocuments() ); 
374   _IDcounter++;
375   aStudy->StudyId( _IDcounter );
376
377   // Assign the value of the URL in the study object
378   aStudyServant->URL(theURL);
379   SCRUTE(theURL);
380
381   // Assign the value of the IOR in the study->root
382   CORBA::String_var anIOR = _orb->object_to_string(aStudy);
383   SALOMEDS_IORAttribute::Set(Doc->Main().Root(),
384                              const_cast<char*>(anIOR.in()),
385                              aStudyServant);
386
387   SALOMEDS_PersRefAttribute::Set(Doc->Main(),const_cast<char*>(theURL)); 
388
389   if (!hdf_file->ExistInternalObject("STUDY_STRUCTURE")) {
390     MESSAGE("SALOMEDS_StudyManager::Open : the study is empty");
391     return aStudy._retn();
392   }
393
394   //Create  the Structure of the OCAF Document
395   HDFgroup *hdf_group_study_structure = new HDFgroup("STUDY_STRUCTURE",hdf_file.get());
396
397   Handle(TDF_Data) DF = Doc->GetData();
398
399   try{
400     BuildTree(aStudyServant,hdf_group_study_structure);
401   }catch(HDFexception){
402     std::ostringstream aStream;
403     aStream<<"Can't open file "<<theURL;
404     std::string eStr = aStream.str();
405     THROW_SALOME_CORBA_EXCEPTION(eStr.c_str(),SALOME::BAD_PARAM);
406   } 
407   
408   hdf_file->CloseOnDisk();
409
410   // Register study in the naming service
411   // Path to acces the study
412   if(!_name_service.Change_Directory("/Study")){
413     MESSAGE( "Unable to access the study directory" );
414   }else{
415     CORBA::String_var aString(aStudyServant->Name());
416     _name_service.Register(aStudy,aString.in());
417   }
418
419   if (isASCII) {
420     SALOMEDS::ListOfFileNames_var aFilesToRemove = new SALOMEDS::ListOfFileNames;
421     aFilesToRemove->length(1);
422     std::string aDir = SALOMEDS_Tool::GetDirFromPath(aHDFUrl);
423     aFilesToRemove[0] = CORBA::string_dup(&aHDFUrl[strlen(aDir.c_str())]);
424     SALOMEDS_Tool::RemoveTemporaryFiles(aDir,aFilesToRemove,true);
425   }
426
427   return aStudy._retn();
428 }
429
430
431
432 //============================================================================
433 /*! Function : Close
434  *  Purpose  : Close a study.
435  *             If the study hasn't been saved, ask the user to confirm the
436  *             close action without saving 
437  */
438 //============================================================================
439 void  SALOMEDS_StudyManager_i::Close(SALOMEDS::Study_ptr aStudy)
440 {
441   SALOMEDS::Locker lock;
442
443   if(aStudy->_is_nil()) return;
444   
445   aStudy->RemovePostponed(-1);
446   
447   // Destroy study name in the naming service
448   if(_name_service.Change_Directory("/Study")){
449     CORBA::String_var aString(aStudy->Name());
450     _name_service.Destroy_Name(aString.in());
451   }
452
453   aStudy->Close();
454 }
455
456 //============================================================================
457 /*! Function : Save
458  *  Purpose  : Save a Study to it's persistent reference
459  */
460 //============================================================================
461 void SALOMEDS_StudyManager_i::Save(SALOMEDS::Study_ptr theStudy, CORBA::Boolean theMultiFile)
462 {
463   SALOMEDS::Locker lock;
464
465   CORBA::String_var anURL = theStudy->URL();
466   if(strcmp(anURL.in(),"") == 0){
467     MESSAGE( "No path specified to save the study. Nothing done");
468   }else{
469     _SaveAs(anURL,theStudy,theMultiFile,false);
470   }
471 }
472
473 void SALOMEDS_StudyManager_i::SaveASCII(SALOMEDS::Study_ptr theStudy, CORBA::Boolean theMultiFile)
474 {
475   SALOMEDS::Locker lock;
476
477   CORBA::String_var anURL = theStudy->URL();
478   if(strcmp(anURL.in(),"") == 0){
479     MESSAGE( "No path specified to save the study. Nothing done");
480   }else{
481     _SaveAs(anURL,theStudy,theMultiFile,true);
482   }
483 }
484
485 //=============================================================================
486 /*! Function : SaveAs
487  *  Purpose  : Save a study to the persistent reference aUrl
488  */
489 //============================================================================
490 void SALOMEDS_StudyManager_i::SaveAs(const char* aUrl, SALOMEDS::Study_ptr theStudy, CORBA::Boolean theMultiFile)
491 {
492   SALOMEDS::Locker lock;
493
494   _SaveAs(aUrl,theStudy,theMultiFile, false);
495
496 }
497
498 void SALOMEDS_StudyManager_i::SaveAsASCII(const char* aUrl, SALOMEDS::Study_ptr theStudy, CORBA::Boolean theMultiFile)
499 {
500   SALOMEDS::Locker lock;
501
502   _SaveAs(aUrl,theStudy,theMultiFile, true);
503 }
504
505 //============================================================================
506 /*! Function : GetOpenStudies
507  *  Purpose  : Get name list of open studies in the session
508  */
509 //============================================================================
510 SALOMEDS::ListOfOpenStudies*  SALOMEDS_StudyManager_i::GetOpenStudies()
511 {
512   // MESSAGE("Begin of GetOpenStudies");
513   SALOMEDS::ListOfOpenStudies_var aStudyList = new SALOMEDS::ListOfOpenStudies;
514
515   if(!_name_service.Change_Directory("/Study")){
516     MESSAGE("No active study in this session");
517   }else{
518     vector<string> aList = _name_service.list_directory();
519     aStudyList->length(aList.size());
520     for(unsigned int ind = 0; ind < aList.size(); ind++){
521       aStudyList[ind] = CORBA::string_dup(aList[ind].c_str());
522       SCRUTE(aStudyList[ind]) ;
523     }
524   }
525
526   return aStudyList._retn();
527 }
528
529 //============================================================================
530 /*! Function : GetStudyByName
531  *  Purpose  : Get a study from its name
532  */
533 //============================================================================
534 SALOMEDS::Study_ptr  
535 SALOMEDS_StudyManager_i::GetStudyByName(const char* theStudyName) 
536 {
537   SALOMEDS::Study_var aStudy;
538
539   // Go to study directory and look for aStudyName
540   if(!_name_service.Change_Directory("/Study")){
541     MESSAGE("No active study in this session");
542     ASSERT(false); // Stop here...
543   }
544   
545   if(_name_service.Find(theStudyName) > 0){
546     // Study found
547     CORBA::Object_ptr anObj = _name_service.Resolve(theStudyName) ;
548     aStudy = SALOMEDS::Study::_narrow(anObj);
549     MESSAGE("Study " << theStudyName << " found in the naming service");
550   }else{
551     MESSAGE("Study " << theStudyName << " not found in the naming service");
552   }
553   return aStudy._retn();
554 }
555
556 //============================================================================
557 /*! Function : GetStudyByID
558  *  Purpose  : Get a study from its ID
559  */
560 //============================================================================
561 SALOMEDS::Study_ptr  
562 SALOMEDS_StudyManager_i::GetStudyByID(CORBA::Short aStudyID) 
563 {
564   SALOMEDS::Study_var aStudy;
565
566   if(!_name_service.Change_Directory("/Study")){
567     MESSAGE("No active study in this session");
568   }else{
569     vector<string> aList = _name_service.list_directory();
570     for(unsigned int ind = 0; ind < aList.size(); ind++){
571       const char* aStudyName = aList[ind].c_str();
572       MESSAGE( "GetStudyByID = " << aStudyName );
573       if(_name_service.Find(aStudyName) > 0){
574         CORBA::Object_ptr anObj = _name_service.Resolve(aStudyName) ;
575         aStudy = SALOMEDS::Study::_narrow(anObj);
576         MESSAGE( " aStudyID : " << aStudyID << "-" << aStudy->StudyId() );
577         if(aStudyID == aStudy->StudyId()){
578           MESSAGE("Study with studyID = " << aStudyID << " found in the naming service");
579           return aStudy._retn();
580         }
581       }else{
582         MESSAGE("Study " << aStudyName << " not found in the naming service");
583       }
584     }
585   }
586   
587   return aStudy._retn();
588 }
589 //============================================================================
590 /*! Function : SaveAttributes
591  *  Purpose  : Save attributes for object
592  */
593 //============================================================================
594 static void SaveAttributes(SALOMEDS::SObject_ptr SO, HDFgroup *hdf_group_sobject) {
595   int a;
596   hdf_size size[1];
597   SALOMEDS::ListOfAttributes_var anAttrList = SO->GetAllAttributes();
598   for(a = anAttrList->length() - 1; a >= 0; a--) {
599     if (strcmp(anAttrList[a]->Type(), "AttributeIOR") == 0) continue; // never write AttributeIOR to file
600     CORBA::String_var aSaveStr(anAttrList[a]->Store());
601     size[0] = (hdf_int32) strlen(aSaveStr.in()) + 1;
602     HDFdataset *hdf_dataset = new HDFdataset(anAttrList[a]->Type(),hdf_group_sobject,HDF_STRING,size,1);
603     hdf_dataset->CreateOnDisk();
604     hdf_dataset->WriteOnDisk(aSaveStr);
605     hdf_dataset->CloseOnDisk();
606     //cout<<"********** Write Attribute "<<anAttrList[a]->Type()<<" : "<<aSaveStr<<" done"<<endl;
607     hdf_dataset = 0; //will be deleted by hdf_sco_group destructor
608   }
609
610   // Reference attribute has no CORBA attribute representation, so, GetAllAttributes can not return this attribute
611   SALOMEDS::SObject_var RefSO;
612   if(SO->ReferencedObject(RefSO)) {
613     CORBA::String_var attribute_reference(RefSO->GetID());
614     size[0] = strlen(attribute_reference) + 1 ; 
615     HDFdataset *hdf_dataset = new HDFdataset("Reference",hdf_group_sobject,HDF_STRING,size,1);
616     hdf_dataset->CreateOnDisk();
617     hdf_dataset->WriteOnDisk(attribute_reference);
618     hdf_dataset->CloseOnDisk();
619     hdf_dataset = 0; // will be deleted by father hdf object destructor
620   }
621 }
622
623 //=============================================================================
624 /*! Function : _SaveProperties
625  *  Purpose  : save the study properties in HDF file
626  */
627 //============================================================================
628 void SALOMEDS_StudyManager_i::_SaveProperties(SALOMEDS_Study_i* theStudy, HDFgroup *hdf_group) 
629 {
630   // add modifications list (user and date of save)
631   SALOMEDS::AttributeStudyProperties_ptr aProp = theStudy->GetProperties();
632   int aLocked = aProp->IsLocked();
633   if (aLocked) 
634     aProp->SetLocked(Standard_False);
635   OSD_Process aProcess;
636   Quantity_Date aDate = aProcess.SystemDate();
637   aProp->SetModification(aProcess.UserName().ToCString(),
638                          CORBA::Long(aDate.Minute()), 
639                          CORBA::Long(aDate.Hour()), 
640                          CORBA::Long(aDate.Day()),
641                          CORBA::Long(aDate.Month()), 
642                          CORBA::Long(aDate.Year()));
643   if(aLocked) 
644     aProp->SetLocked(Standard_True);
645
646   SALOMEDS::StringSeq_var aNames;
647   SALOMEDS::LongSeq_var aMinutes, aHours, aDays, aMonths, aYears;
648   aProp->GetModificationsList(aNames,aMinutes,aHours,aDays,aMonths,aYears,true);
649
650   std::ostringstream aPropertyList;
651   aPropertyList<<(strlen(aProp->GetCreationMode()) != 0? aProp->GetCreationMode()[0] : '0');
652   aPropertyList<<(aProp->IsLocked()? 'l': 'u');
653
654   int aLength = aNames->length();
655   for(int anIndex = 0; anIndex  < aLength; anIndex++) {
656     aPropertyList<<std::setw(2)<<aMinutes[anIndex];
657     aPropertyList<<std::setw(2)<<aHours[anIndex];
658     aPropertyList<<std::setw(2)<<aDays[anIndex];
659     aPropertyList<<std::setw(2)<<aMonths[anIndex];
660     aPropertyList<<std::setw(4)<<aYears[anIndex];
661     aPropertyList<<aNames[anIndex];
662     aPropertyList<<char(0x1);
663   }
664   std::string aProperty = aPropertyList.str();
665
666   hdf_size size[] = {aProperty.size() + 1};
667   HDFdataset *hdf_dataset = new HDFdataset("AttributeStudyProperties",hdf_group,HDF_STRING,size,1);
668   hdf_dataset->CreateOnDisk();
669   hdf_dataset->WriteOnDisk(const_cast<char*>(aProperty.c_str()));
670   MESSAGE("attribute StudyProperties " <<  aProperty << " wrote on file");
671   hdf_dataset->CloseOnDisk();
672   hdf_dataset = 0; //will be deleted by hdf_sco_group destructor
673   aProp->SetModified(0);
674 }
675
676 //=============================================================================
677 /*! Function : _SaveAs
678  *  Purpose  : save the study in HDF file
679  */
680 //============================================================================
681 void SALOMEDS_StudyManager_i::_SaveAs(const char* aUrl, 
682                                       SALOMEDS::Study_ptr theStudy,
683                                       CORBA::Boolean theMultiFile,
684                                       CORBA::Boolean theASCII)
685 {
686   // HDF File will be composed of differents part :
687   // * For each ComponentDataType, all data created by the component
688   //   Informations in data group hdf_group_datacomponent
689   // * Study Structure -> Exactly what is contained in OCAF document
690   //   Informations in data group hdf_group_study_structure
691
692   if(SALOMEDS_Study_i* aStudy = DownCast(theStudy)){
693     HDFfile *hdf_file=0;         
694     HDFgroup *hdf_group_study_structure =0;
695     HDFgroup *hdf_sco_group =0;
696     HDFgroup *hdf_sco_group2 =0;
697
698     HDFgroup *hdf_group_datacomponent =0;
699     HDFdataset *hdf_dataset =0;
700     hdf_size size[1];
701     hdf_int32 name_len = 0;
702   
703     int aLocked = aStudy->GetProperties()->IsLocked();
704     if(aLocked) 
705       aStudy->GetProperties()->SetLocked(false);
706
707     SALOMEDS_StudyBuilder_i* SB= aStudy->GetBuilder();
708     try{
709       // mpv 15.12.2003: for saving components we have to load all data from all modules
710       SALOMEDS_SComponentIterator_i aComponentIter = aStudy->GetComponentIterator();
711       for(; aComponentIter.More(); aComponentIter.Next()){
712         SALOMEDS::SComponent_var sco = aComponentIter.Value();
713         // if there is an associated Engine call its method for saving
714         CORBA::String_var IOREngine;
715         try{
716           if(!sco->ComponentIOR(IOREngine)){
717             SALOMEDS::GenericAttribute_var aGeneric;
718             SALOMEDS::AttributeName_var aName;
719             if(sco->FindAttribute(aGeneric, "AttributeName"))
720               aName = SALOMEDS::AttributeName::_narrow(aGeneric);
721             
722             if(!aName->_is_nil()){
723               CORBA::String_var aCompType = aName->Value();
724
725               CORBA::String_var aFactoryType;
726               if(strcmp(aCompType, "SUPERV") == 0) 
727                 aFactoryType = "SuperVisionContainer";
728               else
729                 aFactoryType = "FactoryServer";
730               
731               Engines::Component_var aComp =
732                 SALOME_LifeCycleCORBA(&_name_service).FindOrLoad_Component(aFactoryType, aCompType);
733                 
734               if(aComp->_is_nil()){
735                 Engines::Component_var aComp =
736                   SALOME_LifeCycleCORBA(&_name_service).FindOrLoad_Component("FactoryServerPy", aCompType);
737               }
738                 
739               if(!aComp->_is_nil()){
740                 SALOMEDS::Driver_var aDriver = SALOMEDS::Driver::_narrow(aComp);
741                 if (!CORBA::is_nil(aDriver)) {
742                   // PAL8065: san - _SaveAs() should always be called from some CORBA method protected with a lock
743                   SALOMEDS::unlock();
744                   SB->LoadWith(sco, aDriver);
745                   SALOMEDS::lock();
746                 }
747               }
748             }
749           }
750         }catch(...){
751           MESSAGE("Can not restore information to resave it");
752           return;
753         }
754       }
755
756       CORBA::String_var anOldName = aStudy->Name();
757       aStudy->URL(aUrl);
758
759       // To change for Save 
760       // Do not have to do a new file but just a Open??? Rewrite all informations after erasing evrything??
761       hdf_file = new HDFfile((char *)aUrl);
762       hdf_file->CreateOnDisk();
763       MESSAGE("File " << aUrl << " created");
764
765       //-----------------------------------------------------------------------
766       // 1 - Create a groupe for each SComponent and Update the PersistanceRef
767       //-----------------------------------------------------------------------
768       hdf_group_datacomponent = new HDFgroup("DATACOMPONENT",hdf_file);
769       hdf_group_datacomponent->CreateOnDisk();
770
771       //SRN: Added 17 Nov, 2003
772       SALOMEDS::SObject_var anAutoSaveSO = aStudy->FindObjectID(AUTO_SAVE_TAG);
773       //SRN: End
774
775       aComponentIter.Init();
776       for(; aComponentIter.More(); aComponentIter.Next()){
777         SALOMEDS::SComponent_var sco = aComponentIter.Value();
778           
779         CORBA::String_var scoid = sco->GetID();
780         hdf_sco_group = new HDFgroup(scoid,hdf_group_datacomponent);
781         hdf_sco_group->CreateOnDisk();
782         
783         CORBA::String_var componentDataType = sco->ComponentDataType();
784         MESSAGE ( "Look for  an engine for data type :"<< componentDataType);
785         
786         //SRN: Added 17 Nov 2003: If there is a specified attribute, the component peforms a special save         
787         if(!CORBA::is_nil(anAutoSaveSO) && SB->IsGUID(sco, AUTO_SAVE_GUID)){        
788           SALOMEDS::GenericAttribute_var aGeneric;
789           SALOMEDS::AttributeTableOfString_var aTable;
790           if(anAutoSaveSO->FindAttribute(aGeneric, "AttributeTableOfString")){
791             aTable = SALOMEDS::AttributeTableOfString::_narrow(aGeneric);
792             Standard_Integer nbRows = aTable->GetNbRows(), k, aTimeOut = 0;
793             if(nbRows > 0 && aTable->GetNbColumns() > 1) {      
794               SALOMEDS::StringSeq_var aRow;
795               for(k=1; k<=nbRows; k++){
796                 aRow = aTable->GetRow(k);
797                 if(strcmp(aRow[0], componentDataType) == 0){
798                   CORBA::String_var anEntry = CORBA::string_dup(aRow[1]);
799                   SALOMEDS::SObject_var aCompSpecificSO = aStudy->FindObjectID(anEntry);
800                   if(!CORBA::is_nil(aCompSpecificSO)) {
801                     SALOMEDS::AttributeInteger_var anInteger;
802                     if(aCompSpecificSO->FindAttribute(aGeneric, "AttributeInteger")) {
803                       anInteger = SALOMEDS::AttributeInteger::_narrow(aGeneric);
804                       anInteger->SetValue(-1);
805                       while(anInteger->Value() < 0) { sleep(2); if(++aTimeOut > AUTO_SAVE_TIME_OUT_IN_SECONDS) break; }
806                     }  // if(aCompSpecificSO->FindAttribute(anInteger, "AttributeInteger"))
807                   }  // if(!CORBA::is_nil(aCompSpecificSO)) 
808                 }  // if (strcmp(aRow[0], componentDataType) == 0)
809               }  // for
810               
811             }  // if(nbRows > 0 && aTable->GetNbColumns() > 1)
812             
813           }  // if(anAutoSaveSO->FindAttribute(aTable, "AttributeTableOfString")
814           
815         }  // if(SB->IsGUID(AUTO_SAVE_GUID)
816         
817         //SRN: End
818         
819         CORBA::String_var IOREngine;
820         if(sco->ComponentIOR(IOREngine)){
821           // we have found the associated engine to write the data 
822           MESSAGE ( "We have found an engine for data type :"<< componentDataType);
823           CORBA::Object_var obj = _orb->string_to_object(IOREngine);
824           SALOMEDS::Driver_var Engine = SALOMEDS::Driver::_narrow(obj) ;
825           
826           if(!CORBA::is_nil(Engine)){
827             MESSAGE ( "Save the data of type:"<< componentDataType);
828             MESSAGE("Engine :"<<Engine->ComponentDataType());
829             
830             SALOMEDS::TMPFile_var aStream;
831             
832             SALOMEDS::unlock(); // asv : fix for PAL8727 
833             if(theASCII) 
834               aStream = Engine->SaveASCII(sco,SALOMEDS_Tool::GetDirFromPath(aUrl).c_str(),theMultiFile);
835             else
836               aStream = Engine->Save(sco,SALOMEDS_Tool::GetDirFromPath(aUrl).c_str(),theMultiFile);
837             SALOMEDS::lock();  // asv : fix for PAL8727
838
839             HDFdataset *hdf_dataset;
840             hdf_size aHDFSize[1];
841             if(aStream->length() > 0){  //The component saved some auxiliary files, then put them into HDF file 
842               
843               aHDFSize[0] = aStream->length();
844               
845               HDFdataset *hdf_dataset = new HDFdataset("FILE_STREAM", hdf_sco_group, HDF_STRING, aHDFSize, 1);
846               hdf_dataset->CreateOnDisk();
847               hdf_dataset->WriteOnDisk((unsigned char*) &aStream[0]);  //Save the stream in the HDF file
848               hdf_dataset->CloseOnDisk();
849             }
850             // store multifile state
851             aHDFSize[0] = 2;
852             hdf_dataset = new HDFdataset("MULTIFILE_STATE", hdf_sco_group, HDF_STRING, aHDFSize, 1);
853             hdf_dataset->CreateOnDisk();
854             hdf_dataset->WriteOnDisk((void*)(theMultiFile?"M":"S")); // save: multi or single
855             hdf_dataset->CloseOnDisk();
856             hdf_dataset=0; //will be deleted by hdf_sco_AuxFiles destructor              
857             
858             // store ASCII state
859             aHDFSize[0] = 2;
860             hdf_dataset = new HDFdataset("ASCII_STATE", hdf_sco_group, HDF_STRING, aHDFSize, 1);
861             hdf_dataset->CreateOnDisk();
862             hdf_dataset->WriteOnDisk((void*)(theASCII?"A":"B")); // save: ASCII or BINARY
863             hdf_dataset->CloseOnDisk();
864             hdf_dataset=0; //will be deleted by hdf_sco_AuxFiles destructor              
865             
866             SALOMEDS::unlock(); //srn: fix for bug PAL8727
867             Translate_IOR_to_persistentID(aStudy,SB,sco,Engine,theMultiFile, theASCII);
868             SALOMEDS::lock();   //srn: fix for bug PAL8727
869             MESSAGE("After Translate_IOR_to_persistentID");
870                   
871             // Creation of the persistance reference  attribute
872           }
873         }
874         hdf_sco_group->CloseOnDisk();
875         hdf_sco_group=0; // will be deleted by hdf_group_datacomponent destructor
876       }
877       hdf_group_datacomponent->CloseOnDisk();
878       hdf_group_datacomponent =0;  // will be deleted by hdf_file destructor
879       
880       
881       //-----------------------------------------------------------------------
882       //3 - Write the Study Structure
883       //-----------------------------------------------------------------------
884       hdf_group_study_structure = new HDFgroup("STUDY_STRUCTURE",hdf_file);
885       hdf_group_study_structure->CreateOnDisk();
886
887       // save component attributes
888       aComponentIter.Init();
889       for(; aComponentIter.More(); aComponentIter.Next()){
890         SALOMEDS::SComponent_var SC = aComponentIter.Value();
891         
892         CORBA::String_var scid = SC->GetID();
893         hdf_sco_group2 = new HDFgroup(scid,hdf_group_study_structure);
894         hdf_sco_group2->CreateOnDisk();
895         SaveAttributes(SC, hdf_sco_group2);
896         // ComponentDataType treatment
897         CORBA::String_var component_name = SC->ComponentDataType();
898         MESSAGE("Component data type " << component_name << " treated");
899         
900         name_len = (hdf_int32) strlen(component_name.in());
901         size[0] = name_len +1 ; 
902         hdf_dataset = new HDFdataset("COMPONENTDATATYPE",hdf_sco_group2,HDF_STRING,size,1);
903         hdf_dataset->CreateOnDisk();
904         hdf_dataset->WriteOnDisk(const_cast<char*>(component_name.in()));
905         MESSAGE("component name " <<  component_name << " wrote on file");
906         hdf_dataset->CloseOnDisk();
907         hdf_dataset=0; //will be deleted by hdf_sco_group destructor
908         _SaveObject(aStudy, SC, hdf_sco_group2);
909         hdf_sco_group2->CloseOnDisk();
910         hdf_sco_group2=0; // will be deleted by hdf_group_study_structure destructor
911       }
912       //-----------------------------------------------------------------------
913       //4 - Write the Study UseCases Structure
914       //-----------------------------------------------------------------------
915       SALOMEDS::SObject_var aSO = aStudy->FindObjectID(USE_CASE_LABEL_ID);
916       if(!aSO->_is_nil()){
917         HDFgroup *hdf_soo_group = new HDFgroup(USE_CASE_LABEL_ID,hdf_group_study_structure);
918         hdf_soo_group->CreateOnDisk();
919         SaveAttributes(aSO, hdf_soo_group);
920         _SaveObject(aStudy, aSO, hdf_soo_group);
921         MESSAGE("Use cases data structure writed");
922         hdf_soo_group->CloseOnDisk();
923         hdf_soo_group=0; // will be deleted by hdf_group_study_structure destructor
924       }
925
926       if (aLocked) 
927         aStudy->GetProperties()->SetLocked(true);
928       //-----------------------------------------------------------------------
929       //5 - Write the Study Properties
930       //-----------------------------------------------------------------------
931       name_len = (hdf_int32) strlen(aStudy->Name());
932       size[0] = name_len +1 ; 
933       hdf_dataset = new HDFdataset("STUDY_NAME",hdf_group_study_structure,HDF_STRING,size,1);
934       hdf_dataset->CreateOnDisk();
935       CORBA::String_var studid = aStudy->Name();
936       hdf_dataset->WriteOnDisk(studid);
937       MESSAGE("study name " << studid << " wrote on file");
938       hdf_dataset->CloseOnDisk();
939       hdf_dataset=0; // will be deleted by hdf_group_study_structure destructor
940
941       _SaveProperties(aStudy, hdf_group_study_structure);
942
943       hdf_group_study_structure->CloseOnDisk();
944       hdf_file->CloseOnDisk();
945
946       _name_service.Change_Directory("/Study");
947       _name_service.Destroy_Name(anOldName);
948       _name_service.Register(theStudy, aStudy->Name());
949
950       aStudy->IsSaved(true);
951       hdf_group_study_structure =0; // will be deleted by hdf_file destructor
952       delete hdf_file; // recursively deletes all hdf objects...
953     }catch(HDFexception){
954       MESSAGE( "HDFexception ! " );
955     }
956     if(theASCII){ // save file in ASCII format
957       HDFascii::ConvertFromHDFToASCII(aUrl, true);
958     }
959   }
960 }
961
962 //============================================================================
963 /*! Function : _SaveObject
964  *  Purpose  :
965  */
966 //============================================================================
967 void SALOMEDS_StudyManager_i::_SaveObject(SALOMEDS_Study_i* theStudy, 
968                                           SALOMEDS::SObject_ptr theSObject, 
969                                           HDFgroup *hdf_group_datatype)
970 {
971   // Write in group hdf_group_datatype all informations of SObject SC
972   // Iterative function to parse all SObjects under a SComponent
973   SALOMEDS::SObject_var RefSO;
974   HDFgroup *hdf_group_sobject = 0;
975
976   SALOMEDS_ChildIterator_i aChildIter = theStudy->GetChildIterator(theSObject);
977   for(; aChildIter.More(); aChildIter.Next()){
978     SALOMEDS::SObject_var aSObject = aChildIter.Value();
979     SALOMEDS::ListOfAttributes_var anAllAttributes = aSObject->GetAllAttributes();
980     
981     // mpv: don't save empty labels
982     if(anAllAttributes->length() == 0 && !aSObject->ReferencedObject(RefSO)){
983       SALOMEDS_ChildIterator_i aSubChildIter = theStudy->GetChildIterator(theSObject);
984       if(!aSubChildIter.More())
985         continue;
986
987       aSubChildIter.InitEx(true);
988       bool anEmpty = true;
989       for(; aSubChildIter.More() && anEmpty; aSubChildIter.Next()){
990         SALOMEDS::SObject_var aSObj = aSubChildIter.Value();
991         SALOMEDS::ListOfAttributes_var anAllAttr = aSObj->GetAllAttributes();
992         if(anAllAttr->length() != 0 || aSObj->ReferencedObject(RefSO)) 
993           anEmpty = false;
994       }
995       if(anEmpty)
996         continue;
997     }
998
999     CORBA::String_var scoid(aSObject->GetID());
1000     hdf_group_sobject = new HDFgroup(scoid,hdf_group_datatype);
1001     hdf_group_sobject->CreateOnDisk();
1002     SaveAttributes(aSObject, hdf_group_sobject);
1003     _SaveObject(theStudy,aSObject, hdf_group_sobject);
1004     hdf_group_sobject->CloseOnDisk();
1005     hdf_group_sobject =0; // will be deleted by father hdf object destructor
1006   }
1007 }
1008
1009 //============================================================================
1010 /*! Function : _SubstituteSlash
1011  *  Purpose  :
1012  */
1013 //============================================================================
1014
1015 std::string SALOMEDS_StudyManager_i::_SubstituteSlash(const char *theUrl)
1016 {
1017   ASSERT(1==0);
1018   TCollection_ExtendedString aUrl(const_cast<char*>(theUrl));
1019   aUrl.ChangeAll(ToExtCharacter('/'),ToExtCharacter(':'));
1020   TCollection_AsciiString ch(aUrl);
1021   return ch.ToCString();
1022 }
1023
1024 //============================================================================
1025 /*! Function : CanCopy
1026  *  Purpose  : 
1027  */
1028 //============================================================================
1029 CORBA::Boolean SALOMEDS_StudyManager_i::CanCopy(SALOMEDS::SObject_ptr theObject) {
1030   SALOMEDS::Driver_var Engine;
1031   { // Guarded block of code
1032     SALOMEDS::Locker lock;
1033
1034     SALOMEDS::SComponent_var aComponent = theObject->GetFatherComponent();
1035
1036     if(aComponent->_is_nil()) 
1037       return false;
1038
1039     if(aComponent == theObject) 
1040       return false;
1041
1042     CORBA::String_var IOREngine;
1043     if(!aComponent->ComponentIOR(IOREngine)) 
1044       return false;
1045
1046     CORBA::Object_var obj = _orb->string_to_object(IOREngine);
1047     Engine = SALOMEDS::Driver::_narrow(obj);
1048     if (CORBA::is_nil(Engine)) 
1049       return false;
1050   } // End of guarded block of code
1051   return Engine->CanCopy(theObject);
1052 }
1053
1054 //============================================================================
1055 /*! Function : CopyLabel
1056  *  Purpose  : 
1057  */
1058 //============================================================================
1059 void SALOMEDS_StudyManager_i::CopyLabel(SALOMEDS_Study_i* theSourceStudy,
1060                                         const SALOMEDS::Driver_ptr theEngine,
1061                                         const Standard_Integer theSourceStartDepth,
1062                                         const TDF_Label& theSource,
1063                                         const TDF_Label& theDestinationMain) 
1064 {
1065   int a;
1066   TDF_Label aTargetLabel = theDestinationMain;
1067   TDF_Label aAuxTargetLabel = theDestinationMain.Father().FindChild(2);
1068   for(a = theSource.Depth() - theSourceStartDepth; a > 0 ; a--) {
1069     TDF_Label aSourceLabel = theSource;
1070     for(int aNbFather = 1; aNbFather < a; aNbFather++) aSourceLabel = aSourceLabel.Father();
1071     aTargetLabel = aTargetLabel.FindChild(aSourceLabel.Tag());
1072     aAuxTargetLabel = aAuxTargetLabel.FindChild(aSourceLabel.Tag());
1073   }
1074   // iterate attributes
1075   TDF_AttributeIterator anAttrIterator(theSource);
1076   Handle(TDF_RelocationTable) aRT = new TDF_RelocationTable();
1077   for(; anAttrIterator.More(); anAttrIterator.Next()) {
1078     Handle(TDF_Attribute) anAttr = anAttrIterator.Value();
1079     if (!Handle(TDataStd_TreeNode)::DownCast(anAttr).IsNull()) continue; // never copy tree node attribute
1080     if (!Handle(SALOMEDS_TargetAttribute)::DownCast(anAttr).IsNull()) continue; // and target attribute
1081     
1082     if (!Handle(TDF_Reference)::DownCast(anAttr).IsNull()) { // reference copied as Comment in auxiliary tree
1083       TDF_Label aReferenced = Handle(TDF_Reference)::DownCast(anAttr)->Get();
1084       TCollection_AsciiString anEntry;
1085       TDF_Tool::Entry(aReferenced, anEntry);
1086       // store the value of name attribute of referenced label
1087       Handle(TDataStd_Name) aNameAttribute;
1088       if (aReferenced.FindAttribute(TDataStd_Name::GetID(), aNameAttribute)) {
1089         anEntry += " ";
1090         anEntry += aNameAttribute->Get();
1091       }
1092       TDataStd_Comment::Set(aAuxTargetLabel, TCollection_ExtendedString(anEntry));
1093       continue;
1094     }
1095     
1096     if (Handle(SALOMEDS_IORAttribute)::DownCast(anAttr).IsNull()) { // IOR => ID and TMPFile of Engine
1097       Handle(TDF_Attribute) aNewAttribute = anAttr->NewEmpty();
1098       aTargetLabel.AddAttribute(aNewAttribute);
1099       anAttr->Paste(aNewAttribute, aRT);
1100       continue;
1101     }
1102
1103     TCollection_AsciiString anEntry;
1104     TDF_Tool::Entry(theSource, anEntry);
1105     SALOMEDS::SObject_var aSO = theSourceStudy->FindObjectID(anEntry.ToCString());
1106     CORBA::Long anObjID;
1107
1108     // PAL8065: san - CopyLabel() should always be called from some CORBA method protected with a lock
1109     SALOMEDS::unlock();
1110     SALOMEDS::TMPFile_var aStream = theEngine->CopyFrom(aSO, anObjID);
1111     SALOMEDS::lock();
1112
1113     int aLen = aStream->length();
1114     TCollection_ExtendedString aResStr("");
1115     for(a = 0; a < aLen; a++) {
1116       aResStr += TCollection_ExtendedString(ToExtCharacter((Standard_Character)aStream[a]));
1117     }
1118     TDataStd_Integer::Set(aAuxTargetLabel, anObjID);
1119     TDataStd_Name::Set(aAuxTargetLabel, aResStr);
1120
1121 //      aRT->SetRelocation(anAttr, aNewAttribute);
1122   }
1123 }
1124
1125 //============================================================================
1126 /*! Function : Copy
1127  *  Purpose  :
1128  */
1129 //============================================================================
1130 CORBA::Boolean SALOMEDS_StudyManager_i::Copy(SALOMEDS::SObject_ptr theObject) {
1131   SALOMEDS::Locker lock;
1132    
1133   // adoptation for alliances datamodel copy: without IOR attributes !!!
1134   // copy only SObjects and attributes without component help
1135   SALOMEDS::GenericAttribute_var anAttribute;
1136   bool aStructureOnly = !theObject->FindAttribute(anAttribute, "AttributeIOR");
1137
1138   PortableServer::ServantBase_var aServant = GetServant(theObject,_poa);
1139   SALOMEDS_SObject_i* aSObject = dynamic_cast<SALOMEDS_SObject_i*>(aServant.in());
1140   if(aSObject == NULL) 
1141     return false;
1142
1143   SALOMEDS_Study_i* aStudy = aSObject->GetStudyServant();
1144   SALOMEDS::Driver_var anEngine;
1145   CORBA::String_var aString;
1146   if (!aStructureOnly) {
1147     SALOMEDS::SComponent_var aComponent = theObject->GetFatherComponent();
1148     if(!aComponent->ComponentIOR(aString)) 
1149       return false;
1150
1151     CORBA::Object_var anObj = _orb->string_to_object(aString);
1152     anEngine = SALOMEDS::Driver::_narrow(anObj) ;
1153   }
1154
1155   // CAF document of current study usage
1156   Handle(TDocStd_Document) aDocument = aStudy->GetDocument();
1157   if(aDocument.IsNull()) 
1158     return false;
1159
1160   // create new document for clipboard
1161   Handle(TDocStd_Document) aTargetDocument;
1162   _OCAFApp->NewDocument("SALOME_STUDY", aTargetDocument);
1163   // set component data type to the name attribute of root label
1164   if(!aStructureOnly){
1165     aString = anEngine->ComponentDataType();
1166     TDataStd_Comment::Set(aTargetDocument->Main().Root(),const_cast<char*>(aString.in()));
1167   }
1168   // set to the Root label integer attribute: study id
1169   TDataStd_Integer::Set(aTargetDocument->Main().Root(),aStudy->StudyId());
1170
1171   // iterate all theObject's label children
1172   TDF_Label aStartLabel;
1173   aString = theObject->GetID();
1174   TDF_Tool::Label(aDocument->GetData(),const_cast<char*>(aString.in()),aStartLabel);
1175   Standard_Integer aSourceStartDepth = aStartLabel.Depth();
1176   
1177   // copy main source label
1178   CopyLabel(aStudy,anEngine,aSourceStartDepth,aStartLabel,aTargetDocument->Main());
1179
1180   // copy all subchildren of the main source label (all levels)
1181   TDF_ChildIterator anIterator(aStartLabel,Standard_True);
1182   for(; anIterator.More(); anIterator.Next()){
1183     CopyLabel(aStudy,anEngine,aSourceStartDepth,anIterator.Value(),aTargetDocument->Main());
1184   }
1185
1186   // done: free old clipboard document and 
1187   if (!_clipboard.IsNull()) {
1188 //      Handle(TDocStd_Owner) anOwner;
1189 //      if (_clipboard->Main().Root().FindAttribute(TDocStd_Owner::GetID(), anOwner)) {
1190 //        Handle(TDocStd_Document) anEmptyDoc;
1191 //        anOwner->SetDocument(anEmptyDoc);
1192 //      }
1193     _OCAFApp->Close(_clipboard);
1194   }
1195
1196   _clipboard = aTargetDocument;
1197
1198   return true;
1199 }
1200 //============================================================================
1201 /*! Function : CanPaste
1202  *  Purpose  :
1203  */
1204 //============================================================================
1205 CORBA::Boolean SALOMEDS_StudyManager_i::CanPaste(SALOMEDS::SObject_ptr theObject) {
1206   CORBA::String_var aName;
1207   Standard_Integer anID;
1208   SALOMEDS::Driver_var Engine;
1209   { // Guarded block of code
1210     SALOMEDS::Locker lock;
1211
1212     if (_clipboard.IsNull()) return false;
1213
1214     Handle(TDataStd_Comment) aCompName;
1215     if (!_clipboard->Main().Root().FindAttribute(TDataStd_Comment::GetID(), aCompName)) return false;
1216     Handle(TDataStd_Integer) anObjID;
1217     if (!_clipboard->Main().Father().FindChild(2).FindAttribute(TDataStd_Integer::GetID(), anObjID))
1218       return false;
1219
1220     SALOMEDS::SComponent_var aComponent = theObject->GetFatherComponent();
1221     if(aComponent->_is_nil()) 
1222       return false;
1223   
1224     CORBA::String_var IOREngine;
1225     if(!aComponent->ComponentIOR(IOREngine)) 
1226       return false;
1227   
1228     CORBA::Object_var obj = _orb->string_to_object(IOREngine);
1229     Engine = SALOMEDS::Driver::_narrow(obj) ;
1230     if (CORBA::is_nil(Engine)) 
1231       return false;
1232
1233     aName = CORBA::string_dup( TCollection_AsciiString(aCompName->Get()).ToCString() );
1234     anID   = anObjID->Get();
1235   } // End of guarded block of code
1236   return Engine->CanPaste(aName.in(),anID);
1237 }
1238 //============================================================================
1239 /*! Function : PasteLabel
1240  *  Purpose  :
1241  */
1242 //============================================================================
1243 TDF_Label SALOMEDS_StudyManager_i::PasteLabel(SALOMEDS_Study_i* theDestinationStudy,
1244                                               const SALOMEDS::Driver_ptr theEngine,
1245                                               const TDF_Label& theSource,
1246                                               const TDF_Label& theDestinationStart,
1247                                               const int theCopiedStudyID,
1248                                               const bool isFirstElement) 
1249 {
1250
1251   // get corresponding source, target and auxiliary labels
1252   TDF_Label aTargetLabel = theDestinationStart;
1253   TDF_Label aAuxSourceLabel = theSource.Root().FindChild(2);
1254   int a;
1255   if (!isFirstElement) {
1256     for(a = theSource.Depth() - 1; a > 0 ; a--) {
1257       TDF_Label aSourceLabel = theSource;
1258       for(int aNbFather = 1; aNbFather < a; aNbFather++)
1259         aSourceLabel = aSourceLabel.Father();
1260       aTargetLabel = aTargetLabel.FindChild(aSourceLabel.Tag());
1261       aAuxSourceLabel = aAuxSourceLabel.FindChild(aSourceLabel.Tag());
1262     }
1263   }
1264
1265   // check auxiliary label for TMPFile => IOR
1266   Handle(TDataStd_Name) aNameAttribute;
1267   if (aAuxSourceLabel.FindAttribute(TDataStd_Name::GetID(), aNameAttribute)) {
1268     Handle(TDataStd_Integer) anObjID;
1269
1270     aAuxSourceLabel.FindAttribute(TDataStd_Integer::GetID(), anObjID);
1271     Handle(TDataStd_Comment) aComponentName;
1272     theSource.Root().FindAttribute(TDataStd_Comment::GetID(), aComponentName);
1273     std::string aCompName = TCollection_AsciiString(aComponentName->Get()).ToCString();
1274     if (theEngine->CanPaste(aCompName.c_str(),anObjID->Get())) {
1275       SALOMEDS::TMPFile_var aTMPFil = new SALOMEDS::TMPFile();
1276       TCollection_ExtendedString aTMPStr = aNameAttribute->Get();
1277       int aLen = aTMPStr.Length();
1278       aTMPFil->length(aLen);
1279       for(a = 0; a < aLen; a++) {
1280         aTMPFil[a] = ToCharacter(aTMPStr.Value(a+1));
1281       }
1282       TCollection_AsciiString anEntry;
1283       TDF_Tool::Entry(aTargetLabel, anEntry);
1284       SALOMEDS::SObject_var aPastedSO = theDestinationStudy->FindObjectID(anEntry.ToCString());
1285       if(isFirstElement){
1286         // PAL8065: san - PasteLabel() should always be called from some CORBA method protected with a lock
1287         SALOMEDS::unlock();
1288         SALOMEDS::SObject_var aDestSO =
1289           theEngine->PasteInto(aTMPFil.in(),
1290                                anObjID->Get(),
1291                                aPastedSO->GetFatherComponent());
1292         SALOMEDS::lock();
1293         TDF_Tool::Label(theDestinationStart.Data(), aDestSO->GetID(), aTargetLabel);
1294       }else 
1295         // PAL8065: san - PasteLabel() should always be called from some CORBA method protected with a lock
1296         SALOMEDS::unlock();
1297         theEngine->PasteInto(aTMPFil.in(),anObjID->Get(),aPastedSO);
1298         SALOMEDS::lock();
1299     }
1300   }
1301
1302   // iterate attributes
1303   TDF_AttributeIterator anAttrIterator(theSource);
1304   Handle(TDF_RelocationTable) aRT = new TDF_RelocationTable();
1305   for(; anAttrIterator.More(); anAttrIterator.Next()) {
1306     Handle(TDF_Attribute) anAttr = anAttrIterator.Value();
1307     if (aTargetLabel.FindAttribute(anAttr->ID(), anAttr)) {
1308       aTargetLabel.ForgetAttribute(anAttr->ID());
1309       anAttr = anAttrIterator.Value();
1310     }
1311     Handle(TDF_Attribute) aNewAttribute = anAttr->NewEmpty();
1312     aTargetLabel.AddAttribute(aNewAttribute);
1313     anAttr->Paste(aNewAttribute, aRT);
1314 //      aRT->SetRelocation(anAttr, aNewAttribute);
1315   }
1316   // check auxiliary label for Comment => reference or name attribute of the referenced object
1317   Handle(TDataStd_Comment) aCommentAttribute;
1318   if (aAuxSourceLabel.FindAttribute(TDataStd_Comment::GetID(), aCommentAttribute)) {
1319     std::string anEntry(TCollection_AsciiString(aCommentAttribute->Get()).ToCString());
1320     std::size_t aNameStart = anEntry.find(' ');
1321     std::string aName;
1322     if(aNameStart != std::string::npos){
1323       aName = anEntry.substr(aNameStart+1);
1324       anEntry = anEntry.substr(0,aNameStart);
1325     }
1326     if (theCopiedStudyID == theDestinationStudy->StudyId()) { // if copy to the same study, reanimate reference
1327       TDF_Label aRefLabel;
1328       TDF_Tool::Label(aTargetLabel.Data(),&anEntry[0],aRefLabel);
1329       TDF_Reference::Set(aTargetLabel, aRefLabel);
1330       SALOMEDS_TargetAttribute::Set(aRefLabel)->Append(aTargetLabel); // target attributes structure support
1331     } else {
1332       if(aNameStart != std::string::npos)
1333         TDataStd_Name::Set(aTargetLabel, &aName[0]);
1334       else
1335         TDataStd_Name::Set(aTargetLabel, 
1336                            TCollection_ExtendedString("Reference to:") + &anEntry[0]);
1337     }
1338   }
1339
1340   return aTargetLabel;
1341 }
1342 //============================================================================
1343 /*! Function : Paste
1344  *  Purpose  :
1345  */
1346 //============================================================================
1347 SALOMEDS::SObject_ptr SALOMEDS_StudyManager_i::Paste(SALOMEDS::SObject_ptr theObject)
1348      throw(SALOMEDS::StudyBuilder::LockProtection)
1349 {
1350   SALOMEDS::Locker lock;
1351
1352   Unexpect aCatch(LockProtection);
1353
1354   PortableServer::ServantBase_var aServant = GetServant(theObject,_poa);
1355   SALOMEDS_SObject_i* aSObject = dynamic_cast<SALOMEDS_SObject_i*>(aServant.in());
1356   if(aSObject == NULL) 
1357     return false;
1358
1359   SALOMEDS_Study_i* aStudy = aSObject->GetStudyServant();
1360
1361   // if study is locked, then paste can't be done
1362   if (aStudy->GetProperties()->IsLocked())
1363     throw SALOMEDS::StudyBuilder::LockProtection();
1364
1365   // if there is no component name, then paste only SObjects and attributes: without component help
1366   Handle(TDataStd_Comment) aComponentName;
1367   bool aStructureOnly = !_clipboard->Main().Root().FindAttribute(TDataStd_Comment::GetID(), aComponentName);
1368
1369   // get copied study ID
1370   Handle(TDataStd_Integer) aStudyIDAttribute;
1371   if (!_clipboard->Main().Root().FindAttribute(TDataStd_Integer::GetID(), aStudyIDAttribute))
1372     return SALOMEDS::SObject::_nil();
1373
1374   // get component-engine
1375   SALOMEDS::SComponent_var aComponent;
1376   SALOMEDS::Driver_var anEngine;
1377   CORBA::String_var aString;
1378   if (!aStructureOnly) {
1379     aComponent = theObject->GetFatherComponent();
1380     if(!aComponent->ComponentIOR(aString)) 
1381       return SALOMEDS::SObject::_nil();
1382
1383     CORBA::Object_var anObj = _orb->string_to_object(aString);
1384     anEngine = SALOMEDS::Driver::_narrow(anObj) ;
1385   }
1386
1387   // CAF document of current study usage
1388   Handle(TDocStd_Document) aDocument = aStudy->GetDocument();
1389   if (aDocument.IsNull()) 
1390     return SALOMEDS::SObject::_nil();
1391
1392   // fill root inserted SObject
1393   int aCStudyID = aStudyIDAttribute->Get();
1394   TDF_Label aLabel = aStructureOnly? aSObject->GetLabel(): aSObject->GetFatherComponentLabel();
1395   TDF_Label aStartLabel = PasteLabel(aStudy,anEngine,_clipboard->Main(),aLabel,aCStudyID,true);
1396
1397   // paste all sublebels
1398   TDF_ChildIterator anIterator(_clipboard->Main(),Standard_True);
1399   for(; anIterator.More(); anIterator.Next()) {
1400     PasteLabel(aStudy,anEngine,anIterator.Value(),aStartLabel,aCStudyID,false);
1401   }
1402
1403   return SALOMEDS_SObject_i::NewRef(aStudy,aStartLabel)._retn();
1404 }