Salome HOME
Issue #1540: Added attribute for array of double.
[modules/shaper.git] / src / Model / Model_Objects.cpp
index 03e7bdee9ab4768a2cdeed9bd77e400ad7fe4ad5..0519e3b1231b61074a6b4cb257b9f6021ac8714d 100644 (file)
@@ -20,7 +20,7 @@
 #include <ModelAPI_Tools.h>
 
 #include <Events_Loop.h>
-#include <Events_Error.h>
+#include <Events_InfoMessage.h>
 
 #include <TDataStd_Integer.hxx>
 #include <TDataStd_Comment.hxx>
@@ -54,7 +54,7 @@ void Model_Objects::setOwner(DocumentPtr theDoc)
   myDoc = theDoc;
   // update all fields and recreate features and result objects if needed
   TDF_LabelList aNoUpdated;
-  synchronizeFeatures(aNoUpdated, true, true);
+  synchronizeFeatures(aNoUpdated, true, true, true);
   myHistory.clear();
 }
 
@@ -139,13 +139,19 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT
     myFeatures.Bind(aFeatureLab, theFeature);
     // must be before the event sending: for OB the feature is already added
     updateHistory(ModelAPI_Feature::group());
+    // do not change the order:
+    // initData()
+    // sendUpdated()
+    // during python script with fillet constraint feature data should be
+    // initialized before using it in GUI
+
+    // must be after binding to the map because of "Box" macro feature that
+    // creates other features in "initData"
+    initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
     // event: feature is added, mist be before "initData" to update OB correctly on Duplicate:
     // first new part, then the content
     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
     ModelAPI_EventCreator::get()->sendUpdated(theFeature, anEvent);
-    // must be after binding to the map because of "Box" macro feature that 
-    // creates other features in "initData"
-    initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS);
   } else { // make feature has not-null data anyway
     theFeature->setData(Model_Data::invalidData());
     theFeature->setDoc(myDoc);
@@ -189,8 +195,10 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
 {
   // check the feature: it must have no depended objects on it
   // the dependencies can be in the feature results
-  std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
-  for (; aResIter != theFeature->results().cend(); aResIter++) {
+  std::list<ResultPtr> aResults;
+  ModelAPI_Tools::allResults(theFeature, aResults);
+  std::list<ResultPtr>::const_iterator aResIter = aResults.cbegin();
+  for (; aResIter != aResults.cend(); aResIter++) {
     ResultPtr aResult = (*aResIter);
     std::shared_ptr<Model_Data> aData = 
         std::dynamic_pointer_cast<Model_Data>(aResult->data());
@@ -218,8 +226,8 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature,
   }
 
   if (!theRefs.empty() && isSendError) {
-    Events_Error::send(
-      "Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
+    Events_InfoMessage("Model_Objects", 
+      "Feature '%1' is used and can not be deleted").arg(theFeature->data()->name()).send();
   }
 }
 
@@ -234,7 +242,7 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
     for(; aRefIter != aRefs.end(); aRefIter++) {
       std::shared_ptr<ModelAPI_CompositeFeature> aComposite = 
         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aRefIter);
-      if (aComposite.get()) {
+      if (aComposite.get() && aComposite->isSub(theFeature)) {
         aComposite->removeFeature(theFeature);
       }
     }
@@ -257,8 +265,6 @@ void Model_Objects::removeFeature(FeaturePtr theFeature)
     RemoveFromRefArray(featuresLabel(), aFeatureLabel);
     // event: feature is deleted
     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
-    // the redisplay signal should be flushed in order to erase the feature presentation in the viewer
-    Events_Loop::loop()->flush(EVENT_DISP);
     updateHistory(ModelAPI_Feature::group());
   }
 }
@@ -298,10 +304,10 @@ void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   if (!aPassedMovedFrom || !aPassedMovedTo) {// not found: unknown situation
     if (!aPassedMovedFrom) {
       static std::string aMovedFromError("The moved feature is not found");
-      Events_Error::send(aMovedFromError);
+      Events_InfoMessage("Model_Objects", aMovedFromError).send();
     } else {
       static std::string aMovedToError("The 'after' feature for movement is not found");
-      Events_Error::send(aMovedToError);
+      Events_InfoMessage("Model_Objects", aMovedToError).send();
     }
     return;
   }
@@ -310,10 +316,9 @@ void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis)
   // update the feature and the history
   clearHistory(theMoved);
   // make sure all (selection) attributes of moved feature will be updated
-  theMoved->data()->setUpdateID(0);
   static Events_ID EVENT_UPD = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED);
   ModelAPI_EventCreator::get()->sendUpdated(theMoved, EVENT_UPD);
