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