44e103c456f74166501edc3abd27c7c79cf1665b
[occt.git] / src / TDF / TDF_Data.cxx
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
45 IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,Standard_Transient)
46
47 #undef DEB_DELTA_CREATION
48 #undef 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 {
99   const Handle(NCollection_IncAllocator) anIncAllocator=
100     new NCollection_IncAllocator (16000);
101   myLabelNodeAllocator = anIncAllocator;
102   myRoot = new (anIncAllocator) TDF_LabelNode (this);
103 }
104
105 //=======================================================================
106 //function : Destroy
107 //purpose  : Used to implement the destructor ~.
108 //=======================================================================
109
110 void TDF_Data::Destroy()
111 {
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);
120   }
121   myRoot->Destroy (myLabelNodeAllocator);
122   myRoot = NULL;
123 }
124
125
126 //=======================================================================
127 //function : OpenTransaction
128 //purpose  : 
129 //=======================================================================
130
131 Standard_Integer TDF_Data::OpenTransaction() 
132 {
133   myTimes.Prepend(myTime);
134   return ++myTransaction;
135 }
136
137
138 //=======================================================================
139 //function : CommitTransaction
140 //purpose  : Commits the current transaction.
141 //=======================================================================
142
143 Handle(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();
149 #ifdef OCCT_DEBUG_DELTA
150     std::cout<<"TDF_Data::Begin Commit #"<<myTransaction<<std::endl;    
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()) {
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);
168         }
169 #endif
170       }
171 #ifdef OCCT_DEBUG_DELTA
172       else {
173         if (myTransaction == 0)
174           std::cout<<"TDF_Data::Commit generated NO delta."<<std::endl;
175       }
176 #endif
177     }
178     myTimes.RemoveFirst();
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
191 Handle(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
211 Standard_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()) {
232       Handle(TDF_Attribute) aPtrCurrentAtt = itr1.Value();
233       itr1.Next();
234       //      currentAtt = itr1.Value();
235
236       // A callback:
237       aPtrCurrentAtt->BeforeCommitTransaction();
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 {
313           const TDF_Attribute* anAttrPtr = aPtrCurrentAtt.operator->(); // to avoid ambiguity
314           TDF_Data_DeltaCreation
315             ("Modification",
316              anAttrPtr->DeltaOnModification(backupAtt));
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
350 void 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
363 void 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
375 Standard_Boolean TDF_Data::IsApplicable
376 (const Handle(TDF_Delta)& aDelta) const
377 {
378   return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
379 }
380
381 //=======================================================================
382 //function : FixOrder
383 //purpose  : 
384 //=======================================================================
385 void TDF_Data::FixOrder(const Handle(TDF_Delta)& theDelta)
386 {
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
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);
397     }
398   }
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     }
404   }
405   theDelta->ReplaceDeltaList(anOrderedList);
406 }
407 //=======================================================================
408 //function : Undo
409 //purpose  : Applies a delta to undo  actions.
410 //=======================================================================
411
412 Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta,
413                                  const Standard_Boolean withDelta)
414 {
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);
422 #endif
423       aDelta->BeforeOrAfterApply(Standard_True);
424       myNotUndoMode = Standard_False;
425       FixOrder(aDelta);
426       aDelta->Apply ();
427       myNotUndoMode = Standard_True;
428       if (withDelta) {
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;
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
449 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
450 {
451   anOS<<"Dump of a TDF_Data."<<std::endl;
452   anOS<<"Current transaction: "<<myTransaction;
453   anOS<<"; Current tick: "<<myTime<<";"<<std::endl;
454   return anOS;
455 }
456
457 //=======================================================================
458 //function : DumpJson
459 //purpose  : 
460 //=======================================================================
461 void 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 }