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