-  ModelAPI_EventCreator::get()->sendReordered(theMoved->document(), theMoved->groupName());
+  ModelAPI_EventCreator::get()->sendReordered(theMoved);
 }
 
 void Model_Objects::clearHistory(ObjectPtr theObj)
@@ -349,12 +354,14 @@ void Model_Objects::createHistory(const std::string& theGroupID)
         FeaturePtr aFeature = feature(aRefs->Value(a));
         if (aFeature.get()) {
           // if feature is in sub-component, remove it from history: it is in sub-tree of sub-component
-          if (!ModelAPI_Tools::compositeOwner(aFeature).get()) {
-            if (isFeature) { // here may be also disabled features
-              if (aFeature->isInHistory()) {
-                aResult.push_back(aFeature);
-              }
-            } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
+          bool isSub = ModelAPI_Tools::compositeOwner(aFeature).get() != NULL;
+          if (isFeature) { // here may be also disabled features
+            if (!isSub && aFeature->isInHistory()) {
+              aResult.push_back(aFeature);
+            }
+          } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature
+            // construction results of sub-features should not be in the tree
+            if (!isSub || theGroupID != ModelAPI_ResultConstruction::group()) {
               // do not use reference to the list here since results can be changed by "isConcealed"
               const std::list<std::shared_ptr<ModelAPI_Result> > aResults = aFeature->results();
               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
@@ -503,7 +510,7 @@ const int Model_Objects::index(std::shared_ptr<ModelAPI_Object> theObject)
 int Model_Objects::size(const std::string& theGroupID)
 {
   createHistory(theGroupID);
-  return myHistory[theGroupID].size();
+  return int(myHistory[theGroupID].size());
 }
 
 void Model_Objects::allResults(const std::string& theGroupID, std::list<ResultPtr>& theResults)
@@ -562,6 +569,7 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature)
         isSameName = (*aRIter)->data()->name() == aName;
       }
     }
+
     if (isSameName) {
       aNumObjects++;
       std::stringstream aNameStream;
@@ -589,8 +597,18 @@ void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTa
   theObj->initAttributes();
 }
 
+std::shared_ptr<ModelAPI_Feature> Model_Objects::featureById(const int theId)
+{
+  if (theId > 0) {
+    TDF_Label aLab = featuresLabel().FindChild(theId, Standard_False);
+    return feature(aLab);
+  }
+  return std::shared_ptr<ModelAPI_Feature>(); // not found
+}
+
 void Model_Objects::synchronizeFeatures(
-  const TDF_LabelList& theUpdated, const bool theUpdateReferences, const bool theFlush)
+  const TDF_LabelList& theUpdated, const bool theUpdateReferences, 
+  const bool theOpen, const bool theFlush)
 {
   Model_Document* anOwner = std::dynamic_pointer_cast<Model_Document>(myDoc).get();
   if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize
@@ -628,7 +646,7 @@ void Model_Objects::synchronizeFeatures(
         TCollection_AsciiString(Handle(TDataStd_Comment)::DownCast(aLabIter.Value())->Get())
         .ToCString(), anOwner);
       if (!aFeature.get()) {  // somethig is wrong, most probably, the opened document has invalid structure
-        Events_Error::send("Invalid type of object in the document");
+        Events_InfoMessage("Model_Objects", "Invalid type of object in the document").send();
         aLabIter.Value()->Label().ForgetAllAttributes();
         continue;
       }
@@ -675,6 +693,7 @@ void Model_Objects::synchronizeFeatures(
         ModelAPI_EventCreator::get()->sendUpdated(aFeature, aRedispEvent);
         updateHistory(aFeature);
         aFeature->erase();
+
         // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
         myFeatures.UnBind(aFIter.Key());
         // reinitialize iterator because unbind may corrupt the previous order in the map
@@ -712,19 +731,21 @@ void Model_Objects::synchronizeFeatures(
     myHistory.clear();
   }
 
-  anOwner->executeFeatures() = false;
+  if (theOpen)
+    anOwner->executeFeatures() = false;
   aLoop->activateFlushes(isActive);
 
   if (theFlush) {
-    aLoop->flush(aCreateEvent);
     aLoop->flush(aDeleteEvent);
+    aLoop->flush(aCreateEvent); // delete should be emitted before create to reacts to aborted feature
     aLoop->flush(anUpdateEvent);
     aLoop->flush(aCreateEvent); // after update of features, there could be results created
     aLoop->flush(aDeleteEvent); // or deleted
     aLoop->flush(aRedispEvent);
     aLoop->flush(aToHideEvent);
   }
-  anOwner->executeFeatures() = true;
+  if (theOpen)
+    anOwner->executeFeatures() = true;
 }
 
 /// synchronises back references for the given object basing on the collected data
@@ -746,8 +767,30 @@ void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& t
     std::set<AttributePtr>::iterator aCurrentIter = aData->refsToMe().begin();
     while(aCurrentIter != aData->refsToMe().end()) {
       if (theNewRefs.find(*aCurrentIter) == theNewRefs.end()) {
-        aData->removeBackReference(*aCurrentIter);
-        aCurrentIter = aData->refsToMe().begin(); // reinitialize iteration after delete
+        // for external references from other documents this system is not working: refs are collected from
+        // different Model_Objects, so before remove check this external object exists and still referenced
+        bool aLeaveIt = false;
+        if ((*aCurrentIter)->owner().get() && (*aCurrentIter)->owner()->document() != myDoc &&
+            (*aCurrentIter)->owner()->data().get() && (*aCurrentIter)->owner()->data()->isValid()) {
+          std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
+          (*aCurrentIter)->owner()->data()->referencesToObjects(aRefs);
+          std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >::iterator
+            aRefIter = aRefs.begin();
+          for(; aRefIter != aRefs.end(); aRefIter++) {
+            if ((*aCurrentIter)->id() == aRefIter->first) {
+              std::list<std::shared_ptr<ModelAPI_Object> >::iterator anOIt;
+              for(anOIt = aRefIter->second.begin(); anOIt != aRefIter->second.end(); anOIt++) {
+                if (*anOIt == theObject) {
+                  aLeaveIt = true;
+                }
+              }
+            }
+          }
+        }
+        if (!aLeaveIt) {
+          aData->removeBackReference(*aCurrentIter);
+          aCurrentIter = aData->refsToMe().begin(); // reinitialize iteration after delete
+        } else aCurrentIter++;
       } else aCurrentIter++;
     }
   }
