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