]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Update the management of the updates: use transactions ID to detect correctly depende...
authormpv <mpv@opencascade.com>
Tue, 30 Jun 2015 10:12:54 +0000 (13:12 +0300)
committermpv <mpv@opencascade.com>
Tue, 30 Jun 2015 10:12:54 +0000 (13:12 +0300)
17 files changed:
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/Model/Model_ResultPart.cpp
src/Model/Model_ResultPart.h
src/Model/Model_Session.cpp
src/Model/Model_Session.h
src/Model/Model_Update.cpp
src/Model/Model_Update.h
src/ModelAPI/ModelAPI_Data.h
src/ModelAPI/ModelAPI_Feature.cpp
src/ModelAPI/ModelAPI_Feature.h
src/ModelAPI/ModelAPI_ResultPart.h
src/ModelAPI/ModelAPI_Session.h
src/PartSetPlugin/PartSetPlugin_Part.cpp
src/PartSetPlugin/PartSetPlugin_Part.h

index 9228db8ab97e075d1edde3db920058adbee0eec2..4546128eb5625815766cddcb2e1d22f60a302f07 100644 (file)
@@ -21,6 +21,7 @@
 #include <ModelAPI_Result.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_ResultPart.h>
 
 #include <GeomData_Point.h>
 #include <GeomData_Point2D.h>
@@ -30,6 +31,7 @@
 
 #include <TDataStd_Name.hxx>
 #include <TDataStd_AsciiString.hxx>
+#include <TDataStd_IntegerArray.hxx>
 #include <TDF_AttributeIterator.hxx>
 #include <TDF_ChildIterator.hxx>
 #include <TDF_RelocationTable.hxx>
@@ -38,7 +40,7 @@
 
 // myLab contains:
 // TDataStd_Name - name of the object
-// TDataStd_Integer - state of the object execution
+// TDataStd_IntegerArray - state of the object execution, transaction ID of update
 // TDataStd_BooleanArray - array of flags of this data:
 //                             0 - is in history or not
 static const int kFlagInHistory = 0;
@@ -240,19 +242,44 @@ void Model_Data::erase()
     myLab.ForgetAllAttributes();
 }
 
+// indexes in the state array
+enum StatesIndexes {
+  STATE_INDEX_STATE = 1, // the state type itself
+  STATE_INDEX_TRANSACTION = 2, // transaction ID
+};
+
+/// Returns the label array, initialises it by default values if not exists
+static Handle(TDataStd_IntegerArray) stateArray(TDF_Label& theLab)
+{
+  Handle(TDataStd_IntegerArray) aStateArray;
+  if (!theLab.FindAttribute(TDataStd_IntegerArray::GetID(), aStateArray)) {
+    aStateArray = TDataStd_IntegerArray::Set(theLab, 1, 2);
+    aStateArray->SetValue(STATE_INDEX_STATE, ModelAPI_StateMustBeUpdated); // default state
+    aStateArray->SetValue(STATE_INDEX_TRANSACTION, 0); // default transaction ID (not existing)
+  }
+  return aStateArray;
+}
+
 void Model_Data::execState(const ModelAPI_ExecState theState)
 {
-  if (theState != ModelAPI_StateNothing)
-    TDataStd_Integer::Set(myLab, (int)theState);
+  if (theState != ModelAPI_StateNothing) {
+    stateArray(myLab)->SetValue(STATE_INDEX_STATE, (int)theState);
+  }
 }
 
 ModelAPI_ExecState Model_Data::execState()
 {
-  Handle(TDataStd_Integer) aStateAttr;
-  if (myLab.FindAttribute(TDataStd_Integer::GetID(), aStateAttr)) {
-    return ModelAPI_ExecState(aStateAttr->Get());
-  }
-  return ModelAPI_StateMustBeUpdated; // default value
+  return ModelAPI_ExecState(stateArray(myLab)->Value(STATE_INDEX_STATE));
+}
+
+int Model_Data::updateID()
+{
+  return stateArray(myLab)->Value(STATE_INDEX_TRANSACTION);
+}
+
+void Model_Data::setUpdateID(const int theID)
+{
+  stateArray(myLab)->SetValue(STATE_INDEX_TRANSACTION, theID);
 }
 
 void Model_Data::setError(const std::string& theError, bool theSend)
@@ -400,10 +427,16 @@ void Model_Data::setIsInHistory(const bool theFlag)
 
 bool Model_Data::isDisplayed()
 {
-  return myObject.get() && myObject->document().get() && 
-    (myObject->document()->isActive() || 
-     myObject->document() == ModelAPI_Session::get()->moduleDocument()) && // root is accessible allways
-    myFlags->Value(kFlagDisplayed) == Standard_True;
+  if (!myObject.get() || !myObject->document().get() || // object is in valid
+      myFlags->Value(kFlagDisplayed) != Standard_True) // or it was not displayed before
+    return false;
+  if (myObject->document()->isActive()) // for active documents it must be ok anyway
+    return true;
+  // any object from the root document except part result may be displayed
+  if (myObject->document() == ModelAPI_Session::get()->moduleDocument() &&
+      myObject->groupName() != ModelAPI_ResultPart::group())
+    return true;
+  return false;
 }
 
 void Model_Data::setDisplayed(const bool theDisplay)
