Salome HOME
Debug of movement of part results
[modules/shaper.git] / src / Model / Model_Document.cpp
index e5c87013ede6a926641a0f41b1c82a0c4fa167aa..6e9fbf778da1aeca0802669c0e14285f9681ff9c 100644 (file)
@@ -13,6 +13,8 @@
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Tools.h>
 
 #include <Events_Loop.h>
 #include <Events_Error.h>
@@ -46,9 +48,11 @@ static const int TAG_GENERAL = 1;  // general properties tag
 
 // general sub-labels
 static const int TAG_CURRENT_FEATURE = 1; ///< where the reference to the current feature label is located (or no attribute if null feature)
+static const int TAG_CURRENT_TRANSACTION = 2; ///< integer, index of the cransaction
+static const int TAG_SELECTION_FEATURE = 3; ///< integer, tag of the selection feature label
 
 Model_Document::Model_Document(const std::string theID, const std::string theKind)
-    : myID(theID), myKind(theKind),
+    : myID(theID), myKind(theKind), myIsActive(false),
       myDoc(new TDocStd_Document("BinOcaf"))  // binary OCAF format
 {
   myObjs = new Model_Objects(myDoc->Main());
@@ -171,7 +175,8 @@ bool Model_Document::load(const char* theFileName, DocumentPtr theThis)
     setCurrentFeature(currentFeature(false), false);
     aSession->setCheckTransactions(true);
     aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
-    aSession->setActiveDocument(anApp->getDocument(myID), true);
+    // this is done in Part result "activate", so no needed here. Causes not-blue active part.
+    // aSession->setActiveDocument(anApp->getDocument(myID), true);
   }
   return !isError;
 }
@@ -257,8 +262,11 @@ void Model_Document::close(const bool theForever)
   // close all subs
   const std::set<std::string> aSubs = subDocuments(true);
   std::set<std::string>::iterator aSubIter = aSubs.begin();
-  for (; aSubIter != aSubs.end(); aSubIter++)
-    subDoc(*aSubIter)->close(theForever);
+  for (; aSubIter != aSubs.end(); aSubIter++) {
+    std::shared_ptr<Model_Document> aSub = subDoc(*aSubIter);
+    if (aSub->myObjs) // if it was not closed before
+      aSub->close(theForever);
+  }
 
   // close for thid document needs no transaction in this document
   std::static_pointer_cast<Model_Session>(Model_Session::get())->setCheckTransactions(false);
@@ -269,6 +277,7 @@ void Model_Document::close(const bool theForever)
     myObjs = 0;
     if (myDoc->CanClose() == CDM_CCS_OK)
       myDoc->Close();
+    mySelectionFeature.reset();
   } else {
     setCurrentFeature(FeaturePtr(), false); // disables all features
   }
@@ -288,6 +297,7 @@ void Model_Document::startOperation()
     myDoc->NewCommand();
   }
   // starts a new operation
+  incrementTransactionID();
   myTransactions.push_back(Transaction());
   if (!myNestedNum.empty())
     (*myNestedNum.rbegin())++;
@@ -324,7 +334,6 @@ bool Model_Document::finishOperation()
   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_TOHIDE));
   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
   // this must be here just after everything is finished but before real transaction stop
   // to avoid messages about modifications outside of the transaction
@@ -424,9 +433,14 @@ bool Model_Document::canUndo()
   // check other subs contains operation that can be undoed
   const std::set<std::string> aSubs = subDocuments(true);
   std::set<std::string>::iterator aSubIter = aSubs.begin();
-  for (; aSubIter != aSubs.end(); aSubIter++)
-    if (subDoc(*aSubIter)->canUndo())
-      return true;
+  for (; aSubIter != aSubs.end(); aSubIter++) {
+    std::shared_ptr<Model_Document> aSub = subDoc(*aSubIter);
+    if (aSub->myObjs) {// if it was not closed before
+      if (aSub->canUndo())
+        return true;
+    }
+  }
+
   return false;
 }
 
@@ -445,14 +459,17 @@ void Model_Document::undoInternal(const bool theWithSubs, const bool theSynchron
     // undo for all subs
     const std::set<std::string> aSubs = subDocuments(true);
     std::set<std::string>::iterator aSubIter = aSubs.begin();
-    for (; aSubIter != aSubs.end(); aSubIter++)
+    for (; aSubIter != aSubs.end(); aSubIter++) {
+      if (!subDoc(*aSubIter)->myObjs)
+        continue;
       subDoc(*aSubIter)->undoInternal(theWithSubs, theSynchronize);
+    }
   }
   // after redo of all sub-documents to avoid updates on not-modified data (issue 370)
   if (theSynchronize) {
+    myObjs->synchronizeFeatures(true, true, isRoot());
     // update the current features status
     setCurrentFeature(currentFeature(false), false);
-    myObjs->synchronizeFeatures(true, true, isRoot());
   }
 }
 
