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