PageRenderTime 27ms CodeModel.GetById 2ms app.highlight 20ms 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
  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
 27#include "linden_common.h"
 28
 29#include <queue>
 30
 31#include "lldir.h"
 32#include "llui.h"
 33#include "lluicolortable.h"
 34#include "lluictrlfactory.h"
 35
 36LLUIColorTable::ColorParams::ColorParams()
 37:	value("value"),
 38	reference("reference")
 39{
 40}
 41
 42LLUIColorTable::ColorEntryParams::ColorEntryParams()
 43:	name("name"),
 44	color("")
 45{
 46}
 47
 48LLUIColorTable::Params::Params()
 49:	color_entries("color")
 50{
 51}
 52
 53void LLUIColorTable::insertFromParams(const Params& p, string_color_map_t& table)
 54{
 55	// this map will contain all color references after the following loop
 56	typedef std::map<std::string, std::string> string_string_map_t;
 57	string_string_map_t unresolved_refs;
 58
 59	for(LLInitParam::ParamIterator<ColorEntryParams>::const_iterator it = p.color_entries.begin();
 60		it != p.color_entries.end();
 61		++it)
 62	{
 63		ColorEntryParams color_entry = *it;
 64		if(color_entry.color.value.isChosen())
 65		{
 66			setColor(color_entry.name, color_entry.color.value, table);
 67		}
 68		else
 69		{
 70			unresolved_refs.insert(string_string_map_t::value_type(color_entry.name, color_entry.color.reference));
 71		}
 72	}
 73
 74	// maintain an in order queue of visited references for better debugging of cycles
 75	typedef std::queue<std::string> string_queue_t;
 76	string_queue_t ref_chain;
 77
 78	// maintain a map of the previously visited references in the reference chain for detecting cycles
 79	typedef std::map<std::string, string_string_map_t::iterator> string_color_ref_iter_map_t;
 80	string_color_ref_iter_map_t visited_refs;
 81
 82	// loop through the unresolved color references until there are none left
 83	while(!unresolved_refs.empty())
 84	{
 85		// we haven't visited any references yet
 86		visited_refs.clear();
 87
 88		string_string_map_t::iterator current = unresolved_refs.begin();
 89		string_string_map_t::iterator previous;
 90
 91		while(true)
 92		{
 93			if(current != unresolved_refs.end())
 94			{
 95				// locate the current reference in the previously visited references...
 96				string_color_ref_iter_map_t::iterator visited = visited_refs.lower_bound(current->first);
 97				if(visited != visited_refs.end()
 98			    && !(visited_refs.key_comp()(current->first, visited->first)))
 99				{
100					// ...if we find the current reference in the previously visited references
101					// we know that there is a cycle
102					std::string ending_ref = current->first;
103					std::string warning("The following colors form a cycle: ");
104
105					// warn about the references in the chain and remove them from
106					// the unresolved references map because they cannot be resolved
107					for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
108						iter != visited_refs.end();
109						++iter)
110					{
111						if(!ref_chain.empty())
112						{
113							warning += ref_chain.front() + "->";
114							ref_chain.pop();
115						}
116						unresolved_refs.erase(iter->second);
117					}
118
119					llwarns << warning + ending_ref << llendl;
120
121					break;
122				}
123				else
124				{
125					// ...continue along the reference chain
126					ref_chain.push(current->first);
127					visited_refs.insert(visited, string_color_ref_iter_map_t::value_type(current->first, current));
128				}
129			}
130			else
131			{
132				// since this reference does not refer to another reference it must refer to an
133				// actual color, lets find it...
134				string_color_map_t::iterator color_value = mLoadedColors.find(previous->second);
135
136				if(color_value != mLoadedColors.end())
137				{
138					// ...we found the color, and we now add every reference in the reference chain
139					// to the color map
140					for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
141						iter != visited_refs.end();
142						++iter)
143					{
144						setColor(iter->first, color_value->second, mLoadedColors);
145						unresolved_refs.erase(iter->second);
146					}
147
148					break;
149				}
150				else
151				{
152					// ... we did not find the color which imples that the current reference
153					// references a non-existant color
154					for(string_color_ref_iter_map_t::iterator iter = visited_refs.begin();
155						iter != visited_refs.end();
156						++iter)
157					{
158						llwarns << iter->first << " references a non-existent color" << llendl;
159						unresolved_refs.erase(iter->second);
160					}
161
162					break;
163				}
164			}
165
166			// find the next color reference in the reference chain
167			previous = current;
168			current = unresolved_refs.find(current->second);
169		}
170	}
171}
172
173void LLUIColorTable::clear()
174{
175	clearTable(mLoadedColors);
176	clearTable(mUserSetColors);
177}
178
179LLUIColor LLUIColorTable::getColor(const std::string& name, const LLColor4& default_color) const
180{
181	string_color_map_t::const_iterator iter = mUserSetColors.find(name);
182	
183	if(iter != mUserSetColors.end())
184	{
185		return LLUIColor(&iter->second);
186	}
187
188	iter = mLoadedColors.find(name);
189	
190	if(iter != mLoadedColors.end())
191	{
192		return LLUIColor(&iter->second);
193	}
194	
195	return  LLUIColor(default_color);
196}
197
198// update user color, loaded colors are parsed on initialization
199void LLUIColorTable::setColor(const std::string& name, const LLColor4& color)
200{
201	setColor(name, color, mUserSetColors);
202	setColor(name, color, mLoadedColors);
203}
204
205bool LLUIColorTable::loadFromSettings()
206{
207	bool result = false;
208
209	std::string default_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "colors.xml");
210	result |= loadFromFilename(default_filename, mLoadedColors);
211
212	std::string current_filename = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, "colors.xml");
213	if(current_filename != default_filename)
214	{
215		result |= loadFromFilename(current_filename, mLoadedColors);
216	}
217
218	current_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SKIN, "colors.xml");
219	if(current_filename != default_filename)
220	{
221		result |= loadFromFilename(current_filename, mLoadedColors);
222	}
223
224	std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
225	loadFromFilename(user_filename, mUserSetColors);
226
227	return result;
228}
229
230void LLUIColorTable::saveUserSettings() const
231{
232	Params params;
233
234	for(string_color_map_t::const_iterator it = mUserSetColors.begin();
235		it != mUserSetColors.end();
236		++it)
237	{
238		ColorEntryParams color_entry;
239		color_entry.name = it->first;
240		color_entry.color.value = it->second;
241
242		params.color_entries.add(color_entry);
243	}
244
245	LLXMLNodePtr output_node = new LLXMLNode("colors", false);
246	LLXUIParser parser;
247	parser.writeXUI(output_node, params);
248
249	if(!output_node->isNull())
250	{
251		const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "colors.xml");
252		LLFILE *fp = LLFile::fopen(filename, "w");
253
254		if(fp != NULL)
255		{
256			LLXMLNode::writeHeaderToFile(fp);
257			output_node->writeToFile(fp);
258
259			fclose(fp);
260		}
261	}
262}
263
264bool LLUIColorTable::colorExists(const std::string& color_name) const
265{
266	return ((mLoadedColors.find(color_name) != mLoadedColors.end())
267		 || (mUserSetColors.find(color_name) != mUserSetColors.end()));
268}
269
270void LLUIColorTable::clearTable(string_color_map_t& table)
271{
272	for(string_color_map_t::iterator it = table.begin();
273		it != table.end();
274		++it)
275	{
276		it->second = LLColor4::magenta;
277	}
278}
279
280// this method inserts a color into the table if it does not exist
281// if the color already exists it changes the color
282void LLUIColorTable::setColor(const std::string& name, const LLColor4& color, string_color_map_t& table)
283{
284	string_color_map_t::iterator it = table.lower_bound(name);
285	if(it != table.end()
286	&& !(table.key_comp()(name, it->first)))
287	{
288		it->second = color;
289	}
290	else
291	{
292		table.insert(it, string_color_map_t::value_type(name, color));
293	}
294}
295
296bool LLUIColorTable::loadFromFilename(const std::string& filename, string_color_map_t& table)
297{
298	LLXMLNodePtr root;
299
300	if(!LLXMLNode::parseFile(filename, root, NULL))
301	{
302		llwarns << "Unable to parse color file " << filename << llendl;
303		return false;
304	}
305
306	if(!root->hasName("colors"))
307	{
308		llwarns << filename << " is not a valid color definition file" << llendl;
309		return false;
310	}
311
312	Params params;
313	LLXUIParser parser;
314	parser.readXUI(root, params, filename);
315
316	if(params.validateBlock())
317	{
318		insertFromParams(params, table);
319	}
320	else
321	{
322		llwarns << filename << " failed to load" << llendl;
323		return false;
324	}
325
326	return true;
327}
328
329void LLUIColorTable::insertFromParams(const Params& p)
330{
331	insertFromParams(p, mUserSetColors);
332}
333
334// EOF
335