0031075: Application Framework - reading STEP file into TDocStd_Document leads to...
[occt.git] / src / TDF / TDF_Data.cxx
index e9f232b..44e103c 100644 (file)
 
 
 #include <NCollection_IncAllocator.hxx>
+#include <Standard_Dump.hxx>
 #include <Standard_NoMoreObject.hxx>
 #include <Standard_NullObject.hxx>
 #include <Standard_Type.hxx>
+#include <Standard_GUID.hxx>
+#include <NCollection_Array1.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TDF_Attribute.hxx>
 #include <TDF_AttributeDelta.hxx>
 #include <TDF_Tool.hxx>
 #include <TDF_Transaction.hxx>
 
-IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,MMgt_TShared)
+typedef NCollection_Array1<Handle(TDF_AttributeDelta)> TDF_Array1OfAttributeIDelta;
+
+IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)
 
 #undef DEB_DELTA_CREATION
 #undef TDF_DATA_COMMIT_OPTIMIZED
 
 #ifdef OCCT_DEBUG_DELTA
 #define TDF_Data_DebugModified(ACTION) \
-  cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<endl; \
+  std::cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<std::endl; \
 if (!myTransaction) { \
   TCollection_AsciiString entry; \
   for (TDF_ChildIterator itr(Root(),Standard_True); itr.More(); itr.Next()) { \
     const TDF_LabelNode* lnp = itr.Value().myLabelNode; \
     if (lnp->AttributesModified() || lnp->MayBeModified()) { \
       TDF_Tool::Entry(itr.Value(),entry); \
-      cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
-      if (lnp->AttributesModified()) cout<<"AttributesModified "; \
-      if (lnp->MayBeModified()) cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
-      cout<<endl; \
-      cout<<itr.Value()<<endl; \
+      std::cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
+      if (lnp->AttributesModified()) std::cout<<"AttributesModified "; \
+      if (lnp->MayBeModified()) std::cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
+      std::cout<<std::endl; \
+      std::cout<<itr.Value()<<std::endl; \
       entry.Clear(); \
     }}}
 #else
@@ -67,7 +72,7 @@ if (!myTransaction) { \
 { \
 TCollection_AsciiString entry; \
 TDF_Tool::Entry(currentAtt->Label(),entry); \
-cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<endl; \
+std::cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<std::endl; \
 }
 #else
 #define TDF_DataDebugDeltaCreation(DELTATYPE)
@@ -105,6 +110,14 @@ myAllowModification     (Standard_True)
 void TDF_Data::Destroy()
 {
   AbortUntilTransaction(1);
+  // Forget the Owner attribute from the root label to avoid referencing document before
+  // desctuction of the framework (on custom attributes forget). Don't call ForgetAll because
+  // it may call backup.
+  while(!myRoot->FirstAttribute().IsNull()) {
+    static Handle(TDF_Attribute) anEmpty;
+    Handle(TDF_Attribute) aFirst = myRoot->FirstAttribute();
+    myRoot->RemoveAttribute(anEmpty, aFirst);
+  }
   myRoot->Destroy (myLabelNodeAllocator);
   myRoot = NULL;
 }
@@ -134,7 +147,7 @@ Handle(TDF_Delta) TDF_Data::CommitTransaction
   if (myTransaction>0) {
     if (withDelta) delta = new TDF_Delta();
 #ifdef OCCT_DEBUG_DELTA
-    cout<<"TDF_Data::Begin Commit #"<<myTransaction<<endl;    
+    std::cout<<"TDF_Data::Begin Commit #"<<myTransaction<<std::endl;    
 #endif
 #ifdef TDF_DATA_COMMIT_OPTIMIZED
     myNbTouchedAtt = 0;
@@ -150,15 +163,15 @@ Handle(TDF_Delta) TDF_Data::CommitTransaction
         delta->Validity(myTimes.First(),myTime);
 #ifdef OCCT_DEBUG_DELTA
         if (myTransaction == 0) {
-          cout<<"TDF_Data::Commit generated this delta in t=0:"<<endl;
-          delta->Dump(cout);
+          std::cout<<"TDF_Data::Commit generated this delta in t=0:"<<std::endl;
+          delta->Dump(std::cout);
         }
 #endif
       }
 #ifdef OCCT_DEBUG_DELTA
       else {
         if (myTransaction == 0)
-          cout<<"TDF_Data::Commit generated NO delta."<<endl;
+          std::cout<<"TDF_Data::Commit generated NO delta."<<std::endl;
       }
 #endif
     }
