1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <TDF_Label.ixx>
18 #include <TDF_Attribute.hxx>
19 #include <TDF_AttributeIterator.hxx>
20 #include <TDF_ChildIterator.hxx>
21 #include <TDF_Data.hxx>
22 #include <TDF_LabelNode.hxx>
23 #include <TDF_LabelNodePtr.hxx>
24 #include <TDF_Tool.hxx>
25 #include <TCollection_AsciiString.hxx>
26 #include <Standard_ImmutableObject.hxx>
29 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
32 //=======================================================================
34 //purpose : Sets imported and all its descendants.
35 //=======================================================================
37 void TDF_Label::Imported(const Standard_Boolean aStatus) const
39 if (IsNull()) Standard_NullObject::Raise("A null Label has no status.");
40 if (myLabelNode->IsImported() != aStatus) {
41 myLabelNode->Imported(aStatus);
42 for (TDF_ChildIterator itr(*this, Standard_True);
43 itr.More(); itr.Next())
44 itr.Value().myLabelNode->Imported(aStatus);
49 //=======================================================================
50 //function : FindAttribute
51 //purpose : Finds an attributes according to an ID.
52 //=======================================================================
54 Standard_Boolean TDF_Label::FindAttribute
55 (const Standard_GUID& anID,
56 Handle(TDF_Attribute)& anAttribute) const
58 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
59 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
60 for ( ; itr.More(); itr.Next()) {
61 if (itr.Value()->ID() == anID) {
62 anAttribute = itr.Value();
66 return Standard_False;
70 //=======================================================================
71 //function : FindAttribute
72 //purpose : Finds an attributes according to an ID and a Transaction.
73 //=======================================================================
75 Standard_Boolean TDF_Label::FindAttribute
76 (const Standard_GUID& anID,
77 const Standard_Integer aTransaction,
78 Handle(TDF_Attribute)& anAttribute) const
80 Handle(TDF_Attribute) locAtt;
81 if (FindAttribute(anID, locAtt)) {
82 while ((!locAtt.IsNull()) && (locAtt->myTransaction > aTransaction))
83 locAtt = locAtt->myBackup;
84 if (!locAtt.IsNull()) {
89 return Standard_False;
92 // Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
94 //=======================================================================
96 //purpose : Returns the depth of the label in the tree.
97 // Root has depth 0. So the depth is the number of fathers.
98 //=======================================================================
100 Standard_Integer TDF_Label::Depth() const
102 if (IsNull()) Standard_NullObject::Raise("A null Label has no depth.");
103 return myLabelNode->Depth();
107 //=======================================================================
108 //function : IsDescendant
109 //purpose : Returns True if <me> is a descendant of <aLabel>.
110 //=======================================================================
112 Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
114 // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
115 // si la profondeur atteinte est inferieure a celle de <aLabel>.
117 const TDF_LabelNode* lp1 = aLabel.myLabelNode;
118 TDF_LabelNode* lp2 = myLabelNode;
120 if ((lp1 == NULL) || (lp2 == NULL))
121 Standard_NullObject::Raise("A null label has no ancestor nor descendant.");
123 if ((lp1 != NULL) && (lp2 != NULL)) {
124 const Standard_Integer d1 = lp1->Depth();
125 Standard_Integer d2 = lp2->Depth();
126 // Tester (d1 > d2) optimise la recherche ET dispense du test (lp2 != NULL)
127 while ((d2 > d1) && (lp2 != lp1)) {
133 return Standard_False;
137 //=======================================================================
140 //=======================================================================
142 const TDF_Label TDF_Label::Root() const
144 if (IsNull()) Standard_NullObject::Raise("A null Label has no root.");
145 return myLabelNode->RootNode();
149 //=======================================================================
150 //function : NbChildren
151 //purpose : Returns the number of children.
152 //=======================================================================
154 Standard_Integer TDF_Label::NbChildren() const
156 if (IsNull()) Standard_NullObject::Raise("A null Label has no children.");
157 Standard_Integer n = 0;
158 if (myLabelNode->FirstChild() != NULL)
159 for (TDF_ChildIterator itr(*this); itr.More(); itr.Next()) ++n;
164 //=======================================================================
165 //function : FindChild
167 //=======================================================================
169 TDF_Label TDF_Label::FindChild
170 (const Standard_Integer aTag,
171 const Standard_Boolean create) const
174 Standard_NullObject::Raise("A null Label has no child.");
175 if (create && ((Depth()+1) & TDF_LabelNodeFlagsMsk))
176 Standard_OutOfRange::Raise("Depth value out of range");
178 return FindOrAddChild(aTag,create);
181 // Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
183 //=======================================================================
185 //purpose : Returns true if owns an attribute with <anID> as ID.
186 //=======================================================================
188 // Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
190 // Handle(TDF_Attribute) att;
191 // return FindAttribute(anID,att);
194 //=======================================================================
195 //function : IsAttribute
196 //purpose : Returns true if owns an attribute with <anID> as ID.
197 //=======================================================================
199 Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
201 Handle(TDF_Attribute) att;
202 return FindAttribute(anID,att);
206 //=======================================================================
207 //function : HasAttribute
208 //purpose : Returns true if the label has at least one unremoved attribute.
209 //=======================================================================
211 Standard_Boolean TDF_Label::HasAttribute() const
213 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
215 if (!myLabelNode->FirstAttribute().IsNull()) {
216 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
219 return Standard_False;
223 //=======================================================================
224 //function : NbAttributes
225 //purpose : Returns the number of attributes.
226 //=======================================================================
228 Standard_Integer TDF_Label::NbAttributes() const
230 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
231 Standard_Integer n = 0;
232 if (!myLabelNode->FirstAttribute().IsNull())
233 for (TDF_AttributeIterator itr (myLabelNode); itr.More(); itr.Next()) ++n;
238 // Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
241 //=======================================================================
242 //function : Transaction
244 //=======================================================================
246 Standard_Integer TDF_Label::Transaction() const
248 if (IsNull()) Standard_NullObject::Raise("A null Label has no transaction.");
249 return myLabelNode->Data()->Transaction();
253 //=======================================================================
255 //purpose : This method is equivalent to operator <<
256 //=======================================================================
258 Standard_OStream& TDF_Label::Dump
259 (Standard_OStream& anOS) const
261 TDF_IDFilter f; TDF_AttributeIndexedMap m;
262 TDF_Label::InternalDump(anOS,f,m,Standard_False);
267 //=======================================================================
268 //function : ExtendedDump
270 //=======================================================================
272 void TDF_Label::ExtendedDump
273 (Standard_OStream& anOS,
274 const TDF_IDFilter& aFilter,
275 TDF_AttributeIndexedMap& aMap) const
276 { TDF_Label::InternalDump(anOS,aFilter,aMap,Standard_True); }
279 //=======================================================================
280 //function : EntryDump
282 //=======================================================================
284 void TDF_Label::EntryDump(Standard_OStream& anOS) const
287 anOS<<"This label is null.";
290 TCollection_AsciiString entry;
291 TDF_Tool::Entry(*this,entry);
296 //=======================================================================
297 //function : FindOrAddChild
298 //purpose : Finds or adds a label child having <aTag> as tag.
299 //=======================================================================
301 TDF_LabelNode* TDF_Label::FindOrAddChild
302 (const Standard_Integer aTag,
303 const Standard_Boolean create) const
305 TDF_LabelNode* currentLnp = myLabelNode->FirstChild();
306 TDF_LabelNode* lastLnp = NULL;
307 TDF_LabelNode* lastFoundLnp = myLabelNode->myLastFoundChild; //jfa 10.01.2003
308 TDF_LabelNode* childLabelNode = NULL;
310 // Finds the right place.
313 // 1. Check, if we access to a child, which is after last touched upon
314 if (lastFoundLnp != NULL) {
315 if (lastFoundLnp->Tag() == aTag) {
318 else if (lastFoundLnp->Tag() < aTag) {
319 lastLnp = lastFoundLnp;
320 currentLnp = lastFoundLnp->Brother();
325 // To facilitate many tools, label brethren are stored in increasing order.
326 while ((currentLnp != NULL) && (currentLnp->Tag() < aTag) ) {
327 lastLnp = currentLnp;
328 currentLnp = currentLnp->Brother();
331 if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
333 childLabelNode = currentLnp;
336 // Creates the label to be inserted always before currentLnp.
337 const TDF_HAllocator& anAllocator = myLabelNode->Data()->LabelNodeAllocator();
338 childLabelNode = new (anAllocator) TDF_LabelNode (aTag, myLabelNode);
339 childLabelNode->myBrother = currentLnp; // May be NULL.
340 childLabelNode->Imported(IsImported());
342 if (lastLnp == NULL) // ... at beginning.
343 myLabelNode->myFirstChild = childLabelNode;
344 else // ... somewhere.
345 lastLnp->myBrother = childLabelNode;
348 if (lastLnp) //agv 14.07.2010
349 myLabelNode->myLastFoundChild = lastLnp; //jfa 10.01.2003
351 return childLabelNode;
354 //=======================================================================
355 //function : InternalDump
356 //purpose : Private method.
357 //=======================================================================
359 void TDF_Label::InternalDump
360 (Standard_OStream& anOS,
361 const TDF_IDFilter& aFilter,
362 TDF_AttributeIndexedMap& aMap,
363 const Standard_Boolean extended) const
366 anOS<<"This label is null.";
369 TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
371 if (IsImported()) anOS<<"IS "; else anOS<<"NOT"; anOS<<" imported; ";
372 if (MayBeModified()) anOS<<"MAYBE"; else anOS<<"NOT"; anOS<<" modified; ";
373 if (AttributesModified()) anOS<<"HAS attributes"; else anOS<<"NO attribute"; anOS<<" modified; ";
374 if (HasAttribute()) {
375 Standard_Integer nba = NbAttributes();
376 anOS<<"has "<<nba<<" attribute"; if (nba > 1) anOS<<"s"; anOS<<"."<<endl;
377 for (TDF_AttributeIterator itr(myLabelNode); itr.More(); itr.Next()) {
379 // const Handle(TDF_Attribute)& att = itr.Value();
380 Handle(TDF_Attribute) att = itr.Value();
382 if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
383 att->TDF_Attribute::Dump(anOS);
387 anOS<<" has no attribute"<<endl;
392 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
393 { return (myLabelNode < aLabel.myLabelNode); }
395 Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
396 { return (myLabelNode > aLabel.myLabelNode); }
398 // from insertor ////////////////////////////////////////////////////////
400 //=======================================================================
403 //=======================================================================
405 // void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute) const
406 // { AddToNode(myLabelNode,anAttribute); }
408 //=======================================================================
409 //function : AddAttribute
411 //=======================================================================
413 void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute) const
414 { AddToNode(myLabelNode,anAttribute); }
417 //=======================================================================
420 //=======================================================================
422 // void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute) const
423 // { ForgetFromNode(myLabelNode,anAttribute); }
426 //=======================================================================
427 //function : ForgetAttribute
429 //=======================================================================
431 void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute) const
432 { ForgetFromNode(myLabelNode,anAttribute); }
435 //=======================================================================
438 //=======================================================================
440 // Standard_Boolean TDF_Label::Forget (const Standard_GUID& anID) const
442 // Handle(TDF_Attribute) anAttribute;
443 // //if (Label().FindAttribute(anID,anAttribute)) {
444 // if (FindAttribute(anID,anAttribute)) {
445 // Forget(anAttribute);
446 // return Standard_True;
448 // return Standard_False;
451 //=======================================================================
452 //function : ForgetAttribute
454 //=======================================================================
456 Standard_Boolean TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
458 Handle(TDF_Attribute) anAttribute;
459 //if (Label().FindAttribute(anID,anAttribute)) {
460 if (FindAttribute(anID,anAttribute)) {
461 ForgetAttribute (anAttribute);
462 return Standard_True;
464 return Standard_False;
468 //=======================================================================
469 //function : ForgetAll
471 //=======================================================================
473 // void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
475 // for (TDF_AttributeIterator itr1(myLabelNode); itr1.More(); itr1.Next())
476 // ForgetFromNode(myLabelNode,itr1.Value());
477 // if (clearChildren)
478 // for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
479 // itr2.Value().ForgetAll(clearChildren);
484 //=======================================================================
485 //function : ForgetAllAttributes
487 //=======================================================================
489 void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
491 TDF_AttributeIterator itr1 (myLabelNode);
492 // AGV-OCC5031: iterator must be incremented before removal of the attribute
493 while (itr1.More()) {
494 const Handle(TDF_Attribute) anAttr = itr1.Value();
496 ForgetFromNode (myLabelNode, anAttr);
498 // while (itr1.More()) {
499 // ForgetFromNode(myLabelNode,itr1.Value());
503 for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
504 itr2.Value().ForgetAllAttributes (clearChildren);
509 //=======================================================================
512 //=======================================================================
514 // void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute) const
515 // { ResumeToNode(myLabelNode,anAttribute); }
517 //=======================================================================
518 //function : ResumeAttribute
520 //=======================================================================
522 void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute) const
523 { ResumeToNode(myLabelNode,anAttribute); }
527 //=======================================================================
528 //function : AddToNode
529 //purpose : Private method used by Add
530 //=======================================================================
532 void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
533 const Handle(TDF_Attribute)& anAttribute) const
535 // check that modification is allowed
536 if ( !toNode->Data()->IsModificationAllowed() ) {
537 TCollection_AsciiString aMess;
538 aMess = "Attribute \"";
539 aMess += anAttribute->DynamicType()->Name();
540 aMess += "\" is added to label outside transaction";
541 Standard_ImmutableObject::Raise(aMess.ToCString());
544 if (!anAttribute->Label().IsNull())
545 Standard_DomainError::Raise("Attribute to add is already attached to a label.");
546 Handle(TDF_Attribute) dummyAtt;
547 //if (Find(anAttribute->ID(),dummyAtt))
548 if (FindAttribute(anAttribute->ID(),dummyAtt))
549 Standard_DomainError::Raise("This label has already such an attribute.");
551 anAttribute->myTransaction = toNode->Data()->Transaction(); /// myData->Transaction();
552 anAttribute->mySavedTransaction = 0;
554 //append to the end of the attribute list
556 for (TDF_AttributeIterator itr (toNode); itr.More(); itr.Next())
557 dummyAtt = itr.Value();
559 toNode->AddAttribute(dummyAtt,anAttribute);
560 toNode->AttributesModified(anAttribute->myTransaction != 0);
561 //if (myData->NotUndoMode()) anAttribute->AfterAddition();
562 if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
566 //=======================================================================
567 //function : ForgetFromNode
568 //purpose : Private method used by Forget
569 //=======================================================================
571 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
572 const Handle(TDF_Attribute)& anAttribute) const
574 // check that modification is allowed
575 if ( !fromNode->Data()->IsModificationAllowed() ) {
576 TCollection_AsciiString aMess;
577 aMess = "Attribute \"";
578 aMess += anAttribute->DynamicType()->Name();
579 aMess += "\" is removed from label outside transaction";
580 Standard_ImmutableObject::Raise(aMess.ToCString());
583 if (fromNode != anAttribute->Label().myLabelNode)
584 Standard_DomainError::Raise
585 ("Attribute to forget not attached to my label.");
587 Standard_Integer curTrans = fromNode->Data()->Transaction();
588 if (!anAttribute->IsForgotten()) {
589 if ( (curTrans == 0) ||
590 ( (anAttribute->myTransaction == curTrans) &&
591 anAttribute->myBackup.IsNull())) {
592 // 1- No transaction is open;
594 // 2- The attribute has been created in the current transaction;
595 // ==> Complete disparition of the attribute.
596 Handle(TDF_Attribute) lastAtt;
597 for (TDF_AttributeIterator itr(fromNode, Standard_False);
600 if (itr.Value() == anAttribute) {
601 //if (myData->NotUndoMode()) {
602 if (fromNode->Data()->NotUndoMode()) {
603 anAttribute->BeforeForget();
604 anAttribute->BeforeRemoval();
606 fromNode->RemoveAttribute(lastAtt,anAttribute);
607 anAttribute->Forget(fromNode->Data()->Transaction()); // vro
610 lastAtt = itr.Value();
614 // One case is here ignored:
615 // The attribute has been modified in the current transaction.
616 // (It has at least one backup.) We don't restore the previous
617 // version before forgetting. It may generated a strange behaviour
618 // in case of forgetting, commiting, aborting...
619 if (fromNode->Data()->NotUndoMode()) anAttribute->BeforeForget();
620 anAttribute->Forget(fromNode->Data()->Transaction());
625 //=======================================================================
626 //function : ResumeToNode
627 //purpose : Private method used by Resume
628 //=======================================================================
630 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
631 const Handle(TDF_Attribute)& anAttribute) const
633 if (anAttribute.IsNull())
634 Standard_NullObject::Raise("The attribute is a null handle.");
635 if (!anAttribute->Label().IsNull())
636 Standard_NullObject::Raise
637 ("Cannot resume an attribute already attached to a label.");
638 if (!anAttribute->IsForgotten())
639 Standard_DomainError::Raise
640 ("Cannot resume an unforgotten attribute.");
642 AddToNode(toNode, anAttribute); // vro
643 anAttribute->Resume();
644 if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
647 //////////////////end from insertor ///////////////////////////////////////////////////