0031075: Application Framework - reading STEP file into TDocStd_Document leads to...
[occt.git] / src / TDF / TDF_Data.cxx
CommitLineData
b311480e 1// Created by: DAUTRY Philippe
2// Copyright (c) 1997-1999 Matra Datavision
973c2be1 3// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
7fd59977 16
42cf5bc1 17#include <NCollection_IncAllocator.hxx>
bc73b006 18#include <Standard_Dump.hxx>
42cf5bc1 19#include <Standard_NoMoreObject.hxx>
20#include <Standard_NullObject.hxx>
21#include <Standard_Type.hxx>
a7378539 22#include <Standard_GUID.hxx>
23#include <NCollection_Array1.hxx>
7fd59977 24#include <TCollection_AsciiString.hxx>
7fd59977 25#include <TDF_Attribute.hxx>
42cf5bc1 26#include <TDF_AttributeDelta.hxx>
7fd59977 27#include <TDF_AttributeIndexedMap.hxx>
42cf5bc1 28#include <TDF_AttributeIterator.hxx>
7fd59977 29#include <TDF_ChildIterator.hxx>
42cf5bc1 30#include <TDF_Data.hxx>
7fd59977 31#include <TDF_Delta.hxx>
7fd59977 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>
42cf5bc1 41#include <TDF_Transaction.hxx>
60d4560d 42
a7378539 43typedef NCollection_Array1<Handle(TDF_AttributeDelta)> TDF_Array1OfAttributeIDelta;
44
25e59720 45IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)
92efcf78 46
7fd59977 47#undef DEB_DELTA_CREATION
48#undef TDF_DATA_COMMIT_OPTIMIZED
49
0797d9d3 50#ifdef OCCT_DEBUG_DELTA
7fd59977 51#define TDF_Data_DebugModified(ACTION) \
04232180 52 std::cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<std::endl; \
7fd59977 53if (!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); \
04232180 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; \
7fd59977 64 entry.Clear(); \
65 }}}
66#else
67#define TDF_Data_DebugModified(ACTION)
68#endif
69
0797d9d3 70#ifdef OCCT_DEBUG_DELTA_CREATION
7fd59977 71#define TDF_DataDebugDeltaCreation(DELTATYPE) \
72{ \
73TCollection_AsciiString entry; \
74TDF_Tool::Entry(currentAtt->Label(),entry); \
04232180 75std::cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<std::endl; \
7fd59977 76}
77#else
78#define TDF_DataDebugDeltaCreation(DELTATYPE)
79#endif
80
81#define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
82if (withDelta) { \
83 TDF_DataDebugDeltaCreation(DELTACOMMENT); \
84 aDelta->AddAttributeDelta(DELTACREATION); \
85}
86
7fd59977 87//=======================================================================
88//function : TDF_Data
89//purpose : empty constructor
90//=======================================================================
91
92TDF_Data::TDF_Data() :
93myTransaction (0),
94myNbTouchedAtt (0),
95myNotUndoMode (Standard_True),
96myTime (0),
97myAllowModification (Standard_True)
98{
99 const Handle(NCollection_IncAllocator) anIncAllocator=
100 new NCollection_IncAllocator (16000);
101 myLabelNodeAllocator = anIncAllocator;
102 myRoot = new (anIncAllocator) TDF_LabelNode (this);
103}
104
7fd59977 105//=======================================================================
106//function : Destroy
107//purpose : Used to implement the destructor ~.
108//=======================================================================
109
110void TDF_Data::Destroy()
111{
112 AbortUntilTransaction(1);
ef779ae0 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);
120 }
60d4560d 121 myRoot->Destroy (myLabelNodeAllocator);
122 myRoot = NULL;
7fd59977 123}
124
125
126//=======================================================================
127//function : OpenTransaction
128//purpose :
129//=======================================================================
130
131Standard_Integer TDF_Data::OpenTransaction()
132{
6af4fe1c 133 myTimes.Prepend(myTime);
7fd59977 134 return ++myTransaction;
135}
136
137
138//=======================================================================
139//function : CommitTransaction
140//purpose : Commits the current transaction.
141//=======================================================================
142
143Handle(TDF_Delta) TDF_Data::CommitTransaction
144(const Standard_Boolean withDelta)
145{
146 Handle(TDF_Delta) delta;
147 if (myTransaction>0) {
148 if (withDelta) delta = new TDF_Delta();
0797d9d3 149#ifdef OCCT_DEBUG_DELTA
04232180 150 std::cout<<"TDF_Data::Begin Commit #"<<myTransaction<<std::endl;
7fd59977 151#endif
152#ifdef TDF_DATA_COMMIT_OPTIMIZED
153 myNbTouchedAtt = 0;
154 if (Root().myLabelNode->MayBeModified())
155#endif
156 myNbTouchedAtt =
157 TDF_Data::CommitTransaction(Root(),delta,withDelta);
158
159 if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
160 --myTransaction;
161 if (withDelta) {
162 if (!delta->IsEmpty()) {
6af4fe1c 163 delta->Validity(myTimes.First(),myTime);
0797d9d3 164#ifdef OCCT_DEBUG_DELTA
7fd59977 165 if (myTransaction == 0) {
04232180 166 std::cout<<"TDF_Data::Commit generated this delta in t=0:"<<std::endl;
167 delta->Dump(std::cout);
7fd59977 168 }
169#endif
170 }
0797d9d3 171#ifdef OCCT_DEBUG_DELTA
7fd59977 172 else {
173 if (myTransaction == 0)
04232180 174 std::cout<<"TDF_Data::Commit generated NO delta."<<std::endl;
7fd59977 175 }
176#endif
177 }
6af4fe1c 178 myTimes.RemoveFirst();
7fd59977 179 }
180 TDF_Data_DebugModified("COMMIT");
181 return delta;
182}
183
184
185//=======================================================================
186//function : CommitUntilTransaction
187//purpose : Commits the transactions until AND including
188// the given transaction index.
189//=======================================================================
190
191Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
192(const Standard_Integer untilTransaction,
193 const Standard_Boolean withDelta)
194{
195 Handle(TDF_Delta) delta;
196 if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
197 while (myTransaction > untilTransaction) {
198 delta = TDF_Data::CommitTransaction(Standard_False);
199 }
200 delta = TDF_Data::CommitTransaction(withDelta);
201 }
202 return delta;
203}
204
205
206//=======================================================================
207//function : CommitTransaction
208//purpose : Recursive method used to implement the commit action.
209//=======================================================================
210
211Standard_Integer TDF_Data::CommitTransaction
212(const TDF_Label& aLabel,
213 const Handle(TDF_Delta)& aDelta,
214 const Standard_Boolean withDelta)
215{
216 aLabel.myLabelNode->MayBeModified(Standard_False);
217 Standard_Integer nbTouchedAtt = 0;
218#ifdef TDF_DATA_COMMIT_OPTIMIZED
219 Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
220#else
221 Standard_Boolean attMod = Standard_True;
222#endif
223
224 if (attMod) {
225 Handle(TDF_Attribute) lastAtt;
226 Handle(TDF_Attribute) backupAtt;
227 Standard_Boolean currentIsRemoved = Standard_False;
228 attMod = Standard_False;
229
230 TDF_AttributeIterator itr1(aLabel, Standard_False);
231 while (itr1.More()) {
fe4f17f0 232 Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value();
7fd59977 233 itr1.Next();
234 // currentAtt = itr1.Value();
235
7fd59977 236 // A callback:
237 aPtrCurrentAtt->BeforeCommitTransaction();
7fd59977 238
239 backupAtt = aPtrCurrentAtt->myBackup;
240
241 if (aPtrCurrentAtt->myTransaction == myTransaction) {
242 ++nbTouchedAtt;
243 --(aPtrCurrentAtt->myTransaction);
244
245 // ------------------------------------------------------- Forgotten
246 if (aPtrCurrentAtt->IsForgotten()) {
247 if (aPtrCurrentAtt->mySavedTransaction >=
248 aPtrCurrentAtt->myTransaction)
249 {
250 const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
251 // Collision with a not forgotten version.
252 if (backupAtt.IsNull()) {
253 TDF_Data_DeltaCreation
254 ("Removal(1)",
255 currentAtt->DeltaOnRemoval());
256 if (myNotUndoMode) currentAtt->BeforeRemoval();
257 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
258 currentIsRemoved = Standard_True;
259 attMod = Standard_True;
260 }
261 else {
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
271 ("Removal(2)",
272 currentAtt->DeltaOnRemoval());
273 if (myNotUndoMode) currentAtt->BeforeRemoval();
274 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
275 currentIsRemoved = Standard_True;
276 }
277 else {
278 // BeforeForget has already been called once.
279 // if (myNotUndoMode) currentAtt->BeforeForget();
280 currentAtt->Forget(myTransaction-1);
281 TDF_Data_DeltaCreation
282 ("Forget(1)",
283 currentAtt->DeltaOnForget());
284 attMod = Standard_True;
285 }
286 }
287 }
288 else {
289 // Forgotten in lower transaction than the current one.
290 TDF_Data_DeltaCreation
291 ("Forget(2)",
292 aPtrCurrentAtt->DeltaOnForget());
293 }
294 }
295 // ---------------------------------------------------------- Resumed.
296 else if (aPtrCurrentAtt->mySavedTransaction < 0) {
297 TDF_Data_DeltaCreation
298 ("Resume",
299 aPtrCurrentAtt->DeltaOnResume());
300 aPtrCurrentAtt->mySavedTransaction = 0;
301 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
302 }
303
304 // ------------------------------------------------------------ Added.
305 else if (backupAtt.IsNull()) {
306 TDF_Data_DeltaCreation
307 ("Addition",
308 aPtrCurrentAtt->DeltaOnAddition());
309 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
310 }
311 // --------------------------------------------------------- Modified.
312 else {
fe4f17f0 313 const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity
7fd59977 314 TDF_Data_DeltaCreation
315 ("Modification",
543a9964 316 anAttrPtr->DeltaOnModification(backupAtt));
7fd59977 317 if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
318 aPtrCurrentAtt->RemoveBackup();
319 attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
320 }
321
322 }
323 else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
324
325 if (currentIsRemoved) currentIsRemoved = Standard_False;
326 else lastAtt = aPtrCurrentAtt;
327 }
328 aLabel.myLabelNode->AttributesModified(attMod);
329 }
330
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())
336#endif
337 nbTouchedAtt +=
338 TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
339 }
340
341 return nbTouchedAtt;
342}
343
344
345//=======================================================================
346//function : AbortTransaction
347//purpose : Aborts the current transaction.
348//=======================================================================
349
350void TDF_Data::AbortTransaction()
351{
352 if (myTransaction>0)
353 Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
354 TDF_Data_DebugModified("New ABORT");
355}
356
357
358//=======================================================================
359//function : AbortUntilTransaction
360//purpose : Aborts the transactions until AND including the given index.
361//=======================================================================
362
363void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
364{
365 if (untilTransaction>0)
366 Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
367}
368
369
370//=======================================================================
371//function : IsApplicable
372//purpose :
373//=======================================================================
374
375Standard_Boolean TDF_Data::IsApplicable
376(const Handle(TDF_Delta)& aDelta) const
377{
378 return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
379}
380
a7378539 381//=======================================================================
382//function : FixOrder
383//purpose :
384//=======================================================================
385void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta)
386{
f46c2b39 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;
390
a7378539 391 const TDF_AttributeDeltaList& attList = theDelta->AttributeDeltas();
f46c2b39 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);
397 }
a7378539 398 }
f46c2b39 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);
403 }
a7378539 404 }
f46c2b39 405 theDelta->ReplaceDeltaList(anOrderedList);
a7378539 406}
7fd59977 407//=======================================================================
408//function : Undo
409//purpose : Applies a delta to undo actions.
410//=======================================================================
411
a7378539 412Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta,
413 const Standard_Boolean withDelta)
7fd59977 414{
415 Handle(TDF_Delta) newDelta;
416 if (!aDelta.IsNull ()) {
417 if (aDelta->IsApplicable(myTime)) {
418 if (withDelta) OpenTransaction();
0797d9d3 419#ifdef OCCT_DEBUG_DELTA
04232180 420 std::cout<<"TDF_Data::Undo applies this delta:"<<std::endl;
421 aDelta->Dump(std::cout);
7fd59977 422#endif
423 aDelta->BeforeOrAfterApply(Standard_True);
424 myNotUndoMode = Standard_False;
a7378539 425 FixOrder(aDelta);
7fd59977 426 aDelta->Apply ();
427 myNotUndoMode = Standard_True;
428 if (withDelta) {
429 newDelta = CommitTransaction(Standard_True);
430 newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
0797d9d3 431#ifdef OCCT_DEBUG_DELTA
04232180 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;
7fd59977 433#endif
434 }
435 myTime = aDelta->BeginTime();
436 aDelta->BeforeOrAfterApply(Standard_False);
437 }
438 }
439 return newDelta;
440}
441
442
443
444//=======================================================================
445//function : Dump
446//purpose :
447//=======================================================================
448
449Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
450{
04232180 451 anOS<<"Dump of a TDF_Data."<<std::endl;
7fd59977 452 anOS<<"Current transaction: "<<myTransaction;
04232180 453 anOS<<"; Current tick: "<<myTime<<";"<<std::endl;
7fd59977 454 return anOS;
455}
bc73b006 456
457//=======================================================================
458//function : DumpJson
459//purpose :
460//=======================================================================
461void TDF_Data::DumpJson (Standard_OStream& theOStream, Standard_Integer /*theDepth*/) const
462{
463 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
464
465 TCollection_AsciiString aStrForTDF_Label;
466 TDF_Tool::Entry (myRoot, aStrForTDF_Label);
467 OCCT_DUMP_FIELD_VALUE_STRING (theOStream, aStrForTDF_Label)
468
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())
474 {
475 const Standard_Integer aTime = aTimeIt.Value();
476 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aTime)
477 }
478 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowModification)
479}