/* * CConfigHandler.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "CConfigHandler.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/GameConstants.h" #include "../lib/VCMIDirs.h" VCMI_LIB_NAMESPACE_BEGIN SettingsStorage settings; SettingsStorage persistentStorage; template SettingsStorage::NodeAccessor::NodeAccessor(SettingsStorage & _parent, std::vector _path): parent(_parent), path(std::move(_path)) { } template SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator[](const std::string & nextNode) const { std::vector newPath = path; newPath.push_back(nextNode); return NodeAccessor(parent, newPath); } template SettingsStorage::NodeAccessor::operator Accessor() const { return Accessor(parent, path); } template SettingsStorage::NodeAccessor SettingsStorage::NodeAccessor::operator () (std::vector _path) const { std::vector newPath = path; newPath.insert( newPath.end(), _path.begin(), _path.end()); return NodeAccessor(parent, newPath); } SettingsStorage::SettingsStorage(): write(NodeAccessor(*this, std::vector() )), listen(NodeAccessor(*this, std::vector() )) { } void SettingsStorage::init(const std::string & dataFilename, const std::string & schema) { this->dataFilename = dataFilename; this->schema = schema; JsonPath confName = JsonPath::builtin(dataFilename); JsonUtils::assembleFromFiles(confName.getOriginalName()).swap(config); // Probably new install. Create config file to save settings to if (!CResourceHandler::get("local")->existsResource(confName)) CResourceHandler::get("local")->createResource(dataFilename); if(!schema.empty()) { JsonUtils::maximize(config, schema); JsonUtils::validate(config, schema, "settings"); } } void SettingsStorage::invalidateNode(const std::vector &changedPath) { for(SettingsListener * listener : listeners) listener->nodeInvalidated(changedPath); JsonNode savedConf = config; savedConf.Struct().erase("session"); if(!schema.empty()) JsonUtils::minimize(savedConf, schema); std::fstream file(CResourceHandler::get()->getResourceName(JsonPath::builtin(dataFilename))->c_str(), std::ofstream::out | std::ofstream::trunc); file << savedConf.toJson(); } JsonNode & SettingsStorage::getNode(const std::vector & path) { JsonNode *node = &config; for(const std::string & value : path) node = &(*node)[value]; return *node; } Settings SettingsStorage::get(const std::vector & path) { return Settings(*this, path); } const JsonNode & SettingsStorage::operator[](const std::string & value) const { return config[value]; } const JsonNode & SettingsStorage::toJsonNode() const { return config; } SettingsListener::SettingsListener(SettingsStorage & _parent, std::vector _path): parent(_parent), path(std::move(_path)) { parent.listeners.insert(this); } SettingsListener::SettingsListener(const SettingsListener &sl): parent(sl.parent), path(sl.path), callback(sl.callback) { parent.listeners.insert(this); } SettingsListener::~SettingsListener() { parent.listeners.erase(this); } void SettingsListener::nodeInvalidated(const std::vector &changedPath) { if (!callback) return; size_t min = std::min(path.size(), changedPath.size()); size_t mismatch = std::mismatch(path.begin(), path.begin()+min, changedPath.begin()).first - path.begin(); if (min == mismatch) callback(parent.getNode(path)); } void SettingsListener::operator() (std::function _callback) { callback = std::move(_callback); } Settings::Settings(SettingsStorage &_parent, const std::vector &_path): parent(_parent), path(_path), node(_parent.getNode(_path)), copy(_parent.getNode(_path)) { } Settings::~Settings() { if (node != copy) parent.invalidateNode(path); } JsonNode* Settings::operator -> () { return &node; } const JsonNode* Settings::operator ->() const { return &node; } const JsonNode & Settings::operator[](const std::string & value) const { return node[value]; } JsonNode & Settings::operator[](const std::string & value) { return node[value]; } // Force instantiation of the SettingsStorage::NodeAccessor class template. // That way method definitions can sit in the cpp file template struct SettingsStorage::NodeAccessor; template struct SettingsStorage::NodeAccessor; VCMI_LIB_NAMESPACE_END