Integration of OCCT 6.5.0 from SVN
[occt.git] / src / TDF / TDF_Label.cxx
1 // File:        TDF_Label.cxx
2 //              --------------
3 // Author:      DAUTRY Philippe
4 //              <fid@fox.paris1.matra-dtv.fr>
5 // Copyright:   Matra Datavision 1997
6
7 // Version:     0.0
8 // History:     Version Date            Purpose
9 //              0.0     Feb  6 1997     Creation
10
11
12
13 #include <TDF_Label.ixx>
14
15 #include <TDF_Attribute.hxx>
16 #include <TDF_AttributeIterator.hxx>
17 #include <TDF_ChildIterator.hxx>
18 #include <TDF_Data.hxx>
19 #include <TDF_LabelNode.hxx>
20 #include <TDF_LabelNodePtr.hxx>
21 #include <TDF_Tool.hxx>
22 #include <TCollection_AsciiString.hxx>
23 #include <Standard_ImmutableObject.hxx>
24
25
26 //=======================================================================
27 //function : TDF_Label
28 //purpose  : 
29 //=======================================================================
30
31 TDF_Label::TDF_Label()
32 :myLabelNode(NULL)
33 {}
34
35 //=======================================================================
36 //function : TDF_Label
37 //purpose  : 
38 //=======================================================================
39
40 TDF_Label::TDF_Label(const TDF_LabelNodePtr& aNode)
41 :myLabelNode(aNode)
42 {}
43
44 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
45
46
47 //=======================================================================
48 //function : Imported
49 //purpose  : Sets imported and all its descendants.
50 //=======================================================================
51
52 void TDF_Label::Imported(const Standard_Boolean aStatus) const
53 {
54   if (IsNull()) Standard_NullObject::Raise("A null Label has no status.");
55   if (myLabelNode->IsImported() != aStatus) {
56     myLabelNode->Imported(aStatus);
57     for (TDF_ChildIterator itr(*this, Standard_True);
58          itr.More(); itr.Next())
59       itr.Value().myLabelNode->Imported(aStatus);
60   }
61 }
62
63
64 //=======================================================================
65 //function : FindAttribute
66 //purpose  : Finds an attributes according to an ID.
67 //=======================================================================
68
69 Standard_Boolean TDF_Label::FindAttribute
70 (const Standard_GUID& anID,
71  Handle(TDF_Attribute)& anAttribute) const
72 {
73   if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
74   TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
75   for ( ; itr.More(); itr.Next()) {
76     if (itr.Value()->ID() == anID) {
77       anAttribute = itr.Value();
78       return Standard_True;
79     }
80   }
81   return Standard_False;
82 }
83
84
85 //=======================================================================
86 //function : FindAttribute
87 //purpose  : Finds an attributes according to an ID and a Transaction.
88 //=======================================================================
89
90 Standard_Boolean TDF_Label::FindAttribute
91 (const Standard_GUID& anID,
92  const Standard_Integer aTransaction,
93  Handle(TDF_Attribute)& anAttribute) const
94 {
95   Handle(TDF_Attribute) locAtt;
96   if (FindAttribute(anID, locAtt)) {
97     while ((!locAtt.IsNull()) && (locAtt->myTransaction > aTransaction))
98       locAtt = locAtt->myBackup;
99     if (!locAtt.IsNull()) {
100       anAttribute = locAtt;
101       return Standard_True;
102     }
103   }
104   return Standard_False;
105 }
106
107 // Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
108
109 //=======================================================================
110 //function : Depth
111 //purpose  : Returns the depth of the label in the tree.
112 //           Root has depth 0. So the depth is the number of fathers.
113 //=======================================================================
114
115 Standard_Integer TDF_Label::Depth() const
116 {
117   if (IsNull()) Standard_NullObject::Raise("A null Label has no depth.");
118   return myLabelNode->Depth();
119 }
120
121
122 //=======================================================================
123 //function : IsDescendant
124 //purpose  : Returns True if <me> is a descendant of <aLabel>.
125 //=======================================================================
126
127 Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
128 {
129   // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
130   // si la profondeur atteinte est inferieure a celle de <aLabel>.
131
132   const TDF_LabelNode* lp1 = aLabel.myLabelNode;
133   TDF_LabelNode*   lp2 = myLabelNode;
134 #ifdef DEB
135   if ((lp1 == NULL) || (lp2 == NULL))
136     Standard_NullObject::Raise("A null label has no ancestor nor descendant.");
137 #endif
138   if ((lp1 != NULL) && (lp2 != NULL)) {
139     const Standard_Integer d1 = lp1->Depth();
140     Standard_Integer d2  = lp2->Depth();
141     // Tester (d1 > d2) optimise la recherche ET dispense du test (lp2 != NULL)
142     while ((d2 > d1) && (lp2 != lp1)) {
143       lp2 = lp2->Father();
144       d2  = lp2->Depth();
145     }
146     return (lp1 == lp2);
147   }
148   return Standard_False;
149 }
150
151
152 //=======================================================================
153 //function : Root
154 //purpose  : 
155 //=======================================================================
156
157 const TDF_Label TDF_Label::Root() const
158 {
159   if (IsNull()) Standard_NullObject::Raise("A null Label has no root.");
160   return myLabelNode->RootNode();
161 }
162
163
164 //=======================================================================
165 //function : NbChildren
166 //purpose  : Returns the number of children.
167 //=======================================================================
168
169 Standard_Integer TDF_Label::NbChildren() const
170 {
171   if (IsNull()) Standard_NullObject::Raise("A null Label has no children.");
172   Standard_Integer n = 0;
173   if (myLabelNode->FirstChild() != NULL)
174     for (TDF_ChildIterator itr(*this); itr.More(); itr.Next()) ++n;
175   return n;
176 }
177
178
179 //=======================================================================
180 //function : FindChild
181 //purpose  : 
182 //=======================================================================
183
184 TDF_Label TDF_Label::FindChild
185 (const Standard_Integer aTag,
186  const Standard_Boolean create) const
187 {
188   if (IsNull())
189     Standard_NullObject::Raise("A null Label has no child.");
190   if (create && ((Depth()+1) & TDF_LabelNodeFlagsMsk))
191       Standard_OutOfRange::Raise("Depth value out of range");
192
193   return FindOrAddChild(aTag,create);
194 }
195
196 // Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
197
198 //=======================================================================
199 //function : IsA
200 //purpose  : Returns true if owns an attribute with <anID> as ID.
201 //=======================================================================
202
203 // Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
204 // {
205 //   Handle(TDF_Attribute) att;
206 //   return FindAttribute(anID,att);
207 // }
208
209 //=======================================================================
210 //function : IsAttribute
211 //purpose  : Returns true if owns an attribute with <anID> as ID.
212 //=======================================================================
213
214 Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
215 {
216   Handle(TDF_Attribute) att;
217   return FindAttribute(anID,att);
218 }
219
220
221 //=======================================================================
222 //function : HasAttribute
223 //purpose  : Returns true if the label has at least one unremoved attribute.
224 //=======================================================================
225
226 Standard_Boolean TDF_Label::HasAttribute() const
227 {
228   if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
229
230   if (!myLabelNode->FirstAttribute().IsNull()) {
231     TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
232     return itr.More();
233   }
234   return Standard_False;
235 }
236
237
238 //=======================================================================
239 //function : NbAttributes
240 //purpose  : Returns the number of attributes.
241 //=======================================================================
242
243 Standard_Integer TDF_Label::NbAttributes() const
244 {
245   if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
246   Standard_Integer n = 0;
247   if (!myLabelNode->FirstAttribute().IsNull())
248     for (TDF_AttributeIterator itr (myLabelNode); itr.More(); itr.Next()) ++n;
249   return n;
250 }
251
252
253 // Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
254
255
256 //=======================================================================
257 //function : Transaction
258 //purpose  : 
259 //=======================================================================
260
261 Standard_Integer TDF_Label::Transaction() const
262 {
263   if (IsNull()) Standard_NullObject::Raise("A null Label has no transaction.");
264   return myLabelNode->Data()->Transaction();
265 }
266
267
268 //=======================================================================
269 //function : Dump
270 //purpose  : This method is equivalent to operator <<
271 //=======================================================================
272
273 Standard_OStream& TDF_Label::Dump
274 (Standard_OStream& anOS) const
275 {
276   TDF_IDFilter f; TDF_AttributeIndexedMap m;
277   TDF_Label::InternalDump(anOS,f,m,Standard_False);
278   return anOS;
279 }
280
281
282 //=======================================================================
283 //function : ExtendedDump
284 //purpose  : 
285 //=======================================================================
286
287 void TDF_Label::ExtendedDump
288 (Standard_OStream& anOS,
289  const TDF_IDFilter& aFilter,
290  TDF_AttributeIndexedMap& aMap) const
291 { TDF_Label::InternalDump(anOS,aFilter,aMap,Standard_True); }
292
293
294 //=======================================================================
295 //function : EntryDump
296 //purpose  : 
297 //=======================================================================
298
299 void TDF_Label::EntryDump(Standard_OStream& anOS) const
300 {
301   if (IsNull ()) {
302     anOS<<"This label is null.";
303   }
304   else {
305     TCollection_AsciiString entry;
306     TDF_Tool::Entry(*this,entry);
307     anOS<<entry;
308   }
309 }
310
311 #ifdef WNT
312 // Disable the warning: "operator new unmatched by delete"
313 #pragma warning (disable:4291)
314 #endif
315
316 //=======================================================================
317 //function : FindOrAddChild
318 //purpose  : Finds or adds a label child having <aTag> as tag.
319 //=======================================================================
320
321 TDF_LabelNode* TDF_Label::FindOrAddChild
322 (const Standard_Integer aTag,
323  const Standard_Boolean create) const
324 {
325   TDF_LabelNode* currentLnp      = myLabelNode->FirstChild();
326   TDF_LabelNode* lastLnp         = NULL;
327   TDF_LabelNode* lastFoundLnp    = myLabelNode->myLastFoundChild; //jfa 10.01.2003
328   TDF_LabelNode* childLabelNode  = NULL;
329
330   // Finds the right place.
331
332   //jfa 10.01.2003
333   // 1. Check, if we access to a child, which is after last touched upon
334   if (lastFoundLnp != NULL) {
335     if (lastFoundLnp->Tag() == aTag) {
336       return lastFoundLnp;
337     }
338     else if (lastFoundLnp->Tag() < aTag) {
339       lastLnp = lastFoundLnp;
340       currentLnp = lastFoundLnp->Brother();
341     }
342   }
343   //jfa 10.01.2003 end
344
345   // To facilitate many tools, label brethren are stored in increasing order.
346   while ((currentLnp != NULL) && (currentLnp->Tag() < aTag) ) {
347     lastLnp    = currentLnp;
348     currentLnp = currentLnp->Brother();
349   }
350
351   if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
352     // The label exists.
353     childLabelNode = currentLnp;
354   }
355   else if (create) {
356     // Creates the label to be inserted always before currentLnp.
357     const Handle(NCollection_IncAllocator)& anIncAllocator =
358       (const Handle(NCollection_IncAllocator)&)
359         myLabelNode ->Data() -> LabelNodeAllocator();
360     childLabelNode =  new (anIncAllocator) TDF_LabelNode (aTag, myLabelNode);
361     childLabelNode->myBrother = currentLnp; // May be NULL.
362     childLabelNode->Imported(IsImported());
363     //Inserts the label:
364     if (lastLnp == NULL) // ... at beginning.
365       myLabelNode->myFirstChild = childLabelNode;
366     else                 // ... somewhere.
367       lastLnp->myBrother = childLabelNode;
368   }
369
370   if (lastLnp)                               //agv 14.07.2010
371     myLabelNode->myLastFoundChild = lastLnp; //jfa 10.01.2003
372
373   return childLabelNode;
374 }
375
376 #ifdef WNT
377 #pragma warning (default:4291)
378 #endif
379
380 //=======================================================================
381 //function : InternalDump
382 //purpose  : Private method.
383 //=======================================================================
384
385 void TDF_Label::InternalDump
386 (Standard_OStream& anOS,
387  const TDF_IDFilter& aFilter,
388  TDF_AttributeIndexedMap& aMap,
389  const Standard_Boolean extended) const
390 {
391   if (IsNull ()) {
392     anOS<<"This label is null.";
393   }
394   else {
395     TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
396     anOS<<entry<<"\t";
397     if (IsImported()) anOS<<"IS "; else anOS<<"NOT"; anOS<<" imported; ";
398     if (MayBeModified()) anOS<<"MAYBE"; else anOS<<"NOT"; anOS<<" modified; ";
399     if (AttributesModified()) anOS<<"HAS attributes"; else anOS<<"NO attribute"; anOS<<" modified; ";
400     if (HasAttribute()) {
401       Standard_Integer nba = NbAttributes();
402       anOS<<"has "<<nba<<" attribute"; if (nba > 1) anOS<<"s"; anOS<<"."<<endl;
403       for (TDF_AttributeIterator itr(myLabelNode); itr.More(); itr.Next()) {
404         // CLE
405         // const Handle(TDF_Attribute)& att = itr.Value();
406         Handle(TDF_Attribute) att = itr.Value();
407         // ENDCLE
408         if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
409         att->TDF_Attribute::Dump(anOS);
410       }
411     }
412     else {
413       anOS<<" has no attribute"<<endl;
414     }
415   }
416 }
417
418 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
419 { return (myLabelNode < aLabel.myLabelNode); }
420
421 Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
422 { return (myLabelNode > aLabel.myLabelNode); }
423
424 // from insertor ////////////////////////////////////////////////////////
425
426 //=======================================================================
427 //function : Add
428 //purpose  : 
429 //=======================================================================
430
431 // void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute)  const
432 // { AddToNode(myLabelNode,anAttribute); }
433
434 //=======================================================================
435 //function : AddAttribute
436 //purpose  : 
437 //=======================================================================
438
439 void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute)  const
440 { AddToNode(myLabelNode,anAttribute); }
441
442
443 //=======================================================================
444 //function : Forget
445 //purpose  : 
446 //=======================================================================
447
448 // void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute)  const
449 // { ForgetFromNode(myLabelNode,anAttribute); }
450
451
452 //=======================================================================
453 //function : ForgetAttribute
454 //purpose  : 
455 //=======================================================================
456
457 void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute)  const
458 { ForgetFromNode(myLabelNode,anAttribute); }
459
460
461 //=======================================================================
462 //function : Forget
463 //purpose  : 
464 //=======================================================================
465
466 // Standard_Boolean  TDF_Label::Forget (const Standard_GUID& anID) const
467 // {  
468 //   Handle(TDF_Attribute) anAttribute;
469 //   //if (Label().FindAttribute(anID,anAttribute)) { 
470 //   if (FindAttribute(anID,anAttribute)) {
471 //     Forget(anAttribute);
472 //     return Standard_True;
473 //   }
474 //   return Standard_False;
475 // }
476
477 //=======================================================================
478 //function : ForgetAttribute
479 //purpose  : 
480 //=======================================================================
481
482 Standard_Boolean  TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
483 {  
484   Handle(TDF_Attribute) anAttribute;
485   //if (Label().FindAttribute(anID,anAttribute)) { 
486   if (FindAttribute(anID,anAttribute)) {
487     ForgetAttribute (anAttribute);
488     return Standard_True;
489   }
490   return Standard_False;
491 }
492
493
494 //=======================================================================
495 //function : ForgetAll
496 //purpose  : 
497 //=======================================================================
498
499 // void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
500 // {
501 //   for (TDF_AttributeIterator itr1(myLabelNode); itr1.More(); itr1.Next())
502 //     ForgetFromNode(myLabelNode,itr1.Value());
503 //   if (clearChildren)
504 //     for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
505 //       itr2.Value().ForgetAll(clearChildren);
506 //     }
507 // }
508
509
510 //=======================================================================
511 //function : ForgetAllAttributes
512 //purpose  : 
513 //=======================================================================
514
515 void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
516 {
517   TDF_AttributeIterator itr1 (myLabelNode);
518 // AGV-OCC5031: iterator must be incremented before removal of the attribute
519   while (itr1.More()) {
520     const Handle(TDF_Attribute) anAttr = itr1.Value();
521     itr1.Next();
522     ForgetFromNode (myLabelNode, anAttr);
523   }
524 // while (itr1.More()) {
525 //   ForgetFromNode(myLabelNode,itr1.Value());
526 //   itr1.Next();
527 // }
528   if (clearChildren)
529     for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
530       itr2.Value().ForgetAllAttributes (clearChildren);
531     }
532 }
533
534
535 //=======================================================================
536 //function : Resume
537 //purpose  : 
538 //=======================================================================
539
540 // void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute)  const
541 // { ResumeToNode(myLabelNode,anAttribute); }
542
543 //=======================================================================
544 //function : ResumeAttribute
545 //purpose  : 
546 //=======================================================================
547
548 void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute)  const
549 { ResumeToNode(myLabelNode,anAttribute); }
550
551
552
553 //=======================================================================
554 //function : AddToNode
555 //purpose  : Private method used by Add
556 //=======================================================================
557
558 void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
559                            const Handle(TDF_Attribute)& anAttribute) const
560 {
561   // check that modification is allowed
562   if ( !toNode->Data()->IsModificationAllowed() ) {
563     TCollection_AsciiString aMess;
564     aMess = "Attribute \"";
565     aMess += anAttribute->DynamicType()->Name();
566     aMess += "\" is added to label outside transaction";
567     Standard_ImmutableObject::Raise(aMess.ToCString());
568   }
569     
570   if (!anAttribute->Label().IsNull())
571     Standard_DomainError::Raise("Attribute to add is already attached to a label.");
572   Handle(TDF_Attribute) dummyAtt;
573   //if (Find(anAttribute->ID(),dummyAtt))  
574   if (FindAttribute(anAttribute->ID(),dummyAtt))
575     Standard_DomainError::Raise("This label has already such an attribute.");
576
577   anAttribute->myTransaction = toNode->Data()->Transaction();  /// myData->Transaction();
578   anAttribute->mySavedTransaction = 0;
579   dummyAtt.Nullify();
580   toNode->AddAttribute(dummyAtt,anAttribute);
581   toNode->AttributesModified(anAttribute->myTransaction != 0);
582   //if (myData->NotUndoMode()) anAttribute->AfterAddition();  
583   if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
584 }
585
586
587 //=======================================================================
588 //function : ForgetFromNode
589 //purpose  : Private method used by Forget
590 //=======================================================================
591
592 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
593                                 const Handle(TDF_Attribute)& anAttribute) const
594 {
595   // check that modification is allowed
596   if ( !fromNode->Data()->IsModificationAllowed() ) {
597     TCollection_AsciiString aMess;
598     aMess = "Attribute \"";
599     aMess += anAttribute->DynamicType()->Name();
600     aMess += "\" is removed from label outside transaction";
601     Standard_ImmutableObject::Raise(aMess.ToCString());
602   }
603     
604   if (fromNode != anAttribute->Label().myLabelNode)
605     Standard_DomainError::Raise
606       ("Attribute to forget not attached to my label.");
607
608   Standard_Integer curTrans = fromNode->Data()->Transaction();
609   if (!anAttribute->IsForgotten()) {
610     if ( (curTrans == 0) ||
611         ( (anAttribute->myTransaction == curTrans) &&
612          anAttribute->myBackup.IsNull())) {
613       // 1- No transaction is open;
614       // OR
615       // 2- The attribute has been created in the current transaction;
616       // ==> Complete disparition of the attribute.
617       Handle(TDF_Attribute) lastAtt;
618       for (TDF_AttributeIterator itr(fromNode, Standard_False);
619            itr.More();
620            itr.Next()) {
621         if (itr.Value() == anAttribute) {
622           //if (myData->NotUndoMode()) { 
623           if (fromNode->Data()->NotUndoMode()) {
624             anAttribute->BeforeForget();
625             anAttribute->BeforeRemoval();
626           }
627           fromNode->RemoveAttribute(lastAtt,anAttribute);
628           anAttribute->Forget(fromNode->Data()->Transaction()); // vro
629           break;
630         }
631         lastAtt = itr.Value();
632       }
633     }
634     else {
635       // One case is here ignored:
636       // The attribute has been modified in the current transaction.
637       // (It has at least one backup.) We don't restore the previous
638       // version before forgetting. It may generated a strange behaviour
639       // in case of forgetting, commiting, aborting...
640       if (fromNode->Data()->NotUndoMode()) anAttribute->BeforeForget();
641       anAttribute->Forget(fromNode->Data()->Transaction());
642     }
643   }
644 }
645
646 //=======================================================================
647 //function : ResumeToNode
648 //purpose  : Private method used by Resume
649 //=======================================================================
650
651 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
652                               const Handle(TDF_Attribute)& anAttribute) const
653 {
654   if (anAttribute.IsNull())
655     Standard_NullObject::Raise("The attribute is a null handle.");
656   if (!anAttribute->Label().IsNull())
657     Standard_NullObject::Raise
658       ("Cannot resume an attribute already attached to a label.");
659   if (!anAttribute->IsForgotten()) 
660     Standard_DomainError::Raise
661       ("Cannot resume an unforgotten attribute.");
662
663   AddToNode(toNode, anAttribute); // vro
664   anAttribute->Resume();
665   if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
666 }
667
668 //////////////////end from insertor ///////////////////////////////////////////////////