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