Salome HOME
This commit was generated by cvs2git to create tag 'V1_4_0b1'.
[modules/kernel.git] / src / SALOMEGUI / QAD_Study.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
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   : QAD_Study.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SALOME
27 //  $Header$
28
29 using namespace std;
30 /*!
31   \class QAD_Study QAD_Study.h
32   \brief Study for QAD-based application.
33 */
34
35 #include "QAD.h"
36 #include "QAD_Tools.h"
37 #include "QAD_Desktop.h"
38 #include "QAD_Study.h"
39 #include "QAD_RightFrame.h"
40 #include "QAD_LeftFrame.h"
41 #include "QAD_MessageBox.h"
42 #include "QAD_Application.h"
43 #include "QAD_ObjectBrowser.h"
44 #include "QAD_PyInterp.h"
45 #include "QAD_Config.h"
46  
47 #include "utilities.h"
48
49 #include "SALOME_Selection.h"
50 #include "SALOME_TypeFilter.hxx"
51 #include "SALOME_InteractiveObject.hxx"
52 #include "SALOME_ListIteratorOfListIO.hxx"
53
54 #include <SALOMEconfig.h>
55 #include CORBA_SERVER_HEADER(SALOMEDS)
56
57 // OPEN CASCADE Include
58 #include <Standard_Failure.hxx>
59
60 // QT Include
61 #include <qapplication.h>
62
63 /*!
64     Constructor
65 */
66 QAD_Study::QAD_Study(QAD_Application* app,
67                      SALOMEDS::Study_var aStudy,
68                      const QString& path ) :
69 myOperationState( Undef ),
70 myApp( app ),
71 myActiveStudyFrame( 0 ),
72 myStudyFrameCount( 0 ),
73 myPath( path )
74 {
75     myStudy = aStudy;
76
77     myTitle = QAD_Tools::getFileNameFromPath( path, true );
78
79     myIsActive = false;
80     myIsSaved = false;
81     myIsModified = false;
82     myIsReadOnly = false;
83
84     myStudyFrames.clear();
85     myOperations.clear();
86
87     myStudyFrames.setAutoDelete( true );
88     myOperations.setAutoDelete( true );
89     myChildWidgets.setAutoDelete( true );
90
91     /* create python interpreter */
92     _interp = new QAD_PyInterp();
93     SCRUTE(_interp);
94
95     /* create default selection */
96     //NRI    Selection( "Salome" );
97     Selection( QAD_Application::getDesktop()->getComponentUserName( "KERNEL" ) );
98
99     /* create study frame */
100     myResult = true;
101     createStudyFrame( getNextStudyFrameName() );
102
103     /* set default Undo/Redo limit */
104     QAD_ASSERT_DEBUG_ONLY( !myStudy->_is_nil() );
105     SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
106
107     int aLocked = myStudy->GetProperties()->IsLocked();
108     if (aLocked) myStudy->GetProperties()->SetLocked(false);
109     SB->UndoLimit(QAD_Desktop::getUndoLevel());
110     if (aLocked) myStudy->GetProperties()->SetLocked(true);
111
112 }
113
114 /*!
115     Destructor
116 */
117 QAD_Study::~QAD_Study ()
118 {
119   close();
120   //SRN: added - clear selection in case the study will be loaded again so the title will coincide
121   SALOME_Selection::RemoveSelection( QString(myTitle + "_" + mySelection) );
122 }
123
124 /*!
125   Returns TRUE if Study is created correctly. Returns FALSE otherwise.
126 */
127 bool QAD_Study::getResult()
128 {
129   return myResult;
130 }
131
132
133 //=======================================================================//
134 //                          StudyFrames management                       //
135 //=======================================================================//
136 /*!
137     Adds study frame
138 */
139 void QAD_Study::addStudyFrame(QAD_StudyFrame* sf )
140 {
141   myStudyFrames.append( sf );
142   
143   sf->getRightFrame()->getViewFrame()->setPopupServer( myApp );
144   // Provide the same common popup menu commands for both the Object Browser and 3D viewer
145   sf->getLeftFrame()->getObjectBrowser()->setPopupServer( myApp );
146
147   /* icon of Study Frame */
148   const QPixmap& icon = myApp->getApplicationIcon();
149   if ( !icon.isNull() )
150     sf->setIcon ( icon );
151
152   /* activation */
153   QAD_ASSERT ( connect( sf, SIGNAL(sfStudyFrameActivated(QAD_StudyFrame*) ),
154                         SLOT(onStudyFrameActivated(QAD_StudyFrame*))) );
155
156   /* closing */
157   QAD_ASSERT ( connect( sf,
158                         SIGNAL(sfStudyFrameClosing(QAD_StudyFrame*) ),
159                         this,
160                         SLOT(onLastStudyFrameClosing(QAD_StudyFrame*))) );
161
162   /* set active sf */
163   myActiveStudyFrame = sf;
164 }
165
166 /*!
167     Removes studyframe from the list
168 */
169 void QAD_Study::removeStudyFrame( QAD_StudyFrame* sf )
170 {
171   if (sf) {
172     if (!myStudy->IsEmpty()) {
173       SALOMEDS::SObject_var fatherSF = myStudy->FindObjectID(sf->entry());
174       if (!fatherSF->_is_nil()) {
175         SALOMEDS::StudyBuilder_var aStudyBuilder = myStudy->NewBuilder();
176         int aLocked = myStudy->GetProperties()->IsLocked();
177         if (aLocked) myStudy->GetProperties()->SetLocked(false);
178         aStudyBuilder->RemoveObject(fatherSF);
179         if (aLocked) myStudy->GetProperties()->SetLocked(true);
180       }
181       
182       updateObjBrowser( true );
183     }
184     myStudyFrames.removeRef( sf );
185   }
186 }
187
188 /*!
189   Returns number of study frames
190 */
191 int QAD_Study::getStudyFramesCount() const
192 {
193   return myStudyFrames.count();
194 }
195
196 /*!
197   Returns study frame by its index in list
198 */
199 QAD_StudyFrame* QAD_Study::getStudyFrame( unsigned i )
200 {
201   return myStudyFrames.at(i);
202 }
203
204 /*!
205   Returns study frame by its name or null if not found
206 */
207 QAD_StudyFrame* QAD_Study::getStudyFrameByName ( const QString& name )
208 {
209   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() )
210     {
211       if ( sf->title().compare(name) == 0 ) {
212         return sf;
213       }
214     }
215   return NULL;
216 }
217
218 /*!
219   Returns first study frame in the list
220 */
221 QAD_StudyFrame* QAD_Study::getFirstStudyFrame()
222 {
223   return myStudyFrames.first();
224 }
225
226 /*!
227   Returns last study frame in the list
228 */
229 QAD_StudyFrame* QAD_Study::getLastStudyFrame()
230 {
231   return myStudyFrames.last();
232 }
233
234 /*!
235   Returns the vector of studyframes
236 */
237 const QList<QAD_StudyFrame>& QAD_Study::getStudyFrames() const
238 {
239   return myStudyFrames;
240 }
241
242 /*!
243   Returns the active study frame
244 */
245 QAD_StudyFrame* QAD_Study::getActiveStudyFrame() const
246 {
247   return myActiveStudyFrame;
248 }
249
250 //=======================================================================//
251 //                  Study properties                                     //
252 //=======================================================================//
253 /*!
254   Returns reference to supporting application
255 */
256 QAD_Application* QAD_Study::getApp() const
257 {
258   return myApp;
259 }
260
261 /*!
262   Returns the name of document ( filename without path and extension )
263 */
264 const QString& QAD_Study::getTitle() const
265 {
266   return myTitle;
267 }
268
269 /*!
270     Returns the absolute file path of this document
271 */
272 const QString& QAD_Study::getPath() const
273 {
274   return myPath;
275 }
276
277 /*!
278     Changes the name of document
279 */
280 void QAD_Study::setTitle( const QString& path )
281 {
282   myPath = path;
283
284   QString title = QAD_Tools::getFileNameFromPath( path, true );
285   QAD_ASSERT_DEBUG_ONLY ( !title.isNull() );
286
287   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf ; sf = myStudyFrames.next() )
288     {
289       QString oldName = sf->title();
290       int k = oldName.find( myTitle, 0, false );
291       QString restName = ( oldName.length() > myTitle.length() + k) ?
292         oldName.right(oldName.length() - (myTitle.length() + k) + 1) :
293         QString( "" );
294
295       if ( k != -1 )
296         {
297           QString newName;
298           if ( k == 0 ) {
299             int l = restName.find( "#", 0, false );
300             int ll =  restName.length();
301             newName = title + restName.mid( l, ll-l );
302           } else {
303             newName = oldName.mid(0, k);
304             newName = newName + title + restName;
305           }
306           sf->setTitle( newName );
307         }
308     }
309   myTitle = title;
310
311   Selection( QAD_Application::getDesktop()->getActiveComponent() );
312 }
313
314 /*!
315     Returns whether the document is active
316 */
317 bool QAD_Study::isActive() const
318 {
319   return myIsActive;
320 }
321
322 /*!
323     Returns whether the document is read only
324 */
325 bool QAD_Study::isReadOnly() const 
326 {
327   return myIsReadOnly;
328 }
329
330 /*!
331     Sets read-only property
332 */
333 void QAD_Study::setReadOnly(bool state)
334 {
335   myIsReadOnly = state;
336 }
337
338 //=======================================================================//
339 //                      Study operations                                 //
340 //=======================================================================//
341 /*!
342     Performs specific study frame related actions when it is activated.
343     By default resumes all suspended operations.
344 */
345 void QAD_Study::onStudyFrameActivated( QAD_StudyFrame* activeStudyFrame )
346 {
347   static int IS_FIRST_STUDY = 1;  
348   if(IS_FIRST_STUDY){ //for normally initialize "salome.py and ..."
349     _interp->run("");  IS_FIRST_STUDY = 0;
350   }
351 //  bool found = false;
352   for ( QAD_StudyFrame* studyframe = myStudyFrames.first(); studyframe; studyframe = myStudyFrames.next() ) {
353     if ( studyframe == activeStudyFrame) {              /* one of my study frames */
354 //      found = true;
355 //      if ( !myActiveStudyFrame || myActiveStudyFrame != activeStudyFrame ) {
356         myActiveStudyFrame =  activeStudyFrame;
357         //NRI    if ( !myIsActive ) {
358         myIsActive = true;
359         resumeAllOperations();
360         /* activate application */
361         myApp->onStudyActivated( this );
362         //NRI      }
363 //      }
364 //      return;
365     }
366   }
367 //  if (!found)
368 //    myActiveStudyFrame = 0;
369 }
370
371
372 /*!
373     Performs specific study related actions when it is deactivated.
374     By default suspends all performing operations.
375 */
376 void QAD_Study::onStudyDeactivated()
377 {
378   //  MESSAGE ("QAD_Study::onStudyDeactivated init. "); 
379   myIsActive = false;
380   suspendAllOperations();
381   //  MESSAGE ("QAD_Study::onStudyDeactivated done. "); 
382 }
383
384 /*!
385     Closes all study frames of the study and performs other specific study
386     related actions needed for proper closing of the study
387 */
388 void QAD_Study::close()
389 {
390   emit closed();
391   if ( !myStudy->_is_nil() )
392     abortAllOperations();
393     /* clear each study frame */
394     for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.first() ) {
395       sf->disconnect();
396       sf->close();
397       qApp->processEvents();
398       qApp->processEvents();
399       removeStudyFrame(sf);
400     }
401
402   /* delete all studyframes */
403   myStudyFrames.clear();
404   myOperations.clear();
405   myChildWidgets.clear();
406
407 //  QWorkspace* ws = QAD_Application::getDesktop()->getMainFrame();
408 //  if (/* !ws->activeWindow() && */ws->windowList().count() > 0 )
409 //    ws->activateWindow(ws->windowList().last());
410 }
411
412 //=======================================================================//
413 //                      Operations management                            //
414 //=======================================================================//
415 /*!
416     Returns number of completed operations
417 */
418 int QAD_Study::getOperationsCount() const
419 {
420     return myOperations.count();
421 }
422
423 /*!
424     Returns the state of the last operation
425 */
426 OperationState QAD_Study::getOperationState() const
427 {
428     return myOperationState;
429 }
430
431 /*!
432     Returns operation by its index in list
433 */
434 QAD_Operation* QAD_Study::getOperation( unsigned i)
435 {
436     return ( myOperations.isEmpty() ? 0 :  myOperations.at(i) );
437 }
438
439 /*!
440     Returns performing operation launched first
441 */
442 QAD_Operation* QAD_Study::getFirstOperation()
443 {
444     return ( myOperations.isEmpty() ? 0 :  myOperations.first() );
445 }
446
447 /*!
448     Returns performing operation launched last
449 */
450 QAD_Operation* QAD_Study::getLastOperation()
451 {
452     return ( myOperations.isEmpty() ? 0 :  myOperations.last() );
453 }
454
455 /*!
456     Aborts all performing operations
457 */
458 void QAD_Study::abortAllOperations()
459 {
460   for ( QAD_Operation* op = myOperations.last(); op;
461         op = myOperations.prev() )
462     op->abort();
463 }
464
465 /*!
466     Resumes all performing operations
467 */
468 void QAD_Study::resumeAllOperations()
469 {
470   for ( QAD_Operation* op = myOperations.first(); op;
471         op = myOperations.next() )
472     op->resume();
473 }
474
475 /*!
476     Suspendes all performing operations
477 */
478 void QAD_Study::suspendAllOperations()
479 {
480   //  MESSAGE ( " QAD_Study::suspendAllOperations init. " )
481   for ( QAD_Operation* op = myOperations.last(); op;
482         op = myOperations.prev() )
483     op->suspend();
484 }
485
486 /*!
487     Initializes the operation and checks its compatibility
488     with another operation in process if any.
489     Returns 'true' if init'ed OK, 'false' otherwise.
490 */
491 bool QAD_Study::initOperation( QAD_Operation* op )
492 {
493     if ( myIsReadOnly )
494     {   /* can't start a non-const operation */
495         if ( op->changesData() )
496         {
497             QAD_MessageBox::error1( QAD_Application::getDesktop(), tr("ERR_ERROR"),
498                                     tr("ERR_DOC_READONLY"), tr("BUT_OK") );
499             return false;
500         }
501     }
502
503     /* Add the new operation
504     */
505     if ( myOperations.isEmpty() )
506         myOperations.append( op );
507     else
508     {
509         /*  Check compatibility of new operation with the existing operations.
510             Since each operations is checked in that way, it's enough to check
511             the last operation only */
512         if ( !getLastOperation()->compatibleWith( op ) )
513         {
514             if ( QAD_MessageBox::warn2( QAD_Application::getDesktop(), tr("WRN_WARNING"),
515                                         tr("QUE_ABORTCURRENTOPERATION"), tr("BUT_YES"),
516                                         tr("BUT_NO"), QAD_YES, QAD_NO, QAD_NO )
517                    == QAD_NO )
518                 return false;
519             getLastOperation()->abort();
520         }
521         myOperations.append( op );
522     }
523     return true;
524 }
525
526 /*!
527     Called when operation was finished.
528     Removes appointed operation from the list and aborted all operations
529     launched after it.
530 */
531 void QAD_Study::clearOperation( QAD_Operation* op)
532 {
533   if ( myOperations.contains( op ) )
534     {
535       /* abort all the operations launched after 'op' */
536       for ( QAD_Operation* cur = myOperations.last(); cur;
537             cur = myOperations.prev() )
538         {
539           if ( cur == op ) break;
540           cur->abort();
541         }
542       myOperations.remove( op );
543     }
544 }
545
546 /*!
547     Creates study frame
548 */
549 QAD_StudyFrame* QAD_Study::createStudyFrame( const QString& title, ViewType theViewType)
550 {
551   QAD_Desktop* parent = QAD_Application::getDesktop();
552 //srn: Forbid appending Interface Applicative and its children to UseCase
553   myStudy->EnableUseCaseAutoFilling(false);   
554   
555   SALOMEDS::SComponent_var father = myStudy->FindComponent("Interface Applicative");
556   SALOMEDS::StudyBuilder_var aStudyBuilder = myStudy->NewBuilder();
557   SALOMEDS::GenericAttribute_var anAttr;
558   SALOMEDS::AttributeName_var    aName;
559   SALOMEDS::AttributeComment_var aComment;
560   SALOMEDS::AttributeSelectable_var aSelAttr;
561
562 // mpv : where is "NewCommand" call?
563 //  aStudyBuilder->CommitCommand();
564
565 // mpv : is study is locked, then next code will raise exception. So, temporary unlock study
566   int aLocked = myStudy->GetProperties()->IsLocked();
567   if (aLocked) myStudy->GetProperties()->SetLocked(false);
568
569   if ( father->_is_nil() ) {
570     father = aStudyBuilder->NewComponent("Interface Applicative");
571     anAttr = aStudyBuilder->FindOrCreateAttribute(father, "AttributeName");
572     aName = SALOMEDS::AttributeName::_narrow(anAttr);
573     aName->SetValue("Interface Applicative");
574     
575     anAttr = aStudyBuilder->FindOrCreateAttribute(father, "AttributeSelectable");
576     aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
577     aSelAttr->SetSelectable(false);
578   }
579   
580   //VRV: T2.5 - add default viewer
581   if(theViewType == VIEW_TYPE_MAX) {
582     QString viewerValue = QAD_CONFIG->getSetting( "Viewer:DefaultViewer" );
583     bool ok;
584     theViewType = (ViewType)viewerValue.toInt( &ok, 10 ); 
585     if (!ok || theViewType < VIEW_OCC || theViewType >= VIEW_TYPE_MAX)
586       theViewType = VIEW_VTK;
587   }
588   //QApplication::restoreOverrideCursor();
589   QAD_StudyFrame* sf = NULL;
590   SALOMEDS::SObject_var newObj = aStudyBuilder->NewObject(father);
591   if ( theViewType == VIEW_OCC) {
592     //      MESSAGE ("Create Study Frame for OCC viewer");
593     sf = new QAD_StudyFrame ( this, parent->getMainFrame(),
594                               title, _interp, VIEW_OCC );
595     
596     Standard_CString name = strdup(sf->title().latin1());
597     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName");
598     aName = SALOMEDS::AttributeName::_narrow(anAttr);
599     aName->SetValue(name);
600     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeComment");
601     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
602     aComment->SetValue("OCC");
603     
604     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeSelectable");
605     aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
606     aSelAttr->SetSelectable(false);
607   } 
608   else if ( theViewType == VIEW_VTK) {
609     //      MESSAGE ("Create Study Frame for VTK viewer");
610     sf = new QAD_StudyFrame ( this, parent->getMainFrame(),
611                               title, _interp, VIEW_VTK );
612     Standard_CString name = strdup(sf->title().latin1());
613     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName");
614     aName = SALOMEDS::AttributeName::_narrow(anAttr);
615     aName->SetValue(name);
616     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeComment");
617     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
618     aComment->SetValue("VTK");
619     
620     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeSelectable");
621     aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
622     aSelAttr->SetSelectable(false);
623   } 
624   else if ( theViewType == VIEW_GRAPHSUPERV) { 
625     //MESSAGE ("Create Study Frame for SUPER`VISOR Graph");
626     sf = new QAD_StudyFrame ( this, parent->getMainFrame(),
627                               title, _interp, VIEW_GRAPHSUPERV );
628     Standard_CString name = strdup(sf->title().latin1());
629     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName");
630     aName = SALOMEDS::AttributeName::_narrow(anAttr);
631     aName->SetValue(name);
632     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeComment");
633     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
634     aComment->SetValue("GRAPH");
635     
636     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeSelectable");
637     aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
638     aSelAttr->SetSelectable(false);
639   }
640   else if ( theViewType == VIEW_PLOT2D ) {
641     sf = new QAD_StudyFrame ( this, parent->getMainFrame(),
642                               title, _interp, VIEW_PLOT2D );
643     Standard_CString name = strdup(sf->title().latin1());
644     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeName");
645     aName = SALOMEDS::AttributeName::_narrow(anAttr);
646     aName->SetValue(name);
647     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeComment");
648     aComment = SALOMEDS::AttributeComment::_narrow(anAttr);
649     aComment->SetValue("PLOT2D");
650     
651     anAttr = aStudyBuilder->FindOrCreateAttribute(newObj, "AttributeSelectable");
652     aSelAttr = SALOMEDS::AttributeSelectable::_narrow(anAttr);
653     aSelAttr->SetSelectable(false);
654   } 
655   //VRV: T2.5 - add default viewer
656
657   sf->resize( int (0.8*parent->getMainFrame()->width()),
658               int (0.8*parent->getMainFrame()->height() ));
659   
660   sf->setEntry(newObj->GetID());
661   
662   addStudyFrame( sf );
663   
664   updateObjBrowser( true );
665   
666   parent->setSettings();
667   
668   myResult = true;
669   
670   if (aLocked) myStudy->GetProperties()->SetLocked(true);
671
672   // T2.12 - add the word "locked" to study frame captions if this study is locked
673   updateCaptions();
674
675   myStudy->EnableUseCaseAutoFilling(true);
676
677   return sf;
678 }
679
680 /*!
681    Updates study frame captions according to IsLocked study flag
682 */
683 void QAD_Study::updateCaptions()
684 {
685   QString appendix("");
686
687   if (!myStudy->_is_nil()) {
688     SALOMEDS::AttributeStudyProperties_var propAttr = myStudy->GetProperties();
689 /*    
690     if (!propAttr->_is_nil() ) {
691       if ( propAttr->IsModified() )
692         appendix += " (" + tr("PRP_STUDY_MODIFIED") + ")";
693       else
694         appendix += " (" + tr("PRP_STUDY_SAVED") + ")";
695     }  
696   
697 */
698     if (!propAttr->_is_nil() && propAttr->IsLocked()) {
699       appendix += " (" + tr("PRP_STUDY_LOCKED") + ")";
700     }
701   }
702
703   for (myStudyFrames.first(); myStudyFrames.current(); myStudyFrames.next()) {
704     myStudyFrames.current()->setCaption(myStudyFrames.current()->title() + appendix);
705   }
706   
707 }
708
709 /*!
710     Shows the active study frame.
711     Called by Desktop after 'new' and 'open' commands.
712 */
713 void QAD_Study::show()
714 {
715   for (myStudyFrames.first(); myStudyFrames.current(); myStudyFrames.next()) {
716     myStudyFrames.current()->show();
717   }
718 }
719
720 //=======================================================================//
721 //                  Study properties (CAF related)                       //
722 //=======================================================================//
723
724 /*!
725     Returns connected SALOMEDS_Study object
726 */
727 SALOMEDS::Study_var QAD_Study::getStudyDocument()
728 {
729   return myStudy;
730 }
731
732 /*!
733     Returns whether the document was saved in file
734 */
735 bool QAD_Study::isSaved() const
736 {
737   return myStudy->IsSaved();
738 }
739
740 /*!
741     Returns whether the document is modified
742 */
743 bool QAD_Study::isModified() const
744 {
745 //  return myStudy->IsModified(); // VSR:05/12/02 - USE PROPERTY : MODIFIED FLAG
746   if ( !myStudy->_is_nil() ) {
747     SALOMEDS::AttributeStudyProperties_var propAttr = myStudy->GetProperties();
748     if ( !propAttr->_is_nil() )
749       return propAttr->IsModified();
750   }
751   return false;
752 }
753
754 bool QAD_Study::undo()
755 {
756   try {
757     SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
758     SB->Undo();
759
760     /* Update Object Browser */
761     updateObjBrowser( true );
762
763     for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
764       /* Update Viewer */
765       sf->getRightFrame()->getViewFrame()->undo( myStudy, sf->entry() );
766     }
767     updateCaptions();
768
769     // mpv 07.03.2003 SAL1805: clear selection must be called after study structure changed
770     SALOME_Selection* Sel = SALOME_Selection::Selection( getSelection() );
771     Sel->ClearIObjects();
772   }
773   // mpv : undo command can raise exception, if study is locked
774   catch ( SALOMEDS::StudyBuilder::LockProtection& ) {
775     QAD_MessageBox::warn1 ((QWidget*)QAD_Application::getDesktop(),
776                            QObject::tr("WRN_WARNING"), 
777                            QObject::tr("WRN_STUDY_LOCKED"),
778                            QObject::tr("BUT_OK"));
779     return false;
780   }
781   catch ( Standard_Failure ) {
782     return false; }
783   return true;
784 }
785
786 /*!
787     Redo last undo
788 */
789 bool QAD_Study::redo()
790 {
791   try {
792     SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
793     SB->Redo();
794
795     /* Update Object Browser */
796     updateObjBrowser( true );
797
798     /* Update Viewer */
799     for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
800       sf->getRightFrame()->getViewFrame()->redo( myStudy, sf->entry() );
801     }
802     updateCaptions();
803
804     // mpv 07.03.2003 SAL1805: clear selection must be called after study structure changed
805     SALOME_Selection* Sel = SALOME_Selection::Selection( getSelection() );
806     Sel->ClearIObjects();
807   }
808   // mpv : redo command can raise exception, if study is locked
809   catch ( SALOMEDS::StudyBuilder::LockProtection& ) {
810     QAD_MessageBox::warn1 ((QWidget*)QAD_Application::getDesktop(),
811                            QObject::tr("WRN_WARNING"), 
812                            QObject::tr("WRN_STUDY_LOCKED"),
813                            QObject::tr("BUT_OK"));
814     return false;
815   }
816   catch ( Standard_Failure ) {
817     return false; }
818   return true;
819 }
820
821 /*!
822   Check if possible to perform 'undo' command
823 */
824 bool QAD_Study::canUndo() const
825 {
826   if ( myStudy->_is_nil() )
827     return false;
828
829   SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
830   return (SB->GetAvailableUndos() > 0 );
831 }
832
833 /*!
834     Check if possible to perform 'redo' command
835 */
836 bool QAD_Study::canRedo() const
837 {
838   if ( myStudy->_is_nil() )
839     return false;
840
841   SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
842   return (SB->GetAvailableRedos() > 0 );
843 }
844
845 /*!
846     Called when operation is started
847     Returns 'true' if started OK, 'false' otherwise.
848 */
849 bool QAD_Study::onOperationStarted( QAD_Operation* op )
850 {
851   if ( !initOperation( op ) )
852     return false;
853
854   try
855     {   /* start a new transaction */
856       SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
857       SB->NewCommand();
858     }
859   catch ( Standard_Failure )
860     {
861       /*  May be, a transaction is already open,
862           it's not a problem */
863     }
864   myOperationState = Started;
865   return true;
866 }
867
868 /*!
869     Called when operation is finished
870 */
871 void QAD_Study::onOperationFinished( QAD_Operation* op )
872 {
873   try {
874     /* transaction is completed OK */
875     SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
876     SB->CommitCommand();
877   }
878   catch ( SALOMEDS::StudyBuilder::LockProtection& ) {
879     QApplication::restoreOverrideCursor();
880     QAD_MessageBox::warn1 ((QWidget*)QAD_Application::getDesktop(),
881                            QObject::tr("WRN_WARNING"), 
882                            QObject::tr("WRN_STUDY_LOCKED"),
883                            QObject::tr("BUT_OK"));
884     onOperationAborted(op);
885     updateObjBrowser( true );
886     return;
887   }
888   catch ( Standard_Failure ) {
889   }
890   myOperationState = Finished;
891   emit docOperationTerminated( true );    /* terminated successfully */
892
893   updateCaptions();
894   // mpv: any operation must call this method, otherwise study may not be saved
895   updateObjBrowser( true );
896
897   clearOperation( op );                   /* we don't need the operation anymore */
898   QAD_Application::getDesktop()->putInfo ( tr("INF_DOC_OPERATIONFINISHED") );
899 }
900
901 /*!
902     Called when operation is suspended
903 */
904 void QAD_Study::onOperationSuspended( QAD_Operation* op )
905 {
906   myOperationState = Suspended;
907 }
908
909 /*!
910     Called when operation is resumed
911 */
912 void QAD_Study::onOperationResumed( QAD_Operation* op )
913 {
914   myOperationState = Resumed;
915 }
916
917 /*!
918     Called when operation is aborted
919 */
920 void QAD_Study::onOperationAborted(QAD_Operation* op)
921 {
922   try {
923     /* abort transaction */
924     SALOMEDS::StudyBuilder_var SB = myStudy->NewBuilder();
925     SB->AbortCommand();
926   }
927   catch ( Standard_Failure )
928     {
929     }
930   myOperationState = Aborted;
931   emit docOperationTerminated( false );       /* aborted */
932
933   updateCaptions();
934
935   clearOperation(op);
936   QAD_Application::getDesktop()->putInfo ( tr("INF_DOC_OPERATIONABORTED") );
937 }
938
939 /*!
940     Call when the last study frame is closing
941 */
942 void QAD_Study::onLastStudyFrameClosing( QAD_StudyFrame* sf )
943 {
944   if ( myStudyFrames.count() == 1 ) {
945     emit docClosing( this );
946   } else
947     removeStudyFrame( sf );
948
949 //  QWorkspace* ws = QAD_Application::getDesktop()->getMainFrame();
950 //  if ( !ws->activeWindow() && ws->windowList().count() > 0 )
951 //    ws->activatePreviousWindow();
952 }
953
954 /*!
955     Call when created a new window3d
956 */
957 QAD_StudyFrame* QAD_Study::newWindow3d(QString name, ViewType theViewType, bool toShow)
958 {
959   if(name == "")  name = getNextStudyFrameName();
960   QAD_StudyFrame* sf = createStudyFrame( name, theViewType );
961   if ( myResult ) {
962     if (toShow) showFrame(sf);
963     //    sf->compressLeft(); /* compress LeftFrame */
964     sf->getRightFrame()->compressBottom(); /* compress BottomFrame */
965     return sf;
966   }
967   return 0;
968 }
969
970 void QAD_Study::showFrame(QAD_StudyFrame* theFrame){
971   theFrame->resize( (int)(0.64*QAD_Application::getDesktop()->getMainFrame()->width()),
972                     (int)(0.64*QAD_Application::getDesktop()->getMainFrame()->height()));
973   theFrame->show();
974
975 }
976
977
978
979 /*!
980     Call when setted a message
981 */
982 void QAD_Study::setMessage(const char* message)
983 {
984   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
985     sf->getRightFrame()->getMessage()->setMessage(message);
986   }
987 }
988
989 /*!
990     Call when updated object browser
991 */
992 void QAD_Study::updateObjBrowser( bool updateSelection )
993 {
994   QAD_Desktop* parent = QAD_Application::getDesktop();
995   SALOME_ModuleCatalog::ModuleCatalog_var Catalog = parent->getCatalogue();
996
997   QString ActiveComp = parent->getActiveComponent();
998
999   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1000     sf->getLeftFrame()->getObjectBrowser()->Update();
1001   }
1002
1003   /* update selection */
1004   if ( updateSelection && (myStudyFrames.count() > 0) ) {
1005     SALOME_Selection* Sel = SALOME_Selection::Selection( getSelection() );
1006     SALOME_ListIteratorOfListIO It( Sel->StoredIObjects() );
1007     for(;It.More();It.Next()) {
1008       if ( Sel->AddIObject( It.Value() ) == 0 ) {
1009         highlight( It.Value(), true, false );
1010       }
1011     }
1012   }
1013   /* update viewers */
1014   update3dViewers();
1015 }
1016
1017 /*!
1018   Updates only Use Case Browser
1019 */
1020 void QAD_Study::updateUseCaseBrowser( bool updateSelection )
1021 {
1022   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1023     sf->getLeftFrame()->getObjectBrowser()->UpdateUseCaseBrowser();
1024   }
1025   /* update selection */
1026   if ( updateSelection && (myStudyFrames.count() > 0) ) {
1027     SALOME_Selection* Sel = SALOME_Selection::Selection( getSelection() );
1028     SALOME_ListIteratorOfListIO It( Sel->StoredIObjects() );
1029     for(;It.More();It.Next()) {
1030       if ( Sel->AddIObject( It.Value() ) == 0 ) {
1031         highlight( It.Value(), true, false );
1032       }
1033     }
1034     /* update viewers */
1035     update3dViewers();
1036   }
1037 }
1038
1039 /*!
1040   unHighlight All Interactive Objects in All Devices
1041 */
1042 void QAD_Study::unHighlightAll() 
1043 {
1044   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1045     /* Device = Viewers */
1046     sf->getRightFrame()->getViewFrame()->unHighlightAll();
1047
1048     /* Device = ObjectBrowser */
1049     sf->getLeftFrame()->getObjectBrowser()->unHighlightAll();
1050   }
1051 }
1052
1053 /*!
1054   Returns type of Interactive Object
1055 */
1056 int QAD_Study::typeIObject( const Handle(SALOME_InteractiveObject)& IObject )
1057 {
1058   bool IsStudyObject     = isInStudy( IObject );
1059   bool IsGraphicalObject = isInViewer( IObject );
1060
1061   //    MESSAGE ( "IsStudyObject : " <<  IsStudyObject )
1062   //    MESSAGE ( "IsGraphicalObject : " <<  IsGraphicalObject )
1063
1064   if ( IsStudyObject ) {
1065     if ( IsGraphicalObject )
1066       return 1; /* StudyObject and GraphicalObject */
1067     else
1068       return 2; /* only StudyObject */
1069   } else {
1070     if ( IsGraphicalObject )
1071       return 3; /* only GraphicalObject */
1072     else
1073       return 4; /* may be a component */
1074   }
1075   return 0;
1076 }
1077
1078
1079 /*!
1080   Renames the Interactive Object in All Devices
1081 */
1082 void QAD_Study::renameIObject( const Handle(SALOME_InteractiveObject)& IObject, QString newName )
1083 {
1084   if (myStudy->GetProperties()->IsLocked()) {
1085     QAD_MessageBox::warn1 ((QWidget*)QAD_Application::getDesktop(),
1086                            QObject::tr("WRN_WARNING"), 
1087                            QObject::tr("WRN_STUDY_LOCKED"),
1088                            QObject::tr("BUT_OK"));
1089     return;
1090   }
1091
1092   highlight( IObject, false );
1093   
1094   int nbFrames = myStudyFrames.count();
1095   for ( int i = 0; i < nbFrames; i++ ) {
1096     QAD_StudyFrame* sf = myStudyFrames.at( i );
1097     switch ( typeIObject(IObject) ) {
1098     case 1:
1099       {
1100         /* Device = Viewers */
1101         sf->getRightFrame()->getViewFrame()->rename(IObject, newName);
1102         /* Device = ObjectBrowser */
1103         sf->getLeftFrame()->getObjectBrowser()->rename(IObject, newName);
1104         break;
1105       }
1106     case 2:
1107       {
1108         /* Device = ObjectBrowser */
1109         sf->getLeftFrame()->getObjectBrowser()->rename(IObject, newName); 
1110       break;
1111       }
1112     case 3:
1113       {
1114         /* Device = Viewers */
1115         sf->getRightFrame()->getViewFrame()->rename(IObject, newName);
1116         break;
1117       }
1118     case 4:
1119       {
1120         QString ActiveComp = QAD_Application::getDesktop()->getActiveComponent();
1121         if ( !ActiveComp.isEmpty() ) {
1122           sf->getLeftFrame()->getObjectBrowser()->rename(IObject,newName);
1123         }
1124         break;
1125       }
1126     }
1127   }
1128
1129   /* SALOMEDS */
1130   SALOMEDS::StudyBuilder_var aStudyBuilder = myStudy->NewBuilder();
1131   SALOMEDS::SObject_var obj = myStudy->FindObjectID( IObject->getEntry() );
1132   if ( !obj->_is_nil() ) {
1133     SALOMEDS::GenericAttribute_var anAttr;
1134     SALOMEDS::AttributeName_var    aName;
1135     anAttr = aStudyBuilder->FindOrCreateAttribute(obj, "AttributeName");
1136     aName = SALOMEDS::AttributeName::_narrow(anAttr);
1137     aName->SetValue(strdup(newName.latin1()));
1138   }
1139
1140   // VSR 13/03/03 - rename Interactive object 
1141   IObject->setName( ( char* )newName.latin1() );
1142
1143   updateObjBrowser( true );
1144 }
1145
1146 /*!
1147   Selects the Interactive Object in All Devices
1148 */
1149 void QAD_Study::highlight( const Handle(SALOME_InteractiveObject)& IObject, bool highlight,bool immediatly ) 
1150 {
1151   //    MESSAGE ( " QAD_Study::highlight : " << highlight )
1152   int typeIO = typeIObject( IObject );
1153
1154   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1155     switch ( typeIO ) {
1156     case 1:
1157       {
1158         /* Device = Viewer */
1159         if (sf->getTypeView() >= 0 ) { /* Device = Viewers */
1160           sf->getRightFrame()->getViewFrame()->highlight(IObject, highlight, immediatly);
1161         }
1162         /* Device = ObjectBrowser */
1163         sf->getLeftFrame()->getObjectBrowser()->highlight(IObject, highlight);
1164         break;
1165       }
1166     case 2:
1167       {
1168         /* Device = ObjectBrowser */
1169         sf->getLeftFrame()->getObjectBrowser()->highlight(IObject, highlight); 
1170         break;
1171       }
1172     case 3:
1173       {
1174         /* Device = Viewer */
1175         if (sf->getTypeView() >= 0) { /* Device = Viewers */
1176           sf->getRightFrame()->getViewFrame()->highlight(IObject, highlight, immediatly);
1177         } 
1178         break;
1179       }
1180     case 4:
1181       {
1182         QString ActiveComp = QAD_Application::getDesktop()->getActiveComponent();
1183         if ( !ActiveComp.isEmpty() ) {
1184           sf->getLeftFrame()->getObjectBrowser()->highlight(IObject,highlight);
1185         }
1186         break;
1187       }
1188     }
1189   }
1190 }
1191
1192 /*!
1193   Returns TRUE if the IObject is a Study Object. Returns FALSE otherwise.
1194 */
1195 bool QAD_Study::isInStudy( const Handle(SALOME_InteractiveObject)& IObject ) 
1196 {
1197   return IObject->hasEntry();
1198 }
1199
1200 /*!
1201   Returns true if the IObject has a Graphical Object. Returns FALSE otherwise.
1202 */
1203 bool QAD_Study::isInViewer( const Handle(SALOME_InteractiveObject)& IObject ) 
1204 {
1205   bool found = false;
1206   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1207     found = sf->getRightFrame()->getViewFrame()->isInViewer(IObject);
1208     if ( found )
1209       return true;
1210   }
1211   return found;
1212 }
1213
1214 /*!
1215   Returns true if the IObject has a Graphical Object into studyframe. Returns FALSE otherwise.
1216 */
1217 bool QAD_Study::isInViewer(const char* anEntry, const char* StudyFrameEntry)
1218 {
1219   SALOMEDS::SObject_var RefSO;
1220   SALOMEDS::SObject_var SO = myStudy->FindObjectID(StudyFrameEntry);
1221   SALOMEDS::ChildIterator_var it = myStudy->NewChildIterator(SO);
1222   for (; it->More();it->Next()){
1223     SALOMEDS::SObject_var CSO= it->Value();
1224     if (CSO->ReferencedObject(RefSO))
1225       if ( strcmp( anEntry, RefSO->GetID() ) == 0 )
1226         return 1;
1227   }
1228   return 0;
1229 }
1230
1231
1232 /*!
1233     Returns title for the new studyframe window
1234 */
1235 QString QAD_Study::getNextStudyFrameName()
1236 {
1237   QString numStudyFrame;
1238   numStudyFrame.sprintf("%s%d", "#", ++myStudyFrameCount );
1239   return myTitle + numStudyFrame;   /* return unique name ( title + unique number) */
1240 }
1241
1242
1243 /*!
1244   Returns the Python interpreter that belongs to this study
1245 */
1246 QAD_PyInterp* QAD_Study::get_PyInterp(void)
1247 {
1248   return _interp;
1249 }
1250
1251 /*!
1252   Sets current selection.
1253 */
1254 void QAD_Study::Selection( QString aSelection )
1255 {
1256   if ( !SALOME_Selection::FindSelection( QString(myTitle + "_" + aSelection) ) )
1257     SALOME_Selection::CreateSelection( QString(myTitle + "_" + aSelection) );
1258
1259   SALOME_Selection* Sel = SALOME_Selection::Selection( QString(myTitle + "_" + aSelection) );
1260
1261   mySelection = aSelection;
1262 }
1263
1264 /*!
1265   Returns the name of current selection
1266 */
1267 QString QAD_Study::getSelection()
1268 {
1269   return QString (myTitle + "_" + mySelection);
1270 }
1271
1272 /*!
1273   Returns the study Id.
1274 */
1275 int QAD_Study::getStudyId()
1276 {
1277   return myStudy->StudyId();
1278 }
1279
1280 void QAD_Study::update3dViewers() 
1281 {
1282   for ( QAD_StudyFrame* sf = myStudyFrames.first(); sf; sf = myStudyFrames.next() ) {
1283     sf->getRightFrame()->getViewFrame()->Repaint();
1284   }
1285 }
1286
1287 /* Adds new child window */
1288 void QAD_Study::addChildWidget( QWidget* child )
1289 {
1290   if ( myChildWidgets.findRef( child ) < 0 ) {
1291     myChildWidgets.append( child );
1292     child->installEventFilter( this );
1293   }
1294 }
1295
1296 /*!
1297   Removes child window from the list ( and deletes it )
1298 */
1299 void QAD_Study::removeChildWidget( QWidget* child )
1300 {
1301   myChildWidgets.removeRef( child );
1302 }
1303
1304 /* Event filter */
1305 bool QAD_Study::eventFilter( QObject* o, QEvent* e)
1306 {
1307   int index = myChildWidgets.findRef( ( QWidget* )o );
1308   if ( index >= 0 && e->type() == QEvent::Close ) {
1309     myChildWidgets.at( index )->removeEventFilter( this );
1310     myChildWidgets.remove( ( QWidget* )o );
1311     return TRUE;
1312   }
1313   return QObject::eventFilter( o, e );
1314 }
1315