Salome HOME
Join modifications from branch OCC_debug_for_3_2_0b1
[modules/gui.git] / src / SUIT / SUIT_Study.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 #include "SUIT_Study.h"
20
21 #include "SUIT_Desktop.h"
22 #include "SUIT_Operation.h"
23 #include "SUIT_DataObject.h"
24 #include "SUIT_MessageBox.h"
25 #include "SUIT_Application.h"
26 #include <qvaluevector.h>
27
28 /*!\class SUIT_Study
29  * Support study management. Object management. Operation management.
30  */
31
32 /*!Constructor.*/
33 SUIT_Study::SUIT_Study( SUIT_Application* app )
34 : QObject(),
35 myApp( app ),
36 myIsSaved( false ),
37 myIsModified( false ),
38 myName( "" ),
39 myBlockChangeState( false )
40 {
41   static int _id = 0;
42
43   myId = ++_id;
44
45   myRoot = new SUIT_DataObject();
46   myOperations.setAutoDelete( false );
47   myOperations.setAutoDelete( false );
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.getLast() : 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 void SUIT_Study::createDocument()
125 {
126 }
127
128 /*!
129  * Open document. Sets file name. return true.
130  */
131 bool SUIT_Study::openDocument( const QString& fileName )
132 {
133   myName = fileName;
134   myIsSaved = true;
135   myIsModified = false;
136
137   return true;
138 }
139
140 /*!
141  * Save document as \a fileName. Set file name.
142  */
143 bool SUIT_Study::saveDocumentAs( const QString& fileName )
144 {
145   myName = fileName;
146   myIsSaved = true;
147   myIsModified = false;
148
149   return true;
150 }
151
152 /*!
153  *\retval TRUE - if document saved successful, else FALSE.
154  */
155 bool SUIT_Study::saveDocument()
156 {
157   return saveDocumentAs( myName );
158 }
159
160 /*!
161  *Abort all operations.
162  */
163 void SUIT_Study::abortAllOperations()
164 {
165   myBlockChangeState = true;
166   for( SUIT_Operation* op = myOperations.first(); op; op = myOperations.next() )
167     op->abort();
168   myBlockChangeState = false;
169   myOperations.clear();
170 }
171
172 /*!
173   Update study. NOT IMPLEMENTED HERE.
174  */
175 void SUIT_Study::update()
176 {
177 }
178
179 /*!
180   Emit study modified.
181  */
182 void SUIT_Study::sendChangesNotification()
183 {
184   emit studyModified( this );
185 }
186
187 /*!
188   Set study saved to \a on.
189  */
190 void SUIT_Study::setIsSaved( const bool on )
191 {
192   myIsSaved = on;
193 }
194
195 /*!
196   Set study modified to \a on.
197  */
198 void SUIT_Study::setIsModified( const bool on )
199 {
200   myIsModified = on;
201 }
202
203 /*!
204   Set root object.
205  */
206 void SUIT_Study::setRoot( SUIT_DataObject* obj )
207 {
208   if ( myRoot == obj )
209     return;
210
211   // This is necessary in order not to destroy the complete tree of objects
212   if ( obj )
213     obj->reparentChildren( myRoot );
214
215   delete myRoot;
216   myRoot = obj;
217 }
218
219 /*!
220   Set study name.
221  */
222 void SUIT_Study::setStudyName( const QString& name )
223 {
224   myName = name;
225 }
226
227 /*!
228  * \brief Verifies whether operation can be activated above already started ones
229   * \param theOp - operation to be checked
230   * \return NULL if operation can be activated, pointer to operation which denies
231   * starting tested operation
232 *
233 * Verifies whether operation can be activated above already started ones. This method
234 * is called from SUIT_Study::start() and SUIT_Study::resume() methods.
235 */
236 SUIT_Operation* SUIT_Study::blockingOperation( SUIT_Operation* theOp ) const
237 {
238   if( theOp->isGranted() )
239     return 0;
240
241   Operations tmpOps( myOperations );
242   SUIT_Operation* anOp = 0;
243   for ( anOp = tmpOps.last(); anOp; anOp = tmpOps.prev() )
244   {
245     if ( anOp != 0 && anOp!= theOp && !anOp->isValid( theOp ) )
246       return anOp;
247   }
248
249   return 0;
250 }
251
252 /*!
253  * \brief Starts operation
254   * \param theOp - operation to be started
255   * \param toCheck - if parameters is equal TRUE then checking performed whether
256   * all already started operations allow to start this operation above them (default
257   * value is TRUE
258   * \return TRUE if operation is started, FALSE otherwise
259 *
260 * Verifies whether theOp operation can be started above already started ones (if toCheck
261 * parameter is equal TRUE) and starts it
262 */
263 bool SUIT_Study::start( SUIT_Operation* theOp, const bool toCheck )
264 {
265   if ( !theOp || myOperations.find( theOp ) >= 0 )
266     return false;
267
268   theOp->setExecStatus( SUIT_Operation::Rejected );
269   theOp->setStudy( this );
270
271   if ( !theOp->isReadyToStart() )
272     return false;
273
274   if ( toCheck )
275   {
276     while( SUIT_Operation* anOp = blockingOperation( theOp ) )
277     {
278       int anAnsw = SUIT_MessageBox::warn2( application()->desktop(),
279                                            tr( "OPERATION_LAUNCH" ), tr( "PREVIOUS_NOT_FINISHED" ),
280                                            tr( "CONTINUE" ), tr( "CANCEL" ), 0, 1, 1 );
281
282       if ( anAnsw == 1 )
283         return false;
284       else
285         anOp->abort();
286     }
287   }
288
289   SUIT_Operation* anOp = activeOperation();
290   if ( anOp )
291   {
292     activeOperation()->suspendOperation();
293     anOp->setState( SUIT_Operation::Suspended );
294   }
295
296   theOp->setState( SUIT_Operation::Running );
297   myOperations.append( theOp );
298  
299   emit theOp->started( theOp );
300   operationStarted( theOp );
301   theOp->startOperation();
302
303   return true;
304 }
305
306 /*!
307  * \brief Aborts operation
308   * \param theOp - operation to be aborted
309   * \return TRUE if operation is aborted successfully
310 *
311 * Verifies whether operation already started and aborts it in this case (sets execution
312 * status to Rejected and stops operation)
313 */
314 bool SUIT_Study::abort( SUIT_Operation* theOp )
315 {
316   if ( !theOp || myOperations.find( theOp ) == -1 )
317     return false;
318
319   theOp->setExecStatus( SUIT_Operation::Rejected );
320
321   theOp->abortOperation();
322   operationAborted( theOp );
323   emit theOp->aborted( theOp );
324
325   stop( theOp );
326
327   return true;
328 }
329
330 /*!
331  * \brief Commits operation
332   * \param theOp - operation to be committed
333   * \return TRUE if operation is committed successfully
334 *
335 * Verifies whether operation already started and commits it in this case (sets execution
336 * status to Accepted and stops operation)
337 */
338 bool SUIT_Study::commit( SUIT_Operation* theOp )
339 {
340   if ( !theOp || myOperations.find( theOp ) == -1 )
341     return false;
342
343   theOp->setExecStatus( SUIT_Operation::Accepted );
344
345   theOp->commitOperation();
346   operationCommited( theOp );
347   emit theOp->committed( theOp );
348
349   stop( theOp );
350
351   emit studyModified( this );
352
353   return true;
354 }
355
356 /*!
357  * \brief Commits operation
358   * \param theOp - operation to be committed
359   * \return TRUE if operation is suspended successfully
360 *
361 * Verifies whether operation already started and suspends it in this case. Operations
362 * ususlly are suspended to start other one above them.
363 */
364 bool SUIT_Study::suspend( SUIT_Operation* theOp )
365 {
366   if ( !theOp || myOperations.find( theOp ) == -1 || theOp->state() == SUIT_Operation::Suspended )
367     return false;
368
369   theOp->setState( SUIT_Operation::Suspended );
370   theOp->suspendOperation();
371   emit theOp->suspended( theOp );
372   return true;
373 }
374
375
376 /*!
377  * \brief Resumes operation
378   * \param theOp - operation to be resumed
379   * \return TRUE if operation is aborted successfully
380 *
381 * Verifies whether operation already started but suspended and resumesit in this case.
382 */
383 bool SUIT_Study::resume( SUIT_Operation* theOp )
384 {
385   if ( !theOp || myOperations.find( theOp ) == -1 ||
386        theOp->state() == SUIT_Operation::Running ||
387        blockingOperation( theOp ) != 0 )
388     return false;
389
390   if ( myOperations.count() > 0 )
391     suspend( myOperations.last() );
392
393   theOp->setState( SUIT_Operation::Running );
394   theOp->resumeOperation();
395
396   // Move operation at the end of list in order to sort it in the order of activation.
397   // As result active operation is a last operation of list, operation which was active
398   // before currently active operation is located before it and so on
399   myOperations.remove( theOp );
400   myOperations.append( theOp );
401
402   emit theOp->resumed( theOp );
403   return true;
404 }
405
406 /*!
407  * \brief Stops operation
408   * \param theOp - operation to be stopped
409 *
410 * Stops operation. This private method is called from abort() and commit() ones to perform
411 * common actions when operation is stopped
412 */
413 void SUIT_Study::stop( SUIT_Operation* theOp )
414 {
415   theOp->setState( SUIT_Operation::Waiting );
416   myOperations.remove( theOp );
417
418   // get last operation which can be resumed
419   SUIT_Operation* anOp, *aResultOp = 0;
420   for ( anOp = myOperations.last(); anOp; anOp = myOperations.prev() )
421   {
422     if ( anOp && anOp != theOp && blockingOperation( anOp ) == 0 )
423     {
424       aResultOp = anOp;
425       break;
426     }
427   }
428
429   theOp->stopOperation();
430   operationStopped( theOp );
431   emit theOp->stopped( theOp );
432
433   if ( aResultOp )
434     resume( aResultOp );
435 }
436
437 /*!
438  * \brief Get all started operations
439   * \return List of all started operations
440 */
441 const QPtrList<SUIT_Operation>& SUIT_Study::operations() const
442 {
443   return myOperations;
444 }
445
446 /*!
447  * \brief Perform some actions when operation starting
448 */
449 void SUIT_Study::operationStarted( SUIT_Operation* op )
450 {
451   if ( !op )
452     return;
453
454   if ( op->testFlags( SUIT_Operation::Transaction ) )
455     op->openTransaction();
456 }
457
458 /*!
459  * \brief Perform some actions when operation aborted
460 */
461 void SUIT_Study::operationAborted( SUIT_Operation* op )
462 {
463   if ( op->testFlags( SUIT_Operation::Transaction ) )
464     op->abortTransaction();
465 }
466
467 /*!
468  * \brief Perform some actions when operation commited
469 */
470 void SUIT_Study::operationCommited( SUIT_Operation* op )
471 {
472   if ( op->testFlags( SUIT_Operation::Transaction ) )
473     op->commitTransaction( op->operationName() );
474 }
475
476 /*!
477  * \brief Perform some actions when operation stopped
478 */
479 void SUIT_Study::operationStopped( SUIT_Operation* )
480 {
481 }
482
483 /*!
484  * \brief Opens transaction for data modifications.
485 */
486 bool SUIT_Study::openTransaction()
487 {
488   return true;
489 }
490
491 /*!
492  * \brief Aborts transaction and all performed data modifications.
493 */
494 bool SUIT_Study::abortTransaction()
495 {
496   return true;
497 }
498
499 /*!
500  * \brief Commits transaction and all performed data modifications.
501 */
502 bool SUIT_Study::commitTransaction( const QString& )
503 {
504   return true;
505 }
506
507 /*!
508  * \brief Returns TRUE if transaction is opened.
509 */
510 bool SUIT_Study::hasTransaction() const
511 {
512   return false;
513 }
514
515 /*!
516  * \brief Stores the study state
517 */
518 int SUIT_Study::storeState()
519 {
520   return -1;
521 }
522  
523 /*!
524  * \brief Restores the study state
525 */
526 void SUIT_Study::restoreState(int savePoint)
527 {
528 }