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