Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / SUIT / SUIT_Study.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  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.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #include "SUIT_Study.h"
23
24 #include "SUIT_Desktop.h"
25 #include "SUIT_Operation.h"
26 #include "SUIT_DataObject.h"
27 #include "SUIT_MessageBox.h"
28 #include "SUIT_Application.h"
29
30 /*!\class SUIT_Study
31  * Support study management. Object management. Operation management.
32  */
33
34 /*!Constructor.*/
35 SUIT_Study::SUIT_Study( SUIT_Application* app )
36 : QObject(),
37 myApp( app ),
38 myName( "" ),
39 myIsSaved( false ),
40 myIsModified( false ),
41 myBlockChangeState( false )
42 {
43   static int _id = 0;
44
45   myId = ++_id;
46
47   myRoot = new SUIT_DataObject();
48 }
49
50 /*!Destructor.*/
51 SUIT_Study::~SUIT_Study()
52 {
53   delete myRoot;
54   myRoot = 0;
55 }
56
57 /*!
58  *\retval study id.
59  */
60 int SUIT_Study::id() const
61 {
62   return myId;
63 }
64
65 /*!
66  *\retval root data object.
67  */
68 SUIT_DataObject* SUIT_Study::root() const
69 {
70   return myRoot;
71 }
72
73 /*!
74  *\retval Application.
75  */
76 SUIT_Application* SUIT_Study::application() const
77 {
78   return myApp;
79 }
80
81 /*!
82  *\retval study name
83  */
84 QString SUIT_Study::studyName() const
85 {
86   return myName;
87 }
88
89 /*!
90  *\retval active operation.
91  */
92 SUIT_Operation* SUIT_Study::activeOperation() const
93 {
94   return myOperations.count() > 0 ? myOperations.last() : 0;
95 }
96
97 /*!
98  *\retval TRUE - if study saved, else FALSE.
99  */
100 bool SUIT_Study::isSaved() const
101 {
102   return myIsSaved;
103 }
104
105 /*!
106  *\retval TRUE - if study modified, else FALSE.
107  */
108 bool SUIT_Study::isModified() const
109 {
110   return myIsModified;
111 }
112
113 /*!
114  *Close document. NOT IMPLEMENTED.
115  */
116 void SUIT_Study::closeDocument(bool /*permanently*/)
117 {
118 }
119
120 /*!
121   Custom document initialization to be performed \n
122    within onNewDoc() handler can be put here
123 */
124 bool SUIT_Study::createDocument( const QString& )
125 {
126   return true;
127 }
128
129 /*!
130  * Open document. Sets file name. return true.
131  */
132 bool SUIT_Study::openDocument( const QString& fileName )
133 {
134   myName = fileName;
135   myIsSaved = true;
136   myIsModified = false;
137
138   return true;
139 }
140
141 /*!
142  * Save document as \a fileName. Set file name.
143  */
144 bool SUIT_Study::saveDocumentAs( const QString& fileName )
145 {
146   myName = fileName;
147   myIsSaved = true;
148   myIsModified = false;
149
150   return true;
151 }
152
153 /*!
154  *\retval TRUE - if document saved successful, else FALSE.
155  */
156 bool SUIT_Study::saveDocument()
157 {
158   return saveDocumentAs( myName );
159 }
160
161 /*!
162  *Abort all operations.
163  */
164 void SUIT_Study::abortAllOperations()
165 {
166   myBlockChangeState = true;
167   for ( Operations::iterator it = myOperations.begin(); it != myOperations.end(); ++it )
168     (*it)->abort();
169   myBlockChangeState = false;
170   myOperations.clear();
171 }
172
173 /*!
174   Update study. NOT IMPLEMENTED HERE.
175  */
176 void SUIT_Study::update()
177 {
178 }
179
180 /*!
181   Emit study modified.
182  */
183 void SUIT_Study::sendChangesNotification()
184 {
185   emit studyModified( this );
186 }
187
188 /*!
189   Set study saved to \a on.
190  */
191 void SUIT_Study::setIsSaved( const bool on )
192 {
193   myIsSaved = on;
194 }
195
196 /*!
197   Set study modified to \a on.
198  */
199 void SUIT_Study::setIsModified( const bool on )
200 {
201   myIsModified = on;
202 }
203
204 /*!
205   Set study modified to \a on.
206  */
207 void SUIT_Study::Modified()
208 {
209   setIsModified( true );
210   sendChangesNotification();
211 }
212
213 /*!
214   Set root object.
215  */
216 void SUIT_Study::setRoot( SUIT_DataObject* obj )
217 {
218   if ( myRoot == obj )
219     return;
220
221   // This is necessary in order not to destroy the complete tree of objects
222   if ( obj )
223     obj->reparentChildren( myRoot );
224
225   delete myRoot;
226   myRoot = obj;
227 }
228
229 /*!
230   Set study name.
231  */
232 void SUIT_Study::setStudyName( const QString& name )
233 {
234   myName = name;
235 }
236
237 /*!
238  * \brief Verifies whether operation can be activated above already started ones
239   * \param theOp - operation to be checked
240   * \return NULL if operation can be activated, pointer to operation which denies
241   * starting tested operation
242 *
243 * Verifies whether operation can be activated above already started ones. This method
244 * is called from SUIT_Study::start() and SUIT_Study::resume() methods.
245 */
246 SUIT_Operation* SUIT_Study::blockingOperation( SUIT_Operation* theOp ) const
247 {
248   if( theOp->isGranted() )
249     return 0;
250
251   Operations tmpOps( myOperations );
252   for ( Operations::const_iterator it = tmpOps.end(); it != tmpOps.begin(); )
253   {
254     it--;
255     SUIT_Operation* anOp = *it;
256     if ( anOp != 0 && anOp!= theOp && !anOp->isValid( theOp ) )
257       return anOp;
258   }
259
260   return 0;
261 }
262
263 /*!
264  * \brief Starts operation
265   * \param theOp - operation to be started
266   * \param toCheck - if parameters is equal TRUE then checking performed whether
267   * all already started operations allow to start this operation above them (default
268   * value is TRUE
269   * \return TRUE if operation is started, FALSE otherwise
270 *
271 * Verifies whether theOp operation can be started above already started ones (if toCheck
272 * parameter is equal TRUE) and starts it
273 */
274 bool SUIT_Study::start( SUIT_Operation* theOp, const bool toCheck )
275 {
276   if ( !theOp || myOperations.contains( theOp ) )
277     return false;
278
279   theOp->setExecStatus( SUIT_Operation::Rejected );
280   theOp->setStudy( this );
281
282   if ( !theOp->isReadyToStart() )
283     return false;
284
285   if ( toCheck )
286   {
287     while ( SUIT_Operation* anOp = blockingOperation( theOp ) )
288     {
289       int anAnsw = SUIT_MessageBox::question( application()->desktop(),
290                                               tr( "OPERATION_LAUNCH" ), tr( "PREVIOUS_NOT_FINISHED" ),
291                                               tr( "CONTINUE" ), tr( "CANCEL" ) );
292
293       if ( anAnsw == 1 )
294         return false;
295       else
296         anOp->abort();
297     }
298   }
299
300   SUIT_Operation* anOp = activeOperation();
301   if ( anOp )
302   {
303     activeOperation()->suspendOperation();
304     anOp->setState( SUIT_Operation::Suspended );
305   }
306
307   theOp->setState( SUIT_Operation::Running );
308   myOperations.append( theOp );
309  
310   emit theOp->started( theOp );
311   operationStarted( theOp );
312   theOp->startOperation();
313
314   return true;
315 }
316
317 /*!
318  * \brief Aborts operation
319   * \param theOp - operation to be aborted
320   * \return TRUE if operation is aborted successfully
321 *
322 * Verifies whether operation already started and aborts it in this case (sets execution
323 * status to Rejected and stops operation)
324 */
325 bool SUIT_Study::abort( SUIT_Operation* theOp )
326 {
327   if ( !theOp || !myOperations.contains( theOp ) )
328     return false;
329
330   theOp->setExecStatus( SUIT_Operation::Rejected );
331
332   theOp->abortOperation();
333   operationAborted( theOp );
334   emit theOp->aborted( theOp );
335
336   stop( theOp );
337
338   return true;
339 }
340
341 /*!
342  * \brief Commits operation
343   * \param theOp - operation to be committed
344   * \return TRUE if operation is committed successfully
345 *
346 * Verifies whether operation already started and commits it in this case (sets execution
347 * status to Accepted and stops operation)
348 */
349 bool SUIT_Study::commit( SUIT_Operation* theOp )
350 {
351   if ( !theOp || !myOperations.contains( theOp ) )
352     return false;
353
354   theOp->setExecStatus( SUIT_Operation::Accepted );
355
356   theOp->commitOperation();
357   operationCommited( theOp );
358   emit theOp->committed( theOp );
359
360   stop( theOp );
361
362   emit studyModified( this );
363
364   return true;
365 }
366
367 /*!
368  * \brief Commits operation
369   * \param theOp - operation to be committed
370   * \return TRUE if operation is suspended successfully
371 *
372 * Verifies whether operation already started and suspends it in this case. Operations
373 * ususlly are suspended to start other one above them.
374 */
375 bool SUIT_Study::suspend( SUIT_Operation* theOp )
376 {
377   if ( !theOp || !myOperations.contains( theOp ) || theOp->state() == SUIT_Operation::Suspended )
378     return false;
379
380   theOp->setState( SUIT_Operation::Suspended );
381   theOp->suspendOperation();
382   emit theOp->suspended( theOp );
383   return true;
384 }
385
386
387 /*!
388  * \brief Resumes operation
389   * \param theOp - operation to be resumed
390   * \return TRUE if operation is aborted successfully
391 *
392 * Verifies whether operation already started but suspended and resumesit in this case.
393 */
394 bool SUIT_Study::resume( SUIT_Operation* theOp )
395 {
396   if ( !theOp || !myOperations.contains( theOp ) ||
397        theOp->state() == SUIT_Operation::Running ||
398        blockingOperation( theOp ) != 0 )
399     return false;
400
401   if ( myOperations.count() > 0 )
402     suspend( myOperations.last() );
403
404   theOp->setState( SUIT_Operation::Running );
405   theOp->resumeOperation();
406
407   // Move operation at the end of list in order to sort it in the order of activation.
408   // As result active operation is a last operation of list, operation which was active
409   // before currently active operation is located before it and so on
410   myOperations.removeAll( theOp );
411   myOperations.append( theOp );
412
413   emit theOp->resumed( theOp );
414   return true;
415 }
416
417 /*!
418  * \brief Stops operation
419   * \param theOp - operation to be stopped
420 *
421 * Stops operation. This private method is called from abort() and commit() ones to perform
422 * common actions when operation is stopped
423 */
424 void SUIT_Study::stop( SUIT_Operation* theOp )
425 {
426   theOp->setState( SUIT_Operation::Waiting );
427   myOperations.removeAll( theOp );
428
429   // get last operation which can be resumed
430   SUIT_Operation* aResultOp = 0;
431
432   QListIterator<SUIT_Operation*> it (myOperations);
433   it.toBack();
434   while( it.hasPrevious() )
435   {
436     SUIT_Operation* anOp = it.previous();
437     if ( anOp && anOp != theOp && blockingOperation( anOp ) == 0 )
438     {
439       aResultOp = anOp;
440       break;
441     }
442   }
443
444   theOp->stopOperation();
445   operationStopped( theOp );
446   emit theOp->stopped( theOp );
447
448   if ( aResultOp )
449     resume( aResultOp );
450 }
451
452 /*!
453  * \brief Get all started operations
454   * \return List of all started operations
455 */
456 const QList<SUIT_Operation*>& SUIT_Study::operations() const
457 {
458   return myOperations;
459 }
460
461 /*!
462  * \brief Perform some actions when operation starting
463 */
464 void SUIT_Study::operationStarted( SUIT_Operation* op )
465 {
466   if ( !op )
467     return;
468
469   if ( op->testFlags( SUIT_Operation::Transaction ) )
470     op->openTransaction();
471 }
472
473 /*!
474  * \brief Perform some actions when operation aborted
475 */
476 void SUIT_Study::operationAborted( SUIT_Operation* op )
477 {
478   if ( op->testFlags( SUIT_Operation::Transaction ) )
479     op->abortTransaction();
480 }
481
482 /*!
483  * \brief Perform some actions when operation commited
484 */
485 void SUIT_Study::operationCommited( SUIT_Operation* op )
486 {
487   if ( op->testFlags( SUIT_Operation::Transaction ) )
488     op->commitTransaction( op->operationName() );
489 }
490
491 /*!
492  * \brief Perform some actions when operation stopped
493 */
494 void SUIT_Study::operationStopped( SUIT_Operation* )
495 {
496 }
497
498 /*!
499  * \brief Opens transaction for data modifications.
500 */
501 bool SUIT_Study::openTransaction()
502 {
503   return true;
504 }
505
506 /*!
507  * \brief Aborts transaction and all performed data modifications.
508 */
509 bool SUIT_Study::abortTransaction()
510 {
511   return true;
512 }
513
514 /*!
515  * \brief Commits transaction and all performed data modifications.
516 */
517 bool SUIT_Study::commitTransaction( const QString& )
518 {
519   return true;
520 }
521
522 /*!
523  * \brief Returns TRUE if transaction is opened.
524 */
525 bool SUIT_Study::hasTransaction() const
526 {
527   return false;
528 }
529
530 /*!
531  * \brief Restores the study state.
532  */
533 void SUIT_Study::restoreState(int /*savePoint*/)
534 {
535 }