diff options
author | Steven Bennetts <steve@lindenlab.com> | 2009-05-08 07:43:08 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2009-05-08 07:43:08 +0000 |
commit | a4000c3744e42fcbb638e742f3b63fa31a0dee15 (patch) | |
tree | 7f472c30e65bbfa04ee9bc06631a1af305cc31fb /indra/llxml | |
parent | 6c4cadbb04d633ad7b762058bdeba6e1f650dafd (diff) |
merge trunk@116587 skinning-7@119389 -> viewer-2.0.0-skinning-7
Diffstat (limited to 'indra/llxml')
-rw-r--r-- | indra/llxml/CMakeLists.txt | 3 | ||||
-rw-r--r-- | indra/llxml/llcontrol.cpp | 724 | ||||
-rw-r--r-- | indra/llxml/llcontrol.h | 286 | ||||
-rw-r--r-- | indra/llxml/llcontrolgroupreader.h | 73 | ||||
-rw-r--r-- | indra/llxml/llxmlnode.cpp | 148 | ||||
-rw-r--r-- | indra/llxml/llxmlnode.h | 30 |
6 files changed, 828 insertions, 436 deletions
diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index dc7787beea..b1ac85812c 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -5,11 +5,13 @@ project(llxml) include(00-Common) include(LLCommon) include(LLMath) +include(LLVFS) include(LLXML) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} ) set(llxml_SOURCE_FILES @@ -38,6 +40,7 @@ add_library (llxml ${llxml_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries( llxml + llvfs llmath ${BOOST_SIGNALS_LIBRARY} ${EXPAT_LIBRARIES} diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index d9ed45ab9d..2271c02cd0 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -56,6 +56,45 @@ #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>(); +// Yay BOOL, its really an S32. +//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, const std::string& control_name); +template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name); +template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name); + //this defines the current version of the settings file const S32 CURRENT_VERSION = 101; @@ -87,9 +126,6 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) case TYPE_COL3: result = LLColor3(a) == LLColor3(b); break; - case TYPE_COL4U: - result = LLColor4U(a) == LLColor4U(b); - break; case TYPE_STRING: result = a.asString() == b.asString(); break; @@ -148,9 +184,15 @@ LLSD LLControlVariable::getComparableValue(const LLSD& value) return storable_value; } -void LLControlVariable::setValue(const LLSD& value, bool saved_value) +void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) { - LLSD storable_value = getComparableValue(value); + if (mValidateSignal(this, new_value) == false) + { + // can not set new value, exit + return; + } + + LLSD storable_value = getComparableValue(new_value); bool value_changed = llsd_compare(getValue(), storable_value) == FALSE; if(saved_value) { @@ -163,7 +205,7 @@ void LLControlVariable::setValue(const LLSD& value, bool saved_value) } else { - // This is a unsaved value. Its needs to reside at + // 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) == FALSE) @@ -185,10 +227,9 @@ void LLControlVariable::setValue(const LLSD& value, bool saved_value) } } - if(value_changed) { - mSignal(storable_value); + mCommitSignal(this, storable_value); } } @@ -262,7 +303,8 @@ LLPointer<LLControlVariable> LLControlGroup::getControl(const std::string& name) //////////////////////////////////////////////////////////////////////////// -LLControlGroup::LLControlGroup() +LLControlGroup::LLControlGroup(const std::string& name) +: LLInstanceTracker<LLControlGroup, std::string>(name) { mTypeString[TYPE_U32] = "U32"; mTypeString[TYPE_S32] = "S32"; @@ -274,7 +316,6 @@ LLControlGroup::LLControlGroup() mTypeString[TYPE_RECT] = "Rect"; mTypeString[TYPE_COL4] = "Color4"; mTypeString[TYPE_COL3] = "Color3"; - mTypeString[TYPE_COL4U] = "Color4u"; mTypeString[TYPE_LLSD] = "LLSD"; } @@ -309,10 +350,13 @@ BOOL LLControlGroup::declareControl(const std::string& name, eControlType type, { if (persist && existing_control->isType(type)) { - // 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 + 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 { @@ -367,11 +411,6 @@ BOOL LLControlGroup::declareRect(const std::string& name, const LLRect &initial_ return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); } -BOOL LLControlGroup::declareColor4U(const std::string& name, const LLColor4U &initial_val, const std::string& comment, BOOL persist ) -{ - return declareControl(name, TYPE_COL4U, initial_val.getValue(), comment, persist); -} - BOOL LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, BOOL persist ) { return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); @@ -389,81 +428,32 @@ BOOL LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_va BOOL LLControlGroup::getBOOL(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_BOOLEAN)) - return control->get().asBoolean(); - else - { - CONTROL_ERRS << "Invalid BOOL control " << name << llendl; - return FALSE; - } + return (BOOL)get<bool>(name); } S32 LLControlGroup::getS32(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_S32)) - return control->get().asInteger(); - else - { - CONTROL_ERRS << "Invalid S32 control " << name << llendl; - return 0; - } + return get<S32>(name); } U32 LLControlGroup::getU32(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_U32)) - return control->get().asInteger(); - else - { - CONTROL_ERRS << "Invalid U32 control " << name << llendl; - return 0; - } + return get<U32>(name); } F32 LLControlGroup::getF32(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_F32)) - return (F32) control->get().asReal(); - else - { - CONTROL_ERRS << "Invalid F32 control " << name << llendl; - return 0.0f; - } -} - -std::string LLControlGroup::findString(const std::string& name) -{ - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_STRING)) - return control->get().asString(); - return LLStringUtil::null; + return get<F32>(name); } std::string LLControlGroup::getString(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_STRING)) - return control->get().asString(); - else - { - CONTROL_ERRS << "Invalid string control " << name << llendl; - return LLStringUtil::null; - } + return get<std::string>(name); } LLWString LLControlGroup::getWString(const std::string& name) { - return utf8str_to_wstring(getString(name)); + return get<LLWString>(name); } std::string LLControlGroup::getText(const std::string& name) @@ -476,123 +466,38 @@ std::string LLControlGroup::getText(const std::string& name) LLVector3 LLControlGroup::getVector3(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_VEC3)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid LLVector3 control " << name << llendl; - return LLVector3::zero; - } + return get<LLVector3>(name); } LLVector3d LLControlGroup::getVector3d(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_VEC3D)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid LLVector3d control " << name << llendl; - return LLVector3d::zero; - } + return get<LLVector3d>(name); } LLRect LLControlGroup::getRect(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_RECT)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid rect control " << name << llendl; - return LLRect::null; - } + return get<LLRect>(name); } LLColor4 LLControlGroup::getColor(const std::string& name) { - ctrl_name_table_t::const_iterator i = mNameTable.find(name); - - if (i != mNameTable.end()) - { - LLControlVariable* control = i->second; - - switch(control->mType) - { - case TYPE_COL4: - { - return LLColor4(control->get()); - } - case TYPE_COL4U: - { - return LLColor4(LLColor4U(control->get())); - } - default: - { - CONTROL_ERRS << "Control " << name << " not a color" << llendl; - return LLColor4::white; - } - } - } - else - { - CONTROL_ERRS << "Invalid getColor control " << name << llendl; - return LLColor4::white; - } -} - -LLColor4U LLControlGroup::getColor4U(const std::string& name) -{ - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_COL4U)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl; - return LLColor4U::white; - } + return get<LLColor4>(name); } LLColor4 LLControlGroup::getColor4(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_COL4)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl; - return LLColor4::white; - } + return get<LLColor4>(name); } LLColor3 LLControlGroup::getColor3(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_COL3)) - return control->get(); - else - { - CONTROL_ERRS << "Invalid LLColor3 control " << name << llendl; - return LLColor3::white; - } + return get<LLColor3>(name); } LLSD LLControlGroup::getLLSD(const std::string& name) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_LLSD)) - return control->getValue(); - CONTROL_ERRS << "Invalid LLSD control " << name << llendl; - return LLSD(); + return get<LLSD>(name); } BOOL LLControlGroup::controlExists(const std::string& name) @@ -601,170 +506,67 @@ BOOL LLControlGroup::controlExists(const std::string& name) return iter != mNameTable.end(); } + //------------------------------------------------------------------- // Set functions //------------------------------------------------------------------- void LLControlGroup::setBOOL(const std::string& name, BOOL val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_BOOLEAN)) - { - control->set(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set<bool>(name, val); } void LLControlGroup::setS32(const std::string& name, S32 val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_S32)) - { - control->set(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setF32(const std::string& name, F32 val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_F32)) - { - control->set(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setU32(const std::string& name, U32 val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_U32)) - { - control->set((LLSD::Integer) val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setString(const std::string& name, const std::string &val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_STRING)) - { - control->set(val); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setVector3(const std::string& name, const LLVector3 &val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_VEC3)) - { - control->set(val.getValue()); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_VEC3D)) - { - control->set(val.getValue()); - } - else - { - CONTROL_ERRS << "Invalid control " << name << llendl; - } + set(name, val); } void LLControlGroup::setRect(const std::string& name, const LLRect &val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_RECT)) - { - control->set(val.getValue()); - } - else - { - CONTROL_ERRS << "Invalid rect control " << name << llendl; - } -} - -void LLControlGroup::setColor4U(const std::string& name, const LLColor4U &val) -{ - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_COL4U)) - { - control->set(val.getValue()); - } - else - { - CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl; - } + set(name, val); } void LLControlGroup::setColor4(const std::string& name, const LLColor4 &val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_COL4)) - { - control->set(val.getValue()); - } - else - { - CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl; - } + set(name, val); } void LLControlGroup::setLLSD(const std::string& name, const LLSD& val) { - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_LLSD)) - { - setValue(name, val); - } - else - { - CONTROL_ERRS << "Invalid LLSD control " << name << llendl; - } + set(name, val); } -void LLControlGroup::setValue(const std::string& name, const LLSD& val) +void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val) { if (name.empty()) { @@ -775,7 +577,7 @@ void LLControlGroup::setValue(const std::string& name, const LLSD& val) if (control) { - control->set(val); + control->setValue(val); } else { @@ -783,6 +585,7 @@ void LLControlGroup::setValue(const std::string& name, const LLSD& val) } } + //--------------------------------------------------------------- // Load and save //--------------------------------------------------------------- @@ -851,9 +654,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require case TYPE_COL4: declareColor4(name, LLColor4::white, LLStringUtil::null, NO_PERSIST); break; - case TYPE_COL4U: - declareColor4U(name, LLColor4U::white, LLStringUtil::null, NO_PERSIST); - break; case TYPE_STRING: default: declareString(name, LLStringUtil::null, LLStringUtil::null, NO_PERSIST); @@ -951,15 +751,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require validitems++; } break; - case TYPE_COL4U: - { - LLColor4U color; - - child_nodep->getAttributeColor4U("value", color); - control->set(color.getValue()); - validitems++; - } - break; case TYPE_COL4: { LLColor4 color; @@ -1059,10 +850,11 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v } U32 validitems = 0; - bool persist = true; bool hidefromsettingseditor = false; + for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) { + bool persist = true; name = (*itr).first; control_map = (*itr).second; @@ -1153,55 +945,6 @@ void LLControlGroup::applyToAll(ApplyFunctor* func) } //============================================================================ -// First-use - -static std::string get_warn_name(const std::string& name) -{ - std::string warnname = "Warn" + name; - for (std::string::iterator iter = warnname.begin(); iter != warnname.end(); ++iter) - { - char c = *iter; - if (!isalnum(c)) - { - *iter = '_'; - } - } - return warnname; -} - -void LLControlGroup::addWarning(const std::string& name) -{ - std::string warnname = get_warn_name(name); - if(mNameTable.find(warnname) == mNameTable.end()) - { - std::string comment = std::string("Enables ") + name + std::string(" warning dialog"); - declareBOOL(warnname, TRUE, comment); - mWarnings.insert(warnname); - } -} - -BOOL LLControlGroup::getWarning(const std::string& name) -{ - std::string warnname = get_warn_name(name); - return getBOOL(warnname); -} - -void LLControlGroup::setWarning(const std::string& name, BOOL val) -{ - std::string warnname = get_warn_name(name); - setBOOL(warnname, val); -} - -void LLControlGroup::resetWarnings() -{ - for (std::set<std::string>::iterator iter = mWarnings.begin(); - iter != mWarnings.end(); ++iter) - { - setBOOL(*iter, TRUE); - } -} - -//============================================================================ #ifdef TEST_HARNESS void main() @@ -1265,4 +1008,297 @@ void main() #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; +} +/* +// Yay BOOL, its really an S32. +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<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<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, const std::string& control_name) +{ + if (type == TYPE_BOOLEAN) + return sd.asBoolean(); + else + { + CONTROL_ERRS << "Invalid BOOL value" << llendl; + return FALSE; + } +} + +template<> +S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_S32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid S32 value" << llendl; + return 0; + } +} + +template<> +U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_U32) + return sd.asInteger(); + else + { + CONTROL_ERRS << "Invalid U32 value" << llendl; + return 0; + } +} + +template<> +F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_F32) + return (F32) sd.asReal(); + else + { + CONTROL_ERRS << "Invalid F32 value" << llendl; + return 0.0f; + } +} + +template<> +std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_STRING) + return sd.asString(); + else + { + CONTROL_ERRS << "Invalid string value" << llendl; + return LLStringUtil::null; + } +} + +template<> +LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& 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, const std::string& control_name) +{ + if (type == TYPE_VEC3) + return sd; + else + { + CONTROL_ERRS << "Invalid LLVector3 value" << llendl; + return LLVector3::zero; + } +} + +template<> +LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_VEC3D) + return sd; + else + { + CONTROL_ERRS << "Invalid LLVector3d value" << llendl; + return LLVector3d::zero; + } +} + +template<> +LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_RECT) + return sd; + else + { + CONTROL_ERRS << "Invalid rect value" << llendl; + return LLRect::null; + } +} + + +template<> +LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_COL4) + { + LLColor4 color(sd); + if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) + { + llwarns << "Color " << control_name << " value out of range " << llendl; + } + else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) + { + llwarns << "Color " << control_name << " value out of range " << llendl; + } + else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) + { + llwarns << "Color " << control_name << " value out of range " << llendl; + } + else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) + { + llwarns << "Color " << control_name << " value out of range " << llendl; + } + + return LLColor4(sd); + } + else + { + CONTROL_ERRS << "Control " << control_name << " not a color" << llendl; + return LLColor4::white; + } +} + +template<> +LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name) +{ + if (type == TYPE_COL3) + return sd; + else + { + CONTROL_ERRS << "Invalid LLColor3 value" << llendl; + return LLColor3::white; + } +} + +template<> +LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& 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); +DECL_LLCC(BOOL, FALSE); +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) llerrs << "Fail "#T << llendl + TEST_LLCC(U32, 666); + TEST_LLCC(S32, (S32)-666); + TEST_LLCC(F32, (F32)-666.666); + TEST_LLCC(bool, true); + TEST_LLCC(BOOL, FALSE); + if((std::string)mySetting_string != "Default String Value") llerrs << "Fail string" << llendl; + 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") llerrs << "Fail BrowserHomePage" << llendl; +} +#endif // TEST_CACHED_CONTROL diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index ba0a1c7cbf..1782c20a7e 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -33,11 +33,14 @@ #ifndef LL_LLCONTROL_H #define LL_LLCONTROL_H +#include "llboost.h" #include "llevent.h" #include "llnametable.h" #include "llmap.h" #include "llstring.h" #include "llrect.h" +#include "llrefcount.h" +#include "llinstancetracker.h" #include "llcontrolgroupreader.h" @@ -65,7 +68,6 @@ class LLVector3; class LLVector3d; class LLColor4; class LLColor3; -class LLColor4U; const BOOL NO_PERSIST = FALSE; @@ -81,15 +83,17 @@ typedef enum e_control_type TYPE_RECT, TYPE_COL4, TYPE_COL3, - TYPE_COL4U, TYPE_LLSD, TYPE_COUNT } eControlType; -class LLControlVariable : public LLRefCount +class LLControlVariable : public LLRefCount, boost::noncopyable { friend class LLControlGroup; - typedef boost::signal<void(const LLSD&)> signal_t; + +public: + typedef boost::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t; + typedef boost::signal<void(LLControlVariable* control, const LLSD&)> commit_signal_t; private: std::string mName; @@ -99,7 +103,8 @@ private: bool mHideFromSettingsEditor; std::vector<LLSD> mValues; - signal_t mSignal; + commit_signal_t mCommitSignal; + validate_signal_t mValidateSignal; public: LLControlVariable(const std::string& name, eControlType type, @@ -116,7 +121,9 @@ public: void resetToDefault(bool fire_signal = false); - signal_t* getSignal() { return &mSignal; } + commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal + commit_signal_t* getCommitSignal() { return &mCommitSignal; } + validate_signal_t* getValidateSignal() { return &mValidateSignal; } bool isDefault() { return (mValues.size() == 1); } bool isSaveValueDefault(); @@ -136,31 +143,55 @@ public: void firePropertyChanged() { - mSignal(mValues.back()); + mCommitSignal(this, mValues.back()); } private: LLSD getComparableValue(const LLSD& value); bool llsd_compare(const LLSD& a, const LLSD & b); - }; +typedef LLPointer<LLControlVariable> LLControlVariablePtr; + +//! Helper functions for converting between static types and LLControl values +template <class T> +eControlType get_control_type() +{ + llwarns << "Usupported control type: " << typeid(T).name() << "." << llendl; + return TYPE_COUNT; +} + +template <class T> +LLSD convert_to_llsd(const T& in) +{ + // default implementation + return LLSD(in); +} + +template <class T> +T convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name) +{ + // needs specialization + return T(sd); +} + //const U32 STRING_CACHE_SIZE = 10000; -class LLControlGroup : public LLControlGroupReader +class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string> { protected: - typedef std::map<std::string, LLPointer<LLControlVariable> > ctrl_name_table_t; + typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t; ctrl_name_table_t mNameTable; - std::set<std::string> mWarnings; std::string mTypeString[TYPE_COUNT]; eControlType typeStringToEnum(const std::string& typestr); std::string typeEnumToString(eControlType typeenum); public: - LLControlGroup(); + LLControlGroup(const std::string& name); ~LLControlGroup(); void cleanup(); - LLPointer<LLControlVariable> getControl(const std::string& name); + typedef LLInstanceTracker<LLControlGroup, std::string>::instance_iter instance_iter; + + LLControlVariablePtr getControl(const std::string& name); struct ApplyFunctor { @@ -178,33 +209,47 @@ public: BOOL declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, BOOL persist = TRUE); BOOL declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, BOOL persist = TRUE); BOOL declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, BOOL persist = TRUE); - BOOL declareColor4U(const std::string& name, const LLColor4U &initial_val, const std::string& comment, BOOL persist = TRUE); BOOL declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, BOOL persist = TRUE); BOOL declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, BOOL persist = TRUE); BOOL declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, BOOL persist = TRUE); - - std::string findString(const std::string& name); - std::string getString(const std::string& name); - LLWString getWString(const std::string& name); - std::string getText(const std::string& name); - LLVector3 getVector3(const std::string& name); - LLVector3d getVector3d(const std::string& name); - LLRect getRect(const std::string& name); + std::string getString(const std::string& name); + std::string getText(const std::string& name); BOOL getBOOL(const std::string& name); S32 getS32(const std::string& name); F32 getF32(const std::string& name); U32 getU32(const std::string& name); + + LLWString getWString(const std::string& name); + LLVector3 getVector3(const std::string& name); + LLVector3d getVector3d(const std::string& name); + LLRect getRect(const std::string& name); LLSD getLLSD(const std::string& name); - // Note: If an LLColor4U control exists, it will cast it to the correct - // LLColor4 for you. LLColor4 getColor(const std::string& name); - LLColor4U getColor4U(const std::string& name); LLColor4 getColor4(const std::string& name); LLColor3 getColor3(const std::string& name); + // generic getter + template<typename T> T get(const std::string& name) + { + LLControlVariable* control = getControl(name); + LLSD value; + eControlType type = TYPE_COUNT; + + if (control) + { + value = control->get(); + type = control->type(); + } + else + { + llwarns << "Control " << name << " not found." << llendl; + } + return convert_from_llsd<T>(value, type, name); + } + void setBOOL(const std::string& name, BOOL val); void setS32(const std::string& name, S32 val); void setF32(const std::string& name, F32 val); @@ -213,12 +258,26 @@ public: void setVector3(const std::string& name, const LLVector3 &val); void setVector3d(const std::string& name, const LLVector3d &val); void setRect(const std::string& name, const LLRect &val); - void setColor4U(const std::string& name, const LLColor4U &val); void setColor4(const std::string& name, const LLColor4 &val); - void setColor3(const std::string& name, const LLColor3 &val); void setLLSD(const std::string& name, const LLSD& val); - void setValue(const std::string& name, const LLSD& val); + + // type agnostic setter that takes LLSD + void setUntypedValue(const std::string& name, const LLSD& val); + + // generic setter + template<typename T> void set(const std::string& name, const T& val) + { + LLControlVariable* control = getControl(name); + if (control && control->isType(get_control_type<T>())) + { + control->set(convert_to_llsd(val)); + } + else + { + llwarns << "Invalid control " << name << llendl; + } + } BOOL controlExists(const std::string& name); @@ -229,17 +288,170 @@ public: U32 saveToFile(const std::string& filename, BOOL nondefault_only); U32 loadFromFile(const std::string& filename, bool default_values = false); void resetToDefaults(); +}; + +//! Publish/Subscribe object to interact with LLControlGroups. + +//! Use an LLCachedControl instance to connect to a LLControlVariable +//! without have to manually create and bind a listener to a local +//! object. +template <class T> +class LLControlCache : public LLRefCount, public LLInstanceTracker<LLControlCache<T>, std::string> +{ +public: + // This constructor will declare a control if it doesn't exist in the contol group + LLControlCache(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + : LLInstanceTracker<LLControlCache<T>, std::string >(name) + { + if(!group.controlExists(name)) + { + if(!declareTypedControl(group, name, default_value, comment)) + { + llerrs << "The control could not be created!!!" << llendl; + } + } + + bindToControl(group, name); + } + + LLControlCache(LLControlGroup& group, + const std::string& name) + : LLInstanceTracker<LLControlCache<T>, std::string >(name) + { + if(!group.controlExists(name)) + { + llerrs << "Control named " << name << "not found." << llendl; + } + + bindToControl(group, name); + } + + ~LLControlCache() + { + if(mConnection.connected()) + { + mConnection.disconnect(); + } + } + + const T& getValue() const { return mCachedValue; } - // Ignorable Warnings - - // Add a config variable to be reset on resetWarnings() - void addWarning(const std::string& name); - BOOL getWarning(const std::string& name); - void setWarning(const std::string& name, BOOL val); - - // Resets all ignorables - void resetWarnings(); +private: + void bindToControl(LLControlGroup& group, const std::string& name) + { + LLControlVariablePtr controlp = group.getControl(name); + mType = controlp->type(); + mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name); + + // Add a listener to the controls signal... + mConnection = controlp->getSignal()->connect( + boost::bind(&LLControlCache<T>::handleValueChange, this, _2) + ); + mType = controlp->type(); + } + bool declareTypedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment) + { + LLSD init_value; + eControlType type = get_control_type<T>(); + init_value = convert_to_llsd(default_value); + if(type < TYPE_COUNT) + { + group.declareControl(name, type, init_value, comment, FALSE); + return true; + } + return false; + } + + bool handleValueChange(const LLSD& newvalue) + { + mCachedValue = convert_from_llsd<T>(newvalue, mType, ""); + return true; + } + +private: + T mCachedValue; + eControlType mType; + boost::signals::connection mConnection; +}; + +template <typename T> +class LLCachedControl +{ +public: + LLCachedControl(LLControlGroup& group, + const std::string& name, + const T& default_value, + const std::string& comment = "Declared In Code") + { + mCachedControlPtr = LLControlCache<T>::getInstance(name); + if (mCachedControlPtr.isNull()) + { + mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment); + } + } + + LLCachedControl(LLControlGroup& group, + const std::string& name) + { + mCachedControlPtr = LLControlCache<T>::getInstance(name); + if (mCachedControlPtr.isNull()) + { + mCachedControlPtr = new LLControlCache<T>(group, name); + } + } + + operator const T&() const { return mCachedControlPtr->getValue(); } + operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); } + const T& operator()() { return mCachedControlPtr->getValue(); } + +private: + LLPointer<LLControlCache<T> > mCachedControlPtr; }; +template <> eControlType get_control_type<U32>(); +template <> eControlType get_control_type<S32>(); +template <> eControlType get_control_type<F32>(); +template <> eControlType get_control_type<bool>(); +// Yay BOOL, its really an S32. +//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<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<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name); +template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name); + +//#define TEST_CACHED_CONTROL 1 +#ifdef TEST_CACHED_CONTROL +void test_cached_control(); +#endif // TEST_CACHED_CONTROL + #endif diff --git a/indra/llxml/llcontrolgroupreader.h b/indra/llxml/llcontrolgroupreader.h index 960b19036e..116ea2eae0 100644 --- a/indra/llxml/llcontrolgroupreader.h +++ b/indra/llxml/llcontrolgroupreader.h @@ -3,7 +3,30 @@ * @brief Interface providing readonly access to LLControlGroup (intended for unit testing) * * $LicenseInfo:firstyear=2001&license=viewergpl$ + * * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ @@ -13,9 +36,11 @@ #include "stdtypes.h" #include <string> -// Many of the types below are commented out because for the purposes of the early testing we're doing, -// we don't need them and we don't want to pull in all the machinery to support them. -// But the model is here for future unit test extensions. +#include "v3math.h" +#include "v3dmath.h" +#include "v3color.h" +#include "v4color.h" +#include "llrect.h" class LLControlGroupReader { @@ -23,22 +48,32 @@ public: LLControlGroupReader() {} virtual ~LLControlGroupReader() {} - virtual std::string getString(const std::string& name) = 0; - //virtual LLWString getWString(const std::string& name) = 0; - virtual std::string getText(const std::string& name) = 0; - //virtual LLVector3 getVector3(const std::string& name) = 0; - //virtual LLVector3d getVector3d(const std::string& name) = 0; - //virtual LLRect getRect(const std::string& name) = 0; - virtual BOOL getBOOL(const std::string& name) = 0; - virtual S32 getS32(const std::string& name) = 0; - virtual F32 getF32(const std::string& name) = 0; - virtual U32 getU32(const std::string& name) = 0; - //virtual LLSD getLLSD(const std::string& name) = 0; - - //virtual LLColor4 getColor(const std::string& name) = 0; - //virtual LLColor4U getColor4U(const std::string& name) = 0; - //virtual LLColor4 getColor4(const std::string& name) = 0; - //virtual LLColor3 getColor3(const std::string& name) = 0; + virtual std::string getString(const std::string& name) { return ""; } + virtual LLWString getWString(const std::string& name) { return LLWString(); } + virtual std::string getText(const std::string& name) { return ""; } + virtual LLVector3 getVector3(const std::string& name) { return LLVector3(); } + virtual LLVector3d getVector3d(const std::string& name) { return LLVector3d(); } + virtual LLRect getRect(const std::string& name) { return LLRect(); } + virtual BOOL getBOOL(const std::string& name) { return FALSE; } + virtual S32 getS32(const std::string& name) { return 0; } + virtual F32 getF32(const std::string& name) {return 0.0f; } + virtual U32 getU32(const std::string& name) {return 0; } + virtual LLSD getLLSD(const std::string& name) { return LLSD(); } + + virtual LLColor4 getColor(const std::string& name) { return LLColor4(); } + virtual LLColor4 getColor4(const std::string& name) { return LLColor4(); } + virtual LLColor3 getColor3(const std::string& name) { return LLColor3(); } + + virtual void setBOOL(const std::string& name, BOOL val) {} + virtual void setS32(const std::string& name, S32 val) {} + virtual void setF32(const std::string& name, F32 val) {} + virtual void setU32(const std::string& name, U32 val) {} + virtual void setString(const std::string& name, const std::string& val) {} + virtual void setVector3(const std::string& name, const LLVector3 &val) {} + virtual void setVector3d(const std::string& name, const LLVector3d &val) {} + virtual void setRect(const std::string& name, const LLRect &val) {} + virtual void setColor4(const std::string& name, const LLColor4 &val) {} + virtual void setLLSD(const std::string& name, const LLSD& val) {} }; #endif /* LL_LLCONTROLGROUPREADER_H */ diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 800b13573f..e97aa55190 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -47,6 +47,7 @@ #include "llquaternion.h" #include "llstring.h" #include "lluuid.h" +#include "lldir.h" const S32 MAX_COLUMN_WIDTH = 80; @@ -64,6 +65,7 @@ LLXMLNode::LLXMLNode() : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -85,6 +87,7 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -106,6 +109,7 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -226,6 +230,10 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) { mChildren->head = target_child->mNext; } + if (target_child == mChildren->tail) + { + mChildren->tail = target_child->mPrev; + } LLXMLNodePtr prev = target_child->mPrev; LLXMLNodePtr next = target_child->mNext; @@ -387,6 +395,7 @@ void XMLCALL StartXMLNode(void *userData, { // Create a new node LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE); + LLXMLNodePtr new_node = new_node_ptr; new_node->mID.clear(); LLXMLNodePtr ptr_new_node = new_node; @@ -401,7 +410,8 @@ void XMLCALL StartXMLNode(void *userData, } new_node_ptr->mParser = parent->mParser; - + new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); + // Set the current active node to the new node XML_Parser *parser = parent->mParser; XML_SetUserData(*parser, (void *)new_node_ptr); @@ -492,6 +502,7 @@ void XMLCALL StartXMLNode(void *userData, if (!new_node->getAttribute(attr_name.c_str(), attr_node, FALSE)) { attr_node = new LLXMLNode(attr_name.c_str(), TRUE); + attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); } attr_node->setValue(attr_value); new_node->addChild(attr_node); @@ -836,12 +847,66 @@ BOOL LLXMLNode::isFullyDefault() } // static -void LLXMLNode::writeHeaderToFile(LLFILE *fOut) +bool LLXMLNode::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root, + const std::vector<std::string>& paths) +{ + std::string full_filename = gDirUtilp->findSkinnedFilename(paths.front(), xui_filename); + if (full_filename.empty()) + { + return false; + } + + if (!LLXMLNode::parseFile(full_filename, root, NULL)) + { + // try filename as passed in since sometimes we load an xml file from a user-supplied path + if (!LLXMLNode::parseFile(xui_filename, root, NULL)) + { + llwarns << "Problem reading UI description file: " << xui_filename << llendl; + return false; + } + } + + LLXMLNodePtr updateRoot; + + std::vector<std::string>::const_iterator itor; + + for (itor = paths.begin(), ++itor; itor != paths.end(); ++itor) + { + std::string nodeName; + std::string updateName; + + std::string layer_filename = gDirUtilp->findSkinnedFilename((*itor), xui_filename); + if(layer_filename.empty()) + { + // no localized version of this file, that's ok, keep looking + continue; + } + + if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) + { + llwarns << "Problem reading localized UI description file: " << (*itor) + gDirUtilp->getDirDelimiter() + xui_filename << llendl; + return false; + } + + updateRoot->getAttributeString("name", updateName); + root->getAttributeString("name", nodeName); + + if (updateName == nodeName) + { + LLXMLNode::updateNode(root, updateRoot); + } + } + + return true; +} + +// static +void LLXMLNode::writeHeaderToFile(LLFILE *out_file) { - fprintf(fOut, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"); + fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"); } -void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) +void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent) { if (isFullyDefault()) { @@ -852,7 +917,8 @@ void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) std::ostringstream ostream; writeToOstream(ostream, indent); std::string outstring = ostream.str(); - if (fwrite(outstring.c_str(), 1, outstring.length(), fOut) != outstring.length()) + size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); + if (written != outstring.length()) { llwarns << "Short write" << llendl; } @@ -872,12 +938,12 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength); // stream the name - output_stream << indent << "<" << mName->mString; + output_stream << indent << "<" << mName->mString << "\n"; // ID if (mID != "") { - output_stream << " id=\"" << mID << "\""; + output_stream << indent << " id=\"" << mID << "\"\n"; } // Type @@ -886,22 +952,22 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i switch (mType) { case TYPE_BOOLEAN: - output_stream << " type=\"boolean\""; + output_stream << indent << " type=\"boolean\"\n"; break; case TYPE_INTEGER: - output_stream << " type=\"integer\""; + output_stream << indent << " type=\"integer\"\n"; break; case TYPE_FLOAT: - output_stream << " type=\"float\""; + output_stream << indent << " type=\"float\"\n"; break; case TYPE_STRING: - output_stream << " type=\"string\""; + output_stream << indent << " type=\"string\"\n"; break; case TYPE_UUID: - output_stream << " type=\"uuid\""; + output_stream << indent << " type=\"uuid\"\n"; break; case TYPE_NODEREF: - output_stream << " type=\"noderef\""; + output_stream << indent << " type=\"noderef\"\n"; break; default: // default on switch(enum) eliminates a warning on linux @@ -915,13 +981,13 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i switch (mEncoding) { case ENCODING_DECIMAL: - output_stream << " encoding=\"decimal\""; + output_stream << indent << " encoding=\"decimal\"\n"; break; case ENCODING_HEX: - output_stream << " encoding=\"hex\""; + output_stream << indent << " encoding=\"hex\"\n"; break; /*case ENCODING_BASE32: - output_stream << " encoding=\"base32\""; + output_stream << indent << " encoding=\"base32\"\n"; break;*/ default: // default on switch(enum) eliminates a warning on linux @@ -932,24 +998,23 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i // Precision if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) { - output_stream << " precision=\"" << mPrecision << "\""; + output_stream << indent << " precision=\"" << mPrecision << "\"\n"; } // Version if (mVersionMajor > 0 || mVersionMinor > 0) { - output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\""; + output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; } // Array length if (!has_default_length && mLength > 0) { - output_stream << " length=\"" << mLength << "\""; + output_stream << indent << " length=\"" << mLength << "\"\n"; } { // Write out attributes - S32 col_pos = 0; LLXMLAttribList::const_iterator attr_itr; LLXMLAttribList::const_iterator attr_end = mAttributes.end(); for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) @@ -971,17 +1036,14 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i std::string attr_str = llformat(" %s=\"%s\"", attr.c_str(), escapeXML(child->mValue).c_str()); - if (col_pos + (S32)attr_str.length() > MAX_COLUMN_WIDTH) - { - output_stream << "\n" << indent << " "; - col_pos = 4; - } - col_pos += attr_str.length(); - output_stream << attr_str; + output_stream << indent << attr_str << "\n"; } } } + // erase last \n before attaching final > or /> + output_stream.seekp(-1, std::ios::cur); + if (mChildren.isNull() && mValue == "") { output_stream << " />\n"; @@ -993,7 +1055,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (mChildren.notNull()) { // stream non-attributes - std::string next_indent = indent + "\t"; + std::string next_indent = indent + " "; for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) { child->writeToOstream(output_stream, next_indent); @@ -1002,7 +1064,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (!mValue.empty()) { std::string contents = getTextContents(); - output_stream << indent << "\t" << escapeXML(contents) << "\n"; + output_stream << indent << " " << escapeXML(contents) << "\n"; } output_stream << indent << "</" << mName->mString << ">\n"; } @@ -2475,14 +2537,15 @@ std::string LLXMLNode::escapeXML(const std::string& xml) return out; } -void LLXMLNode::setStringValue(U32 length, const std::string *array) +void LLXMLNode::setStringValue(U32 length, const std::string *strings) { if (length == 0) return; std::string new_value; for (U32 pos=0; pos<length; ++pos) { - new_value.append(escapeXML(array[pos])); + // *NOTE: Do not escape strings here - do it on output + new_value.append( strings[pos] ); if (pos < length-1) new_value.append(" "); } @@ -3150,6 +3213,19 @@ LLXMLNodePtr LLXMLNode::getNextSibling() const return ret; } +std::string LLXMLNode::getSanitizedValue() const +{ + if (mIsAttribute) + { + return getValue() ; + } + else + { + return getTextContents(); + } +} + + std::string LLXMLNode::getTextContents() const { std::string msg; @@ -3215,3 +3291,13 @@ std::string LLXMLNode::getTextContents() const } return msg; } + +void LLXMLNode::setLineNumber(S32 line_number) +{ + mLineNumber = line_number; +} + +S32 LLXMLNode::getLineNumber() +{ + return mLineNumber; +} diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index d4e127b05c..c983a14410 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -44,8 +44,8 @@ #include <map> #include "indra_constants.h" -#include "llmemory.h" -#include "llthread.h" +#include "llpointer.h" +#include "llthread.h" // LLThreadSafeRefCount #include "llstring.h" #include "llstringtable.h" @@ -153,8 +153,18 @@ public: LLXMLNodePtr& node, LLXMLNodePtr& update_node); static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node); - static void writeHeaderToFile(LLFILE *fOut); - void writeToFile(LLFILE *fOut, const std::string& indent = std::string()); + + static bool getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root, + const std::vector<std::string>& paths); + + + // Write standard XML file header: + // <?xml version="1.0" encoding="utf-8" standalone="yes" ?> + static void writeHeaderToFile(LLFILE *out_file); + + // Write XML to file with one attribute per line. + // XML escapes values as they are written. + void writeToFile(LLFILE *out_file, const std::string& indent = std::string()); void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string()); // Utility @@ -207,6 +217,7 @@ public: U32 getLength() const { return mLength; } U32 getPrecision() const { return mPrecision; } const std::string& getValue() const { return mValue; } + std::string getSanitizedValue() const; std::string getTextContents() const; const LLStringTableEntry* getName() const { return mName; } BOOL hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); } @@ -227,6 +238,8 @@ public: bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); + S32 getLineNumber(); + // The following skip over attributes LLXMLNodePtr getFirstChild() const; LLXMLNodePtr getNextSibling() const; @@ -262,6 +275,8 @@ public: void setName(const std::string& name); void setName(LLStringTableEntry* name); + void setLineNumber(S32 line_number); + // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt) static std::string escapeXML(const std::string& xml); @@ -300,6 +315,7 @@ public: U32 mPrecision; // The number of BITS per array item ValueType mType; // The value type Encoding mEncoding; // The value encoding + S32 mLineNumber; // line number in source file, if applicable LLXMLNode* mParent; // The parent node LLXMLChildrenPtr mChildren; // The child nodes @@ -312,7 +328,11 @@ public: protected: LLStringTableEntry *mName; // The name of this node - std::string mValue; // The value of this node (use getters/setters only) + + // The value of this node (use getters/setters only) + // Values are not XML-escaped in memory + // They may contain " (quot) ' (apos) & (amp) < (lt) > (gt) + std::string mValue; LLXMLNodePtr mDefault; // Mirror node in the default tree |