Salome HOME
Issue #2219: keep the order of remove-shape sub-elements after deselection of some...
[modules/shaper.git] / src / Model / Model_Document.cpp
index 89c596d6d2026e2df305d0709adba247570732d2..c6d7dda35baa7ce1647ba3a60d10e83fa8c74880 100755 (executable)
@@ -1,8 +1,22 @@
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File:        Model_Document.cxx
-// Created:     28 Feb 2014
-// Author:      Mikhail PONIKAROV
+// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
 
 #include <Model_Document.h>
 #include <Model_Data.h>
@@ -16,6 +30,7 @@
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultCompSolid.h>
 #include <Events_Loop.h>
 #include <Events_InfoMessage.h>
 
@@ -73,6 +88,8 @@ static const int TAG_CURRENT_FEATURE = 1; ///< reference to the current feature
 static const int TAG_CURRENT_TRANSACTION = 2; ///< integer, index of the transaction
 static const int TAG_SELECTION_FEATURE = 3; ///< integer, tag of the selection feature label
 static const int TAG_NODES_STATE = 4; ///< array, tag of the Object Browser nodes states
+///< naming structures constructions selected from other document
+static const int TAG_EXTERNAL_CONSTRUCTIONS = 5;
 
 Model_Document::Model_Document(const int theID, const std::string theKind)
     : myID(theID), myKind(theKind), myIsActive(false),
@@ -219,7 +236,8 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum
     for(; aPartRes != aPartResults.end(); aPartRes++) {
       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aPartRes);
       if (aPart.get())
-        anApp->setLoadByDemand(aPart->data()->name());
+        anApp->setLoadByDemand(aPart->data()->name(),
+          aPart->data()->document(ModelAPI_ResultPart::DOC_REF())->docId());
     }
 
   } else { // open failed, but new documnet was created to work with it: inform the model
@@ -231,6 +249,27 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum
 bool Model_Document::save(
   const char* theDirName, const char* theFileName, std::list<std::string>& theResults)
 {
+  // if the history line is not in the end, move it to the end before save, otherwise
+  // problems with results restore and (the most important) naming problems will appear
+  // due to change evolution to SELECTION (problems in NamedShape and Name)
+  FeaturePtr aWasCurrent;
+  std::shared_ptr<Model_Session> aSession =
+    std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
+  if (currentFeature(false) != lastFeature()) {
+    aSession->setCheckTransactions(false);
+    aWasCurrent = currentFeature(false);
+    // if last is nested into something else, make this something else as last:
+    // otherwise it will look like edition of sub-element, so, the main will be disabled
+    FeaturePtr aLast = lastFeature();
+    if (aLast.get()) {
+      CompositeFeaturePtr aMain = ModelAPI_Tools::compositeOwner(aLast);
+      while(aMain.get()) {
+        aLast = aMain;
+        aMain = ModelAPI_Tools::compositeOwner(aLast);
+      }
+    }
+    setCurrentFeature(aLast, true);
+  }
   // create a directory in the root document if it is not yet exist
   Handle(Model_Application) anApp = Model_Application::getApplication();
   if (isRoot()) {
@@ -249,6 +288,10 @@ bool Model_Document::save(
     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
     Events_InfoMessage("Model_Document",
         "Exception in saving of document: %1").arg(aFail->GetMessageString()).send();
+    if (aWasCurrent.get()) { // return the current feature to the initial position
+      setCurrentFeature(aWasCurrent, false);
+      aSession->setCheckTransactions(true);
+    }
     return false;
   }
   bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
@@ -267,6 +310,12 @@ bool Model_Document::save(
         break;
     }
   }
+
+  if (aWasCurrent.get()) { // return the current feature to the initial position
+    setCurrentFeature(aWasCurrent, false);
+    aSession->setCheckTransactions(true);
+  }
+
   myTransactionSave = int(myTransactions.size());
   if (isDone) {  // save also sub-documents if any
     theResults.push_back(TCollection_AsciiString(aPath).ToCString());
@@ -532,10 +581,14 @@ bool Model_Document::finishOperation()
   }
   myObjs->synchronizeBackRefs();
   Events_Loop* aLoop = Events_Loop::loop();
-  aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
-  aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
-  aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
-  aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+  static const Events_ID kCreatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED);
+  static const Events_ID kUpdatedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
+  static const Events_ID kRedispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+  static const Events_ID kDeletedEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED);
+  aLoop->flush(kCreatedEvent);
+  aLoop->flush(kUpdatedEvent);
+  aLoop->flush(kRedispEvent);
+  aLoop->flush(kDeletedEvent);
 
   if (isNestedClosed) {
     if (myDoc->CommitCommand())
@@ -546,12 +599,22 @@ bool Model_Document::finishOperation()
   // to avoid messages about modifications outside of the transaction
   // and to rebuild everything after all updates and creates
   if (isRoot()) { // once for root document
-    Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
     static std::shared_ptr<Events_Message> aFinishMsg
       (new Events_Message(Events_Loop::eventByName("FinishOperation")));
     Events_Loop::loop()->send(aFinishMsg);
-    Events_Loop::loop()->autoFlush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), false);
   }
+
+  // for open of document with primitive box inside (finish transaction in initAttributes)
+  bool aWasActivatedFlushes = aLoop->activateFlushes(true);
+  while(aLoop->hasGrouppedEvent(kCreatedEvent) || aLoop->hasGrouppedEvent(kUpdatedEvent) ||
+        aLoop->hasGrouppedEvent(kRedispEvent) || aLoop->hasGrouppedEvent(kDeletedEvent)) {
+    aLoop->flush(kCreatedEvent);
+    aLoop->flush(kUpdatedEvent);
+    aLoop->flush(kRedispEvent);
+    aLoop->flush(kDeletedEvent);
+  }
+  aLoop->activateFlushes(aWasActivatedFlushes);
+
   // to avoid "updated" message appearance by updater
   //aLoop->clear(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
 
@@ -914,22 +977,23 @@ void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   // add it after all nested (otherwise the nested will be disabled)
   CompositeFeaturePtr aCompositeAfter =
     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theAfterThis);
+  FeaturePtr anAfterThisSub = theAfterThis;
   if (aCompositeAfter.get()) {
     FeaturePtr aSub = aCompositeAfter;
     do {
       FeaturePtr aNext = myObjs->nextFeature(aSub);
       if (!isSub(aCompositeAfter, aNext)) {
-        theAfterThis = aSub;
+        anAfterThisSub = aSub;
         break;
       }
       aSub = aNext;
     } while (aSub.get());
   }
 
-  myObjs->moveFeature(theMoved, theAfterThis);
+  myObjs->moveFeature(theMoved, anAfterThisSub);
   if (aCurrentUp) { // make the moved feature enabled or disabled due to the real status
     setCurrentFeature(currentFeature(false), false);
-  } else if (theAfterThis == currentFeature(false)) {
+  } else if (theAfterThis == currentFeature(false) || anAfterThisSub == currentFeature(false)) {
     // must be after move to make enabled all features which are before theMoved
     setCurrentFeature(theMoved, true);
   }
@@ -1078,7 +1142,7 @@ void Model_Document::setCurrentFeature(
       if (isSub(aMain, anIter)) // sub-elements of not-disabled feature are not disabled
         aDisabledFlag = false;
       else if (anOwners.find(anIter) != anOwners.end())
-        // disable the higher-level feature is the nested is the current
+        // disable the higher-level feature if the nested is the current
         aDisabledFlag = true;
     }
 
@@ -1329,6 +1393,11 @@ void Model_Document::decrementTransactionID()
   TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal);
 }
 
+TDF_Label Model_Document::extConstructionsLabel() const
+{
+  return myDoc->Main().FindChild(TAG_EXTERNAL_CONSTRUCTIONS);
+}
+
 bool Model_Document::isOpened()
 {
   return myObjs && !myDoc.IsNull();
@@ -1587,3 +1656,9 @@ void Model_Document::restoreNodesState(std::list<bool>& theStates) const
     }
   }
 }
+
+void Model_Document::eraseAllFeatures()
+{
+  if (myObjs)
+    myObjs->eraseAllFeatures();
+}