/indra/llui/lluictrlfactory.h

https://bitbucket.org/lindenlab/viewer-beta/ · C++ Header · 333 lines · 213 code · 57 blank · 63 comment · 13 complexity · 9c7089f7b91b93da95a6f63bce5a091f MD5 · raw file

  1. /**
  2. * @file lluictrlfactory.h
  3. * @brief Factory class for creating UI controls
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #ifndef LLUICTRLFACTORY_H
  27. #define LLUICTRLFACTORY_H
  28. #include "llfasttimer.h"
  29. #include "llinitparam.h"
  30. #include "llregistry.h"
  31. #include "llxuiparser.h"
  32. class LLView;
  33. // sort functor for typeid maps
  34. struct LLCompareTypeID
  35. {
  36. bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
  37. {
  38. return lhs->before(*rhs);
  39. }
  40. };
  41. // lookup widget constructor funcs by widget name
  42. template <typename DERIVED_TYPE>
  43. class LLChildRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>
  44. {
  45. public:
  46. typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t;
  47. // local static instance for registering a particular widget
  48. template<typename T>
  49. class Register : public super_t::StaticRegistrar
  50. {
  51. public:
  52. // register with either the provided builder, or the generic templated builder
  53. Register(const char* tag, LLWidgetCreatorFunc func = NULL);
  54. };
  55. protected:
  56. LLChildRegistry() {}
  57. };
  58. class LLDefaultChildRegistry : public LLChildRegistry<LLDefaultChildRegistry>
  59. {
  60. protected:
  61. LLDefaultChildRegistry(){}
  62. friend class LLSingleton<LLDefaultChildRegistry>;
  63. };
  64. // lookup widget name by type
  65. class LLWidgetNameRegistry
  66. : public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID>
  67. {};
  68. // lookup function for generating empty param block by widget type
  69. // this is used for schema generation
  70. //typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
  71. //class LLDefaultParamBlockRegistry
  72. //: public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry, LLCompareTypeID>
  73. //{};
  74. extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
  75. extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
  76. extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS;
  77. // Build time optimization, generate this once in .cpp file
  78. #ifndef LLUICTRLFACTORY_CPP
  79. extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance();
  80. #endif
  81. class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
  82. {
  83. private:
  84. friend class LLSingleton<LLUICtrlFactory>;
  85. LLUICtrlFactory();
  86. ~LLUICtrlFactory();
  87. // only partial specialization allowed in inner classes, so use extra dummy parameter
  88. template <typename PARAM_BLOCK, int DUMMY>
  89. class ParamDefaults : public LLSingleton<ParamDefaults<PARAM_BLOCK, DUMMY> >
  90. {
  91. public:
  92. ParamDefaults()
  93. {
  94. // look up template file for this param block...
  95. const std::string* param_block_tag = getWidgetTag(&typeid(PARAM_BLOCK));
  96. if (param_block_tag)
  97. { // ...and if it exists, back fill values using the most specific template first
  98. PARAM_BLOCK params;
  99. LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, params);
  100. mPrototype.fillFrom(params);
  101. }
  102. // recursively fill from base class param block
  103. ((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY>::instance().get());
  104. }
  105. const PARAM_BLOCK& get() { return mPrototype; }
  106. private:
  107. PARAM_BLOCK mPrototype;
  108. };
  109. // base case for recursion, there are NO base classes of LLInitParam::BaseBlock
  110. template<int DUMMY>
  111. class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> >
  112. {
  113. public:
  114. const LLInitParam::BaseBlock& get() { return mBaseBlock; }
  115. private:
  116. LLInitParam::BaseBlock mBaseBlock;
  117. };
  118. public:
  119. // get default parameter block for widget of a specific type
  120. template<typename T>
  121. static const typename T::Params& getDefaultParams()
  122. {
  123. //#pragma message("Generating ParamDefaults")
  124. return ParamDefaults<typename T::Params, 0>::instance().get();
  125. }
  126. // Does what you want for LLFloaters and LLPanels
  127. // Returns 0 on success
  128. S32 saveToXML(LLView* viewp, const std::string& filename);
  129. // filename tracking for debugging info
  130. std::string getCurFileName();
  131. void pushFileName(const std::string& name);
  132. void popFileName();
  133. template<typename T>
  134. static T* create(typename T::Params& params, LLView* parent = NULL)
  135. {
  136. params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
  137. T* widget = createWidgetImpl<T>(params, parent);
  138. if (widget)
  139. {
  140. widget->postBuild();
  141. }
  142. return widget;
  143. }
  144. LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t&, LLXMLNodePtr output_node );
  145. template<typename T>
  146. static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry, LLXMLNodePtr output_node = NULL)
  147. {
  148. T* widget = NULL;
  149. std::string skinned_filename = findSkinnedFilename(filename);
  150. instance().pushFileName(filename);
  151. {
  152. LLXMLNodePtr root_node;
  153. //if exporting, only load the language being exported,
  154. //instead of layering localized version on top of english
  155. if (output_node)
  156. {
  157. if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root_node))
  158. {
  159. llwarns << "Couldn't parse XUI file: " << filename << llendl;
  160. goto fail;
  161. }
  162. }
  163. else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
  164. {
  165. llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
  166. goto fail;
  167. }
  168. LLView* view = getInstance()->createFromXML(root_node, parent, filename, registry, output_node);
  169. if (view)
  170. {
  171. widget = dynamic_cast<T*>(view);
  172. // not of right type, so delete it
  173. if (!widget)
  174. {
  175. llwarns << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << llendl;
  176. delete view;
  177. view = NULL;
  178. }
  179. }
  180. }
  181. fail:
  182. instance().popFileName();
  183. return widget;
  184. }
  185. template<class T>
  186. static T* getDefaultWidget(const std::string& name)
  187. {
  188. typename T::Params widget_params;
  189. widget_params.name = name;
  190. return create<T>(widget_params);
  191. }
  192. static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
  193. static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
  194. static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
  195. private:
  196. //NOTE: both friend declarations are necessary to keep both gcc and msvc happy
  197. template <typename T> friend class LLChildRegistry;
  198. template <typename T> template <typename U> friend class LLChildRegistry<T>::Register;
  199. static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
  200. // helper function for adding widget type info to various registries
  201. static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
  202. static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
  203. template<typename T>
  204. static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
  205. {
  206. T* widget = NULL;
  207. if (!params.validateBlock())
  208. {
  209. llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
  210. //return NULL;
  211. }
  212. { LLFastTimer _(FTM_WIDGET_CONSTRUCTION);
  213. widget = new T(params);
  214. }
  215. { LLFastTimer _(FTM_INIT_FROM_PARAMS);
  216. widget->initFromParams(params);
  217. }
  218. if (parent)
  219. {
  220. S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
  221. setCtrlParent(widget, parent, tab_group);
  222. }
  223. return widget;
  224. }
  225. template<typename T>
  226. static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
  227. {
  228. LLFastTimer timer(FTM_WIDGET_SETUP);
  229. typename T::Params params(getDefaultParams<T>());
  230. LLXUIParser parser;
  231. parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
  232. if (output_node)
  233. {
  234. // We always want to output top-left coordinates
  235. typename T::Params output_params(params);
  236. T::setupParamsForExport(output_params, parent);
  237. // Export only the differences between this any default params
  238. typename T::Params default_params(getDefaultParams<T>());
  239. copyName(node, output_node);
  240. parser.writeXUI(output_node, output_params, &default_params);
  241. }
  242. // Apply layout transformations, usually munging rect
  243. params.from_xui = true;
  244. T::applyXUILayout(params, parent);
  245. T* widget = createWidgetImpl<T>(params, parent);
  246. typedef typename T::child_registry_t registry_t;
  247. createChildren(widget, node, registry_t::instance(), output_node);
  248. if (widget && !widget->postBuild())
  249. {
  250. delete widget;
  251. widget = NULL;
  252. }
  253. return widget;
  254. }
  255. static const std::string* getWidgetTag(const std::type_info* widget_type);
  256. // this exists to get around dependency on llview
  257. static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);
  258. // Avoid directly using LLUI and LLDir in the template code
  259. static std::string findSkinnedFilename(const std::string& filename);
  260. class LLPanel* mDummyPanel;
  261. std::vector<std::string> mFileNames;
  262. };
  263. // this is here to make gcc happy with reference to LLUICtrlFactory
  264. template<typename DERIVED>
  265. template<typename T>
  266. LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreatorFunc func)
  267. : LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
  268. {
  269. // add this widget to various registries
  270. LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
  271. // since registry_t depends on T, do this in line here
  272. // TODO: uncomment this for schema generation
  273. //typedef typename T::child_registry_t registry_t;
  274. //LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
  275. }
  276. #endif //LLUICTRLFACTORY_H