PageRenderTime 23ms CodeModel.GetById 2ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 27#ifndef LLUICTRLFACTORY_H
 28#define LLUICTRLFACTORY_H
 29
 30#include "llfasttimer.h"
 31#include "llinitparam.h"
 32#include "llregistry.h"
 33#include "llxuiparser.h"
 34
 35class LLView;
 36
 37// sort functor for typeid maps
 38struct LLCompareTypeID
 39{
 40	bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
 41	{
 42		return lhs->before(*rhs);
 43	}
 44};
 45
 46// lookup widget constructor funcs by widget name
 47template <typename DERIVED_TYPE>
 48class LLChildRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>
 49{
 50public:
 51	typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t;
 52	// local static instance for registering a particular widget
 53	template<typename T>
 54	class Register : public super_t::StaticRegistrar
 55	{
 56	public:
 57		// register with either the provided builder, or the generic templated builder
 58		Register(const char* tag, LLWidgetCreatorFunc func = NULL);
 59	};
 60
 61protected:
 62	LLChildRegistry() {}
 63};
 64
 65class LLDefaultChildRegistry : public LLChildRegistry<LLDefaultChildRegistry>
 66{
 67protected:
 68	LLDefaultChildRegistry(){}
 69	friend class LLSingleton<LLDefaultChildRegistry>;
 70};
 71
 72// lookup widget name by type
 73class LLWidgetNameRegistry 
 74:	public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID>
 75{};
 76
 77// lookup function for generating empty param block by widget type
 78// this is used for schema generation
 79//typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();
 80//class LLDefaultParamBlockRegistry
 81//:	public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry, LLCompareTypeID>
 82//{};
 83
 84extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
 85extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
 86extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS;
 87
 88// Build time optimization, generate this once in .cpp file
 89#ifndef LLUICTRLFACTORY_CPP
 90extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance();
 91#endif
 92
 93class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
 94{
 95private:
 96	friend class LLSingleton<LLUICtrlFactory>;
 97	LLUICtrlFactory();
 98	~LLUICtrlFactory();
 99
100	// only partial specialization allowed in inner classes, so use extra dummy parameter
101	template <typename PARAM_BLOCK, int DUMMY>
102	class ParamDefaults : public LLSingleton<ParamDefaults<PARAM_BLOCK, DUMMY> > 
103	{
104	public:
105		ParamDefaults()
106		{
107			// look up template file for this param block...
108			const std::string* param_block_tag = getWidgetTag(&typeid(PARAM_BLOCK));
109			if (param_block_tag)
110			{	// ...and if it exists, back fill values using the most specific template first
111				PARAM_BLOCK params;
112				LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, params);
113				mPrototype.fillFrom(params);
114			}
115			// recursively fill from base class param block
116			((typename PARAM_BLOCK::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename PARAM_BLOCK::base_block_t, DUMMY>::instance().get());
117
118		}
119
120		const PARAM_BLOCK& get() { return mPrototype; }
121
122	private:
123		PARAM_BLOCK mPrototype;
124	};
125
126	// base case for recursion, there are NO base classes of LLInitParam::BaseBlock
127	template<int DUMMY>
128	class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> >
129	{
130	public:
131		const LLInitParam::BaseBlock& get() { return mBaseBlock; }
132	private:
133		LLInitParam::BaseBlock mBaseBlock;
134	};
135
136public:
137
138	// get default parameter block for widget of a specific type
139	template<typename T>
140	static const typename T::Params& getDefaultParams()
141	{
142		//#pragma message("Generating ParamDefaults")
143		return ParamDefaults<typename T::Params, 0>::instance().get();
144	}
145
146	// Does what you want for LLFloaters and LLPanels
147	// Returns 0 on success
148	S32 saveToXML(LLView* viewp, const std::string& filename);
149
150	// filename tracking for debugging info
151	std::string getCurFileName();
152	void pushFileName(const std::string& name);
153	void popFileName();
154
155	template<typename T>
156	static T* create(typename T::Params& params, LLView* parent = NULL)
157	{
158		params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
159
160		T* widget = createWidgetImpl<T>(params, parent);
161		if (widget)
162		{
163			widget->postBuild();
164		}
165
166		return widget;
167	}
168
169	LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t&, LLXMLNodePtr output_node );
170
171	template<typename T>
172	static T* createFromFile(const std::string &filename, LLView *parent, const widget_registry_t& registry, LLXMLNodePtr output_node = NULL)
173	{
174		T* widget = NULL;
175		
176		std::string skinned_filename = findSkinnedFilename(filename);
177		instance().pushFileName(filename);
178		{
179			LLXMLNodePtr root_node;
180
181			//if exporting, only load the language being exported, 			
182			//instead of layering localized version on top of english			
183			if (output_node)			
184			{					
185				if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root_node))				
186				{							
187					llwarns << "Couldn't parse XUI file: " <<  filename  << llendl;					
188					goto fail;				
189				}
190			}
191			else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
192			{
193				llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
194				goto fail;
195			}
196			
197			LLView* view = getInstance()->createFromXML(root_node, parent, filename, registry, output_node);
198			if (view)
199			{
200				widget = dynamic_cast<T*>(view);
201				// not of right type, so delete it
202				if (!widget) 
203				{
204					llwarns << "Widget in " << filename << " was of type " << typeid(view).name() << " instead of expected type " << typeid(T).name() << llendl;
205					delete view;
206					view = NULL;
207				}
208			}
209		}
210fail:
211		instance().popFileName();
212		return widget;
213	}
214
215	template<class T>
216	static T* getDefaultWidget(const std::string& name)
217	{
218		typename T::Params widget_params;
219		widget_params.name = name;
220		return create<T>(widget_params);
221	}
222
223	static void createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t&, LLXMLNodePtr output_node = NULL);
224
225	static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
226	static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
227
228private:
229	//NOTE: both friend declarations are necessary to keep both gcc and msvc happy
230	template <typename T> friend class LLChildRegistry;
231	template <typename T> template <typename U> friend class LLChildRegistry<T>::Register;
232
233	static void copyName(LLXMLNodePtr src, LLXMLNodePtr dest);
234
235	// helper function for adding widget type info to various registries
236	static void registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag);
237
238	static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
239
240	template<typename T>
241	static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL)
242	{
243		T* widget = NULL;
244
245		if (!params.validateBlock())
246		{
247			llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
248			//return NULL;
249		}
250
251		{ LLFastTimer _(FTM_WIDGET_CONSTRUCTION);
252			widget = new T(params);	
253		}
254		{ LLFastTimer _(FTM_INIT_FROM_PARAMS);
255			widget->initFromParams(params);
256		}
257
258		if (parent)
259		{
260			S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : S32_MAX;
261			setCtrlParent(widget, parent, tab_group);
262		}
263		return widget;
264	}
265
266	template<typename T>
267	static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
268	{
269		LLFastTimer timer(FTM_WIDGET_SETUP);
270
271		typename T::Params params(getDefaultParams<T>());
272
273		LLXUIParser parser;
274		parser.readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName());
275
276		if (output_node)
277		{
278			// We always want to output top-left coordinates
279			typename T::Params output_params(params);
280			T::setupParamsForExport(output_params, parent);
281			// Export only the differences between this any default params
282			typename T::Params default_params(getDefaultParams<T>());
283			copyName(node, output_node);
284			parser.writeXUI(output_node, output_params, &default_params);
285		}
286
287		// Apply layout transformations, usually munging rect
288		params.from_xui = true;
289		T::applyXUILayout(params, parent);
290		T* widget = createWidgetImpl<T>(params, parent);
291
292		typedef typename T::child_registry_t registry_t;
293
294		createChildren(widget, node, registry_t::instance(), output_node);
295
296		if (widget && !widget->postBuild())
297		{
298			delete widget;
299			widget = NULL;
300		}
301
302		return widget;
303	}
304
305
306	static const std::string* getWidgetTag(const std::type_info* widget_type);
307
308	// this exists to get around dependency on llview
309	static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);
310
311	// Avoid directly using LLUI and LLDir in the template code
312	static std::string findSkinnedFilename(const std::string& filename);
313
314	class LLPanel*		mDummyPanel;
315	std::vector<std::string>	mFileNames;
316};
317
318// this is here to make gcc happy with reference to LLUICtrlFactory
319template<typename DERIVED>
320template<typename T> 
321LLChildRegistry<DERIVED>::Register<T>::Register(const char* tag, LLWidgetCreatorFunc func)
322:	LLChildRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T> : func)
323{
324	// add this widget to various registries
325	LLUICtrlFactory::instance().registerWidget(&typeid(T), &typeid(typename T::Params), tag);
326	
327	// since registry_t depends on T, do this in line here
328	// TODO: uncomment this for schema generation
329	//typedef typename T::child_registry_t registry_t;
330	//LLChildRegistryRegistry::instance().defaultRegistrar().add(&typeid(T), registry_t::instance());
331}
332
333#endif //LLUICTRLFACTORY_H