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.
17 #include <Standard_DomainError.hxx>
18 #include <Standard_GUID.hxx>
19 #include <Standard_ImmutableObject.hxx>
20 #include <Standard_NullObject.hxx>
21 #include <Standard_OutOfRange.hxx>
22 #include <TCollection_AsciiString.hxx>
23 #include <TDF_Attribute.hxx>
24 #include <TDF_AttributeIterator.hxx>
25 #include <TDF_ChildIterator.hxx>
26 #include <TDF_Data.hxx>
27 #include <TDF_IDFilter.hxx>
28 #include <TDF_Label.hxx>
29 #include <TDF_LabelMapHasher.hxx>
30 #include <TDF_LabelNode.hxx>
31 #include <TDF_LabelNodePtr.hxx>
32 #include <TDF_Tool.hxx>
34 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
35 //=======================================================================
37 //purpose : Sets imported and all its descendants.
38 //=======================================================================
39 void TDF_Label::Imported(const Standard_Boolean aStatus) const
41 if (IsNull()) throw Standard_NullObject("A null Label has no status.");
42 if (myLabelNode->IsImported() != aStatus) {
43 myLabelNode->Imported(aStatus);
44 for (TDF_ChildIterator itr(*this, Standard_True);
45 itr.More(); itr.Next())
46 itr.Value().myLabelNode->Imported(aStatus);
51 //=======================================================================
52 //function : FindAttribute
53 //purpose : Finds an attributes according to an ID.
54 //=======================================================================
56 Standard_Boolean TDF_Label::FindAttribute
57 (const Standard_GUID& anID,
58 Handle(TDF_Attribute)& anAttribute) const
60 if (IsNull()) throw Standard_NullObject("A null Label has no attribute.");
61 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
62 for ( ; itr.More(); itr.Next()) {
63 if (itr.Value()->ID() == anID) {
64 anAttribute = itr.Value();
68 return Standard_False;
72 //=======================================================================
73 //function : FindAttribute
74 //purpose : Finds an attributes according to an ID and a Transaction.
75 //=======================================================================
77 Standard_Boolean TDF_Label::FindAttribute
78 (const Standard_GUID& anID,
79 const Standard_Integer aTransaction,
80 Handle(TDF_Attribute)& anAttribute) const
82 Handle(TDF_Attribute) locAtt;
83 if (FindAttribute(anID, locAtt)) {
84 while ((!locAtt.IsNull()) && (locAtt->myTransaction > aTransaction))
85 locAtt = locAtt->myBackup;
86 if (!locAtt.IsNull()) {
91 return Standard_False;
94 // Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
96 //=======================================================================
98 //purpose : Returns the depth of the label in the tree.
99 // Root has depth 0. So the depth is the number of fathers.
100 //=======================================================================
102 Standard_Integer TDF_Label::Depth() const
104 if (IsNull()) throw Standard_NullObject("A null Label has no depth.");
105 return myLabelNode->Depth();
109 //=======================================================================
110 //function : IsDescendant
111 //purpose : Returns True if <me> is a descendant of <aLabel>.
112 //=======================================================================
114 Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
116 // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
117 // si la profondeur atteinte est inferieure a celle de <aLabel>.
119 const TDF_LabelNode* lp1 = aLabel.myLabelNode;
120 TDF_LabelNode* lp2 = myLabelNode;
122 if ((lp1 == NULL) || (lp2 == NULL))
123 throw Standard_NullObject("A null label has no ancestor nor descendant.");
125 if ((lp1 != NULL) && (lp2 != NULL)) {
126 const Standard_Integer d1 = lp1->Depth();
127 Standard_Integer d2 = lp2->Depth();
128 // Tester (d1 > d2) optimise la recherche ET dispense du test (lp2 != NULL)
129 while ((d2 > d1) && (lp2 != lp1)) {
135 return Standard_False;
139 //=======================================================================
142 //=======================================================================
144 const TDF_Label TDF_Label::Root() const
146 if (IsNull()) throw Standard_NullObject("A null Label has no root.");
147 return myLabelNode->RootNode();
151 //=======================================================================
152 //function : NbChildren
153 //purpose : Returns the number of children.
154 //=======================================================================
156 Standard_Integer TDF_Label::NbChildren() const
158 if (IsNull()) throw Standard_NullObject("A null Label has no children.");
159 Standard_Integer n = 0;
160 if (myLabelNode->FirstChild() != NULL)
161 for (TDF_ChildIterator itr(*this); itr.More(); itr.Next()) ++n;
166 //=======================================================================
167 //function : FindChild
169 //=======================================================================
171 TDF_Label TDF_Label::FindChild
172 (const Standard_Integer aTag,
173 const Standard_Boolean create) const
176 throw Standard_NullObject("A null Label has no child.");
177 if (create && ((Depth()+1) & TDF_LabelNodeFlagsMsk))
178 throw Standard_OutOfRange("Depth value out of range");
180 return FindOrAddChild(aTag,create);
183 // Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
185 //=======================================================================
187 //purpose : Returns true if owns an attribute with <anID> as ID.
188 //=======================================================================
190 // Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
192 // Handle(TDF_Attribute) att;
193 // return FindAttribute(anID,att);
196 //=======================================================================
197 //function : IsAttribute
198 //purpose : Returns true if owns an attribute with <anID> as ID.
199 //=======================================================================
201 Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
203 Handle(TDF_Attribute) att;
204 return FindAttribute(anID,att);
208 //=======================================================================
209 //function : HasAttribute
210 //purpose : Returns true if the label has at least one unremoved attribute.
211 //=======================================================================
213 Standard_Boolean TDF_Label::HasAttribute() const
215 if (IsNull()) throw Standard_NullObject("A null Label has no attribute.");
217 if (!myLabelNode->FirstAttribute().IsNull()) {
218 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
221 return Standard_False;
225 //=======================================================================
226 //function : NbAttributes
227 //purpose : Returns the number of attributes.
228 //=======================================================================
230 Standard_Integer TDF_Label::NbAttributes() const
232 if (IsNull()) throw Standard_NullObject("A null Label has no attribute.");
233 Standard_Integer n = 0;
234 if (!myLabelNode->FirstAttribute().IsNull())
235 for (TDF_AttributeIterator itr (myLabelNode); itr.More(); itr.Next()) ++n;
240 // Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
243 //=======================================================================
244 //function : Transaction
246 //=======================================================================
248 Standard_Integer TDF_Label::Transaction() const
250 if (IsNull()) throw Standard_NullObject("A null Label has no transaction.");
251 return myLabelNode->Data()->Transaction();
255 //=======================================================================
257 //purpose : This method is equivalent to operator <<
258 //=======================================================================
260 Standard_OStream& TDF_Label::Dump
261 (Standard_OStream& anOS) const
263 TDF_IDFilter f; TDF_AttributeIndexedMap m;
264 TDF_Label::InternalDump(anOS,f,m,Standard_False);
269 //=======================================================================
270 //function : ExtendedDump
272 //=======================================================================
274 void TDF_Label::ExtendedDump
275 (Standard_OStream& anOS,
276 const TDF_IDFilter& aFilter,
277 TDF_AttributeIndexedMap& aMap) const
278 { TDF_Label::InternalDump(anOS,aFilter,aMap,Standard_True); }
281 //=======================================================================
282 //function : EntryDump
284 //=======================================================================
286 void TDF_Label::EntryDump(Standard_OStream& anOS) const
289 anOS<<"This label is null.";
292 TCollection_AsciiString entry;
293 TDF_Tool::Entry(*this,entry);
298 //=======================================================================
299 //function : FindOrAddChild
300 //purpose : Finds or adds a label child having <aTag> as tag.
301 //=======================================================================
303 TDF_LabelNode* TDF_Label::FindOrAddChild
304 (const Standard_Integer aTag,
305 const Standard_Boolean create) const
307 TDF_LabelNode* currentLnp = myLabelNode->FirstChild();
308 TDF_LabelNode* lastLnp = NULL;
309 TDF_LabelNode* lastFoundLnp = myLabelNode->myLastFoundChild; //jfa 10.01.2003
310 TDF_LabelNode* childLabelNode = NULL;
312 // Finds the right place.
315 // 1. Check, if we access to a child, which is after last touched upon
316 if (lastFoundLnp != NULL) {
317 if (lastFoundLnp->Tag() == aTag) {
320 else if (lastFoundLnp->Tag() < aTag) {
321 lastLnp = lastFoundLnp;
322 currentLnp = lastFoundLnp->Brother();
327 // To facilitate many tools, label brethren are stored in increasing order.
328 while ((currentLnp != NULL) && (currentLnp->Tag() < aTag) ) {
329 lastLnp = currentLnp;
330 currentLnp = currentLnp->Brother();
333 if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
335 childLabelNode = currentLnp;
338 // Creates the label to be inserted always before currentLnp.
339 const TDF_HAllocator& anAllocator = myLabelNode->Data()->LabelNodeAllocator();
340 childLabelNode = new (anAllocator) TDF_LabelNode (aTag, myLabelNode);
341 childLabelNode->myBrother = currentLnp; // May be NULL.
342 childLabelNode->Imported(IsImported());
344 if (lastLnp == NULL) // ... at beginning.
345 myLabelNode->myFirstChild = childLabelNode;
346 else // ... somewhere.
347 lastLnp->myBrother = childLabelNode;
350 if (lastLnp) //agv 14.07.2010
351 myLabelNode->myLastFoundChild = lastLnp; //jfa 10.01.2003
353 return childLabelNode;
356 //=======================================================================
357 //function : InternalDump
358 //purpose : Private method.
359 //=======================================================================
361 void TDF_Label::InternalDump
362 (Standard_OStream& anOS,
363 const TDF_IDFilter& aFilter,
364 TDF_AttributeIndexedMap& aMap,
365 const Standard_Boolean extended) const
368 anOS<<"This label is null.";
371 TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
373 if (IsImported()) anOS<<"IS "; else anOS<<"NOT"; anOS<<" imported; ";
374 if (MayBeModified()) anOS<<"MAYBE"; else anOS<<"NOT"; anOS<<" modified; ";
375 if (AttributesModified()) anOS<<"HAS attributes"; else anOS<<"NO attribute"; anOS<<" modified; ";
376 if (HasAttribute()) {
377 Standard_Integer nba = NbAttributes();
378 anOS<<"has "<<nba<<" attribute"; if (nba > 1) anOS<<"s"; anOS<<"."<<endl;
379 for (TDF_AttributeIterator itr(myLabelNode); itr.More(); itr.Next()) {
381 // const Handle(TDF_Attribute)& att = itr.Value();
382 Handle(TDF_Attribute) att = itr.Value();
384 if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
385 att->TDF_Attribute::Dump(anOS);
389 anOS<<" has no attribute"<<endl;
394 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
395 { return (myLabelNode < aLabel.myLabelNode); }
397 Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
398 { return (myLabelNode > aLabel.myLabelNode); }
400 // from insertor ////////////////////////////////////////////////////////
402 //=======================================================================
405 //=======================================================================
407 // void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute) const
408 // { AddToNode(myLabelNode,anAttribute); }
410 //=======================================================================
411 //function : AddAttribute
413 //=======================================================================
415 void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute) const
416 { AddToNode(myLabelNode,anAttribute); }
419 //=======================================================================
422 //=======================================================================
424 // void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute) const
425 // { ForgetFromNode(myLabelNode,anAttribute); }
428 //=======================================================================
429 //function : ForgetAttribute
431 //=======================================================================
433 void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute) const
434 { ForgetFromNode(myLabelNode,anAttribute); }
437 //=======================================================================
440 //=======================================================================
442 // Standard_Boolean TDF_Label::Forget (const Standard_GUID& anID) const
444 // Handle(TDF_Attribute) anAttribute;
445 // //if (Label().FindAttribute(anID,anAttribute)) {
446 // if (FindAttribute(anID,anAttribute)) {
447 // Forget(anAttribute);
448 // return Standard_True;
450 // return Standard_False;
453 //=======================================================================
454 //function : ForgetAttribute
456 //=======================================================================
458 Standard_Boolean TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
460 Handle(TDF_Attribute) anAttribute;
461 //if (Label().FindAttribute(anID,anAttribute)) {
462 if (FindAttribute(anID,anAttribute)) {
463 ForgetAttribute (anAttribute);
464 return Standard_True;
466 return Standard_False;
470 //=======================================================================
471 //function : ForgetAll
473 //=======================================================================
475 // void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
477 // for (TDF_AttributeIterator itr1(myLabelNode); itr1.More(); itr1.Next())
478 // ForgetFromNode(myLabelNode,itr1.Value());
479 // if (clearChildren)
480 // for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
481 // itr2.Value().ForgetAll(clearChildren);
486 //=======================================================================
487 //function : ForgetAllAttributes
489 //=======================================================================
491 void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
493 TDF_AttributeIterator itr1 (myLabelNode);
494 // AGV-OCC5031: iterator must be incremented before removal of the attribute
495 while (itr1.More()) {
496 const Handle(TDF_Attribute) anAttr = itr1.Value();
498 ForgetFromNode (myLabelNode, anAttr);
500 // while (itr1.More()) {
501 // ForgetFromNode(myLabelNode,itr1.Value());
505 for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
506 itr2.Value().ForgetAllAttributes (clearChildren);
511 //=======================================================================
514 //=======================================================================
516 // void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute) const
517 // { ResumeToNode(myLabelNode,anAttribute); }
519 //=======================================================================
520 //function : ResumeAttribute
522 //=======================================================================
524 void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute) const
525 { ResumeToNode(myLabelNode,anAttribute); }
529 //=======================================================================
530 //function : AddToNode
531 //purpose : Private method used by Add
532 //=======================================================================
534 void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
535 const Handle(TDF_Attribute)& anAttribute) const
537 // check that modification is allowed
538 if ( !toNode->Data()->IsModificationAllowed() ) {
539 TCollection_AsciiString aMess;
540 aMess = "Attribute \"";
541 aMess += anAttribute->DynamicType()->Name();
542 aMess += "\" is added to label outside transaction";
543 throw Standard_ImmutableObject(aMess.ToCString());
546 if (!anAttribute->Label().IsNull())
547 throw Standard_DomainError("Attribute to add is already attached to a label.");
548 Handle(TDF_Attribute) dummyAtt;
549 //if (Find(anAttribute->ID(),dummyAtt))
550 if (FindAttribute(anAttribute->ID(),dummyAtt))
551 throw Standard_DomainError("This label has already such an attribute.");
553 anAttribute->myTransaction = toNode->Data()->Transaction(); /// myData->Transaction();
554 anAttribute->mySavedTransaction = 0;
556 //append to the end of the attribute list
558 for (TDF_AttributeIterator itr (toNode); itr.More(); itr.Next())
559 dummyAtt = itr.Value();
561 toNode->AddAttribute(dummyAtt,anAttribute);
562 toNode->AttributesModified(anAttribute->myTransaction != 0);
563 //if (myData->NotUndoMode()) anAttribute->AfterAddition();
564 if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
568 //=======================================================================
569 //function : ForgetFromNode
570 //purpose : Private method used by Forget
571 //=======================================================================
573 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
574 const Handle(TDF_Attribute)& anAttribute) const
576 // check that modification is allowed
577 if ( !fromNode->Data()->IsModificationAllowed() ) {
578 TCollection_AsciiString aMess;
579 aMess = "Attribute \"";
580 aMess += anAttribute->DynamicType()->Name();
581 aMess += "\" is removed from label outside transaction";
582 throw Standard_ImmutableObject(aMess.ToCString());
585 if (fromNode != anAttribute->Label().myLabelNode)
586 throw Standard_DomainError("Attribute to forget not attached to my label.");
588 Standard_Integer curTrans = fromNode->Data()->Transaction();
589 if (!anAttribute->IsForgotten()) {
590 if ( (curTrans == 0) ||
591 ( (anAttribute->myTransaction == curTrans) &&
592 anAttribute->myBackup.IsNull())) {
593 // 1- No transaction is open;
595 // 2- The attribute has been created in the current transaction;
596 // ==> Complete disparition of the attribute.
597 Handle(TDF_Attribute) lastAtt;
598 for (TDF_AttributeIterator itr(fromNode, Standard_False);
601 if (itr.Value() == anAttribute) {
602 //if (myData->NotUndoMode()) {
603 if (fromNode->Data()->NotUndoMode()) {
604 anAttribute->BeforeForget();
605 anAttribute->BeforeRemoval();
607 fromNode->RemoveAttribute(lastAtt,anAttribute);
608 anAttribute->Forget(fromNode->Data()->Transaction()); // vro
611 lastAtt = itr.Value();
615 // One case is here ignored:
616 // The attribute has been modified in the current transaction.
617 // (It has at least one backup.) We don't restore the previous
618 // version before forgetting. It may generated a strange behaviour
619 // in case of forgetting, commiting, aborting...
620 if (fromNode->Data()->NotUndoMode()) anAttribute->BeforeForget();
621 anAttribute->Forget(fromNode->Data()->Transaction());
626 //=======================================================================
627 //function : ResumeToNode
628 //purpose : Private method used by Resume
629 //=======================================================================
631 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
632 const Handle(TDF_Attribute)& anAttribute) const
634 if (anAttribute.IsNull())
635 throw Standard_NullObject("The attribute is a null handle.");
636 if (!anAttribute->Label().IsNull())
637 throw Standard_NullObject("Cannot resume an attribute already attached to a label.");
638 if (!anAttribute->IsForgotten())
639 throw Standard_DomainError("Cannot resume an unforgotten attribute.");
641 AddToNode(toNode, anAttribute); // vro
642 anAttribute->Resume();
643 if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
646 //////////////////end from insertor ///////////////////////////////////////////////////