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.
16 #include <TDF_Data.ixx>
18 #include <TCollection_AsciiString.hxx>
20 #include <TDF_Attribute.hxx>
21 #include <TDF_AttributeIterator.hxx>
22 #include <TDF_AttributeIndexedMap.hxx>
23 #include <TDF_ChildIterator.hxx>
24 #include <TDF_Delta.hxx>
25 #include <TDF_AttributeDelta.hxx>
26 #include <TDF_DeltaOnAddition.hxx>
27 #include <TDF_DeltaOnForget.hxx>
28 #include <TDF_DeltaOnModification.hxx>
29 #include <TDF_DeltaOnRemoval.hxx>
30 #include <TDF_DeltaOnResume.hxx>
31 #include <TDF_Label.hxx>
32 #include <TDF_LabelNode.hxx>
33 #include <TDF_LabelNodePtr.hxx>
34 #include <TDF_Tool.hxx>
36 #include <Standard_NoMoreObject.hxx>
37 #include <Standard_NullObject.hxx>
39 #include <NCollection_IncAllocator.hxx>
41 #undef DEB_DELTA_CREATION
42 #undef TDF_DATA_COMMIT_OPTIMIZED
46 #ifdef OCCT_DEBUG_DELTA
47 #define TDF_Data_DebugModified(ACTION) \
48 cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<endl; \
49 if (!myTransaction) { \
50 TCollection_AsciiString entry; \
51 for (TDF_ChildIterator itr(Root(),Standard_True); itr.More(); itr.Next()) { \
52 const TDF_LabelNode* lnp = itr.Value().myLabelNode; \
53 if (lnp->AttributesModified() || lnp->MayBeModified()) { \
54 TDF_Tool::Entry(itr.Value(),entry); \
55 cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
56 if (lnp->AttributesModified()) cout<<"AttributesModified "; \
57 if (lnp->MayBeModified()) cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
59 cout<<itr.Value()<<endl; \
63 #define TDF_Data_DebugModified(ACTION)
66 #ifdef OCCT_DEBUG_DELTA_CREATION
67 #define TDF_DataDebugDeltaCreation(DELTATYPE) \
69 TCollection_AsciiString entry; \
70 TDF_Tool::Entry(currentAtt->Label(),entry); \
71 cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<endl; \
74 #define TDF_DataDebugDeltaCreation(DELTATYPE)
77 #define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
79 TDF_DataDebugDeltaCreation(DELTACOMMENT); \
80 aDelta->AddAttributeDelta(DELTACREATION); \
83 //=======================================================================
85 //purpose : empty constructor
86 //=======================================================================
88 TDF_Data::TDF_Data() :
91 myNotUndoMode (Standard_True),
93 myAllowModification (Standard_True)
95 const Handle(NCollection_IncAllocator) anIncAllocator=
96 new NCollection_IncAllocator (16000);
97 myLabelNodeAllocator = anIncAllocator;
98 myRoot = new (anIncAllocator) TDF_LabelNode (this);
101 //=======================================================================
103 //purpose : Used to implement the destructor ~.
104 //=======================================================================
106 void TDF_Data::Destroy()
108 AbortUntilTransaction(1);
109 myRoot->Destroy (myLabelNodeAllocator);
114 //=======================================================================
115 //function : OpenTransaction
117 //=======================================================================
119 Standard_Integer TDF_Data::OpenTransaction()
121 myTimes.Prepend(myTime);
122 return ++myTransaction;
126 //=======================================================================
127 //function : CommitTransaction
128 //purpose : Commits the current transaction.
129 //=======================================================================
131 Handle(TDF_Delta) TDF_Data::CommitTransaction
132 (const Standard_Boolean withDelta)
134 Handle(TDF_Delta) delta;
135 if (myTransaction>0) {
136 if (withDelta) delta = new TDF_Delta();
137 #ifdef OCCT_DEBUG_DELTA
138 cout<<"TDF_Data::Begin Commit #"<<myTransaction<<endl;
140 #ifdef TDF_DATA_COMMIT_OPTIMIZED
142 if (Root().myLabelNode->MayBeModified())
145 TDF_Data::CommitTransaction(Root(),delta,withDelta);
147 if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
150 if (!delta->IsEmpty()) {
151 delta->Validity(myTimes.First(),myTime);
152 #ifdef OCCT_DEBUG_DELTA
153 if (myTransaction == 0) {
154 cout<<"TDF_Data::Commit generated this delta in t=0:"<<endl;
159 #ifdef OCCT_DEBUG_DELTA
161 if (myTransaction == 0)
162 cout<<"TDF_Data::Commit generated NO delta."<<endl;
166 myTimes.RemoveFirst();
168 TDF_Data_DebugModified("COMMIT");
173 //=======================================================================
174 //function : CommitUntilTransaction
175 //purpose : Commits the transactions until AND including
176 // the given transaction index.
177 //=======================================================================
179 Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
180 (const Standard_Integer untilTransaction,
181 const Standard_Boolean withDelta)
183 Handle(TDF_Delta) delta;
184 if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
185 while (myTransaction > untilTransaction) {
186 delta = TDF_Data::CommitTransaction(Standard_False);
188 delta = TDF_Data::CommitTransaction(withDelta);
194 //=======================================================================
195 //function : CommitTransaction
196 //purpose : Recursive method used to implement the commit action.
197 //=======================================================================
199 Standard_Integer TDF_Data::CommitTransaction
200 (const TDF_Label& aLabel,
201 const Handle(TDF_Delta)& aDelta,
202 const Standard_Boolean withDelta)
204 aLabel.myLabelNode->MayBeModified(Standard_False);
205 Standard_Integer nbTouchedAtt = 0;
206 #ifdef TDF_DATA_COMMIT_OPTIMIZED
207 Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
209 Standard_Boolean attMod = Standard_True;
213 Handle(TDF_Attribute) lastAtt;
214 Handle(TDF_Attribute) backupAtt;
215 Standard_Boolean currentIsRemoved = Standard_False;
216 attMod = Standard_False;
218 TDF_AttributeIterator itr1(aLabel, Standard_False);
219 while (itr1.More()) {
220 TDF_Attribute * aPtrCurrentAtt = itr1.Value();
222 // currentAtt = itr1.Value();
226 aPtrCurrentAtt->BeforeCommitTransaction();
229 backupAtt = aPtrCurrentAtt->myBackup;
231 if (aPtrCurrentAtt->myTransaction == myTransaction) {
233 --(aPtrCurrentAtt->myTransaction);
235 // ------------------------------------------------------- Forgotten
236 if (aPtrCurrentAtt->IsForgotten()) {
237 if (aPtrCurrentAtt->mySavedTransaction >=
238 aPtrCurrentAtt->myTransaction)
240 const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
241 // Collision with a not forgotten version.
242 if (backupAtt.IsNull()) {
243 TDF_Data_DeltaCreation
245 currentAtt->DeltaOnRemoval());
246 if (myNotUndoMode) currentAtt->BeforeRemoval();
247 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
248 currentIsRemoved = Standard_True;
249 attMod = Standard_True;
252 // Modified then Forgotten...
253 // Forgotten flag spreading?
254 currentAtt->Resume();
255 currentAtt->Restore(backupAtt);
256 currentAtt->myTransaction = backupAtt->myTransaction;
257 currentAtt->RemoveBackup();
258 backupAtt = currentAtt->myBackup;
259 if (myTransaction == 1) {
260 TDF_Data_DeltaCreation
262 currentAtt->DeltaOnRemoval());
263 if (myNotUndoMode) currentAtt->BeforeRemoval();
264 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
265 currentIsRemoved = Standard_True;
268 // BeforeForget has already been called once.
269 // if (myNotUndoMode) currentAtt->BeforeForget();
270 currentAtt->Forget(myTransaction-1);
271 TDF_Data_DeltaCreation
273 currentAtt->DeltaOnForget());
274 attMod = Standard_True;
279 // Forgotten in lower transaction than the current one.
280 TDF_Data_DeltaCreation
282 aPtrCurrentAtt->DeltaOnForget());
285 // ---------------------------------------------------------- Resumed.
286 else if (aPtrCurrentAtt->mySavedTransaction < 0) {
287 TDF_Data_DeltaCreation
289 aPtrCurrentAtt->DeltaOnResume());
290 aPtrCurrentAtt->mySavedTransaction = 0;
291 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
294 // ------------------------------------------------------------ Added.
295 else if (backupAtt.IsNull()) {
296 TDF_Data_DeltaCreation
298 aPtrCurrentAtt->DeltaOnAddition());
299 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
301 // --------------------------------------------------------- Modified.
303 TDF_Data_DeltaCreation
305 aPtrCurrentAtt->DeltaOnModification(backupAtt));
306 if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
307 aPtrCurrentAtt->RemoveBackup();
308 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
312 else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
314 if (currentIsRemoved) currentIsRemoved = Standard_False;
315 else lastAtt = aPtrCurrentAtt;
317 aLabel.myLabelNode->AttributesModified(attMod);
320 // Iteration on the children to do the same!
321 //------------------------------------------
322 for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) {
323 #ifdef TDF_DATA_COMMIT_OPTIMIZED
324 if (itr2.Value().myLabelNode->MayBeModified())
327 TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
334 //=======================================================================
335 //function : AbortTransaction
336 //purpose : Aborts the current transaction.
337 //=======================================================================
339 void TDF_Data::AbortTransaction()
342 Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
343 TDF_Data_DebugModified("New ABORT");
347 //=======================================================================
348 //function : AbortUntilTransaction
349 //purpose : Aborts the transactions until AND including the given index.
350 //=======================================================================
352 void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
354 if (untilTransaction>0)
355 Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
359 //=======================================================================
360 //function : IsApplicable
362 //=======================================================================
364 Standard_Boolean TDF_Data::IsApplicable
365 (const Handle(TDF_Delta)& aDelta) const
367 return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
371 //=======================================================================
373 //purpose : Applies a delta to undo actions.
374 //=======================================================================
376 Handle(TDF_Delta) TDF_Data::Undo
377 (const Handle(TDF_Delta)& aDelta,
378 const Standard_Boolean withDelta)
380 Handle(TDF_Delta) newDelta;
381 if (!aDelta.IsNull ()) {
382 if (aDelta->IsApplicable(myTime)) {
383 if (withDelta) OpenTransaction();
384 #ifdef OCCT_DEBUG_DELTA
385 cout<<"TDF_Data::Undo applies this delta:"<<endl;
388 aDelta->BeforeOrAfterApply(Standard_True);
389 myNotUndoMode = Standard_False;
391 myNotUndoMode = Standard_True;
393 newDelta = CommitTransaction(Standard_True);
394 newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
395 #ifdef OCCT_DEBUG_DELTA
396 cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<endl;
399 myTime = aDelta->BeginTime();
400 aDelta->BeforeOrAfterApply(Standard_False);
408 //=======================================================================
411 //=======================================================================
413 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
415 anOS<<"Dump of a TDF_Data."<<endl;
416 anOS<<"Current transaction: "<<myTransaction;
417 anOS<<"; Current tick: "<<myTime<<";"<<endl;