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(NULL),
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 void ConfigurationParameters::createParameter(QString groupPath, QString parameter)
178 {
179  ConfigurationNode* node = m_root->getNode(groupPath);
180  if ( !node->isNull() ) {
181  node->addParameter( parameter );
182  }
183 }
184 
185 void ConfigurationParameters::deleteParameter(QString groupPath, QString parameter) {
186  ConfigurationNode* node = m_root->getNode(groupPath);
187  if ( !node->isNull() ) {
188  node->deleteParameter( parameter );
189  }
190 }
191 
192 bool ConfigurationParameters::startObjectParameters(QString groupPath, QString typeName, ParameterSettable* object)
193 {
194  // Creating the group
195  createGroup(groupPath);
196 
197  // Then adding the "type" parameter
198  createParameter(groupPath, QString("type"), typeName);
199 
200  // Now setting the object corresponding to the given group to object
201  return m_root->setObjectForNode(groupPath, object);
202 }
203 
204 QString ConfigurationParameters::getValue(QString path, bool alsoMatchParents) const
205 {
206  return m_root->getValue(path, alsoMatchParents);
207 }
208 
209 bool ConfigurationParameters::setValue(QString path, QString value)
210 {
211  return m_root->setValue(path, value);
212 }
213 
215 {
216  return m_root->setValue(path, object);
217 }
218 
219 QStringList ConfigurationParameters::getParametersList(QString group) const
220 {
221  return m_root->getNode(group)->getParametersList();
222 }
223 
224 QStringList ConfigurationParameters::getParametersWithPrefixList(QString group, QString prefix) const
225 {
226  // Building the regular expression matching the given prefix
227  QRegExp filter(QString("^") + QRegExp::escape(prefix), (isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive));
228 
229  return getFilteredParametersList(group, filter);
230 }
231 
232 QStringList ConfigurationParameters::getFilteredParametersList(QString group, QRegExp filter) const
233 {
234  return m_root->getNode(group)->getFilteredParametersList(filter);
235 }
236 
238 {
239  m_dontForgetGroupObjectAssociations = true;
240 }
241 
243 {
244  m_dontForgetGroupObjectAssociations = false;
245 }
246 
248 {
249  // Descending the tree and calling resetObject on all nodes
250  QQueue<ConfigurationNode *> nodeQueue;
251  nodeQueue.enqueue(m_root.get());
252 
253  // Now descending the tree
254  while (!nodeQueue.isEmpty()) {
255  // Getting a node and calling resetObject on it
256  ConfigurationNode *curNode = nodeQueue.dequeue();
257  curNode->resetObject();
258 
259  // Now adding all children of current node to the queue
260  #if QT_VERSION_CHECK > 0x450000
261  nodeQueue.append(curNode->getChildrenNodesList());
262  #else
263  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
264  nodeQueue.append( an );
265  }
266  #endif
267  }
268 }
269 
271 {
272  // We perform the update in two steps: first of all we create a map from pointers to group paths;
273  // then we search the whole tree for object parameters and set them
274 
275  // First step: descending the tree and creating the map
276  QMap<ParameterSettable *, QString> objectsMap;
277  QQueue<ConfigurationNode *> nodeQueue;
278  nodeQueue.enqueue(m_root.get());
279 
280  // Now descending the tree
281  while (!nodeQueue.isEmpty()) {
282  // Getting a node and the object for that node
283  ConfigurationNode *curNode = nodeQueue.dequeue();
285 
286  if (object.object != NULL) {
287  // Adding to map
288  // --- when saving an object reference parameter, the first GroupSeparator() will
289  // be removed to avoid to save something like that:
290  // object = /groupPath/nameOfObject
291  // instead of
292  // object = groupPath/nameOfObject
293  QString fullname = curNode->getFullName();
294  if ( fullname.startsWith( GroupSeparator() ) ) {
295  fullname.remove( 0, 1 );
296  }
297  objectsMap[object.object] = fullname; //curNode->getFullName();
298  }
299 
300  // Now adding all children of current node to the queue
301  #if QT_VERSION_CHECK > 0x450000
302  nodeQueue.append(curNode->getChildrenNodesList());
303  #else
304  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
305  nodeQueue.append( an );
306  }
307  #endif
308  }
309 
310  // We have the list of objects and their path, now searching all object parameters
311  // and setting them (we re-use nodeQueue to descend the tree, it is empty for sure)
312  nodeQueue.enqueue(m_root.get());
313 
314  // Descending the tree one more time
315  while (!nodeQueue.isEmpty()) {
316  // Getting a node
317  ConfigurationNode *curNode = nodeQueue.dequeue();
318 
319  // Obtaining the list of object parameters
320  QStringList params = curNode->getObjectParametersList();
321 
322  for (QStringList::iterator it = params.begin(); it != params.end(); it++) {
323  // Getting the object for the parameter
324  ParameterSettable *obj = curNode->getObject(*it).object;
325 
326  // If we have a pointer to obj in the map, setting the value for the parameter
327  if (objectsMap.contains(obj)) {
328  curNode->setValue(*it, objectsMap[obj]);
329  } else {
330  curNode->setValue(*it, QString(""));
331  }
332  }
333 
334  // Now adding all children of current node to the queue
335  #if QT_VERSION_CHECK > 0x450000
336  nodeQueue.append(curNode->getChildrenNodesList());
337  #else
338  foreach( ConfigurationNode* an, curNode->getChildrenNodesList() ) {
339  nodeQueue.append( an );
340  }
341  #endif
342  }
343 }
344 
345 bool ConfigurationParameters::loadParameters(QString filename, bool keepOld, QString format)
346 {
347  // If format is the empty string, guessing it from filename extension
348  if (format.isEmpty()) {
349  format = formatFromFilenameExtension(filename);
350 
351  if (format.isNull()) {
352  return false;
353  }
354  }
355 
356  // Searching the format on the map
357  QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
358 
359  // If not found, returning false
360  if (it == getFormatsMap().end()) {
361  return false;
362  }
363 
364  return it->fileLoaderSaver->load( filename, *this, keepOld );
365 }
366 
367 bool ConfigurationParameters::saveParameters(QString filename, QString format, bool append)
368 {
369  // Before saving updating all object references
371 
372  // If format is the empty string, guessing it from filename extension
373  if (format.isEmpty()) {
374  format = formatFromFilenameExtension(filename);
375 
376  if (format.isNull()) {
377  return false;
378  }
379  }
380 
381  // Searching the format on the map
382  QMap<QString, FileFormat>::iterator it = getFormatsMap().find(format);
383 
384  // If not found, returning false
385  if (it == getFormatsMap().end()) {
386  return false;
387  }
388 
389  return it->fileLoaderSaver->save( filename, *this, append );
390 }
391 
393 {
394  // Searching the ResourceManager containing the given resource
395  for (int i = m_getObjectFromGroupRecursionLevel; i >= 0; i--) {
396  if (m_resourcesUserPerRecursionLevel[i].hasResource(resourceName)) {
397  return &(m_resourcesUserPerRecursionLevel[i]);
398  }
399  }
400 
401  return NULL;
402 }
403 
405 {
406  m_resourcesUserPerRecursionLevel.last().shareResourcesWith(resourcesUser);
407 }
408 
410 {
411  m_factory->addObserver(observer);
412 }
413 
415  m_factory->addObservers( params.m_factory->getObservers() );
416 }
417 
418 QString ConfigurationParameters::formatFromFilenameExtension(QString filename) const
419 {
420  QFileInfo info(filename);
421 
422  QMap<QString, QString>::const_iterator it = getFileExtensionsMap().find(info.suffix());
423  if (it == getFileExtensionsMap().end()) {
424  return QString();
425  } else {
426  return *it;
427  }
428 }
429 
430 void ConfigurationParameters::copyTree(const ConfigurationNode *root)
431 {
432  // Allocating root. Parent is not copied as we suppose root to be a root of a tree
433  m_root.reset(new ConfigurationNode(NULL, root->getName(), root->isCaseSensitive()));
434 
435  // Now recursively copying the tree
436  copyNode(root, m_root.get());
437 }
438 
439 void ConfigurationParameters::copyNode(const ConfigurationNode *source, ConfigurationNode *target)
440 {
441  // First copying all parameters
442  QStringList params = source->getParametersList();
443  for (QStringList::const_iterator it = params.begin(); it != params.end(); it++) {
444  target->addParameter(*it);
445  target->setValue(*it, source->getValue(*it));
446  }
447 
448  // We don't copy the object associated to the node
449 
450  // Now creating children in target and recursively filling them
451  QStringList children = source->getChildrenList();
452  for (QStringList::const_iterator it = children.begin(); it != children.end(); it++) {
453  target->addNode(*it);
454  copyNode(source->getNode(*it), target->getNode(*it));
455  }
456 }
457 
458 bool ConfigurationParameters::setObjectFromGroupStatusToCreating(QString group)
459 {
460  if (m_getObjectFromGroupRecursionLevel == 0) {
461  return true;
462  }
463  return m_root->setObjectForNode(group, NULL, CreatingObject);
464 }
465 
466 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedNotConfigured(QString group, ParameterSettable *object)
467 {
468  if (m_getObjectFromGroupRecursionLevel == 0) {
469  return true;
470  }
471  return m_root->setObjectForNode(group, object, ObjectCreatedNotConfigured);
472 }
473 
474 bool ConfigurationParameters::setObjectFromGroupStatusToConfiguring(QString group)
475 {
476  if (m_getObjectFromGroupRecursionLevel == 0) {
477  return true;
478  }
479  return m_root->setObjectForNode(group, NULL, ConfiguringObject);
480 }
481 
482 bool ConfigurationParameters::setObjectFromGroupStatusToCreatingAndConfiguring(QString group)
483 {
484  if (m_getObjectFromGroupRecursionLevel == 0) {
485  return true;
486  }
487  return m_root->setObjectForNode(group, NULL, CreatingAndConfiguringObject);
488 }
489 
490 bool ConfigurationParameters::setObjectFromGroupStatusToCreatedAndConfigured(QString group, ParameterSettable *object)
491 {
492  if (m_getObjectFromGroupRecursionLevel == 0) {
493  return true;
494  }
495  return m_root->setObjectForNode(group, object, ObjectCreatedAndConfigured);
496 }
497 
498 } // end namespace farsa