diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/llxml/llcontrol.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/llxml/llcontrol.cpp')
-rw-r--r-- | indra/llxml/llcontrol.cpp | 3020 |
1 files changed, 1508 insertions, 1512 deletions
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index c0f27e2c22..beeca105bc 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1,1512 +1,1508 @@ -/** - * @file llcontrol.cpp - * @brief Holds global state for viewer. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include <iostream> -#include <fstream> -#include <algorithm> - -#include "llcontrol.h" - -#include "llstl.h" - -#include "llstring.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4coloru.h" -#include "v4color.h" -#include "v3color.h" -#include "llquaternion.h" -#include "llrect.h" -#include "llxmltree.h" -#include "llsdserialize.h" -#include "llfile.h" -#include "lltimer.h" -#include "lldir.h" - -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG -#define CONTROL_ERRS LL_ERRS("ControlErrors") -#else -#define CONTROL_ERRS LL_WARNS("ControlErrors") -#endif - - -template <> eControlType get_control_type<U32>(); -template <> eControlType get_control_type<S32>(); -template <> eControlType get_control_type<F32>(); -template <> eControlType get_control_type<bool>(); -template <> eControlType get_control_type<std::string>(); - -template <> eControlType get_control_type<LLVector3>(); -template <> eControlType get_control_type<LLVector3d>(); -template <> eControlType get_control_type<LLRect>(); -template <> eControlType get_control_type<LLColor4>(); -template <> eControlType get_control_type<LLColor3>(); -template <> eControlType get_control_type<LLColor4U>(); -template <> eControlType get_control_type<LLSD>(); - -template <> LLSD convert_to_llsd<U32>(const U32& in); -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in); -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in); -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in); -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in); -template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in); - -template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name); - -//this defines the current version of the settings file -const S32 CURRENT_VERSION = 101; - -// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate -// the gSavedSettings profiling code. This code tracks the calls to get a saved (debug) setting. -// When the viewer exits the results are written to the log directory to the file specified -// by SETTINGS_PROFILE below. Only settings with an average access rate >= 2/second are output. -typedef std::pair<std::string, U32> settings_pair_t; -typedef std::vector<settings_pair_t> settings_vec_t; -LLSD getCount; -settings_vec_t getCount_v; -F64 start_time = 0; -std::string SETTINGS_PROFILE = "settings_profile.log"; - -bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) -{ - bool result = false; - switch (mType) - { - case TYPE_U32: - case TYPE_S32: - result = a.asInteger() == b.asInteger(); - break; - case TYPE_BOOLEAN: - result = a.asBoolean() == b.asBoolean(); - break; - case TYPE_F32: - result = a.asReal() == b.asReal(); - break; - case TYPE_VEC3: - case TYPE_VEC3D: - result = LLVector3d(a) == LLVector3d(b); - break; - case TYPE_QUAT: - result = LLQuaternion(a) == LLQuaternion(b); - break; - case TYPE_RECT: - result = LLRect(a) == LLRect(b); - break; - case TYPE_COL4: - result = LLColor4(a) == LLColor4(b); - break; - case TYPE_COL3: - result = LLColor3(a) == LLColor3(b); - break; - case TYPE_STRING: - result = a.asString() == b.asString(); - break; - default: - break; - } - - return result; -} - -LLControlVariable::LLControlVariable(const std::string& name, eControlType type, - LLSD initial, const std::string& comment, - ePersist persist, bool hidefromsettingseditor) - : mName(name), - mComment(comment), - mType(type), - mPersist(persist), - mHideFromSettingsEditor(hidefromsettingseditor) -{ - if ((persist != PERSIST_NO) && mComment.empty()) - { - LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; - } - //Push back versus setValue'ing here, since we don't want to call a signal yet - mValues.push_back(initial); -} - - - -LLControlVariable::~LLControlVariable() -{ -} - -LLSD LLControlVariable::getComparableValue(const LLSD& value) -{ - // *FIX:MEP - The following is needed to make the LLSD::ImplString - // work with boolean controls... - LLSD storable_value; - if(TYPE_BOOLEAN == type() && value.isString()) - { - bool temp; - if(LLStringUtil::convertToBOOL(value.asString(), temp)) - { - storable_value = temp; - } - else - { - storable_value = false; - } - } - else if (TYPE_LLSD == type() && value.isString()) - { - LLPointer<LLSDNotationParser> parser = new LLSDNotationParser; - LLSD result; - std::stringstream value_stream(value.asString()); - if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) - { - storable_value = result; - } - else - { - storable_value = value; - } - } - else - { - storable_value = value; - } - - return storable_value; -} - -void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) -{ - if (!mValidateSignal(this, new_value)) - { - // can not set new value, exit - return; - } - - LLSD storable_value = getComparableValue(new_value); - LLSD original_value = getValue(); - bool value_changed = !llsd_compare(original_value, storable_value); - if(saved_value) - { - // If we're going to save this value, return to default but don't fire - resetToDefault(false); - if (!llsd_compare(mValues.back(), storable_value)) - { - mValues.push_back(storable_value); - } - } - else - { - // This is an unsaved value. Its needs to reside at - // mValues[2] (or greater). It must not affect - // the result of getSaveValue() - if (!llsd_compare(mValues.back(), storable_value)) - { - while(mValues.size() > 2) - { - // Remove any unsaved values. - mValues.pop_back(); - } - - if(mValues.size() < 2) - { - // Add the default to the 'save' value. - mValues.push_back(mValues[0]); - } - - // Add the 'un-save' value. - mValues.push_back(storable_value); - } - } - - if(value_changed) - { - firePropertyChanged(original_value); - } -} - -void LLControlVariable::setDefaultValue(const LLSD& value) -{ - // Set the control variables value and make it - // the default value. If the active value is changed, - // send the signal. - // *NOTE: Default values are not saved, only read. - - LLSD comparable_value = getComparableValue(value); - LLSD original_value = getValue(); - bool value_changed = !llsd_compare(original_value, comparable_value); - resetToDefault(false); - mValues[0] = comparable_value; - if (value_changed) - { - firePropertyChanged(original_value); - } -} - -void LLControlVariable::setPersist(ePersist state) -{ - mPersist = state; -} - -void LLControlVariable::setHiddenFromSettingsEditor(bool hide) -{ - mHideFromSettingsEditor = hide; -} - -void LLControlVariable::setComment(const std::string& comment) -{ - mComment = comment; -} - -void LLControlVariable::resetToDefault(bool fire_signal) -{ - //The first setting is always the default - //Pop to it and fire off the listener - LLSD originalValue = mValues.back(); - - while(mValues.size() > 1) - { - mValues.pop_back(); - } - - if(fire_signal) - { - firePropertyChanged(originalValue); - } -} - -bool LLControlVariable::shouldSave(bool nondefault_only) -{ - // This method is used to decide whether we should save a given - // variable. Two of the three values of mPersist are easy. - if (mPersist == PERSIST_NO) - return false; - - if (mPersist == PERSIST_ALWAYS) - return true; - - // PERSIST_NONDFT - // If caller doesn't need us to filter, just save. - if (! nondefault_only) - return true; - - // PERSIST_NONDFT: caller only wants us to save this variable if its value - // differs from default. - if (isDefault()) // never been altered - return false; - - // We've set at least one other value: compare it to default. Save only if - // they differ. - return ! llsd_compare(getSaveValue(), getDefault()); -} - -LLSD LLControlVariable::getSaveValue() const -{ - //The first level of the stack is default - //We assume that the second level is user preferences that should be saved - if(mValues.size() > 1) return mValues[1]; - return mValues[0]; -} - -LLPointer<LLControlVariable> LLControlGroup::getControl(std::string_view name) -{ - if (mSettingsProfile) - { - incrCount(name); - } - - ctrl_name_table_t::iterator iter = mNameTable.find(name.data()); - return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second; -} - - -//////////////////////////////////////////////////////////////////////////// - -// Must match the type definition in llcontrol.h -const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" - ,"S32" - ,"F32" - ,"Boolean" - ,"String" - ,"Vector3" - ,"Vector3D" - ,"Quaternion" - ,"Rect" - ,"Color4" - ,"Color3" - ,"LLSD" - }; - -LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker<LLControlGroup, std::string>(name), - mSettingsProfile(false) -{ - - if (NULL != getenv("LL_SETTINGS_PROFILE")) - { - mSettingsProfile = true; - } -} - -LLControlGroup::~LLControlGroup() -{ - cleanup(); -} - -static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) -{ - return lhs.second > rhs.second; -}; - -void LLControlGroup::cleanup() -{ - if(mSettingsProfile && getCount.size() != 0) - { - std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); - LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ - if(!out) - { - LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; - } - else - { - F64 end_time = LLTimer::getTotalSeconds(); - U32 total_seconds = (U32)(end_time - start_time); - - std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); - std::ostringstream data_msg; - - data_msg << msg; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; - } - - for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) - { - getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); - } - sort(getCount_v.begin(), getCount_v.end(), compareRoutine); - - for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) - { - U32 access_rate = 0; - if (total_seconds != 0) - { - access_rate = iter->second / total_seconds; - } - if (access_rate >= 2) - { - std::ostringstream data_msg; - msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); - data_msg << msg << "\n"; - size_t data_size = data_msg.str().size(); - if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) - { - LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; - } - } - } - getCount = LLSD::emptyMap(); - fclose(out); - } - } - - mNameTable.clear(); -} - -eControlType LLControlGroup::typeStringToEnum(const std::string& typestr) -{ - for(int i = 0; i < (int)TYPE_COUNT; ++i) - { - if(mTypeString[i] == typestr) return (eControlType)i; - } - return (eControlType)-1; -} - -std::string LLControlGroup::typeEnumToString(eControlType typeenum) -{ - return mTypeString[typeenum]; -} - -LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor) -{ - LLControlVariable* existing_control = getControl(name); - if (existing_control) - { - if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) - { - if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) - { - // Sometimes we need to declare a control *after* it has been loaded from a settings file. - LLSD cur_value = existing_control->getValue(); // get the current value - existing_control->setDefaultValue(initial_val); // set the default to the declared value - existing_control->setValue(cur_value); // now set to the loaded value - } - } - else - { - LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; - } - return existing_control; - } - - // if not, create the control and add it to the name table - LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); - mNameTable[name] = control; - return control; -} - -LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_S32, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_F32, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const bool initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_STRING, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ - return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ - return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ - return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ - return declareControl(name, TYPE_LLSD, initial_val, comment, persist); -} - -void LLControlGroup::incrCount(std::string_view name) -{ - if (0.0 == start_time) - { - start_time = LLTimer::getTotalSeconds(); - } - getCount[name.data()] = getCount[name.data()].asInteger() + 1; -} - -bool LLControlGroup::getBOOL(std::string_view name) -{ - return get<bool>(name); -} - -S32 LLControlGroup::getS32(std::string_view name) -{ - return get<S32>(name); -} - -U32 LLControlGroup::getU32(std::string_view name) -{ - return get<U32>(name); -} - -F32 LLControlGroup::getF32(std::string_view name) -{ - return get<F32>(name); -} - -std::string LLControlGroup::getString(std::string_view name) -{ - return get<std::string>(name); -} - -LLWString LLControlGroup::getWString(std::string_view name) -{ - return get<LLWString>(name); -} - -std::string LLControlGroup::getText(std::string_view name) -{ - std::string utf8_string = getString(name); - LLStringUtil::replaceChar(utf8_string, '^', '\n'); - LLStringUtil::replaceChar(utf8_string, '%', ' '); - return (utf8_string); -} - -LLVector3 LLControlGroup::getVector3(std::string_view name) -{ - return get<LLVector3>(name); -} - -LLVector3d LLControlGroup::getVector3d(std::string_view name) -{ - return get<LLVector3d>(name); -} - -LLQuaternion LLControlGroup::getQuaternion(std::string_view name) -{ - return get<LLQuaternion>(name); -} - -LLRect LLControlGroup::getRect(std::string_view name) -{ - return get<LLRect>(name); -} - - -LLColor4 LLControlGroup::getColor(std::string_view name) -{ - return get<LLColor4>(name); -} - -LLColor4 LLControlGroup::getColor4(std::string_view name) -{ - return get<LLColor4>(name); -} - -LLColor3 LLControlGroup::getColor3(std::string_view name) -{ - return get<LLColor3>(name); -} - -LLSD LLControlGroup::getLLSD(std::string_view name) -{ - return get<LLSD>(name); -} - -LLSD LLControlGroup::asLLSD(bool diffs_only) -{ - // Dump all stored values as LLSD - LLSD result = LLSD::emptyArray(); - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable *control = iter->second; - if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) - { - continue; - } - const std::string& name = iter->first; - result[name] = getLLSD(name); - } - return result; -} - -bool LLControlGroup::controlExists(const std::string& name) -{ - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter != mNameTable.end(); -} - - -//------------------------------------------------------------------- -// Set functions -//------------------------------------------------------------------- - -void LLControlGroup::setBOOL(std::string_view name, bool val) -{ - set<bool>(name, val); -} - - -void LLControlGroup::setS32(std::string_view name, S32 val) -{ - set(name, val); -} - - -void LLControlGroup::setF32(std::string_view name, F32 val) -{ - set(name, val); -} - - -void LLControlGroup::setU32(std::string_view name, U32 val) -{ - set(name, val); -} - - -void LLControlGroup::setString(std::string_view name, const std::string &val) -{ - set(name, val); -} - - -void LLControlGroup::setVector3(std::string_view name, const LLVector3 &val) -{ - set(name, val); -} - -void LLControlGroup::setVector3d(std::string_view name, const LLVector3d &val) -{ - set(name, val); -} - -void LLControlGroup::setQuaternion(std::string_view name, const LLQuaternion &val) -{ - set(name, val); -} - -void LLControlGroup::setRect(std::string_view name, const LLRect &val) -{ - set(name, val); -} - -void LLControlGroup::setColor4(std::string_view name, const LLColor4 &val) -{ - set(name, val); -} - -void LLControlGroup::setLLSD(std::string_view name, const LLSD& val) -{ - set(name, val); -} - -void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val) -{ - if (name.empty()) - { - return; - } - - LLControlVariable* control = getControl(name); - - if (control) - { - control->setValue(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << LL_ENDL; - } -} - - -//--------------------------------------------------------------- -// Load and save -//--------------------------------------------------------------- - -// Returns number of controls loaded, so 0 if failure -U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as) -{ - std::string name; - - LLXmlTree xml_controls; - - if (!xml_controls.parseFile(filename)) - { - LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; - return 0; - } - - LLXmlTreeNode* rootp = xml_controls.getRoot(); - if (!rootp || !rootp->hasAttribute("version")) - { - LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; - return 0; - } - - U32 validitems = 0; - S32 version; - - rootp->getAttributeS32("version", version); - - // Check file version - if (version != CURRENT_VERSION) - { - LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; - return 0; - } - - LLXmlTreeNode* child_nodep = rootp->getFirstChild(); - while(child_nodep) - { - name = child_nodep->getName(); - - bool declared = controlExists(name); - - if (require_declaration && !declared) - { - // Declaration required, but this name not declared. - // Complain about non-empty names. - if (!name.empty()) - { - //read in to end of line - LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; - } - child_nodep = rootp->getNextChild(); - continue; - } - - // Got an item. Load it up. - // If not declared, assume it's a string - if (!declared) - { - switch(declare_as) - { - case TYPE_COL4: - declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - case TYPE_STRING: - default: - declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); - break; - } - } - - // Control name has been declared in code. - LLControlVariable *control = getControl(name); - - llassert(control); - - switch(control->mType) - { - case TYPE_F32: - { - F32 initial = 0.f; - - child_nodep->getAttributeF32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_S32: - { - S32 initial = 0; - - child_nodep->getAttributeS32("value", initial); - - control->set(initial); - validitems++; - } - break; - case TYPE_U32: - { - U32 initial = 0; - child_nodep->getAttributeU32("value", initial); - control->set((LLSD::Integer) initial); - validitems++; - } - break; - case TYPE_BOOLEAN: - { - bool initial = false; - - child_nodep->getAttributeBOOL("value", initial); - control->set(initial); - - validitems++; - } - break; - case TYPE_STRING: - { - std::string string; - child_nodep->getAttributeString("value", string); - control->set(string); - validitems++; - } - break; - case TYPE_VEC3: - { - LLVector3 vector; - - child_nodep->getAttributeVector3("value", vector); - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_VEC3D: - { - LLVector3d vector; - - child_nodep->getAttributeVector3d("value", vector); - - control->set(vector.getValue()); - validitems++; - } - break; - case TYPE_QUAT: - { - LLQuaternion quat; - - child_nodep->getAttributeQuat("value", quat); - - control->set(quat.getValue()); - validitems++; - } - break; - case TYPE_RECT: - { - //RN: hack to support reading rectangles from a string - std::string rect_string; - - child_nodep->getAttributeString("value", rect_string); - std::istringstream istream(rect_string); - S32 left, bottom, width, height; - - istream >> left >> bottom >> width >> height; - - LLRect rect; - rect.setOriginAndSize(left, bottom, width, height); - - control->set(rect.getValue()); - validitems++; - } - break; - case TYPE_COL4: - { - LLColor4 color; - - child_nodep->getAttributeColor4("value", color); - control->set(color.getValue()); - validitems++; - } - break; - case TYPE_COL3: - { - LLVector3 color; - - child_nodep->getAttributeVector3("value", color); - control->set(LLColor3(color.mV).getValue()); - validitems++; - } - break; - - default: - break; - - } - - child_nodep = rootp->getNextChild(); - } - - return validitems; -} - -U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only) -{ - LLSD settings; - int num_saved = 0; - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - LLControlVariable* control = iter->second; - if (!control) - { - LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; - } - else if( control->shouldSave(nondefault_only) ) - { - settings[iter->first]["Type"] = typeEnumToString(control->type()); - settings[iter->first]["Comment"] = control->getComment(); - settings[iter->first]["Value"] = control->getSaveValue(); - ++num_saved; - } - } - llofstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::toPrettyXML(settings, file); - file.close(); - LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL; - } - else - { - // This is a warning because sometime we want to use settings files which can't be written... - LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; - return 0; - } - return num_saved; -} - -U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values) -{ - LLSD settings; - llifstream infile; - infile.open(filename.c_str()); - if(!infile.is_open()) - { - LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; - return 0; - } - - if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) - { - infile.close(); - LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; - return loadFromFileLegacy(filename, true, TYPE_STRING); - } - - U32 validitems = 0; - bool hidefromsettingseditor = false; - - for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) - { - LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; - std::string const & name = itr->first; - LLSD const & control_map = itr->second; - - if(control_map.has("Persist")) - { - persist = control_map["Persist"].asInteger()? - LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; - } - - // Sometimes we want to use the settings system to provide cheap persistence, but we - // don't want the settings themselves to be easily manipulated in the UI because - // doing so can cause support problems. So we have this option: - if(control_map.has("HideFromEditor")) - { - hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); - } - else - { - hidefromsettingseditor = false; - } - - // If the control exists just set the value from the input file. - LLControlVariable* existing_control = getControl(name); - if(existing_control) - { - // set_default_values is true when we're loading the initial, - // immutable files from app_settings, e.g. settings.xml. - if(set_default_values) - { - // Override all previously set properties of this control. - // ... except for type. The types must match. - eControlType new_type = typeStringToEnum(control_map["Type"].asString()); - if(existing_control->isType(new_type)) - { - existing_control->setDefaultValue(control_map["Value"]); - existing_control->setPersist(persist); - existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); - existing_control->setComment(control_map["Comment"].asString()); - } - else - { - LL_ERRS() << "Mismatched type of control variable '" - << name << "' found while loading '" - << filename << "'." << LL_ENDL; - } - } - else if(existing_control->isPersisted()) - { - // save_values is specifically false for (e.g.) - // SessionSettingsFile and UserSessionSettingsFile -- in other - // words, for a file that's supposed to be transient. - existing_control->setValue(control_map["Value"], save_values); - } - // *NOTE: If not persisted and not setting defaults, - // the value should not get loaded. - } - else - { - // We've never seen this control before. Either we're loading up - // the initial set of default settings files (set_default_values) - // -- or we're loading user settings last saved by a viewer that - // supports a superset of the variables we know. - // CHOP-962: if we're loading an unrecognized user setting, make - // sure we save it later. If you try an experimental viewer, tweak - // a new setting, briefly revert to an old viewer, then return to - // the new one, we don't want the old viewer to discard the - // setting you changed. - if (! set_default_values) - { - // Using PERSIST_ALWAYS insists that saveToFile() (which calls - // LLControlVariable::shouldSave()) must save this control - // variable regardless of its value. We can safely set this - // LLControlVariable persistent because the 'persistent' flag - // is not itself persisted! - persist = LLControlVariable::PERSIST_ALWAYS; - // We want to mention unrecognized user settings variables - // (e.g. from a newer version of the viewer) in the log. But - // we also arrive here for Boolean variables generated by - // the notifications subsystem when the user checks "Don't - // show me this again." These aren't declared in settings.xml; - // they're actually named for the notification they suppress. - // We don't want to mention those. Apologies, this is a bit of - // a hack: we happen to know that user settings go into an - // LLControlGroup whose name is "Global". - if (getKey() == "Global") - { - LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() - << " settings variable " << name << LL_ENDL; - } - } - - declareControl(name, - typeStringToEnum(control_map["Type"].asString()), - control_map["Value"], - control_map["Comment"].asString(), - persist, - hidefromsettingseditor - ); - } - - ++validitems; - } - - LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; - return validitems; -} - -void LLControlGroup::resetToDefaults() -{ - ctrl_name_table_t::iterator control_iter; - for (control_iter = mNameTable.begin(); - control_iter != mNameTable.end(); - ++control_iter) - { - LLControlVariable* control = (*control_iter).second; - control->resetToDefault(); - } -} - -void LLControlGroup::applyToAll(ApplyFunctor* func) -{ - for (ctrl_name_table_t::iterator iter = mNameTable.begin(); - iter != mNameTable.end(); iter++) - { - func->apply(iter->first, iter->second); - } -} - -//============================================================================ - -#ifdef TEST_HARNESS -void main() -{ - F32_CONTROL foo, getfoo; - - S32_CONTROL bar, getbar; - - BOOL_CONTROL baz; - - U32 count = gGlobals.loadFromFile("controls.ini"); - LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; - - // test insertion - foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f); - gGlobals.addEntry("gFoo", foo); - - bar = new LLControlVariable<S32>("gBar", 10, 2, 22); - gGlobals.addEntry("gBar", bar); - - baz = new LLControlVariable<bool>("gBaz", false); - gGlobals.addEntry("gBaz", baz); - - // test retrieval - getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo"); - getfoo->dump(); - - getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); - getbar->dump(); - - // change data - getfoo->set(10.f); - getfoo->dump(); - - // Failure modes - - // ...min > max - // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f); - - // ...initial > max - // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000); - - // ...misspelled name - // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); - // getfoo->dump(); - - // ...invalid data type - getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); - getfoo->set(true); - getfoo->dump(); - - // ...out of range data - // getfoo->set(100000000.f); - // getfoo->dump(); - - // Clean Up - delete foo; - delete bar; - delete baz; -} -#endif - - -template <> eControlType get_control_type<U32>() -{ - return TYPE_U32; -} - -template <> eControlType get_control_type<S32>() -{ - return TYPE_S32; -} - -template <> eControlType get_control_type<F32>() -{ - return TYPE_F32; -} - -template <> eControlType get_control_type<bool> () -{ - return TYPE_BOOLEAN; -} - -template <> eControlType get_control_type<std::string>() -{ - return TYPE_STRING; -} - -template <> eControlType get_control_type<LLVector3>() -{ - return TYPE_VEC3; -} - -template <> eControlType get_control_type<LLVector3d>() -{ - return TYPE_VEC3D; -} - -template <> eControlType get_control_type<LLQuaternion>() -{ - return TYPE_QUAT; -} - -template <> eControlType get_control_type<LLRect>() -{ - return TYPE_RECT; -} - -template <> eControlType get_control_type<LLColor4>() -{ - return TYPE_COL4; -} - -template <> eControlType get_control_type<LLColor3>() -{ - return TYPE_COL3; -} - -template <> eControlType get_control_type<LLSD>() -{ - return TYPE_LLSD; -} - - -template <> LLSD convert_to_llsd<U32>(const U32& in) -{ - return (LLSD::Integer)in; -} - -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in) -{ - return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in) -{ - return in.getValue(); -} -template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in) -{ - return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in) -{ - return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in) -{ - return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in) -{ - return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in) -{ - return in.getValue(); -} - - -template<> -bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_BOOLEAN) - return sd.asBoolean(); - else - { - CONTROL_ERRS << "Invalid bool value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return false; - } -} - -template<> -S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_S32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } -} - -template<> -U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_U32) - return sd.asInteger(); - else - { - CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0; - } -} - -template<> -F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_F32) - return (F32) sd.asReal(); - else - { - CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return 0.0f; - } -} - -template<> -std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_STRING) - return sd.asString(); - else - { - CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLStringUtil::null; - } -} - -template<> -LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name)); -} - -template<> -LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_VEC3) - return (LLVector3)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3::zero; - } -} - -template<> -LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_VEC3D) - return (LLVector3d)sd; - else - { - CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLVector3d::zero; - } -} - -template<> -LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_QUAT) - return (LLQuaternion)sd; - else - { - CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLQuaternion(); - } -} - -template<> -LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_RECT) - return LLRect(sd); - else - { - CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLRect::null; - } -} - - -template<> -LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_COL4) - { - LLColor4 color(sd); - if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL; - } - else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL; - } - else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL; - } - else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) - { - LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; - } - - return LLColor4(sd); - } - else - { - CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; - return LLColor4::white; - } -} - -template<> -LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - if (type == TYPE_COL3) - return sd; - else - { - CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; - return LLColor3::white; - } -} - -template<> -LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name) -{ - return sd; -} - - -#if TEST_CACHED_CONTROL - -#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V) -DECL_LLCC(U32, (U32)666); -DECL_LLCC(S32, (S32)-666); -DECL_LLCC(F32, (F32)-666.666); -DECL_LLCC(bool, true); -static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value"); -DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); -DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); -DECL_LLCC(LLRect, LLRect(0, 0, 100, 500)); -DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); -DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); -DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); - -LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"]; -DECL_LLCC(LLSD, test_llsd); - -static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment"); - -void test_cached_control() -{ -#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL - TEST_LLCC(U32, 666); - TEST_LLCC(S32, (S32)-666); - TEST_LLCC(F32, (F32)-666.666); - TEST_LLCC(bool, true); - if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; - TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); - TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); - TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); - TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); - TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); - TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); -//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - - if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; -} -#endif // TEST_CACHED_CONTROL - +/**
+ * @file llcontrol.cpp
+ * @brief Holds global state for viewer.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "llcontrol.h"
+
+#include "llstl.h"
+
+#include "llstring.h"
+#include "v3math.h"
+#include "v3dmath.h"
+#include "v4coloru.h"
+#include "v4color.h"
+#include "v3color.h"
+#include "llquaternion.h"
+#include "llrect.h"
+#include "llxmltree.h"
+#include "llsdserialize.h"
+#include "llfile.h"
+#include "lltimer.h"
+#include "lldir.h"
+
+#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+#define CONTROL_ERRS LL_ERRS("ControlErrors")
+#else
+#define CONTROL_ERRS LL_WARNS("ControlErrors")
+#endif
+
+
+template <> eControlType get_control_type<U32>();
+template <> eControlType get_control_type<S32>();
+template <> eControlType get_control_type<F32>();
+template <> eControlType get_control_type<bool>();
+template <> eControlType get_control_type<std::string>();
+
+template <> eControlType get_control_type<LLVector3>();
+template <> eControlType get_control_type<LLVector3d>();
+template <> eControlType get_control_type<LLRect>();
+template <> eControlType get_control_type<LLColor4>();
+template <> eControlType get_control_type<LLColor3>();
+template <> eControlType get_control_type<LLColor4U>();
+template <> eControlType get_control_type<LLSD>();
+
+template <> LLSD convert_to_llsd<U32>(const U32& in);
+template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
+template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
+template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
+template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
+template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
+template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in);
+
+template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name);
+template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name);
+
+//this defines the current version of the settings file
+const S32 CURRENT_VERSION = 101;
+
+// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate
+// the gSavedSettings profiling code. This code tracks the calls to get a saved (debug) setting.
+// When the viewer exits the results are written to the log directory to the file specified
+// by SETTINGS_PROFILE below. Only settings with an average access rate >= 2/second are output.
+typedef std::pair<std::string, U32> settings_pair_t;
+typedef std::vector<settings_pair_t> settings_vec_t;
+LLSD getCount;
+settings_vec_t getCount_v;
+F64 start_time = 0;
+std::string SETTINGS_PROFILE = "settings_profile.log";
+
+bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
+{
+ bool result = false;
+ switch (mType)
+ {
+ case TYPE_U32:
+ case TYPE_S32:
+ result = a.asInteger() == b.asInteger();
+ break;
+ case TYPE_BOOLEAN:
+ result = a.asBoolean() == b.asBoolean();
+ break;
+ case TYPE_F32:
+ result = a.asReal() == b.asReal();
+ break;
+ case TYPE_VEC3:
+ case TYPE_VEC3D:
+ result = LLVector3d(a) == LLVector3d(b);
+ break;
+ case TYPE_QUAT:
+ result = LLQuaternion(a) == LLQuaternion(b);
+ break;
+ case TYPE_RECT:
+ result = LLRect(a) == LLRect(b);
+ break;
+ case TYPE_COL4:
+ result = LLColor4(a) == LLColor4(b);
+ break;
+ case TYPE_COL3:
+ result = LLColor3(a) == LLColor3(b);
+ break;
+ case TYPE_STRING:
+ result = a.asString() == b.asString();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
+ LLSD initial, const std::string& comment,
+ ePersist persist, bool hidefromsettingseditor)
+ : mName(name),
+ mComment(comment),
+ mType(type),
+ mPersist(persist),
+ mHideFromSettingsEditor(hidefromsettingseditor)
+{
+ if ((persist != PERSIST_NO) && mComment.empty())
+ {
+ LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL;
+ }
+ //Push back versus setValue'ing here, since we don't want to call a signal yet
+ mValues.push_back(initial);
+}
+
+
+
+LLControlVariable::~LLControlVariable()
+{
+}
+
+LLSD LLControlVariable::getComparableValue(const LLSD& value)
+{
+ // *FIX:MEP - The following is needed to make the LLSD::ImplString
+ // work with boolean controls...
+ LLSD storable_value;
+ if(TYPE_BOOLEAN == type() && value.isString())
+ {
+ bool temp;
+ if(LLStringUtil::convertToBOOL(value.asString(), temp))
+ {
+ storable_value = temp;
+ }
+ else
+ {
+ storable_value = false;
+ }
+ }
+ else if (TYPE_LLSD == type() && value.isString())
+ {
+ LLPointer<LLSDNotationParser> parser = new LLSDNotationParser;
+ LLSD result;
+ std::stringstream value_stream(value.asString());
+ if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE)
+ {
+ storable_value = result;
+ }
+ else
+ {
+ storable_value = value;
+ }
+ }
+ else
+ {
+ storable_value = value;
+ }
+
+ return storable_value;
+}
+
+void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
+{
+ if (!mValidateSignal(this, new_value))
+ {
+ // can not set new value, exit
+ return;
+ }
+
+ LLSD storable_value = getComparableValue(new_value);
+ LLSD original_value = getValue();
+ bool value_changed = !llsd_compare(original_value, storable_value);
+ if(saved_value)
+ {
+ // If we're going to save this value, return to default but don't fire
+ resetToDefault(false);
+ if (!llsd_compare(mValues.back(), storable_value))
+ {
+ mValues.push_back(storable_value);
+ }
+ }
+ else
+ {
+ // This is an unsaved value. Its needs to reside at
+ // mValues[2] (or greater). It must not affect
+ // the result of getSaveValue()
+ if (!llsd_compare(mValues.back(), storable_value))
+ {
+ while(mValues.size() > 2)
+ {
+ // Remove any unsaved values.
+ mValues.pop_back();
+ }
+
+ if(mValues.size() < 2)
+ {
+ // Add the default to the 'save' value.
+ mValues.push_back(mValues[0]);
+ }
+
+ // Add the 'un-save' value.
+ mValues.push_back(storable_value);
+ }
+ }
+
+ if(value_changed)
+ {
+ firePropertyChanged(original_value);
+ }
+}
+
+void LLControlVariable::setDefaultValue(const LLSD& value)
+{
+ // Set the control variables value and make it
+ // the default value. If the active value is changed,
+ // send the signal.
+ // *NOTE: Default values are not saved, only read.
+
+ LLSD comparable_value = getComparableValue(value);
+ LLSD original_value = getValue();
+ bool value_changed = !llsd_compare(original_value, comparable_value);
+ resetToDefault(false);
+ mValues[0] = comparable_value;
+ if (value_changed)
+ {
+ firePropertyChanged(original_value);
+ }
+}
+
+void LLControlVariable::setPersist(ePersist state)
+{
+ mPersist = state;
+}
+
+void LLControlVariable::setHiddenFromSettingsEditor(bool hide)
+{
+ mHideFromSettingsEditor = hide;
+}
+
+void LLControlVariable::setComment(const std::string& comment)
+{
+ mComment = comment;
+}
+
+void LLControlVariable::resetToDefault(bool fire_signal)
+{
+ //The first setting is always the default
+ //Pop to it and fire off the listener
+ LLSD originalValue = mValues.back();
+
+ while(mValues.size() > 1)
+ {
+ mValues.pop_back();
+ }
+
+ if(fire_signal)
+ {
+ firePropertyChanged(originalValue);
+ }
+}
+
+bool LLControlVariable::shouldSave(bool nondefault_only)
+{
+ // This method is used to decide whether we should save a given
+ // variable. Two of the three values of mPersist are easy.
+ if (mPersist == PERSIST_NO)
+ return false;
+
+ if (mPersist == PERSIST_ALWAYS)
+ return true;
+
+ // PERSIST_NONDFT
+ // If caller doesn't need us to filter, just save.
+ if (! nondefault_only)
+ return true;
+
+ // PERSIST_NONDFT: caller only wants us to save this variable if its value
+ // differs from default.
+ if (isDefault()) // never been altered
+ return false;
+
+ // We've set at least one other value: compare it to default. Save only if
+ // they differ.
+ return ! llsd_compare(getSaveValue(), getDefault());
+}
+
+LLSD LLControlVariable::getSaveValue() const
+{
+ //The first level of the stack is default
+ //We assume that the second level is user preferences that should be saved
+ if(mValues.size() > 1) return mValues[1];
+ return mValues[0];
+}
+
+LLPointer<LLControlVariable> LLControlGroup::getControl(std::string_view name)
+{
+ if (mSettingsProfile)
+ {
+ incrCount(name);
+ }
+
+ ctrl_name_table_t::iterator iter = mNameTable.find(name.data());
+ return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+// Must match the type definition in llcontrol.h
+const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
+ ,"S32"
+ ,"F32"
+ ,"Boolean"
+ ,"String"
+ ,"Vector3"
+ ,"Vector3D"
+ ,"Quaternion"
+ ,"Rect"
+ ,"Color4"
+ ,"Color3"
+ ,"LLSD"
+ };
+
+LLControlGroup::LLControlGroup(const std::string& name)
+: LLInstanceTracker<LLControlGroup, std::string>(name),
+ mSettingsProfile(false)
+{
+
+ if (NULL != getenv("LL_SETTINGS_PROFILE"))
+ {
+ mSettingsProfile = true;
+ }
+}
+
+LLControlGroup::~LLControlGroup()
+{
+ cleanup();
+}
+
+static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs)
+{
+ return lhs.second > rhs.second;
+};
+
+void LLControlGroup::cleanup()
+{
+ if(mSettingsProfile && getCount.size() != 0)
+ {
+ std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE);
+ LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */
+ if(!out)
+ {
+ LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL;
+ }
+ else
+ {
+ F64 end_time = LLTimer::getTotalSeconds();
+ U32 total_seconds = (U32)(end_time - start_time);
+
+ std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds);
+ std::ostringstream data_msg;
+
+ data_msg << msg;
+ size_t data_size = data_msg.str().size();
+ if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
+ {
+ LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL;
+ }
+
+ for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter)
+ {
+ getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger()));
+ }
+ sort(getCount_v.begin(), getCount_v.end(), compareRoutine);
+
+ for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter)
+ {
+ U32 access_rate = 0;
+ if (total_seconds != 0)
+ {
+ access_rate = iter->second / total_seconds;
+ }
+ if (access_rate >= 2)
+ {
+ std::ostringstream data_msg;
+ msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str());
+ data_msg << msg << "\n";
+ size_t data_size = data_msg.str().size();
+ if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
+ {
+ LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL;
+ }
+ }
+ }
+ getCount = LLSD::emptyMap();
+ fclose(out);
+ }
+ }
+
+ mNameTable.clear();
+}
+
+eControlType LLControlGroup::typeStringToEnum(const std::string& typestr)
+{
+ for(int i = 0; i < (int)TYPE_COUNT; ++i)
+ {
+ if(mTypeString[i] == typestr) return (eControlType)i;
+ }
+ return (eControlType)-1;
+}
+
+std::string LLControlGroup::typeEnumToString(eControlType typeenum)
+{
+ return mTypeString[typeenum];
+}
+
+LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor)
+{
+ LLControlVariable* existing_control = getControl(name);
+ if (existing_control)
+ {
+ if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type))
+ {
+ if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val))
+ {
+ // Sometimes we need to declare a control *after* it has been loaded from a settings file.
+ LLSD cur_value = existing_control->getValue(); // get the current value
+ existing_control->setDefaultValue(initial_val); // set the default to the declared value
+ existing_control->setValue(cur_value); // now set to the loaded value
+ }
+ }
+ else
+ {
+ LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL;
+ }
+ return existing_control;
+ }
+
+ // if not, create the control and add it to the name table
+ LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor);
+ mNameTable[name] = control;
+ return control;
+}
+
+LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_S32, initial_val, comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_F32, initial_val, comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const bool initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_STRING, initial_val, comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
+{
+ return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
+{
+ return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
+{
+ return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist);
+}
+
+LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
+{
+ return declareControl(name, TYPE_LLSD, initial_val, comment, persist);
+}
+
+void LLControlGroup::incrCount(std::string_view name)
+{
+ if (0.0 == start_time)
+ {
+ start_time = LLTimer::getTotalSeconds();
+ }
+ getCount[name.data()] = getCount[name.data()].asInteger() + 1;
+}
+
+bool LLControlGroup::getBOOL(std::string_view name)
+{
+ return get<bool>(name);
+}
+
+S32 LLControlGroup::getS32(std::string_view name)
+{
+ return get<S32>(name);
+}
+
+U32 LLControlGroup::getU32(std::string_view name)
+{
+ return get<U32>(name);
+}
+
+F32 LLControlGroup::getF32(std::string_view name)
+{
+ return get<F32>(name);
+}
+
+std::string LLControlGroup::getString(std::string_view name)
+{
+ return get<std::string>(name);
+}
+
+LLWString LLControlGroup::getWString(std::string_view name)
+{
+ return get<LLWString>(name);
+}
+
+std::string LLControlGroup::getText(std::string_view name)
+{
+ std::string utf8_string = getString(name);
+ LLStringUtil::replaceChar(utf8_string, '^', '\n');
+ LLStringUtil::replaceChar(utf8_string, '%', ' ');
+ return (utf8_string);
+}
+
+LLVector3 LLControlGroup::getVector3(std::string_view name)
+{
+ return get<LLVector3>(name);
+}
+
+LLVector3d LLControlGroup::getVector3d(std::string_view name)
+{
+ return get<LLVector3d>(name);
+}
+
+LLQuaternion LLControlGroup::getQuaternion(std::string_view name)
+{
+ return get<LLQuaternion>(name);
+}
+
+LLRect LLControlGroup::getRect(std::string_view name)
+{
+ return get<LLRect>(name);
+}
+
+
+LLColor4 LLControlGroup::getColor(std::string_view name)
+{
+ return get<LLColor4>(name);
+}
+
+LLColor4 LLControlGroup::getColor4(std::string_view name)
+{
+ return get<LLColor4>(name);
+}
+
+LLColor3 LLControlGroup::getColor3(std::string_view name)
+{
+ return get<LLColor3>(name);
+}
+
+LLSD LLControlGroup::getLLSD(std::string_view name)
+{
+ return get<LLSD>(name);
+}
+
+LLSD LLControlGroup::asLLSD(bool diffs_only)
+{
+ // Dump all stored values as LLSD
+ LLSD result = LLSD::emptyArray();
+ for (ctrl_name_table_t::iterator iter = mNameTable.begin();
+ iter != mNameTable.end(); iter++)
+ {
+ LLControlVariable *control = iter->second;
+ if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault()))
+ {
+ continue;
+ }
+ const std::string& name = iter->first;
+ result[name] = getLLSD(name);
+ }
+ return result;
+}
+
+bool LLControlGroup::controlExists(const std::string& name)
+{
+ ctrl_name_table_t::iterator iter = mNameTable.find(name);
+ return iter != mNameTable.end();
+}
+
+
+//-------------------------------------------------------------------
+// Set functions
+//-------------------------------------------------------------------
+
+void LLControlGroup::setBOOL(std::string_view name, bool val)
+{
+ set<bool>(name, val);
+}
+
+
+void LLControlGroup::setS32(std::string_view name, S32 val)
+{
+ set(name, val);
+}
+
+
+void LLControlGroup::setF32(std::string_view name, F32 val)
+{
+ set(name, val);
+}
+
+
+void LLControlGroup::setU32(std::string_view name, U32 val)
+{
+ set(name, val);
+}
+
+
+void LLControlGroup::setString(std::string_view name, const std::string &val)
+{
+ set(name, val);
+}
+
+
+void LLControlGroup::setVector3(std::string_view name, const LLVector3 &val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setVector3d(std::string_view name, const LLVector3d &val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setQuaternion(std::string_view name, const LLQuaternion &val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setRect(std::string_view name, const LLRect &val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setColor4(std::string_view name, const LLColor4 &val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setLLSD(std::string_view name, const LLSD& val)
+{
+ set(name, val);
+}
+
+void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val)
+{
+ if (name.empty())
+ {
+ return;
+ }
+
+ LLControlVariable* control = getControl(name);
+
+ if (control)
+ {
+ control->setValue(val);
+ }
+ else
+ {
+ CONTROL_ERRS << "Invalid control " << name << LL_ENDL;
+ }
+}
+
+
+//---------------------------------------------------------------
+// Load and save
+//---------------------------------------------------------------
+
+// Returns number of controls loaded, so 0 if failure
+U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as)
+{
+ std::string name;
+
+ LLXmlTree xml_controls;
+
+ if (!xml_controls.parseFile(filename))
+ {
+ LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL;
+ return 0;
+ }
+
+ LLXmlTreeNode* rootp = xml_controls.getRoot();
+ if (!rootp || !rootp->hasAttribute("version"))
+ {
+ LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL;
+ return 0;
+ }
+
+ U32 validitems = 0;
+ S32 version;
+
+ rootp->getAttributeS32("version", version);
+
+ // Check file version
+ if (version != CURRENT_VERSION)
+ {
+ LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL;
+ return 0;
+ }
+
+ LLXmlTreeNode* child_nodep = rootp->getFirstChild();
+ while(child_nodep)
+ {
+ name = child_nodep->getName();
+
+ bool declared = controlExists(name);
+
+ if (require_declaration && !declared)
+ {
+ // Declaration required, but this name not declared.
+ // Complain about non-empty names.
+ if (!name.empty())
+ {
+ //read in to end of line
+ LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL;
+ }
+ child_nodep = rootp->getNextChild();
+ continue;
+ }
+
+ // Got an item. Load it up.
+ // If not declared, assume it's a string
+ if (!declared)
+ {
+ switch(declare_as)
+ {
+ case TYPE_COL4:
+ declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO);
+ break;
+ case TYPE_STRING:
+ default:
+ declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO);
+ break;
+ }
+ }
+
+ // Control name has been declared in code.
+ LLControlVariable *control = getControl(name);
+
+ llassert(control);
+
+ switch(control->mType)
+ {
+ case TYPE_F32:
+ {
+ F32 initial = 0.f;
+
+ child_nodep->getAttributeF32("value", initial);
+
+ control->set(initial);
+ validitems++;
+ }
+ break;
+ case TYPE_S32:
+ {
+ S32 initial = 0;
+
+ child_nodep->getAttributeS32("value", initial);
+
+ control->set(initial);
+ validitems++;
+ }
+ break;
+ case TYPE_U32:
+ {
+ U32 initial = 0;
+ child_nodep->getAttributeU32("value", initial);
+ control->set((LLSD::Integer) initial);
+ validitems++;
+ }
+ break;
+ case TYPE_BOOLEAN:
+ {
+ bool initial = false;
+
+ child_nodep->getAttributeBOOL("value", initial);
+ control->set(initial);
+
+ validitems++;
+ }
+ break;
+ case TYPE_STRING:
+ {
+ std::string string;
+ child_nodep->getAttributeString("value", string);
+ control->set(string);
+ validitems++;
+ }
+ break;
+ case TYPE_VEC3:
+ {
+ LLVector3 vector;
+
+ child_nodep->getAttributeVector3("value", vector);
+ control->set(vector.getValue());
+ validitems++;
+ }
+ break;
+ case TYPE_VEC3D:
+ {
+ LLVector3d vector;
+
+ child_nodep->getAttributeVector3d("value", vector);
+
+ control->set(vector.getValue());
+ validitems++;
+ }
+ break;
+ case TYPE_QUAT:
+ {
+ LLQuaternion quat;
+
+ child_nodep->getAttributeQuat("value", quat);
+
+ control->set(quat.getValue());
+ validitems++;
+ }
+ break;
+ case TYPE_RECT:
+ {
+ //RN: hack to support reading rectangles from a string
+ std::string rect_string;
+
+ child_nodep->getAttributeString("value", rect_string);
+ std::istringstream istream(rect_string);
+ S32 left, bottom, width, height;
+
+ istream >> left >> bottom >> width >> height;
+
+ LLRect rect;
+ rect.setOriginAndSize(left, bottom, width, height);
+
+ control->set(rect.getValue());
+ validitems++;
+ }
+ break;
+ case TYPE_COL4:
+ {
+ LLColor4 color;
+
+ child_nodep->getAttributeColor4("value", color);
+ control->set(color.getValue());
+ validitems++;
+ }
+ break;
+ case TYPE_COL3:
+ {
+ LLVector3 color;
+
+ child_nodep->getAttributeVector3("value", color);
+ control->set(LLColor3(color.mV).getValue());
+ validitems++;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+ child_nodep = rootp->getNextChild();
+ }
+
+ return validitems;
+}
+
+U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only)
+{
+ LLSD settings;
+ int num_saved = 0;
+ for (ctrl_name_table_t::iterator iter = mNameTable.begin();
+ iter != mNameTable.end(); iter++)
+ {
+ LLControlVariable* control = iter->second;
+ if (!control)
+ {
+ LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL;
+ }
+ else if( control->shouldSave(nondefault_only) )
+ {
+ settings[iter->first]["Type"] = typeEnumToString(control->type());
+ settings[iter->first]["Comment"] = control->getComment();
+ settings[iter->first]["Value"] = control->getSaveValue();
+ ++num_saved;
+ }
+ }
+ llofstream file;
+ file.open(filename.c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::toPrettyXML(settings, file);
+ file.close();
+ LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL;
+ }
+ else
+ {
+ // This is a warning because sometime we want to use settings files which can't be written...
+ LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL;
+ return 0;
+ }
+ return num_saved;
+}
+
+U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
+{
+ LLSD settings;
+ llifstream infile;
+ infile.open(filename.c_str());
+ if(!infile.is_open())
+ {
+ LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL;
+ return 0;
+ }
+
+ if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
+ {
+ infile.close();
+ LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL;
+ return loadFromFileLegacy(filename, true, TYPE_STRING);
+ }
+
+ U32 validitems = 0;
+ bool hidefromsettingseditor = false;
+
+ for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
+ {
+ LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT;
+ std::string const & name = itr->first;
+ LLSD const & control_map = itr->second;
+
+ if(control_map.has("Persist"))
+ {
+ persist = control_map["Persist"].asInteger()?
+ LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO;
+ }
+
+ // Sometimes we want to use the settings system to provide cheap persistence, but we
+ // don't want the settings themselves to be easily manipulated in the UI because
+ // doing so can cause support problems. So we have this option:
+ if(control_map.has("HideFromEditor"))
+ {
+ hidefromsettingseditor = control_map["HideFromEditor"].asInteger();
+ }
+ else
+ {
+ hidefromsettingseditor = false;
+ }
+
+ // If the control exists just set the value from the input file.
+ LLControlVariable* existing_control = getControl(name);
+ if(existing_control)
+ {
+ // set_default_values is true when we're loading the initial,
+ // immutable files from app_settings, e.g. settings.xml.
+ if(set_default_values)
+ {
+ // Override all previously set properties of this control.
+ // ... except for type. The types must match.
+ eControlType new_type = typeStringToEnum(control_map["Type"].asString());
+ if(existing_control->isType(new_type))
+ {
+ existing_control->setDefaultValue(control_map["Value"]);
+ existing_control->setPersist(persist);
+ existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor);
+ existing_control->setComment(control_map["Comment"].asString());
+ }
+ else
+ {
+ LL_ERRS() << "Mismatched type of control variable '"
+ << name << "' found while loading '"
+ << filename << "'." << LL_ENDL;
+ }
+ }
+ else if(existing_control->isPersisted())
+ {
+ // save_values is specifically false for (e.g.)
+ // SessionSettingsFile and UserSessionSettingsFile -- in other
+ // words, for a file that's supposed to be transient.
+ existing_control->setValue(control_map["Value"], save_values);
+ }
+ // *NOTE: If not persisted and not setting defaults,
+ // the value should not get loaded.
+ }
+ else
+ {
+ // We've never seen this control before. Either we're loading up
+ // the initial set of default settings files (set_default_values)
+ // -- or we're loading user settings last saved by a viewer that
+ // supports a superset of the variables we know.
+ // CHOP-962: if we're loading an unrecognized user setting, make
+ // sure we save it later. If you try an experimental viewer, tweak
+ // a new setting, briefly revert to an old viewer, then return to
+ // the new one, we don't want the old viewer to discard the
+ // setting you changed.
+ if (! set_default_values)
+ {
+ // Using PERSIST_ALWAYS insists that saveToFile() (which calls
+ // LLControlVariable::shouldSave()) must save this control
+ // variable regardless of its value. We can safely set this
+ // LLControlVariable persistent because the 'persistent' flag
+ // is not itself persisted!
+ persist = LLControlVariable::PERSIST_ALWAYS;
+ // We want to mention unrecognized user settings variables
+ // (e.g. from a newer version of the viewer) in the log. But
+ // we also arrive here for Boolean variables generated by
+ // the notifications subsystem when the user checks "Don't
+ // show me this again." These aren't declared in settings.xml;
+ // they're actually named for the notification they suppress.
+ // We don't want to mention those. Apologies, this is a bit of
+ // a hack: we happen to know that user settings go into an
+ // LLControlGroup whose name is "Global".
+ if (getKey() == "Global")
+ {
+ LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey()
+ << " settings variable " << name << LL_ENDL;
+ }
+ }
+
+ declareControl(name,
+ typeStringToEnum(control_map["Type"].asString()),
+ control_map["Value"],
+ control_map["Comment"].asString(),
+ persist,
+ hidefromsettingseditor
+ );
+ }
+
+ ++validitems;
+ }
+
+ LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL;
+ return validitems;
+}
+
+void LLControlGroup::resetToDefaults()
+{
+ ctrl_name_table_t::iterator control_iter;
+ for (control_iter = mNameTable.begin();
+ control_iter != mNameTable.end();
+ ++control_iter)
+ {
+ LLControlVariable* control = (*control_iter).second;
+ control->resetToDefault();
+ }
+}
+
+void LLControlGroup::applyToAll(ApplyFunctor* func)
+{
+ for (ctrl_name_table_t::iterator iter = mNameTable.begin();
+ iter != mNameTable.end(); iter++)
+ {
+ func->apply(iter->first, iter->second);
+ }
+}
+
+//============================================================================
+
+#ifdef TEST_HARNESS
+void main()
+{
+ F32_CONTROL foo, getfoo;
+
+ S32_CONTROL bar, getbar;
+
+ BOOL_CONTROL baz;
+
+ U32 count = gGlobals.loadFromFile("controls.ini");
+ LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL;
+
+ // test insertion
+ foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
+ gGlobals.addEntry("gFoo", foo);
+
+ bar = new LLControlVariable<S32>("gBar", 10, 2, 22);
+ gGlobals.addEntry("gBar", bar);
+
+ baz = new LLControlVariable<bool>("gBaz", false);
+ gGlobals.addEntry("gBaz", baz);
+
+ // test retrieval
+ getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo");
+ getfoo->dump();
+
+ getbar = (S32_CONTROL) gGlobals.resolveName("gBar");
+ getbar->dump();
+
+ // change data
+ getfoo->set(10.f);
+ getfoo->dump();
+
+ // Failure modes
+
+ // ...min > max
+ // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f);
+
+ // ...initial > max
+ // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000);
+
+ // ...misspelled name
+ // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled");
+ // getfoo->dump();
+
+ // ...invalid data type
+ getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo");
+ getfoo->set(true);
+ getfoo->dump();
+
+ // ...out of range data
+ // getfoo->set(100000000.f);
+ // getfoo->dump();
+
+ // Clean Up
+ delete foo;
+ delete bar;
+ delete baz;
+}
+#endif
+
+
+template <> eControlType get_control_type<U32>()
+{
+ return TYPE_U32;
+}
+
+template <> eControlType get_control_type<S32>()
+{
+ return TYPE_S32;
+}
+
+template <> eControlType get_control_type<F32>()
+{
+ return TYPE_F32;
+}
+
+template <> eControlType get_control_type<bool> ()
+{
+ return TYPE_BOOLEAN;
+}
+
+template <> eControlType get_control_type<std::string>()
+{
+ return TYPE_STRING;
+}
+
+template <> eControlType get_control_type<LLVector3>()
+{
+ return TYPE_VEC3;
+}
+
+template <> eControlType get_control_type<LLVector3d>()
+{
+ return TYPE_VEC3D;
+}
+
+template <> eControlType get_control_type<LLQuaternion>()
+{
+ return TYPE_QUAT;
+}
+
+template <> eControlType get_control_type<LLRect>()
+{
+ return TYPE_RECT;
+}
+
+template <> eControlType get_control_type<LLColor4>()
+{
+ return TYPE_COL4;
+}
+
+template <> eControlType get_control_type<LLColor3>()
+{
+ return TYPE_COL3;
+}
+
+template <> eControlType get_control_type<LLSD>()
+{
+ return TYPE_LLSD;
+}
+
+
+template <> LLSD convert_to_llsd<U32>(const U32& in)
+{
+ return (LLSD::Integer)in;
+}
+
+template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in)
+{
+ return in.getValue();
+}
+
+template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)
+{
+ return in.getValue();
+}
+template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in)
+{
+ return in.getValue();
+}
+
+template <> LLSD convert_to_llsd<LLRect>(const LLRect& in)
+{
+ return in.getValue();
+}
+
+template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in)
+{
+ return in.getValue();
+}
+
+template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in)
+{
+ return in.getValue();
+}
+
+template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in)
+{
+ return in.getValue();
+}
+
+
+template<>
+bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_BOOLEAN)
+ return sd.asBoolean();
+ else
+ {
+ CONTROL_ERRS << "Invalid bool value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return false;
+ }
+}
+
+template<>
+S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_S32)
+ return sd.asInteger();
+ else
+ {
+ CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return 0;
+ }
+}
+
+template<>
+U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_U32)
+ return sd.asInteger();
+ else
+ {
+ CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return 0;
+ }
+}
+
+template<>
+F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_F32)
+ return (F32) sd.asReal();
+ else
+ {
+ CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return 0.0f;
+ }
+}
+
+template<>
+std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_STRING)
+ return sd.asString();
+ else
+ {
+ CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLStringUtil::null;
+ }
+}
+
+template<>
+LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name));
+}
+
+template<>
+LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_VEC3)
+ return (LLVector3)sd;
+ else
+ {
+ CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLVector3::zero;
+ }
+}
+
+template<>
+LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_VEC3D)
+ return (LLVector3d)sd;
+ else
+ {
+ CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLVector3d::zero;
+ }
+}
+
+template<>
+LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_QUAT)
+ return (LLQuaternion)sd;
+ else
+ {
+ CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLQuaternion();
+ }
+}
+
+template<>
+LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_RECT)
+ return LLRect(sd);
+ else
+ {
+ CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLRect::null;
+ }
+}
+
+
+template<>
+LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_COL4)
+ {
+ LLColor4 color(sd);
+ if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
+ {
+ LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL;
+ }
+ else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
+ {
+ LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL;
+ }
+ else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
+ {
+ LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL;
+ }
+ else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
+ {
+ LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL;
+ }
+
+ return LLColor4(sd);
+ }
+ else
+ {
+ CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL;
+ return LLColor4::white;
+ }
+}
+
+template<>
+LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ if (type == TYPE_COL3)
+ return sd;
+ else
+ {
+ CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
+ return LLColor3::white;
+ }
+}
+
+template<>
+LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name)
+{
+ return sd;
+}
+
+
+#if TEST_CACHED_CONTROL
+
+#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V)
+DECL_LLCC(U32, (U32)666);
+DECL_LLCC(S32, (S32)-666);
+DECL_LLCC(F32, (F32)-666.666);
+DECL_LLCC(bool, true);
+static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value");
+DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
+DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
+DECL_LLCC(LLRect, LLRect(0, 0, 100, 500));
+DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
+DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
+DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
+
+LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
+DECL_LLCC(LLSD, test_llsd);
+
+void test_cached_control()
+{
+#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL
+ TEST_LLCC(U32, 666);
+ TEST_LLCC(S32, (S32)-666);
+ TEST_LLCC(F32, (F32)-666.666);
+ TEST_LLCC(bool, true);
+ if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL;
+ TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
+ TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
+ TEST_LLCC(LLRect, LLRect(0, 0, 100, 500));
+ TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
+ TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
+ TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
+//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);
+}
+#endif // TEST_CACHED_CONTROL
+
|