fc62badde7b986116d5717a653f3a5d9e33729ac
[occt.git] / src / TDF / TDF_Label.cxx
1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2012 OPEN CASCADE SAS
4 //
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.
9 //
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.
12 //
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.
19
20 #include <TDF_Label.ixx>
21
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>
31
32
33 //=======================================================================
34 //function : TDF_Label
35 //purpose  : 
36 //=======================================================================
37
38 TDF_Label::TDF_Label()
39 :myLabelNode(NULL)
40 {}
41
42 //=======================================================================
43 //function : TDF_Label
44 //purpose  : 
45 //=======================================================================
46
47 TDF_Label::TDF_Label(const TDF_LabelNodePtr& aNode)
48 :myLabelNode(aNode)
49 {}
50
51 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
52
53
54 //=======================================================================
55 //function : Imported
56 //purpose  : Sets imported and all its descendants.
57 //=======================================================================
58
59 void TDF_Label::Imported(const Standard_Boolean aStatus) const
60 {
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);
67   }
68 }
69
70
71 //=======================================================================
72 //function : FindAttribute
73 //purpose  : Finds an attributes according to an ID.
74 //=======================================================================
75
76 Standard_Boolean TDF_Label::FindAttribute
77 (const Standard_GUID& anID,
78  Handle(TDF_Attribute)& anAttribute) const
79 {
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();
85       return Standard_True;
86     }
87   }
88   return Standard_False;
89 }
90
91
92 //=======================================================================
93 //function : FindAttribute
94 //purpose  : Finds an attributes according to an ID and a Transaction.
95 //=======================================================================
96
97 Standard_Boolean TDF_Label::FindAttribute
98 (const Standard_GUID& anID,
99  const Standard_Integer aTransaction,
100  Handle(TDF_Attribute)& anAttribute) const
101 {
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;
109     }
110   }
111   return Standard_False;
112 }
113
114 // Label comfort methods ++++++++++++++++++++++++++++++++++++++++++++++++
115
116 //=======================================================================
117 //function : Depth
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 //=======================================================================
121
122 Standard_Integer TDF_Label::Depth() const
123 {
124   if (IsNull()) Standard_NullObject::Raise("A null Label has no depth.");
125   return myLabelNode->Depth();
126 }
127
128
129 //=======================================================================
130 //function : IsDescendant
131 //purpose  : Returns True if <me> is a descendant of <aLabel>.
132 //=======================================================================
133
134 Standard_Boolean TDF_Label::IsDescendant(const TDF_Label& aLabel) const
135 {
136   // Cet algorithme remonte jusqu'a la racine. On peut s'arreter
137   // si la profondeur atteinte est inferieure a celle de <aLabel>.
138
139   const TDF_LabelNode* lp1 = aLabel.myLabelNode;
140   TDF_LabelNode*   lp2 = myLabelNode;
141 #ifdef DEB
142   if ((lp1 == NULL) || (lp2 == NULL))
143     Standard_NullObject::Raise("A null label has no ancestor nor descendant.");
144 #endif
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)) {
150       lp2 = lp2->Father();
151       d2  = lp2->Depth();
152     }
153     return (lp1 == lp2);
154   }
155   return Standard_False;
156 }
157
158
159 //=======================================================================
160 //function : Root
161 //purpose  : 
162 //=======================================================================
163
164 const TDF_Label TDF_Label::Root() const
165 {
166   if (IsNull()) Standard_NullObject::Raise("A null Label has no root.");
167   return myLabelNode->RootNode();
168 }
169
170
171 //=======================================================================
172 //function : NbChildren
173 //purpose  : Returns the number of children.
174 //=======================================================================
175
176 Standard_Integer TDF_Label::NbChildren() const
177 {
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;
182   return n;
183 }
184
185
186 //=======================================================================
187 //function : FindChild
188 //purpose  : 
189 //=======================================================================
190
191 TDF_Label TDF_Label::FindChild
192 (const Standard_Integer aTag,
193  const Standard_Boolean create) const
194 {
195   if (IsNull())
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");
199
200   return FindOrAddChild(aTag,create);
201 }
202
203 // Attribute comfort methods ++++++++++++++++++++++++++++++++++++++++++++
204
205 //=======================================================================
206 //function : IsA
207 //purpose  : Returns true if owns an attribute with <anID> as ID.
208 //=======================================================================
209
210 // Standard_Boolean TDF_Label::IsA(const Standard_GUID& anID) const
211 // {
212 //   Handle(TDF_Attribute) att;
213 //   return FindAttribute(anID,att);
214 // }
215
216 //=======================================================================
217 //function : IsAttribute
218 //purpose  : Returns true if owns an attribute with <anID> as ID.
219 //=======================================================================
220
221 Standard_Boolean TDF_Label::IsAttribute(const Standard_GUID& anID) const
222 {
223   Handle(TDF_Attribute) att;
224   return FindAttribute(anID,att);
225 }
226
227
228 //=======================================================================
229 //function : HasAttribute
230 //purpose  : Returns true if the label has at least one unremoved attribute.
231 //=======================================================================
232
233 Standard_Boolean TDF_Label::HasAttribute() const
234 {
235   if (IsNull()) Standard_NullObject::Raise("A null Label has no attribute.");
236
237   if (!myLabelNode->FirstAttribute().IsNull()) {
238     TDF_AttributeIterator itr (myLabelNode); // Without removed attributes.
239     return itr.More();
240   }
241   return Standard_False;
242 }
243
244
245 //=======================================================================
246 //function : NbAttributes
247 //purpose  : Returns the number of attributes.
248 //=======================================================================
249
250 Standard_Integer TDF_Label::NbAttributes() const
251 {
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;
256   return n;
257 }
258
259
260 // Miscelleaneous +++++++++++++++++++++++++++++++++++++++++++++++++++++++
261
262
263 //=======================================================================
264 //function : Transaction
265 //purpose  : 
266 //=======================================================================
267
268 Standard_Integer TDF_Label::Transaction() const
269 {
270   if (IsNull()) Standard_NullObject::Raise("A null Label has no transaction.");
271   return myLabelNode->Data()->Transaction();
272 }
273
274
275 //=======================================================================
276 //function : Dump
277 //purpose  : This method is equivalent to operator <<
278 //=======================================================================
279
280 Standard_OStream& TDF_Label::Dump
281 (Standard_OStream& anOS) const
282 {
283   TDF_IDFilter f; TDF_AttributeIndexedMap m;
284   TDF_Label::InternalDump(anOS,f,m,Standard_False);
285   return anOS;
286 }
287
288
289 //=======================================================================
290 //function : ExtendedDump
291 //purpose  : 
292 //=======================================================================
293
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); }
299
300
301 //=======================================================================
302 //function : EntryDump
303 //purpose  : 
304 //=======================================================================
305
306 void TDF_Label::EntryDump(Standard_OStream& anOS) const
307 {
308   if (IsNull ()) {
309     anOS<<"This label is null.";
310   }
311   else {
312     TCollection_AsciiString entry;
313     TDF_Tool::Entry(*this,entry);
314     anOS<<entry;
315   }
316 }
317
318 //=======================================================================
319 //function : FindOrAddChild
320 //purpose  : Finds or adds a label child having <aTag> as tag.
321 //=======================================================================
322
323 TDF_LabelNode* TDF_Label::FindOrAddChild
324 (const Standard_Integer aTag,
325  const Standard_Boolean create) const
326 {
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;
331
332   // Finds the right place.
333
334   //jfa 10.01.2003
335   // 1. Check, if we access to a child, which is after last touched upon
336   if (lastFoundLnp != NULL) {
337     if (lastFoundLnp->Tag() == aTag) {
338       return lastFoundLnp;
339     }
340     else if (lastFoundLnp->Tag() < aTag) {
341       lastLnp = lastFoundLnp;
342       currentLnp = lastFoundLnp->Brother();
343     }
344   }
345   //jfa 10.01.2003 end
346
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();
351   }
352
353   if ( (currentLnp != NULL) && (currentLnp->Tag() == aTag) ) {
354     // The label exists.
355     childLabelNode = currentLnp;
356   }
357   else if (create) {
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());
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 //=======================================================================
377 //function : InternalDump
378 //purpose  : Private method.
379 //=======================================================================
380
381 void TDF_Label::InternalDump
382 (Standard_OStream& anOS,
383  const TDF_IDFilter& aFilter,
384  TDF_AttributeIndexedMap& aMap,
385  const Standard_Boolean extended) const
386 {
387   if (IsNull ()) {
388     anOS<<"This label is null.";
389   }
390   else {
391     TCollection_AsciiString entry; TDF_Tool::Entry(*this,entry);
392     anOS<<entry<<"\t";
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()) {
400         // CLE
401         // const Handle(TDF_Attribute)& att = itr.Value();
402         Handle(TDF_Attribute) att = itr.Value();
403         // ENDCLE
404         if (extended && aFilter.IsKept(att)) anOS<<"\t# "<<aMap.Add(att);
405         att->TDF_Attribute::Dump(anOS);
406       }
407     }
408     else {
409       anOS<<" has no attribute"<<endl;
410     }
411   }
412 }
413
414 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
415 { return (myLabelNode < aLabel.myLabelNode); }
416
417 Standard_Boolean TDF_Label::HasGreaterNode(const TDF_Label& aLabel) const
418 { return (myLabelNode > aLabel.myLabelNode); }
419
420 // from insertor ////////////////////////////////////////////////////////
421
422 //=======================================================================
423 //function : Add
424 //purpose  : 
425 //=======================================================================
426
427 // void TDF_Label::Add(const Handle(TDF_Attribute)& anAttribute)  const
428 // { AddToNode(myLabelNode,anAttribute); }
429
430 //=======================================================================
431 //function : AddAttribute
432 //purpose  : 
433 //=======================================================================
434
435 void TDF_Label::AddAttribute (const Handle(TDF_Attribute)& anAttribute)  const
436 { AddToNode(myLabelNode,anAttribute); }
437
438
439 //=======================================================================
440 //function : Forget
441 //purpose  : 
442 //=======================================================================
443
444 // void TDF_Label::Forget(const Handle(TDF_Attribute)& anAttribute)  const
445 // { ForgetFromNode(myLabelNode,anAttribute); }
446
447
448 //=======================================================================
449 //function : ForgetAttribute
450 //purpose  : 
451 //=======================================================================
452
453 void TDF_Label::ForgetAttribute (const Handle(TDF_Attribute)& anAttribute)  const
454 { ForgetFromNode(myLabelNode,anAttribute); }
455
456
457 //=======================================================================
458 //function : Forget
459 //purpose  : 
460 //=======================================================================
461
462 // Standard_Boolean  TDF_Label::Forget (const Standard_GUID& anID) const
463 // {  
464 //   Handle(TDF_Attribute) anAttribute;
465 //   //if (Label().FindAttribute(anID,anAttribute)) { 
466 //   if (FindAttribute(anID,anAttribute)) {
467 //     Forget(anAttribute);
468 //     return Standard_True;
469 //   }
470 //   return Standard_False;
471 // }
472
473 //=======================================================================
474 //function : ForgetAttribute
475 //purpose  : 
476 //=======================================================================
477
478 Standard_Boolean  TDF_Label::ForgetAttribute (const Standard_GUID& anID) const
479 {  
480   Handle(TDF_Attribute) anAttribute;
481   //if (Label().FindAttribute(anID,anAttribute)) { 
482   if (FindAttribute(anID,anAttribute)) {
483     ForgetAttribute (anAttribute);
484     return Standard_True;
485   }
486   return Standard_False;
487 }
488
489
490 //=======================================================================
491 //function : ForgetAll
492 //purpose  : 
493 //=======================================================================
494
495 // void TDF_Label::ForgetAll (const Standard_Boolean clearChildren) const
496 // {
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);
502 //     }
503 // }
504
505
506 //=======================================================================
507 //function : ForgetAllAttributes
508 //purpose  : 
509 //=======================================================================
510
511 void TDF_Label::ForgetAllAttributes (const Standard_Boolean clearChildren) const
512 {
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();
517     itr1.Next();
518     ForgetFromNode (myLabelNode, anAttr);
519   }
520 // while (itr1.More()) {
521 //   ForgetFromNode(myLabelNode,itr1.Value());
522 //   itr1.Next();
523 // }
524   if (clearChildren)
525     for (TDF_ChildIterator itr2(myLabelNode); itr2.More(); itr2.Next()) {
526       itr2.Value().ForgetAllAttributes (clearChildren);
527     }
528 }
529
530
531 //=======================================================================
532 //function : Resume
533 //purpose  : 
534 //=======================================================================
535
536 // void TDF_Label::Resume (const Handle(TDF_Attribute)& anAttribute)  const
537 // { ResumeToNode(myLabelNode,anAttribute); }
538
539 //=======================================================================
540 //function : ResumeAttribute
541 //purpose  : 
542 //=======================================================================
543
544 void TDF_Label::ResumeAttribute (const Handle(TDF_Attribute)& anAttribute)  const
545 { ResumeToNode(myLabelNode,anAttribute); }
546
547
548
549 //=======================================================================
550 //function : AddToNode
551 //purpose  : Private method used by Add
552 //=======================================================================
553
554 void TDF_Label::AddToNode (const TDF_LabelNodePtr& toNode,
555                            const Handle(TDF_Attribute)& anAttribute) const
556 {
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());
564   }
565     
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.");
572
573   anAttribute->myTransaction = toNode->Data()->Transaction();  /// myData->Transaction();
574   anAttribute->mySavedTransaction = 0;
575   dummyAtt.Nullify();
576   toNode->AddAttribute(dummyAtt,anAttribute);
577   toNode->AttributesModified(anAttribute->myTransaction != 0);
578   //if (myData->NotUndoMode()) anAttribute->AfterAddition();  
579   if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
580 }
581
582
583 //=======================================================================
584 //function : ForgetFromNode
585 //purpose  : Private method used by Forget
586 //=======================================================================
587
588 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
589                                 const Handle(TDF_Attribute)& anAttribute) const
590 {
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());
598   }
599     
600   if (fromNode != anAttribute->Label().myLabelNode)
601     Standard_DomainError::Raise
602       ("Attribute to forget not attached to my label.");
603
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;
610       // OR
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);
615            itr.More();
616            itr.Next()) {
617         if (itr.Value() == anAttribute) {
618           //if (myData->NotUndoMode()) { 
619           if (fromNode->Data()->NotUndoMode()) {
620             anAttribute->BeforeForget();
621             anAttribute->BeforeRemoval();
622           }
623           fromNode->RemoveAttribute(lastAtt,anAttribute);
624           anAttribute->Forget(fromNode->Data()->Transaction()); // vro
625           break;
626         }
627         lastAtt = itr.Value();
628       }
629     }
630     else {
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());
638     }
639   }
640 }
641
642 //=======================================================================
643 //function : ResumeToNode
644 //purpose  : Private method used by Resume
645 //=======================================================================
646
647 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
648                               const Handle(TDF_Attribute)& anAttribute) const
649 {
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.");
658
659   AddToNode(toNode, anAttribute); // vro
660   anAttribute->Resume();
661   if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
662 }
663
664 //////////////////end from insertor ///////////////////////////////////////////////////