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