Salome HOME
Copyrights update
[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 void SUIT_Study::createDocument()
121 {
122   /*! Custom document initialization to be performed \n
123    *  within onNewDoc() handler can be put here
124    */
125 }
126
127 /*!
128  * Open document. Sets file name. return true.
129  */
130 bool SUIT_Study::openDocument( const QString& fileName )
131 {
132   myName = fileName;
133   myIsSaved = true;
134   myIsModified = false;
135
136   return true;
137 }
138
139 /*!
140  * Save document as \a fileName. Set file name.
141  */
142 bool SUIT_Study::saveDocumentAs( const QString& fileName )
143 {
144   myName = fileName;
145   myIsSaved = true;
146   myIsModified = false;
147
148   return true;
149 }
150
151 /*!
152  *\retval TRUE - if document saved successful, else FALSE.
153  */
154 bool SUIT_Study::saveDocument()
155 {
156   return saveDocumentAs( myName );
157 }
158
159 /*!
160  *Abort all operations.
161  */
162 void SUIT_Study::abortAllOperations()
163 {
164   myBlockChangeState = true;
165   for( SUIT_Operation* op = myOperations.first(); op; op = myOperations.next() )
166     op->abort();
167   myBlockChangeState = false;
168   myOperations.clear();
169 }
170
171 /*!
172   Update study. NOT IMPLEMENTED HERE.
173  */
174 void SUIT_Study::update()
175 {
176 }
177
178 /*!
179   Emit study modified.
180  */
181 void SUIT_Study::sendChangesNotification()
182 {
183   emit studyModified( this );
184 }
185
186 /*!
187   Set study saved to \a on.
188  */
189 void SUIT_Study::setIsSaved( const bool on )
190 {
191   myIsSaved = on;
192 }
193
194 /*!
195   Set study modified to \a on.
196  */
197 void SUIT_Study::setIsModified( const bool on )
198 {
199   myIsModified = on;
200 }
201
202 /*!
203   Set root object.
204  */
205 void SUIT_Study::setRoot( SUIT_DataObject* obj )
206 {
207   if ( myRoot == obj )
208     return;
209
210   // This is necessary in order not to destroy the complete tree of objects
211   if ( obj )
212     obj->reparentChildren( myRoot );
213
214   delete myRoot;
215   myRoot = obj;
216 }
217
218 /*!
219   Set study name.
220  */
221 void SUIT_Study::setStudyName( const QString& name )
222 {
223   myName = name;
224 }
225
226 /*!
227  * \brief Verifies whether operation can be activated above already started ones
228   * \param theOp - operation to be checked
229   * \return NULL if operation can be activated, pointer to operation which denies
230   * starting tested operation
231 *
232 * Verifies whether operation can be activated above already started ones. This method
233 * is called from SUIT_Study::start() and SUIT_Study::resume() methods.
234 */
235 SUIT_Operation* SUIT_Study::blockingOperation( SUIT_Operation* theOp ) const
236 {
237   if( theOp->isGranted() )
238     return 0;
239
240   Operations tmpOps( myOperations );
241   SUIT_Operation* anOp = 0;
242   for ( anOp = tmpOps.last(); anOp; anOp = tmpOps.prev() )
243   {
244     if ( anOp != 0 && anOp!= theOp && !anOp->isValid( theOp ) )
245       return anOp;
246   }
247
248   return 0;
249 }
250
251 /*!
252  * \brief Starts operation
253   * \param theOp - operation to be started
254   * \param toCheck - if parameters is equal TRUE then checking performed whether
255   * all already started operations allow to start this operation above them (default
256   * value is TRUE
257   * \return TRUE if operation is started, FALSE otherwise
258 *
259 * Verifies whether theOp operation can be started above already started ones (if toCheck
260 * parameter is equal TRUE) and starts it
261 */
262 bool SUIT_Study::start( SUIT_Operation* theOp, const bool toCheck )
263 {
264   if ( !theOp || myOperations.find( theOp ) >= 0 )
265     return false;
266
267   theOp->setExecStatus( SUIT_Operation::Rejected );
268   theOp->setStudy( this );
269
270   if ( !theOp->isReadyToStart() )
271     return false;
272
273   if ( toCheck )
274   {
275     while( SUIT_Operation* anOp = blockingOperation( theOp ) )
276     {
277       int anAnsw = SUIT_MessageBox::warn2( application()->desktop(),
278                                            tr( "OPERATION_LAUNCH" ), tr( "PREVIOUS_NOT_FINISHED" ),
279                                            tr( "CONTINUE" ), tr( "CANCEL" ), 0, 1, 1 );
280
281       if ( anAnsw == 1 )
282         return false;
283       else
284         anOp->abort();
285     }
286   }
287
288   SUIT_Operation* anOp = activeOperation();
289   if ( anOp )
290   {
291     activeOperation()->suspendOperation();
292     anOp->setState( SUIT_Operation::Suspended );
293   }
294
295   theOp->setState( SUIT_Operation::Running );
296   myOperations.append( theOp );
297  
298   emit theOp->started( theOp );
299   operationStarted( theOp );
300   theOp->startOperation();
301
302   return true;
303 }
304
305 /*!
306  * \brief Aborts operation
307   * \param theOp - operation to be aborted
308   * \return TRUE if operation is aborted successfully
309 *
310 * Verifies whether operation already started and aborts it in this case (sets execution
311 * status to Rejected and stops operation)
312 */
313 bool SUIT_Study::abort( SUIT_Operation* theOp )
314 {
315   if ( !theOp || myOperations.find( theOp ) == -1 )
316     return false;
317
318   theOp->setExecStatus( SUIT_Operation::Rejected );
319
320   theOp->abortOperation();
321   operationAborted( theOp );
322   emit theOp->aborted( theOp );
323
324   stop( theOp );
325
326   return true;
327 }
328
329 /*!
330  * \brief Commits operation
331   * \param theOp - operation to be committed
332   * \return TRUE if operation is committed successfully
333 *
334 * Verifies whether operation already started and commits it in this case (sets execution
335 * status to Accepted and stops operation)
336 */
337 bool SUIT_Study::commit( SUIT_Operation* theOp )
338 {
339   if ( !theOp || myOperations.find( theOp ) == -1 )
340     return false;
341
342   theOp->setExecStatus( SUIT_Operation::Accepted );
343
344   theOp->commitOperation();
345   operationCommited( theOp );
346   emit theOp->committed( theOp );
347
348   stop( theOp );
349
350   emit studyModified( this );
351
352   return true;
353 }
354
355 /*!
356  * \brief Commits operation
357   * \param theOp - operation to be committed
358   * \return TRUE if operation is suspended successfully
359 *
360 * Verifies whether operation already started and suspends it in this case. Operations
361 * ususlly are suspended to start other one above them.
362 */
363 bool SUIT_Study::suspend( SUIT_Operation* theOp )
364 {
365   if ( !theOp || myOperations.find( theOp ) == -1 || theOp->state() == SUIT_Operation::Suspended )
366     return false;
367
368   theOp->setState( SUIT_Operation::Suspended );
369   theOp->suspendOperation();
370   emit theOp->suspended( theOp );
371   return true;
372 }
373
374
375 /*!
376  * \brief Resumes operation
377   * \param theOp - operation to be resumed
378   * \return TRUE if operation is aborted successfully
379 *
380 * Verifies whether operation already started but suspended and resumesit in this case.
381 */
382 bool SUIT_Study::resume( SUIT_Operation* theOp )
383 {
384   if ( !theOp || myOperations.find( theOp ) == -1 ||
385        theOp->state() == SUIT_Operation::Running ||
386        blockingOperation( theOp ) != 0 )
387     return false;
388
389   if ( myOperations.count() > 0 )
390     suspend( myOperations.last() );
391
392   theOp->setState( SUIT_Operation::Running );
393   theOp->resumeOperation();
394
395   // Move operation at the end of list in order to sort it in the order of activation.
396   // As result active operation is a last operation of list, operation which was active
397   // before currently active operation is located before it and so on
398   myOperations.remove( theOp );
399   myOperations.append( theOp );
400
401   emit theOp->resumed( theOp );
402   return true;
403 }
404
405 /*!
406  * \brief Stops operation
407   * \param theOp - operation to be stopped
408 *
409 * Stops operation. This private method is called from abort() and commit() ones to perform
410 * common actions when operation is stopped
411 */
412 void SUIT_Study::stop( SUIT_Operation* theOp )
413 {
414   theOp->setState( SUIT_Operation::Waiting );
415   myOperations.remove( theOp );
416
417   // get last operation which can be resumed
418   SUIT_Operation* anOp, *aResultOp = 0;
419   for ( anOp = myOperations.last(); anOp; anOp = myOperations.prev() )
420   {
421     if ( anOp && anOp != theOp && blockingOperation( anOp ) == 0 )
422     {
423       aResultOp = anOp;
424       break;
425     }
426   }
427
428   theOp->stopOperation();
429   operationStopped( theOp );
430   emit theOp->stopped( theOp );
431
432   if ( aResultOp )
433     resume( aResultOp );
434 }
435
436 /*!
437  * \brief Get all started operations
438   * \return List of all started operations
439 */
440 const QPtrList<SUIT_Operation>& SUIT_Study::operations() const
441 {
442   return myOperations;
443 }
444
445 /*!
446  * \brief Perform some actions when operation starting
447 */
448 void SUIT_Study::operationStarted( SUIT_Operation* op )
449 {
450   if ( !op )
451     return;
452
453   if ( op->testFlags( SUIT_Operation::Transaction ) )
454     op->openTransaction();
455 }
456
457 /*!
458  * \brief Perform some actions when operation aborted
459 */
460 void SUIT_Study::operationAborted( SUIT_Operation* op )
461 {
462   if ( op->testFlags( SUIT_Operation::Transaction ) )
463     op->abortTransaction();
464 }
465
466 /*!
467  * \brief Perform some actions when operation commited
468 */
469 void SUIT_Study::operationCommited( SUIT_Operation* op )
470 {
471   if ( op->testFlags( SUIT_Operation::Transaction ) )
472     op->commitTransaction( op->operationName() );
473 }
474
475 /*!
476  * \brief Perform some actions when operation stopped
477 */
478 void SUIT_Study::operationStopped( SUIT_Operation* )
479 {
480 }
481
482 /*!
483  * \brief Opens transaction for data modifications.
484 */
485 bool SUIT_Study::openTransaction()
486 {
487   return true;
488 }
489
490 /*!
491  * \brief Aborts transaction and all performed data modifications.
492 */
493 bool SUIT_Study::abortTransaction()
494 {
495   return true;
496 }
497
498 /*!
499  * \brief Commits transaction and all performed data modifications.
500 */
501 bool SUIT_Study::commitTransaction( const QString& )
502 {
503   return true;
504 }
505
506 /*!
507  * \brief Returns TRUE if transaction is opened.
508 */
509 bool SUIT_Study::hasTransaction() const
510 {
511   return false;
512 }