configurationnode.cpp
1 /***************************************************************************
2  * Copyright (C) 2008 by Tomassino Ferrauto *
3  * t_ferrauto@yahoo.it *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
21 #include "configurationnode.h"
22 #include "configurationparameters.h"
23 #include <memory>
24 
25 namespace farsa {
26 
27 ConfigurationNode::ConfigurationNode(ConfigurationNode *parent, QString name, bool caseSensitive) :
28  m_parent(parent),
29  m_caseSensitive(caseSensitive),
30  m_name(((name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) ? QString() : name),
31  m_nullNode(m_name.isNull() ? NULL : new ConfigurationNode(this, QString())),
32  m_nullValue(),
33  m_object(),
34  m_children(),
35  m_childrenkeys(),
36  m_parameters(),
37  m_parameterskeys(),
38  m_objectParameters()
39 {
40 }
41 
43 {
44  // Removing the null node
45  delete m_nullNode;
46 
47  // Removing everything
48  clearAll();
49 }
50 
51 QList<const ConfigurationNode*> ConfigurationNode::getAncestors() const
52 {
53  if (isNull()) {
54  return QList<const ConfigurationNode*>();
55  }
56 
57  QList<const ConfigurationNode*> list;
58 
59  // If we have a parent, calling its getAncestors and appending us to the result
60  if (m_parent != NULL) {
61  list = m_parent->getAncestors();
62  }
63 
64  list.append(this);
65 
66  return list;
67 }
68 
70 {
71  if (isNull()) {
72  return QStringList();
73  }
74 
75  QStringList list;
76 
77  // If we have a parent, calling its getAncestorsNames and appending us to the result, otherwise returning the
78  // list with only the empty string (the root node is referenced using "")
79  if (m_parent != NULL) {
80  list = m_parent->getAncestorsNames();
81  list.append(m_name);
82  } else {
83  list.append("");
84  }
85 
86  return list;
87 }
88 
90 {
91  if (isNull()) {
92  return QString();
93  }
94 
95  // If we have a parent, calling its getFullName and prepending the result to our name
96  if (m_parent != NULL) {
97  return m_parent->getFullName() + ConfigurationParameters::GroupSeparator() + m_name;
98  } else {
99  return m_name;
100  }
101 }
102 
104 {
105  // Not adding the node if its name is NULL, the group separator or the parent node or if this is a null node
106  if ((isNull()) || (name.isEmpty()) || (name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) {
107  // The NULL node hasn't a NULL node inside, returning self
108  return (isNull()) ? this : m_nullNode;
109  }
110 
111  // Checking if a node with that name already exists
112  foreach( QString child, m_children.keys() ) {
113  if ( child.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
114  return m_children[child];
115  }
116  }
117 
118  std::auto_ptr<ConfigurationNode> newNode(new ConfigurationNode(this, name, m_caseSensitive));
119 
120  m_children.insert(name, newNode.get());
121  m_childrenkeys.push_back(name);
122 
123  return newNode.release();
124 }
125 
127 {
128  // Using the const version and a const_cast
129  return const_cast<ConfigurationNode*>((const_cast<const ConfigurationNode*>(this))->getNode(path));
130 }
131 
133 {
134  if (isNull()) {
135  return this;
136  }
137 
138  // Getting the first element of the path
139  QString firstNode = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
140 
141  if (firstNode.isEmpty()) {
142  // If the first node is the empty string (i.e. the whole path is the empty string) returning this
143 
144  return this;
145  } else if (firstNode == ConfigurationParameters::ParentGroup()) {
146  // The path points to our parent group, returning it (if we have no parent, returning self)
147 
148  return (m_parent == NULL) ? this : m_parent;
149  } else {
150  // Getting the first node from the list of my children and, if it exists, calling its getNode function
151  foreach( QString child, m_children.keys() ) {
152  if ( child.compare( firstNode, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
153  QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
154  return m_children[child]->getNode(remainingPath);
155  }
156  }
157  // child not found
158  m_nullNode->clearAll();
159  return m_nullNode;
160  }
161 }
162 
164 {
165  if (isNull()) {
166  return false;
167  }
168 
169  // Searching the element to remove
170  foreach( QString child, m_children.keys() ) {
171  if ( child.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
172  m_children.remove(child);
173  m_childrenkeys.removeAll(name);
174  return true;
175  }
176  }
177 
178  // If the node doesn't exist, returning false
179  return false;
180 }
181 
182 bool ConfigurationNode::renameNode(QString oldName, QString newName)
183 {
184  if (isNull() || (newName.isEmpty()) || (newName == ConfigurationParameters::GroupSeparator()) || (newName == ConfigurationParameters::ParentGroup())) {
185  return false;
186  }
187 
188  // If the node doesn't exist, returning false
189  QString oldCaseAwareName = QString();
190  foreach( QString child, m_children.keys() ) {
191  if ( child.compare( oldName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
192  oldCaseAwareName = child;
193  break;
194  }
195  }
196  if ( oldCaseAwareName.isEmpty() ) {
197  return false;
198  }
199 
200  // Take the element with oldName and re-insert it with newName
201  ConfigurationNode* node = m_children.take(oldCaseAwareName);
202  m_children.insert(newName, node);
203  // change the name in the childrenkeys mantaining the order
204  int id = m_childrenkeys.indexOf(oldCaseAwareName);
205  m_childrenkeys.replace( id, newName );
206  return true;
207 }
208 
209 QList<ConfigurationNode*> ConfigurationNode::getChildrenNodesList()
210 {
211  return m_children.values();
212 }
213 
215 {
216  return m_childrenkeys;
217 }
218 
219 QStringList ConfigurationNode::getFilteredChildrenList(QRegExp filter) const
220 {
221  return m_childrenkeys.filter(filter);
222 }
223 
224 bool ConfigurationNode::setObjectForNode(QString path, ParameterSettable* object, ObjectCreationStatus status)
225 {
226  // Getting the node for path
227  ConfigurationNode* node = getNode(path);
228 
229  if (node->isNull()) {
230  return false;
231  }
232 
233  // Setting the object and its status
234  if ((object != NULL) || (status == CreatingObject)) {
235  node->m_object.object = object;
236  }
237  node->m_object.objectStatus = status;
238 
239  return true;
240 }
241 
243 {
244  m_object.object = NULL;
245  m_object.objectStatus = ObjectNotCreated;
246 }
247 
249 {
250  // Getting the node for path
251  const ConfigurationNode* node = getNode(path);
252 
253  if (node->isNull()) {
254  return ObjectAndStatus();
255  }
256 
257  return node->m_object;
258 }
259 
261 {
262  // Not adding the property if its name is NULL, the group separator, the parent group or if this is a null node
263  if ((isNull()) || (name.isEmpty()) || (name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) {
264  return false;
265  }
266 
267  // Searching if a property with that name already exists
268  foreach( QString parameter, m_parameters.keys() ) {
269  if ( parameter.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
270  return false;
271  }
272  }
273  // Adding the new parameter to the map with an empty value
274  m_parameters.insert(name, QString(""));
275  m_parameterskeys.push_back(name);
276  return true;
277 }
278 
279 QString ConfigurationNode::getValue(QString path, bool alsoMatchParents) const
280 {
281  if (isNull()) {
282  return QString();
283  }
284 
285  // The value to return
286  QString value = QString();
287 
288  // Getting the first element of the path and the remaining part of it
289  QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
290  QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
291 
292  if (remainingPath.isEmpty()) {
293  // This must be a parameter of mine, otherwise an error occurred
294  foreach( QString parameter, m_parameters.keys() ) {
295  if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
296  value = m_parameters[parameter];
297  break;
298  }
299  }
300  } else if (firstPart == ConfigurationParameters::ParentGroup()) {
301  // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
302 
303  const ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
304  return p->getValue(remainingPath, alsoMatchParents);
305  } else {
306  // The value of the parameter in the current node (used only if alsoMatchParents is true)
307  QString currentParameterValue = QString();
308 
309  // If alsoMatchParents is true checking if we have that parameter before calling child nodes
310  if (alsoMatchParents) {
311  QString parameterName = path.section(ConfigurationParameters::GroupSeparator(), -1, -1, QString::SectionSkipEmpty);
312  foreach( QString parameter, m_parameters.keys() ) {
313  if ( parameter.compare( parameterName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
314  currentParameterValue = m_parameters[parameter];
315  break;
316  }
317  }
318  }
319 
320  // Getting the first node from the list of my children and, if it exists, calling its getValue function
321  foreach( QString child, m_children.keys() ) {
322  if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
323  value = m_children[child]->getValue(remainingPath, alsoMatchParents);
324  // If we also have to match the parameter in parents and the parameter wasn't found in children,
325  // using our value
326  if ((alsoMatchParents) && (value.isEmpty())) {
327  value = currentParameterValue;
328  }
329  break;
330  }
331  }
332  }
333  return value;
334 }
335 
336 ConfigurationNode::ObjectAndStatus ConfigurationNode::getObject(QString path, bool alsoMatchParents) const
337 {
338  if (isNull()) {
339  return ObjectAndStatus();
340  }
341 
342  // The value to return (the object field is set to NULL by the constructor)
343  ObjectAndStatus object;
344 
345  // Getting the first element of the path and the remaining part of it
346  QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
347  QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
348 
349  if (remainingPath.isEmpty()) {
350  foreach( QString parameter, m_objectParameters.keys() ) {
351  if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
352  object = m_objectParameters[parameter];
353  break;
354  }
355  }
356  } else if (firstPart == ConfigurationParameters::ParentGroup()) {
357  // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
358 
359  const ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
360  return p->getObject(remainingPath, alsoMatchParents);
361  } else {
362  // The value of the parameter in the current node (used only if alsoMatchParents is true)
363  ObjectAndStatus currentParameterObject;
364 
365  // If alsoMatchParents is true checking if we have that parameter before calling child nodes
366  if (alsoMatchParents) {
367  QString parameterName = path.section(ConfigurationParameters::GroupSeparator(), -1, -1, QString::SectionSkipEmpty);
368  foreach( QString parameter, m_objectParameters.keys() ) {
369  if ( parameter.compare( parameterName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
370  currentParameterObject = m_objectParameters[parameter];
371  break;
372  }
373  }
374  }
375 
376  // Getting the first node from the list of my children and, if it exists, calling its getObject function
377  foreach( QString child, m_children.keys() ) {
378  if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
379  object = m_children[child]->getObject(remainingPath, alsoMatchParents);
380  // If we also have to match the parameter in parents and the parameter wasn't found in children,
381  // using our value
382  if ((alsoMatchParents) && (object.object == NULL)) {
383  object = currentParameterObject;
384  }
385  break;
386  }
387  }
388  }
389 
390  return object;
391 }
392 
393 bool ConfigurationNode::setValue(QString path, QString value)
394 {
395  if (isNull()) {
396  return false;
397  }
398 
399  // Getting the first element of the path and the remaining part of it
400  QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
401  QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
402 
403  if (remainingPath.isEmpty()) {
404  // This must be a parameter of mine, otherwise an error occurred
405  foreach( QString parameter, m_parameters.keys() ) {
406  if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
407  m_parameters[parameter] = value;
408  return true;
409  }
410  }
411  return false;
412  } else if (firstPart == ConfigurationParameters::ParentGroup()) {
413  // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
414 
415  ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
416  return p->setValue(remainingPath, value);
417  } else {
418  // Getting the first node from the list of my children and, if it exists, calling its setValue function
419  foreach( QString child, m_children.keys() ) {
420  if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
421  return m_children[child]->setValue(remainingPath, value);
422  }
423  }
424  return false;
425  }
426 }
427 
429 {
430  if (isNull()) {
431  return false;
432  }
433 
434  // Getting the first element of the path and the remaining part of it
435  QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
436  QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
437 
438  if (remainingPath.isEmpty()) {
439  // This must be a parameter of mine, otherwise an error occurred
440  foreach( QString parameter, m_parameters.keys() ) {
441  if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
442  m_parameters[parameter] = QString(" ");
443  // Saving the reference to the object into the m_objectParameters map
444  m_objectParameters[parameter].object = object;
445  m_objectParameters[parameter].objectStatus = ObjectCreatedAndConfigured;
446  return true;
447  }
448  }
449  return false;
450  } else if (firstPart == ConfigurationParameters::ParentGroup()) {
451  // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
452 
453  ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
454  return p->setValue(remainingPath, object);
455  } else {
456  // Getting the first node from the list of my children and, if it exists, calling its setValue function
457  foreach( QString child, m_children.keys() ) {
458  if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
459  return m_children[child]->setValue(remainingPath, object);
460  }
461  }
462  return false;
463  }
464 }
465 
467 {
468  if (isNull()) {
469  return false;
470  }
471 
472  // Searching the element to remove
473  foreach( QString parameter, m_parameters.keys() ) {
474  if ( parameter.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
475  m_parameters.remove( parameter );
476  m_parameterskeys.removeAll( parameter );
477  return true;
478  }
479  }
480  return false;
481 }
482 
484 {
485  // NULL nodes have no parameters, so this returns an empty list
486  return m_parameterskeys;
487 }
488 
489 QStringList ConfigurationNode::getFilteredParametersList(QRegExp filter) const
490 {
491  return m_parameterskeys.filter(filter);
492 }
493 
495 {
496  // NULL nodes have no parameters, so this returns an empty list
497  return QStringList(m_objectParameters.keys());
498 }
499 
500 QStringList ConfigurationNode::getFilteredObjectParametersList(QRegExp filter) const
501 {
502  return QStringList(m_objectParameters.keys()).filter(filter);
503 }
504 
506 {
507  if (isNull()) {
508  return;
509  }
510 
511  // Removing all child nodes
512  for (QMap<QString, ConfigurationNode*>::iterator it = m_children.begin(); it != m_children.end(); it++) {
513  delete it.value();
514  }
515  m_children.clear();
516  m_childrenkeys.clear();
517 
518  // Removing all parameters
519  m_parameters.clear();
520  m_parameterskeys.clear();
521 }
522 
523 } // end namespace farsa