configuration/src/configurationnode.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Tomassino Ferrauto                              *
00003  *   t_ferrauto@yahoo.it                                                   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include "configurationnode.h"
00022 #include "configurationparameters.h"
00023 #include <memory>
00024 
00025 namespace farsa {
00026 
00027 ConfigurationNode::ConfigurationNode(ConfigurationNode *parent, QString name, bool caseSensitive) :
00028     m_parent(parent),
00029     m_caseSensitive(caseSensitive),
00030     m_name(((name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) ? QString() : name),
00031     m_nullNode(m_name.isNull() ? NULL : new ConfigurationNode(this, QString())),
00032     m_nullValue(),
00033     m_object(),
00034     m_children(),
00035     m_childrenkeys(),
00036     m_parameters(),
00037     m_parameterskeys(),
00038     m_objectParameters()
00039 {
00040 }
00041 
00042 ConfigurationNode::~ConfigurationNode()
00043 {
00044     // Removing the null node
00045     delete m_nullNode;
00046 
00047     // Removing everything
00048     clearAll();
00049 }
00050 
00051 QList<const ConfigurationNode*> ConfigurationNode::getAncestors() const
00052 {
00053     if (isNull()) {
00054         return QList<const ConfigurationNode*>();
00055     }
00056 
00057     QList<const ConfigurationNode*> list;
00058 
00059     // If we have a parent, calling its getAncestors and appending us to the result
00060     if (m_parent != NULL) {
00061         list = m_parent->getAncestors();
00062     }
00063 
00064     list.append(this);
00065 
00066     return list;
00067 }
00068 
00069 QStringList ConfigurationNode::getAncestorsNames() const
00070 {
00071     if (isNull()) {
00072         return QStringList();
00073     }
00074 
00075     QStringList list;
00076 
00077     // If we have a parent, calling its getAncestorsNames and appending us to the result, otherwise returning the
00078     // list with only the empty string (the root node is referenced using "")
00079     if (m_parent != NULL) {
00080         list = m_parent->getAncestorsNames();
00081         list.append(m_name);
00082     } else {
00083         list.append("");
00084     }
00085 
00086     return list;
00087 }
00088 
00089 QString ConfigurationNode::getFullName() const
00090 {
00091     if (isNull()) {
00092         return QString();
00093     }
00094 
00095     // If we have a parent, calling its getFullName and prepending the result to our name
00096     if (m_parent != NULL) {
00097         return m_parent->getFullName() + ConfigurationParameters::GroupSeparator() + m_name;
00098     } else {
00099         return m_name;
00100     }
00101 }
00102 
00103 ConfigurationNode* ConfigurationNode::addNode(QString name)
00104 {
00105     // Not adding the node if its name is NULL, the group separator or the parent node or if this is a null node
00106     if ((isNull()) || (name.isEmpty()) || (name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) {
00107         // The NULL node hasn't a NULL node inside, returning self
00108         return (isNull()) ? this : m_nullNode;
00109     }
00110 
00111     // Checking if a node with that name already exists
00112     foreach( QString child, m_children.keys() ) {
00113         if ( child.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00114             return m_children[child];
00115         }
00116     }
00117 
00118     std::auto_ptr<ConfigurationNode> newNode(new ConfigurationNode(this, name, m_caseSensitive));
00119 
00120     m_children.insert(name, newNode.get());
00121     m_childrenkeys.push_back(name);
00122 
00123     return newNode.release();
00124 }
00125 
00126 ConfigurationNode* ConfigurationNode::getNode(QString path)
00127 {
00128     // Using the const version and a const_cast
00129     return const_cast<ConfigurationNode*>((const_cast<const ConfigurationNode*>(this))->getNode(path));
00130 }
00131 
00132 const ConfigurationNode* ConfigurationNode::getNode(QString path) const
00133 {
00134     if (isNull()) {
00135         return this;
00136     }
00137 
00138     // Getting the first element of the path
00139     QString firstNode = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
00140 
00141     if (firstNode.isEmpty()) {
00142         // If the first node is the empty string (i.e. the whole path is the empty string) returning this
00143 
00144         return this;
00145     } else if (firstNode == ConfigurationParameters::ParentGroup()) {
00146         // The path points to our parent group, returning it (if we have no parent, returning self)
00147 
00148         return (m_parent == NULL) ? this : m_parent;
00149     } else {
00150         // Getting the first node from the list of my children and, if it exists, calling its getNode function
00151         foreach( QString child, m_children.keys() ) {
00152             if ( child.compare( firstNode, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00153                 QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
00154                 return m_children[child]->getNode(remainingPath);
00155             }
00156         }
00157         // child not found
00158         m_nullNode->clearAll();
00159         return m_nullNode;
00160     }
00161 }
00162 
00163 bool ConfigurationNode::deleteNode(QString name)
00164 {
00165     if (isNull()) {
00166         return false;
00167     }
00168 
00169     // Searching the element to remove
00170     foreach( QString child, m_children.keys() ) {
00171         if ( child.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00172             m_children.remove(child);
00173             m_childrenkeys.removeAll(name);
00174             return true;
00175         }
00176     }
00177 
00178     // If the node doesn't exist, returning false
00179     return false;
00180 }
00181 
00182 bool ConfigurationNode::renameNode(QString oldName, QString newName)
00183 {
00184     if (isNull() || (newName.isEmpty()) || (newName == ConfigurationParameters::GroupSeparator()) || (newName == ConfigurationParameters::ParentGroup())) {
00185         return false;
00186     }
00187     
00188     // If the node doesn't exist, returning false
00189     QString oldCaseAwareName = QString();
00190     foreach( QString child, m_children.keys() ) {
00191         if ( child.compare( oldName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00192             oldCaseAwareName = child;
00193             break;
00194         }
00195     }
00196     if ( oldCaseAwareName.isEmpty() ) {
00197         return false;
00198     }
00199 
00200     // Take the element with oldName and re-insert it with newName
00201     ConfigurationNode* node = m_children.take(oldCaseAwareName);
00202     m_children.insert(newName, node);
00203     // change the name in the childrenkeys mantaining the order
00204     int id = m_childrenkeys.indexOf(oldCaseAwareName);
00205     m_childrenkeys.replace( id, newName );
00206     return true;
00207 }
00208 
00209 QList<ConfigurationNode*> ConfigurationNode::getChildrenNodesList()
00210 {
00211     return m_children.values();
00212 }
00213 
00214 QStringList ConfigurationNode::getChildrenList() const
00215 {
00216     return m_childrenkeys;
00217 }
00218 
00219 QStringList ConfigurationNode::getFilteredChildrenList(QRegExp filter) const
00220 {
00221     return m_childrenkeys.filter(filter);
00222 }
00223 
00224 bool ConfigurationNode::setObjectForNode(QString path, ParameterSettable* object, ObjectCreationStatus status)
00225 {
00226     // Getting the node for path
00227     ConfigurationNode* node = getNode(path);
00228 
00229     if (node->isNull()) {
00230         return false;
00231     }
00232 
00233     // Setting the object and its status
00234     if ((object != NULL) || (status == CreatingObject)) {
00235         node->m_object.object = object;
00236     }
00237     node->m_object.objectStatus = status;
00238 
00239     return true;
00240 }
00241 
00242 void ConfigurationNode::resetObject()
00243 {
00244     m_object.object = NULL;
00245     m_object.objectStatus = ObjectNotCreated;
00246 }
00247 
00248 ConfigurationNode::ObjectAndStatus ConfigurationNode::getObjectForNode(QString path) const
00249 {
00250     // Getting the node for path
00251     const ConfigurationNode* node = getNode(path);
00252 
00253     if (node->isNull()) {
00254         return ObjectAndStatus();
00255     }
00256 
00257     return node->m_object;
00258 }
00259 
00260 bool ConfigurationNode::addParameter(QString name)
00261 {
00262     // Not adding the property if its name is NULL, the group separator, the parent group or if this is a null node
00263     if ((isNull()) || (name.isEmpty()) || (name == ConfigurationParameters::GroupSeparator()) || (name == ConfigurationParameters::ParentGroup())) {
00264         return false;
00265     }
00266 
00267     // Searching if a property with that name already exists
00268     foreach( QString parameter, m_parameters.keys() ) {
00269         if ( parameter.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00270             return false;
00271         }
00272     }
00273     // Adding the new parameter to the map with an empty value
00274     m_parameters.insert(name, QString(""));
00275     m_parameterskeys.push_back(name);
00276     return true;
00277 }
00278 
00279 QString ConfigurationNode::getValue(QString path, bool alsoMatchParents) const
00280 {
00281     if (isNull()) {
00282         return QString();
00283     }
00284 
00285     // The value to return
00286     QString value = QString();
00287 
00288     // Getting the first element of the path and the remaining part of it
00289     QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
00290     QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
00291 
00292     if (remainingPath.isEmpty()) {
00293         // This must be a parameter of mine, otherwise an error occurred
00294         foreach( QString parameter, m_parameters.keys() ) {
00295             if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00296                 value = m_parameters[parameter];
00297                 break;
00298             }
00299         }
00300     } else if (firstPart == ConfigurationParameters::ParentGroup()) {
00301         // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
00302 
00303         const ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
00304         return p->getValue(remainingPath, alsoMatchParents);
00305     } else {
00306         // The value of the parameter in the current node (used only if alsoMatchParents is true)
00307         QString currentParameterValue = QString();
00308 
00309         // If alsoMatchParents is true checking if we have that parameter before calling child nodes
00310         if (alsoMatchParents) {
00311             QString parameterName = path.section(ConfigurationParameters::GroupSeparator(), -1, -1, QString::SectionSkipEmpty);
00312             foreach( QString parameter, m_parameters.keys() ) {
00313                 if ( parameter.compare( parameterName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00314                     currentParameterValue = m_parameters[parameter];
00315                     break;
00316                 }
00317             }
00318         }
00319 
00320         // Getting the first node from the list of my children and, if it exists, calling its getValue function
00321         foreach( QString child, m_children.keys() ) {
00322             if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00323                 value = m_children[child]->getValue(remainingPath, alsoMatchParents);
00324                 // If we also have to match the parameter in parents and the parameter wasn't found in children,
00325                 // using our value
00326                 if ((alsoMatchParents) && (value.isEmpty())) {
00327                     value = currentParameterValue;
00328                 }
00329                 break;
00330             }
00331         }
00332     }
00333     return value;
00334 }
00335 
00336 ConfigurationNode::ObjectAndStatus ConfigurationNode::getObject(QString path, bool alsoMatchParents) const
00337 {
00338     if (isNull()) {
00339         return ObjectAndStatus();
00340     }
00341 
00342     // The value to return (the object field is set to NULL by the constructor)
00343     ObjectAndStatus object;
00344 
00345     // Getting the first element of the path and the remaining part of it
00346     QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
00347     QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
00348 
00349     if (remainingPath.isEmpty()) {
00350         foreach( QString parameter, m_objectParameters.keys() ) {
00351             if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00352                 object = m_objectParameters[parameter];
00353                 break;
00354             }
00355         }
00356     } else if (firstPart == ConfigurationParameters::ParentGroup()) {
00357         // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
00358 
00359         const ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
00360         return p->getObject(remainingPath, alsoMatchParents);
00361     } else {
00362         // The value of the parameter in the current node (used only if alsoMatchParents is true)
00363         ObjectAndStatus currentParameterObject;
00364 
00365         // If alsoMatchParents is true checking if we have that parameter before calling child nodes
00366         if (alsoMatchParents) {
00367             QString parameterName = path.section(ConfigurationParameters::GroupSeparator(), -1, -1, QString::SectionSkipEmpty);
00368             foreach( QString parameter, m_objectParameters.keys() ) {
00369                 if ( parameter.compare( parameterName, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00370                     currentParameterObject = m_objectParameters[parameter];
00371                     break;
00372                 }
00373             }
00374         }
00375 
00376         // Getting the first node from the list of my children and, if it exists, calling its getObject function
00377         foreach( QString child, m_children.keys() ) {
00378             if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00379                 object = m_children[child]->getObject(remainingPath, alsoMatchParents);
00380                 // If we also have to match the parameter in parents and the parameter wasn't found in children,
00381                 // using our value
00382                 if ((alsoMatchParents) && (object.object == NULL)) {
00383                     object = currentParameterObject;
00384                 }
00385                 break;
00386             }
00387         }
00388     }
00389 
00390     return object;
00391 }
00392 
00393 bool ConfigurationNode::setValue(QString path, QString value)
00394 {
00395     if (isNull()) {
00396         return false;
00397     }
00398 
00399     // Getting the first element of the path and the remaining part of it
00400     QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
00401     QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
00402 
00403     if (remainingPath.isEmpty()) {
00404         // This must be a parameter of mine, otherwise an error occurred
00405         foreach( QString parameter, m_parameters.keys() ) {
00406             if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00407                 m_parameters[parameter] = value;
00408                 return true;
00409             }
00410         }
00411         return false;
00412     } else if (firstPart == ConfigurationParameters::ParentGroup()) {
00413         // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
00414 
00415         ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
00416         return p->setValue(remainingPath, value);
00417     } else {
00418         // Getting the first node from the list of my children and, if it exists, calling its setValue function
00419         foreach( QString child, m_children.keys() ) {
00420             if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00421                 return m_children[child]->setValue(remainingPath, value);
00422             }
00423         }
00424         return false;
00425     }
00426 }
00427 
00428 bool ConfigurationNode::setValue(QString path, ParameterSettable* object)
00429 {
00430     if (isNull()) {
00431         return false;
00432     }
00433 
00434     // Getting the first element of the path and the remaining part of it
00435     QString firstPart = path.section(ConfigurationParameters::GroupSeparator(), 0, 0, QString::SectionSkipEmpty);
00436     QString remainingPath = path.section(ConfigurationParameters::GroupSeparator(), 1, -1, QString::SectionSkipEmpty);
00437 
00438     if (remainingPath.isEmpty()) {
00439         // This must be a parameter of mine, otherwise an error occurred
00440         foreach( QString parameter, m_parameters.keys() ) {
00441             if ( parameter.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00442                 m_parameters[parameter] = QString(" ");
00443                 // Saving the reference to the object into the m_objectParameters map
00444                 m_objectParameters[parameter].object = object;
00445                 m_objectParameters[parameter].objectStatus = ObjectCreatedAndConfigured;
00446                 return true;
00447             }
00448         }
00449         return false;
00450     } else if (firstPart == ConfigurationParameters::ParentGroup()) {
00451         // Calling the function in parent group (calling it again on ourself if we don't have any parent group)
00452 
00453         ConfigurationNode* const p = (m_parent == NULL) ? this : m_parent;
00454         return p->setValue(remainingPath, object);
00455     } else {
00456         // Getting the first node from the list of my children and, if it exists, calling its setValue function
00457         foreach( QString child, m_children.keys() ) {
00458             if ( child.compare( firstPart, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00459                 return m_children[child]->setValue(remainingPath, object);
00460             }
00461         }
00462         return false;
00463     }
00464 }
00465 
00466 bool ConfigurationNode::deleteParameter(QString name)
00467 {
00468     if (isNull()) {
00469         return false;
00470     }
00471 
00472     // Searching the element to remove
00473     foreach( QString parameter, m_parameters.keys() ) {
00474         if ( parameter.compare( name, (m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) ) == 0 ) {
00475             m_parameters.remove( parameter );
00476             m_parameterskeys.removeAll( parameter );
00477             return true;
00478         }
00479     }
00480     return false;
00481 }
00482 
00483 QStringList ConfigurationNode::getParametersList() const
00484 {
00485     // NULL nodes have no parameters, so this returns an empty list
00486     return m_parameterskeys;
00487 }
00488 
00489 QStringList ConfigurationNode::getFilteredParametersList(QRegExp filter) const
00490 {
00491     return m_parameterskeys.filter(filter);
00492 }
00493 
00494 QStringList ConfigurationNode::getObjectParametersList() const
00495 {
00496     // NULL nodes have no parameters, so this returns an empty list
00497     return QStringList(m_objectParameters.keys());
00498 }
00499 
00500 QStringList ConfigurationNode::getFilteredObjectParametersList(QRegExp filter) const
00501 {
00502     return QStringList(m_objectParameters.keys()).filter(filter);
00503 }
00504 
00505 void ConfigurationNode::clearAll()
00506 {
00507     if (isNull()) {
00508         return;
00509     }
00510 
00511     // Removing all child nodes
00512     for (QMap<QString, ConfigurationNode*>::iterator it = m_children.begin(); it != m_children.end(); it++) {
00513         delete it.value();
00514     }
00515     m_children.clear();
00516     m_childrenkeys.clear();
00517 
00518     // Removing all parameters
00519     m_parameters.clear();
00520     m_parameterskeys.clear();
00521 }
00522 
00523 } // end namespace farsa