Code owners
Assign users and groups as approvers for specific file changes. Learn more.
llcontrol.h 17.57 KiB
/**
* @file llcontrol.h
* @brief A mechanism for storing "control state" for a program
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLCONTROL_H
#define LL_LLCONTROL_H
#include "llboost.h"
#include "llevent.h"
#include "llstring.h"
#include "llrect.h"
#include "llrefcount.h"
#include "llinstancetracker.h"
#include "absl/container/flat_hash_map.h"
#include <vector>
#include <string_view>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
class LLVector3;
class LLVector3d;
class LLQuaternion;
class LLColor4;
class LLColor4U;
class LLColor3;
// if this is changed, also modify mTypeString in llcontrol.h
typedef enum e_control_type
{
TYPE_U32 = 0,
TYPE_S32,
TYPE_F32,
TYPE_BOOLEAN,
TYPE_STRING,
TYPE_VEC3,
TYPE_VEC3D,
TYPE_VEC4,
TYPE_QUAT,
TYPE_RECT,
TYPE_COL4,
TYPE_COL3,
TYPE_UUID,
TYPE_LLSD,
TYPE_COUNT
} eControlType;
class LLControlVariable final : public LLRefCount
{
LOG_CLASS(LLControlVariable);
friend class LLControlGroup;
public:
typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t;
typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t;
enum ePersist
{
PERSIST_NO, // don't save this var
PERSIST_NONDFT, // save this var if differs from default
PERSIST_ALWAYS // save this var even if has default value
};
private:
std::string mName;
std::string mComment;
eControlType mType;
ePersist mPersist;
bool mHideFromSettingsEditor;
std::vector<LLSD> mValues;
commit_signal_t mCommitSignal;
validate_signal_t mValidateSignal;
public:
LLControlVariable(const std::string name, eControlType type,
LLSD initial, const std::string comment,
ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false);
virtual ~LLControlVariable() = default;
const std::string& getName() const { return mName; }
const std::string& getComment() const { return mComment; }
eControlType type() { return mType; }
bool isType(eControlType tp) { return tp == mType; }
void resetToDefault(bool fire_signal = false);
commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal
commit_signal_t* getCommitSignal() { return &mCommitSignal; }
validate_signal_t* getValidateSignal() { return &mValidateSignal; }
// [RLVa:KB] - Patch: RLVa-2.1.0
bool hasUnsavedValue() { return mValues.size() > 2; }
// [/RLVa:KB]
bool isDefault() { return (mValues.size() == 1); }
bool shouldSave(bool nondefault_only);
bool isPersisted() { return mPersist != PERSIST_NO; }
bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; }
LLSD get() const { return getValue(); }
LLSD getValue() const { return mValues.back(); }
LLSD getDefault() const { return mValues.front(); }
LLSD getSaveValue() const;
void set(const LLSD& val) { setValue(val); }
void setValue(const LLSD& value, bool saved_value = TRUE);
void setDefaultValue(const LLSD& value);
void setPersist(ePersist);
void setHiddenFromSettingsEditor(bool hide);
void setComment(const std::string comment);
private:
void firePropertyChanged(const LLSD &pPreviousValue);
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()
{
LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL;
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, std::string_view control_name)
{
// needs specialization
return T(sd);
}
//const U32 STRING_CACHE_SIZE = 10000;
class LLControlGroup final : public LLInstanceTracker<LLControlGroup, std::string>
{
LOG_CLASS(LLControlGroup);
protected:
typedef absl::flat_hash_map<std::string, LLControlVariablePtr> ctrl_name_table_t;
ctrl_name_table_t mNameTable;
static const std::string mTypeString[TYPE_COUNT];
std::set<std::string> mIncludedFiles;
public:
static eControlType typeStringToEnum(const std::string& typestr);
static std::string typeEnumToString(eControlType typeenum);
LLControlGroup(const std::string& name);
~LLControlGroup();
void cleanup();
LLControlVariablePtr getControl(std::string_view name);
struct ApplyFunctor
{
virtual ~ApplyFunctor() = default;
virtual void apply(const std::string& name, LLControlVariable* control) = 0;
};
void applyToAll(ApplyFunctor* func);
LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, BOOL hidefromsettingseditor = FALSE);
LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareVec4(const std::string& name, const LLVector4& initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareUUID(const std::string& name, const LLUUID& initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
std::string getString(std::string_view name);
std::string getText(std::string_view name);
BOOL getBOOL(std::string_view name);
bool getBool(std::string_view name);
S32 getS32(std::string_view name);
F32 getF32(std::string_view name);
U32 getU32(std::string_view name);
LLWString getWString(std::string_view name);
LLVector3 getVector3(std::string_view name);
LLVector3d getVector3d(std::string_view name);
LLVector4 getVector4(std::string_view name);
LLRect getRect(std::string_view name);
LLUUID getUUID(std::string_view name);
LLSD getLLSD(std::string_view name);
LLQuaternion getQuaternion(std::string_view name);
LLColor4 getColor(std::string_view name);
LLColor4 getColor4(std::string_view name);
LLColor3 getColor3(std::string_view name);
LLSD asLLSD(bool diffs_only);
// generic getter
template<typename T> T get(std::string_view name)
{
LLControlVariable* control = getControl(name);
LLSD value;
eControlType type = TYPE_COUNT;
if (control)
{
value = control->get();
type = control->type();
}
else
{
LL_WARNS() << "Control " << name << " not found." << LL_ENDL;
return T();
}
return convert_from_llsd<T>(value, type, name);
}
void setBOOL(std::string_view name, BOOL val);
void setS32(std::string_view name, S32 val);
void setF32(std::string_view name, F32 val);
void setU32(std::string_view name, U32 val);
void setString(std::string_view name, const std::string& val);
void setVector3(std::string_view name, const LLVector3 &val);
void setVector3d(std::string_view name, const LLVector3d &val);
void setVector4(std::string_view name, const LLVector4& val);
void setQuaternion(std::string_view name, const LLQuaternion &val);
void setRect(std::string_view name, const LLRect &val);
void setColor4(std::string_view name, const LLColor4 &val);
void setUUID(std::string_view name, const LLUUID& val);
void setLLSD(std::string_view name, const LLSD& val);
// type agnostic setter that takes LLSD
void setUntypedValue(std::string_view name, const LLSD& val);
// generic setter
template<typename T> void set(std::string_view name, const T& val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(get_control_type<T>()))
{
control->set(convert_to_llsd(val));
}
else
{
LL_WARNS() << "Invalid control " << name << LL_ENDL;
}
}
BOOL controlExists(std::string_view 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 std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING);
U32 saveToFile(const std::string& filename, BOOL nondefault_only);
U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
void resetToDefaults();
void incrCount(std::string_view name);
bool mSettingsProfile;
};
//! 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 final : 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))
{
LL_ERRS() << "The control could not be created!!!" << LL_ENDL;
}
}
bindToControl(group, name);
}
LLControlCache(LLControlGroup& group,
const std::string& name)
: LLInstanceTracker<LLControlCache<T>, std::string >(name)
{
if(!group.controlExists(name))
{
LL_ERRS() << "Control named " << name << "not found." << LL_ENDL;
}
bindToControl(group, name);
}
~LLControlCache() = default;
const T& getValue() const { return mCachedValue; }
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...
// NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last
mConnection = controlp->getSignal()->connect(0,
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, LLControlVariable::PERSIST_NO);
return true;
}
return false;
}
bool handleValueChange(const LLSD& newvalue)
{
mCachedValue = convert_from_llsd<T>(newvalue, mType, "");
return true;
}
private:
T mCachedValue;
eControlType mType;
boost::signals2::scoped_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()() const { 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<LLVector4>();
template <> eControlType get_control_type<LLQuaternion>();
template <> eControlType get_control_type<LLRect>();
template <> eControlType get_control_type<LLColor4>();
template <> eControlType get_control_type<LLColor3>();
template <> eControlType get_control_type<LLUUID>();
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<LLVector4>(const LLVector4& in);
template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& 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<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLVector4 convert_from_llsd<LLVector4>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLUUID convert_from_llsd<LLUUID>(const LLSD& sd, eControlType type, std::string_view control_name);
template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name);
//#define TEST_CACHED_CONTROL 1
#ifdef TEST_CACHED_CONTROL
void test_cached_control();
#endif // TEST_CACHED_CONTROL
#endif