Salome HOME
#18963 Minimize compiler warnings
[modules/kernel.git] / src / DF / DF_Label.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "DF_definitions.hxx"
21 #include "DF_Label.hxx"
22 #include "DF_Document.hxx"
23 #include "DF_Attribute.hxx"
24 #include "DF_ChildIterator.hxx"
25
26 #include <algorithm>
27
28 //Class DF_Label defines a persistence reference in DF_Document that contains a tree of Labels.
29 //This reference is named "entry" and is a sequence of tags divided by ":". The root entry is "0:".
30 //For example "0:1:1" corresponds the following structure
31 // 0_
32 //   |
33 //   |_1_
34 //       |
35 //       |_ 1
36
37 DF_Label DF_Label::Label(const DF_Label& theLabel, const std::string& theEntry, bool isCreated)
38 {
39   if(theLabel.IsNull()) return DF_Label();
40   
41   DF_Label aLabel = theLabel.Root();
42   if(theEntry == "0:") return aLabel;
43   if(theEntry == "0:1") return theLabel.GetDocument()->Main();
44
45   char* cc = (char*)theEntry.c_str();
46   int n = 0;
47   int i=0;
48
49   while (*cc != '\0') {
50     while ( *cc >= '0' && *cc <= '9') {
51       n = 10*n + (*cc - '0');
52       ++cc;
53     }
54     if (*cc == ':' || *cc == '\0') {
55       if(i>0)
56         {
57           if(aLabel.IsNull())break;
58           aLabel = aLabel.FindChild(n, isCreated);
59         }
60       i++;
61       n = 0;
62       if (*cc != '\0') ++cc;
63     }
64     else {
65       return DF_Label();
66     }
67   }
68
69   return aLabel;
70 }
71
72 DF_Label::DF_Label(DF_LabelNode* theNode)
73   :_node(theNode)
74 {
75 }
76
77 //Constructor
78 DF_Label::DF_Label()
79 {
80   _node = NULL;
81 }
82
83 //Copy constructor
84 DF_Label::DF_Label(const DF_Label& theLabel)
85 {
86   _node = theLabel._node;
87 }
88
89 DF_Label& DF_Label::operator=(const DF_Label& theLabel)
90 {
91   _node = theLabel._node;
92   return *this;
93 }
94
95 //Destructor
96 DF_Label::~DF_Label()
97 {
98   _node = NULL;
99 }
100
101 //Returns a smart pointer to Document which contains this Label
102 DF_Document* DF_Label::GetDocument() const
103 {
104   if(!_node) return NULL;
105   return _node->_document;
106 }
107
108 //Returns true if theLabel equals to this label
109 bool DF_Label::operator==(const DF_Label& theLabel)
110 {
111   if(IsNull() || theLabel.IsNull()) return false;
112   return (theLabel.Entry() == Entry());
113 }
114
115 //Returns true if theLabel doesn't equals to this label
116 bool DF_Label::operator!=(const DF_Label& theLabel)
117 {
118   if(IsNull() || theLabel.IsNull()) return true;
119   return (theLabel.Entry() != Entry());
120 }
121
122
123 //Returns a tag of this Label
124 int DF_Label::Tag() const
125 {
126   if(!_node) return -1;
127   return _node->_tag;
128 }
129
130 //Returns true if this Label is attached to the tree in the Document.
131 bool DF_Label::IsAttached()
132 {
133   if(!_node) return false;
134   return _node->_document != 0;
135 }
136
137 //Searches an Attribute with given ID located on this Label.
138 //Returns true if the Attribute is found.
139 DF_Attribute* DF_Label::FindAttribute(const std::string& theID) const
140 {
141   if(!_node) return NULL;
142
143   std::map< std::string, DF_Attribute* >::iterator it=_node->_attributes.find(theID);
144   if(it == _node->_attributes.end()) return NULL;
145   return it->second;
146
147 }
148
149 //Returns true if there is an Attribute with given ID on this Label.
150 bool DF_Label::IsAttribute(const std::string& theID) const
151 {
152   if(!_node) return false;
153
154   return (_node->_attributes.find(theID) != _node->_attributes.end());
155 }
156
157 //Adds theAttribute to the Label where this Attribute is located.
158 //Returns true if theAttribute was added.
159 bool DF_Label::AddAttribute(DF_Attribute* theAttribute) const
160 {
161   if(!_node) return false;
162
163   if(_node->_attributes.find(theAttribute->ID()) != _node->_attributes.end()) return false;
164   theAttribute->_node = _node;
165   _node->_attributes[theAttribute->ID()] = theAttribute;
166   theAttribute->AfterAddition();    
167
168   return true;
169 }
170
171 //Forgets an Attribute with given ID located on the this Label.
172 bool DF_Label::ForgetAttribute(const std::string& theID) const
173 {
174   if(!_node) return false;
175
176   if(_node->_attributes.find(theID) == _node->_attributes.end()) return false;
177   DF_Attribute* attr = _node->_attributes[theID];
178   attr->BeforeForget();
179   _node->_attributes.erase(theID);
180   delete attr;
181
182   return true;
183 }
184
185 //Forgets all Attributes located on this Label.
186 bool DF_Label::ForgetAllAttributes(bool clearChildren) const
187 {
188   if(!_node) return false;
189
190   std::vector<DF_Attribute*> va = GetAttributes();
191   _node->_attributes.clear();
192
193   for(size_t i = 0, len = va.size(); i<len; i++) {
194     va[i]->BeforeForget();
195     delete va[i];
196   }
197
198   if(clearChildren) {
199     DF_ChildIterator CI(*this, true);
200     for(; CI.More(); CI.Next()) 
201       CI.Value().ForgetAllAttributes(true);
202   }
203
204   return true;
205 }
206
207 //Returns Father of this Label.
208 DF_Label DF_Label::Father() const
209 {
210   if(!_node) return DF_Label();
211
212   return _node->_father;
213 }
214
215 //Returns is this Label is not initialized
216 bool DF_Label::IsNull() const
217 {
218   return (!_node || (_node->_document == NULL));
219 }
220
221 //Returns is this Label is a Root label
222 bool DF_Label::IsRoot() const
223 {
224   if(IsNull() || Father().IsNull()) return true;
225   return false;
226 }
227
228
229 //Returns true if this Label has Attributes.
230 bool DF_Label::HasAttributes() const
231 {
232   if(!_node) return false;
233
234   return !(_node->_attributes.empty());
235 }
236
237 //Returns a list of Attributes of this Label.
238 std::vector<DF_Attribute*> DF_Label::GetAttributes() const
239 {
240   std::vector<DF_Attribute*> attributes;
241   if(!_node) return attributes;
242   
243   typedef std::map<std::string, DF_Attribute*>::const_iterator AI;
244   std::vector<std::string> sorted;
245   for(AI p = _node->_attributes.begin(); p!=_node->_attributes.end(); p++)
246     sorted.push_back(p->first);
247     
248   sort(sorted.begin(), sorted.end());
249   size_t len = sorted.size();
250   for(size_t i = 0; i<len; i++)
251     attributes.push_back(_node->_attributes[sorted[i]]);
252
253   return attributes;
254 }
255
256 //Returns true if this Label has a child Label.
257 bool DF_Label::HasChild() const
258 {
259   if(!_node) return false;
260
261   return _node->_firstChild != 0;
262 }
263
264 //Returns a number of child Labels.
265 int DF_Label::NbChildren() const
266 {
267   if(!_node) return -1;
268
269   if(!_node->_firstChild) return 0;
270   int nb = 1;
271   DF_LabelNode* next = _node->_firstChild->_next;
272   while(next) {
273     nb++;
274     next = next->_next;
275   }
276
277   return nb;
278 }
279
280 //Returns the depth (a number of fathers required to identify the Label) of this Label in the tree.
281 int DF_Label::Depth() const
282 {
283   if(!_node) return -1;
284
285   return _node->_depth;
286 }
287
288 //Returns true if this Label is a descendant of theLabel.
289 bool DF_Label::IsDescendant(const DF_Label& theLabel)
290 {
291   if(!_node) return false;
292
293   DF_LabelNode* father = _node->_father;
294   if(!father) return false;
295
296   while(father) {
297     if(father == theLabel._node) return true;
298     father = father->_father;
299   }
300
301   return false;
302 }
303
304 //Returns the root Label of a Label tree to which this Label belongs.
305 DF_Label DF_Label::Root() const
306 {
307   if(!_node) return DF_Label();
308
309   return _node->_document->Main().Father();
310 }
311
312 //Finds a child Label of this Label with a given tag. If isCreate = true and there is no child
313 //Label with the given tag, the child Label is created.
314 DF_Label DF_Label::FindChild(int theTag, bool isCreate)
315 {
316   if(!_node || IsNull()) return DF_Label();
317
318   DF_LabelNode *aLabel = NULL, *aPrevious = NULL, *aNext = NULL;
319   if(!_node->_firstChild && !isCreate) return DF_Label();
320
321   if(_node->_firstChild && _node->_firstChild->_tag == theTag)
322     return DF_Label(_node->_firstChild);
323  
324   if(_node->_lastChild) {
325     if(_node->_lastChild->_tag == theTag) return DF_Label(_node->_lastChild);
326     if(_node->_lastChild->_tag < theTag) aPrevious = _node->_lastChild;
327   }
328   
329   if ( !aPrevious && _node->_firstChild )
330   {
331     // IPAL54049: Operations on multiple study objects are very long
332     // Use _node->_firstChild->_previous to store the last found child
333     if ( _node->_firstChild->_previous &&
334          _node->_firstChild->_previous->_tag <= theTag )
335       aLabel = _node->_firstChild->_previous;
336     else
337       aLabel = _node->_firstChild;
338
339     while(aLabel) {
340       if(aLabel->_tag == theTag) {
341         _node->_firstChild->_previous = aLabel;
342         return DF_Label(aLabel);
343       }
344       if(aLabel->_tag > theTag) {
345         aNext = aLabel;
346         break;
347       }
348       if(aLabel->_tag < theTag) aPrevious = aLabel;
349       aLabel = aLabel->_next;
350     }
351   }
352   
353   if(!isCreate) return DF_Label();
354
355   DF_LabelNode* aChild = new DF_LabelNode();
356   aChild->_father = this->_node;
357   aChild->_document = _node->_document;
358   aChild->_tag = theTag;
359   aChild->_depth = _node->_depth+1;
360   if(aNext) {
361     aChild->_previous = aNext->_previous;
362     aChild->_next = aNext;
363     aNext->_previous = aChild;
364   }
365   if(aPrevious) {
366     aChild->_previous = aPrevious;
367     aChild->_next = aPrevious->_next;
368     aPrevious->_next = aChild;
369   }
370     
371   if(!_node->_firstChild || (aNext && aNext == _node->_firstChild) ) _node->_firstChild = aChild;
372   if(!_node->_lastChild || !aNext) _node->_lastChild = aChild;
373   
374   return aChild;
375 }
376
377 //Creates a new child Label of this Label.
378 DF_Label DF_Label::NewChild()
379 {
380   if(!_node || IsNull()) return DF_Label();
381
382   int tag = 1;
383   if(_node->_lastChild) tag = _node->_lastChild->_tag+1;
384   
385   return FindChild(tag, true);
386 }
387
388 //Returns a tag of the last child
389 int DF_Label::LastChildTag() const
390 {
391   return _node->_lastChild ? _node->_lastChild->_tag : 0;
392 }
393
394 //Returns a string entry of this Label
395 std::string DF_Label::Entry() const
396 {
397   DF_LabelNode* father = this->_node;
398   if(!father->_father)return "0:";
399   int tag;
400   char buff[128];
401   char* wstr= buff;
402   char* str = buff;
403
404   while(father)
405     {
406       tag=father->_tag;
407       do{
408          // Conversion. Number is reversed.
409          *wstr++ = '0' + (tag % 10);
410       }while(tag /= 10);
411       father = father->_father;
412       if(father)*wstr++ = ':';
413     }
414   *wstr-- = '\0';
415
416   //reverse the buffer
417   char aux;
418   while (wstr > str)
419     aux = *wstr, *wstr-- = *str, *str++ = aux;
420
421   return buff;
422 }
423
424 bool DF_Label::IsEqual(const DF_Label& theLabel)
425 {
426   if(theLabel.IsNull() || IsNull()) return false;
427   DF_Label L(theLabel);
428   return (L.Entry() == Entry());
429 }
430
431
432 void DF_Label::Nullify() 
433 {
434   delete _node;
435   _node = NULL;
436 }
437
438 void DF_Label::dump()
439 {
440   if(!_node) std::cout << "DF_Label addr : " << this << " NULL " << std::endl;
441   else {
442     std::cout << "DF_Label addr : " << this->_node << " entry : " << Entry() << std::endl;
443     if(_node->_father) std::cout << " Father : " << _node->_father << " entry : " << Father().Entry() << std::endl;
444     else std::cout << " Father : NULL " << std::endl;
445
446     if(_node->_firstChild) std::cout << " FirstChild : " << _node->_firstChild << " entry : " << DF_Label(_node->_firstChild).Entry() << std::endl;
447     else std::cout << " FirstChild : NULL " << std::endl;
448
449     if(_node->_lastChild) std::cout << " LastChild : " << _node->_lastChild << " entry : " << DF_Label(_node->_lastChild).Entry() << std::endl;
450     else std::cout << " LastChild : NULL " << std::endl;
451
452     if(_node->_previous) std::cout << " Previous : " << _node->_previous << " entry : " << DF_Label(_node->_previous).Entry() << std::endl;
453     else std::cout << " Previous : NULL " << std::endl;
454
455     if(_node->_next) std::cout << " Next : " << _node->_next << " entry : " << DF_Label(_node->_next).Entry() << std::endl;
456     else std::cout << " Next : NULL " << std::endl;
457   }
458 }
459
460
461 /*
462  ###############################################
463             DF_LabelNode methods
464  ###############################################
465 */
466
467 DF_LabelNode::DF_LabelNode()
468 {
469   _depth = 0;
470   _tag = 0;
471   _attributes.clear();
472   _document = NULL;
473   _father = NULL;
474   _firstChild = NULL;
475   _lastChild = NULL;
476   _previous = NULL;
477   _next = NULL;
478 }
479
480 DF_LabelNode::~DF_LabelNode()
481 {
482   std::vector<DF_Attribute*> va;
483   typedef std::map<std::string, DF_Attribute*>::const_iterator AI;
484   for(AI p = _attributes.begin(); p!=_attributes.end(); p++)
485     va.push_back(p->second);
486
487   for(size_t i = 0, len = va.size(); i<len; i++) 
488     delete va[i];
489
490   _attributes.clear();
491 }
492
493
494 void DF_LabelNode::Reset()
495 {
496   _depth = 0;
497   _tag = 0;
498
499   std::vector<DF_Attribute*> va;
500   typedef std::map<std::string, DF_Attribute*>::const_iterator AI;
501   for(AI p = _attributes.begin(); p!=_attributes.end(); p++)
502     va.push_back(p->second);
503
504   for(size_t i = 0, len = va.size(); i<len; i++) 
505     delete va[i];
506
507   _attributes.clear();
508   _document = NULL;
509   _father = NULL;
510   _firstChild = NULL;
511   _lastChild = NULL;
512   _previous = NULL;
513   _next = NULL;  
514 }