index 38733fb7209708d3b9a2147d3c00dd46821df3ac..fba3cd500f1d3b3a0ac6c3f8d8026783a7cf4bfb 100644 (file)
@@ -192,6 +192,13 @@ class Model_Data : public ModelAPI_Data
   /// Returns the invalid data pointer: static method
   static std::shared_ptr<ModelAPI_Data> invalidData();
 
+  /// Identifier of the transaction when object (feature or result) was updated last time.
+  MODEL_EXPORT virtual int updateID();
+
+  /// Identifier of the transaction when object (feature or result) was updated last time.
+  /// This method is called by the updater.
+  MODEL_EXPORT virtual void setUpdateID(const int theID);
+
 protected:
   /// Returns true if "is in history" custom behaviors is defined for the feature
   MODEL_EXPORT virtual bool isInHistory();
index 75cfb1de8b761910f7b3875a35add957da0a6834..a18375f865debf61efa7489cb36dcda87f6a68e4 100644 (file)
@@ -46,6 +46,7 @@ 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
 
 Model_Document::Model_Document(const std::string theID, const std::string theKind)
     : myID(theID), myKind(theKind), myIsActive(false),
@@ -292,6 +293,7 @@ void Model_Document::startOperation()
     myDoc->NewCommand();
   }
   // starts a new operation
+  incrementTransactionID();
   myTransactions.push_back(Transaction());
   if (!myNestedNum.empty())
     (*myNestedNum.rbegin())++;
@@ -862,3 +864,24 @@ 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);
+}
index bc414a15672e9d41f7cf7c7c3c4d4916bd8d829b..1aaca02ac372e4563dd4ad1706f6c611e72f239e 100644 (file)
@@ -172,6 +172,13 @@ class Model_Document : public ModelAPI_Document
   ///! history. Not very fast method, for calling once, not in big cycles.
   MODEL_EXPORT virtual std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures();
 
+  /// Returns the global identifier of the current transaction (needed for the update algo)
+  MODEL_EXPORT virtual int transactionID();
+  /// Increases the transaction ID
+  MODEL_EXPORT virtual void incrementTransactionID();
+  /// Decreases the transaction ID
+  MODEL_EXPORT virtual void decrementTransactionID();
+
  protected:
   //! Returns (creates if needed) the general label
   TDF_Label generalLabel() const;
index e49604794c6e2e4149106645dc762c744b582832..5216e6107e6ad8639f2d9ac374ff60407d0e1211 100644 (file)
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_ResultBody.h>
+#include <Model_Document.h>
 
+#include <TNaming_Tool.hxx>
+#include <TNaming_NamedShape.hxx>
+#include <TNaming_Iterator.hxx>
+#include <TDataStd_Name.hxx>
 #include <TopoDS_Compound.hxx>
 #include <BRep_Builder.hxx>
 
@@ -122,12 +127,6 @@ std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shape()
   return aResult;
 }
 
-#include <Model_Document.h>
-#include <TNaming_Tool.hxx>
-#include <TNaming_NamedShape.hxx>
-#include <TNaming_Iterator.hxx>
-#include <TDataStd_Name.hxx>
-
 std::string Model_ResultPart::nameInPart(const std::shared_ptr<GeomAPI_Shape>& theShape)
 {
   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
@@ -176,3 +175,8 @@ void Model_ResultPart::colorConfigInfo(std::string& theSection, std::string& the
   theName = "result_part_color";
   theDefault = DEFAULT_COLOR();
 }
+
+void Model_ResultPart::updateShape()
+{
+  myShape.Nullify();
+}
index fe00a84bd0654dbf6b2237b594911593be9a75cc..11f813388a82a59c3ff375be1a80dc105b936888 100644 (file)
@@ -41,6 +41,8 @@ class Model_ResultPart : public ModelAPI_ResultPart
   MODEL_EXPORT virtual std::string nameInPart(const std::shared_ptr<GeomAPI_Shape>& theShape);
   /// Returns the shape by the name in the part
   MODEL_EXPORT virtual std::shared_ptr<GeomAPI_Shape> shapeInPart(const std::string& theName);
+  /// Updates the shape-result of the part (called on Part feature execution)
+  MODEL_EXPORT virtual void updateShape();
 
   /// Returns the parameters of color definition in the resources config manager
   MODEL_EXPORT virtual void colorConfigInfo(std::string& theSection, std::string& theName,
index 9d76861f6411516a1cfae49ef2f6151b2937d1dc..daae187f0cb829159cbe0149a182356ff4e1f85e 100644 (file)
@@ -425,3 +425,8 @@ ModelAPI_ValidatorsFactory* Model_Session::validators()
   static Model_ValidatorsFactory* aFactory = new Model_ValidatorsFactory;
   return aFactory;
 }
+
+int Model_Session::transactionID()
+{
+  return ROOT_DOC->transactionID();
+}
index 2584a2e201aa35a14012df0e8c79c6a08ea29d9c..62d69e5bef3147cde64bcc98e66bc160f08b5f97 100644 (file)
@@ -117,6 +117,9 @@ class Model_Session : public ModelAPI_Session, public Events_Listener
   /// Is called only once, on startup of the application
   Model_Session();
 
+  /// Returns the global identifier of the current transaction (needed for the update algo)
+  MODEL_EXPORT virtual int transactionID();
+
  protected:
   /// Loads (if not done yet) the information about the features and plugins
   void LoadPluginsInfo();
index d3cc6c9c166782b76a9148ccd46bfdf7cbab6740..5aa0e18f78011bec544c9dc047800a4abb813457 100644 (file)
@@ -99,13 +99,9 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
       }
       // created objects are always must be up to date (python box feature)
       // and updated not in internal uptation chain
