CConfigHandler.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * CConfigHandler.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CConfigHandler.h"
  12. #include "filesystem/Filesystem.h"
  13. #include "GameConstants.h"
  14. #include "VCMIDirs.h"
  15. #include "json/JsonUtils.h"
  16. VCMI_LIB_NAMESPACE_BEGIN
  17. SettingsStorage settings;
  18. SettingsStorage persistentStorage;
  19. SettingsStorage keyBindingsConfig;
  20. template<typename Accessor>
  21. SettingsStorage::NodeAccessor<Accessor>::NodeAccessor(SettingsStorage & _parent, std::vector<std::string> _path):
  22. parent(_parent),
  23. path(std::move(_path))
  24. {
  25. }
  26. template<typename Accessor>
  27. SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator[](const std::string & nextNode) const
  28. {
  29. std::vector<std::string> newPath = path;
  30. newPath.push_back(nextNode);
  31. return NodeAccessor(parent, newPath);
  32. }
  33. template<typename Accessor>
  34. SettingsStorage::NodeAccessor<Accessor>::operator Accessor() const
  35. {
  36. return Accessor(parent, path);
  37. }
  38. template<typename Accessor>
  39. SettingsStorage::NodeAccessor<Accessor> SettingsStorage::NodeAccessor<Accessor>::operator () (std::vector<std::string> _path) const
  40. {
  41. std::vector<std::string> newPath = path;
  42. newPath.insert( newPath.end(), _path.begin(), _path.end());
  43. return NodeAccessor(parent, newPath);
  44. }
  45. SettingsStorage::SettingsStorage():
  46. write(NodeAccessor<Settings>(*this, std::vector<std::string>() )),
  47. listen(NodeAccessor<SettingsListener>(*this, std::vector<std::string>() ))
  48. {
  49. }
  50. SettingsStorage::~SettingsStorage()
  51. {
  52. // hack for possible crash due to static destruction order (setting storage can be destroyed before all listeners have died)
  53. for(SettingsListener * listener : listeners)
  54. listener->terminate();
  55. }
  56. void SettingsStorage::init(const std::string & dataFilename, const std::string & schema)
  57. {
  58. this->dataFilename = dataFilename;
  59. this->schema = schema;
  60. JsonPath confName = JsonPath::builtin(dataFilename);
  61. config = JsonUtils::assembleFromFiles(confName.getOriginalName());
  62. // Probably new install. Create config file to save settings to
  63. if (!CResourceHandler::get("local")->existsResource(confName))
  64. {
  65. CResourceHandler::get("local")->createResource(dataFilename);
  66. if(schema.empty())
  67. invalidateNode(std::vector<std::string>());
  68. }
  69. if(!schema.empty())
  70. {
  71. JsonUtils::maximize(config, schema);
  72. JsonUtils::validate(config, schema, "settings");
  73. }
  74. }
  75. void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath)
  76. {
  77. for(SettingsListener * listener : listeners)
  78. listener->nodeInvalidated(changedPath);
  79. JsonNode savedConf = config;
  80. savedConf.Struct().erase("session");
  81. if(!schema.empty())
  82. JsonUtils::minimize(savedConf, schema);
  83. std::fstream file(CResourceHandler::get()->getResourceName(JsonPath::builtin(dataFilename))->c_str(), std::ofstream::out | std::ofstream::trunc);
  84. file << savedConf.toString();
  85. }
  86. JsonNode & SettingsStorage::getNode(const std::vector<std::string> & path)
  87. {
  88. JsonNode *node = &config;
  89. for(const std::string & value : path)
  90. node = &(*node)[value];
  91. return *node;
  92. }
  93. Settings SettingsStorage::get(const std::vector<std::string> & path)
  94. {
  95. return Settings(*this, path);
  96. }
  97. const JsonNode & SettingsStorage::operator[](const std::string & value) const
  98. {
  99. return config[value];
  100. }
  101. const JsonNode & SettingsStorage::toJsonNode() const
  102. {
  103. return config;
  104. }
  105. SettingsListener::SettingsListener(SettingsStorage & _parent, std::vector<std::string> _path):
  106. parent(_parent),
  107. path(std::move(_path))
  108. {
  109. parent.listeners.insert(this);
  110. }
  111. SettingsListener::SettingsListener(const SettingsListener &sl):
  112. parent(sl.parent),
  113. path(sl.path),
  114. callback(sl.callback)
  115. {
  116. parent.listeners.insert(this);
  117. }
  118. void SettingsListener::terminate()
  119. {
  120. wasTerminated = true;
  121. }
  122. SettingsListener::~SettingsListener()
  123. {
  124. if (!wasTerminated)
  125. parent.listeners.erase(this);
  126. }
  127. void SettingsListener::nodeInvalidated(const std::vector<std::string> &changedPath)
  128. {
  129. if (!callback)
  130. return;
  131. size_t min = std::min(path.size(), changedPath.size());
  132. size_t mismatch = std::mismatch(path.begin(), path.begin()+min, changedPath.begin()).first - path.begin();
  133. if (min == mismatch)
  134. callback(parent.getNode(path));
  135. }
  136. void SettingsListener::operator() (std::function<void(const JsonNode&)> _callback)
  137. {
  138. callback = std::move(_callback);
  139. }
  140. Settings::Settings(SettingsStorage &_parent, const std::vector<std::string> &_path):
  141. parent(_parent),
  142. path(_path),
  143. node(_parent.getNode(_path)),
  144. copy(_parent.getNode(_path))
  145. {
  146. }
  147. Settings::~Settings()
  148. {
  149. if (node != copy)
  150. parent.invalidateNode(path);
  151. }
  152. JsonNode* Settings::operator -> ()
  153. {
  154. return &node;
  155. }
  156. const JsonNode* Settings::operator ->() const
  157. {
  158. return &node;
  159. }
  160. const JsonNode & Settings::operator[](const std::string & value) const
  161. {
  162. return node[value];
  163. }
  164. JsonNode & Settings::operator[](const std::string & value)
  165. {
  166. return node[value];
  167. }
  168. // Force instantiation of the SettingsStorage::NodeAccessor class template.
  169. // That way method definitions can sit in the cpp file
  170. template struct SettingsStorage::NodeAccessor<SettingsListener>;
  171. template struct SettingsStorage::NodeAccessor<Settings>;
  172. VCMI_LIB_NAMESPACE_END