lluictrlfactory.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:14k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lluictrlfactory.cpp
  3.  * @brief Factory class for creating UI controls
  4.  *
  5.  * $LicenseInfo:firstyear=2003&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2003-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #define LLUICTRLFACTORY_CPP
  34. #include "lluictrlfactory.h"
  35. #include "llxmlnode.h"
  36. #include <fstream>
  37. #include <boost/tokenizer.hpp>
  38. // other library includes
  39. #include "llcontrol.h"
  40. #include "lldir.h"
  41. #include "v4color.h"
  42. #include "v3dmath.h"
  43. #include "llquaternion.h"
  44. // this library includes
  45. #include "llfloater.h"
  46. LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction");
  47. LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams");
  48. LLFastTimer::DeclareTimer FTM_WIDGET_SETUP("Widget Setup");
  49. //-----------------------------------------------------------------------------
  50. // UI Ctrl class for padding
  51. class LLUICtrlLocate : public LLUICtrl
  52. {
  53. public:
  54. struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
  55. {
  56. Params()
  57. {
  58. name = "locate";
  59. tab_stop = false;
  60. }
  61. };
  62. LLUICtrlLocate(const Params& p) : LLUICtrl(p) {}
  63. virtual void draw() { }
  64. };
  65. static LLDefaultChildRegistry::Register<LLUICtrlLocate> r1("locate");
  66. // Build time optimization, generate this once in .cpp file
  67. template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance();
  68. //-----------------------------------------------------------------------------
  69. // LLUICtrlFactory()
  70. //-----------------------------------------------------------------------------
  71. LLUICtrlFactory::LLUICtrlFactory()
  72. : mDummyPanel(NULL) // instantiated when first needed
  73. {
  74. }
  75. LLUICtrlFactory::~LLUICtrlFactory()
  76. {
  77. // go ahead and leak mDummyPanel since this is static destructor time
  78. //delete mDummyPanel;
  79. //mDummyPanel = NULL;
  80. }
  81. void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block)
  82. {
  83. std::string filename = std::string("widgets") + gDirUtilp->getDirDelimiter() + widget_tag + ".xml";
  84. LLXMLNodePtr root_node;
  85. if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
  86. {
  87. LLXUIParser::instance().readXUI(root_node, block, filename);
  88. }
  89. }
  90. static LLFastTimer::DeclareTimer FTM_CREATE_CHILDREN("Create XUI Children");
  91. //static 
  92. void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node)
  93. {
  94. LLFastTimer ft(FTM_CREATE_CHILDREN);
  95. if (node.isNull()) return;
  96. for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling())
  97. {
  98. LLXMLNodePtr outputChild;
  99. if (output_node) 
  100. {
  101. outputChild = output_node->createChild("", FALSE);
  102. }
  103. if (!instance().createFromXML(child_node, viewp, LLStringUtil::null, registry, outputChild))
  104. {
  105. // child_node is not a valid child for the current parent
  106. std::string child_name = std::string(child_node->getName()->mString);
  107. if (LLDefaultChildRegistry::instance().getValue(child_name))
  108. {
  109. // This means that the registry assocaited with the parent widget does not have an entry
  110. // for the child widget
  111. // You might need to add something like:
  112. // static ParentWidgetRegistry::Register<ChildWidgetType> register("child_widget_name");
  113. llwarns << child_name << " is not a valid child of " << node->getName()->mString << llendl;
  114. }
  115. else
  116. {
  117. llwarns << "Could not create widget named " << child_node->getName()->mString << llendl;
  118. }
  119. }
  120. if (outputChild && !outputChild->mChildren && outputChild->mAttributes.empty() && outputChild->getValue().empty())
  121. {
  122. output_node->deleteChild(outputChild);
  123. }
  124. }
  125. }
  126. static LLFastTimer::DeclareTimer FTM_XML_PARSE("XML Reading/Parsing");
  127. //-----------------------------------------------------------------------------
  128. // getLayeredXMLNode()
  129. //-----------------------------------------------------------------------------
  130. bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
  131. {
  132. LLFastTimer timer(FTM_XML_PARSE);
  133. return LLXMLNode::getLayeredXMLNode(xui_filename, root, LLUI::getXUIPaths());
  134. }
  135. //-----------------------------------------------------------------------------
  136. // getLocalizedXMLNode()
  137. //-----------------------------------------------------------------------------
  138. bool LLUICtrlFactory::getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root)
  139. {
  140. LLFastTimer timer(FTM_XML_PARSE);
  141. std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), xui_filename);
  142. if (!LLXMLNode::parseFile(full_filename, root, NULL))
  143. {
  144. return false;
  145. }
  146. else
  147. {
  148. return true;
  149. }
  150. }
  151. static LLFastTimer::DeclareTimer FTM_BUILD_FLOATERS("Build Floaters");
  152. //-----------------------------------------------------------------------------
  153. // buildFloater()
  154. //-----------------------------------------------------------------------------
  155. bool LLUICtrlFactory::buildFloater(LLFloater* floaterp, const std::string& filename, LLXMLNodePtr output_node)
  156. {
  157. LLFastTimer timer(FTM_BUILD_FLOATERS);
  158. LLXMLNodePtr root;
  159. //if exporting, only load the language being exported, 
  160. //instead of layering localized version on top of english
  161. if (output_node)
  162. {
  163. if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
  164. {
  165. llwarns << "Couldn't parse floater from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
  166. return false;
  167. }
  168. }
  169. else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
  170. {
  171. llwarns << "Couldn't parse floater from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
  172. return false;
  173. }
  174. // root must be called floater
  175. if( !(root->hasName("floater") || root->hasName("multi_floater")) )
  176. {
  177. llwarns << "Root node should be named floater in: " << filename << llendl;
  178. return false;
  179. }
  180. bool res = true;
  181. lldebugs << "Building floater " << filename << llendl;
  182. mFileNames.push_back(gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename));
  183. {
  184. if (!floaterp->getFactoryMap().empty())
  185. {
  186. mFactoryStack.push_front(&floaterp->getFactoryMap());
  187. }
  188.  // for local registry callbacks; define in constructor, referenced in XUI or postBuild
  189. floaterp->getCommitCallbackRegistrar().pushScope();
  190. floaterp->getEnableCallbackRegistrar().pushScope();
  191. res = floaterp->initFloaterXML(root, floaterp->getParent(), output_node);
  192. floaterp->setXMLFilename(filename);
  193. floaterp->getCommitCallbackRegistrar().popScope();
  194. floaterp->getEnableCallbackRegistrar().popScope();
  195. if (!floaterp->getFactoryMap().empty())
  196. {
  197. mFactoryStack.pop_front();
  198. }
  199. }
  200. mFileNames.pop_back();
  201. return res;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // saveToXML()
  205. //-----------------------------------------------------------------------------
  206. S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename)
  207. {
  208. return 0;
  209. }
  210. static LLFastTimer::DeclareTimer FTM_BUILD_PANELS("Build Panels");
  211. //-----------------------------------------------------------------------------
  212. // buildPanel()
  213. //-----------------------------------------------------------------------------
  214. BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const std::string& filename, LLXMLNodePtr output_node)
  215. {
  216. LLFastTimer timer(FTM_BUILD_PANELS);
  217. BOOL didPost = FALSE;
  218. LLXMLNodePtr root;
  219. //if exporting, only load the language being exported, 
  220. //instead of layering localized version on top of english
  221. if (output_node)
  222. {
  223. if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root))
  224. {
  225. llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename  << llendl;
  226. return didPost;
  227. }
  228. }
  229. else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
  230. {
  231. llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl;
  232. return didPost;
  233. }
  234. // root must be called panel
  235. if( !root->hasName("panel" ) )
  236. {
  237. llwarns << "Root node should be named panel in : " << filename << llendl;
  238. return didPost;
  239. }
  240. lldebugs << "Building panel " << filename << llendl;
  241. mFileNames.push_back(gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename));
  242. {
  243. if (!panelp->getFactoryMap().empty())
  244. {
  245. mFactoryStack.push_front(&panelp->getFactoryMap());
  246. }
  247.  // for local registry callbacks; define in constructor, referenced in XUI or postBuild
  248. panelp->getCommitCallbackRegistrar().pushScope();
  249. panelp->getEnableCallbackRegistrar().pushScope();
  250. didPost = panelp->initPanelXML(root, NULL, output_node);
  251. panelp->getCommitCallbackRegistrar().popScope();
  252. panelp->getEnableCallbackRegistrar().popScope();
  253. panelp->setXMLFilename(filename);
  254. if (!panelp->getFactoryMap().empty())
  255. {
  256. mFactoryStack.pop_front();
  257. }
  258. }
  259. mFileNames.pop_back();
  260. return didPost;
  261. }
  262. //-----------------------------------------------------------------------------
  263. //-----------------------------------------------------------------------------
  264. static LLFastTimer::DeclareTimer FTM_CREATE_FROM_XML("Create child widget");
  265. LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node)
  266. {
  267. LLFastTimer timer(FTM_CREATE_FROM_XML);
  268. std::string ctrl_type = node->getName()->mString;
  269. LLStringUtil::toLower(ctrl_type);
  270. const LLWidgetCreatorFunc* funcp = registry.getValue(ctrl_type);
  271. if (funcp == NULL)
  272. {
  273. return NULL;
  274. }
  275. if (parent == NULL)
  276. {
  277. if (mDummyPanel == NULL)
  278. {
  279. LLPanel::Params p;
  280. mDummyPanel = create<LLPanel>(p);
  281. }
  282. parent = mDummyPanel;
  283. }
  284. LLView *view = (*funcp)(node, parent, output_node);
  285. return view;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // createFactoryPanel()
  289. //-----------------------------------------------------------------------------
  290. LLPanel* LLUICtrlFactory::createFactoryPanel(const std::string& name)
  291. {
  292. std::deque<const LLCallbackMap::map_t*>::iterator itor;
  293. for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
  294. {
  295. const LLCallbackMap::map_t* factory_map = *itor;
  296. // Look up this panel's name in the map.
  297. LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
  298. if (iter != factory_map->end())
  299. {
  300. // Use the factory to create the panel, instead of using a default LLPanel.
  301. LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
  302. return ret;
  303. }
  304. }
  305. LLPanel::Params panel_p;
  306. return create<LLPanel>(panel_p);
  307. }
  308. //-----------------------------------------------------------------------------
  309. //static
  310. BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color)
  311. {
  312. std::string colorstring;
  313. BOOL res = node->getAttributeString(name.c_str(), colorstring);
  314. if (res)
  315. {
  316. if (LLUIColorTable::instance().colorExists(colorstring))
  317. {
  318. color.setVec(LLUIColorTable::instance().getColor(colorstring));
  319. }
  320. else
  321. {
  322. res = FALSE;
  323. }
  324. }
  325. if (!res)
  326. {
  327. res = LLColor4::parseColor(colorstring, &color);
  328. }
  329. if (!res)
  330. {
  331. res = node->getAttributeColor(name.c_str(), color);
  332. }
  333. return res;
  334. }
  335. //static
  336. void LLUICtrlFactory::setCtrlParent(LLView* view, LLView* parent, S32 tab_group)
  337. {
  338. if (tab_group == S32_MAX) tab_group = parent->getLastTabGroup();
  339. parent->addChild(view, tab_group);
  340. }
  341. // Avoid directly using LLUI and LLDir in the template code
  342. //static
  343. std::string LLUICtrlFactory::findSkinnedFilename(const std::string& filename)
  344. {
  345. return gDirUtilp->findSkinnedFilename(LLUI::getSkinPath(), filename);
  346. }
  347. void LLUICtrlFactory::pushFactoryFunctions(const LLCallbackMap::map_t* map)
  348. {
  349. mFactoryStack.push_back(map);
  350. }
  351. void LLUICtrlFactory::popFactoryFunctions()
  352. {
  353. if (!mFactoryStack.empty())
  354. {
  355. mFactoryStack.pop_back();
  356. }
  357. }
  358. //static 
  359. void LLUICtrlFactory::copyName(LLXMLNodePtr src, LLXMLNodePtr dest)
  360. {
  361. dest->setName(src->getName()->mString);
  362. }
  363. // adds a widget and its param block to various registries
  364. //static 
  365. void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, dummy_widget_creator_func_t creator_func, const std::string& tag)
  366. {
  367. // associate parameter block type with template .xml file
  368. std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
  369. if (existing_tag != NULL && *existing_tag != tag)
  370. {
  371. llerrs << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << llendl;
  372. }
  373. LLWidgetNameRegistry ::instance().defaultRegistrar().add(param_block_type, tag);
  374. // associate widget type with factory function
  375. LLDefaultWidgetRegistry::instance().defaultRegistrar().add(widget_type, creator_func);
  376. //FIXME: comment this in when working on schema generation
  377. //LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type);
  378. //LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &getEmptyParamBlock<T>);
  379. }
  380. //static
  381. dummy_widget_creator_func_t* LLUICtrlFactory::getDefaultWidgetFunc(const std::type_info* widget_type)
  382. {
  383. return LLDefaultWidgetRegistry::instance().getValue(widget_type);
  384. }
  385. //static 
  386. const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_type)
  387. {
  388. return LLWidgetNameRegistry::instance().getValue(widget_type);
  389. }