-      if (theMessage->eventID() == kCreatedEvent) {
-        myJustCreated.insert(*anObjIter);
-      } else if (myJustCreated.find(*anObjIter) == myJustCreated.end()) { // moved and updated
-        myJustUpdated.insert(*anObjIter);
-      }
+      myJustUpdated.insert(*anObjIter);
     }
-     // this event is for solver update, not here, do not react immideately
+    // this event is for solver update, not here, do not react immideately
     if (!isOnlyResults && !(theMessage->eventID() == kMovedEvent))
       processOperation(false);
   } else if (theMessage->eventID() == kOpStartEvent) {
@@ -117,16 +113,12 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
   }
   if (isOperationChanged) {
     // remove all macros before clearing all created and execute all not-previewed
-    std::set<ObjectPtr>::iterator aCreatedIter = myJustCreated.begin();
     std::set<ObjectPtr>::iterator anUpdatedIter = myJustUpdated.begin();
-    for(; aCreatedIter != myJustCreated.end() || anUpdatedIter != myJustUpdated.end();
-      aCreatedIter == myJustCreated.end() ? anUpdatedIter++ : aCreatedIter++) {
-      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*
-        (aCreatedIter == myJustCreated.end() ? anUpdatedIter : aCreatedIter));
+    for(; anUpdatedIter != myJustUpdated.end(); anUpdatedIter++) {
+      FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anUpdatedIter);
       if (aFeature.get()) {
         // execute not-previewed feature on "apply"
-        if (!aFeature->isPreviewNeeded() && (myJustCreated.find(aFeature) != myJustCreated.end() ||
-          myJustUpdated.find(aFeature) != myJustUpdated.end())) {
+        if (!aFeature->isPreviewNeeded() && myJustUpdated.find(aFeature) != myJustUpdated.end()) {
           static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
           if (aFactory->validate(aFeature)) {
             executeFeature(aFeature);
@@ -138,8 +130,6 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
         }
       }
     }
-    myJustCreated.clear();
-    myJustUpdated.clear();
     myIsParamUpdated = false;
   }
 }
@@ -149,7 +139,7 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
   if (theFinish) {
     // the hardcode (DBC asked): hide the sketch referenced by extrusion on apply
     std::set<std::shared_ptr<ModelAPI_Object> >::iterator aFIter;
-    for(aFIter = myJustCreated.begin(); aFIter != myJustCreated.end(); aFIter++)
+    for(aFIter = myJustUpdated.begin(); aFIter != myJustUpdated.end(); aFIter++)
     {
       FeaturePtr aF = std::dynamic_pointer_cast<ModelAPI_Feature>(*aFIter);
       if (aF && aF->data()->isValid() && aF->getKind() == "Extrusion") {
@@ -176,9 +166,20 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
       myIsAutomatic = true;
     }
 
-    updateInDoc(ModelAPI_Session::get()->moduleDocument());
+    // iterate all features in the root document to update each
+    DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
+    Model_Objects* anObjs = std::dynamic_pointer_cast<Model_Document>(aRootDoc)->objects();
+    if (!anObjs) return;
+    FeaturePtr aFeatureIter = anObjs->firstFeature();
+    std::set<FeaturePtr> aProcessedFeatures; // to avoid processing twice
+    for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) {
+      updateFeature(aFeatureIter, aProcessedFeatures);
+    }
 
     if (isAutomaticChanged) myIsAutomatic = false;
+    // make just updated clear after each processing: it is not needed anymore, update causes
+    // execute immideately
+    //myJustUpdated.clear(); // just before myIsExecuted = false because after myJustUpdated will be processed again
     myIsExecuted = false;
 
     // flush to update display
@@ -188,44 +189,64 @@ void Model_Update::processOperation(const bool theTotalUpdate, const bool theFin
   }
 }
 
