Salome HOME
Fix for bug 10438: Crash during Explode on Blocks operation (Global selection on...
[modules/gui.git] / src / SUIT / SUIT_Study.cxx
index cbff2154e0997ea1312318b9a452adb13ea02128..9c2af0282d394045b990ba003b537826bd85eecb 100755 (executable)
 #include "SUIT_DataObject.h"
 #include "SUIT_MessageBox.h"
 #include "SUIT_Application.h"
+#include <qvaluevector.h>
 
+/*!\class SUIT_Study
+ * Support study management. Object management. Operation management.
+ */
+
+/*!Constructor.*/
 SUIT_Study::SUIT_Study( SUIT_Application* app )
 : QObject(),
 myApp( app ),
 myIsSaved( false ),
 myIsModified( false ),
-myName( "" )
+myName( "" ),
+myBlockChangeState( false )
 {
   static int _id = 0;
 
-  myId = _id++;
+  myId = ++_id;
 
   myRoot = new SUIT_DataObject();
   myOperations.setAutoDelete( false );
+
+  connect( this, SIGNAL( changeOperationState( bool ) ), this, SLOT( onChangeOperationState( bool ) ) );
+
+  myOperations.setAutoDelete( false );
 }
 
+/*!Destructor.*/
 SUIT_Study::~SUIT_Study()
 {
   delete myRoot;
   myRoot = 0;
 }
 
+/*!
+ *\retval study id.
+ */
 int SUIT_Study::id() const
 {
   return myId;
 }
 
+/*!
+ *\retval root data object.
+ */
 SUIT_DataObject* SUIT_Study::root() const
 {
   return myRoot;
 }
 
+/*!
+ *\retval Application.
+ */
 SUIT_Application* SUIT_Study::application() const
 {
   return myApp;
 }
 
+/*!
+ *\retval study name
+ */
 QString SUIT_Study::studyName() const
 {
   return myName;
 }
 
+/*!
+ *\retval active operation.
+ */
 SUIT_Operation* SUIT_Study::activeOperation() const
 {
-  return myOperations.current();
+  return myOperations.count() > 0 ? myOperations.getLast() : 0;
 }
 
+/*!
+ *\retval TRUE - if study saved, else FALSE.
+ */
 bool SUIT_Study::isSaved() const
 {
   return myIsSaved;
 }
 
+/*!
+ *\retval TRUE - if study modified, else FALSE.
+ */
 bool SUIT_Study::isModified() const
 {
   return myIsModified;
 }
 
-void SUIT_Study::closeDocument()
+/*!
+ *Close document. NOT IMPLEMENTED.
+ */
+void SUIT_Study::closeDocument(bool permanently)
 {
 }
 
 void SUIT_Study::createDocument()
 {
-  // Custom document initialization to be performed
-  // within onNewDoc() handler can be put here
+  /*! Custom document initialization to be performed \n
+   *  within onNewDoc() handler can be put here
+   */
 }
 
+/*!
+ * Open document. Sets file name. return true.
+ */
 bool SUIT_Study::openDocument( const QString& fileName )
 {
   myName = fileName;
@@ -81,6 +121,9 @@ bool SUIT_Study::openDocument( const QString& fileName )
   return true;
 }
 
+/*!
+ * Save document as \a fileName. Set file name.
+ */
 bool SUIT_Study::saveDocumentAs( const QString& fileName )
 {
   myName = fileName;
@@ -90,40 +133,60 @@ bool SUIT_Study::saveDocumentAs( const QString& fileName )
   return true;
 }
 
+/*!
+ *\retval TRUE - if document saved successful, else FALSE.
+ */
 bool SUIT_Study::saveDocument()
 {
   return saveDocumentAs( myName );
 }
 
+/*!
+ *Abort all operations.
+ */
 void SUIT_Study::abortAllOperations()
 {
-  SUIT_Operation* aOperation = 0;
-  while ( aOperation = myOperations.current() )
-  {
-    aOperation->abort();
-    myOperations.pop();
-  }
+  myBlockChangeState = true;
+  for( SUIT_Operation* op = myOperations.first(); op; op = myOperations.next() )
+    op->abort();
+  myBlockChangeState = false;
+  myOperations.clear();
 }
 
+/*!
+  Update study. NOT IMPLEMENTED HERE.
+ */
 void SUIT_Study::update()
 {
 }
 
+/*!
+  Emit study modified.
+ */
 void SUIT_Study::sendChangesNotification()
 {
   emit studyModified( this );
 }
 
+/*!
+  Set study saved to \a on.
+ */
 void SUIT_Study::setIsSaved( const bool on )
 {
   myIsSaved = on;
 }
 
+/*!
+  Set study modified to \a on.
+ */
 void SUIT_Study::setIsModified( const bool on )
 {
   myIsModified = on;
 }
 
+/*!
+  Set root object.
+ */
 void SUIT_Study::setRoot( SUIT_DataObject* obj )
 {
   if ( myRoot == obj )
@@ -133,44 +196,223 @@ void SUIT_Study::setRoot( SUIT_DataObject* obj )
   myRoot = obj;
 }
 
+/*!
+  Set study name.
+ */
 void SUIT_Study::setStudyName( const QString& name )
 {
   myName = name;
 }
 
-void SUIT_Study::stopOperation()
+/*!
+ * \brief Verifies whether operation can be activated above already started ones
+  * \param theOp - operation to be checked
+  * \return NULL if operation can be activated, pointer to operation which denies
+  * starting tested operation
+*
+* Verifies whether operation can be activated above already started ones. This method
+* is called from SUIT_Study::start() and SUIT_Study::resume() methods.
+*/
+SUIT_Operation* SUIT_Study::blockingOperation( SUIT_Operation* theOp ) const
 {
-  myOperations.pop();
-  if ( myOperations.current() )
-    myOperations.current()->resume();
-  myIsModified = true;
+  if( theOp->isGranted() )
+    return 0;
+
+  Operations tmpOps( myOperations );
+  SUIT_Operation* anOp = 0;
+  for ( anOp = tmpOps.last(); anOp; anOp = tmpOps.prev() )
+  {
+    if ( anOp != 0 && anOp!= theOp && !anOp->isValid( theOp ) )
+      return anOp;
+  }
+
+  return 0;
 }
 
-bool SUIT_Study::canStartOperation( SUIT_Operation* theOperation )
+/*!
+ * \brief Starts operation
+  * \param theOp - operation to be started
+  * \param toCheck - if parameters is equal TRUE then checking performed whether
+  * all already started operations allow to start this operation above them (default
+  * value is TRUE
+  * \return TRUE if operation is started, FALSE otherwise
+*
+* Verifies whether theOp operation can be started above already started ones (if toCheck
+* parameter is equal TRUE) and starts it
+*/
+bool SUIT_Study::start( SUIT_Operation* theOp, const bool toCheck )
 {
-  SUIT_Operation* anActiveOperation = (SUIT_Operation*)activeOperation();
-  if ( anActiveOperation )
+  if ( !theOp || myOperations.find( theOp ) >= 0 )
+    return false;
+
+  theOp->setExecStatus( SUIT_Operation::Rejected );
+  theOp->setStudy( this );
+
+  if ( !theOp->isReadyToStart() )
+    return false;
+
+  if ( toCheck )
   {
-    if ( !theOperation->isGranted() )
+    while( SUIT_Operation* anOp = blockingOperation( theOp ) )
     {
-      if ( !anActiveOperation->isValid( theOperation ) )
-      {
-        // Ask user about existing operation
-        int anAnsw = SUIT_MessageBox::warn2( application()->desktop(), tr( "Operation launch" ), 
-                                             tr( "Previous operation is not finished and will be aborted." ),
-                                             tr( "Continue" ), tr( "Cancel" ), 0, 1, 1 );
-        if ( anAnsw == 1 )
-          return false;
-
-        anActiveOperation->abort();
-        myOperations.pop();
-        myOperations.push( theOperation );
-        return true;
-      }
+      int anAnsw = SUIT_MessageBox::warn2( application()->desktop(),
+         tr( "OPERATION_LAUNCH" ), tr( "PREVIOUS_NOT_FINISHED" ),
+         tr( "CONTINUE" ), tr( "CANCEL" ), 0, 1, 1 );
+
+      if( anAnsw == 1 )
+        return false;
+      else
+        anOp->abort();
     }
-    anActiveOperation->suspend();
   }
-  myOperations.push( theOperation );
 
+  SUIT_Operation* anOp = activeOperation();
+  if ( anOp )
+  {
+    activeOperation()->suspendOperation();
+    anOp->setState( SUIT_Operation::Suspended );
+  }
+
+  theOp->setState( SUIT_Operation::Running );
+  myOperations.append( theOp );
+  emit theOp->started( theOp );
+  theOp->startOperation();
+  
+  return true;
+}
+
+/*!
+ * \brief Aborts operation
+  * \param theOp - operation to be aborted
+  * \return TRUE if operation is aborted successfully
+*
+* Verifies whether operation already started and aborts it in this case (sets execution
+* status to Rejected and stops operation)
+*/
+bool SUIT_Study::abort( SUIT_Operation* theOp )
+{
+  if ( !theOp || myOperations.find( theOp ) == -1 )
+    return false;
+
+  theOp->abortOperation();
+  theOp->setExecStatus( SUIT_Operation::Rejected );
+  emit theOp->aborted( theOp );
+  stop( theOp );
+  return true;
+}
+
+/*!
+ * \brief Commits operation
+  * \param theOp - operation to be committed
+  * \return TRUE if operation is committed successfully
+*
+* Verifies whether operation already started and commits it in this case (sets execution
+* status to Accepted and stops operation)
+*/
+bool SUIT_Study::commit( SUIT_Operation* theOp )
+{
+  if ( !theOp || myOperations.find( theOp ) == -1 )
+    return false;
+
+  theOp->commitOperation();
+  theOp->setExecStatus( SUIT_Operation::Accepted );
+  emit theOp->committed( theOp );
+  stop( theOp );
+  emit studyModified( this );
+  return true;
+}
+
+/*!
+ * \brief Commits operation
+  * \param theOp - operation to be committed
+  * \return TRUE if operation is suspended successfully
+*
+* Verifies whether operation already started and suspends it in this case. Operations
+* ususlly are suspended to start other one above them.
+*/
+bool SUIT_Study::suspend( SUIT_Operation* theOp )
+{
+  if ( !theOp || myOperations.find( theOp ) == -1 || theOp->state() == SUIT_Operation::Suspended )
+    return false;
+
+  theOp->setState( SUIT_Operation::Suspended );
+  theOp->suspendOperation();
+  emit theOp->suspended( theOp );
+  return true;
+}
+
+
+/*!
+ * \brief Resumes operation
+  * \param theOp - operation to be resumed
+  * \return TRUE if operation is aborted successfully
+*
+* Verifies whether operation already started but suspended and resumesit in this case.
+*/
+bool SUIT_Study::resume( SUIT_Operation* theOp )
+{
+  if ( !theOp || myOperations.find( theOp ) == -1 ||
+       theOp->state() == SUIT_Operation::Running ||
+       blockingOperation( theOp ) != 0 )
+    return false;
+
+  if ( myOperations.count() > 0 )
+    suspend( myOperations.last() );
+
+  theOp->setState( SUIT_Operation::Running );
+  theOp->resumeOperation();
+
+  // Move operation at the end of list in order to sort it in the order of activation.
+  // As result active operation is a last operation of list, operation which was active
+  // before currently active operation is located before it and so on
+  myOperations.remove( theOp );
+  myOperations.append( theOp );
+
+  emit theOp->resumed( theOp );
   return true;
 }
+
+/*!
+ * \brief Stops operation
+  * \param theOp - operation to be stopped
+*
+* Stops operation. This private method is called from abort() and commit() ones to perform
+* common actions when operation is stopped
+*/
+void SUIT_Study::stop( SUIT_Operation* theOp )
+{
+  theOp->setState( SUIT_Operation::Waiting );
+  myOperations.remove( theOp );
+
+  // get last operation which can be resumed
+  SUIT_Operation* anOp, *aResultOp = 0;
+  for( anOp = myOperations.last(); anOp; anOp = myOperations.prev() )
+    if ( anOp && anOp != theOp && blockingOperation( anOp ) == 0 )
+    {
+      aResultOp = anOp;
+      break;
+    }
+
+  emit theOp->stopped( theOp );
+  if ( aResultOp )
+    resume( aResultOp );
+}
+
+/*!
+ * \brief Get all started operations
+  * \return List of all started operations
+*/
+const QPtrList<SUIT_Operation>& SUIT_Study::operations() const
+{
+  return myOperations;
+}
+
+
+
+
+
+
+
+
+
+