1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2012 OPEN CASCADE SAS
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.
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.
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.
20 #include <TDF_Label.ixx>
22 #include <TDF_Attribute.hxx>
23 #include <TDF_AttributeIterator.hxx>
24 #include <TDF_ChildIterator.hxx>
25 #include <TDF_Data.hxx>
26 #include <TDF_LabelNode.hxx>
27 #include <TDF_LabelNodePtr.hxx>
28 #include <TDF_Tool.hxx>
29 #include <TCollection_AsciiString.hxx>
30 #include <Standard_ImmutableObject.hxx>
33 //=======================================================================
34 //function : TDF_Label
36 //=======================================================================
38 TDF_Label::TDF_Label()
42 //=======================================================================
43 //function : TDF_Label
45 //=======================================================================
47 TDF_Label::TDF_Label(const TDF_LabelNodePtr& aNode)
51 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
54 //=======================================================================
56 //purpose : Sets imported and all its descendants.
57 //=======================================================================
59 void TDF_Label::Imported(const Standard_Boolean aStatus) const
61 if (IsNull()) Standard_NullObject::Raise("A null Label has no status.");
62 if (myLabelNode->IsImported() != aStatus) {
63 myLabelNode->Imported(aStatus);
64 for (TDF_ChildIterator itr(*this, Standard_True);
65 itr.More(); itr.Next())
66 itr.Value().myLabelNode->Imported(aStatus);
71 //=======================================================================
72 //function : FindAttribute
73 //purpose : Finds an attributes according to an ID.
74 //=======================================================================
76 Standard_Boolean TDF_Label::FindAttribute
77 (const Standard_GUID& anID,
78 Handle(TDF_Attribute)& anAttribute) const
80 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
81 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
82 for ( ; itr.More(); itr.Next()) {
83 if (itr.Value()->ID() == anID) {
84 anAttribute = itr.Value();
88 return Standard_False;
92 //=======================================================================
93 //function : FindAttribute
94 //purpose : Finds an attributes according to an ID and a Transaction.
95 //=======================================================================
97 Standard_Boolean TDF_Label::FindAttribute
98 (const Standard_GUID& anID,
99 const Standard_Integer aTransaction,
100 Handle(TDF_Attribute)& anAttribute) const
102 Handle(TDF_Attribute) locAtt;
103 if (FindAttribute(anID, locAtt)) {
104 while ((!locAtt.IsNull()) && (locAtt->myTransaction > aTransaction))
105 locAtt = locAtt->myBackup;
106 if (!locAtt.IsNull()) {
107 anAttribute = locAtt;
108 return Standard_True;
111 return Standard_False;
114 // Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
116 //=======================================================================
118 //purpose : Returns the depth of the label in the tree.
119 // Root has depth 0. So the depth is the number of fathers.
120 //=======================================================================
122 Standard_Integer TDF_Label::Depth() const
124 if (IsNull()) Standard_NullObject::Raise("A null Label has no depth.");
125 return myLabelNode->Depth();
129 //=======================================================================
130 //function : IsDescendant
131 //purpose : Returns True if <me> is a descendant of <aLabel>.
132 //=======================================================================
134 Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
136 // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
137 // si la profondeur atteinte est inferieure a celle de <aLabel>.
139 const TDF_LabelNode* lp1 = aLabel.myLabelNode;
140 TDF_LabelNode* lp2 = myLabelNode;
142 if ((lp1 == NULL) || (lp2 == NULL))
143 Standard_NullObject::Raise("A null label has no ancestor nor descendant.");
145 if ((lp1 != NULL) && (lp2 != NULL)) {
146 const Standard_Integer d1 = lp1->Depth();
147 Standard_Integer d2 = lp2->Depth();
148 // Tester (d1 > d2) optimise la recherche ET dispense du test (lp2 != NULL)
149 while ((d2 > d1) && (lp2 != lp1)) {
155 return Standard_False;
159 //=======================================================================
162 //=======================================================================
164 const TDF_Label TDF_Label::Root() const
166 if (IsNull()) Standard_NullObject::Raise("A null Label has no root.");
167 return myLabelNode->RootNode();
171 //=======================================================================
172 //function : NbChildren
173 //purpose : Returns the number of children.
174 //=======================================================================
176 Standard_Integer TDF_Label::NbChildren() const
178 if (IsNull()) Standard_NullObject::Raise("A null Label has no children.");
179 Standard_Integer n = 0;
180 if (myLabelNode->FirstChild() != NULL)
181 for (TDF_ChildIterator itr(*this); itr.More(); itr.Next()) ++n;
186 //=======================================================================
187 //function : FindChild
189 //=======================================================================
191 TDF_Label TDF_Label::FindChild
192 (const Standard_Integer aTag,
193 const Standard_Boolean create) const
196 Standard_NullObject::Raise("A null Label has no child.");
197 if (create && ((Depth()+1) & TDF_LabelNodeFlagsMsk))
198 Standard_OutOfRange::Raise("Depth value out of range");
200 return FindOrAddChild(aTag,create);
203 // Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
205 //=======================================================================
207 //purpose : Returns true if owns an attribute with <anID> as ID.
208 //=======================================================================
210 // Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
212 // Handle(TDF_Attribute) att;
213 // return FindAttribute(anID,att);
216 //=======================================================================
217 //function : IsAttribute
218 //purpose : Returns true if owns an attribute with <anID> as ID.
219 //=======================================================================
221 Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
223 Handle(TDF_Attribute) att;
224 return FindAttribute(anID,att);
228 //=======================================================================
229 //function : HasAttribute
230 //purpose : Returns true if the label has at least one unremoved attribute.
231 //=======================================================================
233 Standard_Boolean TDF_Label::HasAttribute() const
235 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
237 if (!myLabelNode->FirstAttribute().IsNull()) {
238 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
241 return Standard_False;
245 //=======================================================================
246 //function : NbAttributes
247 //purpose : Returns the number of attributes.
248 //=======================================================================
250 Standard_Integer TDF_Label::NbAttributes() const
252 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
253 Standard_Integer n = 0;
254 if (!myLabelNode->FirstAttribute().IsNull())
255 for (TDF_AttributeIterator itr (myLabelNode); itr.More(); itr.Next()) ++n;
260 // Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
263 //=======================================================================
264 //function : Transaction
266 //=======================================================================
268 Standard_Integer TDF_Label::Transaction() const
270 if (IsNull()) Standard_NullObject::Raise("A null Label has no transaction.");
271 return myLabelNode->Data()->Transaction();
275 //=======================================================================
277 //purpose : This method is equivalent to operator <<
278 //=======================================================================
280 Standard_OStream& TDF_Label::Dump
281 (Standard_OStream& anOS) const
283 TDF_IDFilter f; TDF_AttributeIndexedMap m;
284 TDF_Label::InternalDump(anOS,f,m,Standard_False);
289 //=======================================================================
290 //function : ExtendedDump
292 //=======================================================================
294 void TDF_Label::ExtendedDump
295 (Standard_OStream& anOS,
296 const TDF_IDFilter& aFilter,
297 TDF_AttributeIndexedMap& aMap) const
298 { TDF_Label::InternalDump(anOS,aFilter,aMap,Standard_True); }
301 //=======================================================================
302 //function : EntryDump
304 //=======================================================================
306 void TDF_Label::EntryDump(Standard_OStream& anOS) const
309 anOS<<"This label is null.";
312 TCollection_AsciiString entry;
313 TDF_Tool::Entry(*this,entry);
318 //=======================================================================
319 //function : FindOrAddChild
320 //purpose : Finds or adds a label child having <aTag> as tag.
321 //=======================================================================
323 TDF_LabelNode* TDF_Label::FindOrAddChild
324 (const Standard_Integer aTag,
325 const Standard_Boolean create) const
327 TDF_LabelNode* currentLnp = myLabelNode->FirstChild();
328 TDF_LabelNode* lastLnp = NULL;
329 TDF_LabelNode* lastFoundLnp = myLabelNode->myLastFoundChild; //jfa 10.01.2003
330 TDF_LabelNode* childLabelNode = NULL;
332 // Finds the right place.
335 // 1. Check, if we access to a child, which is after last touched upon
336 if (lastFoundLnp != NULL) {
337 if (lastFoundLnp->Tag() == aTag) {
340 else if (lastFoundLnp->Tag() < aTag) {
341 lastLnp = lastFoundLnp;
342 currentLnp = lastFoundLnp->Brother();
347 // To facilitate many tools, label brethren are stored in increasing order.
348 while ((currentLnp != NULL) && (currentLnp->Tag() < aTag) ) {
349 lastLnp = currentLnp;
350 currentLnp = currentLnp->Brother();
353 if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
355 childLabelNode = currentLnp;
358 // Creates the label to be inserted always before currentLnp.
359 const TDF_HAllocator& anAllocator = myLabelNode->Data()->LabelNodeAllocator();
360 childLabelNode = new (anAllocator) TDF_LabelNode (aTag, myLabelNode);
361 childLabelNode->myBrother = currentLnp; // May be NULL.
362 childLabelNode->Imported(IsImported());
364 if (lastLnp == NULL) // ... at beginning.
365 myLabelNode->myFirstChild = childLabelNode;
366 else // ... somewhere.
367 lastLnp->myBrother = childLabelNode;
370 if (lastLnp) //agv 14.07.2010
371 myLabelNode->myLastFoundChild = lastLnp; //jfa 10.01.2003
373 return childLabelNode;
376 //=======================================================================
377 //function : InternalDump
378 //purpose : Private method.
379 //=======================================================================
381 void TDF_Label::InternalDump
382 (Standard_OStream& anOS,
383 const TDF_IDFilter& aFilter,
384 TDF_AttributeIndexedMap& aMap,
385 const Standard_Boolean extended) const
388 anOS<<"This label is null.";
391 TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
393 if (IsImported()) anOS<<"IS "; else anOS<<"NOT"; anOS<<" imported; ";
394 if (MayBeModified()) anOS<<"MAYBE"; else anOS<<"NOT"; anOS<<" modified; ";
395 if (AttributesModified()) anOS<<"HAS attributes"; else anOS<<"NO attribute"; anOS<<" modified; ";
396 if (HasAttribute()) {
397 Standard_Integer nba = NbAttributes();
398 anOS<<"has "<<nba<<" attribute"; if (nba > 1) anOS<<"s"; anOS<<"."<<endl;
399 for (TDF_AttributeIterator itr(myLabelNode); itr.More(); itr.Next()) {
401 // const Handle(TDF_Attribute)& att = itr.Value();
402 Handle(TDF_Attribute) att = itr.Value();
404 if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
405 att->TDF_Attribute::Dump(anOS);
409 anOS<<" has no attribute"<<endl;
414 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
415 { return (myLabelNode < aLabel.myLabelNode); }
417 Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
418 { return (myLabelNode > aLabel.myLabelNode); }
420 // from insertor ////////////////////////////////////////////////////////
422 //=======================================================================
425 //=======================================================================
427 // void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute) const
428 // { AddToNode(myLabelNode,anAttribute); }
430 //=======================================================================
431 //function : AddAttribute
433 //=======================================================================
435 void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute) const
436 { AddToNode(myLabelNode,anAttribute); }
439 //=======================================================================
442 //=======================================================================
444 // void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute) const
445 // { ForgetFromNode(myLabelNode,anAttribute); }
448 //=======================================================================
449 //function : ForgetAttribute
451 //=======================================================================
453 void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute) const
454 { ForgetFromNode(myLabelNode,anAttribute); }
457 //=======================================================================
460 //=======================================================================
462 // Standard_Boolean TDF_Label::Forget (const Standard_GUID& anID) const
464 // Handle(TDF_Attribute) anAttribute;
465 // //if (Label().FindAttribute(anID,anAttribute)) {
466 // if (FindAttribute(anID,anAttribute)) {
467 // Forget(anAttribute);
468 // return Standard_True;
470 // return Standard_False;
473 //=======================================================================
474 //function : ForgetAttribute
476 //=======================================================================
478 Standard_Boolean TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
480 Handle(TDF_Attribute) anAttribute;
481 //if (Label().FindAttribute(anID,anAttribute)) {
482 if (FindAttribute(anID,anAttribute)) {
483 ForgetAttribute (anAttribute);
484 return Standard_True;
486 return Standard_False;
490 //=======================================================================
491 //function : ForgetAll
493 //=======================================================================
495 // void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
497 // for (TDF_AttributeIterator itr1(myLabelNode); itr1.More(); itr1.Next())
498 // ForgetFromNode(myLabelNode,itr1.Value());
499 // if (clearChildren)
500 // for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
501 // itr2.Value().ForgetAll(clearChildren);
506 //=======================================================================
507 //function : ForgetAllAttributes
509 //=======================================================================
511 void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
513 TDF_AttributeIterator itr1 (myLabelNode);
514 // AGV-OCC5031: iterator must be incremented before removal of the attribute
515 while (itr1.More()) {
516 const Handle(TDF_Attribute) anAttr = itr1.Value();
518 ForgetFromNode (myLabelNode, anAttr);
520 // while (itr1.More()) {
521 // ForgetFromNode(myLabelNode,itr1.Value());
525 for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
526 itr2.Value().ForgetAllAttributes (clearChildren);
531 //=======================================================================
534 //=======================================================================
536 // void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute) const
537 // { ResumeToNode(myLabelNode,anAttribute); }
539 //=======================================================================
540 //function : ResumeAttribute
542 //=======================================================================
544 void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute) const
545 { ResumeToNode(myLabelNode,anAttribute); }
549 //=======================================================================
550 //function : AddToNode
551 //purpose : Private method used by Add
552 //=======================================================================
554 void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
555 const Handle(TDF_Attribute)& anAttribute) const
557 // check that modification is allowed
558 if ( !toNode->Data()->IsModificationAllowed() ) {
559 TCollection_AsciiString aMess;
560 aMess = "Attribute \"";
561 aMess += anAttribute->DynamicType()->Name();
562 aMess += "\" is added to label outside transaction";
563 Standard_ImmutableObject::Raise(aMess.ToCString());
566 if (!anAttribute->Label().IsNull())
567 Standard_DomainError::Raise("Attribute to add is already attached to a label.");
568 Handle(TDF_Attribute) dummyAtt;
569 //if (Find(anAttribute->ID(),dummyAtt))
570 if (FindAttribute(anAttribute->ID(),dummyAtt))
571 Standard_DomainError::Raise("This label has already such an attribute.");
573 anAttribute->myTransaction = toNode->Data()->Transaction(); /// myData->Transaction();
574 anAttribute->mySavedTransaction = 0;
576 toNode->AddAttribute(dummyAtt,anAttribute);
577 toNode->AttributesModified(anAttribute->myTransaction != 0);
578 //if (myData->NotUndoMode()) anAttribute->AfterAddition();
579 if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
583 //=======================================================================
584 //function : ForgetFromNode
585 //purpose : Private method used by Forget
586 //=======================================================================
588 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
589 const Handle(TDF_Attribute)& anAttribute) const
591 // check that modification is allowed
592 if ( !fromNode->Data()->IsModificationAllowed() ) {
593 TCollection_AsciiString aMess;
594 aMess = "Attribute \"";
595 aMess += anAttribute->DynamicType()->Name();
596 aMess += "\" is removed from label outside transaction";
597 Standard_ImmutableObject::Raise(aMess.ToCString());
600 if (fromNode != anAttribute->Label().myLabelNode)
601 Standard_DomainError::Raise
602 ("Attribute to forget not attached to my label.");
604 Standard_Integer curTrans = fromNode->Data()->Transaction();
605 if (!anAttribute->IsForgotten()) {
606 if ( (curTrans == 0) ||
607 ( (anAttribute->myTransaction == curTrans) &&
608 anAttribute->myBackup.IsNull())) {
609 // 1- No transaction is open;
611 // 2- The attribute has been created in the current transaction;
612 // ==> Complete disparition of the attribute.
613 Handle(TDF_Attribute) lastAtt;
614 for (TDF_AttributeIterator itr(fromNode, Standard_False);
617 if (itr.Value() == anAttribute) {
618 //if (myData->NotUndoMode()) {
619 if (fromNode->Data()->NotUndoMode()) {
620 anAttribute->BeforeForget();
621 anAttribute->BeforeRemoval();
623 fromNode->RemoveAttribute(lastAtt,anAttribute);
624 anAttribute->Forget(fromNode->Data()->Transaction()); // vro
627 lastAtt = itr.Value();
631 // One case is here ignored:
632 // The attribute has been modified in the current transaction.
633 // (It has at least one backup.) We don't restore the previous
634 // version before forgetting. It may generated a strange behaviour
635 // in case of forgetting, commiting, aborting...
636 if (fromNode->Data()->NotUndoMode()) anAttribute->BeforeForget();
637 anAttribute->Forget(fromNode->Data()->Transaction());
642 //=======================================================================
643 //function : ResumeToNode
644 //purpose : Private method used by Resume
645 //=======================================================================
647 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
648 const Handle(TDF_Attribute)& anAttribute) const
650 if (anAttribute.IsNull())
651 Standard_NullObject::Raise("The attribute is a null handle.");
652 if (!anAttribute->Label().IsNull())
653 Standard_NullObject::Raise
654 ("Cannot resume an attribute already attached to a label.");
655 if (!anAttribute->IsForgotten())
656 Standard_DomainError::Raise
657 ("Cannot resume an unforgotten attribute.");
659 AddToNode(toNode, anAttribute); // vro
660 anAttribute->Resume();
661 if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
664 //////////////////end from insertor ///////////////////////////////////////////////////