0025418: Debug output to be limited to OCC development environment
[occt.git] / src / TDF / TDF_Label.cxx
CommitLineData
b311480e 1// Created by: DAUTRY Philippe
2// Copyright (c) 1997-1999 Matra Datavision
973c2be1 3// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
7fd59977 16#include <TDF_Label.ixx>
17
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>
27
28
7fd59977 29// Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
30
31
32//=======================================================================
33//function : Imported
34//purpose : Sets imported and all its descendants.
35//=======================================================================
36
37void TDF_Label::Imported(const Standard_Boolean aStatus) const
38{
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);
45 }
46}
47
48
49//=======================================================================
50//function : FindAttribute
51//purpose : Finds an attributes according to an ID.
52//=======================================================================
53
54Standard_Boolean TDF_Label::FindAttribute
55(const Standard_GUID& anID,
56 Handle(TDF_Attribute)& anAttribute) const
57{
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();
63 return Standard_True;
64 }
65 }
66 return Standard_False;
67}
68
69
70//=======================================================================
71//function : FindAttribute
72//purpose : Finds an attributes according to an ID and a Transaction.
73//=======================================================================
74
75Standard_Boolean TDF_Label::FindAttribute
76(const Standard_GUID& anID,
77 const Standard_Integer aTransaction,
78 Handle(TDF_Attribute)& anAttribute) const
79{
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()) {
85 anAttribute = locAtt;
86 return Standard_True;
87 }
88 }
89 return Standard_False;
90}
91
92// Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
93
94//=======================================================================
95//function : Depth
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//=======================================================================
99
100Standard_Integer TDF_Label::Depth() const
101{
102 if (IsNull()) Standard_NullObject::Raise("A null Label has no depth.");
103 return myLabelNode->Depth();
104}
105
106
107//=======================================================================
108//function : IsDescendant
109//purpose : Returns True if <me> is a descendant of <aLabel>.
110//=======================================================================
111
112Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
113{
114 // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
115 // si la profondeur atteinte est inferieure a celle de <aLabel>.
116
117 const TDF_LabelNode* lp1 = aLabel.myLabelNode;
118 TDF_LabelNode* lp2 = myLabelNode;
0797d9d3 119#ifdef OCCT_DEBUG
7fd59977 120 if ((lp1 == NULL) || (lp2 == NULL))
121 Standard_NullObject::Raise("A null label has no ancestor nor descendant.");
122#endif
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)) {
128 lp2 = lp2->Father();
129 d2 = lp2->Depth();
130 }
131 return (lp1 == lp2);
132 }
133 return Standard_False;
134}
135
136
137//=======================================================================
138//function : Root
139//purpose :
140//=======================================================================
141
142const TDF_Label TDF_Label::Root() const
143{
144 if (IsNull()) Standard_NullObject::Raise("A null Label has no root.");
145 return myLabelNode->RootNode();
146}
147
148
149//=======================================================================
150//function : NbChildren
151//purpose : Returns the number of children.
152//=======================================================================
153
154Standard_Integer TDF_Label::NbChildren() const
155{
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;
160 return n;
161}
162
163
164//=======================================================================
165//function : FindChild
166//purpose :
167//=======================================================================
168
169TDF_Label TDF_Label::FindChild
170(const Standard_Integer aTag,
171 const Standard_Boolean create) const
172{
173 if (IsNull())
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");
177
178 return FindOrAddChild(aTag,create);
179}
180
181// Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
182
183//=======================================================================
184//function : IsA
185//purpose : Returns true if owns an attribute with <anID> as ID.
186//=======================================================================
187
188// Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
189// {
190// Handle(TDF_Attribute) att;
191// return FindAttribute(anID,att);
192// }
193
194//=======================================================================
195//function : IsAttribute
196//purpose : Returns true if owns an attribute with <anID> as ID.
197//=======================================================================
198
199Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
200{
201 Handle(TDF_Attribute) att;
202 return FindAttribute(anID,att);
203}
204
205
206//=======================================================================
207//function : HasAttribute
208//purpose : Returns true if the label has at least one unremoved attribute.
209//=======================================================================
210
211Standard_Boolean TDF_Label::HasAttribute() const
212{
213 if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
214
215 if (!myLabelNode->FirstAttribute().IsNull()) {
216 TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
217 return itr.More();
218 }
219 return Standard_False;
220}
221
222
223//=======================================================================
224//function : NbAttributes
225//purpose : Returns the number of attributes.
226//=======================================================================
227
228Standard_Integer TDF_Label::NbAttributes() const
229{
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;
234 return n;
235}
236
237
238// Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
239
240
241//=======================================================================
242//function : Transaction
243//purpose :
244//=======================================================================
245
246Standard_Integer TDF_Label::Transaction() const
247{
248 if (IsNull()) Standard_NullObject::Raise("A null Label has no transaction.");
249 return myLabelNode->Data()->Transaction();
250}
251
252
253//=======================================================================
254//function : Dump
255//purpose : This method is equivalent to operator <<
256//=======================================================================
257
258Standard_OStream& TDF_Label::Dump
259(Standard_OStream& anOS) const
260{
261 TDF_IDFilter f; TDF_AttributeIndexedMap m;
262 TDF_Label::InternalDump(anOS,f,m,Standard_False);
263 return anOS;
264}
265
266
267//=======================================================================
268//function : ExtendedDump
269//purpose :
270//=======================================================================
271
272void 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); }
277
278
279//=======================================================================
280//function : EntryDump
281//purpose :
282//=======================================================================
283
284void TDF_Label::EntryDump(Standard_OStream& anOS) const
285{
286 if (IsNull ()) {
287 anOS<<"This label is null.";
288 }
289 else {
290 TCollection_AsciiString entry;
291 TDF_Tool::Entry(*this,entry);
292 anOS<<entry;
293 }
294}
295
7fd59977 296//=======================================================================
297//function : FindOrAddChild
298//purpose : Finds or adds a label child having <aTag> as tag.
299//=======================================================================
300
301TDF_LabelNode* TDF_Label::FindOrAddChild
302(const Standard_Integer aTag,
303 const Standard_Boolean create) const
304{
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;
309
310 // Finds the right place.
311
312 //jfa 10.01.2003
313 // 1. Check, if we access to a child, which is after last touched upon
314 if (lastFoundLnp != NULL) {
315 if (lastFoundLnp->Tag() == aTag) {
316 return lastFoundLnp;
317 }
318 else if (lastFoundLnp->Tag() < aTag) {
319 lastLnp = lastFoundLnp;
320 currentLnp = lastFoundLnp->Brother();
321 }
322 }
323 //jfa 10.01.2003 end
324
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();
329 }
330
331 if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
332 // The label exists.
333 childLabelNode = currentLnp;
334 }
335 else if (create) {
336 // Creates the label to be inserted always before currentLnp.
60d4560d 337 const TDF_HAllocator& anAllocator = myLabelNode->Data()->LabelNodeAllocator();
338 childLabelNode = new (anAllocator) TDF_LabelNode (aTag, myLabelNode);
7fd59977 339 childLabelNode->myBrother = currentLnp; // May be NULL.
340 childLabelNode->Imported(IsImported());
341 //Inserts the label:
342 if (lastLnp == NULL) // ... at beginning.
343 myLabelNode->myFirstChild = childLabelNode;
344 else // ... somewhere.
345 lastLnp->myBrother = childLabelNode;
346 }
347
348 if (lastLnp) //agv 14.07.2010
349 myLabelNode->myLastFoundChild = lastLnp; //jfa 10.01.2003
350
351 return childLabelNode;
352}
353
7fd59977 354//=======================================================================
355//function : InternalDump
356//purpose : Private method.
357//=======================================================================
358
359void TDF_Label::InternalDump
360(Standard_OStream& anOS,
361 const TDF_IDFilter& aFilter,
362 TDF_AttributeIndexedMap& aMap,
363 const Standard_Boolean extended) const
364{
365 if (IsNull ()) {
366 anOS<<"This label is null.";
367 }
368 else {
369 TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
370 anOS<<entry<<"\t";
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()) {
378 // CLE
379 // const Handle(TDF_Attribute)& att = itr.Value();
380 Handle(TDF_Attribute) att = itr.Value();
381 // ENDCLE
382 if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
383 att->TDF_Attribute::Dump(anOS);
384 }
385 }
386 else {
387 anOS<<" has no attribute"<<endl;
388 }
389 }
390}
391
392Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
393{ return (myLabelNode < aLabel.myLabelNode); }
394
395Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
396{ return (myLabelNode > aLabel.myLabelNode); }
397
398// from insertor ////////////////////////////////////////////////////////
399
400//=======================================================================
401//function : Add
402//purpose :
403//=======================================================================
404
405// void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute) const
406// { AddToNode(myLabelNode,anAttribute); }
407
408//=======================================================================
409//function : AddAttribute
410//purpose :
411//=======================================================================
412
413void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute) const
414{ AddToNode(myLabelNode,anAttribute); }
415
416
417//=======================================================================
418//function : Forget
419//purpose :
420//=======================================================================
421
422// void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute) const
423// { ForgetFromNode(myLabelNode,anAttribute); }
424
425
426//=======================================================================
427//function : ForgetAttribute
428//purpose :
429//=======================================================================
430
431void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute) const
432{ ForgetFromNode(myLabelNode,anAttribute); }
433
434
435//=======================================================================
436//function : Forget
437//purpose :
438//=======================================================================
439
440// Standard_Boolean TDF_Label::Forget (const Standard_GUID& anID) const
441// {
442// Handle(TDF_Attribute) anAttribute;
443// //if (Label().FindAttribute(anID,anAttribute)) {
444// if (FindAttribute(anID,anAttribute)) {
445// Forget(anAttribute);
446// return Standard_True;
447// }
448// return Standard_False;
449// }
450
451//=======================================================================
452//function : ForgetAttribute
453//purpose :
454//=======================================================================
455
456Standard_Boolean TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
457{
458 Handle(TDF_Attribute) anAttribute;
459 //if (Label().FindAttribute(anID,anAttribute)) {
460 if (FindAttribute(anID,anAttribute)) {
461 ForgetAttribute (anAttribute);
462 return Standard_True;
463 }
464 return Standard_False;
465}
466
467
468//=======================================================================
469//function : ForgetAll
470//purpose :
471//=======================================================================
472
473// void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
474// {
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);
480// }
481// }
482
483
484//=======================================================================
485//function : ForgetAllAttributes
486//purpose :
487//=======================================================================
488
489void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
490{
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();
495 itr1.Next();
496 ForgetFromNode (myLabelNode, anAttr);
497 }
498// while (itr1.More()) {
499// ForgetFromNode(myLabelNode,itr1.Value());
500// itr1.Next();
501// }
502 if (clearChildren)
503 for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
504 itr2.Value().ForgetAllAttributes (clearChildren);
505 }
506}
507
508
509//=======================================================================
510//function : Resume
511//purpose :
512//=======================================================================
513
514// void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute) const
515// { ResumeToNode(myLabelNode,anAttribute); }
516
517//=======================================================================
518//function : ResumeAttribute
519//purpose :
520//=======================================================================
521
522void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute) const
523{ ResumeToNode(myLabelNode,anAttribute); }
524
525
526
527//=======================================================================
528//function : AddToNode
529//purpose : Private method used by Add
530//=======================================================================
531
532void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
533 const Handle(TDF_Attribute)& anAttribute) const
534{
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());
542 }
543
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.");
550
551 anAttribute->myTransaction = toNode->Data()->Transaction(); /// myData->Transaction();
552 anAttribute->mySavedTransaction = 0;
d01cc61d 553
554 //append to the end of the attribute list
7fd59977 555 dummyAtt.Nullify();
d01cc61d 556 for (TDF_AttributeIterator itr (toNode); itr.More(); itr.Next())
557 dummyAtt = itr.Value();
558
7fd59977 559 toNode->AddAttribute(dummyAtt,anAttribute);
560 toNode->AttributesModified(anAttribute->myTransaction != 0);
561 //if (myData->NotUndoMode()) anAttribute->AfterAddition();
562 if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
563}
564
565
566//=======================================================================
567//function : ForgetFromNode
568//purpose : Private method used by Forget
569//=======================================================================
570
571void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
572 const Handle(TDF_Attribute)& anAttribute) const
573{
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());
581 }
582
583 if (fromNode != anAttribute->Label().myLabelNode)
584 Standard_DomainError::Raise
585 ("Attribute to forget not attached to my label.");
586
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;
593 // OR
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);
598 itr.More();
599 itr.Next()) {
600 if (itr.Value() == anAttribute) {
601 //if (myData->NotUndoMode()) {
602 if (fromNode->Data()->NotUndoMode()) {
603 anAttribute->BeforeForget();
604 anAttribute->BeforeRemoval();
605 }
606 fromNode->RemoveAttribute(lastAtt,anAttribute);
607 anAttribute->Forget(fromNode->Data()->Transaction()); // vro
608 break;
609 }
610 lastAtt = itr.Value();
611 }
612 }
613 else {
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());
621 }
622 }
623}
624
625//=======================================================================
626//function : ResumeToNode
627//purpose : Private method used by Resume
628//=======================================================================
629
630void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
631 const Handle(TDF_Attribute)& anAttribute) const
632{
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.");
641
642 AddToNode(toNode, anAttribute); // vro
643 anAttribute->Resume();
644 if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
645}
646
647//////////////////end from insertor ///////////////////////////////////////////////////