252a0ab934039ff629d8153060d3c723dadc8970
[occt.git] / src / TDF / TDF_Data.cxx
1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 //              -------------
21
22 // Version:     0.0
23 //Version Date            Purpose
24 //              0.0     Feb  6 1997     Creation
25
26
27
28 #include <TDF_Data.ixx>
29
30 #include <TCollection_AsciiString.hxx>
31
32 #include <TDF_Attribute.hxx>
33 #include <TDF_AttributeIterator.hxx>
34 #include <TDF_AttributeIndexedMap.hxx>
35 #include <TDF_ChildIterator.hxx>
36 #include <TDF_Delta.hxx>
37 #include <TDF_AttributeDelta.hxx>
38 #include <TDF_DeltaOnAddition.hxx>
39 #include <TDF_DeltaOnForget.hxx>
40 #include <TDF_DeltaOnModification.hxx>
41 #include <TDF_DeltaOnRemoval.hxx>
42 #include <TDF_DeltaOnResume.hxx>
43 #include <TDF_Label.hxx>
44 #include <TDF_LabelNode.hxx>
45 #include <TDF_LabelNodePtr.hxx>
46 #include <TDF_Tool.hxx>
47
48 #include <Standard_NoMoreObject.hxx>
49 #include <Standard_NullObject.hxx>
50
51 #undef DEB_DELTA_CREATION
52 #undef TDF_DATA_COMMIT_OPTIMIZED
53
54 #define BUC60879
55
56 #ifdef DEB_DELTA
57 #define TDF_Data_DebugModified(ACTION) \
58   cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<endl; \
59 if (!myTransaction) { \
60   TCollection_AsciiString entry; \
61   for (TDF_ChildIterator itr(Root(),Standard_True); itr.More(); itr.Next()) { \
62     const TDF_LabelNode* lnp = itr.Value().myLabelNode; \
63     if (lnp->AttributesModified() || lnp->MayBeModified()) { \
64       TDF_Tool::Entry(itr.Value(),entry); \
65       cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
66       if (lnp->AttributesModified()) cout<<"AttributesModified "; \
67       if (lnp->MayBeModified()) cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
68       cout<<endl; \
69       cout<<itr.Value()<<endl; \
70       entry.Clear(); \
71     }}}
72 #else
73 #define TDF_Data_DebugModified(ACTION)
74 #endif
75
76 #ifdef DEB_DELTA_CREATION
77 #define TDF_DataDebugDeltaCreation(DELTATYPE) \
78 { \
79 TCollection_AsciiString entry; \
80 TDF_Tool::Entry(currentAtt->Label(),entry); \
81 cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<endl; \
82 }
83 #else
84 #define TDF_DataDebugDeltaCreation(DELTATYPE)
85 #endif
86
87 #define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
88 if (withDelta) { \
89   TDF_DataDebugDeltaCreation(DELTACOMMENT); \
90   aDelta->AddAttributeDelta(DELTACREATION); \
91 }
92
93 //=======================================================================
94 //function : TDF_Data
95 //purpose  : empty constructor
96 //=======================================================================
97
98 TDF_Data::TDF_Data() :
99 myTransaction           (0),
100 myNbTouchedAtt          (0),
101 myNotUndoMode           (Standard_True),
102 myTime                  (0),
103 myAllowModification     (Standard_True)
104 {
105   const Handle(NCollection_IncAllocator) anIncAllocator=
106     new NCollection_IncAllocator (16000);
107   myLabelNodeAllocator = anIncAllocator;
108   myRoot = new (anIncAllocator) TDF_LabelNode (this);
109 }
110
111 //=======================================================================
112 //function : Destroy
113 //purpose  : Used to implement the destructor ~.
114 //=======================================================================
115
116 void TDF_Data::Destroy()
117 {
118   AbortUntilTransaction(1);
119   delete myRoot;
120 }
121
122
123 //=======================================================================
124 //function : OpenTransaction
125 //purpose  : 
126 //=======================================================================
127
128 Standard_Integer TDF_Data::OpenTransaction() 
129 {
130   myTimes.Push(myTime);
131   return ++myTransaction;
132 }
133
134
135 //=======================================================================
136 //function : CommitTransaction
137 //purpose  : Commits the current transaction.
138 //=======================================================================
139
140 Handle(TDF_Delta) TDF_Data::CommitTransaction
141 (const Standard_Boolean withDelta) 
142 {
143   Handle(TDF_Delta) delta;
144   if (myTransaction>0) {
145     if (withDelta) delta = new TDF_Delta();
146 #ifdef DEB_DELTA
147     cout<<"TDF_Data::Begin Commit #"<<myTransaction<<endl;    
148 #endif
149 #ifdef TDF_DATA_COMMIT_OPTIMIZED
150     myNbTouchedAtt = 0;
151     if (Root().myLabelNode->MayBeModified())
152 #endif
153       myNbTouchedAtt =
154         TDF_Data::CommitTransaction(Root(),delta,withDelta);
155
156     if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
157     --myTransaction;
158     if (withDelta) {
159       if (!delta->IsEmpty()) {
160         delta->Validity(myTimes.Top(),myTime);
161 #ifdef DEB_DELTA
162         if (myTransaction == 0) {
163           cout<<"TDF_Data::Commit generated this delta in t=0:"<<endl;
164           delta->Dump(cout);
165         }
166 #endif
167       }
168 #ifdef DEB_DELTA
169       else {
170         if (myTransaction == 0)
171           cout<<"TDF_Data::Commit generated NO delta."<<endl;
172       }
173 #endif
174     }
175     myTimes.Pop();
176   }
177   TDF_Data_DebugModified("COMMIT");
178   return delta;
179 }
180
181
182 //=======================================================================
183 //function : CommitUntilTransaction
184 //purpose  : Commits the transactions until AND including
185 //           the given transaction index.
186 //=======================================================================
187
188 Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
189 (const Standard_Integer untilTransaction,
190  const Standard_Boolean withDelta)
191 {
192   Handle(TDF_Delta) delta;
193   if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
194     while (myTransaction > untilTransaction) {
195       delta = TDF_Data::CommitTransaction(Standard_False);
196     }
197     delta = TDF_Data::CommitTransaction(withDelta);
198   }
199   return delta;
200 }
201
202
203 //=======================================================================
204 //function : CommitTransaction
205 //purpose  : Recursive method used to implement the commit action.
206 //=======================================================================
207
208 Standard_Integer TDF_Data::CommitTransaction
209 (const TDF_Label& aLabel,
210  const Handle(TDF_Delta)& aDelta,
211  const Standard_Boolean withDelta)
212 {
213   aLabel.myLabelNode->MayBeModified(Standard_False);
214   Standard_Integer nbTouchedAtt = 0;
215 #ifdef TDF_DATA_COMMIT_OPTIMIZED
216   Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
217 #else
218   Standard_Boolean attMod = Standard_True;
219 #endif
220
221   if (attMod) {
222     Handle(TDF_Attribute)    lastAtt;
223     Handle(TDF_Attribute)  backupAtt;
224     Standard_Boolean currentIsRemoved = Standard_False;
225     attMod = Standard_False;
226
227     TDF_AttributeIterator itr1(aLabel, Standard_False);
228     while (itr1.More()) {
229       TDF_Attribute * aPtrCurrentAtt = itr1.Value();
230       itr1.Next();
231       //      currentAtt = itr1.Value();
232
233 #ifdef BUC60879
234       // A callback:
235       aPtrCurrentAtt->BeforeCommitTransaction();
236 #endif
237
238       backupAtt  = aPtrCurrentAtt->myBackup;
239
240       if (aPtrCurrentAtt->myTransaction == myTransaction) {
241         ++nbTouchedAtt;
242         --(aPtrCurrentAtt->myTransaction);
243
244         // ------------------------------------------------------- Forgotten
245         if (aPtrCurrentAtt->IsForgotten()) {
246           if (aPtrCurrentAtt->mySavedTransaction >=
247               aPtrCurrentAtt->myTransaction)
248           {
249             const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
250             // Collision with a not forgotten version.
251             if (backupAtt.IsNull()) {
252               TDF_Data_DeltaCreation
253                 ("Removal(1)",
254                  currentAtt->DeltaOnRemoval());
255               if (myNotUndoMode) currentAtt->BeforeRemoval();
256               aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
257               currentIsRemoved = Standard_True;
258               attMod = Standard_True;
259             }
260             else {
261               // Modified then Forgotten...
262               // Forgotten flag spreading?
263               currentAtt->Resume();
264               currentAtt->Restore(backupAtt);
265               currentAtt->myTransaction = backupAtt->myTransaction;
266               currentAtt->RemoveBackup();
267               backupAtt = currentAtt->myBackup;
268               if (myTransaction == 1) {
269                 TDF_Data_DeltaCreation
270                   ("Removal(2)",
271                    currentAtt->DeltaOnRemoval());
272                 if (myNotUndoMode) currentAtt->BeforeRemoval();
273                 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
274                 currentIsRemoved = Standard_True;
275               }
276               else {
277                 // BeforeForget has already been called once.
278                 // if (myNotUndoMode) currentAtt->BeforeForget();
279                 currentAtt->Forget(myTransaction-1);
280                 TDF_Data_DeltaCreation
281                   ("Forget(1)",
282                    currentAtt->DeltaOnForget());
283                 attMod = Standard_True;
284               }
285             }
286           }
287           else {
288             // Forgotten in lower transaction than the current one.
289             TDF_Data_DeltaCreation
290               ("Forget(2)",
291                aPtrCurrentAtt->DeltaOnForget());
292           }
293         }
294         // ---------------------------------------------------------- Resumed.
295         else if (aPtrCurrentAtt->mySavedTransaction < 0) {
296           TDF_Data_DeltaCreation
297             ("Resume",
298              aPtrCurrentAtt->DeltaOnResume());
299           aPtrCurrentAtt->mySavedTransaction = 0;
300           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
301         }
302
303         // ------------------------------------------------------------ Added.
304         else if (backupAtt.IsNull()) {
305           TDF_Data_DeltaCreation
306             ("Addition",
307              aPtrCurrentAtt->DeltaOnAddition());
308           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
309         }
310         // --------------------------------------------------------- Modified.
311         else {
312           TDF_Data_DeltaCreation
313             ("Modification",
314              aPtrCurrentAtt->DeltaOnModification(backupAtt));
315           if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
316             aPtrCurrentAtt->RemoveBackup();
317           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
318         }
319
320       }
321       else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
322
323       if (currentIsRemoved) currentIsRemoved = Standard_False;
324       else lastAtt = aPtrCurrentAtt;
325     }
326     aLabel.myLabelNode->AttributesModified(attMod);
327   }
328
329   // Iteration on the children to do the same!
330   //------------------------------------------
331   for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) {
332 #ifdef TDF_DATA_COMMIT_OPTIMIZED
333     if (itr2.Value().myLabelNode->MayBeModified())
334 #endif
335       nbTouchedAtt +=
336         TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
337   }
338
339   return nbTouchedAtt;
340 }
341
342
343 //=======================================================================
344 //function : AbortTransaction
345 //purpose  : Aborts the current transaction.
346 //=======================================================================
347
348 void TDF_Data::AbortTransaction() 
349 {
350   if (myTransaction>0)
351     Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
352   TDF_Data_DebugModified("New ABORT");
353 }
354
355
356 //=======================================================================
357 //function : AbortUntilTransaction
358 //purpose  : Aborts the transactions until AND including the given index.
359 //=======================================================================
360
361 void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
362 {
363   if (untilTransaction>0)
364     Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
365 }
366
367
368 //=======================================================================
369 //function : IsApplicable
370 //purpose  : 
371 //=======================================================================
372
373 Standard_Boolean TDF_Data::IsApplicable
374 (const Handle(TDF_Delta)& aDelta) const
375 {
376   return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
377 }
378
379
380 //=======================================================================
381 //function : Undo
382 //purpose  : Applies a delta to undo  actions.
383 //=======================================================================
384
385 Handle(TDF_Delta) TDF_Data::Undo
386 (const Handle(TDF_Delta)& aDelta,
387  const Standard_Boolean withDelta)
388 {
389   Handle(TDF_Delta) newDelta;
390   if (!aDelta.IsNull ()) {
391     if (aDelta->IsApplicable(myTime)) {
392       if (withDelta) OpenTransaction();
393 #ifdef DEB_DELTA
394       cout<<"TDF_Data::Undo applies this delta:"<<endl;
395       aDelta->Dump(cout);
396 #endif
397       aDelta->BeforeOrAfterApply(Standard_True);
398       myNotUndoMode = Standard_False;
399       aDelta->Apply ();
400       myNotUndoMode = Standard_True;
401       if (withDelta) {
402         newDelta = CommitTransaction(Standard_True);
403         newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
404 #ifdef DEB_DELTA
405         cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<endl;
406 #endif
407       }
408       myTime = aDelta->BeginTime();
409       aDelta->BeforeOrAfterApply(Standard_False);
410     }
411   }
412   return newDelta;
413 }
414
415
416
417 //=======================================================================
418 //function : Dump
419 //purpose  : 
420 //=======================================================================
421
422 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
423 {
424   anOS<<"Dump of a TDF_Data."<<endl;
425   anOS<<"Current transaction: "<<myTransaction;
426   anOS<<"; Current tick: "<<myTime<<";"<<endl;
427   return anOS;
428 }