diff options
author | Steven Bennetts <steve@lindenlab.com> | 2009-06-21 08:04:56 +0000 |
---|---|---|
committer | Steven Bennetts <steve@lindenlab.com> | 2009-06-21 08:04:56 +0000 |
commit | 9ec432034dc3c45d7ce763eb02dae4cc7f6b8da8 (patch) | |
tree | 4a505c1e0919af52800b3ffb3eaf135e7d6f9ce6 /indra/llui/lluictrlfactory.h | |
parent | 351ebe9fcb76f3b99c2957004bb8493a904869ee (diff) |
merge -r 122421-124917 viewer-2.0.0-2 -> viewer-2.0.0-3
ignore-dead-branch
Diffstat (limited to 'indra/llui/lluictrlfactory.h')
-rw-r--r-- | indra/llui/lluictrlfactory.h | 408 |
1 files changed, 379 insertions, 29 deletions
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 5e7c24efc0..4045022c8e 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -33,68 +33,418 @@ #ifndef LLUICTRLFACTORY_H #define LLUICTRLFACTORY_H +#include "llcallbackmap.h" +#include "llinitparam.h" +#include "llxmlnode.h" +#include "llfasttimer.h" + +#include <boost/function.hpp> #include <iosfwd> #include <stack> -#include "llcallbackmap.h" -#include "llfloater.h" - -class LLView; class LLPanel; +class LLFloater; +class LLView; -class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory> +class LLXUIParser : public LLInitParam::Parser, public LLSingleton<LLXUIParser> { +LOG_CLASS(LLXUIParser); + +protected: + LLXUIParser(); + friend class LLSingleton<LLXUIParser>; public: + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent=false); + void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); + +private: + typedef std::list<std::pair<std::string, bool> > token_list_t; + + bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + bool readBoolValue(void* val_ptr); + bool readStringValue(void* val_ptr); + bool readU8Value(void* val_ptr); + bool readS8Value(void* val_ptr); + bool readU16Value(void* val_ptr); + bool readS16Value(void* val_ptr); + bool readU32Value(void* val_ptr); + bool readS32Value(void* val_ptr); + bool readF32Value(void* val_ptr); + bool readF64Value(void* val_ptr); + bool readColor4Value(void* val_ptr); + bool readUIColorValue(void* val_ptr); + bool readUUIDValue(void* val_ptr); + bool readSDValue(void* val_ptr); + + //writer helper functions + bool writeBoolValue(const void* val_ptr, const name_stack_t&); + bool writeStringValue(const void* val_ptr, const name_stack_t&); + bool writeU8Value(const void* val_ptr, const name_stack_t&); + bool writeS8Value(const void* val_ptr, const name_stack_t&); + bool writeU16Value(const void* val_ptr, const name_stack_t&); + bool writeS16Value(const void* val_ptr, const name_stack_t&); + bool writeU32Value(const void* val_ptr, const name_stack_t&); + bool writeS32Value(const void* val_ptr, const name_stack_t&); + bool writeF32Value(const void* val_ptr, const name_stack_t&); + bool writeF64Value(const void* val_ptr, const name_stack_t&); + bool writeColor4Value(const void* val_ptr, const name_stack_t&); + bool writeUIColorValue(const void* val_ptr, const name_stack_t&); + bool writeUUIDValue(const void* val_ptr, const name_stack_t&); + bool writeSDValue(const void* val_ptr, const name_stack_t&); + + LLXMLNodePtr getNode(const name_stack_t& stack); + +private: + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + S32 mLastWriteGeneration; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; +}; + +// global static instance for registering all widget types +typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; + +typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t; + +template <typename DERIVED_TYPE> +class LLWidgetRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> +{ +public: + typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t; + // local static instance for registering a particular widget + template<typename T, typename PARAM_BLOCK = typename T::Params> + class Register : public super_t::StaticRegistrar + { + public: + // register with either the provided builder, or the generic templated builder + Register(const char* tag, LLWidgetCreatorFunc func = NULL); + }; + +protected: + LLWidgetRegistry() {} +}; + +class LLDefaultWidgetRegistry : public LLWidgetRegistry<LLDefaultWidgetRegistry> +{ +protected: + LLDefaultWidgetRegistry() {} + friend class LLSingleton<LLDefaultWidgetRegistry>; +}; + +struct LLCompareTypeID +{ + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return lhs->before(*rhs); + } +}; + + +class LLWidgetTemplateRegistry +: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetTemplateRegistry, LLCompareTypeID> +{ + +}; + +extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP; +extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION; +extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS; + +class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory> +{ +private: + friend class LLSingleton<LLUICtrlFactory>; LLUICtrlFactory(); - // do not call! needs to be public so run-time can clean up the singleton - virtual ~LLUICtrlFactory(); + ~LLUICtrlFactory(); + + // only partial specialization allowed in inner classes, so use extra dummy parameter + template <typename T, int DUMMY> + class ParamDefaults : public LLSingleton<ParamDefaults<T, DUMMY> > + { + public: + ParamDefaults() + { + // recursively initialize from base class param block + ((typename T::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename T::base_block_t, DUMMY>::instance().get()); + // after initializing base classes, look up template file for this param block + std::string* param_block_tag = LLWidgetTemplateRegistry::instance().getValue(&typeid(T)); + if (param_block_tag) + { + LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype); + } + } + + const T& get() { return mPrototype; } - void setupPaths(); + private: + T mPrototype; + }; - void buildFloater(LLFloater* floaterp, const std::string &filename, - const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); - BOOL buildPanel(LLPanel* panelp, const std::string &filename, - const LLCallbackMap::map_t* factory_map = NULL); + // base case for recursion, there are NO base classes of LLInitParam::BaseBlock + template<int DUMMY> + class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> > + { + public: + const LLInitParam::BaseBlock& get() { return mBaseBlock; } + private: + LLInitParam::BaseBlock mBaseBlock; + }; - void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); } - void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); } +public: + + template<typename T> + static const T& getDefaultParams() + { + //#pragma message("Generating ParamDefaults") + return ParamDefaults<T, 0>::instance().get(); + } - class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp); - class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp); + void buildFloater(LLFloater* floaterp, const std::string &filename, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL); + LLFloater* buildFloaterFromXML(const std::string& filename, BOOL open_floater = TRUE); + BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL); // Does what you want for LLFloaters and LLPanels // Returns 0 on success S32 saveToXML(LLView* viewp, const std::string& filename); - // Rebuilds all currently built panels. - void rebuild(); + std::string getCurFileName() { return mFileNames.empty() ? "" : mFileNames.back(); } static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color); LLPanel* createFactoryPanel(const std::string& name); - virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node); - virtual LLView* createWidget(LLPanel *parent, LLXMLNodePtr node); + void pushFactoryFunctions(const LLCallbackMap::map_t* map); + void popFactoryFunctions(); + + template<typename T> + static T* create(typename T::Params& params, LLView* parent = NULL) + { + //#pragma message("Generating LLUICtrlFactory::create") + params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get()); + //S32 foo = "test"; + + if (!params.validateBlock()) + { + llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; + } + T* widget = new T(params); + widget->initFromParams(params); + if (parent) + widget->setParent(parent); + return widget; + } + + LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& ); + + static const widget_registry_t& getWidgetRegistry(LLView*); + + template<typename T> + static T* createFromFile(const std::string &filename, LLView *parent, LLXMLNodePtr output_node = NULL) + { + //#pragma message("Generating LLUICtrlFactory::createFromFile") + T* widget = NULL; + + std::string skinned_filename = findSkinnedFilename(filename); + getInstance()->mFileNames.push_back(skinned_filename); + { + LLXMLNodePtr root_node; + + //if exporting, only load the language being exported, + //instead of layering localized version on top of english + if (output_node) + { + if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root_node)) + { + llwarns << "Couldn't parse XUI file: " << filename << llendl; + goto fail; + } + } + else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) + { + llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl; + goto fail; + } + + LLView* view = getInstance()->createFromXML(root_node, parent, filename, output_node, getWidgetRegistry(parent)); + if (view) + { + widget = dynamic_cast<T*>(view); + // not of right type, so delete it + if (!widget) + { + delete view; + view = NULL; + } + + } + } +fail: + getInstance()->mFileNames.pop_back(); + return widget; + } + + template <class T> + static T* createDummyWidget(const std::string& name) + { + //#pragma message("Generating LLUICtrlFactory::createDummyWidget") + typename T::Params params; + params.name(name); + + return create<T>(params); + } + + template<typename T, typename PARAM_BLOCK> + static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) + { + LLFastTimer timer(FTM_WIDGET_SETUP); + + //#pragma message("Generating LLUICtrlFactory::defaultBuilder") + PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>()); + + LLXUIParser::instance().readXUI(node, params); + + if (output_node) + { + // We always want to output top-left coordinates + PARAM_BLOCK output_params(params); + T::setupParamsForExport(output_params, parent); + // Export only the differences between this any default params + PARAM_BLOCK default_params(getDefaultParams<PARAM_BLOCK>()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); + } + + // Apply layout transformations, usually munging rect + T::setupParams(params, parent); + + if (!params.validateBlock()) + { + llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl; + } + T* widget; + { + LLFastTimer timer(FTM_WIDGET_CONSTRUCTION); + widget = new T(params); + } + { + LLFastTimer timer(FTM_INIT_FROM_PARAMS); + widget->initFromParams(params); + } + + if (parent) + { + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + setCtrlParent(widget, parent, tab_group); + } + + createChildren(widget, node, output_node); + + if (!widget->postBuild()) + { + delete widget; + return NULL; + } + + return widget; + } + + static void createChildren(LLView* viewp, LLXMLNodePtr node, LLXMLNodePtr output_node = NULL); static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + + static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root); - static const std::vector<std::string>& getXUIPaths(); + static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); private: - bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root); + //static void setCtrlValue(LLView* view, LLXMLNodePtr node); + static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group); + + // Avoid directly using LLUI and LLDir in the template code + static std::string findSkinnedFilename(const std::string& filename); + + typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t; + factory_stack_t mFactoryStack; + + LLPanel* mDummyPanel; + std::vector<std::string> mFileNames; +}; + +// this is here to make gcc happy with reference to LLUICtrlFactory +template<typename DERIVED> +template<typename T, typename PARAM_BLOCK> +LLWidgetRegistry<DERIVED>::Register<T, PARAM_BLOCK>::Register(const char* tag, LLWidgetCreatorFunc func) +: LLWidgetRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func) +{ + //FIXME: inventory_panel will register itself with LLPanel::Params but it does have its own params...:( + LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag); +} + + +typedef boost::function<LLPanel* (void)> LLPannelClassCreatorFunc; - typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t; - built_panel_t mBuiltPanels; +// local static instance for registering a particular panel class - typedef std::map<LLHandle<LLFloater>, std::string> built_floater_t; - built_floater_t mBuiltFloaters; +class LLRegisterPanelClass +: public LLSingleton< LLRegisterPanelClass > +{ +public: + // reigister with either the provided builder, or the generic templated builder + void addPanelClass(const std::string& tag,LLPannelClassCreatorFunc func) + { + mPannelClassesNames[tag] = func; + } + + LLPanel* createPanelClass(const std::string& tag) + { + param_name_map_t::iterator iT = mPannelClassesNames.find(tag); + if(iT == mPannelClassesNames.end()) + return 0; + return iT->second(); + } + template<typename T> + static T* defaultPanelClassBuilder() + { + T* pT = new T(); + return pT; + } - std::deque<const LLCallbackMap::map_t*> mFactoryStack; +private: + typedef std::map< std::string, LLPannelClassCreatorFunc> param_name_map_t; + + param_name_map_t mPannelClassesNames; +}; - static std::vector<std::string> sXUIPaths; - LLPanel* mDummyPanel; +// local static instance for registering a particular panel class +template<typename T> +class LLRegisterPanelClassWrapper +: public LLRegisterPanelClass +{ +public: + // reigister with either the provided builder, or the generic templated builder + LLRegisterPanelClassWrapper(const std::string& tag); }; +template<typename T> +LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag) +{ + LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>); +} + + #endif //LLUICTRLFACTORY_H |