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