-void Model_Update::updateInDoc(std::shared_ptr<ModelAPI_Document> theDoc)
+void Model_Update::updateFeature(FeaturePtr theFeature, std::set<FeaturePtr>& theProcessed)
 {
-  std::set<FeaturePtr> alreadyProcessed; // features that are processed before others
-  // all features one by one
-  Model_Objects* anObjs = std::dynamic_pointer_cast<Model_Document>(theDoc)->objects();
-  if (!anObjs) return;
-  FeaturePtr aFeatureIter = anObjs->firstFeature();
-  for (; aFeatureIter.get(); aFeatureIter = anObjs->nextFeature(aFeatureIter)) {
-    if (!aFeatureIter->data()->isValid()) // this may be on close of the document
-      continue;
-    if (aFeatureIter && alreadyProcessed.find(aFeatureIter) == alreadyProcessed.end()) {
-      // update selection and parameters attributes first, before sub-features analysis (sketch plane)
-      updateArguments(aFeatureIter);
-      // composite feature must be executed after sub-features execution
-      CompositeFeaturePtr aComposite = 
-        std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureIter);
-      if (aComposite) {
-        // number of subs can be changed in execution: like fillet
-        for(int a = 0; a < aComposite->numberOfSubs(); a++) {
-          FeaturePtr aSub = aComposite->subFeature(a);
-          updateArguments(aSub);
-          updateFeature(aSub);
-          alreadyProcessed.insert(aSub);
-        }
-      }
+  // check all features this feature depended on (recursive call of updateFeature)
+  static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
 
-      updateFeature(aFeatureIter);
-      // update the document results recursively
-      const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeatureIter->results();
-      std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
-      for (; aRIter != aResults.cend(); aRIter++) {
-        ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRIter);
-        if (aPart.get()) {
-          if (!aPart->isDisabled() && aPart->partDoc().get()) {
-            updateInDoc(aPart->partDoc());
-          }
+  if (theProcessed.find(theFeature) != theProcessed.end())
+    return;
+  theProcessed.insert(theFeature);
+  if (theFeature->isDisabled())
+    return;
+
+  CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+  // If automatice update is not needed and feature attributes were not updated right now,
+  // do not execute it and do not update arguments.
+  if (!myIsAutomatic && myJustUpdated.find(theFeature) == myJustUpdated.end() && !aCompos.get()) {
+    // execute will be performed later, but some features may have not-result 
+    // presentations, so call update for them (like coincidence in the sketcher)
+    static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+    ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP);
+    return;
+  }
+
+  // Update selection and parameters attributes first, before sub-features analysis (sketch plane).
+  updateArguments(theFeature);
+
+  // composite feature must be executed after sub-features execution
+  if (aCompos) {
+    // number of subs can be changed in execution: like fillet
+    for(int a = 0; a < aCompos->numberOfSubs(); a++) {
+      FeaturePtr aSub = aCompos->subFeature(a);
+      updateFeature(aSub, theProcessed);
+    }
+  }
+  // this checking must be after the composite feature sub-elements processing:
+  // composite feature status may depend on it's subelements
+  if (theFeature->data()->execState() == ModelAPI_StateInvalidArgument)
+    return;
+
+  bool aJustUpdated = myJustUpdated.find(theFeature) != myJustUpdated.end();
+
+  if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
+    aJustUpdated = true;
+
+  // execute feature if it must be updated
+  if (theFeature->isPreviewNeeded()) {
+    if ((myIsAutomatic || aJustUpdated) &&
+      std::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures()) {
+        ModelAPI_ExecState aState = theFeature->data()->execState();
+        if (aFactory->validate(theFeature)) {
+          executeFeature(theFeature);
+        } else {
+          theFeature->eraseResults();
+          redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
         }
-      }
+    }
+  } else { // preview is not needed => make state Done
+    if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
+      theFeature->data()->execState(ModelAPI_StateDone);
     }
   }
 }
@@ -239,7 +260,10 @@ void Model_Update::redisplayWithResults(FeaturePtr theFeature, const ModelAPI_Ex
   for (; aRIter != aResults.cend(); aRIter++) {
     std::shared_ptr<ModelAPI_Result> aRes = *aRIter;
     aRes->data()->execState(theState);
-    myJustUpdated.insert(aRes);
+    if (theFeature->data()->updateID() > aRes->data()->updateID()) {
+      myJustUpdated.insert(aRes);
+      aRes->data()->setUpdateID(theFeature->data()->updateID());
+    }
     ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
   }
   // to redisplay "presentable" feature (for ex. distance constraint)
@@ -267,7 +291,6 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
 
   static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
 
-  bool aJustUpdated = false;
   ModelAPI_ExecState aState = theFeature->data()->execState();
   if (aState == ModelAPI_StateInvalidArgument) // a chance to be corrected
     aState = ModelAPI_StateMustBeUpdated;
@@ -301,8 +324,8 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
           ModelAPI_AttributeEvalMessage::send(aPointAttribute, this);
         }
         if ((!aPointAttribute->textX().empty() && aPointAttribute->expressionInvalid(0)) ||
-            (!aPointAttribute->textY().empty() && aPointAttribute->expressionInvalid(1)) ||
-            (!aPointAttribute->textZ().empty() && aPointAttribute->expressionInvalid(2)))
+          (!aPointAttribute->textY().empty() && aPointAttribute->expressionInvalid(1)) ||
+          (!aPointAttribute->textZ().empty() && aPointAttribute->expressionInvalid(2)))
           aState = ModelAPI_StateInvalidArgument;
       }
     }
