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