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