configurationparameters.cpp
1 /***************************************************************************
2  * Copyright (C) 2008-2009 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 "realfactory.h"
22 #include "configurationnode.h"
23 #include "configurationparameters.h"
24 #include "parametersfileloadersaver.h"
25 #include "parametersettable.h"
26 #include "configurationexceptions.h"
27 #include <QFileInfo>
28 #include <QQueue>
29 #include <memory>
30 
31 namespace farsa {
32 
33 QMap<QString, ConfigurationParameters::FileFormat>& ConfigurationParameters::getFormatsMap()
34 {
35  static QMap<QString, ConfigurationParameters::FileFormat> formatsMap;
36 
37  return formatsMap;
38 }
39 
40 QMap<QString, QString>& ConfigurationParameters::getFileExtensionsMap()
41 {
42  static QMap<QString, QString> fileExtensionsMap;
43 
44  return fileExtensionsMap;
45 }
46 
47 bool ConfigurationParameters::registerFileFormat(QString format, ParametersFileLoaderSaver *fileLoaderSaver, QString defaultExtension)
48 {
49  // Checking whether the format already exists
50  QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
51  if (it != getFormatsMap().end()) {
52  return false;
53  }
54 
55  // If defaultExtension is the empty string, changing it to format
56  if (defaultExtension.isEmpty()) {
57  defaultExtension = format;
58  }
59 
60  // Filling the structure with format informations
61  FileFormat f(format, fileLoaderSaver, defaultExtension);
62 
63  // Adding format to maps
64  getFormatsMap().insert(format, f);
65  getFileExtensionsMap().insert(defaultExtension, format);
66 
67  return true;
68 }
69 
71  m_factory(new RealFactory(*this)),
72  m_root(new ConfigurationNode(NULL, "", caseSensitive)),
73  m_getObjectFromGroupRecursionLevel(0),
74  m_objectsToConfigure(),
75  m_dontForgetGroupObjectAssociations(false),
76  m_resourcesUserPerRecursionLevel(QList<SimpleResourcesUser>() << SimpleResourcesUser())
77 {
78 }
79 
81  m_factory(new RealFactory(*this)),
82  m_root(new ConfigurationNode(NULL, "", true)),
83  m_getObjectFromGroupRecursionLevel(0),
84  m_objectsToConfigure(),
85  m_dontForgetGroupObjectAssociations(false),
86  m_resourcesUserPerRecursionLevel(QList<SimpleResourcesUser>() << SimpleResourcesUser())
87 {
88  // Copying the tree
89  copyTree(other.m_root.get());
90 }
91 
93 {
94  // Checking that we are not in a call to getObjectFromGroup
95  if (m_getObjectFromGroupRecursionLevel != 0) {
97  }
98 
99  // Checking for self-assignement
100  if (&other == this) {
101  return *this;
102  }
103 
104  // Copying the tree (this removes the previous one)
105  copyTree(other.m_root.get());
106 
107  // Now also substituting all observers
108  m_factory->clearObservers();
109  m_factory->addObservers(other.m_factory->getObservers());
110 
111  return *this;
112 }
113 
115 {
116  // Nothing to do here, we use auto_ptr
117 }
118 
120 {
121  return m_root->isCaseSensitive();
122 }
123 
125 {
126  m_root->clearAll();
127 }
128 
129 QStringList ConfigurationParameters::getGroupsList(QString group) const
130 {
131  return m_root->getNode(group)->getChildrenList();
132 }
133 
134 QStringList ConfigurationParameters::getGroupsWithPrefixList(QString group, QString prefix) const
135 {
136  // Building the regular expression matching the given prefix
137  QRegExp filter(QString("^") + QRegExp::escape(prefix), (isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive));
138 
139  return getFilteredGroupsList(group, filter);
140 }
141 
142 QStringList ConfigurationParameters::getFilteredGroupsList(QString group, QRegExp filter) const
143 {
144  return m_root->getNode(group)->getFilteredChildrenList(filter);
145 }
146 
148 {
149  // Splitting path
150  QStringList splittedPath = groupPath.split(ConfigurationParameters::GroupSeparator(), QString::SkipEmptyParts, Qt::CaseSensitive);
151 
152  // Now creating all nodes
153  ConfigurationNode* lastNode = m_root.get();
154  for (QStringList::iterator it = splittedPath.begin(); it != splittedPath.end(); it++) {
155  lastNode = lastNode->addNode(*it);
156  }
157 }
158 
160 {
161  //--- extract the group name
162  QString groupName = groupPath.section( ConfigurationParameters::GroupSeparator(), -1 );
163  //--- extract the path
164  QString groupParent = groupPath.section( ConfigurationParameters::GroupSeparator(), 0, -2 );
165  return m_root->getNode(groupParent)->deleteNode(groupName);
166 }
167 
168 bool ConfigurationParameters::renameGroup(QString oldGroupPath, QString newGroupName)
169 {
170  //--- extract the group name
171  QString groupName = oldGroupPath.section( ConfigurationParameters::GroupSeparator(), -1 );
172  //--- extract the path
173  QString groupParent = oldGroupPath.section( ConfigurationParameters::GroupSeparator(), 0, -2 );
174  return m_root->getNode(groupParent)->renameNode(groupName, newGroupName);
175 }
176 
177 bool ConfigurationParameters::copyGroupTree(QString sourceGroup, QString destGroup) {
178  ConfigurationNode* sourceNode = m_root->getNode( sourceGroup );
179  if ( sourceNode->isNull() ) {
180  return false;
181  }
182  ConfigurationNode* destNode = m_root->getNode( destGroup );
183  if ( destNode->isNull() ) {
184  // create the destination node
185  createGroup( destGroup );
186  destNode = m_root->getNode( destGroup );
187  }
188  copyNode( sourceNode, destNode );
189  return true;
190 }
191 
192 void ConfigurationParameters::createParameter(QString groupPath, QString parameter)
193 {
194  ConfigurationNode* node = m_root->getNode(groupPath);
195  if ( !node->isNull() ) {
196  node->addParameter( parameter );
197  }
198 }
199 
200 void ConfigurationParameters::deleteParameter(QString groupPath, QString parameter) {
201  ConfigurationNode* node = m_root->getNode(groupPath);
202  if ( !node->isNull() ) {
203  node->deleteParameter( parameter );
204  }
205 }
206 
207 bool ConfigurationParameters::startObjectParameters(QString groupPath, QString typeName, ParameterSettable* object)
208 {
209  // Creating the group
210  createGroup(groupPath);
211 
212  // Then adding the "type" parameter
213  createParameter(groupPath, QString("type"), typeName);
214 
215  // Now setting the object corresponding to the given group to object
216  return m_root->setObjectForNode(groupPath, object);
217 }
218 
219 QString ConfigurationParameters::getValue(QString path, bool alsoMatchParents) const
220 {
221  return m_root->getValue(path, alsoMatchParents);
222 }
223 
224 bool ConfigurationParameters::setValue(QString path, QString value)
225 {
226  return m_root->setValue(path, value);
227 }
228 
230 {
231  return m_root->setValue(path, object);
232 }
233 
234 QStringList ConfigurationParameters::getParametersList(QString group) const
235 {
236  return m_root->getNode(group)->getParametersList();
237 }
238 
239 QStringList ConfigurationParameters::getParametersWithPrefixList(QString group, QString prefix) const
240 {
241  // Building the regular expression matching the given prefix
242  QRegExp filter(QString("^") + QRegExp::escape(prefix), (isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive));
243 
244  return getFilteredParametersList(group, filter);
245 }
246 
247 QStringList ConfigurationParameters::getFilteredParametersList(QString group, QRegExp filter) const
248 {
249  return m_root->getNode(group)->getFilteredParametersList(filter);
250 }
251 
253 {
254  m_dontForgetGroupObjectAssociations = true;
255 }
256 
258 {
259  m_dontForgetGroupObjectAssociations = false;
260 }
261 
263 {
264  // Descending the tree and calling resetObject on all nodes
265  QQueue<ConfigurationNode *> nodeQueue;
266  nodeQueue.enqueue(m_root.get());
267 
268  // Now descending the tree
269  while (!nodeQueue.isEmpty()) {
270  // Getting a node and calling resetObject on it
271  ConfigurationNode *curNode = nodeQueue.dequeue();
272  curNode->resetObject();
273 
274  // Now adding all children of current node to the queue
275  #if QT_VERSION_CHECK > 0x450000
276  nodeQueue.append(curNode->getChildrenNodesList());
277  #else
278  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
279  nodeQueue.append( an );
280  }
281  #endif
282  }
283 }
284 
286 {
287  // We perform the update in two steps: first of all we create a map from pointers to group paths;
288  // then we search the whole tree for object parameters and set them
289 
290  // First step: descending the tree and creating the map
291  QMap<ParameterSettable *, QString> objectsMap;
292  QQueue<ConfigurationNode *> nodeQueue;
293  nodeQueue.enqueue(m_root.get());
294 
295  // Now descending the tree
296  while (!nodeQueue.isEmpty()) {
297  // Getting a node and the object for that node
298  ConfigurationNode *curNode = nodeQueue.dequeue();
300 
301  if (object.object != NULL) {
302  // Adding to map
303  // --- when saving an object reference parameter, the first GroupSeparator() will
304  // be removed to avoid to save something like that:
305  // object = /groupPath/nameOfObject
306  // instead of
307  // object = groupPath/nameOfObject
308  QString fullname = curNode->getFullName();
309  if ( fullname.startsWith( GroupSeparator() ) ) {
310  fullname.remove( 0, 1 );
311  }
312  objectsMap[object.object] = fullname; //curNode->getFullName();
313  }
314 
315  // Now adding all children of current node to the queue
316  #if QT_VERSION_CHECK > 0x450000
317  nodeQueue.append(curNode->getChildrenNodesList());
318  #else
319  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
320  nodeQueue.append( an );
321  }
322  #endif
323  }
324 
325  // We have the list of objects and their path, now searching all object parameters
326  // and setting them (we re-use nodeQueue to descend the tree, it is empty for sure)
327  nodeQueue.enqueue(m_root.get());
328 
329  // Descending the tree one more time
330  while (!nodeQueue.isEmpty()) {
331  // Getting a node
332  ConfigurationNode *curNode = nodeQueue.dequeue();
333 
334  // Obtaining the list of object parameters
335  QStringList params = curNode->getObjectParametersList();
336 
337  for (QStringList::iterator it = params.begin(); it != params.end(); it++) {
338  // Getting the object for the parameter
339  ParameterSettable *obj = curNode->getObject(*it).object;
340 
341  // If we have a pointer to obj in the map, setting the value for the parameter
342  if (objectsMap.contains(obj)) {
343  curNode->setValue(*it, objectsMap[obj]);
344  } else {
345  curNode->setValue(*it, QString(""));
346  }
347  }
348 
349  // Now adding all children of current node to the queue
350  #if QT_VERSION_CHECK > 0x450000
351  nodeQueue.append(curNode->getChildrenNodesList());
352  #else
353  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
354  nodeQueue.append( an );
355  }
356  #endif
357  }
358 }
359 
360 bool ConfigurationParameters::loadParameters(QString filename, bool keepOld, QString format)
361 {
362  // If format is the empty string, guessing it from filename extension
363  if (format.isEmpty()) {
364  format = formatFromFilenameExtension(filename);
365 
366  if (format.isNull()) {
367  return false;
368  }
369  }
370 
371  // Searching the format on the map
372  QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
373 
374  // If not found, returning false
375  if (it == getFormatsMap().end()) {
376  return false;
377  }
378 
379  return it->fileLoaderSaver->load( filename, *this, keepOld );
380 }
381 
382 bool ConfigurationParameters::saveParameters(QString filename, QString format, bool append)
383 {
384  // Before saving updating all object references
386 
387  // If format is the empty string, guessing it from filename extension
388  if (format.isEmpty()) {
389  format = formatFromFilenameExtension(filename);
390 
391  if (format.isNull()) {
392  return false;
393  }
394  }
395 
396  // Searching the format on the map
397  QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
398 
399  // If not found, returning false
400  if (it == getFormatsMap().end()) {
401  return false;
402  }
403 
404  return it->fileLoaderSaver->save( filename, *this, append );
405 }
406 
408 {
409  // Searching the ResourceManager containing the given resource
410  for (int i = m_getObjectFromGroupRecursionLevel; i >= 0; i--) {
411  if (m_resourcesUserPerRecursionLevel[i].hasResource(resourceName)) {
412  return &(m_resourcesUserPerRecursionLevel[i]);
413  }
414  }
415 
416  return NULL;
417 }
418 
420 {
421  m_resourcesUserPerRecursionLevel.last().shareResourcesWith(resourcesUser);
422 }
423 
425 {
426  m_factory->addObserver(observer);
427 }
428 
430  m_factory->addObservers( params.m_factory->getObservers() );
431 }
432 
433 QString ConfigurationParameters::formatFromFilenameExtension(QString filename) const
434 {
435  QFileInfo info(filename);
436 
437  QMap<QString, QString>::const_iterator it = getFileExtensionsMap().find(info.suffix());
438  if (it == getFileExtensionsMap().end()) {
439  return QString();
440  } else {
441  return *it;
442  }
443 }
444 
445 void ConfigurationParameters::copyTree(const ConfigurationNode *root)
446 {
447  // Allocating root. Parent is not copied as we suppose root to be a root of a tree
448  m_root.reset(new ConfigurationNode(NULL, root->getName(), root->isCaseSensitive()));
449 
450  // Now recursively copying the tree
451  copyNode(root, m_root.get());
452 }
453 
454 void ConfigurationParameters::copyNode(const ConfigurationNode *source, ConfigurationNode *target)
455 {
456  // First copying all parameters
457  QStringList params = source->getParametersList();
458  for (QStringList::const_iterator it = params.begin(); it != params.end(); it++) {
459  target->addParameter(*it);
460  target->setValue(*it, source->getValue(*it));
461  }
462 
463  // We don't copy the object associated to the node
464 
465  // Now creating children in target and recursively filling them
466  QStringList children = source->getChildrenList();
467  for (QStringList::const_iterator it = children.begin(); it != children.end(); it++) {
468  target->addNode(*it);
469  copyNode(source->getNode(*it), target->getNode(*it));
470  }
471 }
472 
473 bool ConfigurationParameters::setObjectFromGroupStatusToCreating(QString group)
474 {
475  if (m_getObjectFromGroupRecursionLevel == 0) {
476  return true;
477  }
478  return m_root->setObjectForNode(group, NULL, CreatingObject);
479 }
480 
481 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedNotConfigured(QString group, ParameterSettable *object)
482 {
483  if (m_getObjectFromGroupRecursionLevel == 0) {
484  return true;
485  }
486  return m_root->setObjectForNode(group, object, ObjectCreatedNotConfigured);
487 }
488 
489 bool ConfigurationParameters::setObjectFromGroupStatusToConfiguring(QString group)
490 {
491  if (m_getObjectFromGroupRecursionLevel == 0) {
492  return true;
493  }
494  return m_root->setObjectForNode(group, NULL, ConfiguringObject);
495 }
496 
497 bool ConfigurationParameters::setObjectFromGroupStatusToCreatingAndConfiguring(QString group)
498 {
499  if (m_getObjectFromGroupRecursionLevel == 0) {
500  return true;
501  }
502  return m_root->setObjectForNode(group, NULL, CreatingAndConfiguringObject);
503 }
504 
505 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedAndConfigured(QString group, ParameterSettable *object)
506 {
507  if (m_getObjectFromGroupRecursionLevel == 0) {
508  return true;
509  }
510  return m_root->setObjectForNode(group, object, ObjectCreatedAndConfigured);
511 }
512 
513 } // end namespace farsa
void stopRememberingGroupObjectAssociations()
Stops remembering associations between groups and objects.
A simple class to access/declare resources (not thread-safe)
bool isCaseSensitive() const
Returns true if we are case sensistive, false otherwise.
QStringList getFilteredParametersList(QString group, QRegExp filter) const
Returns the list of parameters in the given group whose name matches the given regular expression...
bool loadParameters(QString filename, bool keepOld=false, QString format="")
Loads a configuration file.
bool copyGroupTree(QString sourceGroup, QString destGroup)
Copy a group tree to another location.
ConfigurationParameters(bool caseSensitive=false)
Constructor.
bool setValue(QString path, QString value)
Sets the value of the parameter with the given path.
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.
The base for classes that can be configured/saved using a ConfigurationParameters object...
QStringList getParametersWithPrefixList(QString group, QString prefix) const
Returns the list of parameters in the given group whose name starts with the provided string...
void updateObjectReferences()
Updates all object references to point to actual groups.
QString getFullName() const
Returns the full name of the node (i.e. the full path from root to this node)
bool deleteGroup(QString groupPath)
Delete the last group in the path specified.
QList< ConfigurationNode * > getChildrenNodesList()
Returns the list of child nodes.
SimpleResourcesUser * getResourcesUserForResource(QString resourceName)
Returns the resouce user holding the resource with the given name.
void shareObserversWith(ConfigurationParameters &params)
share the FactoryObservers with an another ConfigurationParameters
void createGroup(QString groupPath)
Create a group in the path specified.
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 resetGroupObjectAssociations()
Resets all associations between groups and objects.
void resetObject()
Resets the object for this node.
bool startObjectParameters(QString groupPath, QString typeName, ParameterSettable *object)
Initializes a group so that it corresponds to the given object.
FactoryObserver class to keep trace on operations done by Factory.
The parent of classes managing resources.
Definition: resourcesuser.h:70
void deleteParameter(QString groupPath, QString parameter)
Delete a parameter in the group path specified.
bool saveParameters(QString filename, QString format="", bool append=false)
Saves a configuration file.
QString getValue(QString path, bool alsoMatchParents=false) const
Returns a parameter value.
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 renameGroup(QString oldGroupPath, QString newGroupName)
Rename the last group in the path specified with the new name.
static bool registerFileFormat(QString format, ParametersFileLoaderSaver *fileLoaderSaver, QString defaultExtension)
The function to register file formats to use when loading or saving parameters from/to file...
QStringList getGroupsWithPrefixList(QString group, QString prefix) const
Returns the list of sub-groups in the given group whose name starts with the provided string...
QStringList getFilteredGroupsList(QString group, QRegExp filter) const
Returns the list of sub-groups in the given group whose name matches the given regular expression...
QStringList getGroupsList(QString group) const
Returns the list of sub-groups in the given group.
bool deleteParameter(QString name)
Deletes a parameter.
void setResourcesUser(ResourcesUser *resourcesUser)
Registers a new resource user.
A node in the configuration tree.
void addObserver(FactoryObserver *observer)
Add a new observer.
void clearAll()
Delete all parameters in all groups and subgroups.
void startRememberingGroupObjectAssociations()
Starts remembering associations between groups and objects.
static QString GroupSeparator()
The character used to split path in groups.
Factory class to create ParameterSettable objects.
Definition: realfactory.h:186
ConfigurationNode * addNode(QString name)
Adds a child node with the given name and returns a pointer to it.
QStringList getParametersList(QString group) const
Returns the list of parameters in the given group.
void createParameter(QString groupPath, QString parameter)
Create a parameter in the group path specified.
The exception thrown when trying to copy a ConfigurationParameter.
ConfigurationParameters & operator=(const ConfigurationParameters &other)
Assignment operator.
QStringList getObjectParametersList() const
Returns the list of parameters referring to objects.
The base for all classes able to load/save configuration parameters from/to file. ...