00001
00032 #include "linden_common.h"
00033
00034 #include "lluictrlfactory.h"
00035
00036 #include <fstream>
00037 #include <boost/tokenizer.hpp>
00038
00039
00040 #include "llcontrol.h"
00041 #include "lldir.h"
00042 #include "v4color.h"
00043
00044
00045 #include "llbutton.h"
00046 #include "llcheckboxctrl.h"
00047
00048 #include "llcombobox.h"
00049 #include "llcontrol.h"
00050 #include "lldir.h"
00051 #include "llevent.h"
00052 #include "llfloater.h"
00053 #include "lliconctrl.h"
00054 #include "lllineeditor.h"
00055 #include "llmenugl.h"
00056 #include "llradiogroup.h"
00057 #include "llscrollcontainer.h"
00058 #include "llscrollingpanellist.h"
00059 #include "llscrolllistctrl.h"
00060 #include "llslider.h"
00061 #include "llsliderctrl.h"
00062 #include "llmultislider.h"
00063 #include "llmultisliderctrl.h"
00064 #include "llspinctrl.h"
00065 #include "lltabcontainer.h"
00066 #include "lltabcontainervertical.h"
00067 #include "lltextbox.h"
00068 #include "lltexteditor.h"
00069 #include "llui.h"
00070 #include "llviewborder.h"
00071
00072 const char XML_HEADER[] = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n";
00073
00074 const S32 HPAD = 4;
00075 const S32 VPAD = 4;
00076 const S32 FLOATER_H_MARGIN = 15;
00077 const S32 MIN_WIDGET_HEIGHT = 10;
00078
00079 std::vector<LLString> LLUICtrlFactory::mXUIPaths;
00080
00081
00082 class LLUICtrlLocate : public LLUICtrl
00083 {
00084 public:
00085 LLUICtrlLocate() : LLUICtrl("locate", LLRect(0,0,0,0), FALSE, NULL, NULL) { setTabStop(FALSE); }
00086 virtual void draw() { }
00087
00088 static LLView *fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00089 {
00090 LLString name("pad");
00091 node->getAttributeString("name", name);
00092
00093 LLUICtrlLocate *new_ctrl = new LLUICtrlLocate();
00094 new_ctrl->setName(name);
00095 new_ctrl->initFromXML(node, parent);
00096 return new_ctrl;
00097 }
00098 };
00099
00100 static LLRegisterWidget<LLUICtrlLocate> r1("locate");
00101 static LLRegisterWidget<LLUICtrlLocate> r2("pad");
00102
00103
00104
00105
00106 LLUICtrlFactory::LLUICtrlFactory()
00107 : mDummyPanel(NULL)
00108 {
00109 setupPaths();
00110 }
00111
00112 LLUICtrlFactory::~LLUICtrlFactory()
00113 {
00114 delete mDummyPanel;
00115 mDummyPanel = NULL;
00116 }
00117
00118 void LLUICtrlFactory::setupPaths()
00119 {
00120 LLString filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "paths.xml");
00121
00122 LLXMLNodePtr root;
00123 BOOL success = LLXMLNode::parseFile(filename, root, NULL);
00124 mXUIPaths.clear();
00125
00126 if (success)
00127 {
00128 LLXMLNodePtr path;
00129 LLString app_dir = gDirUtilp->getAppRODataDir();
00130
00131 for (path = root->getFirstChild(); path.notNull(); path = path->getNextSibling())
00132 {
00133 LLUIString path_val_ui(path->getValue());
00134 LLString language = "en-us";
00135 if (LLUI::sConfigGroup)
00136 {
00137 language = LLUI::sConfigGroup->getString("Language");
00138 if(language == "default")
00139 {
00140 language = LLUI::sConfigGroup->getString("SystemLanguage");
00141 }
00142 }
00143 path_val_ui.setArg("[Language]", language);
00144 LLString fullpath = app_dir + path_val_ui.getString();
00145
00146 if (std::find(mXUIPaths.begin(), mXUIPaths.end(), fullpath) == mXUIPaths.end())
00147 {
00148 mXUIPaths.push_back(app_dir + path_val_ui.getString());
00149 }
00150 }
00151 }
00152 else
00153 {
00154 LLString slash = gDirUtilp->getDirDelimiter();
00155 LLString dir = gDirUtilp->getAppRODataDir() + slash + "skins" + slash + "xui" + slash + "en-us" + slash;
00156 llwarns << "XUI::config file unable to open." << llendl;
00157 mXUIPaths.push_back(dir);
00158 }
00159 }
00160
00161
00162
00163
00164
00165
00166 bool LLUICtrlFactory::getLayeredXMLNode(const LLString &filename, LLXMLNodePtr& root)
00167 {
00168 if (!LLXMLNode::parseFile(mXUIPaths.front() + filename, root, NULL))
00169 {
00170 if (!LLXMLNode::parseFile(filename, root, NULL))
00171 {
00172 llwarns << "Problem reading UI description file: " << mXUIPaths.front() + filename << llendl;
00173 return FALSE;
00174 }
00175 }
00176
00177 LLXMLNodePtr updateRoot;
00178
00179 std::vector<LLString>::const_iterator itor;
00180
00181 for (itor = mXUIPaths.begin(), ++itor; itor != mXUIPaths.end(); ++itor)
00182 {
00183 LLString nodeName;
00184 LLString updateName;
00185
00186 LLXMLNode::parseFile((*itor) + filename, updateRoot, NULL);
00187
00188 updateRoot->getAttributeString("name", updateName);
00189 root->getAttributeString("name", nodeName);
00190
00191 if (updateName == nodeName)
00192 {
00193 LLXMLNode::updateNode(root, updateRoot);
00194 }
00195 }
00196
00197 return TRUE;
00198 }
00199
00200
00201
00202
00203
00204 void LLUICtrlFactory::buildFloater(LLFloater* floaterp, const LLString &filename,
00205 const LLCallbackMap::map_t* factory_map, BOOL open)
00206 {
00207 LLXMLNodePtr root;
00208
00209 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
00210 {
00211 return;
00212 }
00213
00214
00215 if( !(root->hasName("floater") || root->hasName("multi_floater") ) )
00216 {
00217 llwarns << "Root node should be named floater in: " << filename << llendl;
00218 return;
00219 }
00220
00221 if (factory_map)
00222 {
00223 mFactoryStack.push_front(factory_map);
00224 }
00225
00226 floaterp->initFloaterXML(root, NULL, this, open);
00227
00228 if (LLUI::sShowXUINames)
00229 {
00230 floaterp->setToolTip(filename);
00231 }
00232
00233 if (factory_map)
00234 {
00235 mFactoryStack.pop_front();
00236 }
00237
00238 LLHandle<LLFloater> handle = floaterp->getHandle();
00239 mBuiltFloaters[handle] = filename;
00240 }
00241
00242
00243
00244
00245 S32 LLUICtrlFactory::saveToXML(LLView* viewp, const LLString& filename)
00246 {
00247 llofstream out(filename.c_str());
00248 if (!out.good())
00249 {
00250 llwarns << "Unable to open " << filename << " for output." << llendl;
00251 return 1;
00252 }
00253
00254 out << XML_HEADER;
00255
00256 LLXMLNodePtr xml_node = viewp->getXML();
00257
00258 xml_node->writeToOstream(out);
00259
00260 out.close();
00261 return 0;
00262 }
00263
00264
00265
00266
00267 BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename,
00268 const LLCallbackMap::map_t* factory_map)
00269 {
00270 BOOL didPost = FALSE;
00271 LLXMLNodePtr root;
00272
00273 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
00274 {
00275 return didPost;
00276 }
00277
00278
00279 if( !root->hasName("panel" ) )
00280 {
00281 llwarns << "Root node should be named panel in : " << filename << llendl;
00282 return didPost;
00283 }
00284
00285 if (factory_map)
00286 {
00287 mFactoryStack.push_front(factory_map);
00288 }
00289
00290 didPost = panelp->initPanelXML(root, NULL, this);
00291
00292 if (LLUI::sShowXUINames)
00293 {
00294 panelp->setToolTip(filename);
00295 }
00296
00297 LLHandle<LLPanel> handle = panelp->getHandle();
00298 mBuiltPanels[handle] = filename;
00299
00300 if (factory_map)
00301 {
00302 mFactoryStack.pop_front();
00303 }
00304
00305 return didPost;
00306 }
00307
00308
00309
00310
00311 LLMenuGL *LLUICtrlFactory::buildMenu(const LLString &filename, LLView* parentp)
00312 {
00313
00314 LLXMLNodePtr root;
00315 LLMenuGL* menu;
00316
00317 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
00318 {
00319 return NULL;
00320 }
00321
00322
00323 if( !root->hasName( "menu_bar" ) && !root->hasName( "menu" ))
00324 {
00325 llwarns << "Root node should be named menu bar or menu in : " << filename << llendl;
00326 return NULL;
00327 }
00328
00329 if (root->hasName("menu"))
00330 {
00331 menu = (LLMenuGL*)LLMenuGL::fromXML(root, parentp, this);
00332 }
00333 else
00334 {
00335 menu = (LLMenuGL*)LLMenuBarGL::fromXML(root, parentp, this);
00336 }
00337
00338 if (LLUI::sShowXUINames)
00339 {
00340 menu->setToolTip(filename);
00341 }
00342
00343 return menu;
00344 }
00345
00346
00347
00348
00349 LLPieMenu *LLUICtrlFactory::buildPieMenu(const LLString &filename, LLView* parentp)
00350 {
00351 LLXMLNodePtr root;
00352
00353 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
00354 {
00355 return NULL;
00356 }
00357
00358
00359 if( !root->hasName( LL_PIE_MENU_TAG ))
00360 {
00361 llwarns << "Root node should be named " << LL_PIE_MENU_TAG << " in : " << filename << llendl;
00362 return NULL;
00363 }
00364
00365 LLString name("menu");
00366 root->getAttributeString("name", name);
00367
00368 LLPieMenu *menu = new LLPieMenu(name);
00369 parentp->addChild(menu);
00370 menu->initXML(root, parentp, this);
00371
00372 if (LLUI::sShowXUINames)
00373 {
00374 menu->setToolTip(filename);
00375 }
00376
00377 return menu;
00378 }
00379
00380
00381
00382
00383 void LLUICtrlFactory::rebuild()
00384 {
00385 built_panel_t::iterator built_panel_it;
00386 for (built_panel_it = mBuiltPanels.begin();
00387 built_panel_it != mBuiltPanels.end();
00388 ++built_panel_it)
00389 {
00390 LLString filename = built_panel_it->second;
00391 LLPanel* panelp = built_panel_it->first.get();
00392 if (!panelp)
00393 {
00394 continue;
00395 }
00396 llinfos << "Rebuilding UI panel " << panelp->getName()
00397 << " from " << filename
00398 << llendl;
00399 BOOL visible = panelp->getVisible();
00400 panelp->setVisible(FALSE);
00401 panelp->setFocus(FALSE);
00402 panelp->deleteAllChildren();
00403
00404 buildPanel(panelp, filename.c_str(), &panelp->getFactoryMap());
00405 panelp->setVisible(visible);
00406 }
00407
00408 built_floater_t::iterator built_floater_it;
00409 for (built_floater_it = mBuiltFloaters.begin();
00410 built_floater_it != mBuiltFloaters.end();
00411 ++built_floater_it)
00412 {
00413 LLFloater* floaterp = built_floater_it->first.get();
00414 if (!floaterp)
00415 {
00416 continue;
00417 }
00418 LLString filename = built_floater_it->second;
00419 llinfos << "Rebuilding UI floater " << floaterp->getName()
00420 << " from " << filename
00421 << llendl;
00422 BOOL visible = floaterp->getVisible();
00423 floaterp->setVisible(FALSE);
00424 floaterp->setFocus(FALSE);
00425 floaterp->deleteAllChildren();
00426
00427 gFloaterView->removeChild(floaterp);
00428 buildFloater(floaterp, filename, &floaterp->getFactoryMap());
00429 floaterp->setVisible(visible);
00430 }
00431 }
00432
00433
00434
00435
00436 LLView *LLUICtrlFactory::createCtrlWidget(LLPanel *parent, LLXMLNodePtr node)
00437 {
00438 LLString ctrl_type = node->getName()->mString;
00439 LLString::toLower(ctrl_type);
00440
00441 LLWidgetClassRegistry::factory_func_t func = LLWidgetClassRegistry::getInstance()->getCreatorFunc(ctrl_type);
00442
00443 if (func == NULL)
00444 {
00445 llwarns << "Unknown control type " << ctrl_type << llendl;
00446 return NULL;
00447 }
00448
00449 if (parent == NULL)
00450 {
00451 if (mDummyPanel == NULL)
00452 {
00453 mDummyPanel = new LLPanel;
00454 }
00455 parent = mDummyPanel;
00456 }
00457 LLView *ctrl = func(node, parent, this);
00458
00459 return ctrl;
00460 }
00461
00462 LLView* LLUICtrlFactory::createWidget(LLPanel *parent, LLXMLNodePtr node)
00463 {
00464 LLView* view = createCtrlWidget(parent, node);
00465
00466 S32 tab_group = parent->getLastTabGroup();
00467 node->getAttributeS32("tab_group", tab_group);
00468
00469 if (view)
00470 {
00471 parent->addChild(view, tab_group);
00472 }
00473
00474 return view;
00475 }
00476
00477
00478
00479
00480 LLPanel* LLUICtrlFactory::createFactoryPanel(LLString name)
00481 {
00482 std::deque<const LLCallbackMap::map_t*>::iterator itor;
00483 for (itor = mFactoryStack.begin(); itor != mFactoryStack.end(); ++itor)
00484 {
00485 const LLCallbackMap::map_t* factory_map = *itor;
00486
00487
00488 LLCallbackMap::map_const_iter_t iter = factory_map->find( name );
00489 if (iter != factory_map->end())
00490 {
00491
00492 LLPanel *ret = (LLPanel*) iter->second.mCallback( iter->second.mData );
00493 return ret;
00494 }
00495 }
00496 return NULL;
00497 }
00498
00499
00500
00501
00502 BOOL LLUICtrlFactory::getAttributeColor(LLXMLNodePtr node, const LLString& name, LLColor4& color)
00503 {
00504 LLString colorstring;
00505 BOOL res = node->getAttributeString(name, colorstring);
00506 if (res && LLUI::sColorsGroup)
00507 {
00508 if (LLUI::sColorsGroup->controlExists(colorstring))
00509 {
00510 color.setVec(LLUI::sColorsGroup->getColor(colorstring));
00511 }
00512 else
00513 {
00514 res = FALSE;
00515 }
00516 }
00517 if (!res)
00518 {
00519 res = LLColor4::parseColor(colorstring.c_str(), &color);
00520 }
00521 if (!res)
00522 {
00523 res = node->getAttributeColor(name, color);
00524 }
00525 return res;
00526 }
00527