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