Salome HOME
Updated copyright comment
[modules/gui.git] / src / SUIT / SUIT_Study.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, 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, or (at your option) any later version.
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 \c true - if study saved, else \c false.
100  */
101 bool SUIT_Study::isSaved() const
102 {
103   return myIsSaved;
104 }
105
106 /*!
107  *\retval \c true - if study modified, else \c 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 \c 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 \c true - if document saved successful, else \c 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   while ( !myOperations.isEmpty() ) {
169     Operations::iterator it = myOperations.begin();
170     (*it)->abort();
171   }
172   myBlockChangeState = false;
173   myOperations.clear();
174 }
175
176 /*!
177   Update study. NOT IMPLEMENTED HERE.
178  */
179 void SUIT_Study::update()
180 {
181 }
182
183 /*!
184   Emit study modified.
185  */
186 void SUIT_Study::sendChangesNotification()
187 {
188   emit studyModified( this );
189 }
190
191 /*!
192   Set study saved to \a on.
193  */
194 void SUIT_Study::setIsSaved( const bool on )
195 {
196   myIsSaved = on;
197 }
198
199 /*!
200   Set study modified to \a on.
201  */
202 void SUIT_Study::setIsModified( const bool on )
203 {
204   myIsModified = on;
205 }
206
207 /*!
208   Set study modified to \a on.
209  */
210 void SUIT_Study::Modified()
211 {
212   setIsModified( true );
213   sendChangesNotification();
214 }
215
216 /*!
217   Set root object.
218  */
219 void SUIT_Study::setRoot( SUIT_DataObject* obj )
220 {
221   if ( myRoot == obj )
222     return;
223
224   // This is necessary in order not to destroy the complete tree of objects
225   if ( obj )
226     obj->reparentChildren( myRoot );
227
228   delete myRoot;
229   myRoot = obj;
230 }
231
232 /*!
233   Set study name.
234  */
235 void SUIT_Study::setStudyName( const QString& name )
236 {
237   myName = name;
238 }
239
240 /*!
241  * \brief Verifies whether operation can be activated above already started ones
242   * \param theOp - operation to be checked
243   * \return NULL if operation can be activated, pointer to operation which denies
244   * starting tested operation
245 *
246 * Verifies whether operation can be activated above already started ones. This method
247 * is called from SUIT_Study::start() and SUIT_Study::resume() methods.
248 */
249 SUIT_Operation* SUIT_Study::blockingOperation( SUIT_Operation* theOp ) const
250 {
251   if( theOp->isGranted() )
252     return 0;
253
254   Operations tmpOps( myOperations );
255   for ( Operations::const_iterator it = tmpOps.end(); it != tmpOps.begin(); )
256   {
257     it--;
258     SUIT_Operation* anOp = *it;
259     if ( anOp != 0 && anOp!= theOp && !anOp->isValid( theOp ) )
260       return anOp;
261   }
262
263   return 0;
264 }
265
266 /*!
267  * \brief Starts operation
268   * \param theOp - operation to be started
269   * \param toCheck - if parameters is equal \c true then checking performed whether
270   * all already started operations allow to start this operation above them (default
271   * value is \c true
272   * \return \c true if operation is started, \c false otherwise
273 *
274 * Verifies whether theOp operation can be started above already started ones (if toCheck
275 * parameter is equal \c true) and starts it
276 */
277 bool SUIT_Study::start( SUIT_Operation* theOp, const bool toCheck )
278 {
279   if ( !theOp || myOperations.contains( theOp ) )
280     return false;
281
282   theOp->setExecStatus( SUIT_Operation::Rejected );
283   theOp->setStudy( this );
284
285   if ( !theOp->isReadyToStart() )
286     return false;
287
288   if ( toCheck )
289   {
290     while ( SUIT_Operation* anOp = blockingOperation( theOp ) )
291     {
292       int anAnsw = SUIT_MessageBox::question( application()->desktop(),
293                                               tr( "OPERATION_LAUNCH" ), tr( "PREVIOUS_NOT_FINISHED" ),
294                                               tr( "CONTINUE" ), tr( "CANCEL" ) );
295
296       if ( anAnsw == 1 )
297         return false;
298       else
299         anOp->abort();
300     }
301   }
302
303   SUIT_Operation* anOp = activeOperation();
304   if ( anOp )
305   {
306     activeOperation()->suspendOperation();
307     anOp->setState( SUIT_Operation::Suspended );
308   }
309
310   theOp->setState( SUIT_Operation::Running );
311   myOperations.append( theOp );
312  
313   emit theOp->started( theOp );
314   operationStarted( theOp );
315   theOp->startOperation();
316
317   return true;
318 }
319
320 /*!
321  * \brief Aborts operation
322   * \param theOp - operation to be aborted
323   * \return \c true if operation is aborted successfully
324 *
325 * Verifies whether operation already started and aborts it in this case (sets execution
326 * status to Rejected and stops operation)
327 */
328 bool SUIT_Study::abort( SUIT_Operation* theOp )
329 {
330   if ( !theOp || !myOperations.contains( theOp ) )
331     return false;
332
333   theOp->setExecStatus( SUIT_Operation::Rejected );
334
335   theOp->abortOperation();
336   operationAborted( theOp );
337   emit theOp->aborted( theOp );
338
339   stop( theOp );
340
341   return true;
342 }
343
344 /*!
345  * \brief Commits operation
346   * \param theOp - operation to be committed
347   * \return \c true if operation is committed successfully
348 *
349 * Verifies whether operation already started and commits it in this case (sets execution
350 * status to Accepted and stops operation)
351 */
352 bool SUIT_Study::commit( SUIT_Operation* theOp )
353 {
354   if ( !theOp || !myOperations.contains( theOp ) )
355     return false;
356
357   theOp->setExecStatus( SUIT_Operation::Accepted );
358
359   theOp->commitOperation();
360   operationCommited( theOp );
361   emit theOp->committed( theOp );
362
363   stop( theOp );
364
365   emit studyModified( this );
366
367   return true;
368 }
369
370 /*!
371  * \brief Commits operation
372   * \param theOp - operation to be committed
373   * \return \c true if operation is suspended successfully
374 *
375 * Verifies whether operation already started and suspends it in this case. Operations
376 * ususlly are suspended to start other one above them.
377 */
378 bool SUIT_Study::suspend( SUIT_Operation* theOp )
379 {
380   if ( !theOp || !myOperations.contains( theOp ) || theOp->state() == SUIT_Operation::Suspended )
381     return false;
382
383   theOp->setState( SUIT_Operation::Suspended );
384   theOp->suspendOperation();
385   emit theOp->suspended( theOp );
386   return true;
387 }
388
389
390 /*!
391  * \brief Resumes operation
392   * \param theOp - operation to be resumed
393   * \return \c true if operation is aborted successfully
394 *
395 * Verifies whether operation already started but suspended and resumesit in this case.
396 */
397 bool SUIT_Study::resume( SUIT_Operation* theOp )
398 {
399   if ( !theOp || !myOperations.contains( theOp ) ||
400        theOp->state() == SUIT_Operation::Running ||
401        blockingOperation( theOp ) != 0 )
402     return false;
403
404   if ( myOperations.count() > 0 )
405     suspend( myOperations.last() );
406
407   theOp->setState( SUIT_Operation::Running );
408   theOp->resumeOperation();
409
410   // Move operation at the end of list in order to sort it in the order of activation.
411   // As result active operation is a last operation of list, operation which was active
412   // before currently active operation is located before it and so on
413   myOperations.removeAll( theOp );
414   myOperations.append( theOp );
415
416   emit theOp->resumed( theOp );
417   return true;
418 }
419
420 /*!
421  * \brief Stops operation
422   * \param theOp - operation to be stopped
423 *
424 * Stops operation. This private method is called from abort() and commit() ones to perform
425 * common actions when operation is stopped
426 */
427 void SUIT_Study::stop( SUIT_Operation* theOp )
428 {
429   theOp->setState( SUIT_Operation::Waiting );
430   myOperations.removeAll( theOp );
431
432   // get last operation which can be resumed
433   SUIT_Operation* aResultOp = 0;
434
435   QListIterator<SUIT_Operation*> it (myOperations);
436   it.toBack();
437   while( it.hasPrevious() )
438   {
439     SUIT_Operation* anOp = it.previous();
440     if ( anOp && anOp != theOp && blockingOperation( anOp ) == 0 )
441     {
442       aResultOp = anOp;
443       break;
444     }
445   }
446
447   theOp->stopOperation();
448   operationStopped( theOp );
449   emit theOp->stopped( theOp );
450
451   if ( aResultOp )
452     resume( aResultOp );
453 }
454
455 /*!
456  * \brief Get all started operations
457   * \return List of all started operations
458 */
459 const QList<SUIT_Operation*>& SUIT_Study::operations() const
460 {
461   return myOperations;
462 }
463
464 /*!
465  * \brief Perform some actions when operation starting
466 */
467 void SUIT_Study::operationStarted( SUIT_Operation* op )
468 {
469   if ( !op )
470     return;
471
472   if ( op->testFlags( SUIT_Operation::Transaction ) )
473     op->openTransaction();
474 }
475
476 /*!
477  * \brief Perform some actions when operation aborted
478 */
479 void SUIT_Study::operationAborted( SUIT_Operation* op )
480 {
481   if ( op->testFlags( SUIT_Operation::Transaction ) )
482     op->abortTransaction();
483 }
484
485 /*!
486  * \brief Perform some actions when operation commited
487 */
488 void SUIT_Study::operationCommited( SUIT_Operation* op )
489 {
490   if ( op->testFlags( SUIT_Operation::Transaction ) )
491     op->commitTransaction( op->operationName() );
492 }
493
494 /*!
495  * \brief Perform some actions when operation stopped
496 */
497 void SUIT_Study::operationStopped( SUIT_Operation* )
498 {
499 }
500
501 /*!
502  * \brief Opens transaction for data modifications.
503 */
504 bool SUIT_Study::openTransaction()
505 {
506   return true;
507 }
508
509 /*!
510  * \brief Aborts transaction and all performed data modifications.
511 */
512 bool SUIT_Study::abortTransaction()
513 {
514   return true;
515 }
516
517 /*!
518  * \brief Commits transaction and all performed data modifications.
519 */
520 bool SUIT_Study::commitTransaction( const QString& )
521 {
522   return true;
523 }
524
525 /*!
526  * \brief Returns \c true if transaction is opened.
527 */
528 bool SUIT_Study::hasTransaction() const
529 {
530   return false;
531 }
532
533 /*!
534  * \brief Restores the study state.
535  */
536 void SUIT_Study::restoreState(int /*savePoint*/)
537 {
538 }