#ifndef ICL_CONFIG_FILE_H #define ICL_CONFIG_FILE_H #include #include #include #include namespace icl{ /// Utility class for creating and reading XML-based hierarchical configuration files /** ConfigFile class can be used in object based as well as in static manner. ConfigFile objects can e.g. be used, to locally read a configuration file or to create a configuration file. Besides a static singleton ConfigFile object accessible via ConfigFile::getConfig can be used as a global configuration for applications. ConfigFiles are XML-based (using Qt's XML package for parsing and creating XML structure). The document is hierarchical as the following example demonstrates
      \ 
      \ 
        \This is the new title\ 
        \
\
\7\ \6.450000\ \./notHallo.txt\ \ \ \
\a\ \b\ \ \
When accessing ConfigFile data members, each hierarchy level must be separated using the '.' character. So e.g. the filename can be accessed using DataStore access function: \code ConfigFile config("myConfig.xml"); // myConfig.xml shall contain the contents above string fn = config.get("general.params.filename"); \endcode To avoid errors, the "get"-function can be called with a default return value: \code ConfigFile config("myConfig.xml"); string fn = config.get("general.params.filename","defaultpath.xml"); \endcode In the same manner, ConfigFile entries can be generated: The example file above was generated with the following code (Note: the "config"-prefix is compulsory!) \code ConfigFile a; a.setTitle("This is the new title"); a.add("config.general.params.threshold",7); a.add("config.general.params.value",6.45); a.add("config.general.params.filename",std::string("./hallo.txt")); a.add("config.general.params.filename",std::string("./notHallo.txt")); a.add("config.special.hint",'a'); a.add("config.special.no-hint",'b'); a.save("config.xml"); \endcode \section TPS Types Functions for data access and data definition are implemented as non-inline templates, which are instantiated for the following types: - char - unsigned char - short - unsigned short - int - unsigned int - float - double - string - Size - Point - Rect - Range - Range \section PERF Performance Internally data is stored in the parent classes (DataStore) hash maps to optimize data access. ConfigFile data key is the the '.'-concatenated identifier. */ class ConfigFile : public DataStore{ public: struct EntryNotFoundException : public ICLException{ std::string entryName; std::string typeName; EntryNotFoundException(const std::string &entryName, const std::string &typeName): ICLException(entryName+" could not be found!"),entryName(entryName),typeName(typeName){} virtual ~EntryNotFoundException() throw(){} }; /// Default constructor creating an empty ConfigFile instance /** The empty ConfigFile has the following string representation:
        \
        \
          \no title defined"\
        \
        
*/ ConfigFile(); /// Creates a ConfigFile instance with given filename /** @param filename if filename is found and it contains a valid ConfigFile structure, it is read into the ConfigFile instance. Otherwise, filename is stored internally for later use if load(void) or save(void) is called. */ ConfigFile(const std::string &filename); /// return the current filename const std::string &getFileName() const { return m_sFileName; } /// sets new internal filename for using load(void) or save(void) void setFileName(const std::string &fileName) { m_sFileName = fileName; } /// loads the ConfigFile from given filename and updates internal filename variable /** Warning: old data content is lost! */ void load(const std::string &filename); /// loads the ConfigFile using internal filename variable /** Warning: old data content is lost! */ void load(); /// Writes data to disk using given filename void save(const std::string &filename) const; /// Writes data to dist using internal filename void save() const; /// Sets up a new title to the internal document void setTitle(const std::string &title); /// Sets up a default prefix automatically put before each given key void setDefaultPrefix(const std::string &defaultPrefix){ m_sDefaultPrefix = defaultPrefix; } /// Returns given default prefix const std::string &getDefaultPrefix() const { return m_sDefaultPrefix; } /// Adds a new data element to the ConfigFile /** Warning: if not unique decidable, an explicit information about the value type T is compulsory. e.g. \code ConfigFile f; f.add("config.filename","myText.txt"); \endcode Causes an error because the template type T is resolved as const char* which is not supported yet. Better versions use an explicit template: \code ConfigFile f; f.add("config.filename","myText.txt"); \endcode or an explicit string argument: \code ConfigFile f; f.add("config.filename",std::string("myText.txt")); \endcode to avoid these errors.\n Note: Integer constants are of type "int" by default, and floating point constants are of type "double" by default: */ template void add(const std::string &id, const T &val); /// returns a given value from the internal document hash-map /** This function is equivalent to the getValue function template provided by the parent DataStore class, except this function applies two additional checks first: - checking if entry "id" is actually contained (if not, def is returned) - checking if entry "id" has actually the given type (if not, def is returned) */ template inline const T get(const std::string &idIn,const T &def=T()) const{ std::string id = m_sDefaultPrefix+idIn; if(contains(id) && checkType(id)){ return getValue(id); }else{ return def; } } /// returns a given value from the internal document hash-map /** This function is equivalent to the getValue function template provided by the parent DataStore class, except this function applies two additional checks first: - checking if entry "id" is actually contained (if not, an ConfigFile::EntryNotFoundException is thrown) - checking if entry "id" has actually the given type (if not, an ConfigFile::EntryNotFoundException is thrown) */ template inline const T try_get(const std::string &idIn) const throw (EntryNotFoundException){ std::string id = m_sDefaultPrefix+idIn; if(!contains(id) || !checkType(id)){ throw EntryNotFoundException(id,get_type_name()); } return getValue(id); } // ---------------- static misc ---------------------------- /// loads the global ConfigFile from given filename static void loadConfig(const std::string &filename); /// loads a ConfigFile object into the global config file (shallowly copied!) static void loadConfig(const ConfigFile &configFile); /// returns the global ConfigFile static const ConfigFile &getConfig(){ return s_oConfig; } /// equivalent to ConfigFile::getConfig().get... template static const T sget(const std::string &id, const T &def=T()){ return getConfig().get(id,def); } /// equivalent to ConfigFile::getConfig().try_get... template static const T stry_get(const std::string &id) throw (EntryNotFoundException){ return getConfig().try_get(id); } private: /// filename std::string m_sFileName; /// internally used XMLDocument type (currently QDomDocument) class XMLDocHandle; /** \cond */ struct XMLDocHandleDelOp{ static void delete_func(XMLDocHandle *h); }; /** \endcond */ /// shallow copyable smart pointer of the document handle SmartPtr m_spXMLDocHandle; /// global ConfigFile instance static ConfigFile s_oConfig; /// internally used utility function void updateTitleFromDocument(); std::string m_sDefaultPrefix; /// ostream operator is allowed to access privat members friend std::ostream &operator<<(std::ostream&,const ConfigFile&); }; /// Default ostream operator to put a ConfigFile into a stream std::ostream &operator<<(std::ostream &s, const ConfigFile &cf); } #endif