diff options
author | Steven Bennetts <steve@lindenlab.com> | 2008-03-15 01:18:27 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2008-03-15 01:18:27 +0000 |
commit | 672a76d0ea08a0d0fc824e103ee4c4242b7e03ec (patch) | |
tree | b623a9c884383ad75ed755b2c373db2b90643671 /indra/llxml | |
parent | 04611efae8a3291ceba8a29dd920bdae0d404830 (diff) |
reverting premature commit at 82410.
Diffstat (limited to 'indra/llxml')
-rw-r--r-- | indra/llxml/llcontrol.cpp | 816 | ||||
-rw-r--r-- | indra/llxml/llcontrol.h | 210 |
2 files changed, 698 insertions, 328 deletions
diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 9de426fc03..4ad44f455f 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -57,9 +57,19 @@ #endif //this defines the current version of the settings file +U32 LLControlBase::sMaxControlNameLength = 0; + +//These lists are used to store the ID's of registered event listeners. +std::list<S32> LLControlBase::mFreeIDs; +std::list<S32> LLControlBase::mUsedIDs; + +S32 LLControlBase::mTopID; + +std::set<LLControlBase*> LLControlBase::mChangedControls; + const S32 CURRENT_VERSION = 101; -BOOL LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) +BOOL LLControl::llsd_compare(const LLSD& a, const LLSD & b) { switch (mType) { @@ -91,154 +101,58 @@ BOOL LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) return FALSE; } -LLControlVariable::LLControlVariable(const LLString& name, eControlType type, - LLSD initial, const LLString& comment, - BOOL persist) - : mName(name), - mComment(comment), - mType(type), - mPersist(persist) -{ - if (mPersist && mComment.empty()) - { - llerrs << "Must supply a comment for control " << mName << llendl; - } - //Push back versus setValue'ing here, since we don't want to call a signal yet - mValues.push_back(initial); -} - - - -LLControlVariable::~LLControlVariable() -{ -} - -void LLControlVariable::setValue(const LLSD& value, bool saved_value) -{ - bool value_changed = llsd_compare(getValue(), value) == FALSE; - 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(), value) == FALSE) - { - mValues.push_back(value); - } - } - else - { - // This is a unsaved value. Its needs to reside at - // mValues[2] (or greater). It must not affect - // the result of getSaveValue() - if (llsd_compare(mValues.back(), value) == FALSE) - { - 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(value); - } - } - - if(value_changed) - { - mSignal(value); - } -} - -void LLControlVariable::resetToDefault(bool fire_signal) +LLControlBase::~LLControlBase() { - //The first setting is always the default - //Pop to it and fire off the listener - while(mValues.size() > 1) mValues.pop_back(); - if(fire_signal) firePropertyChanged(); -} - -bool LLControlVariable::isSaveValueDefault() -{ - return (mValues.size() == 1) - || ((mValues.size() > 1) && llsd_compare(mValues[1], mValues[0])); } -LLSD LLControlVariable::getSaveValue() const +// virtual +void LLControlBase::resetToDefault() { - //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]; } -LLControlVariable* LLControlGroup::getControl(const LLString& name) +LLControlGroup::LLControlGroup(): mNameTable() { - ctrl_name_table_t::iterator iter = mNameTable.find(name); - return iter == mNameTable.end() ? NULL : iter->second; + //mFreeStringOffset = 0; } - -//////////////////////////////////////////////////////////////////////////// - -LLControlGroup::LLControlGroup() +LLControlGroup::~LLControlGroup() { - mTypeString[TYPE_U32] = "U32"; - mTypeString[TYPE_S32] = "S32"; - mTypeString[TYPE_F32] = "F32"; - mTypeString[TYPE_BOOLEAN] = "Boolean"; - mTypeString[TYPE_STRING] = "String"; - mTypeString[TYPE_VEC3] = "Vector3"; - mTypeString[TYPE_VEC3D] = "Vector3D"; - mTypeString[TYPE_RECT] = "Rect"; - mTypeString[TYPE_COL4] = "Color4"; - mTypeString[TYPE_COL3] = "Color3"; - mTypeString[TYPE_COL4U] = "Color4u"; - mTypeString[TYPE_LLSD] = "LLSD"; } -LLControlGroup::~LLControlGroup() +LLSD LLControlBase::registerListener(LLSimpleListenerObservable *listener, LLSD userdata) { - cleanup(); + // Symmetric listener relationship + addListener(listener, "", userdata); + listener->addListener(this, "", userdata); + return getValue(); } void LLControlGroup::cleanup() { - for_each(mNameTable.begin(), mNameTable.end(), DeletePairedPointer()); mNameTable.clear(); } -eControlType LLControlGroup::typeStringToEnum(const LLString& typestr) -{ - for(int i = 0; i < (int)TYPE_COUNT; ++i) - { - if(mTypeString[i] == typestr) return (eControlType)i; - } - return (eControlType)-1; -} - -LLString LLControlGroup::typeEnumToString(eControlType typeenum) +LLControlBase* LLControlGroup::getControl(const LLString& name) { - return mTypeString[typeenum]; + ctrl_name_table_t::iterator iter = mNameTable.find(name); + return iter == mNameTable.end() ? NULL : (LLControlBase*)iter->second; } BOOL LLControlGroup::declareControl(const LLString& name, eControlType type, const LLSD initial_val, const LLString& comment, BOOL persist) { - if(mNameTable.find(name) != mNameTable.end()) + if(!mNameTable[name]) { - llwarns << "LLControlGroup::declareControl: Control named " << name << " already exists." << llendl; - mNameTable[name]->setValue(initial_val); + // if not, create the control and add it to the name table + LLControl* control = new LLControl(name, type, initial_val, comment, persist); + mNameTable[name] = control; return TRUE; } - // if not, create the control and add it to the name table - LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist); - mNameTable[name] = control; - return TRUE; + else + { + llwarns << "LLControlGroup::declareControl: Control named " << name << " already exists." << llendl; + mNameTable.erase(name); + return FALSE; + } } BOOL LLControlGroup::declareU32(const LLString& name, const U32 initial_val, const LLString& comment, BOOL persist) @@ -296,14 +210,19 @@ BOOL LLControlGroup::declareColor3(const LLString& name, const LLColor3 &initial return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); } -BOOL LLControlGroup::declareLLSD(const LLString& name, const LLSD &initial_val, const LLString& comment, BOOL persist ) +LLSD LLControlGroup::registerListener(const LLString& name, LLSimpleListenerObservable *listener) { - return declareControl(name, TYPE_LLSD, initial_val, comment, persist); + LLControlBase *control = getControl(name); + if (control) + { + return control->registerListener(listener); + } + return LLSD(); } BOOL LLControlGroup::getBOOL(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_BOOLEAN)) return control->get().asBoolean(); @@ -316,7 +235,7 @@ BOOL LLControlGroup::getBOOL(const LLString& name) S32 LLControlGroup::getS32(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_S32)) return control->get().asInteger(); @@ -329,7 +248,7 @@ S32 LLControlGroup::getS32(const LLString& name) U32 LLControlGroup::getU32(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_U32)) return control->get().asInteger(); @@ -342,7 +261,7 @@ U32 LLControlGroup::getU32(const LLString& name) F32 LLControlGroup::getF32(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_F32)) return (F32) control->get().asReal(); @@ -355,7 +274,7 @@ F32 LLControlGroup::getF32(const LLString& name) LLString LLControlGroup::findString(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) return control->get().asString(); @@ -364,7 +283,7 @@ LLString LLControlGroup::findString(const LLString& name) LLString LLControlGroup::getString(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) return control->get().asString(); @@ -390,7 +309,7 @@ LLString LLControlGroup::getText(const LLString& name) LLVector3 LLControlGroup::getVector3(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3)) return control->get(); @@ -403,7 +322,7 @@ LLVector3 LLControlGroup::getVector3(const LLString& name) LLVector3d LLControlGroup::getVector3d(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3D)) return control->get(); @@ -416,7 +335,7 @@ LLVector3d LLControlGroup::getVector3d(const LLString& name) LLRect LLControlGroup::getRect(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_RECT)) return control->get(); @@ -434,7 +353,7 @@ LLColor4 LLControlGroup::getColor(const LLString& name) if (i != mNameTable.end()) { - LLControlVariable* control = i->second; + LLControlBase* control = i->second; switch(control->mType) { @@ -462,7 +381,7 @@ LLColor4 LLControlGroup::getColor(const LLString& name) LLColor4U LLControlGroup::getColor4U(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4U)) return control->get(); @@ -475,7 +394,7 @@ LLColor4U LLControlGroup::getColor4U(const LLString& name) LLColor4 LLControlGroup::getColor4(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4)) return control->get(); @@ -488,7 +407,7 @@ LLColor4 LLControlGroup::getColor4(const LLString& name) LLColor3 LLControlGroup::getColor3(const LLString& name) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL3)) return control->get(); @@ -499,16 +418,6 @@ LLColor3 LLControlGroup::getColor3(const LLString& name) } } -LLSD LLControlGroup::getLLSD(const LLString& name) -{ - LLControlVariable* control = getControl(name); - - if (control && control->isType(TYPE_LLSD)) - return control->getValue(); - CONTROL_ERRS << "Invalid LLSD control " << name << llendl; - return LLSD(); -} - BOOL LLControlGroup::controlExists(const LLString& name) { ctrl_name_table_t::iterator iter = mNameTable.find(name); @@ -521,7 +430,7 @@ BOOL LLControlGroup::controlExists(const LLString& name) void LLControlGroup::setBOOL(const LLString& name, BOOL val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_BOOLEAN)) { @@ -536,7 +445,7 @@ void LLControlGroup::setBOOL(const LLString& name, BOOL val) void LLControlGroup::setS32(const LLString& name, S32 val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_S32)) { @@ -551,7 +460,7 @@ void LLControlGroup::setS32(const LLString& name, S32 val) void LLControlGroup::setF32(const LLString& name, F32 val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_F32)) { @@ -566,7 +475,7 @@ void LLControlGroup::setF32(const LLString& name, F32 val) void LLControlGroup::setU32(const LLString& name, U32 val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_U32)) { @@ -581,7 +490,7 @@ void LLControlGroup::setU32(const LLString& name, U32 val) void LLControlGroup::setString(const LLString& name, const LLString &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_STRING)) { @@ -596,7 +505,7 @@ void LLControlGroup::setString(const LLString& name, const LLString &val) void LLControlGroup::setVector3(const LLString& name, const LLVector3 &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3)) { @@ -610,7 +519,7 @@ void LLControlGroup::setVector3(const LLString& name, const LLVector3 &val) void LLControlGroup::setVector3d(const LLString& name, const LLVector3d &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_VEC3D)) { @@ -624,7 +533,7 @@ void LLControlGroup::setVector3d(const LLString& name, const LLVector3d &val) void LLControlGroup::setRect(const LLString& name, const LLRect &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_RECT)) { @@ -638,7 +547,7 @@ void LLControlGroup::setRect(const LLString& name, const LLRect &val) void LLControlGroup::setColor4U(const LLString& name, const LLColor4U &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4U)) { @@ -652,7 +561,7 @@ void LLControlGroup::setColor4U(const LLString& name, const LLColor4U &val) void LLControlGroup::setColor4(const LLString& name, const LLColor4 &val) { - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control && control->isType(TYPE_COL4)) { @@ -664,20 +573,6 @@ void LLControlGroup::setColor4(const LLString& name, const LLColor4 &val) } } -void LLControlGroup::setLLSD(const LLString& 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; - } -} - void LLControlGroup::setValue(const LLString& name, const LLSD& val) { if (name.empty()) @@ -685,7 +580,7 @@ void LLControlGroup::setValue(const LLString& name, const LLSD& val) return; } - LLControlVariable* control = getControl(name); + LLControlBase* control = getControl(name); if (control) { @@ -701,9 +596,239 @@ void LLControlGroup::setValue(const LLString& name, const LLSD& val) // Load and save //--------------------------------------------------------------- -// Returns number of controls loaded, so 0 if failure U32 LLControlGroup::loadFromFileLegacy(const LLString& filename, BOOL require_declaration, eControlType declare_as) { + U32 item = 0; + U32 validitems = 0; + llifstream file; + S32 version; + + file.open(filename.c_str()); /*Flawfinder: ignore*/ + + if (!file) + { + llinfos << "LLControlGroup::loadFromFile unable to open." << llendl; + return 0; + } + + // Check file version + LLString name; + file >> name; + file >> version; + if (name != "version" || version != CURRENT_VERSION) + { + llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl; + return 0; + } + + while (!file.eof()) + { + file >> name; + + if (name.empty()) + { + continue; + } + + if (name.substr(0,2) == "//") + { + // This is a comment. + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + file.getline(buffer, MAX_STRING); + continue; + } + + BOOL declared = mNameTable.find(name) != mNameTable.end(); + + 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 + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + file.getline(buffer, MAX_STRING); + llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl; + } + continue; + } + + // Got an item. Load it up. + item++; + + // If not declared, assume it's a string + if (!declared) + { + switch(declare_as) + { + case TYPE_COL4: + declareColor4(name, LLColor4::white, LLString::null, NO_PERSIST); + break; + case TYPE_COL4U: + declareColor4U(name, LLColor4U::white, LLString::null, NO_PERSIST); + break; + case TYPE_STRING: + default: + declareString(name, LLString::null, LLString::null, NO_PERSIST); + break; + } + } + + // Control name has been declared in code. + LLControlBase *control = getControl(name); + + llassert(control); + + mLoadedSettings.insert(name); + + switch(control->mType) + { + case TYPE_F32: + { + F32 initial; + + file >> initial; + + control->set(initial); + validitems++; + } + break; + case TYPE_S32: + { + S32 initial; + + file >> initial; + + control->set(initial); + validitems++; + } + break; + case TYPE_U32: + { + U32 initial; + + file >> initial; + control->set((LLSD::Integer) initial); + validitems++; + } + break; + case TYPE_BOOLEAN: + { + char boolstring[256]; /*Flawfinder: ignore*/ + BOOL valid = FALSE; + BOOL initial = FALSE; + + file >> boolstring; + if (!strcmp("TRUE", boolstring)) + { + initial = TRUE; + valid = TRUE; + } + else if (!strcmp("FALSE", boolstring)) + { + initial = FALSE; + valid = TRUE; + } + + if (valid) + { + control->set(initial); + } + else + { + llinfos << filename << "Item " << item << ": Invalid BOOL control " << name << ", " << boolstring << llendl; + } + + validitems++; + } + break; + case TYPE_STRING: + { + LLString string; + + file >> string; + + control->set(string); + validitems++; + } + break; + case TYPE_VEC3: + { + F32 x, y, z; + + file >> x >> y >> z; + + LLVector3 vector(x, y, z); + + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_VEC3D: + { + F64 x, y, z; + + file >> x >> y >> z; + + LLVector3d vector(x, y, z); + + control->set(vector.getValue()); + validitems++; + } + break; + case TYPE_RECT: + { + S32 left, bottom, width, height; + + file >> left >> bottom >> width >> height; + + LLRect rect; + rect.setOriginAndSize(left, bottom, width, height); + + control->set(rect.getValue()); + validitems++; + } + break; + case TYPE_COL4U: + { + S32 red, green, blue, alpha; + LLColor4U color; + file >> red >> green >> blue >> alpha; + color.setVec(red, green, blue, alpha); + control->set(color.getValue()); + validitems++; + } + break; + case TYPE_COL4: + { + LLColor4 color; + file >> color.mV[VRED] >> color.mV[VGREEN] + >> color.mV[VBLUE] >> color.mV[VALPHA]; + control->set(color.getValue()); + validitems++; + } + break; + case TYPE_COL3: + { + LLColor3 color; + file >> color.mV[VRED] >> color.mV[VGREEN] + >> color.mV[VBLUE]; + control->set(color.getValue()); + validitems++; + } + break; + } + } + + file.close(); + + return validitems; +} + +// Returns number of controls loaded, so 0 if failure +U32 LLControlGroup::loadFromFile(const LLString& filename, BOOL require_declaration, eControlType declare_as) +{ LLString name; LLXmlTree xml_controls; @@ -776,9 +901,11 @@ U32 LLControlGroup::loadFromFileLegacy(const LLString& filename, BOOL require_de } // Control name has been declared in code. - LLControlVariable *control = getControl(name); + LLControlBase *control = getControl(name); llassert(control); + + mLoadedSettings.insert(name); switch(control->mType) { @@ -892,43 +1019,59 @@ U32 LLControlGroup::loadFromFileLegacy(const LLString& filename, BOOL require_de LLVector3 color; child_nodep->getAttributeVector3("value", color); - control->set(LLColor3(color.mV).getValue()); + control->set(LLColor3(color.mV).getValue()); validitems++; } break; - - default: - break; - } - + child_nodep = rootp->getNextChild(); } return validitems; } +struct compare_controls +{ + bool operator() (const LLControlBase* const a, const LLControlBase* const b) const + { + return a->getName() < b->getName(); + } +}; + U32 LLControlGroup::saveToFile(const LLString& filename, BOOL nondefault_only) { - LLSD settings; - int num_saved = 0; + const char ENDL = '\n'; + + llinfos << "Saving settings to file: " << filename << llendl; + + // place the objects in a temporary container that enforces a sort + // order to ease manual editing of the file + + typedef std::set< LLControlBase*, compare_controls > control_list_t; + control_list_t controls; + for (ctrl_name_table_t::iterator iter = mNameTable.begin(); iter != mNameTable.end(); iter++) { - LLControlVariable* control = iter->second; + LLString name = iter->first; + if (name.empty()) + { + CONTROL_ERRS << "Control with no name found!!!" << llendl; + break; + } + + LLControlBase* control = (LLControlBase *)iter->second; if (!control) { - llwarns << "Tried to save invalid control: " << iter->first << llendl; + llwarns << "Tried to save invalid control: " << name << llendl; } - if( control && control->isPersisted() ) + if( control && control->mPersist ) { - if (!(nondefault_only && (control->isSaveValueDefault()))) + if (!(nondefault_only && (control->mIsDefault))) { - settings[iter->first]["Type"] = typeEnumToString(control->type()); - settings[iter->first]["Comment"] = control->getComment(); - settings[iter->first]["Value"] = control->getSaveValue(); - ++num_saved; + controls.insert( control ); } else { @@ -937,58 +1080,156 @@ U32 LLControlGroup::saveToFile(const LLString& filename, BOOL nondefault_only) } } } + llofstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::toPrettyXML(settings, file); - file.close(); - llinfos << "Saved to " << filename << llendl; - } - else - { - // This is a warning because sometime we want to use settings files which can't be written... - llwarns << "Unable to open settings file: " << filename << llendl; - return 0; - } - return num_saved; -} + file.open(filename.c_str()); /*Flawfinder: ignore*/ -U32 LLControlGroup::loadFromFile(const LLString& filename, BOOL require_declaration, eControlType declare_as) -{ - LLString name; - LLSD settings; - LLSD control_map; - llifstream infile; - infile.open(filename.c_str()); - if(!infile.is_open()) + if (!file.is_open()) { - llwarns << "Cannot find file " << filename << " to load." << llendl; + // This is a warning because sometime we want to use settings files which can't be written... + llwarns << "LLControlGroup::saveToFile unable to open file for writing" << llendl; return 0; } - S32 ret = LLSDSerialize::fromXML(settings, infile); - if (ret <= 0) + + // Write file version + file << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n"; + file << "<settings version = \"" << CURRENT_VERSION << "\">\n"; + for (control_list_t::iterator iter = controls.begin(); + iter != controls.end(); ++iter) { - infile.close(); - llwarns << "Unable to open LLSD control file " << filename << ". Trying Legacy Method." << llendl; - return loadFromFileLegacy(filename, require_declaration, declare_as); - } + LLControlBase* control = *iter; + file << "\t<!--" << control->comment() << "-->" << ENDL; + LLString name = control->getName(); + switch (control->type()) + { + case TYPE_U32: + { + file << "\t<" << name << " value=\"" << (U32) control->get().asInteger() << "\"/>\n"; + break; + } + case TYPE_S32: + { + file << "\t<" << name << " value=\"" << (S32) control->get().asInteger() << "\"/>\n"; + break; + } + case TYPE_F32: + { + file << "\t<" << name << " value=\"" << (F32) control->get().asReal() << "\"/>\n"; + break; + } + case TYPE_VEC3: + { + LLVector3 vector(control->get()); + file << "\t<" << name << " value=\"" << vector.mV[VX] << " " << vector.mV[VY] << " " << vector.mV[VZ] << "\"/>\n"; + break; + } + case TYPE_VEC3D: + { + LLVector3d vector(control->get()); + file << "\t<" << name << " value=\"" << vector.mdV[VX] << " " << vector.mdV[VY] << " " << vector.mdV[VZ] << "\"/>\n"; + break; + } + case TYPE_RECT: + { + LLRect rect(control->get()); + file << "\t<" << name << " value=\"" << rect.mLeft << " " << rect.mBottom << " " << rect.getWidth() << " " << rect.getHeight() << "\"/>\n"; + break; + } + case TYPE_COL4: + { + LLColor4 color(control->get()); + file << "\t<" << name << " value=\"" << color.mV[VRED] << ", " << color.mV[VGREEN] << ", " << color.mV[VBLUE] << ", " << color.mV[VALPHA] << "\"/>\n"; + break; + } + case TYPE_COL3: + { + LLColor3 color(control->get()); + file << "\t<" << name << " value=\"" << color.mV[VRED] << ", " << color.mV[VGREEN] << ", " << color.mV[VBLUE] << "\"/>\n"; + break; + } + case TYPE_BOOLEAN: + { + file << "\t<" << name << " value=\"" << (control->get().asBoolean() ? "TRUE" : "FALSE") << "\"/>\n"; + break; + } + case TYPE_STRING: + { + file << "\t<" << name << " value=\"" << LLSDXMLFormatter::escapeString(control->get().asString()) << "\"/>\n"; + break; + } + default: + { + CONTROL_ERRS << "LLControlGroup::saveToFile - unknown control type!" << llendl; + break; + } + } - U32 validitems = 0; - int persist = 1; - for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) + // Debug spam + // llinfos << name << " " << control->getValue().asString() << llendl; + }// next + + file << "</settings>\n"; + file.close(); + + return controls.size(); +} + +void LLControlGroup::applyOverrides(const std::map<std::string, std::string>& overrides) +{ + for (std::map<std::string, std::string>::const_iterator iter = overrides.begin(); + iter != overrides.end(); ++iter) { - name = (*itr).first; - control_map = (*itr).second; - - if(control_map.has("Persist")) persist = control_map["Persist"].asInteger(); - - declareControl(name, typeStringToEnum(control_map["Type"].asString()), control_map["Value"], control_map["Comment"].asString(), persist); - - ++validitems; + const std::string& command = iter->first; + const std::string& value = iter->second; + LLControlBase* control = (LLControlBase *)mNameTable[command]; + if (control) + { + switch(control->mType) + { + case TYPE_U32: + control->set((LLSD::Integer)atof(value.c_str())); + break; + case TYPE_S32: + control->set((S32)atof(value.c_str())); + break; + case TYPE_F32: + control->set((F32)atof(value.c_str())); + break; + case TYPE_BOOLEAN: + if (!LLString::compareInsensitive(value.c_str(), "TRUE")) + { + control->set(TRUE); + } + else if (!LLString::compareInsensitive(value.c_str(), "FALSE")) + { + control->set(FALSE); + } + else + { + control->set((BOOL)atof(value.c_str())); + } + break; + case TYPE_STRING: + control->set(value); + break; +// // *FIX: implement this given time and need. +// case TYPE_UUID: +// break; + // we don't support command line overrides of vec3 or col4 + // yet - requires parsing of multiple values + case TYPE_VEC3: + case TYPE_VEC3D: + case TYPE_COL4: + case TYPE_COL3: + default: + break; + } + } + else + { + llinfos << "There is no control variable " << command << llendl; + } } - - return validitems; } void LLControlGroup::resetToDefaults() @@ -998,20 +1239,11 @@ void LLControlGroup::resetToDefaults() control_iter != mNameTable.end(); ++control_iter) { - LLControlVariable* control = (*control_iter).second; + LLControlBase* 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); - } -} - //============================================================================ // First-use @@ -1032,7 +1264,7 @@ static LLString get_warn_name(const LLString& name) void LLControlGroup::addWarning(const LLString& name) { LLString warnname = get_warn_name(name); - if(mNameTable.find(warnname) == mNameTable.end()) + if(!mNameTable[warnname]) { LLString comment = LLString("Enables ") + name + LLString(" warning dialog"); declareBOOL(warnname, TRUE, comment); @@ -1061,6 +1293,91 @@ void LLControlGroup::resetWarnings() } } + + +//============================================================================= +// Listener ID generator/management + +void LLControlBase::releaseListenerID(S32 id) +{ + mFreeIDs.push_back(id); +} + +S32 LLControlBase::allocateListenerID() +{ + if(mFreeIDs.size() == 0) + { //Out of IDs so generate some new ones. + for(int t=0;t<32;t++) + { + mFreeIDs.push_back(mTopID++); + } + } + S32 rtn = mFreeIDs.front(); + mFreeIDs.pop_front(); + mUsedIDs.push_back(rtn); + return rtn; +} + +bool LLControlBase::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) +{ + if (event->desc() == "value_changed") + { + setValue(((LLValueChangedEvent*)(LLEvent*)event)->mValue); + return TRUE; + } + return TRUE; +} + +void LLControlBase::firePropertyChanged() +{ + LLValueChangedEvent *evt = new LLValueChangedEvent(this, getValue()); + fireEvent(evt, ""); +} + +//============================================================================ +// Used to add a listener callback that will be called on the frame that the controls value changes + +S32 LLControl::addListener(LLControl::tListenerCallback* cbfn) +{ + S32 id = allocateListenerID(); + mListeners.push_back(cbfn); + mListenerIDs.push_back( id ); + return id; +} + +void LLControl::updateListeners() { + LLControl::tPropertyChangedListIter iter = mChangeEvents.begin(); + while(iter!=mChangeEvents.end()){ + LLControl::tPropertyChangedEvent& evt = *iter; + (*evt.mCBFN)(evt.mNewValue,evt.mID,*this); + iter++; + } + mChangeEvents.clear(); +} + +//static +void LLControlBase::updateAllListeners() +{ + std::set< LLControlBase* >::iterator iter = mChangedControls.begin(); + while(iter != mChangedControls.end()){ + (*iter)->updateListeners(); + iter++; + } + mChangedControls.clear(); +} + +LLControl::LLControl( + const LLString& name, + eControlType type, + LLSD initial, + const LLString& comment, + BOOL persist) : + LLControlBase(name, type, comment, persist), + mCurrent(initial), + mDefault(initial) +{ +} + //============================================================================ #ifdef TEST_HARNESS @@ -1076,17 +1393,17 @@ void main() llinfos << "Loaded " << count << " controls" << llendl; // test insertion - foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f); + foo = new LLControl<F32>("gFoo", 5.f, 1.f, 20.f); gGlobals.addEntry("gFoo", foo); - bar = new LLControlVariable<S32>("gBar", 10, 2, 22); + bar = new LLControl<S32>("gBar", 10, 2, 22); gGlobals.addEntry("gBar", bar); - baz = new LLControlVariable<BOOL>("gBaz", FALSE); + baz = new LLControl<BOOL>("gBaz", FALSE); gGlobals.addEntry("gBaz", baz); // test retrieval - getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo"); + getfoo = (LLControl<F32>*) gGlobals.resolveName("gFoo"); getfoo->dump(); getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); @@ -1099,10 +1416,10 @@ void main() // Failure modes // ...min > max - // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f); + // badfoo = new LLControl<F32>("gFoo2", 100.f, 20.f, 5.f); // ...initial > max - // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000); + // badbar = new LLControl<S32>("gBar2", 10, 20, 100000); // ...misspelled name // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); @@ -1124,4 +1441,3 @@ void main() } #endif - diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 7a638a7b73..a1a2a4c851 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -38,26 +38,6 @@ #include "llstring.h" #include "llrect.h" -#include <vector> - -// *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 -// Disable the warning for the boost includes. -#if LL_WINDOWS -# if (_MSC_VER >= 1300 && _MSC_VER < 1400) -# pragma warning(push) -# pragma warning( disable : 4675 ) -# endif -#endif - -#include <boost/bind.hpp> -#include <boost/signal.hpp> - -#if LL_WINDOWS -# if (_MSC_VER >= 1300 && _MSC_VER < 1400) -# pragma warning(pop) -# endif -#endif - class LLVector3; class LLVector3d; class LLColor4; @@ -68,7 +48,7 @@ const BOOL NO_PERSIST = FALSE; typedef enum e_control_type { - TYPE_U32 = 0, + TYPE_U32, TYPE_S32, TYPE_F32, TYPE_BOOLEAN, @@ -78,82 +58,159 @@ typedef enum e_control_type TYPE_RECT, TYPE_COL4, TYPE_COL3, - TYPE_COL4U, - TYPE_LLSD, - TYPE_COUNT + TYPE_COL4U } eControlType; -class LLControlVariable +class LLControlBase : public LLSimpleListenerObservable { - friend class LLControlGroup; - typedef boost::signal<void(const LLSD&)> signal_t; - -private: +friend class LLControlGroup; +protected: LLString mName; LLString mComment; eControlType mType; + BOOL mHasRange; BOOL mPersist; - std::vector<LLSD> mValues; - - signal_t mSignal; - + BOOL mIsDefault; + + static std::set<LLControlBase*> mChangedControls; + static std::list<S32> mFreeIDs;//These lists are used to store the ID's of registered event listeners. + static std::list<S32> mUsedIDs; + static S32 mTopID;//This is the index of the highest ID event listener ID. When the free pool is exhausted, new IDs are allocated from here. + public: - LLControlVariable(const LLString& name, eControlType type, - LLSD initial, const LLString& comment, - BOOL persist = TRUE); + static void releaseListenerID(S32 id); + static S32 allocateListenerID(); + static void updateAllListeners(); + virtual void updateListeners() = 0; + + LLControlBase(const LLString& name, eControlType type, const LLString& comment, BOOL persist) + : mName(name), + mComment(comment), + mType(type), + mHasRange(FALSE), + mPersist(persist), + mIsDefault(TRUE) + { + if (mPersist && mComment.empty()) + { + llerrs << "Must supply a comment for control " << mName << llendl; + } + sMaxControlNameLength = llmax((U32)mName.size(), sMaxControlNameLength); + } + + virtual ~LLControlBase(); - virtual ~LLControlVariable(); - const LLString& getName() const { return mName; } const LLString& getComment() const { return mComment; } eControlType type() { return mType; } - BOOL isType(eControlType tp) { return tp == mType; } - - void resetToDefault(bool fire_signal = TRUE); - - signal_t* getSignal() { return &mSignal; } - - bool isDefault() { return (mValues.size() == 1); } - bool isSaveValueDefault(); - bool isPersisted() { return mPersist; } - void set(const LLSD& val) { setValue(val); } - LLSD get() const { return getValue(); } - LLSD getDefault() const { return mValues.front(); } - LLSD getValue() const { return mValues.back(); } - LLSD getSaveValue() const; - void setValue(const LLSD& value, bool saved_value = TRUE); - void firePropertyChanged() + BOOL isType(eControlType tp) { return tp == mType; } + + // Defaults to no-op + virtual void resetToDefault(); + + LLSD registerListener(LLSimpleListenerObservable *listener, LLSD userdata = ""); + + virtual LLSD get() const = 0; + virtual LLSD getValue() const = 0; + virtual void setValue(LLSD value) = 0; + virtual void set(LLSD value) = 0; + + // From LLSimpleListener + virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata); + + void firePropertyChanged(); + + static U32 sMaxControlNameLength; + +protected: + const char* name() { return mName.c_str(); } + const char* comment() { return mComment.c_str(); } +}; + +class LLControl +: public LLControlBase +{ +friend class LLControlGroup; +protected: + LLSD mCurrent; + LLSD mDefault; + +public: + + typedef void tListenerCallback(const LLSD& newValue,S32 listenerID, LLControl& control); + typedef struct{ + S32 mID; + LLSD mNewValue; + tListenerCallback* mCBFN; + }tPropertyChangedEvent; + + typedef std::list<tPropertyChangedEvent>::iterator tPropertyChangedListIter; + std::list<tPropertyChangedEvent> mChangeEvents; + std::list< tListenerCallback* > mListeners; + std::list< S32 > mListenerIDs; + + virtual void updateListeners(); + S32 addListener(tListenerCallback* cbfn); + + LLControl( + const LLString& name, + eControlType type, + LLSD initial, const + LLString& comment, + BOOL persist = TRUE); + + void set(LLSD val) { setValue(val); } + LLSD get() const { return getValue(); } + LLSD getdefault() const { return mDefault; } + LLSD getValue() const { return mCurrent; } + BOOL llsd_compare(const LLSD& a, const LLSD& b); + + void setValue(LLSD value) + { + if (llsd_compare(mCurrent, value) == FALSE) + { + mCurrent = value; + mIsDefault = llsd_compare(mCurrent, mDefault); + firePropertyChanged(); + } + } + + /*virtual*/ void resetToDefault() + { + setValue(mDefault); + } + + virtual ~LLControl() { - mSignal(mValues.back()); + //Remove and deregister all listeners.. + while(mListenerIDs.size()) + { + S32 id = mListenerIDs.front(); + mListenerIDs.pop_front(); + releaseListenerID(id); + } } - BOOL llsd_compare(const LLSD& a, const LLSD& b); }; //const U32 STRING_CACHE_SIZE = 10000; class LLControlGroup { -protected: - typedef std::map<LLString, LLControlVariable* > ctrl_name_table_t; +public: + typedef std::map<LLString, LLPointer<LLControlBase> > ctrl_name_table_t; ctrl_name_table_t mNameTable; std::set<LLString> mWarnings; - LLString mTypeString[TYPE_COUNT]; + std::set<LLString> mLoadedSettings; // Filled in with names loaded from settings.xml - eControlType typeStringToEnum(const LLString& typestr); - LLString typeEnumToString(eControlType typeenum); public: LLControlGroup(); ~LLControlGroup(); void cleanup(); + bool hasLoaded(const LLString& name) { return mLoadedSettings.find(name) != mLoadedSettings.end(); } + void clearLoaded() { mLoadedSettings.clear(); } // Call once we've done any settings tweaks which may need this data - LLControlVariable* getControl(const LLString& name); - - struct ApplyFunctor - { - virtual ~ApplyFunctor() {}; - virtual void apply(const LLString& name, LLControlVariable* control) = 0; - }; - void applyToAll(ApplyFunctor* func); + LLControlBase* getControl(const LLString& name); + LLSD registerListener(const LLString& name, LLSimpleListenerObservable *listener); BOOL declareControl(const LLString& name, eControlType type, const LLSD initial_val, const LLString& comment, BOOL persist); BOOL declareU32(const LLString& name, U32 initial_val, const LLString& comment, BOOL persist = TRUE); @@ -167,7 +224,6 @@ public: BOOL declareColor4U(const LLString& name, const LLColor4U &initial_val, const LLString& comment, BOOL persist = TRUE); BOOL declareColor4(const LLString& name, const LLColor4 &initial_val, const LLString& comment, BOOL persist = TRUE); BOOL declareColor3(const LLString& name, const LLColor3 &initial_val, const LLString& comment, BOOL persist = TRUE); - BOOL declareLLSD(const LLString& name, const LLSD &initial_val, const LLString& comment, BOOL persist = TRUE); LLString findString(const LLString& name); @@ -181,7 +237,7 @@ public: S32 getS32(const LLString& name); F32 getF32(const LLString& name); U32 getU32(const LLString& name); - LLSD getLLSD(const LLString& name); + LLSD getValue(const LLString& name); // Note: If an LLColor4U control exists, it will cast it to the correct @@ -202,21 +258,19 @@ public: void setColor4U(const LLString& name, const LLColor4U &val); void setColor4(const LLString& name, const LLColor4 &val); void setColor3(const LLString& name, const LLColor3 &val); - void setLLSD(const LLString& name, const LLSD& val); void setValue(const LLString& name, const LLSD& val); - - + BOOL controlExists(const LLString& name); // Returns number of controls loaded, 0 if failed // If require_declaration is false, will auto-declare controls it finds // as the given type. - U32 loadFromFileLegacy(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); - U32 saveToFile(const LLString& filename, BOOL nondefault_only); - U32 loadFromFile(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); + U32 loadFromFileLegacy(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); + U32 loadFromFile(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING); + U32 saveToFile(const LLString& filename, BOOL skip_if_default); + void applyOverrides(const std::map<std::string, std::string>& overrides); void resetToDefaults(); - // Ignorable Warnings // Add a config variable to be reset on resetWarnings() |