PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/lluicolortable.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 335 lines | 236 code | 52 blank | 47 comment | 41 complexity | 2cdb25372b1a9e3fb1966795bc17c615 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lluicolortable.cpp
  3. * @brief brief LLUIColorTable class implementation file
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include <queue>
  28. #include "lldir.h"
  29. #include "llui.h"
  30. #include "lluicolortable.h"
  31. #include "lluictrlfactory.h"
  32. LLUIColorTable::ColorParams::ColorParams()
  33. : value("value"),
  34. reference("reference")
  35. {
  36. }
  37. LLUIColorTable::ColorEntryParams::ColorEntryParams()
  38. : name("name"),
  39. color("")
  40. {
  41. }
  42. LLUIColorTable::Params::Params()
  43. : color_entries("color")
  44. {
  45. }
  46. void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table)
  47. {
  48. // this map will contain all color references after the following loop
  49. typedef std::map<std::string, std::string> string_string_map_t;
  50. string_string_map_t unresolved_refs;
  51. for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin();
  52. it != p.color_entries.end();
  53. ++it)
  54. {
  55. ColorEntryParams color_entry = *it;
  56. if(color_entry.color.value.isChosen())
  57. {
  58. setColor(color_entry.name, color_entry.color.value, table);
  59. }
  60. else
  61. {
  62. unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference));
  63. }
  64. }
  65. // maintain an in order queue of visited references for better debugging of cycles
  66. typedef std::queue<std::string> string_queue_t;
  67. string_queue_t ref_chain;
  68. // maintain a map of the previously visited references in the reference chain for detecting cycles
  69. typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t;
  70. string_color_ref_iter_map_t visited_refs;
  71. // loop through the unresolved color references until there are none left
  72. while(!unresolved_refs.empty())
  73. {
  74. // we haven't visited any references yet
  75. visited_refs.clear();
  76. string_string_map_t::iterator current = unresolved_refs.begin();
  77. string_string_map_t::iterator previous;
  78. while(true)
  79. {
  80. if(current != unresolved_refs.end())
  81. {
  82. // locate the current reference in the previously visited references...
  83. string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(current->first);
  84. if(visited != visited_refs.end()
  85. && !(visited_refs.key_comp()(current->first, visited->first)))
  86. {
  87. // ...if we find the current reference in the previously visited references
  88. // we know that there is a cycle
  89. std::string ending_ref = current->first;
  90. std::string warning("The following colors form a cycle: ");
  91. // warn about the references in the chain and remove them from
  92. // the unresolved references map because they cannot be resolved
  93. for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
  94. iter != visited_refs.end();
  95. ++iter)
  96. {
  97. if(!ref_chain.empty())
  98. {
  99. warning += ref_chain.front() + "->";
  100. ref_chain.pop();
  101. }
  102. unresolved_refs.erase(iter->second);
  103. }
  104. llwarns << warning + ending_ref << llendl;
  105. break;
  106. }
  107. else
  108. {
  109. // ...continue along the reference chain
  110. ref_chain.push(current->first);
  111. visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(current->first, current));
  112. }
  113. }
  114. else
  115. {
  116. // since this reference does not refer to another reference it must refer to an
  117. // actual color, lets find it...
  118. string_color_map_t::iterator color_value = mLoadedColors.find(previous->second);
  119. if(color_value != mLoadedColors.end())
  120. {
  121. // ...we found the color, and we now add every reference in the reference chain
  122. // to the color map
  123. for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
  124. iter != visited_refs.end();
  125. ++iter)
  126. {
  127. setColor(iter->first, color_value->second, mLoadedColors);
  128. unresolved_refs.erase(iter->second);
  129. }
  130. break;
  131. }
  132. else
  133. {
  134. // ... we did not find the color which imples that the current reference
  135. // references a non-existant color
  136. for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
  137. iter != visited_refs.end();
  138. ++iter)
  139. {
  140. llwarns << iter->first << " references a non-existent color" << llendl;
  141. unresolved_refs.erase(iter->second);
  142. }
  143. break;
  144. }
  145. }
  146. // find the next color reference in the reference chain
  147. previous = current;
  148. current = unresolved_refs.find(current->second);
  149. }
  150. }
  151. }
  152. void LLUIColorTable::clear()
  153. {
  154. clearTable(mLoadedColors);
  155. clearTable(mUserSetColors);
  156. }
  157. LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const
  158. {
  159. string_color_map_t::const_iterator iter = mUserSetColors.find(name);
  160. if(iter != mUserSetColors.end())
  161. {
  162. return LLUIColor(&iter->second);
  163. }
  164. iter = mLoadedColors.find(name);
  165. if(iter != mLoadedColors.end())
  166. {
  167. return LLUIColor(&iter->second);
  168. }
  169. return LLUIColor(default_color);
  170. }
  171. // update user color, loaded colors are parsed on initialization
  172. void LLUIColorTable::setColor(const std::string& name, const LLColor4& color)
  173. {
  174. setColor(name, color, mUserSetColors);
  175. setColor(name, color, mLoadedColors);
  176. }
  177. bool LLUIColorTable::loadFromSettings()
  178. {
  179. bool result = false;
  180. std::string default_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "colors.xml");
  181. result |= loadFromFilename(default_filename, mLoadedColors);
  182. std::string current_filename = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, "colors.xml");
  183. if(current_filename != default_filename)
  184. {
  185. result |= loadFromFilename(current_filename, mLoadedColors);
  186. }
  187. current_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SKIN, "colors.xml");
  188. if(current_filename != default_filename)
  189. {
  190. result |= loadFromFilename(current_filename, mLoadedColors);
  191. }
  192. std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
  193. loadFromFilename(user_filename, mUserSetColors);
  194. return result;
  195. }
  196. void LLUIColorTable::saveUserSettings() const
  197. {
  198. Params params;
  199. for(string_color_map_t::const_iterator it = mUserSetColors.begin();
  200. it != mUserSetColors.end();
  201. ++it)
  202. {
  203. ColorEntryParams color_entry;
  204. color_entry.name = it->first;
  205. color_entry.color.value = it->second;
  206. params.color_entries.add(color_entry);
  207. }
  208. LLXMLNodePtr output_node = new LLXMLNode("colors", false);
  209. LLXUIParser parser;
  210. parser.writeXUI(output_node, params);
  211. if(!output_node->isNull())
  212. {
  213. const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
  214. LLFILE *fp = LLFile::fopen(filename, "w");
  215. if(fp != NULL)
  216. {
  217. LLXMLNode::writeHeaderToFile(fp);
  218. output_node->writeToFile(fp);
  219. fclose(fp);
  220. }
  221. }
  222. }
  223. bool LLUIColorTable::colorExists(const std::string& color_name) const
  224. {
  225. return ((mLoadedColors.find(color_name) != mLoadedColors.end())
  226. || (mUserSetColors.find(color_name) != mUserSetColors.end()));
  227. }
  228. void LLUIColorTable::clearTable(string_color_map_t& table)
  229. {
  230. for(string_color_map_t::iterator it = table.begin();
  231. it != table.end();
  232. ++it)
  233. {
  234. it->second = LLColor4::magenta;
  235. }
  236. }
  237. // this method inserts a color into the table if it does not exist
  238. // if the color already exists it changes the color
  239. void LLUIColorTable::setColor(const std::string& name, const LLColor4& color, string_color_map_t& table)
  240. {
  241. string_color_map_t::iterator it = table.lower_bound(name);
  242. if(it != table.end()
  243. && !(table.key_comp()(name, it->first)))
  244. {
  245. it->second = color;
  246. }
  247. else
  248. {
  249. table.insert(it, string_color_map_t::value_type(name, color));
  250. }
  251. }
  252. bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_map_t& table)
  253. {
  254. LLXMLNodePtr root;
  255. if(!LLXMLNode::parseFile(filename, root, NULL))
  256. {
  257. llwarns << "Unable to parse color file " << filename << llendl;
  258. return false;
  259. }
  260. if(!root->hasName("colors"))
  261. {
  262. llwarns << filename << " is not a valid color definition file" << llendl;
  263. return false;
  264. }
  265. Params params;
  266. LLXUIParser parser;
  267. parser.readXUI(root, params, filename);
  268. if(params.validateBlock())
  269. {
  270. insertFromParams(params, table);
  271. }
  272. else
  273. {
  274. llwarns << filename << " failed to load" << llendl;
  275. return false;
  276. }
  277. return true;
  278. }
  279. void LLUIColorTable::insertFromParams(const Params& p)
  280. {
  281. insertFromParams(p, mUserSetColors);
  282. }
  283. // EOF