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
QStringList getFilteredParametersList(QRegExp filter) const
Returns the list of parameters whose name matches the given regular expression.
QStringList getParametersList() const
Returns the list of parameter names.
bool deleteNode(QString name)
Removes the child node with the given name.
QStringList getFilteredObjectParametersList(QRegExp filter) const
Returns the list of parameters referring to objects.
~ConfigurationNode()
Destructor. This also destroys child nodes.
ObjectCreationStatus objectStatus
The status of the object.
bool renameNode(QString oldName, QString newName)
Rename the child node with the new given name.
bool isNull() const
Returns true if this is a NULL node.
The class containing configuration parameters.
ObjectAndStatus getObjectForNode(QString path) const
Returns the object corresponding to the given node.
void clearAll()
Deletes all children and parameters.
The base for classes that can be configured/saved using a ConfigurationParameters object...
ConfigurationNode * getNode(QString path)
Returns a pointer to the node having the given path.
QString getFullName() const
Returns the full name of the node (i.e. the full path from root to this node)
ConfigurationNode(ConfigurationNode *parent, QString name=QString(), bool caseSensitive=false)
Constructor. This creates an empty node.
QList< ConfigurationNode * > getChildrenNodesList()
Returns the list of child nodes.
static QString ParentGroup()
The sequence used to indicate the parent group.
QString getValue(QString path, bool alsoMatchParents=false) const
Returns the value of the parameter with the given path.
QStringList getFilteredChildrenList(QRegExp filter) const
Returns the list of child nodes whose name matches the given regular expression.
bool addParameter(QString name)
Adds a new parameter.
ObjectAndStatus getObject(QString path, bool alsoMatchParents=false) const
Returns the object to which the parameter with the given path refer.
void resetObject()
Resets the object for this node.
QStringList getChildrenList() const
Returns the list of child nodes (the list of names)
ParameterSettable * object
The object.
The structure with the object for a node and its status.
bool setValue(QString path, QString value)
Sets the value of the parameter with the given path.
bool deleteParameter(QString name)
Deletes a parameter.
A node in the configuration tree.
QList< const ConfigurationNode * > getAncestors() const
Returns a list of pointers to ancestor nodes.
QStringList getAncestorsNames() const
Returns a list of names of ancestor nodes.
static QString GroupSeparator()
The character used to split path in groups.
ConfigurationNode * addNode(QString name)
Adds a child node with the given name and returns a pointer to it.
QStringList getObjectParametersList() const
Returns the list of parameters referring to objects.
bool setObjectForNode(QString path, ParameterSettable *object, ObjectCreationStatus status=ObjectCreatedAndConfigured)
Sets the object corresponding to the given node to object.