PageRenderTime 138ms CodeModel.GetById 15ms app.highlight 112ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llxml/llcontrol.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1309 lines | 1007 code | 201 blank | 101 comment | 119 complexity | 34ff542f0ded867cea613f60bd5c16c0 MD5 | raw file
   1/** 
   2 * @file llcontrol.cpp
   3 * @brief Holds global state for viewer.
   4 *
   5 * $LicenseInfo:firstyear=2001&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 <iostream>
  30#include <fstream>
  31#include <algorithm>
  32
  33#include "llcontrol.h"
  34
  35#include "llstl.h"
  36
  37#include "llstring.h"
  38#include "v3math.h"
  39#include "v3dmath.h"
  40#include "v4coloru.h"
  41#include "v4color.h"
  42#include "v3color.h"
  43#include "llrect.h"
  44#include "llxmltree.h"
  45#include "llsdserialize.h"
  46
  47#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
  48#define CONTROL_ERRS LL_ERRS("ControlErrors")
  49#else
  50#define CONTROL_ERRS LL_WARNS("ControlErrors")
  51#endif
  52
  53
  54template <> eControlType get_control_type<U32>();
  55template <> eControlType get_control_type<S32>();
  56template <> eControlType get_control_type<F32>();
  57template <> eControlType get_control_type<bool>();
  58// Yay BOOL, its really an S32.
  59//template <> eControlType get_control_type<BOOL> () ;
  60template <> eControlType get_control_type<std::string>();
  61
  62template <> eControlType get_control_type<LLVector3>();
  63template <> eControlType get_control_type<LLVector3d>();
  64template <> eControlType get_control_type<LLRect>();
  65template <> eControlType get_control_type<LLColor4>();
  66template <> eControlType get_control_type<LLColor3>();
  67template <> eControlType get_control_type<LLColor4U>();
  68template <> eControlType get_control_type<LLSD>();
  69
  70template <> LLSD convert_to_llsd<U32>(const U32& in);
  71template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
  72template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
  73template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
  74template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
  75template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
  76template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in);
  77
  78template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name);
  79template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name);
  80template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name);
  81template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name);
  82template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name);
  83template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name);
  84template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name);
  85template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name);
  86template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name);
  87template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name);
  88template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, const std::string& control_name);
  89template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name);
  90template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name);
  91
  92//this defines the current version of the settings file
  93const S32 CURRENT_VERSION = 101;
  94
  95bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
  96{
  97	bool result = false;
  98	switch (mType)
  99	{
 100	case TYPE_U32:
 101	case TYPE_S32:
 102		result = a.asInteger() == b.asInteger();
 103		break;
 104	case TYPE_BOOLEAN:
 105		result = a.asBoolean() == b.asBoolean();
 106		break;
 107	case TYPE_F32:
 108		result = a.asReal() == b.asReal();
 109		break;
 110	case TYPE_VEC3:
 111	case TYPE_VEC3D:
 112		result = LLVector3d(a) == LLVector3d(b);
 113		break;
 114	case TYPE_RECT:
 115		result = LLRect(a) == LLRect(b);
 116		break;
 117	case TYPE_COL4:
 118		result = LLColor4(a) == LLColor4(b);
 119		break;
 120	case TYPE_COL3:
 121		result = LLColor3(a) == LLColor3(b);
 122		break;
 123	case TYPE_STRING:
 124		result = a.asString() == b.asString();
 125		break;
 126	default:
 127		break;
 128	}
 129
 130	return result;
 131}
 132
 133LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
 134							 LLSD initial, const std::string& comment,
 135							 bool persist, bool hidefromsettingseditor)
 136	: mName(name),
 137	  mComment(comment),
 138	  mType(type),
 139	  mPersist(persist),
 140	  mHideFromSettingsEditor(hidefromsettingseditor)
 141{
 142	if (mPersist && mComment.empty())
 143	{
 144		llerrs << "Must supply a comment for control " << mName << llendl;
 145	}
 146	//Push back versus setValue'ing here, since we don't want to call a signal yet
 147	mValues.push_back(initial);
 148}
 149
 150
 151
 152LLControlVariable::~LLControlVariable()
 153{
 154}
 155
 156LLSD LLControlVariable::getComparableValue(const LLSD& value)
 157{
 158	// *FIX:MEP - The following is needed to make the LLSD::ImplString 
 159	// work with boolean controls...
 160	LLSD storable_value;
 161	if(TYPE_BOOLEAN == type() && value.isString())
 162	{
 163		BOOL temp;
 164		if(LLStringUtil::convertToBOOL(value.asString(), temp)) 
 165		{
 166			storable_value = (bool)temp;
 167		}
 168		else
 169		{
 170			storable_value = false;
 171		}
 172	}
 173	else if (TYPE_LLSD == type() && value.isString())
 174	{
 175		LLPointer<LLSDNotationParser> parser = new LLSDNotationParser;
 176		LLSD result;
 177		std::stringstream value_stream(value.asString());
 178		if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE)
 179		{
 180			storable_value = result;
 181		}
 182		else
 183		{
 184			storable_value = value;
 185		}
 186	}
 187	else
 188	{
 189		storable_value = value;
 190	}
 191
 192	return storable_value;
 193}
 194
 195void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
 196{
 197	if (mValidateSignal(this, new_value) == false)
 198	{
 199		// can not set new value, exit
 200		return;
 201	}
 202	
 203	LLSD storable_value = getComparableValue(new_value);
 204	bool value_changed = llsd_compare(getValue(), storable_value) == FALSE;
 205	if(saved_value)
 206	{
 207    	// If we're going to save this value, return to default but don't fire
 208		resetToDefault(false);
 209	    if (llsd_compare(mValues.back(), storable_value) == FALSE)
 210	    {
 211		    mValues.push_back(storable_value);
 212	    }
 213	}
 214    else
 215    {
 216        // This is an unsaved value. Its needs to reside at
 217        // mValues[2] (or greater). It must not affect 
 218        // the result of getSaveValue()
 219	    if (llsd_compare(mValues.back(), storable_value) == FALSE)
 220	    {
 221            while(mValues.size() > 2)
 222            {
 223                // Remove any unsaved values.
 224                mValues.pop_back();
 225            }
 226
 227            if(mValues.size() < 2)
 228            {
 229                // Add the default to the 'save' value.
 230                mValues.push_back(mValues[0]);
 231            }
 232
 233            // Add the 'un-save' value.
 234            mValues.push_back(storable_value);
 235	    }
 236    }
 237
 238    if(value_changed)
 239    {
 240        mCommitSignal(this, storable_value); 
 241    }
 242}
 243
 244void LLControlVariable::setDefaultValue(const LLSD& value)
 245{
 246	// Set the control variables value and make it 
 247	// the default value. If the active value is changed,
 248	// send the signal.
 249	// *NOTE: Default values are not saved, only read.
 250
 251	LLSD comparable_value = getComparableValue(value);
 252	bool value_changed = (llsd_compare(getValue(), comparable_value) == FALSE);
 253	resetToDefault(false);
 254	mValues[0] = comparable_value;
 255	if(value_changed)
 256	{
 257		firePropertyChanged();
 258	}
 259}
 260
 261void LLControlVariable::setPersist(bool state)
 262{
 263	mPersist = state;
 264}
 265
 266void LLControlVariable::setHiddenFromSettingsEditor(bool hide)
 267{
 268	mHideFromSettingsEditor = hide;
 269}
 270
 271void LLControlVariable::setComment(const std::string& comment)
 272{
 273	mComment = comment;
 274}
 275
 276void LLControlVariable::resetToDefault(bool fire_signal)
 277{
 278	//The first setting is always the default
 279	//Pop to it and fire off the listener
 280	while(mValues.size() > 1)
 281	{
 282		mValues.pop_back();
 283	}
 284	
 285	if(fire_signal) 
 286	{
 287		firePropertyChanged();
 288	}
 289}
 290
 291bool LLControlVariable::isSaveValueDefault()
 292{ 
 293    return (mValues.size() ==  1) 
 294        || ((mValues.size() > 1) && llsd_compare(mValues[1], mValues[0]));
 295}
 296
 297LLSD LLControlVariable::getSaveValue() const
 298{
 299	//The first level of the stack is default
 300	//We assume that the second level is user preferences that should be saved
 301	if(mValues.size() > 1) return mValues[1];
 302	return mValues[0];
 303}
 304
 305LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name)
 306{
 307	ctrl_name_table_t::iterator iter = mNameTable.find(name);
 308	return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second;
 309}
 310
 311
 312////////////////////////////////////////////////////////////////////////////
 313
 314LLControlGroup::LLControlGroup(const std::string& name)
 315:	LLInstanceTracker<LLControlGroup, std::string>(name)
 316{
 317	mTypeString[TYPE_U32] = "U32";
 318	mTypeString[TYPE_S32] = "S32";
 319	mTypeString[TYPE_F32] = "F32";
 320	mTypeString[TYPE_BOOLEAN] = "Boolean";
 321	mTypeString[TYPE_STRING] = "String";
 322	mTypeString[TYPE_VEC3] = "Vector3";
 323    mTypeString[TYPE_VEC3D] = "Vector3D";
 324	mTypeString[TYPE_RECT] = "Rect";
 325	mTypeString[TYPE_COL4] = "Color4";
 326	mTypeString[TYPE_COL3] = "Color3";
 327	mTypeString[TYPE_LLSD] = "LLSD";
 328}
 329
 330LLControlGroup::~LLControlGroup()
 331{
 332	cleanup();
 333}
 334
 335void LLControlGroup::cleanup()
 336{
 337	mNameTable.clear();
 338}
 339
 340eControlType LLControlGroup::typeStringToEnum(const std::string& typestr)
 341{
 342	for(int i = 0; i < (int)TYPE_COUNT; ++i)
 343	{
 344		if(mTypeString[i] == typestr) return (eControlType)i;
 345	}
 346	return (eControlType)-1;
 347}
 348
 349std::string LLControlGroup::typeEnumToString(eControlType typeenum)
 350{
 351	return mTypeString[typeenum];
 352}
 353
 354BOOL LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, BOOL persist, BOOL hidefromsettingseditor)
 355{
 356	LLControlVariable* existing_control = getControl(name);
 357	if (existing_control)
 358 	{
 359		if (persist && existing_control->isType(type))
 360		{
 361			if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val))
 362			{
 363				// Sometimes we need to declare a control *after* it has been loaded from a settings file.
 364				LLSD cur_value = existing_control->getValue(); // get the current value
 365				existing_control->setDefaultValue(initial_val); // set the default to the declared value
 366				existing_control->setValue(cur_value); // now set to the loaded value
 367			}
 368		}
 369		else
 370		{
 371			llwarns << "Control named " << name << " already exists, ignoring new declaration." << llendl;
 372		}
 373 		return TRUE;
 374	}
 375
 376	// if not, create the control and add it to the name table
 377	LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor);
 378	mNameTable[name] = control;	
 379	return TRUE;
 380}
 381
 382BOOL LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, BOOL persist)
 383{
 384	return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist);
 385}
 386
 387BOOL LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, BOOL persist)
 388{
 389	return declareControl(name, TYPE_S32, initial_val, comment, persist);
 390}
 391
 392BOOL LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, BOOL persist)
 393{
 394	return declareControl(name, TYPE_F32, initial_val, comment, persist);
 395}
 396
 397BOOL LLControlGroup::declareBOOL(const std::string& name, const BOOL initial_val, const std::string& comment, BOOL persist)
 398{
 399	return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist);
 400}
 401
 402BOOL LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, BOOL persist)
 403{
 404	return declareControl(name, TYPE_STRING, initial_val, comment, persist);
 405}
 406
 407BOOL LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, BOOL persist)
 408{
 409	return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist);
 410}
 411
 412BOOL LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, BOOL persist)
 413{
 414	return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
 415}
 416
 417BOOL LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, BOOL persist)
 418{
 419	return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
 420}
 421
 422BOOL LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, BOOL persist )
 423{
 424	return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist);
 425}
 426
 427BOOL LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, BOOL persist )
 428{
 429	return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist);
 430}
 431
 432BOOL LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, BOOL persist )
 433{
 434	return declareControl(name, TYPE_LLSD, initial_val, comment, persist);
 435}
 436
 437BOOL LLControlGroup::getBOOL(const std::string& name)
 438{
 439	return (BOOL)get<bool>(name);
 440}
 441
 442S32 LLControlGroup::getS32(const std::string& name)
 443{
 444	return get<S32>(name);
 445}
 446
 447U32 LLControlGroup::getU32(const std::string& name)
 448{
 449	return get<U32>(name);
 450}
 451
 452F32 LLControlGroup::getF32(const std::string& name)
 453{
 454	return get<F32>(name);
 455}
 456
 457std::string LLControlGroup::getString(const std::string& name)
 458{
 459	return get<std::string>(name);
 460}
 461
 462LLWString LLControlGroup::getWString(const std::string& name)
 463{
 464	return get<LLWString>(name);
 465}
 466
 467std::string LLControlGroup::getText(const std::string& name)
 468{
 469	std::string utf8_string = getString(name);
 470	LLStringUtil::replaceChar(utf8_string, '^', '\n');
 471	LLStringUtil::replaceChar(utf8_string, '%', ' ');
 472	return (utf8_string);
 473}
 474
 475LLVector3 LLControlGroup::getVector3(const std::string& name)
 476{
 477	return get<LLVector3>(name);
 478}
 479
 480LLVector3d LLControlGroup::getVector3d(const std::string& name)
 481{
 482	return get<LLVector3d>(name);
 483}
 484
 485LLRect LLControlGroup::getRect(const std::string& name)
 486{
 487	return get<LLRect>(name);
 488}
 489
 490
 491LLColor4 LLControlGroup::getColor(const std::string& name)
 492{
 493	return get<LLColor4>(name);
 494}
 495
 496LLColor4 LLControlGroup::getColor4(const std::string& name)
 497{
 498	return get<LLColor4>(name);
 499}
 500
 501LLColor3 LLControlGroup::getColor3(const std::string& name)
 502{
 503	return get<LLColor3>(name);
 504}
 505
 506LLSD LLControlGroup::getLLSD(const std::string& name)
 507{
 508	return get<LLSD>(name);
 509}
 510
 511BOOL LLControlGroup::controlExists(const std::string& name)
 512{
 513	ctrl_name_table_t::iterator iter = mNameTable.find(name);
 514	return iter != mNameTable.end();
 515}
 516
 517
 518//-------------------------------------------------------------------
 519// Set functions
 520//-------------------------------------------------------------------
 521
 522void LLControlGroup::setBOOL(const std::string& name, BOOL val)
 523{
 524	set<bool>(name, val);
 525}
 526
 527
 528void LLControlGroup::setS32(const std::string& name, S32 val)
 529{
 530	set(name, val);
 531}
 532
 533
 534void LLControlGroup::setF32(const std::string& name, F32 val)
 535{
 536	set(name, val);
 537}
 538
 539
 540void LLControlGroup::setU32(const std::string& name, U32 val)
 541{
 542	set(name, val);
 543}
 544
 545
 546void LLControlGroup::setString(const std::string& name, const std::string &val)
 547{
 548	set(name, val);
 549}
 550
 551
 552void LLControlGroup::setVector3(const std::string& name, const LLVector3 &val)
 553{
 554	set(name, val);
 555}
 556
 557void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val)
 558{
 559	set(name, val);
 560}
 561
 562void LLControlGroup::setRect(const std::string& name, const LLRect &val)
 563{
 564	set(name, val);
 565}
 566
 567void LLControlGroup::setColor4(const std::string& name, const LLColor4 &val)
 568{
 569	set(name, val);
 570}
 571
 572void LLControlGroup::setLLSD(const std::string& name, const LLSD& val)
 573{
 574	set(name, val);
 575}
 576
 577void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val)
 578{
 579	if (name.empty())
 580	{
 581		return;
 582	}
 583
 584	LLControlVariable* control = getControl(name);
 585	
 586	if (control)
 587	{
 588		control->setValue(val);
 589	}
 590	else
 591	{
 592		CONTROL_ERRS << "Invalid control " << name << llendl;
 593	}
 594}
 595
 596
 597//---------------------------------------------------------------
 598// Load and save
 599//---------------------------------------------------------------
 600
 601// Returns number of controls loaded, so 0 if failure
 602U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require_declaration, eControlType declare_as)
 603{
 604	std::string name;
 605
 606	LLXmlTree xml_controls;
 607
 608	if (!xml_controls.parseFile(filename))
 609	{
 610		llwarns << "Unable to open control file " << filename << llendl;
 611		return 0;
 612	}
 613
 614	LLXmlTreeNode* rootp = xml_controls.getRoot();
 615	if (!rootp || !rootp->hasAttribute("version"))
 616	{
 617		llwarns << "No valid settings header found in control file " << filename << llendl;
 618		return 0;
 619	}
 620
 621	U32		item = 0;
 622	U32		validitems = 0;
 623	S32 version;
 624	
 625	rootp->getAttributeS32("version", version);
 626
 627	// Check file version
 628	if (version != CURRENT_VERSION)
 629	{
 630		llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl;
 631		return 0;
 632	}
 633
 634	LLXmlTreeNode* child_nodep = rootp->getFirstChild();
 635	while(child_nodep)
 636	{
 637		name = child_nodep->getName();		
 638		
 639		BOOL declared = controlExists(name);
 640
 641		if (require_declaration && !declared)
 642		{
 643			// Declaration required, but this name not declared.
 644			// Complain about non-empty names.
 645			if (!name.empty())
 646			{
 647				//read in to end of line
 648				llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl;
 649			}
 650			child_nodep = rootp->getNextChild();
 651			continue;
 652		}
 653
 654		// Got an item.  Load it up.
 655		item++;
 656
 657		// If not declared, assume it's a string
 658		if (!declared)
 659		{
 660			switch(declare_as)
 661			{
 662			case TYPE_COL4:
 663				declareColor4(name, LLColor4::white, LLStringUtil::null, NO_PERSIST);
 664				break;
 665			case TYPE_STRING:
 666			default:
 667				declareString(name, LLStringUtil::null, LLStringUtil::null, NO_PERSIST);
 668				break;
 669			}
 670		}
 671
 672		// Control name has been declared in code.
 673		LLControlVariable *control = getControl(name);
 674
 675		llassert(control);
 676		
 677		switch(control->mType)
 678		{
 679		case TYPE_F32:
 680			{
 681				F32 initial = 0.f;
 682
 683				child_nodep->getAttributeF32("value", initial);
 684
 685				control->set(initial);
 686				validitems++;
 687			}
 688			break;
 689		case TYPE_S32:
 690			{
 691				S32 initial = 0;
 692
 693				child_nodep->getAttributeS32("value", initial);
 694
 695				control->set(initial);
 696				validitems++;
 697			}
 698			break;
 699		case TYPE_U32:
 700			{
 701				U32 initial = 0;
 702				child_nodep->getAttributeU32("value", initial);
 703				control->set((LLSD::Integer) initial);
 704				validitems++;
 705			}
 706			break;
 707		case TYPE_BOOLEAN:
 708			{
 709				BOOL initial = FALSE;
 710
 711				child_nodep->getAttributeBOOL("value", initial);
 712				control->set(initial);
 713
 714				validitems++;
 715			}
 716			break;
 717		case TYPE_STRING:
 718			{
 719				std::string string;
 720				child_nodep->getAttributeString("value", string);
 721				control->set(string);
 722				validitems++;
 723			}
 724			break;
 725		case TYPE_VEC3:
 726			{
 727				LLVector3 vector;
 728
 729				child_nodep->getAttributeVector3("value", vector);
 730				control->set(vector.getValue());
 731				validitems++;
 732			}
 733			break;
 734		case TYPE_VEC3D:
 735			{
 736				LLVector3d vector;
 737
 738				child_nodep->getAttributeVector3d("value", vector);
 739
 740				control->set(vector.getValue());
 741				validitems++;
 742			}
 743			break;
 744		case TYPE_RECT:
 745			{
 746				//RN: hack to support reading rectangles from a string
 747				std::string rect_string;
 748
 749				child_nodep->getAttributeString("value", rect_string);
 750				std::istringstream istream(rect_string);
 751				S32 left, bottom, width, height;
 752
 753				istream >> left >> bottom >> width >> height;
 754
 755				LLRect rect;
 756				rect.setOriginAndSize(left, bottom, width, height);
 757
 758				control->set(rect.getValue());
 759				validitems++;
 760			}
 761			break;
 762		case TYPE_COL4:
 763			{
 764				LLColor4 color;
 765				
 766				child_nodep->getAttributeColor4("value", color);
 767				control->set(color.getValue());
 768				validitems++;
 769			}
 770			break;
 771		case TYPE_COL3:
 772			{
 773				LLVector3 color;
 774				
 775				child_nodep->getAttributeVector3("value", color);
 776				control->set(LLColor3(color.mV).getValue());
 777				validitems++;
 778			}
 779			break;
 780
 781		default:
 782		  break;
 783
 784		}
 785	
 786		child_nodep = rootp->getNextChild();
 787	}
 788
 789	return validitems;
 790}
 791
 792U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only)
 793{
 794	LLSD settings;
 795	int num_saved = 0;
 796	for (ctrl_name_table_t::iterator iter = mNameTable.begin();
 797		 iter != mNameTable.end(); iter++)
 798	{
 799		LLControlVariable* control = iter->second;
 800		if (!control)
 801		{
 802			llwarns << "Tried to save invalid control: " << iter->first << llendl;
 803		}
 804
 805		if( control && control->isPersisted() )
 806		{
 807			if (!(nondefault_only && (control->isSaveValueDefault())))
 808			{
 809				settings[iter->first]["Type"] = typeEnumToString(control->type());
 810				settings[iter->first]["Comment"] = control->getComment();
 811				settings[iter->first]["Value"] = control->getSaveValue();
 812				++num_saved;
 813			}
 814			else
 815			{
 816				// Debug spam
 817				// llinfos << "Skipping " << control->getName() << llendl;
 818			}
 819		}
 820	}
 821	llofstream file;
 822	file.open(filename);
 823	if (file.is_open())
 824	{
 825		LLSDSerialize::toPrettyXML(settings, file);
 826		file.close();
 827		llinfos << "Saved to " << filename << llendl;
 828	}
 829	else
 830	{
 831        // This is a warning because sometime we want to use settings files which can't be written...
 832		llwarns << "Unable to open settings file: " << filename << llendl;
 833		return 0;
 834	}
 835	return num_saved;
 836}
 837
 838U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
 839{
 840	LLSD settings;
 841	llifstream infile;
 842	infile.open(filename);
 843	if(!infile.is_open())
 844	{
 845		llwarns << "Cannot find file " << filename << " to load." << llendl;
 846		return 0;
 847	}
 848
 849	S32 ret = LLSDSerialize::fromXML(settings, infile);
 850
 851	if (ret <= 0)
 852	{
 853		infile.close();
 854		llwarns << "Unable to open LLSD control file " << filename << ". Trying Legacy Method." << llendl;		
 855		return loadFromFileLegacy(filename, TRUE, TYPE_STRING);
 856	}
 857
 858	U32	validitems = 0;
 859	bool hidefromsettingseditor = false;
 860	
 861	for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
 862	{
 863		bool persist = true;
 864		std::string const & name = itr->first;
 865		LLSD const & control_map = itr->second;
 866		
 867		if(control_map.has("Persist")) 
 868		{
 869			persist = control_map["Persist"].asInteger();
 870		}
 871		
 872		// Sometimes we want to use the settings system to provide cheap persistence, but we
 873		// don't want the settings themselves to be easily manipulated in the UI because 
 874		// doing so can cause support problems. So we have this option:
 875		if(control_map.has("HideFromEditor"))
 876		{
 877			hidefromsettingseditor = control_map["HideFromEditor"].asInteger();
 878		}
 879		else
 880		{
 881			hidefromsettingseditor = false;
 882		}
 883		
 884		// If the control exists just set the value from the input file.
 885		LLControlVariable* existing_control = getControl(name);
 886		if(existing_control)
 887		{
 888			if(set_default_values)
 889			{
 890				// Override all previously set properties of this control.
 891				// ... except for type. The types must match.
 892				eControlType new_type = typeStringToEnum(control_map["Type"].asString());
 893				if(existing_control->isType(new_type))
 894				{
 895					existing_control->setDefaultValue(control_map["Value"]);
 896					existing_control->setPersist(persist);
 897					existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor);
 898					existing_control->setComment(control_map["Comment"].asString());
 899				}
 900				else
 901				{
 902					llerrs << "Mismatched type of control variable '"
 903						   << name << "' found while loading '"
 904						   << filename << "'." << llendl;
 905				}
 906			}
 907			else if(existing_control->isPersisted())
 908			{
 909				existing_control->setValue(control_map["Value"], save_values);
 910			}
 911			// *NOTE: If not persisted and not setting defaults, 
 912			// the value should not get loaded.
 913		}
 914		else
 915		{
 916			declareControl(name, 
 917						   typeStringToEnum(control_map["Type"].asString()), 
 918						   control_map["Value"], 
 919						   control_map["Comment"].asString(), 
 920						   persist,
 921						   hidefromsettingseditor
 922						   );
 923		}
 924		
 925		++validitems;
 926	}
 927
 928	return validitems;
 929}
 930
 931void LLControlGroup::resetToDefaults()
 932{
 933	ctrl_name_table_t::iterator control_iter;
 934	for (control_iter = mNameTable.begin();
 935		control_iter != mNameTable.end();
 936		++control_iter)
 937	{
 938		LLControlVariable* control = (*control_iter).second;
 939		control->resetToDefault();
 940	}
 941}
 942
 943void LLControlGroup::applyToAll(ApplyFunctor* func)
 944{
 945	for (ctrl_name_table_t::iterator iter = mNameTable.begin();
 946		 iter != mNameTable.end(); iter++)
 947	{
 948		func->apply(iter->first, iter->second);
 949	}
 950}
 951
 952//============================================================================
 953
 954#ifdef TEST_HARNESS
 955void main()
 956{
 957	F32_CONTROL foo, getfoo;
 958
 959	S32_CONTROL bar, getbar;
 960	
 961	BOOL_CONTROL baz;
 962
 963	U32 count = gGlobals.loadFromFile("controls.ini");
 964	llinfos << "Loaded " << count << " controls" << llendl;
 965
 966	// test insertion
 967	foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
 968	gGlobals.addEntry("gFoo", foo);
 969
 970	bar = new LLControlVariable<S32>("gBar", 10, 2, 22);
 971	gGlobals.addEntry("gBar", bar);
 972
 973	baz = new LLControlVariable<BOOL>("gBaz", FALSE);
 974	gGlobals.addEntry("gBaz", baz);
 975
 976	// test retrieval
 977	getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo");
 978	getfoo->dump();
 979
 980	getbar = (S32_CONTROL) gGlobals.resolveName("gBar");
 981	getbar->dump();
 982
 983	// change data
 984	getfoo->set(10.f);
 985	getfoo->dump();
 986
 987	// Failure modes
 988
 989	// ...min > max
 990	// badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f);
 991
 992	// ...initial > max
 993	// badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000);
 994
 995	// ...misspelled name
 996	// getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled");
 997	// getfoo->dump();
 998
 999	// ...invalid data type
1000	getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo");
1001	getfoo->set(TRUE);
1002	getfoo->dump();
1003
1004	// ...out of range data
1005	// getfoo->set(100000000.f);
1006	// getfoo->dump();
1007
1008	// Clean Up
1009	delete foo;
1010	delete bar;
1011	delete baz;
1012}
1013#endif
1014
1015
1016template <> eControlType get_control_type<U32>() 
1017{ 
1018	return TYPE_U32; 
1019}
1020
1021template <> eControlType get_control_type<S32>() 
1022{ 
1023	return TYPE_S32; 
1024}
1025
1026template <> eControlType get_control_type<F32>() 
1027{ 
1028	return TYPE_F32; 
1029}
1030
1031template <> eControlType get_control_type<bool> () 
1032{ 
1033	return TYPE_BOOLEAN; 
1034}
1035/*
1036// Yay BOOL, its really an S32.
1037template <> eControlType get_control_type<BOOL> () 
1038{ 
1039	return TYPE_BOOLEAN; 
1040}
1041*/
1042template <> eControlType get_control_type<std::string>() 
1043{ 
1044	return TYPE_STRING; 
1045}
1046
1047template <> eControlType get_control_type<LLVector3>() 
1048{ 
1049	return TYPE_VEC3; 
1050}
1051
1052template <> eControlType get_control_type<LLVector3d>() 
1053{ 
1054	return TYPE_VEC3D; 
1055}
1056
1057template <> eControlType get_control_type<LLRect>() 
1058{ 
1059	return TYPE_RECT; 
1060}
1061
1062template <> eControlType get_control_type<LLColor4>() 
1063{ 
1064	return TYPE_COL4; 
1065}
1066
1067template <> eControlType get_control_type<LLColor3>() 
1068{ 
1069	return TYPE_COL3; 
1070}
1071
1072template <> eControlType get_control_type<LLSD>() 
1073{ 
1074	return TYPE_LLSD; 
1075}
1076
1077
1078template <> LLSD convert_to_llsd<U32>(const U32& in) 
1079{ 
1080	return (LLSD::Integer)in; 
1081}
1082
1083template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in) 
1084{ 
1085	return in.getValue(); 
1086}
1087
1088template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in) 
1089{ 
1090	return in.getValue(); 
1091}
1092
1093template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) 
1094{ 
1095	return in.getValue(); 
1096}
1097
1098template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in) 
1099{ 
1100	return in.getValue(); 
1101}
1102
1103template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in) 
1104{ 
1105	return in.getValue(); 
1106}
1107
1108template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in) 
1109{ 
1110	return in.getValue();
1111}
1112
1113
1114template<>
1115bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name)
1116{
1117	if (type == TYPE_BOOLEAN)
1118		return sd.asBoolean();
1119	else
1120	{
1121		CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl;
1122		return FALSE;
1123	}
1124}
1125
1126template<>
1127S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name)
1128{
1129	if (type == TYPE_S32)
1130		return sd.asInteger();
1131	else
1132	{
1133		CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl;
1134		return 0;
1135	}
1136}
1137
1138template<>
1139U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name)
1140{
1141	if (type == TYPE_U32)	
1142		return sd.asInteger();
1143	else
1144	{
1145		CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl;
1146		return 0;
1147	}
1148}
1149
1150template<>
1151F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name)
1152{
1153	if (type == TYPE_F32)
1154		return (F32) sd.asReal();
1155	else
1156	{
1157		CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl;
1158		return 0.0f;
1159	}
1160}
1161
1162template<>
1163std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name)
1164{
1165	if (type == TYPE_STRING)
1166		return sd.asString();
1167	else
1168	{
1169		CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl;
1170		return LLStringUtil::null;
1171	}
1172}
1173
1174template<>
1175LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name)
1176{
1177	return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name));
1178}
1179
1180template<>
1181LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name)
1182{
1183	if (type == TYPE_VEC3)
1184		return (LLVector3)sd;
1185	else
1186	{
1187		CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl;
1188		return LLVector3::zero;
1189	}
1190}
1191
1192template<>
1193LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name)
1194{
1195	if (type == TYPE_VEC3D)
1196		return (LLVector3d)sd;
1197	else
1198	{
1199		CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl;
1200		return LLVector3d::zero;
1201	}
1202}
1203
1204template<>
1205LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name)
1206{
1207	if (type == TYPE_RECT)
1208		return LLRect(sd);
1209	else
1210	{
1211		CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl;
1212		return LLRect::null;
1213	}
1214}
1215
1216
1217template<>
1218LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name)
1219{
1220	if (type == TYPE_COL4)
1221	{
1222		LLColor4 color(sd);
1223		if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
1224		{
1225			llwarns << "Color " << control_name << " red value out of range: " << color << llendl;
1226		}
1227		else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
1228		{
1229			llwarns << "Color " << control_name << " green value out of range: " << color << llendl;
1230		}
1231		else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
1232		{
1233			llwarns << "Color " << control_name << " blue value out of range: " << color << llendl;
1234		}
1235		else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
1236		{
1237			llwarns << "Color " << control_name << " alpha value out of range: " << color << llendl;
1238		}
1239
1240		return LLColor4(sd);
1241	}
1242	else
1243	{
1244		CONTROL_ERRS << "Control " << control_name << " not a color" << llendl;
1245		return LLColor4::white;
1246	}
1247}
1248
1249template<>
1250LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name)
1251{
1252	if (type == TYPE_COL3)
1253		return sd;
1254	else
1255	{
1256		CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl;
1257		return LLColor3::white;
1258	}
1259}
1260
1261template<>
1262LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name)
1263{
1264	return sd;
1265}
1266
1267
1268#if TEST_CACHED_CONTROL
1269
1270#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V)
1271DECL_LLCC(U32, (U32)666);
1272DECL_LLCC(S32, (S32)-666);
1273DECL_LLCC(F32, (F32)-666.666);
1274DECL_LLCC(bool, true);
1275DECL_LLCC(BOOL, FALSE);
1276static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value");
1277DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
1278DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
1279DECL_LLCC(LLRect, LLRect(0, 0, 100, 500));
1280DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
1281DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
1282DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
1283
1284LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
1285DECL_LLCC(LLSD, test_llsd);
1286
1287static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment");
1288
1289void test_cached_control()
1290{
1291#define TEST_LLCC(T, V) if((T)mySetting_##T != V) llerrs << "Fail "#T << llendl
1292	TEST_LLCC(U32, 666);
1293	TEST_LLCC(S32, (S32)-666);
1294	TEST_LLCC(F32, (F32)-666.666);
1295	TEST_LLCC(bool, true);
1296	TEST_LLCC(BOOL, FALSE);
1297	if((std::string)mySetting_string != "Default String Value") llerrs << "Fail string" << llendl;
1298	TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
1299	TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
1300	TEST_LLCC(LLRect, LLRect(0, 0, 100, 500));
1301	TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
1302	TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
1303	TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
1304//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); 
1305
1306	if((std::string)test_BrowserHomePage != "http://www.secondlife.com") llerrs << "Fail BrowserHomePage" << llendl;
1307}
1308#endif // TEST_CACHED_CONTROL
1309