@@ -793,6 +836,7 @@ void Model_Objects::synchronizeBackRefs()
       synchronizeBackRefsForObject(anEmpty, aFeature);
     } else {
       synchronizeBackRefsForObject(aFound->second, aFeature);
+      allRefs.erase(aFound); // to check that all refs are counted
     }
     // also for results
     std::list<ResultPtr> aResults;
@@ -804,9 +848,25 @@ void Model_Objects::synchronizeBackRefs()
         synchronizeBackRefsForObject(anEmpty, *aRIter);
       } else {
         synchronizeBackRefsForObject(aFound->second, *aRIter);
+        allRefs.erase(aFound); // to check that all refs are counted
       }
     }
   }
+  for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
+    FeaturePtr aFeature = aFeatures.Value();
+    std::list<ResultPtr> aResults;
+    ModelAPI_Tools::allResults(aFeature, aResults);
+    // update the concealment status for disply in isConcealed of ResultBody
+    std::list<ResultPtr>::iterator aRIter = aResults.begin();
+    for(; aRIter != aResults.cend(); aRIter++) {
+      (*aRIter)->isConcealed();
+    }
+  }
+  // the rest all refs means that feature references to the external document feature: process also them
+  std::map<ObjectPtr, std::set<AttributePtr> >::iterator anExtIter = allRefs.begin();
+  for(; anExtIter != allRefs.end(); anExtIter++) {
+    synchronizeBackRefsForObject(anExtIter->second, anExtIter->first);
+  }
 }
 
 TDF_Label Model_Objects::resultLabel(
@@ -997,7 +1057,7 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
   if (!theFeature->data() || !theFeature->data()->isValid() || theFeature->isDisabled())
     return;
   // check that results are presented on all labels
-  int aResSize = theFeature->results().size();
+  int aResSize = int(theFeature->results().size());
   TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father());
   for(; aLabIter.More(); aLabIter.Next()) {
     // here must be GUID of the feature
@@ -1025,8 +1085,8 @@ void Model_Objects::updateResults(FeaturePtr theFeature)
           theFeature->attributeChanged("expression"); // just produce a value
           break;
         } else {
-          Events_Error::send(std::string("Unknown type of result is found in the document:") +
-            TCollection_AsciiString(aGroup->Get()).ToCString());
+          Events_InfoMessage("Model_Objects", "Unknown type of result is found in the document:")
+            .arg(TCollection_AsciiString(aGroup->Get()).ToCString()).send();
         }
       }
       if (aNewBody && !aNewBody->data()->isDeleted()) {