@@ -216,7 +229,7 @@ Standard_Integer TDF_Data::CommitTransaction
 
     TDF_AttributeIterator itr1(aLabel, Standard_False);
     while (itr1.More()) {
-      TDF_Attribute * aPtrCurrentAtt = itr1.Value();
+      Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value();
       itr1.Next();
       //      currentAtt = itr1.Value();
 
@@ -297,7 +310,7 @@ Standard_Integer TDF_Data::CommitTransaction
         }
         // --------------------------------------------------------- Modified.
         else {
-          const TDF_Attribute* anAttrPtr = aPtrCurrentAtt; // to avoid ambiguity
+          const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity
           TDF_Data_DeltaCreation
             ("Modification",
              anAttrPtr->DeltaOnModification(backupAtt));
@@ -365,33 +378,58 @@ Standard_Boolean TDF_Data::IsApplicable
   return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
 }
 
-
+//=======================================================================
+//function : FixOrder
+//purpose  : 
+//=======================================================================
+void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta)
+{
+  // make all OnRemoval (which will cause addition of the attribute) are in the end
+  // to do not put two attributes with the same GUID at one label during undo/redo
+  TDF_AttributeDeltaList anOrderedList;
+
+  const TDF_AttributeDeltaList& attList = theDelta->AttributeDeltas();
+  TDF_ListIteratorOfAttributeDeltaList anIt(attList);
+  for (; anIt.More(); anIt.Next()) { // append not-removal
+    Handle(TDF_AttributeDelta) attDelta = anIt.Value();
+    if (!attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
+      anOrderedList.Append(attDelta);
+    }
+  }
+  for (anIt.Initialize(attList); anIt.More(); anIt.Next()) { // append removal
+    Handle(TDF_AttributeDelta) attDelta = anIt.Value();
+    if (attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
+      anOrderedList.Append(attDelta);
+    }
+  }
+  theDelta->ReplaceDeltaList(anOrderedList);
+}
 //=======================================================================
 //function : Undo
 //purpose  : Applies a delta to undo  actions.
 //=======================================================================
 
-Handle(TDF_Delta) TDF_Data::Undo
-(const Handle(TDF_Delta)& aDelta,
- const Standard_Boolean withDelta)
+Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta,
+                                 const Standard_Boolean withDelta)
 {
   Handle(TDF_Delta) newDelta;
   if (!aDelta.IsNull ()) {
     if (aDelta->IsApplicable(myTime)) {
       if (withDelta) OpenTransaction();
 #ifdef OCCT_DEBUG_DELTA
-      cout<<"TDF_Data::Undo applies this delta:"<<endl;
-      aDelta->Dump(cout);
+      std::cout<<"TDF_Data::Undo applies this delta:"<<std::endl;
+      aDelta->Dump(std::cout);
 #endif
       aDelta->BeforeOrAfterApply(Standard_True);
       myNotUndoMode = Standard_False;
+      FixOrder(aDelta);
       aDelta->Apply ();
       myNotUndoMode = Standard_True;
       if (withDelta) {
         newDelta = CommitTransaction(Standard_True);
         newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
 #ifdef OCCT_DEBUG_DELTA
-        cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<endl;
+        std::cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<std::endl;
 #endif
       }
       myTime = aDelta->BeginTime();
@@ -410,8 +448,32 @@ Handle(TDF_Delta) TDF_Data::Undo
 
 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
 {
-  anOS<<"Dump of a TDF_Data."<<endl;
+  anOS<<"Dump of a TDF_Data."<<std::endl;
   anOS<<"Current transaction: "<<myTransaction;
-  anOS<<"; Current tick: "<<myTime<<";"<<endl;
+  anOS<<"; Current tick: "<<myTime<<";"<<std::endl;
   return anOS;
 }
+
+//=======================================================================
+//function : DumpJson
+//purpose  : 
+//=======================================================================
+void TDF_Data::DumpJson (Standard_OStream& theOStream, Standard_Integer /*theDepth*/) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  TCollection_AsciiString aStrForTDF_Label;
+  TDF_Tool::Entry (myRoot, aStrForTDF_Label);
+  OCCT_DUMP_FIELD_VALUE_STRING (theOStream, aStrForTDF_Label)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTransaction)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbTouchedAtt)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNotUndoMode)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTime)
+  for (TColStd_ListOfInteger::Iterator aTimeIt (myTimes); aTimeIt.More(); aTimeIt.Next())
+  {
+    const Standard_Integer aTime = aTimeIt.Value();
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aTime)
+  }
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowModification)
+}