@@ -320,44 +343,46 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
           ModelAPI_AttributeEvalMessage::send(aPoint2DAttribute, this);
         }
         if ((!aPoint2DAttribute->textX().empty() && aPoint2DAttribute->expressionInvalid(0)) ||
-            (!aPoint2DAttribute->textY().empty() && aPoint2DAttribute->expressionInvalid(1)))
+          (!aPoint2DAttribute->textY().empty() && aPoint2DAttribute->expressionInvalid(1)))
           aState = ModelAPI_StateInvalidArgument;
       }
     }
   }
 
   //if (aState == ModelAPI_StateDone) {// all referenced objects are ready to be used
-    //std::cout<<"Execute feature "<<theFeature->getKind()<<std::endl;
-    // before execution update the selection attributes if any
-    list<AttributePtr> aRefs = 
-      theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
-    list<AttributePtr>::iterator aRefsIter = aRefs.begin();
-    for (; aRefsIter != aRefs.end(); aRefsIter++) {
-      std::shared_ptr<ModelAPI_AttributeSelection> aSel =
-        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
-      ObjectPtr aContext = aSel->context();
-      // update argument onlt if the referenced object is changed
-      if (aContext.get() && isUpdated(aContext) && !aContext->isDisabled()) {
+  //std::cout<<"Execute feature "<<theFeature->getKind()<<std::endl;
+  // before execution update the selection attributes if any
+  list<AttributePtr> aRefs = 
+    theFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
+  list<AttributePtr>::iterator aRefsIter = aRefs.begin();
+  for (; aRefsIter != aRefs.end(); aRefsIter++) {
+    std::shared_ptr<ModelAPI_AttributeSelection> aSel =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
+    ObjectPtr aContext = aSel->context();
+    // update argument onlt if the referenced object is changed
+    if (aContext.get() && !aContext->isDisabled() && 
+      aContext->data()->updateID() > theFeature->data()->updateID()) {
         if (aState == ModelAPI_StateDone)
           aState = ModelAPI_StateMustBeUpdated;
         if (!aSel->update()) { // this must be done on execution since it may be long operation
           if (!aFactory->isNotObligatory(theFeature->getKind(), theFeature->data()->id(aSel)) &&
-              aFactory->isCase(theFeature, theFeature->data()->id(aSel)))
+            aFactory->isCase(theFeature, theFeature->data()->id(aSel)))
             aState = ModelAPI_StateInvalidArgument;
         }
-      }
     }
-    aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
-    for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
-      std::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
-        std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
-      for(int a = aSel->size() - 1; a >= 0; a--) {
-        std::shared_ptr<ModelAPI_AttributeSelection> aSelAttr =
-          std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aSel->value(a));
-        if (aSelAttr) {
-          ObjectPtr aContext = aSelAttr->context();
-          // update argument onlt if the referenced object is changed
-          if (aContext.get() && isUpdated(aContext) && !aContext->isDisabled()) {
+  }
+  aRefs = theFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
+  for (aRefsIter = aRefs.begin(); aRefsIter != aRefs.end(); aRefsIter++) {
+    std::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
+    for(int a = aSel->size() - 1; a >= 0; a--) {
+      std::shared_ptr<ModelAPI_AttributeSelection> aSelAttr =
+        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aSel->value(a));
+      if (aSelAttr) {
+        ObjectPtr aContext = aSelAttr->context();
+        // update argument onlt if the referenced object is changed
+        if (aContext.get() && !aContext->isDisabled() &&
+          aContext->data()->updateID() > theFeature->data()->updateID()) {
             if (aState == ModelAPI_StateDone)
               aState = ModelAPI_StateMustBeUpdated;
             if (!aSelAttr->update()) {
@@ -366,111 +391,34 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
                 aFactory->isCase(theFeature, theFeature->data()->id(aSel)))
                 aState = ModelAPI_StateInvalidArgument;
             }
-          }
-        }
-      }
-    }
-  //}
-  if (aJustUpdated && myJustCreated.find(theFeature) == myJustCreated.end())
-  myJustUpdated.insert(theFeature);
-  if (aState != ModelAPI_StateDone)
-    theFeature->data()->execState(aState);
-}
-
-void Model_Update::updateFeature(FeaturePtr theFeature)
-{
-  // check all features this feature depended on (recursive call of updateFeature)
-  static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
-
-  if (theFeature->data()->execState() == ModelAPI_StateInvalidArgument)
-    return;
-  bool aJustUpdated = false;
-
-  if (theFeature) {
-    if (myIsAutomatic && theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
-      aJustUpdated = true;
-
-    ModelAPI_ExecState aState = ModelAPI_StateDone;
-
-    // check all references: if referenced objects are updated, this object also must be updated
-    // also check state of referenced objects: if they are not ready, inherit corresponding state
-    std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
-    std::shared_ptr<Model_Data> aData = 
-      std::dynamic_pointer_cast<Model_Data>(theFeature->data());
-    aData->referencesToObjects(aRefs);
-    std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRef = aRefs.begin();
-    for(; aRef != aRefs.end(); aRef++) {
-      std::list<ObjectPtr>::iterator aRefObj = aRef->second.begin();
-      for(; aRefObj != aRef->second.end(); aRefObj++) {
-        // if reference is null, it may mean that this reference is to other document
-        // the does not supported by RefList: peremeters may be recomputed
-        if (!aRefObj->get() && theFeature->firstResult().get() && 
-            theFeature->firstResult()->groupName() == ModelAPI_ResultParameter::group()) {
-          aJustUpdated = true;
-        } else if (myJustCreated.find(*aRefObj) != myJustCreated.end() ||
-            myJustUpdated.find(*aRefObj) != myJustUpdated.end()) { 
-          aJustUpdated = true;
         }
-        aState = stateByReference(*aRefObj, aState);
       }
     }
-
-    // some arguments were changed, so, this feature must be updated
-    if (myJustCreated.find(theFeature) != myJustCreated.end()) {
-      aJustUpdated = true;
-    } else {
-      if (aJustUpdated) {
-        if (myJustUpdated.find(theFeature) == myJustUpdated.end())
-          myJustUpdated.insert(theFeature);
-      } else {
-        aJustUpdated = myJustUpdated.find(theFeature) != myJustUpdated.end();
-      }
-    }
-    //std::cout<<"Update feature "<<theFeature->getKind()<<" must be updated = "<<aMustbeUpdated<<std::endl;
-    // execute feature if it must be updated
-    if (aJustUpdated) {
-      if (theFeature->isDisabled()) {  // do not execute the disabled feature
-        // the disabled features must be updated after enabling anyway if their arguments were changed
-        if (theFeature->data()->execState() == ModelAPI_StateDone &&
-          aState == ModelAPI_StateMustBeUpdated)
-          theFeature->data()->execState(ModelAPI_StateMustBeUpdated);
-      } else {
-        if (theFeature->isPreviewNeeded()) {
-          if (std::dynamic_pointer_cast<Model_Document>(theFeature->document())->executeFeatures() ||
-              !theFeature->isPersistentResult()) {
-            if (aFactory->validate(theFeature)) {
-              FeaturePtr aCurrent = theFeature->document()->currentFeature(false);
-              if (myIsAutomatic || !theFeature->isPersistentResult() /* execute quick, not persistent results */
-                  || (isUpdated(theFeature) && 
-                       (theFeature == aCurrent || 
-                        (aCurrent.get() && aCurrent->isMacro())))) // currently edited
-              {
-                if (aState == ModelAPI_StateDone || aState == ModelAPI_StateMustBeUpdated) {
-                  executeFeature(theFeature);
-                }
-              } else { // must be updatet, but not updated yet
-                theFeature->data()->execState(ModelAPI_StateMustBeUpdated);
-                const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
-                std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
-                for (; aRIter != aResults.cend(); aRIter++) {
-                  std::shared_ptr<ModelAPI_Result> aRes = *aRIter;
-                  aRes->data()->execState(ModelAPI_StateMustBeUpdated);
-                }
-              }
-            } else {
-              theFeature->eraseResults();
-              redisplayWithResults(theFeature, ModelAPI_StateInvalidArgument); // result also must be updated
-            }
-          } else { // for automatically updated features (on abort, etc) it is necessary to redisplay anyway
-            redisplayWithResults(theFeature, ModelAPI_StateNothing);
-          }
-        } else { // preview is not needed => make state Done
-          if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
-            theFeature->data()->execState(ModelAPI_StateDone);
-        }
+  }
+  // check all references: if referenced objects are updated, this object also must be updated
+  // also check state of referenced objects: if they are not ready, inherit corresponding state
+  std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefsObj;
+  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theFeature->data());
+  aData->referencesToObjects(aRefsObj);
+  std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRef = aRefsObj.begin();
+  for(; aRef != aRefsObj.end(); aRef++) {
+    std::list<ObjectPtr>::iterator aRefObj = aRef->second.begin();
+    for(; aRefObj != aRef->second.end(); aRefObj++) {
+      // if reference is null, it may mean that this reference is to other document
+      // the does not supported by RefList: parameters may be recomputed
+      if (!aRefObj->get() && theFeature->firstResult().get() && 
+        theFeature->firstResult()->groupName() == ModelAPI_ResultParameter::group()) {
+          aState = ModelAPI_StateMustBeUpdated;
+      } else if (myJustUpdated.find(*aRefObj) != myJustUpdated.end() || 
+        (aRefObj->get() && (*aRefObj)->data()->updateID() > theFeature->data()->updateID())) { 
+        aState = ModelAPI_StateMustBeUpdated;
       }
+      aState = stateByReference(*aRefObj, aState);
     }
   }
+
+  if (aState != ModelAPI_StateDone)
+    theFeature->data()->execState(aState);
 }
 
 void Model_Update::executeFeature(FeaturePtr theFeature)
@@ -480,6 +428,7 @@ void Model_Update::executeFeature(FeaturePtr theFeature)
   theFeature->data()->execState(ModelAPI_StateDone);
   try {
     theFeature->execute();
+    myJustUpdated.erase(theFeature);
     if (theFeature->data()->execState() != ModelAPI_StateDone) {
       aState = ModelAPI_StateExecFailed;
     } else {
@@ -493,11 +442,6 @@ void Model_Update::executeFeature(FeaturePtr theFeature)
   if (aState != ModelAPI_StateDone) {
     theFeature->eraseResults();
   }
+  theFeature->data()->setUpdateID(ModelAPI_Session::get()->transactionID());
   redisplayWithResults(theFeature, aState);
 }
-
-bool Model_Update::isUpdated(const ObjectPtr& theObj)
-{
-  return myJustCreated.find(theObj) != myJustCreated.end() ||
-         myJustUpdated.find(theObj) != myJustUpdated.end();
-}
index c28d30b255ca3cba728e4a94e9713f3700c640fc..56a16cbd2c69fa14616e7521d5e33bfc0df74dae 100644 (file)
@@ -23,9 +23,7 @@ class ModelAPI_Feature;
  */
 class Model_Update : public Events_Listener
 {
-  /// created features during this transaction: must be updated all the time
-  std::set<std::shared_ptr<ModelAPI_Object> > myJustCreated;
-  /// updated features during this transaction: must be updated in the end of transaction
+  /// updated features during this transaction: must be updated immediately
   std::set<std::shared_ptr<ModelAPI_Object> > myJustUpdated;
   /// to know that all next updates are caused by this execution
   bool myIsExecuted;
@@ -42,13 +40,13 @@ class Model_Update : public Events_Listener
   MODEL_EXPORT virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
 protected:
-  /// updates all features in the document and then - in sub-documents
-  void updateInDoc(std::shared_ptr<ModelAPI_Document> theDoc);
   /// Recoursively checks and updates the feature if needed (calls the execute method)
   /// Returns true if feature was updated.
-  void updateFeature(std::shared_ptr<ModelAPI_Feature> theFeature);
+  void updateFeature(std::shared_ptr<ModelAPI_Feature> theFeature,
+    std::set<std::shared_ptr<ModelAPI_Feature> >& theProcessed);
 
   /// Updates the selection and parametrical arguments before the later feature analysis
+  /// Returns true if something really was updated
   void updateArguments(std::shared_ptr<ModelAPI_Feature> theFeature);
 
   /// Sends the redisplay events for feature and results, updates the updated status
@@ -62,9 +60,6 @@ protected:
   /// Performs the feature execution
   /// \returns the status of execution
   void executeFeature(std::shared_ptr<ModelAPI_Feature> theFeature);
-
-  /// returns true if the object was created or updated
-  bool isUpdated(const std::shared_ptr<ModelAPI_Object>& theObj);
 };
 
 #endif
index e57aaec10a62c18ff9df8a474b44927b89ae5d28..0cd4631e60849c3a87bbdc1ce0467707a77c77ce 100644 (file)
@@ -147,6 +147,13 @@ class MODELAPI_EXPORT ModelAPI_Data
   /// Returns the invalid data pointer (to avoid working with NULL shared ptrs in swig)
   virtual std::shared_ptr<ModelAPI_Data> invalidPtr() = 0;
 
+  /// Identifier of the transaction when object (feature or result) was updated last time.
+  virtual int updateID() = 0;
+
+  /// Identifier of the transaction when object (feature or result) was updated last time.
+  /// This method is called by the updater.
+  virtual void setUpdateID(const int theID) = 0;
+
  protected:
   /// Objects are created for features automatically
   ModelAPI_Data();
index 3c78c82d0a254403579b4068b47877724efb30d6..e7f96587c2be002f7acea66a403d83f1bb18efc9 100644 (file)
@@ -17,7 +17,7 @@ const std::list<std::shared_ptr<ModelAPI_Result> >& ModelAPI_Feature::results()
   return myResults;
 }
 
-std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::firstResult()
+std::shared_ptr<ModelAPI_Result> ModelAPI_Feature::firstResult() const
 {
   return myResults.empty() ? std::shared_ptr<ModelAPI_Result>() : *(myResults.begin());
 }
index 8631c3e08b2d53beb32c0ad5fb951e2e5064337a..85ce31df224b59c55cd7a3937733da8e92fe8011 100644 (file)
@@ -72,7 +72,7 @@ class ModelAPI_Feature : public ModelAPI_Object
   /// returns the current results of the feature
   MODELAPI_EXPORT const std::list<std::shared_ptr<ModelAPI_Result> >& results();
   /// returns the first result in the list or NULL reference
-  MODELAPI_EXPORT std::shared_ptr<ModelAPI_Result> firstResult();
+  MODELAPI_EXPORT std::shared_ptr<ModelAPI_Result> firstResult() const;
   /// returns the last result in the list or NULL reference
   MODELAPI_EXPORT std::shared_ptr<ModelAPI_Result> lastResult();
   /// sets the alone result
index fec9342164ed8d5b26c4e0558f10bd6d2e8f900c..74d86953f84129e36779bf386484769ac2ab2d4b 100644 (file)
@@ -58,6 +58,8 @@ class ModelAPI_ResultPart : public ModelAPI_Result
   virtual std::string nameInPart(const std::shared_ptr<GeomAPI_Shape>& theShape) = 0;
   /// Returns the shape by the name in the part
   virtual std::shared_ptr<GeomAPI_Shape> shapeInPart(const std::string& theName) = 0;
+  /// Updates the shape-result of the part (called on Part feature execution)
+  virtual void updateShape() = 0;
 };
 
 //! Pointer on feature object
index 47f6071810e4980069cec0671d47fde61f3e3bf1..33aa5a67d46f83d688ebcd3bd6dc10a4eab0b462 100644 (file)
@@ -108,6 +108,9 @@ class MODELAPI_EXPORT ModelAPI_Session
   {
   }
 
+  /// Returns the global identifier of the current transaction (needed for the update algo)
+  virtual int transactionID() = 0;
+
  protected:
   /// Sets the session interface implementation (once per application launch)
   static void setSession(std::shared_ptr<ModelAPI_Session> theManager);
index fda4e53a14613add4c2c1acf9787f55b0a369bb7..04b6ddd6ef97461c7c2de13f7178078f20c79901 100644 (file)
@@ -39,6 +39,8 @@ void PartSetPlugin_Part::execute()
 
       aResult->activate();
     }
