1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <NCollection_IncAllocator.hxx>
18 #include <Standard_Dump.hxx>
19 #include <Standard_NoMoreObject.hxx>
20 #include <Standard_NullObject.hxx>
21 #include <Standard_Type.hxx>
22 #include <Standard_GUID.hxx>
23 #include <NCollection_Array1.hxx>
24 #include <TCollection_AsciiString.hxx>
25 #include <TDF_Attribute.hxx>
26 #include <TDF_AttributeDelta.hxx>
27 #include <TDF_AttributeIndexedMap.hxx>
28 #include <TDF_AttributeIterator.hxx>
29 #include <TDF_ChildIterator.hxx>
30 #include <TDF_Data.hxx>
31 #include <TDF_Delta.hxx>
32 #include <TDF_DeltaOnAddition.hxx>
33 #include <TDF_DeltaOnForget.hxx>
34 #include <TDF_DeltaOnModification.hxx>
35 #include <TDF_DeltaOnRemoval.hxx>
36 #include <TDF_DeltaOnResume.hxx>
37 #include <TDF_Label.hxx>
38 #include <TDF_LabelNode.hxx>
39 #include <TDF_LabelNodePtr.hxx>
40 #include <TDF_Tool.hxx>
41 #include <TDF_Transaction.hxx>
43 typedef NCollection_Array1<Handle(TDF_AttributeDelta)> TDF_Array1OfAttributeIDelta;
45 IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)
47 #undef DEB_DELTA_CREATION
48 #define TDF_DATA_COMMIT_OPTIMIZED
50 #ifdef OCCT_DEBUG_DELTA
51 #define TDF_Data_DebugModified(ACTION) \
52 std::cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<std::endl; \
53 if (!myTransaction) { \
54 TCollection_AsciiString entry; \
55 for (TDF_ChildIterator itr(Root(),Standard_True); itr.More(); itr.Next()) { \
56 const TDF_LabelNode* lnp = itr.Value().myLabelNode; \
57 if (lnp->AttributesModified() || lnp->MayBeModified()) { \
58 TDF_Tool::Entry(itr.Value(),entry); \
59 std::cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
60 if (lnp->AttributesModified()) std::cout<<"AttributesModified "; \
61 if (lnp->MayBeModified()) std::cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
62 std::cout<<std::endl; \
63 std::cout<<itr.Value()<<std::endl; \
67 #define TDF_Data_DebugModified(ACTION)
70 #ifdef OCCT_DEBUG_DELTA_CREATION
71 #define TDF_DataDebugDeltaCreation(DELTATYPE) \
73 TCollection_AsciiString entry; \
74 TDF_Tool::Entry(currentAtt->Label(),entry); \
75 std::cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<std::endl; \
78 #define TDF_DataDebugDeltaCreation(DELTATYPE)
81 #define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
83 TDF_DataDebugDeltaCreation(DELTACOMMENT); \
84 aDelta->AddAttributeDelta(DELTACREATION); \
87 //=======================================================================
89 //purpose : empty constructor
90 //=======================================================================
92 TDF_Data::TDF_Data() :
95 myNotUndoMode (Standard_True),
97 myAllowModification (Standard_True)
99 const Handle(NCollection_IncAllocator) anIncAllocator=
100 new NCollection_IncAllocator (16000);
101 myLabelNodeAllocator = anIncAllocator;
102 myRoot = new (anIncAllocator) TDF_LabelNode (this);
105 //=======================================================================
107 //purpose : Used to implement the destructor ~.
108 //=======================================================================
110 void TDF_Data::Destroy()
112 AbortUntilTransaction(1);
113 // Forget the Owner attribute from the root label to avoid referencing document before
114 // desctuction of the framework (on custom attributes forget). Don't call ForgetAll because
115 // it may call backup.
116 while(!myRoot->FirstAttribute().IsNull()) {
117 static Handle(TDF_Attribute) anEmpty;
118 Handle(TDF_Attribute) aFirst = myRoot->FirstAttribute();
119 myRoot->RemoveAttribute(anEmpty, aFirst);
121 myRoot->Destroy (myLabelNodeAllocator);
126 //=======================================================================
127 //function : OpenTransaction
129 //=======================================================================
131 Standard_Integer TDF_Data::OpenTransaction()
133 myTimes.Prepend(myTime);
134 return ++myTransaction;
138 //=======================================================================
139 //function : CommitTransaction
140 //purpose : Commits the current transaction.
141 //=======================================================================
143 Handle(TDF_Delta) TDF_Data::CommitTransaction
144 (const Standard_Boolean withDelta)
146 Handle(TDF_Delta) delta;
147 if (myTransaction>0) {
148 if (withDelta) delta = new TDF_Delta();
149 #ifdef OCCT_DEBUG_DELTA
150 std::cout<<"TDF_Data::Begin Commit #"<<myTransaction<<std::endl;
152 #ifdef TDF_DATA_COMMIT_OPTIMIZED
154 if (Root().myLabelNode->MayBeModified())
157 TDF_Data::CommitTransaction(Root(),delta,withDelta);
159 if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
162 if (!delta->IsEmpty()) {
163 delta->Validity(myTimes.First(),myTime);
164 #ifdef OCCT_DEBUG_DELTA
165 if (myTransaction == 0) {
166 std::cout<<"TDF_Data::Commit generated this delta in t=0:"<<std::endl;
167 delta->Dump(std::cout);
171 #ifdef OCCT_DEBUG_DELTA
173 if (myTransaction == 0)
174 std::cout<<"TDF_Data::Commit generated NO delta."<<std::endl;
178 myTimes.RemoveFirst();
180 TDF_Data_DebugModified("COMMIT");
185 //=======================================================================
186 //function : CommitUntilTransaction
187 //purpose : Commits the transactions until AND including
188 // the given transaction index.
189 //=======================================================================
191 Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
192 (const Standard_Integer untilTransaction,
193 const Standard_Boolean withDelta)
195 Handle(TDF_Delta) delta;
196 if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
197 while (myTransaction > untilTransaction) {
198 delta = TDF_Data::CommitTransaction(Standard_False);
200 delta = TDF_Data::CommitTransaction(withDelta);
206 //=======================================================================
207 //function : CommitTransaction
208 //purpose : Recursive method used to implement the commit action.
209 //=======================================================================
211 Standard_Integer TDF_Data::CommitTransaction
212 (const TDF_Label& aLabel,
213 const Handle(TDF_Delta)& aDelta,
214 const Standard_Boolean withDelta)
216 aLabel.myLabelNode->MayBeModified(Standard_False);
217 Standard_Integer nbTouchedAtt = 0;
218 #ifdef TDF_DATA_COMMIT_OPTIMIZED
219 Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
221 Standard_Boolean attMod = Standard_True;
225 Handle(TDF_Attribute) lastAtt;
226 Handle(TDF_Attribute) backupAtt;
227 Standard_Boolean currentIsRemoved = Standard_False;
228 attMod = Standard_False;
230 TDF_AttributeIterator itr1(aLabel, Standard_False);
231 while (itr1.More()) {
232 Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value();
234 // currentAtt = itr1.Value();
237 aPtrCurrentAtt->BeforeCommitTransaction();
239 backupAtt = aPtrCurrentAtt->myBackup;
241 if (aPtrCurrentAtt->myTransaction == myTransaction) {
243 --(aPtrCurrentAtt->myTransaction);
245 // ------------------------------------------------------- Forgotten
246 if (aPtrCurrentAtt->IsForgotten()) {
247 if (aPtrCurrentAtt->mySavedTransaction >=
248 aPtrCurrentAtt->myTransaction)
250 const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
251 // Collision with a not forgotten version.
252 if (backupAtt.IsNull()) {
253 TDF_Data_DeltaCreation
255 currentAtt->DeltaOnRemoval());
256 if (myNotUndoMode) currentAtt->BeforeRemoval();
257 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
258 currentIsRemoved = Standard_True;
259 attMod = Standard_True;
262 // Modified then Forgotten...
263 // Forgotten flag spreading?
264 currentAtt->Resume();
265 currentAtt->Restore(backupAtt);
266 currentAtt->myTransaction = backupAtt->myTransaction;
267 currentAtt->RemoveBackup();
268 backupAtt = currentAtt->myBackup;
269 if (myTransaction == 1) {
270 TDF_Data_DeltaCreation
272 currentAtt->DeltaOnRemoval());
273 if (myNotUndoMode) currentAtt->BeforeRemoval();
274 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
275 currentIsRemoved = Standard_True;
278 // BeforeForget has already been called once.
279 // if (myNotUndoMode) currentAtt->BeforeForget();
280 currentAtt->Forget(myTransaction-1);
281 TDF_Data_DeltaCreation
283 currentAtt->DeltaOnForget());
284 attMod = Standard_True;
289 // Forgotten in lower transaction than the current one.
290 TDF_Data_DeltaCreation
292 aPtrCurrentAtt->DeltaOnForget());
295 // ---------------------------------------------------------- Resumed.
296 else if (aPtrCurrentAtt->mySavedTransaction < 0) {
297 TDF_Data_DeltaCreation
299 aPtrCurrentAtt->DeltaOnResume());
300 aPtrCurrentAtt->mySavedTransaction = 0;
301 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
304 // ------------------------------------------------------------ Added.
305 else if (backupAtt.IsNull()) {
306 TDF_Data_DeltaCreation
308 aPtrCurrentAtt->DeltaOnAddition());
309 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
311 // --------------------------------------------------------- Modified.
313 const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity
314 TDF_Data_DeltaCreation
316 anAttrPtr->DeltaOnModification(backupAtt));
317 if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
318 aPtrCurrentAtt->RemoveBackup();
319 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
323 else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
325 if (currentIsRemoved) currentIsRemoved = Standard_False;
326 else lastAtt = aPtrCurrentAtt;
328 aLabel.myLabelNode->AttributesModified(attMod);
331 // Iteration on the children to do the same!
332 //------------------------------------------
333 for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) {
334 #ifdef TDF_DATA_COMMIT_OPTIMIZED
335 if (itr2.Value().myLabelNode->MayBeModified())
338 TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
345 //=======================================================================
346 //function : AbortTransaction
347 //purpose : Aborts the current transaction.
348 //=======================================================================
350 void TDF_Data::AbortTransaction()
353 Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
354 TDF_Data_DebugModified("New ABORT");
358 //=======================================================================
359 //function : AbortUntilTransaction
360 //purpose : Aborts the transactions until AND including the given index.
361 //=======================================================================
363 void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
365 if (untilTransaction>0)
366 Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
370 //=======================================================================
371 //function : IsApplicable
373 //=======================================================================
375 Standard_Boolean TDF_Data::IsApplicable
376 (const Handle(TDF_Delta)& aDelta) const
378 return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
381 //=======================================================================
382 //function : FixOrder
384 //=======================================================================
385 void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta)
387 // make all OnRemoval (which will cause addition of the attribute) are in the end
388 // to do not put two attributes with the same GUID at one label during undo/redo
389 TDF_AttributeDeltaList anOrderedList;
391 const TDF_AttributeDeltaList& attList = theDelta->AttributeDeltas();
392 TDF_ListIteratorOfAttributeDeltaList anIt(attList);
393 for (; anIt.More(); anIt.Next()) { // append not-removal
394 Handle(TDF_AttributeDelta) attDelta = anIt.Value();
395 if (!attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
396 anOrderedList.Append(attDelta);
399 for (anIt.Initialize(attList); anIt.More(); anIt.Next()) { // append removal
400 Handle(TDF_AttributeDelta) attDelta = anIt.Value();
401 if (attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
402 anOrderedList.Append(attDelta);
405 theDelta->ReplaceDeltaList(anOrderedList);
407 //=======================================================================
409 //purpose : Applies a delta to undo actions.
410 //=======================================================================
412 Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta,
413 const Standard_Boolean withDelta)
415 Handle(TDF_Delta) newDelta;
416 if (!aDelta.IsNull ()) {
417 if (aDelta->IsApplicable(myTime)) {
418 if (withDelta) OpenTransaction();
419 #ifdef OCCT_DEBUG_DELTA
420 std::cout<<"TDF_Data::Undo applies this delta:"<<std::endl;
421 aDelta->Dump(std::cout);
423 aDelta->BeforeOrAfterApply(Standard_True);
424 myNotUndoMode = Standard_False;
427 myNotUndoMode = Standard_True;
429 newDelta = CommitTransaction(Standard_True);
430 newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
431 #ifdef OCCT_DEBUG_DELTA
432 std::cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<std::endl;
435 myTime = aDelta->BeginTime();
436 aDelta->BeforeOrAfterApply(Standard_False);
444 //=======================================================================
447 //=======================================================================
449 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
451 anOS<<"Dump of a TDF_Data."<<std::endl;
452 anOS<<"Current transaction: "<<myTransaction;
453 anOS<<"; Current tick: "<<myTime<<";"<<std::endl;
457 //=======================================================================
458 //function : DumpJson
460 //=======================================================================
461 void TDF_Data::DumpJson (Standard_OStream& theOStream, Standard_Integer /*theDepth*/) const
463 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
465 TCollection_AsciiString aStrForTDF_Label;
466 TDF_Tool::Entry (myRoot, aStrForTDF_Label);
467 OCCT_DUMP_FIELD_VALUE_STRING (theOStream, aStrForTDF_Label)
469 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTransaction)
470 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbTouchedAtt)
471 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNotUndoMode)
472 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTime)
473 for (TColStd_ListOfInteger::Iterator aTimeIt (myTimes); aTimeIt.More(); aTimeIt.Next())
475 const Standard_Integer aTime = aTimeIt.Value();
476 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aTime)
478 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowModification)