0024645: Pointer to the last is wrong for a tree node
[occt.git] / src / TDataStd / TDataStd_TreeNode.cxx
1 // Created on: 1999-06-10
2 // Created by: Vladislav ROMASHKO
3 // Copyright (c) 1999-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <TDataStd_TreeNode.ixx>
18 #include <TDF_Label.hxx>
19 #include <Standard_DomainError.hxx>
20
21 // This bug concerns the method IsDescendant():
22 #define BUC60817
23
24 // This bug concerns the method BeforeForget() - Forget/Resume, Undo/Redo behaviour of the attribute
25 #define BUC60844
26
27 //=======================================================================
28 //function : Find
29 //purpose  : 
30 //=======================================================================
31
32 Standard_Boolean TDataStd_TreeNode::Find(const TDF_Label& L,
33                                          Handle(TDataStd_TreeNode)& T)
34 {
35   return L.FindAttribute(TDataStd_TreeNode::GetDefaultTreeID(), T);
36 }
37
38 //=======================================================================
39 //TreeNode : GetDefaultTreeID
40 //purpose  : Static method to get the default ID of a TreeNode
41 //=======================================================================
42
43 const Standard_GUID&  TDataStd_TreeNode::GetDefaultTreeID() 
44 {  
45   static Standard_GUID TDataStd_TreeNodeID ("2a96b621-ec8b-11d0-bee7-080009dc3333");
46   return TDataStd_TreeNodeID; 
47 }
48
49 //=======================================================================
50 //TreeNode : Set
51 //purpose  : Finds or creates a TreeNode attribute with default ID
52 //=======================================================================
53
54 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Set(const TDF_Label& L)
55 {
56   Handle(TDataStd_TreeNode) TN;
57   if (!L.FindAttribute(TDataStd_TreeNode::GetDefaultTreeID(),TN)) {
58     TN = new TDataStd_TreeNode();
59     TN->SetTreeID(TDataStd_TreeNode::GetDefaultTreeID());
60     L.AddAttribute(TN);
61   }
62   return TN;
63 }
64
65 //=======================================================================
66 //function : Set
67 //purpose  : Finds or creates a TreeNode  attribute with explicit ID
68 //         : a driver for it
69 //=======================================================================
70
71 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Set (const TDF_Label& L, 
72                                                   const Standard_GUID& explicitID)
73 {
74   Handle(TDataStd_TreeNode) TN;
75   if (!L.FindAttribute(explicitID,TN)) {
76     TN = new TDataStd_TreeNode ();    
77     TN->SetTreeID(explicitID);
78     L.AddAttribute(TN);
79   }
80   return TN;
81 }
82
83 //=======================================================================
84 //TreeNode : ID
85 //purpose  : Returns GUID of the TreeNode
86 //=======================================================================
87
88 const Standard_GUID& TDataStd_TreeNode::ID() const
89 {
90   return myTreeID; 
91 }
92
93 //=======================================================================
94 //TreeNode : TDataStd_TreeNode
95 //purpose  : Constructor
96 //=======================================================================
97
98 TDataStd_TreeNode::TDataStd_TreeNode () :
99   myFather(NULL),  myPrevious(NULL), myNext(NULL), myFirst(NULL), myLast(NULL)
100 {}  
101
102
103 //=======================================================================
104 //function : Append
105 //purpose  : Add <TN> as last child of me
106 //=======================================================================
107
108 Standard_Boolean TDataStd_TreeNode::Append (const Handle(TDataStd_TreeNode)& TN)
109 {  
110   if (!(TN->ID() == myTreeID) )
111     Standard_DomainError::Raise("TDataStd_TreeNode::Append : uncompatible GUID");
112
113   Handle(TDataStd_TreeNode) bid;
114   TN->SetNext(bid); // Deconnects from next.
115
116   // Find the last
117   if (!HasFirst()) {
118     SetFirst(TN);
119     TN->SetPrevious(bid); // Deconnects from previous.
120   }
121   else 
122   {
123     Handle(TDataStd_TreeNode) L = Last();
124     L->SetNext(TN);
125     TN->SetPrevious(L);
126   }
127   // Set Father
128   TN->SetFather(this);
129   myLast=TN.operator->();
130   return !TN.IsNull();
131 }
132
133 //=======================================================================
134 //function : Prepend
135 //purpose  : Add <TN> as first child of me
136 //=======================================================================
137
138 Standard_Boolean TDataStd_TreeNode::Prepend (const Handle(TDataStd_TreeNode)& TN)
139 {  
140   if (!(TN->ID() == myTreeID) ) 
141     Standard_DomainError::Raise("TDataStd_TreeNode::Prepend : uncompatible GUID");
142
143   Handle(TDataStd_TreeNode) bid;
144   TN->SetPrevious(bid);
145   if (HasFirst()) {
146     TN->SetNext(First());
147     First()->SetPrevious(TN);
148   }
149   else {
150     TN->SetNext(bid);
151     SetLast(TN);
152   }
153   TN->SetFather(this);
154   SetFirst(TN);
155   return !TN.IsNull();
156 }
157
158 //=======================================================================
159 //function : InsertBefore
160 //purpose  : Inserts the TreeNode  <TN> before me
161 //=======================================================================
162
163 Standard_Boolean TDataStd_TreeNode::InsertBefore (const Handle(TDataStd_TreeNode)& TN)
164 {
165   if (!(TN->ID() == myTreeID) ) 
166     Standard_DomainError::Raise("TDataStd_TreeNode::InsertBefore : uncompatible GUID");
167
168   TN->SetFather(Father());
169   TN->SetPrevious(Previous());
170   TN->SetNext(this);
171   
172   if (!HasPrevious())
173     Father()->SetFirst(TN);
174   else
175     Previous()->SetNext(TN);
176   
177   SetPrevious(TN);
178   return !TN.IsNull();
179 }
180
181 //=======================================================================
182 //function : InsertAfter
183 //purpose  : Inserts the TreeNode  <TN> after me
184 //=======================================================================
185
186 Standard_Boolean TDataStd_TreeNode::InsertAfter (const Handle(TDataStd_TreeNode)& TN)
187 {
188   if (!(TN->ID() == myTreeID) ) 
189     Standard_DomainError::Raise("TDataStd_TreeNode::InsertAfter : uncompatible GUID");
190   
191   if (HasFather() && !HasNext())
192     Father()->SetLast(TN);
193
194   TN->SetFather(Father());
195   TN->SetPrevious(this);
196   TN->SetNext(Next());
197   
198   if (HasNext()) 
199     Next()->SetPrevious(TN);
200
201   SetNext(TN);
202   return !TN.IsNull();
203 }
204
205 //=======================================================================
206 //function : Remove
207 //purpose  : Removees the function from the function tree
208 //=======================================================================
209
210 Standard_Boolean TDataStd_TreeNode::Remove ()
211 {
212   if (IsRoot()) return Standard_True;
213
214   Handle(TDataStd_TreeNode) bid;
215   if (!HasPrevious())
216     Father()->SetFirst(Next());
217   else
218     Previous()->SetNext(Next());
219
220   if (HasNext()) {
221     if (HasPrevious()) Next()->SetPrevious(Previous());
222     else Next()->SetPrevious(bid);
223   }
224   else {
225     if (HasPrevious()) Previous()->SetNext(bid);
226   }
227
228   if (Father()->HasFirst()) {
229     if (this == Father()->First().operator->()) {
230       if (HasNext()) {
231             Father()->SetFirst(Next());
232       }
233       else Father()->SetFirst(bid);
234     }
235   }
236   
237   if(Father()->HasLast()) {
238     Father()->SetLast(bid);
239   }
240
241   SetFather(bid);
242   SetNext(bid);
243   SetPrevious(bid);
244   return Standard_True;
245 }
246
247
248 //=======================================================================
249 //function : Depth
250 //purpose  : 
251 //=======================================================================
252
253 Standard_Integer TDataStd_TreeNode::Depth () const
254 {  
255   Standard_Integer depth = 0;
256
257   TDataStd_TreeNode* O = (TDataStd_TreeNode*) this;
258   while (O->myFather != NULL)
259   {
260     depth++;
261     O = O->myFather;
262   }
263
264   return depth;
265 }
266
267 //=======================================================================
268 //function : NbChildren
269 //purpose  : Returns the number of child nodes.
270 //           If <allLevels> is true, the method counts children of all levels
271 //           (children of children ...)
272 //=======================================================================
273 Standard_Integer TDataStd_TreeNode::NbChildren(const Standard_Boolean allLevels) const
274 {  
275     Standard_Integer nb = 0;
276     TDataStd_TreeNode* C = myFirst;
277     while (C != NULL)
278     {
279         if (allLevels && 
280             C->myFirst != NULL)
281         {
282             nb += C->NbChildren(allLevels);
283         }
284         nb++;
285         C = C->myNext;
286     }
287     return nb;
288 }
289  
290 //=======================================================================
291 //function : SetTreeID
292 //purpose  : Finds or creates a TreeNode  attribute with explicit ID
293 //         : a driver for it
294 //=======================================================================
295
296 void TDataStd_TreeNode::SetTreeID (const Standard_GUID& explicitID)
297 {
298   myTreeID = explicitID;
299 }
300
301
302 //=======================================================================
303 //function : IsAscendant
304 //purpose  : 
305 //=======================================================================
306
307 Standard_Boolean TDataStd_TreeNode::IsAscendant (const Handle(TDataStd_TreeNode)& ofTN) const
308 {
309   return ofTN->IsDescendant(this);
310 }
311
312
313 //=======================================================================
314 //function : IsDescendant
315 //purpose  : 
316 //=======================================================================
317
318 Standard_Boolean TDataStd_TreeNode::IsDescendant (const Handle(TDataStd_TreeNode)& ofTN) const
319 {
320 #ifdef BUC60817
321
322   TDataStd_TreeNode* O = (TDataStd_TreeNode*) this;
323   while (O->myFather != NULL)
324   {
325     if (O->myFather == ofTN)
326       return Standard_True;
327     O = O->myFather;
328   }
329
330 #else
331   Handle(TDataStd_TreeNode) current;
332   for (current = this;  current = current->Father(); current->HasFather()) {
333     if (current == ofTN) return Standard_True;
334   }
335 #endif
336   return Standard_False;
337 }
338
339 //=======================================================================
340 //function : IsFather
341 //purpose  : 
342 //=======================================================================
343
344 Standard_Boolean TDataStd_TreeNode::IsFather (const Handle(TDataStd_TreeNode)& ofTN) const
345 {
346   return (ofTN->Father() == this);
347 }
348
349
350 //=======================================================================
351 //function : IsChild
352 //purpose  : 
353 //=======================================================================
354
355 Standard_Boolean TDataStd_TreeNode::IsChild (const Handle(TDataStd_TreeNode)& ofTN) const
356 {
357   return (myFather == ofTN.operator->());
358 }
359
360
361 //=======================================================================
362 //TreeNode : Father
363 //purpose  : Returns the Father of the TreeNode
364 //=======================================================================
365
366 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Father() const
367 {
368   Handle(TDataStd_TreeNode) O = myFather;
369   return O;
370 }
371
372 //=======================================================================
373 //TreeNode : IsRoot
374 //purpose  : Returns Standard_True if the TreeNode is not attached to a
375 //           TreeNode tree or hasn't an Father.
376 //=======================================================================
377
378 Standard_Boolean TDataStd_TreeNode::IsRoot() const
379 {
380   if (myFather    == NULL && 
381       myPrevious == NULL &&
382       myNext     == NULL)
383     return Standard_True;
384   return Standard_False;
385 }
386
387 //=======================================================================
388 //TreeNode : Root
389 //purpose  : Returns the TreeNode which has no Father
390 //=======================================================================
391
392 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Root() const
393 {
394   TDataStd_TreeNode* O = (TDataStd_TreeNode*) this;
395   while (O->myFather != NULL)
396   {
397     O = O->myFather;
398   }
399   return O;
400 }
401
402 //=======================================================================
403 //TreeNode : Next
404 //purpose  : Returns next (in the TreeNode tree) TreeNode
405 //=======================================================================
406
407 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Next() const
408 {
409   Handle(TDataStd_TreeNode) O = myNext;  
410   return O;
411 }
412
413 //=======================================================================
414 //TreeNode : Previous
415 //purpose  : Returns previous (in the TreeNode tree) TreeNode
416 //=======================================================================
417
418 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Previous() const
419 {
420   Handle(TDataStd_TreeNode) O = myPrevious;
421   return O;
422 }
423
424 //=======================================================================
425 //TreeNode : First 
426 //purpose  : Returns first child
427 //=======================================================================
428
429 Handle(TDataStd_TreeNode) TDataStd_TreeNode::First () const
430 {
431   Handle(TDataStd_TreeNode) O = myFirst;
432   return O;
433 }
434
435 //=======================================================================
436 //TreeNode : Last 
437 //purpose  : Returns last child
438 //           Optimize an Append operation if it is called in a circle
439 //=======================================================================
440
441 Handle(TDataStd_TreeNode) TDataStd_TreeNode::Last ()
442 {
443   if(myLast && !myLast->IsChild(this))
444     myLast=NULL;
445
446   if(myLast == NULL) 
447     return FindLast();
448   
449   return myLast;
450 }
451
452 //=======================================================================
453 //TreeNode : FindLast 
454 //purpose  : Returns last child
455 //           Optimizes an Append operation if it is called in a circle
456 //=======================================================================
457 Handle(TDataStd_TreeNode) TDataStd_TreeNode::FindLast ()
458 {
459         if (myFirst == NULL)
460                 return myFirst;
461         TDataStd_TreeNode* L = myFirst;
462         while (L->myNext != NULL)
463         {
464                 L = L->myNext;
465         }
466         return L;
467 }
468
469 //=======================================================================
470 //TreeNode : SetFather
471 //purpose  : Sets the TreeNode F as Father of me
472 //=======================================================================
473
474 void TDataStd_TreeNode::SetFather(const Handle(TDataStd_TreeNode)& F)
475 {
476   Backup();
477   if (F.IsNull()) myFather = NULL;
478   else            myFather = F.operator->();
479   myLast=NULL;
480 }
481
482 //=======================================================================
483 //TreeNode : SetNext
484 //purpose  : Sets the TreeNode F next to me 
485 //=======================================================================
486
487 void TDataStd_TreeNode::SetNext(const Handle(TDataStd_TreeNode)& F)
488 {
489   Backup();
490   if (F.IsNull()) myNext = NULL;
491   else            myNext = F.operator->();
492   myLast=NULL;
493 }
494
495
496 //=======================================================================
497 //TreeNode : SetPrevious
498 //purpose  : Sets the TreeNode F previous to me
499 //=======================================================================
500
501 void TDataStd_TreeNode::SetPrevious(const Handle(TDataStd_TreeNode)& F)
502 {
503   Backup();
504   if (F.IsNull()) myPrevious = NULL;
505   else            myPrevious = F.operator->();
506   myLast=NULL;
507 }
508
509 //=======================================================================
510 //TreeNode : SetFirst
511 //purpose  : Sets the TreeNode F as first in the TreeNode tree
512 //=======================================================================
513
514 void TDataStd_TreeNode::SetFirst(const Handle(TDataStd_TreeNode)& F)
515 {
516   Backup();
517   if (F.IsNull()) myFirst = NULL;
518   else            myFirst = F.operator->();
519   myLast=NULL;
520 }
521
522 //=======================================================================
523 //TreeNode : SetLast
524 //purpose  : Sets the TreeNode F as last in the TreeNode tree
525 //=======================================================================
526
527 void TDataStd_TreeNode::SetLast(const Handle(TDataStd_TreeNode)& F)
528 {
529   Backup();
530   if (F.IsNull()) myLast = NULL;
531   else            myLast = F.operator->();
532 }
533
534 //=======================================================================
535 //TreeNode : AfterAddition
536 //purpose  : Connects the TreeNode to the tree.
537 //           Backuped attribute must stay disconnected
538 //=======================================================================
539
540 void TDataStd_TreeNode::AfterAddition() {
541   if (!IsBackuped()) {
542     if (myPrevious)
543       myPrevious->SetNext(this);
544     else if (myFather)
545       myFather->SetFirst(this);
546     if (myNext)
547       myNext->SetPrevious(this);
548   }
549 }
550
551 //=======================================================================
552 //TreeNode : BeforeForget
553 //purpose  : Disconnect the TreeNode from the tree.
554 //           Backuped attribute is normaly not concerned by such an operation
555 //=======================================================================
556
557 void TDataStd_TreeNode::BeforeForget() {
558 #ifdef BUC60844  
559   if (!IsBackuped()) {
560     Remove();
561     while (HasFirst()) First()->Remove();
562   }
563 #else
564   if (!IsBackuped()) Remove();
565 #endif
566 }
567
568 //=======================================================================
569 //TreeNode : AfterResume
570 //purpose  : Connects the TreeNode to the tree
571 //=======================================================================
572
573 void TDataStd_TreeNode::AfterResume() {
574   AfterAddition();
575 }
576
577 //=======================================================================
578 //TreeNode : BeforeUndo
579 //purpose  : Disconnect the TreeNode from the tree.
580 //=======================================================================
581
582 Standard_Boolean TDataStd_TreeNode::BeforeUndo(const Handle(TDF_AttributeDelta)& anAttDelta,
583                                                 const Standard_Boolean /*forceIt*/)
584 {
585   if (anAttDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnAddition))) BeforeForget(); // Disconnect.
586   return Standard_True;
587 }
588
589 //=======================================================================
590 //TreeNode : AfterUndo
591 //purpose  : Connect the TreeNode from the tree.
592 //=======================================================================
593
594 Standard_Boolean TDataStd_TreeNode::AfterUndo(const Handle(TDF_AttributeDelta)& anAttDelta,
595                                               const Standard_Boolean /*forceIt*/)
596 {
597   if (anAttDelta->IsKind(STANDARD_TYPE(TDF_DeltaOnRemoval))) AfterAddition(); // Reconnect.
598   return Standard_True;
599 }
600
601 //=======================================================================
602 //TreeNode : Restore
603 //purpose  : 
604 //=======================================================================
605
606 void TDataStd_TreeNode::Restore(const Handle(TDF_Attribute)& other) {
607   Handle(TDataStd_TreeNode) F =  Handle(TDataStd_TreeNode)::DownCast(other);
608   myFather     = F->myFather;
609   myPrevious   = F->myPrevious;
610   myNext       = F->myNext;
611   myFirst      = F->myFirst; 
612   myTreeID     = F->myTreeID;
613   myLast       = NULL;
614 }
615
616 //=======================================================================
617 //TreeNode : Paste
618 //purpose  : Method for Copy mechanism
619 //=======================================================================
620
621 void TDataStd_TreeNode::Paste(const Handle(TDF_Attribute)& into,
622                               const Handle(TDF_RelocationTable)& RT) const
623 {
624   Handle(TDataStd_TreeNode) intof = Handle(TDataStd_TreeNode)::DownCast(into);
625   Handle(TDataStd_TreeNode) func;
626   if (!RT->HasRelocation(myFather, func) && RT->AfterRelocate()) {
627     func.Nullify();
628   }
629   intof->SetFather(func);
630   if (!RT->HasRelocation(myNext, func) && RT->AfterRelocate()) {
631     func.Nullify();
632   }
633   intof->SetNext(func);
634   if (!RT->HasRelocation(myPrevious, func) && RT->AfterRelocate()) {
635     func.Nullify();
636   }
637   intof->SetPrevious(func);
638   if (!RT->HasRelocation(myFirst, func) && RT->AfterRelocate()) {
639     func.Nullify();
640   }
641
642   intof->SetFirst(func);
643   intof->SetTreeID(myTreeID);
644 }
645
646 //=======================================================================
647 //TreeNode : NewEmpty
648 //purpose  : Returns new empty TreeNode attribute
649 //=======================================================================
650
651 Handle(TDF_Attribute) TDataStd_TreeNode::NewEmpty() const
652 {
653   Handle(TDataStd_TreeNode) T = new TDataStd_TreeNode();
654   T->SetTreeID(myTreeID);
655   return T;
656 }
657
658 //=======================================================================
659 //TreeNode : References
660 //purpose  : Collects the references
661 //=======================================================================
662
663 void TDataStd_TreeNode::References(const Handle(TDF_DataSet)& aDataSet) const
664 {
665   TDataStd_TreeNode* fct = myFirst;
666   while (fct != NULL) {
667     aDataSet->AddAttribute(fct);
668     fct = fct->myNext;
669   }
670 }
671
672 //=======================================================================
673 //TreeNode : Dump
674 //purpose  : Dump of the TreeNode
675 //=======================================================================
676
677 Standard_OStream& TDataStd_TreeNode::Dump (Standard_OStream& anOS) const
678 {
679   TDF_Attribute::Dump (anOS);
680   if (myFather) {
681     anOS<<"  Father=";
682     if (!myFather->Label().IsNull()) myFather->Label().EntryDump(anOS);
683   }
684   if (myPrevious) {
685     anOS<<"  Previous=";
686     if (!myPrevious->Label().IsNull()) myPrevious->Label().EntryDump(anOS);
687   }
688   if (myNext) {
689     anOS<<"  Next=";
690     if (!myNext->Label().IsNull()) myNext->Label().EntryDump(anOS);
691   }
692   if (myFirst) {
693     anOS<<"  First=";
694     if (!myFirst->Label().IsNull()) myFirst->Label().EntryDump(anOS);
695   }
696   if (myLast) {
697     anOS<<"  Last=";
698     if (!myLast->Label().IsNull()) myLast->Label().EntryDump(anOS);
699   }
700   anOS<<endl;
701   return anOS;
702 }