+  } else { // execute is called for result update anyway
+    aResult->updateShape();
   }
 }
 
@@ -47,3 +49,70 @@ const std::string& PartSetPlugin_Part::documentToAdd()
   // part must be added only to the module document
   return ModelAPI_Session::get()->moduleDocument()->kind();
 }
+
+std::shared_ptr<ModelAPI_Feature> PartSetPlugin_Part::addFeature(std::string theID)
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    if (aDoc.get())
+      return aDoc->addFeature(theID);
+  }
+  return FeaturePtr();
+}
+
+int PartSetPlugin_Part::numberOfSubs() const
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    if (aDoc.get())
+      return aDoc->size(ModelAPI_Feature::group());
+  }
+  return 0;
+}
+
+std::shared_ptr<ModelAPI_Feature> PartSetPlugin_Part::subFeature(const int theIndex) const
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    if (aDoc.get()) {
+      return std::dynamic_pointer_cast<ModelAPI_Feature>(
+        aDoc->object(ModelAPI_Feature::group(), theIndex));
+    }
+  }
+  return FeaturePtr();
+}
+
+int PartSetPlugin_Part::subFeatureId(const int theIndex) const
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    if (aDoc.get()) {
+      return aDoc->object(ModelAPI_Feature::group(), theIndex)->data()->featureId();
+    }
+  }
+  return 0; // none
+}
+
+bool PartSetPlugin_Part::isSub(ObjectPtr theObject) const
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    return document() == aDoc;
+  }
+  return false;
+}
+
+void PartSetPlugin_Part::removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature)
+{
+  ResultPartPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(firstResult());
+  if (aResult.get()) {
+    DocumentPtr aDoc = aResult->partDoc();
+    if (aDoc.get())
+      aDoc->removeFeature(theFeature);
+  }
+}
index d679d9ccf62b9586d704309d5b437b0ec3d499ad..a07be67e10853a025c50470d0370e24048174e66 100644 (file)
@@ -8,13 +8,14 @@
 #define PartSetPlugin_Part_H_
 
 #include "PartSetPlugin.h"
