configuration/src/configurationparameters.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2008-2009 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 "realfactory.h"
00022 #include "configurationnode.h"
00023 #include "configurationparameters.h"
00024 #include "parametersfileloadersaver.h"
00025 #include "parametersettable.h"
00026 #include "configurationexceptions.h"
00027 #include <QFileInfo>
00028 #include <QQueue>
00029 #include <memory>
00030 
00031 namespace farsa {
00032 
00033 QMap<QString, ConfigurationParameters::FileFormat>& ConfigurationParameters::getFormatsMap()
00034 {
00035     static QMap<QString, ConfigurationParameters::FileFormat> formatsMap;
00036 
00037     return formatsMap;
00038 }
00039 
00040 QMap<QString, QString>& ConfigurationParameters::getFileExtensionsMap()
00041 {
00042     static QMap<QString, QString> fileExtensionsMap;
00043 
00044     return fileExtensionsMap;
00045 }
00046 
00047 bool ConfigurationParameters::registerFileFormat(QString format, ParametersFileLoaderSaver *fileLoaderSaver, QString defaultExtension)
00048 {
00049     // Checking whether the format already exists
00050     QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
00051     if (it != getFormatsMap().end()) {
00052         return false;
00053     }
00054 
00055     // If defaultExtension is the empty string, changing it to format
00056     if (defaultExtension.isEmpty()) {
00057         defaultExtension = format;
00058     }
00059 
00060     // Filling the structure with format informations
00061     FileFormat f(format, fileLoaderSaver, defaultExtension);
00062 
00063     // Adding format to maps
00064     getFormatsMap().insert(format, f);
00065     getFileExtensionsMap().insert(defaultExtension, format);
00066 
00067     return true;
00068 }
00069 
00070 ConfigurationParameters::ConfigurationParameters(bool caseSensitive) :
00071     m_factory(new RealFactory(*this)),
00072     m_root(new ConfigurationNode(NULL, "", caseSensitive)),
00073     m_getObjectFromGroupRecursionLevel(0),
00074     m_objectsToConfigure(),
00075     m_dontForgetGroupObjectAssociations(false),
00076     m_resourcesUserPerRecursionLevel(QList<SimpleResourcesUser>() << SimpleResourcesUser())
00077 {
00078 }
00079 
00080 ConfigurationParameters::ConfigurationParameters(const ConfigurationParameters &other) :
00081     m_factory(new RealFactory(*this)),
00082     m_root(NULL),
00083     m_getObjectFromGroupRecursionLevel(0),
00084     m_objectsToConfigure(),
00085     m_dontForgetGroupObjectAssociations(false),
00086     m_resourcesUserPerRecursionLevel(QList<SimpleResourcesUser>() << SimpleResourcesUser())
00087 {
00088     // Copying the tree
00089     copyTree(other.m_root.get());
00090 }
00091 
00092 ConfigurationParameters& ConfigurationParameters::operator=(const ConfigurationParameters &other)
00093 {
00094     // Checking that we are not in a call to getObjectFromGroup
00095     if (m_getObjectFromGroupRecursionLevel != 0) {
00096         throw CopyDuringObjectCreationException();
00097     }
00098 
00099     // Checking for self-assignement
00100     if (&other == this) {
00101         return *this;
00102     }
00103 
00104     // Copying the tree (this removes the previous one)
00105     copyTree(other.m_root.get());
00106 
00107     // Now also substituting all observers
00108     m_factory->clearObservers();
00109     m_factory->addObservers(other.m_factory->getObservers());
00110 
00111     return *this;
00112 }
00113 
00114 ConfigurationParameters::~ConfigurationParameters()
00115 {
00116     // Nothing to do here, we use auto_ptr
00117 }
00118 
00119 bool ConfigurationParameters::isCaseSensitive() const
00120 {
00121     return m_root->isCaseSensitive();
00122 }
00123 
00124 void ConfigurationParameters::clearAll()
00125 {
00126     m_root->clearAll();
00127 }
00128 
00129 QStringList ConfigurationParameters::getGroupsList(QString group) const
00130 {
00131     return m_root->getNode(group)->getChildrenList();
00132 }
00133 
00134 QStringList ConfigurationParameters::getGroupsWithPrefixList(QString group, QString prefix) const
00135 {
00136     // Building the regular expression matching the given prefix
00137     QRegExp filter(QString("^") + QRegExp::escape(prefix), (isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive));
00138 
00139     return getFilteredGroupsList(group, filter);
00140 }
00141 
00142 QStringList ConfigurationParameters::getFilteredGroupsList(QString group, QRegExp filter) const
00143 {
00144     return m_root->getNode(group)->getFilteredChildrenList(filter);
00145 }
00146 
00147 void ConfigurationParameters::createGroup(QString groupPath)
00148 {
00149     // Splitting path
00150     QStringList splittedPath = groupPath.split(ConfigurationParameters::GroupSeparator(), QString::SkipEmptyParts, Qt::CaseSensitive);
00151 
00152     // Now creating all nodes
00153     ConfigurationNode* lastNode = m_root.get();
00154     for (QStringList::iterator it = splittedPath.begin(); it != splittedPath.end(); it++) {
00155         lastNode = lastNode->addNode(*it);
00156     }
00157 }
00158 
00159 bool ConfigurationParameters::deleteGroup(QString groupPath)
00160 {
00161     //--- extract the group name
00162     QString groupName = groupPath.section( ConfigurationParameters::GroupSeparator(), -1 );
00163     //--- extract the path 
00164     QString groupParent = groupPath.section( ConfigurationParameters::GroupSeparator(), 0, -2 );
00165     return m_root->getNode(groupParent)->deleteNode(groupName);
00166 }
00167 
00168 bool ConfigurationParameters::renameGroup(QString oldGroupPath, QString newGroupName)
00169 {
00170     //--- extract the group name
00171     QString groupName = oldGroupPath.section( ConfigurationParameters::GroupSeparator(), -1 );
00172     //--- extract the path 
00173     QString groupParent = oldGroupPath.section( ConfigurationParameters::GroupSeparator(), 0, -2 );
00174     return m_root->getNode(groupParent)->renameNode(groupName, newGroupName);
00175 }
00176 
00177 void ConfigurationParameters::createParameter(QString groupPath, QString parameter)
00178 {
00179     ConfigurationNode* node = m_root->getNode(groupPath);
00180     if ( !node->isNull() ) {
00181         node->addParameter( parameter );
00182     }
00183 }
00184 
00185 void ConfigurationParameters::deleteParameter(QString groupPath, QString parameter) {
00186     ConfigurationNode* node = m_root->getNode(groupPath);
00187     if ( !node->isNull() ) {
00188         node->deleteParameter( parameter );
00189     }
00190 }
00191 
00192 bool ConfigurationParameters::startObjectParameters(QString groupPath, QString typeName, ParameterSettable* object)
00193 {
00194     // Creating the group
00195     createGroup(groupPath);
00196 
00197     // Then adding the "type" parameter
00198     createParameter(groupPath, QString("type"), typeName);
00199 
00200     // Now setting the object corresponding to the given group to object
00201     return m_root->setObjectForNode(groupPath, object);
00202 }
00203 
00204 QString ConfigurationParameters::getValue(QString path, bool alsoMatchParents) const
00205 {
00206     return m_root->getValue(path, alsoMatchParents);
00207 }
00208 
00209 bool ConfigurationParameters::setValue(QString path, QString value)
00210 {
00211     return m_root->setValue(path, value);
00212 }
00213 
00214 bool ConfigurationParameters::setValue(QString path, ParameterSettable* object)
00215 {
00216     return m_root->setValue(path, object);
00217 }
00218 
00219 QStringList ConfigurationParameters::getParametersList(QString group) const
00220 {
00221     return m_root->getNode(group)->getParametersList();
00222 }
00223 
00224 QStringList ConfigurationParameters::getParametersWithPrefixList(QString group, QString prefix) const
00225 {
00226     // Building the regular expression matching the given prefix
00227     QRegExp filter(QString("^") + QRegExp::escape(prefix), (isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive));
00228 
00229     return getFilteredParametersList(group, filter);
00230 }
00231 
00232 QStringList ConfigurationParameters::getFilteredParametersList(QString group, QRegExp filter) const
00233 {
00234     return m_root->getNode(group)->getFilteredParametersList(filter);
00235 }
00236 
00237 void ConfigurationParameters::startRememberingGroupObjectAssociations()
00238 {
00239     m_dontForgetGroupObjectAssociations = true;
00240 }
00241 
00242 void ConfigurationParameters::stopRememberingGroupObjectAssociations()
00243 {
00244     m_dontForgetGroupObjectAssociations = false;
00245 }
00246 
00247 void ConfigurationParameters::resetGroupObjectAssociations()
00248 {
00249     // Descending the tree and calling resetObject on all nodes
00250     QQueue<ConfigurationNode *> nodeQueue;
00251     nodeQueue.enqueue(m_root.get());
00252 
00253     // Now descending the tree
00254     while (!nodeQueue.isEmpty()) {
00255         // Getting a node and calling resetObject on it
00256         ConfigurationNode *curNode = nodeQueue.dequeue();
00257         curNode->resetObject();
00258 
00259         // Now adding all children of current node to the queue
00260         #if QT_VERSION_CHECK > 0x450000
00261             nodeQueue.append(curNode->getChildrenNodesList());
00262         #else
00263             foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
00264                 nodeQueue.append( an );
00265             }
00266         #endif
00267     }
00268 }
00269 
00270 void ConfigurationParameters::updateObjectReferences()
00271 {
00272     // We perform the update in two steps: first of all we create a map from pointers to group paths;
00273     // then we search the whole tree for object parameters and set them
00274 
00275     // First step: descending the tree and creating the map
00276     QMap<ParameterSettable *, QString> objectsMap;
00277     QQueue<ConfigurationNode *> nodeQueue;
00278     nodeQueue.enqueue(m_root.get());
00279 
00280     // Now descending the tree
00281     while (!nodeQueue.isEmpty()) {
00282         // Getting a node and the object for that node
00283         ConfigurationNode *curNode = nodeQueue.dequeue();
00284         ConfigurationNode::ObjectAndStatus object = curNode->getObjectForNode("");
00285 
00286         if (object.object != NULL) {
00287             // Adding to map
00288             // --- when saving an object reference parameter, the first GroupSeparator() will
00289             //     be removed to avoid to save something like that:
00290             // object = /groupPath/nameOfObject
00291             //    instead of
00292             // object = groupPath/nameOfObject
00293             QString fullname = curNode->getFullName();
00294             if ( fullname.startsWith( GroupSeparator() ) ) {
00295                 fullname.remove( 0, 1 );
00296             }
00297             objectsMap[object.object] = fullname; //curNode->getFullName();
00298         }
00299 
00300         // Now adding all children of current node to the queue
00301         #if QT_VERSION_CHECK > 0x450000
00302             nodeQueue.append(curNode->getChildrenNodesList());
00303         #else
00304             foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
00305                 nodeQueue.append( an );
00306             }
00307         #endif
00308     }
00309 
00310     // We have the list of objects and their path, now searching all object parameters
00311     // and setting them (we re-use nodeQueue to descend the tree, it is empty for sure)
00312     nodeQueue.enqueue(m_root.get());
00313 
00314     // Descending the tree one more time
00315     while (!nodeQueue.isEmpty()) {
00316         // Getting a node
00317         ConfigurationNode *curNode = nodeQueue.dequeue();
00318 
00319         // Obtaining the list of object parameters
00320         QStringList params = curNode->getObjectParametersList();
00321 
00322         for (QStringList::iterator it = params.begin(); it != params.end(); it++) {
00323             // Getting the object for the parameter
00324             ParameterSettable *obj = curNode->getObject(*it).object;
00325 
00326             // If we have a pointer to obj in the map, setting the value for the parameter
00327             if (objectsMap.contains(obj)) {
00328                 curNode->setValue(*it, objectsMap[obj]);
00329             } else {
00330                 curNode->setValue(*it, QString(""));
00331             }
00332         }
00333 
00334         // Now adding all children of current node to the queue
00335         #if QT_VERSION_CHECK > 0x450000
00336             nodeQueue.append(curNode->getChildrenNodesList());
00337         #else
00338             foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
00339                 nodeQueue.append( an );
00340             }
00341         #endif
00342     }
00343 }
00344 
00345 bool ConfigurationParameters::loadParameters(QString filename, bool keepOld, QString format)
00346 {
00347     // If format is the empty string, guessing it from filename extension
00348     if (format.isEmpty()) {
00349         format = formatFromFilenameExtension(filename);
00350 
00351         if (format.isNull()) {
00352             return false;
00353         }
00354     }
00355 
00356     // Searching the format on the map
00357     QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
00358 
00359     // If not found, returning false
00360     if (it == getFormatsMap().end()) {
00361         return false;
00362     }
00363 
00364     return it->fileLoaderSaver->load( filename, *this, keepOld );
00365 }
00366 
00367 bool ConfigurationParameters::saveParameters(QString filename, QString format, bool append)
00368 {
00369     // Before saving updating all object references
00370     updateObjectReferences();
00371 
00372     // If format is the empty string, guessing it from filename extension
00373     if (format.isEmpty()) {
00374         format = formatFromFilenameExtension(filename);
00375 
00376         if (format.isNull()) {
00377             return false;
00378         }
00379     }
00380 
00381     // Searching the format on the map
00382     QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
00383 
00384     // If not found, returning false
00385     if (it == getFormatsMap().end()) {
00386         return false;
00387     }
00388 
00389     return it->fileLoaderSaver->save( filename, *this, append );
00390 }
00391 
00392 SimpleResourcesUser* ConfigurationParameters::getResourcesUserForResource(QString resourceName)
00393 {
00394     // Searching the ResourceManager containing the given resource
00395     for (int i = m_getObjectFromGroupRecursionLevel; i >= 0; i--) {
00396         if (m_resourcesUserPerRecursionLevel[i].hasResource(resourceName)) {
00397             return &(m_resourcesUserPerRecursionLevel[i]);
00398         }
00399     }
00400 
00401     return NULL;
00402 }
00403 
00404 void ConfigurationParameters::setResourcesUser(ResourcesUser* resourcesUser)
00405 {
00406     m_resourcesUserPerRecursionLevel.last().shareResourcesWith(resourcesUser);
00407 }
00408 
00409 void ConfigurationParameters::addObserver(FactoryObserver* observer)
00410 {
00411     m_factory->addObserver(observer);
00412 }
00413 
00414 QString ConfigurationParameters::formatFromFilenameExtension(QString filename) const
00415 {
00416     QFileInfo info(filename);
00417 
00418     QMap<QString, QString>::const_iterator it = getFileExtensionsMap().find(info.suffix());
00419     if (it == getFileExtensionsMap().end()) {
00420         return QString();
00421     } else {
00422         return *it;
00423     }
00424 }
00425 
00426 void ConfigurationParameters::copyTree(const ConfigurationNode *root)
00427 {
00428     // Allocating root. Parent is not copied as we suppose root to be a root of a tree
00429     m_root.reset(new ConfigurationNode(NULL, root->getName(), root->isCaseSensitive()));
00430 
00431     // Now recursively copying the tree
00432     copyNode(root, m_root.get());
00433 }
00434 
00435 void ConfigurationParameters::copyNode(const ConfigurationNode *source, ConfigurationNode *target)
00436 {
00437     // First copying all parameters
00438     QStringList params = source->getParametersList();
00439     for (QStringList::const_iterator it = params.begin(); it != params.end(); it++) {
00440         target->addParameter(*it);
00441         target->setValue(*it, source->getValue(*it));
00442     }
00443 
00444     // We don't copy the object associated to the node
00445 
00446     // Now creating children in target and recursively filling them
00447     QStringList children = source->getChildrenList();
00448     for (QStringList::const_iterator it = children.begin(); it != children.end(); it++) {
00449         target->addNode(*it);
00450         copyNode(source->getNode(*it), target->getNode(*it));
00451     }
00452 }
00453 
00454 bool ConfigurationParameters::setObjectFromGroupStatusToCreating(QString group)
00455 {
00456     if (m_getObjectFromGroupRecursionLevel == 0) {
00457         return true;
00458     }
00459     return m_root->setObjectForNode(group, NULL, CreatingObject);
00460 }
00461 
00462 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedNotConfigured(QString group, ParameterSettable *object)
00463 {
00464     if (m_getObjectFromGroupRecursionLevel == 0) {
00465         return true;
00466     }
00467     return m_root->setObjectForNode(group, object, ObjectCreatedNotConfigured);
00468 }
00469 
00470 bool ConfigurationParameters::setObjectFromGroupStatusToConfiguring(QString group)
00471 {
00472     if (m_getObjectFromGroupRecursionLevel == 0) {
00473         return true;
00474     }
00475     return m_root->setObjectForNode(group, NULL, ConfiguringObject);
00476 }
00477 
00478 bool ConfigurationParameters::setObjectFromGroupStatusToCreatingAndConfiguring(QString group)
00479 {
00480     if (m_getObjectFromGroupRecursionLevel == 0) {
00481         return true;
00482     }
00483     return m_root->setObjectForNode(group, NULL, CreatingAndConfiguringObject);
00484 }
00485 
00486 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedAndConfigured(QString group, ParameterSettable *object)
00487 {
00488     if (m_getObjectFromGroupRecursionLevel == 0) {
00489         return true;
00490     }
00491     return m_root->setObjectForNode(group, object, ObjectCreatedAndConfigured);
00492 }
00493 
00494 } // end namespace farsa