0024645: Pointer to the last is wrong for a tree node
[occt.git] / src / TDataStd / TDataStd_TreeNode.cxx
CommitLineData
b311480e 1// Created on: 1999-06-10
2// Created by: Vladislav ROMASHKO
3// Copyright (c) 1999-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 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
32Standard_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
43const 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
54Handle(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
71Handle(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
88const Standard_GUID& TDataStd_TreeNode::ID() const
89{
90 return myTreeID;
91}
92
93//=======================================================================
94//TreeNode : TDataStd_TreeNode
95//purpose : Constructor
96//=======================================================================
97
98TDataStd_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
108Standard_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
138Standard_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
163Standard_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
186Standard_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
210Standard_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 (Handle(TDataStd_TreeNode)::DownCast(this) == Father()->First()) {
230 if (HasNext()) {
231 Father()->SetFirst(Next());
232 }
233 else Father()->SetFirst(bid);
234 }
235 }
236
237 if(Father()->HasLast()) {
bf5b5293 238 Father()->SetLast(bid);
7fd59977 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
253Standard_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//=======================================================================
273Standard_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
296void TDataStd_TreeNode::SetTreeID (const Standard_GUID& explicitID)
297{
298 myTreeID = explicitID;
299}
300
301
302//=======================================================================
303//function : IsAscendant
304//purpose :
305//=======================================================================
306
307Standard_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
318Standard_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
344Standard_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
355Standard_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
366Handle(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
378Standard_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
392Handle(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
407Handle(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
418Handle(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
429Handle(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
441Handle(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//=======================================================================
457Handle(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
474void 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
487void 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
501void 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
514void 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
527void 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
540void 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
557void 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
573void TDataStd_TreeNode::AfterResume() {
574 AfterAddition();
575}
576
577//=======================================================================
578//TreeNode : BeforeUndo
579//purpose : Disconnect the TreeNode from the tree.
580//=======================================================================
581
582Standard_Boolean TDataStd_TreeNode::BeforeUndo(const Handle(TDF_AttributeDelta)& anAttDelta,
35e08fe8 583 const Standard_Boolean /*forceIt*/)
7fd59977 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
594Standard_Boolean TDataStd_TreeNode::AfterUndo(const Handle(TDF_AttributeDelta)& anAttDelta,
35e08fe8 595 const Standard_Boolean /*forceIt*/)
7fd59977 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
606void 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
621void 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
651Handle(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
663void 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
677Standard_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 }
bf5b5293 696 if (myLast) {
697 anOS<<" Last=";
698 if (!myLast->Label().IsNull()) myLast->Label().EntryDump(anOS);
699 }
7fd59977 700 anOS<<endl;
701 return anOS;
702}