Salome HOME
Merge branch 'master' of newgeom:newgeom
[modules/shaper.git] / src / Model / Model_Document.cpp
index d2fcb36eb017c9553fc8e2e014f312ae215eb7e1..59ebd2fb0f1663417cfa9e1b17c945d973215a64 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <TDataStd_Integer.hxx>
 #include <TDataStd_Comment.hxx>
-#include <TDataStd_UAttribute.hxx>
 #include <TDF_ChildIDIterator.hxx>
 #include <TDataStd_ReferenceArray.hxx>
 #include <TDataStd_HLabelArray1.hxx>
@@ -45,15 +44,14 @@ static const int TAG_HISTORY = 3;  // tag of the history sub-tree (python dump)
 static const int TAG_FEATURE_ARGUMENTS = 1;  ///< where the arguments are located
 static const int TAG_FEATURE_RESULTS = 2;  ///< where the results are located
 
-Model_Document::Model_Document(const std::string theID)
-    : myID(theID),
+Model_Document::Model_Document(const std::string theID, const std::string theKind)
+    : myID(theID), myKind(theKind),
       myDoc(new TDocStd_Document("BinOcaf"))  // binary OCAF format
 {
-  myDoc->SetUndoLimit(UNDO_LIMIT);
+  myDoc->SetUndoLimit(UNDO_LIMIT);  
   myTransactionsAfterSave = 0;
   myNestedNum = -1;
   myExecuteFeatures = true;
-  //myDoc->SetNestedTransactionMode();
   // to have something in the document and avoid empty doc open/save problem
   // in transaction for nesting correct working
   myDoc->NewCommand();
@@ -146,6 +144,8 @@ bool Model_Document::load(const char* theFileName)
   }
   if (!isError) {
     myDoc->SetUndoLimit(UNDO_LIMIT);
+    // to avoid the problem that feature is created in the current, not this, document
+    Model_Session::get()->setActiveDocument(anApp->getDocument(myID));
     synchronizeFeatures();
   }
   return !isError;
@@ -255,8 +255,12 @@ bool Model_Document::compactNested()
 
 void Model_Document::finishOperation()
 {
-  // just to be sure that everybody knows that changes were performed
+  // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside
+  std::set<std::string>::iterator aSubIter = mySubs.begin();
+  for (; aSubIter != mySubs.end(); aSubIter++)
+    subDoc(*aSubIter)->finishOperation();
 
+  // just to be sure that everybody knows that changes were performed
   if (!myDoc->HasOpenCommand() && myNestedNum != -1)
     boost::static_pointer_cast<Model_Session>(Model_Session::get())
         ->setCheckTransactions(false);  // for nested transaction commit
@@ -282,10 +286,6 @@ void Model_Document::finishOperation()
     myTransactionsAfterSave++;
   }
 
-  // finish for all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
-    subDoc(*aSubIter)->finishOperation();
 }
 
 void Model_Document::abortOperation()
@@ -399,6 +399,8 @@ FeaturePtr Model_Document::addFeature(std::string theID)
   TDF_Label anEmptyLab;
   FeaturePtr anEmptyFeature;
   FeaturePtr aFeature = ModelAPI_Session::get()->createFeature(theID);
