3e04b9aa1b7cdc48c79bda8b49f078c12d05ba6c
[occt.git] / src / TDF / TDF_Label.cxx
1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
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
29 // Attribute methods ++++++++++++++++++++++++++++++++++++++++++++++++++++
30
31
32 //=======================================================================
33 //function : Imported
34 //purpose  : Sets imported and all its descendants.
35 //=======================================================================
36
37 void 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
54 Standard_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
75 Standard_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
100 Standard_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
112 Standard_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;
119 #ifdef DEB
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
142 const 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
154 Standard_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
169 TDF_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
199 Standard_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
211 Standard_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
228 Standard_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
246 Standard_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
258 Standard_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
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); }
277
278
279 //=======================================================================
280 //function : EntryDump
281 //purpose  : 
282 //=======================================================================
283
284 void 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
296 //=======================================================================
297 //function : FindOrAddChild
298 //purpose  : Finds or adds a label child having <aTag> as tag.
299 //=======================================================================
300
301 TDF_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.
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());
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
354 //=======================================================================
355 //function : InternalDump
356 //purpose  : Private method.
357 //=======================================================================
358
359 void 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
392 Standard_Boolean TDF_Label::HasLowerNode(const TDF_Label& aLabel) const
393 { return (myLabelNode < aLabel.myLabelNode); }
394
395 Standard_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
413 void 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
431 void 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
456 Standard_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
489 void 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
522 void 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
532 void 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;
553   dummyAtt.Nullify();
554   toNode->AddAttribute(dummyAtt,anAttribute);
555   toNode->AttributesModified(anAttribute->myTransaction != 0);
556   //if (myData->NotUndoMode()) anAttribute->AfterAddition();  
557   if (toNode->Data()->NotUndoMode()) anAttribute->AfterAddition();
558 }
559
560
561 //=======================================================================
562 //function : ForgetFromNode
563 //purpose  : Private method used by Forget
564 //=======================================================================
565
566 void TDF_Label::ForgetFromNode (const TDF_LabelNodePtr& fromNode,
567                                 const Handle(TDF_Attribute)& anAttribute) const
568 {
569   // check that modification is allowed
570   if ( !fromNode->Data()->IsModificationAllowed() ) {
571     TCollection_AsciiString aMess;
572     aMess = "Attribute \"";
573     aMess += anAttribute->DynamicType()->Name();
574     aMess += "\" is removed from label outside transaction";
575     Standard_ImmutableObject::Raise(aMess.ToCString());
576   }
577     
578   if (fromNode != anAttribute->Label().myLabelNode)
579     Standard_DomainError::Raise
580       ("Attribute to forget not attached to my label.");
581
582   Standard_Integer curTrans = fromNode->Data()->Transaction();
583   if (!anAttribute->IsForgotten()) {
584     if ( (curTrans == 0) ||
585         ( (anAttribute->myTransaction == curTrans) &&
586          anAttribute->myBackup.IsNull())) {
587       // 1- No transaction is open;
588       // OR
589       // 2- The attribute has been created in the current transaction;
590       // ==> Complete disparition of the attribute.
591       Handle(TDF_Attribute) lastAtt;
592       for (TDF_AttributeIterator itr(fromNode, Standard_False);
593            itr.More();
594            itr.Next()) {
595         if (itr.Value() == anAttribute) {
596           //if (myData->NotUndoMode()) { 
597           if (fromNode->Data()->NotUndoMode()) {
598             anAttribute->BeforeForget();
599             anAttribute->BeforeRemoval();
600           }
601           fromNode->RemoveAttribute(lastAtt,anAttribute);
602           anAttribute->Forget(fromNode->Data()->Transaction()); // vro
603           break;
604         }
605         lastAtt = itr.Value();
606       }
607     }
608     else {
609       // One case is here ignored:
610       // The attribute has been modified in the current transaction.
611       // (It has at least one backup.) We don't restore the previous
612       // version before forgetting. It may generated a strange behaviour
613       // in case of forgetting, commiting, aborting...
614       if (fromNode->Data()->NotUndoMode()) anAttribute->BeforeForget();
615       anAttribute->Forget(fromNode->Data()->Transaction());
616     }
617   }
618 }
619
620 //=======================================================================
621 //function : ResumeToNode
622 //purpose  : Private method used by Resume
623 //=======================================================================
624
625 void TDF_Label::ResumeToNode (const TDF_LabelNodePtr& toNode,
626                               const Handle(TDF_Attribute)& anAttribute) const
627 {
628   if (anAttribute.IsNull())
629     Standard_NullObject::Raise("The attribute is a null handle.");
630   if (!anAttribute->Label().IsNull())
631     Standard_NullObject::Raise
632       ("Cannot resume an attribute already attached to a label.");
633   if (!anAttribute->IsForgotten()) 
634     Standard_DomainError::Raise
635       ("Cannot resume an unforgotten attribute.");
636
637   AddToNode(toNode, anAttribute); // vro
638   anAttribute->Resume();
639   if (toNode->Data()->NotUndoMode()) anAttribute->AfterResume();
640 }
641
642 //////////////////end from insertor ///////////////////////////////////////////////////