diff --git a/bin/app/data/ApplicationSettings_template.xml b/bin/app/data/ApplicationSettings_template.xml index b9144b1a..83c51a4e 100644 --- a/bin/app/data/ApplicationSettings_template.xml +++ b/bin/app/data/ApplicationSettings_template.xml @@ -7,7 +7,9 @@ - + + + diff --git a/bin/app/data/ProjectSettings_template.xml b/bin/app/data/ProjectSettings_template.xml index ad3a5dcb..fcd103c3 100644 --- a/bin/app/data/ProjectSettings_template.xml +++ b/bin/app/data/ProjectSettings_template.xml @@ -8,6 +8,8 @@ - + + + diff --git a/bin/test/data/SettingsTestSuite/settings.xml b/bin/test/data/SettingsTestSuite/settings.xml index e9d468d4..462cbcf7 100644 --- a/bin/test/data/SettingsTestSuite/settings.xml +++ b/bin/test/data/SettingsTestSuite/settings.xml @@ -7,7 +7,11 @@ data - data/|src/ + + data/ + src/ + + diff --git a/src/lib/ApplicationSettings.cpp b/src/lib/ApplicationSettings.cpp index 80c14764..90277683 100644 --- a/src/lib/ApplicationSettings.cpp +++ b/src/lib/ApplicationSettings.cpp @@ -18,7 +18,9 @@ ApplicationSettings::~ApplicationSettings() std::vector ApplicationSettings::getHeaderSearchPaths() const { - return getValues("source/HeaderSearchPaths", ""); + //TODO: defaultValues? + std::vector defaultValues; + return getValues("source/HeaderSearchPaths", defaultValues); } int ApplicationSettings::getCodeTabWidth() const diff --git a/src/lib/ProjectSettings.cpp b/src/lib/ProjectSettings.cpp index 31710d0c..4f90715d 100644 --- a/src/lib/ProjectSettings.cpp +++ b/src/lib/ProjectSettings.cpp @@ -32,5 +32,7 @@ bool ProjectSettings::setSourcePath(const std::string& sourcePath) std::vector ProjectSettings::getHeaderSearchPaths() const { - return getValues("source/HeaderSearchPaths", ""); + //TODO defaultvalues? + std::vector defaultValues; + return getValues("source/HeaderSearchPaths/HeaderSearchPath", defaultValues); } diff --git a/src/lib/Settings.cpp b/src/lib/Settings.cpp index a68f1cd9..434719ee 100644 --- a/src/lib/Settings.cpp +++ b/src/lib/Settings.cpp @@ -33,7 +33,7 @@ void Settings::save(const std::string& filePath) { if (m_config) { - m_config->save(); + m_config->save(filePath); } else { @@ -45,16 +45,3 @@ void Settings::clear() { m_config = ConfigManager::createEmpty(); } - -std::vector Settings::getValues(const std::string& key, std::string defaultValue) const -{ - std::string value = getValue(key, defaultValue); - - if (value.size()) - { - std::deque values = utility::split(value, '|'); - return std::vector(values.begin(), values.end()); - } - - return std::vector(); -} diff --git a/src/lib/Settings.h b/src/lib/Settings.h index d5ba19a5..a0debe84 100644 --- a/src/lib/Settings.h +++ b/src/lib/Settings.h @@ -21,7 +21,8 @@ protected: template T getValue(const std::string& key, T defaultValue) const; - std::vector getValues(const std::string& key, std::string defaultValue) const; + template + std::vector getValues(const std::string& key, std::vector defaultValues) const; template bool setValue(const std::string& key, T value); @@ -44,6 +45,20 @@ T Settings::getValue(const std::string& key, T defaultValue) const return defaultValue; } +template +std::vector Settings::getValues(const std::string& key, std::vector defaultValues) const +{ + if(m_config) + { + std::vector values; + if(m_config->getValues(key, values)) + { + return values; + } + } + return defaultValues; +} + template bool Settings::setValue(const std::string& key, T value) { diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index f54196cd..ca332b93 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -24,7 +24,7 @@ Storage::Storage() { for (const std::pair& p : QueryCommand::getCommandTypeMap()) { - m_filterIndex.addNode(std::vector({ p.first })); + m_filterIndex.addNode(std::vector(1, p.first)); } } diff --git a/src/lib/utility/ConfigManager.cpp b/src/lib/utility/ConfigManager.cpp index 942a6d59..b039811e 100644 --- a/src/lib/utility/ConfigManager.cpp +++ b/src/lib/utility/ConfigManager.cpp @@ -4,6 +4,7 @@ #include "utility/logging/logging.h" #include "utility/text/TextAccess.h" +#include "utility/utilityString.h" std::shared_ptr ConfigManager::createEmpty() { @@ -19,7 +20,7 @@ std::shared_ptr ConfigManager::createAndLoad(const std::shared_pt bool ConfigManager::getValue(const std::string& key, std::string& value) const { - std::map::const_iterator it = m_values.find(key); + std::multimap::const_iterator it = m_values.find(key); if (it != m_values.end()) { @@ -66,9 +67,73 @@ bool ConfigManager::getValue(const std::string& key, bool& value) const return false; } +bool ConfigManager::getValues(const std::string& key, std::vector& values) const +{ + std::pair ::const_iterator, + std::multimap::const_iterator> ret; + ret = m_values.equal_range(key); + + if (ret.first != m_values.end()) + { + std::multimap::const_iterator cit = ret.first; + for(;cit!=ret.second;++cit) + { + values.push_back(cit->second); + } + return true; + } + else + { + LOG_ERROR("value " + key + " is not present in config."); + return false; + } +} + +bool ConfigManager::getValues(const std::string& key, std::vector& values) const +{ + std::vector valuesStringVector; + if (getValues(key, valuesStringVector)) + { + for (std::string valueString : valuesStringVector) + { + values.push_back(atoi(valueString.c_str())); + } + return true; + } + return false; +} + +bool ConfigManager::getValues(const std::string& key, std::vector& values) const +{ + std::vector valuesStringVector; + if (getValues(key, valuesStringVector)) + { + for (std::string valueString : valuesStringVector) + { + values.push_back(static_cast(atof(valueString.c_str()))); + } + return true; + } + return false; +} + +bool ConfigManager::getValues(const std::string& key, std::vector& values) const +{ + std::vector valuesStringVector; + if (getValues(key, valuesStringVector)) + { + for (std::string valueString : valuesStringVector) + { + values.push_back(atoi(valueString.c_str()) != 0); + } + return true; + } + return false; +} + void ConfigManager::setValue(const std::string& key, const std::string& value) { - std::map::iterator it = m_values.find(key); + std::multimap::iterator it = m_values.find(key); if (it != m_values.end()) { @@ -95,6 +160,50 @@ void ConfigManager::setValue(const std::string& key, const bool value) setValue(key, std::string(value ? "1" : "0")); } +void ConfigManager::setValues(const std::string& key, const std::vector& values) +{ + std::multimap::iterator it = m_values.find(key); + + if(it != m_values.end()) + { + m_values.erase(key); + } + for(std::string s : values) + { + m_values.emplace(key, s); + } +} + +void ConfigManager::setValues(const std::string& key, const std::vector& values) +{ + std::vector stringValues; + for(int i : values) + { + stringValues.push_back(std::to_string(i)); + } + setValues(key, stringValues); +} + +void ConfigManager::setValues(const std::string& key, const std::vector& values) +{ + std::vector stringValues; + for(float f : values) + { + stringValues.push_back(std::to_string(f)); + } + setValues(key, stringValues); +} + +void ConfigManager::setValues(const std::string& key, const std::vector& values) +{ + std::vector stringValues; + for(bool b : values) + { + stringValues.push_back(std::string(b ? "1" : "0")); + } + setValues(key, stringValues); +} + void ConfigManager::load(const std::shared_ptr textAccess) { std::string text = textAccess->getText(); @@ -116,21 +225,69 @@ void ConfigManager::load(const std::shared_ptr textAccess) } } -void ConfigManager::save() +void ConfigManager::save(const std::string filepath) { - LOG_ERROR("function: configmanager::save not implemented"); + std::string output(""); + createXmlDocument(true, filepath, output); } ConfigManager::ConfigManager() { } +bool ConfigManager::createXmlDocument(bool saveAsFile, const std::string filepath, std::string& output) +{ + bool success = true; + TiXmlDocument doc; + TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "utf-8", "" ); + doc.LinkEndChild(decl); + TiXmlElement *root = new TiXmlElement("config"); + doc.LinkEndChild(root); + + for(std::multimap::iterator it = m_values.begin(); it != m_values.end(); ++it) + { + std::vector tokens = utility::splitToVector(it->first, "/"); + TiXmlElement* element = doc.RootElement(); + TiXmlElement* child; + while(tokens.size() > 1) + { + child = element->FirstChildElement(tokens.front().c_str()); + if(!child) + { + child = new TiXmlElement(tokens.front().c_str()); + element->LinkEndChild(child); + } + tokens.erase(tokens.begin()); + element = child; + } + + child = new TiXmlElement(tokens.front().c_str()); + element->LinkEndChild(child); + TiXmlText* text = new TiXmlText(it->second.c_str()); + child->LinkEndChild(text); + } + + if(saveAsFile) + { + success = doc.SaveFile(filepath.c_str()); + } + else + { + TiXmlPrinter printer; + doc.Accept(&printer); + output = printer.CStr(); + } + success = doc.SaveFile(filepath.c_str()); + doc.Clear(); + return success; +} + void ConfigManager::parseSubtree(TiXmlNode* currentNode, const std::string& currentPath) { if (currentNode->Type() == TiXmlNode::TINYXML_TEXT) { std::string key = currentPath.substr(0, currentPath.size() - 1); - m_values[key] = currentNode->ToText()->Value(); + m_values.insert(std::pair(key,currentNode->ToText()->Value())); } else { @@ -140,3 +297,10 @@ void ConfigManager::parseSubtree(TiXmlNode* currentNode, const std::string& curr } } } + +std::string ConfigManager::toString() +{ + std::string output; + createXmlDocument(false, "", output); + return output; +} diff --git a/src/lib/utility/ConfigManager.h b/src/lib/utility/ConfigManager.h index 33ae8ebe..87f3ed13 100644 --- a/src/lib/utility/ConfigManager.h +++ b/src/lib/utility/ConfigManager.h @@ -4,6 +4,7 @@ #include #include #include +#include class TextAccess; class TiXmlNode; @@ -19,13 +20,24 @@ public: bool getValue(const std::string& key, float& value) const; bool getValue(const std::string& key, bool& value) const; + bool getValues(const std::string& key, std::vector& values) const; + bool getValues(const std::string& key, std::vector& values) const; + bool getValues(const std::string& key, std::vector& values) const; + bool getValues(const std::string& key, std::vector& values) const; + void setValue(const std::string& key, const std::string& value); void setValue(const std::string& key, const int value); void setValue(const std::string& key, const float value); void setValue(const std::string& key, const bool value); + void setValues(const std::string& key, const std::vector& values); + void setValues(const std::string& key, const std::vector& values); + void setValues(const std::string& key, const std::vector& values); + void setValues(const std::string& key, const std::vector& values); + void load(const std::shared_ptr textAccess); - void save(); + void save(const std::string filepath); + std::string toString(); private: ConfigManager(); @@ -33,8 +45,8 @@ private: void operator=(const ConfigManager&); void parseSubtree(TiXmlNode* parentElement, const std::string& currentPath); - - std::map m_values; + bool createXmlDocument(bool saveAsFile, std::string filepath, std::string& output); + std::multimap m_values; }; #endif // CONFIG_MANAGER_H diff --git a/src/test/ConfigManagerTestSuite.h b/src/test/ConfigManagerTestSuite.h index 3c8121eb..15f623db 100644 --- a/src/test/ConfigManagerTestSuite.h +++ b/src/test/ConfigManagerTestSuite.h @@ -97,21 +97,50 @@ public: TS_ASSERT(value); } + void test_config_manager_returns_correct_list_for_key() + { + std::shared_ptr config = ConfigManager::createAndLoad(getConfigTextAccess()); + + std::vector values; + + bool success(config->getValues("paths/path", values)); + + TS_ASSERT(success); + TS_ASSERT_EQUALS(values.size(), 3); + TS_ASSERT_EQUALS(values[0], 2); + TS_ASSERT_EQUALS(values[1], 5); + TS_ASSERT_EQUALS(values[2], 8); + } + + void test_config_manager_save_and_load_configuration_and_compare() + { + std::shared_ptr config = ConfigManager::createAndLoad(getConfigTextAccess()); + config->save("temp.xml"); + std::shared_ptr config2 = ConfigManager::createAndLoad(TextAccess::createFromFile("temp.xml")); + TS_ASSERT_EQUALS(config->toString(), config2->toString()); + } + private: std::shared_ptr getConfigTextAccess() { std::string text = - "\n" + "\n" "\n" "\n" "\n" - "42\n" - "1\n" "0\n" + "1\n" + "42\n" "\n" "\n" + "\n" + "4\n" + "2\n" + "5\n" + "8\n" + "\n" "\n"; - return TextAccess::createFromString(text); } + };