Salome HOME
Merge branch 'Dev_1.4.0' of newgeom:newgeom into Dev_1.4.0
[modules/shaper.git] / src / Model / Model_Document.cpp
index 5d33e78ba6ae330eb1344b3dbb757bb9c48f6e29..4ff65b48c699da6b4d07e62764f267cd22fdebf1 100644 (file)
@@ -68,6 +68,8 @@ Model_Document::Model_Document(const std::string theID, const std::string theKin
   // in transaction for nesting correct working
   myDoc->NewCommand();
   TDataStd_Integer::Set(myDoc->Main().Father(), 0);
+  // this to avoid creation of integer attribute outside the transaction after undo
+  transactionID();
   myDoc->CommitCommand();
 }
 
@@ -103,8 +105,9 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis)
   }
   TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
   PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
+  Handle(TDocStd_Document) aLoaded;
   try {
-    aStatus = anApp->Open(aPath, myDoc);
+    aStatus = anApp->Open(aPath, aLoaded);
   } catch (Standard_Failure) {
     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
     Events_Error::send(
@@ -166,6 +169,7 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis)
     }
   }
   if (!isError) {
+    myDoc = aLoaded;
     myDoc->SetUndoLimit(UNDO_LIMIT);
     // to avoid the problem that feature is created in the current, not this, document
     std::shared_ptr<Model_Session> aSession = 
@@ -182,7 +186,13 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis)
     aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
     // this is done in Part result "activate", so no needed here. Causes not-blue active part.
     // aSession->setActiveDocument(anApp->getDocument(myID), true);
-  }
+  } else { // open failed, but new documnet was created to work with it: inform the model
+    static std::shared_ptr<Events_Message> aMsg(
+        new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED)));
+    Events_Loop::loop()->send(aMsg);
+    TDF_LabelList anEmpty;
+    myObjs->synchronizeFeatures(anEmpty, true, true);
+  } 
   return !isError;
 }
 
@@ -278,6 +288,7 @@ void Model_Document::close(const bool theForever)
 
   // close all only if it is really asked, otherwise it can be undoed/redoed
   if (theForever) {
+    // flush everything to avoid messages with bad objects
     delete myObjs;
     myObjs = 0;
     if (myDoc->CanClose() == CDM_CCS_OK)
@@ -512,7 +523,7 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron
       subDoc(*aSubIter)->undoInternal(theWithSubs, theSynchronize);
     }
   }
-  // after redo of all sub-documents to avoid updates on not-modified data (issue 370)
+  // after undo of all sub-documents to avoid updates on not-modified data (issue 370)
   if (theSynchronize) {
     myObjs->synchronizeFeatures(aDeltaLabels, true, isRoot());
     // update the current features status
@@ -604,6 +615,7 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre
   FeaturePtr aFeature = aSession->createFeature(theID, this);
   if (!aFeature)
     return aFeature;
+  aFeature->init();
   Model_Document* aDocToAdd;
   if (!aFeature->documentToAdd().empty()) { // use the customized document to add
     if (aFeature->documentToAdd() != kind()) { // the root document by default
@@ -615,7 +627,24 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre
     aDocToAdd = this;
   }
   if (aFeature) {
-    aDocToAdd->myObjs->addFeature(aFeature, aDocToAdd->currentFeature(false));
+    // searching for feature after which must be added the next feature: this is the current feature
+    // but also all sub-features of this feature
+    FeaturePtr aCurrent = aDocToAdd->currentFeature(false);
+    bool isModified = true;
+    for(CompositeFeaturePtr aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCurrent);
+        aComp.get() && isModified; 
+        aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCurrent)) {
+      isModified =  false;
+      int aSubs = aComp->numberOfSubs(false);
+      for(int a = 0; a < aSubs; a++) {
+        FeaturePtr aSub = aComp->subFeature(a, false);
+        if (myObjs->isLater(aSub, aCurrent)) {
+          isModified =  true;
+          aCurrent = aSub;
+        }
+      }
+    }
+    aDocToAdd->myObjs->addFeature(aFeature, aCurrent);
     if (!aFeature->isAction()) {  // do not add action to the data model
       if (theMakeCurrent)  // after all this feature stays in the document, so make it current
         aDocToAdd->setCurrentFeature(aFeature, false);
@@ -642,6 +671,8 @@ void Model_Document::removeFeature(FeaturePtr theFeature)
 void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
 {
   myObjs->moveFeature(theMoved, theAfterThis);
+  if (theAfterThis == currentFeature(true))
+    setCurrentFeature(theMoved, true);
 }
 
 void Model_Document::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
@@ -723,7 +754,7 @@ std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature(const bool theV
 }
 
 void Model_Document::setCurrentFeature(std::shared_ptr<ModelAPI_Feature> theCurrent,
-  const bool theVisible)
+  const bool theVisible, const bool theFlushUpdates)
 {
   // blocks the flush signals to avoid each objects visualization in the viewer
   // they should not be shown once after all modifications are performed
@@ -818,9 +849,11 @@ void Model_Document::setCurrentFeature(std::shared_ptr<ModelAPI_Feature> theCurr
   // unblock  the flush signals and up them after this
   aLoop->activateFlushes(isActive);
 
-  aLoop->flush(aCreateEvent);
-  aLoop->flush(aRedispEvent);
-  aLoop->flush(aDeleteEvent);
+  if (theFlushUpdates) {
+    aLoop->flush(aCreateEvent);
+    aLoop->flush(aRedispEvent);
+    aLoop->flush(aDeleteEvent);
+  }
 }
 
 void Model_Document::setCurrentFeatureUp()
@@ -830,7 +863,8 @@ void Model_Document::setCurrentFeatureUp()
   FeaturePtr aCurrent = currentFeature(false);
   if (aCurrent.get()) { // if not, do nothing because null is the upper
     FeaturePtr aPrev = myObjs->nextFeature(aCurrent, true);
-    setCurrentFeature(aPrev, false);
+    // do not flush: it is called only on remove, it will be flushed in the end of transaction
+    setCurrentFeature(aPrev, false, false);
   }
 }
 
@@ -978,7 +1012,27 @@ std::shared_ptr<ModelAPI_Feature> Model_Document::internalFeature(const int theI
   return myObjs->internalFeature(theIndex);
 }
 
-// Feature that is used for selection in the Part document by the external request
+void Model_Document::synchronizeTransactions()
+{
+  Model_Document* aRoot = 
+    std::dynamic_pointer_cast<Model_Document>(ModelAPI_Session::get()->moduleDocument()).get();
+  if (aRoot == this)
+    return; // don't need to synchronise root with root
+
+  std::shared_ptr<Model_Session> aSession = 
+    std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
+  while(myRedos.size() > aRoot->myRedos.size()) { // remove redos in this
+    aSession->setCheckTransactions(false);
+    redo();
+    aSession->setCheckTransactions(true);
+  }
+  /* this case can not be reproduced in any known case for the current moment, so, just comment
+  while(myRedos.size() < aRoot->myRedos.size()) { // add more redos in this
+    undoInternal(false, true);
+  }*/
+}
+
+/// Feature that is used for selection in the Part document by the external request
 class Model_SelectionInPartFeature : public ModelAPI_Feature {
 public:
   /// Nothing to do in constructor