+  if (!aFeature)
+    return aFeature;
   boost::shared_ptr<Model_Document> aDocToAdd = boost::dynamic_pointer_cast<Model_Document>(
       aFeature->documentToAdd());
   if (aFeature) {
@@ -459,15 +461,35 @@ static int RemoveFromRefArray(TDF_Label theArrayLab, TDF_Label theReferenced, co
   return aResult;
 }
 
-void Model_Document::removeFeature(FeaturePtr theFeature)
+void Model_Document::removeFeature(FeaturePtr theFeature, const bool theCheck)
 {
+  if (theCheck) {
+    // check the feature: it must have no depended objects on it
+    std::list<ResultPtr>::const_iterator aResIter = theFeature->results().cbegin();
+    for(; aResIter != theFeature->results().cend(); aResIter++) {
+      if (myConcealedResults.find(*aResIter) != myConcealedResults.end()) {
+        Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
+        return;
+      }
+    }
+    NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator anObjIter(myObjs);
+    for(; anObjIter.More(); anObjIter.Next()) {
+      DataPtr aData = anObjIter.Value()->data();
+      if (aData->referencesTo(theFeature)) {
+        Events_Error::send("Feature '" + theFeature->data()->name() + "' is used and can not be deleted");
+        return;
+      }
+    }
+  }
+
   boost::shared_ptr<Model_Data> aData = boost::static_pointer_cast<Model_Data>(theFeature->data());
   TDF_Label aFeatureLabel = aData->label().Father();
   if (myObjs.IsBound(aFeatureLabel))
     myObjs.UnBind(aFeatureLabel);
   else
     return;  // not found feature => do not remove
-
+  // erase fields
+  theFeature->erase();
   // erase all attributes under the label of feature
   aFeatureLabel.ForgetAllAttributes();
   // remove it from the references array
@@ -475,6 +497,7 @@ void Model_Document::removeFeature(FeaturePtr theFeature)
 
   // event: feature is deleted
   ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
+  /* this is in "erase"
   // results of this feature must be redisplayed
   static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
   const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
@@ -485,6 +508,7 @@ void Model_Document::removeFeature(FeaturePtr theFeature)
     ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
     ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), aRes->groupName());
   }
+  */
 }
 
 FeaturePtr Model_Document::feature(TDF_Label& theLabel)
@@ -565,7 +589,12 @@ ObjectPtr Model_Document::object(const std::string& theGroupID, const int theInd
       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
       for (; aRIter != aResults.cend(); aRIter++) {
-        if ((theHidden || (*aRIter)->isInHistory()) && (*aRIter)->groupName() == theGroupID) {
+        if ((*aRIter)->groupName() != theGroupID) continue;
+        bool isIn = theHidden;
+        if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
+          isIn = myConcealedResults.find(*aRIter) == myConcealedResults.end();
+        }
+        if (isIn) {
           if (anIndex == theIndex)
             return *aRIter;
           anIndex++;
@@ -597,9 +626,13 @@ int Model_Document::size(const std::string& theGroupID, const bool theHidden)
       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
       for (; aRIter != aResults.cend(); aRIter++) {
-        if ((theHidden || (*aRIter)->isInHistory()) && (*aRIter)->groupName() == theGroupID) {
-          aResult++;
+        if ((*aRIter)->groupName() != theGroupID) continue;
+        bool isIn = theHidden;
+        if (!isIn && (*aRIter)->isInHistory()) { // check that there is nobody references this result
+          isIn = myConcealedResults.find(*aRIter) == myConcealedResults.end();
         }
+        if (isIn)
+          aResult++;
       }
     }
   }
@@ -725,9 +758,6 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
     if (aKeptFeatures.find(aFIter.Value()) == aKeptFeatures.end()
         && aNewFeatures.find(aFIter.Value()) == aNewFeatures.end()) {
       FeaturePtr aFeature = aFIter.Value();
-      TDF_Label aLab = aFIter.Key();
-      aFIter.Next();
-      myObjs.UnBind(aLab);
       // event: model is updated
       //if (aFeature->isInHistory()) {
         ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_Feature::group());
@@ -736,14 +766,21 @@ void Model_Document::synchronizeFeatures(const bool theMarkUpdated)
       static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
       const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
+      /*
       for (; aRIter != aResults.cend(); aRIter++) {
         boost::shared_ptr<ModelAPI_Result> aRes = *aRIter;
         //aRes->setData(boost::shared_ptr<ModelAPI_Data>()); // deleted flag
         ModelAPI_EventCreator::get()->sendUpdated(aRes, EVENT_DISP);
         ModelAPI_EventCreator::get()->sendDeleted(aThis, aRes->groupName());
       }
+      */
       // redisplay also removed feature (used for sketch and AISObject)
       ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP);
+      aFeature->erase();
+      // unbind after the "erase" call: on abort sketch is removes sub-objects that corrupts aFIter
+      TDF_Label aLab = aFIter.Key();
+      aFIter.Next();
+      myObjs.UnBind(aLab);
     } else
       aFIter.Next();
   }
@@ -783,15 +820,11 @@ void Model_Document::storeResult(boost::shared_ptr<ModelAPI_Data> theFeatureData
   }
 }
 