@@ -468,9 +485,12 @@ bool Model_Document::canRedo()
   // check other subs contains operation that can be redoed
   const std::set<std::string> aSubs = subDocuments(true);
   std::set<std::string>::iterator aSubIter = aSubs.begin();
-  for (; aSubIter != aSubs.end(); aSubIter++)
+  for (; aSubIter != aSubs.end(); aSubIter++) {
+    if (!subDoc(*aSubIter)->myObjs)
+      continue;
     if (subDoc(*aSubIter)->canRedo())
       return true;
+  }
   return false;
 }
 
@@ -490,10 +510,10 @@ void Model_Document::redo()
   for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->redo();
 
-  // update the current features status
-  setCurrentFeature(currentFeature(false), false);
   // after redo of all sub-documents to avoid updates on not-modified data (issue 370)
   myObjs->synchronizeFeatures(true, true, isRoot());
+  // update the current features status
+  setCurrentFeature(currentFeature(false), false);
 }
 
 std::list<std::string> Model_Document::undoList() const
@@ -545,10 +565,10 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre
     aDocToAdd = this;
   }
   if (aFeature) {
-    aDocToAdd->myObjs->addFeature(aFeature, currentFeature(false));
+    aDocToAdd->myObjs->addFeature(aFeature, aDocToAdd->currentFeature(false));
     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
-        setCurrentFeature(aFeature, false);
+        aDocToAdd->setCurrentFeature(aFeature, false);
     } else { // feature must be executed
        // no creation event => updater not working, problem with remove part
       aFeature->execute();
@@ -566,17 +586,14 @@ void Model_Document::refsToFeature(FeaturePtr theFeature,
 
 void Model_Document::removeFeature(FeaturePtr theFeature)
 {
-  // if this feature is current, make the current the previous feature
-  if (theFeature == currentFeature(false)) {
-    int aCurrentIndex = index(theFeature);
-    if (aCurrentIndex != -1) {
-      setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(
-        object(ModelAPI_Feature::group(), aCurrentIndex - 1)), false);
-    }
-  }
   myObjs->removeFeature(theFeature);
 }
 
+void Model_Document::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
+{
+  myObjs->moveFeature(theMoved, theAfterThis);
+}
+
 void Model_Document::updateHistory(const std::shared_ptr<ModelAPI_Object> theObject)
 {
   myObjs->updateHistory(theObject);
@@ -636,13 +653,16 @@ int Model_Document::size(const std::string& theGroupID)
 
 std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature(const bool theVisible)
 {
+  if (!myObjs) // on close document feature destruction it may call this method
+    return std::shared_ptr<ModelAPI_Feature>();
   TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
   Handle(TDF_Reference) aRef;
   if (aRefLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
     TDF_Label aLab = aRef->Get();
     FeaturePtr aResult = myObjs->feature(aLab);
     if (theVisible) { // get nearest visible (in history) going up
-      while(aResult.get() && !aResult->isInHistory()) {
+      while(aResult.get() &&  // sub-composites are never in history
+             (!aResult->isInHistory() || ModelAPI_Tools::compositeOwner(aResult).get())) {
         aResult = myObjs->nextFeature(aResult, true);
       }
     }
@@ -654,32 +674,47 @@ std::shared_ptr<ModelAPI_Feature> Model_Document::currentFeature(const bool theV
 void Model_Document::setCurrentFeature(std::shared_ptr<ModelAPI_Feature> theCurrent,
   const bool theVisible)
 {
+  // blocks the flush signals to avoid each objects visualization in the viewer
+  // they should not be shown once after all modifications are performed
+  Events_Loop* aLoop = Events_Loop::loop();
+  bool isActive = aLoop->activateFlushes(false);
+
   TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
+  CompositeFeaturePtr aMain; // main feature that may nest the new current
   if (theCurrent.get()) {
-    /*
-    if (theVisible) { // make features below which are not in history also enabled: sketch subs
-      FeaturePtr aNext = myObjs->nextFeature(theCurrent);
-      for (; aNext.get(); aNext = myObjs->nextFeature(theCurrent)) {
-        if (aNext->isInHistory()) {
-          break; // next in history is not needed
-        } else { // next not in history is good for making current
-          theCurrent = aNext;
+    aMain = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theCurrent);
+    if (!aMain.get()) {
+      // if feature nests into compisite feature, make the composite feature as current
+      const std::set<AttributePtr>& aRefsToMe = theCurrent->data()->refsToMe();
+      std::set<AttributePtr>::const_iterator aRefToMe = aRefsToMe.begin();
+      for(; aRefToMe != aRefsToMe.end(); aRefToMe++) {
+        CompositeFeaturePtr aComposite = 
+          std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*aRefToMe)->owner());
+        if (aComposite.get() && aComposite->isSub(theCurrent)) {
+          aMain = aComposite;
+          break;
         }
       }
-    }*/
-    // if feature nests into compisite feature, make the composite feature as current
-    const std::set<AttributePtr>& aRefsToMe = theCurrent->data()->refsToMe();
-    std::set<AttributePtr>::const_iterator aRefToMe = aRefsToMe.begin();
-    for(; aRefToMe != aRefsToMe.end(); aRefToMe++) {
-      CompositeFeaturePtr aComposite = 
-        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*aRefToMe)->owner());
-      if (aComposite.get() && aComposite->isSub(theCurrent)) {
-        theCurrent = aComposite;
-      }
     }
+  }
 
+  if (theVisible) { // make features below which are not in history also enabled: sketch subs
+    FeaturePtr aNext = 
+      theCurrent.get() ? myObjs->nextFeature(theCurrent) : myObjs->firstFeature();
+    for (; aNext.get(); aNext = myObjs->nextFeature(theCurrent)) {
+      if (aNext->isInHistory()) {
+        break; // next in history is not needed
+      } else { // next not in history is good for making current
+        theCurrent = aNext;
+      }
+    }
+  }
+  if (theCurrent.get()) {
     std::shared_ptr<Model_Data> aData = std::static_pointer_cast<Model_Data>(theCurrent->data());
-    if (!aData.get()) return; // unknown case
+    if (!aData.get() || !aData->isValid()) {
+      aLoop->activateFlushes(isActive);
+      return;
+    }
     TDF_Label aFeatureLabel = aData->label().Father();
 
     Handle(TDF_Reference) aRef;
@@ -692,31 +727,60 @@ void Model_Document::setCurrentFeature(std::shared_ptr<ModelAPI_Feature> theCurr
     aRefLab.ForgetAttribute(TDF_Reference::GetID());
   }
   // make all features after this feature disabled in reversed order (to remove results without deps)
-  static Events_Loop* aLoop = Events_Loop::loop();
   static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-
-  // if the current feature is composite features, all sub-features also must be enabled
-  CompositeFeaturePtr aCurComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theCurrent);
-
+  static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+  static Events_ID aDeleteEvent = aLoop->eventByName(EVENT_OBJECT_DELETED);
 
   bool aPassed = false; // flag that the current object is already passed in cycle
   FeaturePtr anIter = myObjs->lastFeature();
+  bool aWasChanged = false;
   for(; anIter.get(); anIter = myObjs->nextFeature(anIter, true)) {
     // check this before passed become enabled: the current feature is enabled!
     if (anIter == theCurrent) aPassed = true;
 
     bool aDisabledFlag = !aPassed;
-    if (aCurComp.get() && aCurComp->isSub(anIter))
+    if (aMain.get() && aMain->isSub(anIter)) // sub-elements of not-disabled feature are not disabled
       aDisabledFlag = false;
+    if (anIter->getKind() == "Parameter") {// parameters are always out of the history of features, but not parameters
+      if (theCurrent.get() && theCurrent->getKind() != "Parameter")
+        aDisabledFlag = false;
+    }
     if (anIter->setDisabled(aDisabledFlag)) {
       // state of feature is changed => so feature become updated
       static Events_ID anUpdateEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
       ModelAPI_EventCreator::get()->sendUpdated(anIter, anUpdateEvent);
       // flush is in the end of this method
       ModelAPI_EventCreator::get()->sendUpdated(anIter, aRedispEvent /*, false*/);
+      aWasChanged = true;
+    }
+    // update for everyone the concealment flag immideately: on edit feature in the midle of history
+    if (aWasChanged) {
+      const std::list<std::shared_ptr<ModelAPI_Result> >& aResList = anIter->results();
+      std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResList.begin();
+      for(; aRes != aResList.end(); aRes++) {
+        if ((*aRes).get() && (*aRes)->data()->isValid() && !(*aRes)->isDisabled())
+          std::dynamic_pointer_cast<Model_Data>((*aRes)->data())->updateConcealmentFlag();
+      }
+
     }
   }
+  // unblock  the flush signals and up them after this
+  aLoop->activateFlushes(isActive);
+
+  aLoop->flush(aCreateEvent);
   aLoop->flush(aRedispEvent);
+  aLoop->flush(aDeleteEvent);
+}
+
+void Model_Document::setCurrentFeatureUp()
+{
+  // on remove just go up for minimum step: highlight external objects in sketch causes 
+  // problems if it is true: here and in "setCurrentFeature"
+  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);
+  }
 }
 
 TDF_Label Model_Document::generalLabel() const
@@ -742,6 +806,14 @@ std::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
   return myObjs->createPart(theFeatureData, theIndex);
 }
 
+std::shared_ptr<ModelAPI_ResultPart> Model_Document::copyPart(
+      const std::shared_ptr<ModelAPI_Result>& theOldPart, 
+      const std::shared_ptr<ModelAPI_ResultPart>& theOrigin, 
+      const int theIndex)
+{
+  return myObjs->copyPart(theOldPart, theOrigin, theIndex);
+}
+
 std::shared_ptr<ModelAPI_ResultGroup> Model_Document::createGroup(
     const std::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
@@ -792,3 +864,120 @@ ResultPtr Model_Document::findByName(const std::string theName)
 {
   return myObjs->findByName(theName);
 }
+
+std::list<std::shared_ptr<ModelAPI_Feature> > Model_Document::allFeatures()
+{
+  return myObjs->allFeatures();
+}
+
+void Model_Document::setActive(const bool theFlag)
+{
+  if (theFlag != myIsActive) {
+    myIsActive = theFlag;
+    // redisplay all the objects of this part
+    static Events_Loop* aLoop = Events_Loop::loop();
+    static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+
+    for(int a = size(ModelAPI_Feature::group()) - 1; a >= 0; a--) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(
+        object(ModelAPI_Feature::group(), a));
+      if (aFeature.get() && aFeature->data()->isValid()) {
+        const std::list<std::shared_ptr<ModelAPI_Result> >& aResList = aFeature->results();
+        std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResList.begin();
+        for(; aRes != aResList.end(); aRes++) {
+          ModelAPI_EventCreator::get()->sendUpdated(*aRes, aRedispEvent);
+        }
+      }
+    }
+  }
+}
+
+bool Model_Document::isActive() const
+{
+  return myIsActive;
+}
+
+int Model_Document::transactionID()
+{
+  Handle(TDataStd_Integer) anIndex;
+  if (!generalLabel().FindChild(TAG_CURRENT_TRANSACTION).
+      FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
+    anIndex = TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), 1);
+  }
+  return anIndex->Get();
+}
+
+void Model_Document::incrementTransactionID()
+{
+  int aNewVal = transactionID() + 1;
+  TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal);
+}
+void Model_Document::decrementTransactionID()
+{
+  int aNewVal = transactionID() - 1;
+  TDataStd_Integer::Set(generalLabel().FindChild(TAG_CURRENT_TRANSACTION), aNewVal);
+}
+
+bool Model_Document::isOpened()
+{
+  return myObjs && !myDoc.IsNull();
+}
+
+int Model_Document::numInternalFeatures()
+{
+  return myObjs->numInternalFeatures();
+}
+
+std::shared_ptr<ModelAPI_Feature> Model_Document::internalFeature(const int theIndex)
+{
+  return myObjs->internalFeature(theIndex);
+}
+
+// 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
+  Model_SelectionInPartFeature() : ModelAPI_Feature() {}
+
+  /// Returns the unique kind of a feature
+  virtual const std::string& getKind() {
+    static std::string MY_KIND("InternalSelectionInPartFeature");
+    return MY_KIND;
+  }
+  /// Request for initialization of data model of the object: adding all attributes
+  virtual void initAttributes() {
+    data()->addAttribute("selection", ModelAPI_AttributeSelectionList::typeId());
+  }
+  /// Nothing to do in the execution function
+  virtual void execute() {}
+
+};
+
+//! Returns the feature that is used for calculation of selection externally from the document
+AttributeSelectionListPtr Model_Document::selectionInPartFeature()
+{
+  // return already created, otherwise create
+  if (!mySelectionFeature.get() || !mySelectionFeature->data()->isValid()) {
+    // create a new one
+    mySelectionFeature = FeaturePtr(new Model_SelectionInPartFeature);
+  
+    TDF_Label aFeatureLab = generalLabel().FindChild(TAG_SELECTION_FEATURE);
+    std::shared_ptr<Model_Data> aData(new Model_Data);
+    aData->setLabel(aFeatureLab.FindChild(1));
+    aData->setObject(mySelectionFeature);
+    mySelectionFeature->setDoc(myObjs->owner());
+    mySelectionFeature->setData(aData);
+    std::string aName = id() + "_Part";
+    mySelectionFeature->data()->setName(aName);
+    mySelectionFeature->setDoc(myObjs->owner());
+    mySelectionFeature->initAttributes();
+  }
+  return mySelectionFeature->selectionList("selection");
+}
+
+FeaturePtr Model_Document::lastFeature()
+{
+  if (myObjs)
+    return myObjs->lastFeature();
+  return FeaturePtr();
+}