// Created by: DAUTRY Philippe // Copyright (c) 1997-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef NCollection_Array1 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 "<AttributesModified()) cout<<"AttributesModified "; \ if (lnp->MayBeModified()) cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \ cout<Label(),entry); \ cout<<"Creation of a DeltaOn"<DynamicType()<AddAttributeDelta(DELTACREATION); \ } //======================================================================= //function : TDF_Data //purpose : empty constructor //======================================================================= TDF_Data::TDF_Data() : myTransaction (0), myNbTouchedAtt (0), myNotUndoMode (Standard_True), myTime (0), myAllowModification (Standard_True) { const Handle(NCollection_IncAllocator) anIncAllocator= new NCollection_IncAllocator (16000); myLabelNodeAllocator = anIncAllocator; myRoot = new (anIncAllocator) TDF_LabelNode (this); } //======================================================================= //function : Destroy //purpose : Used to implement the destructor ~. //======================================================================= void TDF_Data::Destroy() { AbortUntilTransaction(1); myRoot->Destroy (myLabelNodeAllocator); myRoot = NULL; } //======================================================================= //function : OpenTransaction //purpose : //======================================================================= Standard_Integer TDF_Data::OpenTransaction() { myTimes.Prepend(myTime); return ++myTransaction; } //======================================================================= //function : CommitTransaction //purpose : Commits the current transaction. //======================================================================= Handle(TDF_Delta) TDF_Data::CommitTransaction (const Standard_Boolean withDelta) { Handle(TDF_Delta) delta; if (myTransaction>0) { if (withDelta) delta = new TDF_Delta(); #ifdef OCCT_DEBUG_DELTA cout<<"TDF_Data::Begin Commit #"<MayBeModified()) #endif myNbTouchedAtt = TDF_Data::CommitTransaction(Root(),delta,withDelta); if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime; --myTransaction; if (withDelta) { if (!delta->IsEmpty()) { delta->Validity(myTimes.First(),myTime); #ifdef OCCT_DEBUG_DELTA if (myTransaction == 0) { cout<<"TDF_Data::Commit generated this delta in t=0:"<Dump(cout); } #endif } #ifdef OCCT_DEBUG_DELTA else { if (myTransaction == 0) cout<<"TDF_Data::Commit generated NO delta."<0) && (myTransaction >= untilTransaction)) { while (myTransaction > untilTransaction) { delta = TDF_Data::CommitTransaction(Standard_False); } delta = TDF_Data::CommitTransaction(withDelta); } return delta; } //======================================================================= //function : CommitTransaction //purpose : Recursive method used to implement the commit action. //======================================================================= Standard_Integer TDF_Data::CommitTransaction (const TDF_Label& aLabel, const Handle(TDF_Delta)& aDelta, const Standard_Boolean withDelta) { aLabel.myLabelNode->MayBeModified(Standard_False); Standard_Integer nbTouchedAtt = 0; #ifdef TDF_DATA_COMMIT_OPTIMIZED Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified(); #else Standard_Boolean attMod = Standard_True; #endif if (attMod) { Handle(TDF_Attribute) lastAtt; Handle(TDF_Attribute) backupAtt; Standard_Boolean currentIsRemoved = Standard_False; attMod = Standard_False; TDF_AttributeIterator itr1(aLabel, Standard_False); while (itr1.More()) { Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value(); itr1.Next(); // currentAtt = itr1.Value(); // A callback: aPtrCurrentAtt->BeforeCommitTransaction(); backupAtt = aPtrCurrentAtt->myBackup; if (aPtrCurrentAtt->myTransaction == myTransaction) { ++nbTouchedAtt; --(aPtrCurrentAtt->myTransaction); // ------------------------------------------------------- Forgotten if (aPtrCurrentAtt->IsForgotten()) { if (aPtrCurrentAtt->mySavedTransaction >= aPtrCurrentAtt->myTransaction) { const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt; // Collision with a not forgotten version. if (backupAtt.IsNull()) { TDF_Data_DeltaCreation ("Removal(1)", currentAtt->DeltaOnRemoval()); if (myNotUndoMode) currentAtt->BeforeRemoval(); aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt); currentIsRemoved = Standard_True; attMod = Standard_True; } else { // Modified then Forgotten... // Forgotten flag spreading? currentAtt->Resume(); currentAtt->Restore(backupAtt); currentAtt->myTransaction = backupAtt->myTransaction; currentAtt->RemoveBackup(); backupAtt = currentAtt->myBackup; if (myTransaction == 1) { TDF_Data_DeltaCreation ("Removal(2)", currentAtt->DeltaOnRemoval()); if (myNotUndoMode) currentAtt->BeforeRemoval(); aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt); currentIsRemoved = Standard_True; } else { // BeforeForget has already been called once. // if (myNotUndoMode) currentAtt->BeforeForget(); currentAtt->Forget(myTransaction-1); TDF_Data_DeltaCreation ("Forget(1)", currentAtt->DeltaOnForget()); attMod = Standard_True; } } } else { // Forgotten in lower transaction than the current one. TDF_Data_DeltaCreation ("Forget(2)", aPtrCurrentAtt->DeltaOnForget()); } } // ---------------------------------------------------------- Resumed. else if (aPtrCurrentAtt->mySavedTransaction < 0) { TDF_Data_DeltaCreation ("Resume", aPtrCurrentAtt->DeltaOnResume()); aPtrCurrentAtt->mySavedTransaction = 0; attMod = attMod || (aPtrCurrentAtt->myTransaction > 0); } // ------------------------------------------------------------ Added. else if (backupAtt.IsNull()) { TDF_Data_DeltaCreation ("Addition", aPtrCurrentAtt->DeltaOnAddition()); attMod = attMod || (aPtrCurrentAtt->myTransaction > 0); } // --------------------------------------------------------- Modified. else { const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity TDF_Data_DeltaCreation ("Modification", anAttrPtr->DeltaOnModification(backupAtt)); if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction) aPtrCurrentAtt->RemoveBackup(); attMod = attMod || (aPtrCurrentAtt->myTransaction > 0); } } else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0); if (currentIsRemoved) currentIsRemoved = Standard_False; else lastAtt = aPtrCurrentAtt; } aLabel.myLabelNode->AttributesModified(attMod); } // Iteration on the children to do the same! //------------------------------------------ for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) { #ifdef TDF_DATA_COMMIT_OPTIMIZED if (itr2.Value().myLabelNode->MayBeModified()) #endif nbTouchedAtt += TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta); } return nbTouchedAtt; } //======================================================================= //function : AbortTransaction //purpose : Aborts the current transaction. //======================================================================= void TDF_Data::AbortTransaction() { if (myTransaction>0) Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False); TDF_Data_DebugModified("New ABORT"); } //======================================================================= //function : AbortUntilTransaction //purpose : Aborts the transactions until AND including the given index. //======================================================================= void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction) { if (untilTransaction>0) Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False); } //======================================================================= //function : IsApplicable //purpose : //======================================================================= Standard_Boolean TDF_Data::IsApplicable (const Handle(TDF_Delta)& aDelta) const { return !aDelta.IsNull() && aDelta->IsApplicable(myTime); } //======================================================================= //function : FixOrder //purpose : //======================================================================= void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta) { const TDF_AttributeDeltaList& attList = theDelta->AttributeDeltas(); Handle(TDF_AttributeDelta) attDelta; Handle(TDF_Attribute) att; Standard_Integer i, indx1(0), indx2(0); Standard_GUID aGuid; TDF_ListIteratorOfAttributeDeltaList itr(attList) ; for (i=1; itr.More(); itr.Next(), i++) { attDelta = itr.Value(); if(indx1) { att = attDelta->Attribute(); if((att->ID() == aGuid) && (attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnAddition)))) { indx2 = i; break; } } else if (attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) { att = attDelta->Attribute(); aGuid = att->ID(); indx1 = i; } } if(indx1 && indx2) { TDF_Array1OfAttributeIDelta anArray(1, attList.Extent()); itr.Initialize(attList); for (i=1; itr.More(); itr.Next(), i++) anArray.SetValue(i, itr.Value()); Handle(TDF_AttributeDelta) attDelta1, attDelta2; attDelta1 = anArray.Value(indx1); attDelta2 = anArray.Value(indx2); anArray.SetValue(indx1, attDelta2); anArray.SetValue(indx2, attDelta1); TDF_AttributeDeltaList attList2; for(i=1; i<= anArray.Upper(); i++) attList2.Append(anArray.Value(i)); theDelta->ReplaceDeltaList(attList2); } } //======================================================================= //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) newDelta; if (!aDelta.IsNull ()) { if (aDelta->IsApplicable(myTime)) { if (withDelta) OpenTransaction(); #ifdef OCCT_DEBUG_DELTA cout<<"TDF_Data::Undo applies this delta:"<Dump(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#"<BeginTime()<<" to time \t#"<EndTime()<BeginTime(); aDelta->BeforeOrAfterApply(Standard_False); } } return newDelta; } //======================================================================= //function : Dump //purpose : //======================================================================= Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const { anOS<<"Dump of a TDF_Data."<