1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
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>
42
43 typedef NCollection_Array1<Handle(TDF_AttributeDelta)> TDF_Array1OfAttributeIDelta;
44
IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)45 IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)
46
47 #undef DEB_DELTA_CREATION
48 #define TDF_DATA_COMMIT_OPTIMIZED
49
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; \
64 entry.Clear(); \
65 }}}
66 #else
67 #define TDF_Data_DebugModified(ACTION)
68 #endif
69
70 #ifdef OCCT_DEBUG_DELTA_CREATION
71 #define TDF_DataDebugDeltaCreation(DELTATYPE) \
72 { \
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; \
76 }
77 #else
78 #define TDF_DataDebugDeltaCreation(DELTATYPE)
79 #endif
80
81 #define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
82 if (withDelta) { \
83 TDF_DataDebugDeltaCreation(DELTACOMMENT); \
84 aDelta->AddAttributeDelta(DELTACREATION); \
85 }
86
87 //=======================================================================
88 //function : TDF_Data
89 //purpose : empty constructor
90 //=======================================================================
91
92 TDF_Data::TDF_Data() :
93 myTransaction (0),
94 myNbTouchedAtt (0),
95 myNotUndoMode (Standard_True),
96 myTime (0),
97 myAllowModification (Standard_True),
98 myAccessByEntries (Standard_False)
99 {
100 const Handle(NCollection_IncAllocator) anIncAllocator=
101 new NCollection_IncAllocator (16000);
102 myLabelNodeAllocator = anIncAllocator;
103 myRoot = new (anIncAllocator) TDF_LabelNode (this);
104 }
105
106 //=======================================================================
107 //function : Destroy
108 //purpose : Used to implement the destructor ~.
109 //=======================================================================
110
Destroy()111 void TDF_Data::Destroy()
112 {
113 AbortUntilTransaction(1);
114 // Forget the Owner attribute from the root label to avoid referencing document before
115 // desctuction of the framework (on custom attributes forget). Don't call ForgetAll because
116 // it may call backup.
117 while(!myRoot->FirstAttribute().IsNull()) {
118 static Handle(TDF_Attribute) anEmpty;
119 Handle(TDF_Attribute) aFirst = myRoot->FirstAttribute();
120 myRoot->RemoveAttribute(anEmpty, aFirst);
121 }
122 myAccessByEntriesTable.Clear();
123 myRoot->Destroy (myLabelNodeAllocator);
124 myRoot = NULL;
125 }
126
127
128 //=======================================================================
129 //function : OpenTransaction
130 //purpose :
131 //=======================================================================
132
OpenTransaction()133 Standard_Integer TDF_Data::OpenTransaction()
134 {
135 myTimes.Prepend(myTime);
136 return ++myTransaction;
137 }
138
139
140 //=======================================================================
141 //function : CommitTransaction
142 //purpose : Commits the current transaction.
143 //=======================================================================
144
Handle(TDF_Delta)145 Handle(TDF_Delta) TDF_Data::CommitTransaction
146 (const Standard_Boolean withDelta)
147 {
148 Handle(TDF_Delta) delta;
149 if (myTransaction>0) {
150 if (withDelta) delta = new TDF_Delta();
151 #ifdef OCCT_DEBUG_DELTA
152 std::cout<<"TDF_Data::Begin Commit #"<<myTransaction<<std::endl;
153 #endif
154 #ifdef TDF_DATA_COMMIT_OPTIMIZED
155 myNbTouchedAtt = 0;
156 if (Root().myLabelNode->MayBeModified())
157 #endif
158 myNbTouchedAtt =
159 TDF_Data::CommitTransaction(Root(),delta,withDelta);
160
161 if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
162 --myTransaction;
163 if (withDelta) {
164 if (!delta->IsEmpty()) {
165 delta->Validity(myTimes.First(),myTime);
166 #ifdef OCCT_DEBUG_DELTA
167 if (myTransaction == 0) {
168 std::cout<<"TDF_Data::Commit generated this delta in t=0:"<<std::endl;
169 delta->Dump(std::cout);
170 }
171 #endif
172 }
173 #ifdef OCCT_DEBUG_DELTA
174 else {
175 if (myTransaction == 0)
176 std::cout<<"TDF_Data::Commit generated NO delta."<<std::endl;
177 }
178 #endif
179 }
180 myTimes.RemoveFirst();
181 }
182 TDF_Data_DebugModified("COMMIT");
183 return delta;
184 }
185
186
187 //=======================================================================
188 //function : CommitUntilTransaction
189 //purpose : Commits the transactions until AND including
190 // the given transaction index.
191 //=======================================================================
192
Handle(TDF_Delta)193 Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
194 (const Standard_Integer untilTransaction,
195 const Standard_Boolean withDelta)
196 {
197 Handle(TDF_Delta) delta;
198 if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
199 while (myTransaction > untilTransaction) {
200 delta = TDF_Data::CommitTransaction(Standard_False);
201 }
202 delta = TDF_Data::CommitTransaction(withDelta);
203 }
204 return delta;
205 }
206
207
208 //=======================================================================
209 //function : CommitTransaction
210 //purpose : Recursive method used to implement the commit action.
211 //=======================================================================
212
CommitTransaction(const TDF_Label & aLabel,const Handle (TDF_Delta)& aDelta,const Standard_Boolean withDelta)213 Standard_Integer TDF_Data::CommitTransaction
214 (const TDF_Label& aLabel,
215 const Handle(TDF_Delta)& aDelta,
216 const Standard_Boolean withDelta)
217 {
218 aLabel.myLabelNode->MayBeModified(Standard_False);
219 Standard_Integer nbTouchedAtt = 0;
220 #ifdef TDF_DATA_COMMIT_OPTIMIZED
221 Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
222 #else
223 Standard_Boolean attMod = Standard_True;
224 #endif
225
226 if (attMod) {
227 Handle(TDF_Attribute) lastAtt;
228 Handle(TDF_Attribute) backupAtt;
229 Standard_Boolean currentIsRemoved = Standard_False;
230 attMod = Standard_False;
231
232 TDF_AttributeIterator itr1(aLabel, Standard_False);
233 while (itr1.More()) {
234 Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value();
235 itr1.Next();
236 // currentAtt = itr1.Value();
237
238 // A callback:
239 aPtrCurrentAtt->BeforeCommitTransaction();
240
241 backupAtt = aPtrCurrentAtt->myBackup;
242
243 if (aPtrCurrentAtt->myTransaction == myTransaction) {
244 ++nbTouchedAtt;
245 --(aPtrCurrentAtt->myTransaction);
246
247 // ------------------------------------------------------- Forgotten
248 if (aPtrCurrentAtt->IsForgotten()) {
249 if (aPtrCurrentAtt->mySavedTransaction >=
250 aPtrCurrentAtt->myTransaction)
251 {
252 const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
253 // Collision with a not forgotten version.
254 if (backupAtt.IsNull()) {
255 TDF_Data_DeltaCreation
256 ("Removal(1)",
257 currentAtt->DeltaOnRemoval());
258 if (myNotUndoMode) currentAtt->BeforeRemoval();
259 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
260 currentIsRemoved = Standard_True;
261 attMod = Standard_True;
262 }
263 else {
264 // Modified then Forgotten...
265 // Forgotten flag spreading?
266 currentAtt->Resume();
267 currentAtt->Restore(backupAtt);
268 currentAtt->myTransaction = backupAtt->myTransaction;
269 currentAtt->RemoveBackup();
270 backupAtt = currentAtt->myBackup;
271 if (myTransaction == 1) {
272 TDF_Data_DeltaCreation
273 ("Removal(2)",
274 currentAtt->DeltaOnRemoval());
275 if (myNotUndoMode) currentAtt->BeforeRemoval();
276 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
277 currentIsRemoved = Standard_True;
278 }
279 else {
280 // BeforeForget has already been called once.
281 // if (myNotUndoMode) currentAtt->BeforeForget();
282 currentAtt->Forget(myTransaction-1);
283 TDF_Data_DeltaCreation
284 ("Forget(1)",
285 currentAtt->DeltaOnForget());
286 attMod = Standard_True;
287 }
288 }
289 }
290 else {
291 // Forgotten in lower transaction than the current one.
292 TDF_Data_DeltaCreation
293 ("Forget(2)",
294 aPtrCurrentAtt->DeltaOnForget());
295 }
296 }
297 // ---------------------------------------------------------- Resumed.
298 else if (aPtrCurrentAtt->mySavedTransaction < 0) {
299 TDF_Data_DeltaCreation
300 ("Resume",
301 aPtrCurrentAtt->DeltaOnResume());
302 aPtrCurrentAtt->mySavedTransaction = 0;
303 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
304 }
305
306 // ------------------------------------------------------------ Added.
307 else if (backupAtt.IsNull()) {
308 TDF_Data_DeltaCreation
309 ("Addition",
310 aPtrCurrentAtt->DeltaOnAddition());
311 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
312 }
313 // --------------------------------------------------------- Modified.
314 else {
315 const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity
316 TDF_Data_DeltaCreation
317 ("Modification",
318 anAttrPtr->DeltaOnModification(backupAtt));
319 if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
320 aPtrCurrentAtt->RemoveBackup();
321 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
322 }
323
324 }
325 else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
326
327 if (currentIsRemoved) currentIsRemoved = Standard_False;
328 else lastAtt = aPtrCurrentAtt;
329 }
330 aLabel.myLabelNode->AttributesModified(attMod);
331 }
332
333 // Iteration on the children to do the same!
334 //------------------------------------------
335 for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) {
336 #ifdef TDF_DATA_COMMIT_OPTIMIZED
337 if (itr2.Value().myLabelNode->MayBeModified())
338 #endif
339 nbTouchedAtt +=
340 TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
341 }
342
343 return nbTouchedAtt;
344 }
345
346
347 //=======================================================================
348 //function : AbortTransaction
349 //purpose : Aborts the current transaction.
350 //=======================================================================
351
AbortTransaction()352 void TDF_Data::AbortTransaction()
353 {
354 if (myTransaction>0)
355 Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
356 TDF_Data_DebugModified("New ABORT");
357 }
358
359
360 //=======================================================================
361 //function : AbortUntilTransaction
362 //purpose : Aborts the transactions until AND including the given index.
363 //=======================================================================
364
AbortUntilTransaction(const Standard_Integer untilTransaction)365 void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
366 {
367 if (untilTransaction>0)
368 Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
369 }
370
371
372 //=======================================================================
373 //function : IsApplicable
374 //purpose :
375 //=======================================================================
376
IsApplicable(const Handle (TDF_Delta)& aDelta) const377 Standard_Boolean TDF_Data::IsApplicable
378 (const Handle(TDF_Delta)& aDelta) const
379 {
380 return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
381 }
382
383 //=======================================================================
384 //function : FixOrder
385 //purpose :
386 //=======================================================================
FixOrder(const Handle (TDF_Delta)& theDelta)387 void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta)
388 {
389 // make all OnRemoval (which will cause addition of the attribute) are in the end
390 // to do not put two attributes with the same GUID at one label during undo/redo
391 TDF_AttributeDeltaList anOrderedList;
392
393 const TDF_AttributeDeltaList& attList = theDelta->AttributeDeltas();
394 TDF_ListIteratorOfAttributeDeltaList anIt(attList);
395 for (; anIt.More(); anIt.Next()) { // append not-removal
396 Handle(TDF_AttributeDelta) attDelta = anIt.Value();
397 if (!attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
398 anOrderedList.Append(attDelta);
399 }
400 }
401 for (anIt.Initialize(attList); anIt.More(); anIt.Next()) { // append removal
402 Handle(TDF_AttributeDelta) attDelta = anIt.Value();
403 if (attDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) {
404 anOrderedList.Append(attDelta);
405 }
406 }
407 theDelta->ReplaceDeltaList(anOrderedList);
408 }
409 //=======================================================================
410 //function : Undo
411 //purpose : Applies a delta to undo actions.
412 //=======================================================================
413
Handle(TDF_Delta)414 Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta,
415 const Standard_Boolean withDelta)
416 {
417 Handle(TDF_Delta) newDelta;
418 if (!aDelta.IsNull ()) {
419 if (aDelta->IsApplicable(myTime)) {
420 if (withDelta) OpenTransaction();
421 #ifdef OCCT_DEBUG_DELTA
422 std::cout<<"TDF_Data::Undo applies this delta:"<<std::endl;
423 aDelta->Dump(std::cout);
424 #endif
425 aDelta->BeforeOrAfterApply(Standard_True);
426 myNotUndoMode = Standard_False;
427 FixOrder(aDelta);
428 aDelta->Apply ();
429 myNotUndoMode = Standard_True;
430 if (withDelta) {
431 newDelta = CommitTransaction(Standard_True);
432 newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
433 #ifdef OCCT_DEBUG_DELTA
434 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 #endif
436 }
437 myTime = aDelta->BeginTime();
438 aDelta->BeforeOrAfterApply(Standard_False);
439 }
440 }
441 return newDelta;
442 }
443
444 //=======================================================================
445 //function : SetAccessByEntries
446 //purpose :
447 //=======================================================================
448
SetAccessByEntries(const Standard_Boolean aSet)449 void TDF_Data::SetAccessByEntries(const Standard_Boolean aSet)
450 {
451 myAccessByEntries = aSet;
452
453 myAccessByEntriesTable.Clear();
454 if (myAccessByEntries) {
455 // Add root label.
456 TCollection_AsciiString anEntry;
457 TDF_Tool::Entry (myRoot, anEntry);
458 myAccessByEntriesTable.Bind (anEntry, myRoot);
459
460 // Add all other labels.
461 TDF_ChildIterator itr (myRoot, Standard_True);
462 for (; itr.More(); itr.Next()) {
463 const TDF_Label aLabel = itr.Value();
464 TDF_Tool::Entry (aLabel, anEntry);
465 myAccessByEntriesTable.Bind (anEntry, aLabel);
466 }
467 }
468 }
469
470 //=======================================================================
471 //function : RegisterLabel
472 //purpose :
473 //=======================================================================
474
RegisterLabel(const TDF_Label & aLabel)475 void TDF_Data::RegisterLabel(const TDF_Label& aLabel)
476 {
477 TCollection_AsciiString anEntry;
478 TDF_Tool::Entry (aLabel, anEntry);
479 myAccessByEntriesTable.Bind (anEntry, aLabel);
480 }
481
482 //=======================================================================
483 //function : Dump
484 //purpose :
485 //=======================================================================
486
Dump(Standard_OStream & anOS) const487 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
488 {
489 anOS<<"Dump of a TDF_Data."<<std::endl;
490 anOS<<"Current transaction: "<<myTransaction;
491 anOS<<"; Current tick: "<<myTime<<";"<<std::endl;
492 return anOS;
493 }
494
495 //=======================================================================
496 //function : DumpJson
497 //purpose :
498 //=======================================================================
DumpJson(Standard_OStream & theOStream,Standard_Integer) const499 void TDF_Data::DumpJson (Standard_OStream& theOStream, Standard_Integer /*theDepth*/) const
500 {
501 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
502
503 TCollection_AsciiString aStrForTDF_Label;
504 TDF_Tool::Entry (myRoot, aStrForTDF_Label);
505 OCCT_DUMP_FIELD_VALUE_STRING (theOStream, aStrForTDF_Label)
506
507 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTransaction)
508 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbTouchedAtt)
509 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNotUndoMode)
510 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTime)
511 for (TColStd_ListOfInteger::Iterator aTimeIt (myTimes); aTimeIt.More(); aTimeIt.Next())
512 {
513 const Standard_Integer aTime = aTimeIt.Value();
514 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aTime)
515 }
516 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowModification)
517 }
518