-static const Standard_GUID ID_CONSTRUCTION("b59fa408-8ab1-42b8-980c-af5adeebe7e4");
-static const Standard_GUID ID_BODY("c1148e9a-9b17-4e9c-9160-18e918fd0013");
-static const Standard_GUID ID_PART("1b3319b9-3e0a-4298-a1dc-3fb5aaf9be59");
-
 boost::shared_ptr<ModelAPI_ResultConstruction> Model_Document::createConstruction(
     const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
-  TDataStd_UAttribute::Set(aLab, ID_CONSTRUCTION);
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str());
   ObjectPtr anOldObject = object(aLab);
   boost::shared_ptr<ModelAPI_ResultConstruction> aResult;
   if (anOldObject) {
@@ -808,7 +841,7 @@ boost::shared_ptr<ModelAPI_ResultBody> Model_Document::createBody(
     const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
-  TDataStd_UAttribute::Set(aLab, ID_BODY);
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str());
   ObjectPtr anOldObject = object(aLab);
   boost::shared_ptr<ModelAPI_ResultBody> aResult;
   if (anOldObject) {
@@ -825,7 +858,7 @@ boost::shared_ptr<ModelAPI_ResultPart> Model_Document::createPart(
     const boost::shared_ptr<ModelAPI_Data>& theFeatureData, const int theIndex)
 {
   TDF_Label aLab = resultLabel(theFeatureData, theIndex);
-  TDataStd_UAttribute::Set(aLab, ID_PART);
+  TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str());
   ObjectPtr anOldObject = object(aLab);
   boost::shared_ptr<ModelAPI_ResultPart> aResult;
   if (anOldObject) {
@@ -877,12 +910,16 @@ void Model_Document::updateResults(FeaturePtr theFeature)
     ResultPtr aNewBody;
     if (aResSize <= aResIndex) {
       TDF_Label anArgLab = aLabIter.Value();
-      if (anArgLab.IsAttribute(ID_BODY)) {
-        aNewBody = createBody(theFeature->data(), aResIndex);
-      } else if (anArgLab.IsAttribute(ID_PART)) {
-        aNewBody = createPart(theFeature->data(), aResIndex);
-      } else if (!anArgLab.IsAttribute(ID_CONSTRUCTION) && anArgLab.FindChild(1).HasAttribute()) {
-        Events_Error::send("Unknown type of result is found in the document");
+      Handle(TDataStd_Comment) aGroup;
+      if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) {
+        if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) {
+          aNewBody = createBody(theFeature->data(), aResIndex);
+        } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) {
+          aNewBody = createPart(theFeature->data(), aResIndex);
+        } else if (aGroup->Get() != ModelAPI_ResultConstruction::group().c_str()) {
+          Events_Error::send(std::string("Unknown type of result is found in the document:") +
+            TCollection_AsciiString(aGroup->Get()).ToCString());
+        }
       }
       if (aNewBody) {
         theFeature->setResult(aNewBody, aResIndex);
@@ -891,6 +928,48 @@ void Model_Document::updateResults(FeaturePtr theFeature)
   }
 }
 
+void Model_Document::objectIsReferenced(const ObjectPtr& theObject)
+{
+  // only bodies are concealed now
+  ResultBodyPtr aResult = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(theObject);
+  if (aResult) {
+    if (myConcealedResults.find(aResult) != myConcealedResults.end()) {
+      Events_Error::send(std::string("The object '") + aResult->data()->name() +
+        "' is already referenced");
+    } else {
+      myConcealedResults.insert(aResult);
+      boost::shared_ptr<ModelAPI_Document> aThis = 
+        Model_Application::getApplication()->getDocument(myID);
+      ModelAPI_EventCreator::get()->sendDeleted(aThis, ModelAPI_ResultBody::group());
+
+      static Events_Loop* aLoop = Events_Loop::loop();
+      static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+      static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get();
+      aECreator->sendUpdated(aResult, EVENT_DISP);
+    }
+  }
+}
+
+void Model_Document::objectIsNotReferenced(const ObjectPtr& theObject)
+{
+  // only bodies are concealed now
+  ResultBodyPtr aResult = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(theObject);
+  if (aResult) {
+    std::set<ResultPtr>::iterator aFind = myConcealedResults.find(aResult);
+    if (aFind != myConcealedResults.end()) {
+      ResultPtr aFeature = *aFind;
+      myConcealedResults.erase(aFind);
+      boost::shared_ptr<ModelAPI_Document> aThis = 
+        Model_Application::getApplication()->getDocument(myID);
+      static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+      ModelAPI_EventCreator::get()->sendUpdated(aFeature, anEvent, false);
+    } else {
+      Events_Error::send(std::string("The object '") + aResult->data()->name() +
+        "' was not referenced '");
+    }
+  }
+}
+
 Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper)
 {
   return TDF_LabelMapHasher::HashCode(theLab, theUpper);