-#include <ModelAPI_Feature.h>
+#include <ModelAPI_CompositeFeature.h>
 
 /**\class PartSetPlugin_Part
  * \ingroup Plugins
  * \brief Feature for creation of the new part in PartSet.
+ * All sub-features are sub-elements of composite feature.
  */
-class PartSetPlugin_Part : public ModelAPI_Feature
+class PartSetPlugin_Part : public ModelAPI_CompositeFeature
 {
  public:
   /// Part kind
@@ -46,6 +47,27 @@ class PartSetPlugin_Part : public ModelAPI_Feature
   /// Part must be added only to PartSet
   PARTSETPLUGIN_EXPORT virtual const std::string& documentToAdd();
 
+  // composite feature methods
+
+  /// Adds feature to its document
+  virtual std::shared_ptr<ModelAPI_Feature> addFeature(std::string theID);
+
+  /// Returns the number of sub-features of the document
+  virtual int numberOfSubs() const;
+
+  /// Returns the sub-feature by zero-base index
+  virtual std::shared_ptr<ModelAPI_Feature> subFeature(const int theIndex) const;
+
+  /// Returns the sub-feature unique identifier in this composite feature by zero-base index
+  virtual int subFeatureId(const int theIndex) const;
+
+  /// Returns true if feature or reuslt belong to this composite feature as subs
+  virtual bool isSub(ObjectPtr theObject) const;
+
+  /// This method to inform that sub-feature is removed and must be removed from the internal data
+  /// structures of the owner (the remove from the document will be done outside just after)
+  virtual void removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature);
+
   /// Use plugin manager for features creation
   PartSetPlugin_Part();
 };