/indra/llui/llfloaterreg.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 507 lines · 375 code · 54 blank · 78 comment · 73 complexity · 255d9f5c14c2d0695c1d28b4b78f8830 MD5 · raw file

  1. /**
  2. * @file llfloaterreg.cpp
  3. * @brief LLFloaterReg Floater Registration Class
  4. *
  5. * $LicenseInfo:firstyear=2002&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. #include "linden_common.h"
  27. #include "llfloaterreg.h"
  28. //#include "llagent.h"
  29. #include "llfloater.h"
  30. #include "llmultifloater.h"
  31. #include "llfloaterreglistener.h"
  32. //*******************************************************
  33. //static
  34. LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList;
  35. LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap;
  36. LLFloaterReg::build_map_t LLFloaterReg::sBuildMap;
  37. std::map<std::string,std::string> LLFloaterReg::sGroupMap;
  38. bool LLFloaterReg::sBlockShowFloaters = false;
  39. std::set<std::string> LLFloaterReg::sAlwaysShowableList;
  40. static LLFloaterRegListener sFloaterRegListener;
  41. //*******************************************************
  42. //static
  43. void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname)
  44. {
  45. sBuildMap[name].mFunc = func;
  46. sBuildMap[name].mFile = filename;
  47. sGroupMap[name] = groupname.empty() ? name : groupname;
  48. sGroupMap[groupname] = groupname; // for referencing directly by group name
  49. }
  50. //static
  51. LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
  52. {
  53. const std::string& groupname = sGroupMap[name];
  54. if (!groupname.empty())
  55. {
  56. instance_list_t& list = sInstanceMap[groupname];
  57. if (!list.empty())
  58. {
  59. for (instance_list_t::reverse_iterator iter = list.rbegin(); iter != list.rend(); ++iter)
  60. {
  61. LLFloater* inst = *iter;
  62. if (inst->getVisible() && !inst->isMinimized())
  63. {
  64. return inst;
  65. }
  66. }
  67. }
  68. }
  69. return NULL;
  70. }
  71. LLFloater* LLFloaterReg::getLastFloaterCascading()
  72. {
  73. LLRect candidate_rect;
  74. candidate_rect.mTop = 100000;
  75. LLFloater* candidate_floater = NULL;
  76. std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
  77. for( ; it != it_end; ++it)
  78. {
  79. const std::string& group_name = it->second;
  80. instance_list_t& instances = sInstanceMap[group_name];
  81. for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
  82. {
  83. LLFloater* inst = *iter;
  84. if (inst->getVisible() && inst->isPositioning(LLFloaterEnums::OPEN_POSITIONING_CASCADING))
  85. {
  86. if (candidate_rect.mTop > inst->getRect().mTop)
  87. {
  88. candidate_floater = inst;
  89. candidate_rect = inst->getRect();
  90. }
  91. }
  92. }
  93. }
  94. return candidate_floater;
  95. }
  96. //static
  97. LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key)
  98. {
  99. LLFloater* res = NULL;
  100. const std::string& groupname = sGroupMap[name];
  101. if (!groupname.empty())
  102. {
  103. instance_list_t& list = sInstanceMap[groupname];
  104. for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
  105. {
  106. LLFloater* inst = *iter;
  107. if (inst->matchesKey(key))
  108. {
  109. res = inst;
  110. break;
  111. }
  112. }
  113. }
  114. return res;
  115. }
  116. //static
  117. LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key)
  118. {
  119. LLFloater* res = findInstance(name, key);
  120. if (!res)
  121. {
  122. const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc;
  123. const std::string& xui_file = sBuildMap[name].mFile;
  124. if (build_func)
  125. {
  126. const std::string& groupname = sGroupMap[name];
  127. if (!groupname.empty())
  128. {
  129. instance_list_t& list = sInstanceMap[groupname];
  130. res = build_func(key);
  131. if (!res)
  132. {
  133. llwarns << "Failed to build floater type: '" << name << "'." << llendl;
  134. return NULL;
  135. }
  136. bool success = res->buildFromFile(xui_file, NULL);
  137. if (!success)
  138. {
  139. llwarns << "Failed to build floater type: '" << name << "'." << llendl;
  140. return NULL;
  141. }
  142. // Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe
  143. if (res->mKey.isUndefined())
  144. {
  145. res->mKey = key;
  146. }
  147. res->setInstanceName(name);
  148. LLFloater *last_floater = (list.empty() ? NULL : list.back());
  149. res->applyControlsAndPosition(last_floater);
  150. gFloaterView->adjustToFitScreen(res, false);
  151. list.push_back(res);
  152. }
  153. }
  154. if (!res)
  155. {
  156. llwarns << "Floater type: '" << name << "' not registered." << llendl;
  157. }
  158. }
  159. return res;
  160. }
  161. //static
  162. LLFloater* LLFloaterReg::removeInstance(const std::string& name, const LLSD& key)
  163. {
  164. LLFloater* res = NULL;
  165. const std::string& groupname = sGroupMap[name];
  166. if (!groupname.empty())
  167. {
  168. instance_list_t& list = sInstanceMap[groupname];
  169. for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
  170. {
  171. LLFloater* inst = *iter;
  172. if (inst->matchesKey(key))
  173. {
  174. res = inst;
  175. list.erase(iter);
  176. break;
  177. }
  178. }
  179. }
  180. return res;
  181. }
  182. //static
  183. // returns true if the instance existed
  184. bool LLFloaterReg::destroyInstance(const std::string& name, const LLSD& key)
  185. {
  186. LLFloater* inst = removeInstance(name, key);
  187. if (inst)
  188. {
  189. delete inst;
  190. return true;
  191. }
  192. else
  193. {
  194. return false;
  195. }
  196. }
  197. // Iterators
  198. //static
  199. LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::string& name)
  200. {
  201. instance_map_t::iterator iter = sInstanceMap.find(name);
  202. if (iter != sInstanceMap.end())
  203. {
  204. return iter->second;
  205. }
  206. else
  207. {
  208. return sNullInstanceList;
  209. }
  210. }
  211. // Visibility Management
  212. //static
  213. LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
  214. {
  215. if( sBlockShowFloaters
  216. // see EXT-7090
  217. && sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
  218. return 0;//
  219. LLFloater* instance = getInstance(name, key);
  220. if (instance)
  221. {
  222. instance->openFloater(key);
  223. if (focus)
  224. instance->setFocus(TRUE);
  225. }
  226. return instance;
  227. }
  228. //static
  229. // returns true if the instance exists
  230. bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
  231. {
  232. LLFloater* instance = findInstance(name, key);
  233. if (instance)
  234. {
  235. // When toggling *visibility*, close the host instead of the floater when hosted
  236. if (instance->getHost())
  237. instance->getHost()->closeFloater();
  238. else
  239. instance->closeFloater();
  240. return true;
  241. }
  242. else
  243. {
  244. return false;
  245. }
  246. }
  247. //static
  248. // returns true if the instance is visible when completed
  249. bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
  250. {
  251. LLFloater* instance = findInstance(name, key);
  252. if (LLFloater::isShown(instance))
  253. {
  254. // When toggling *visibility*, close the host instead of the floater when hosted
  255. if (instance->getHost())
  256. instance->getHost()->closeFloater();
  257. else
  258. instance->closeFloater();
  259. return false;
  260. }
  261. else
  262. {
  263. return showInstance(name, key, TRUE) ? true : false;
  264. }
  265. }
  266. //static
  267. // returns true if the instance exists and is visible (doesnt matter minimized or not)
  268. bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key)
  269. {
  270. LLFloater* instance = findInstance(name, key);
  271. return LLFloater::isVisible(instance);
  272. }
  273. //static
  274. void LLFloaterReg::showInitialVisibleInstances()
  275. {
  276. // Iterate through alll registered instance names and show any with a save visible state
  277. for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
  278. {
  279. const std::string& name = iter->first;
  280. std::string controlname = getVisibilityControlName(name);
  281. if (LLFloater::getControlGroup()->controlExists(controlname))
  282. {
  283. BOOL isvis = LLFloater::getControlGroup()->getBOOL(controlname);
  284. if (isvis)
  285. {
  286. showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true
  287. }
  288. }
  289. }
  290. }
  291. //static
  292. void LLFloaterReg::hideVisibleInstances(const std::set<std::string>& exceptions)
  293. {
  294. // Iterate through alll active instances and hide them
  295. for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
  296. {
  297. const std::string& name = iter->first;
  298. if (exceptions.find(name) != exceptions.end())
  299. continue;
  300. instance_list_t& list = iter->second;
  301. for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
  302. {
  303. LLFloater* floater = *iter;
  304. floater->pushVisible(FALSE);
  305. }
  306. }
  307. }
  308. //static
  309. void LLFloaterReg::restoreVisibleInstances()
  310. {
  311. // Iterate through all active instances and restore visibility
  312. for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter)
  313. {
  314. instance_list_t& list = iter->second;
  315. for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter)
  316. {
  317. LLFloater* floater = *iter;
  318. floater->popVisible();
  319. }
  320. }
  321. }
  322. //static
  323. std::string LLFloaterReg::getRectControlName(const std::string& name)
  324. {
  325. std::string res = std::string("floater_rect_") + name;
  326. LLStringUtil::replaceChar( res, ' ', '_' );
  327. return res;
  328. }
  329. //static
  330. std::string LLFloaterReg::declareRectControl(const std::string& name)
  331. {
  332. std::string controlname = getRectControlName(name);
  333. LLFloater::getControlGroup()->declareRect(controlname, LLRect(),
  334. llformat("Window Position and Size for %s", name.c_str()),
  335. TRUE);
  336. return controlname;
  337. }
  338. //static
  339. std::string LLFloaterReg::getVisibilityControlName(const std::string& name)
  340. {
  341. std::string res = std::string("floater_vis_") + name;
  342. LLStringUtil::replaceChar( res, ' ', '_' );
  343. return res;
  344. }
  345. //static
  346. std::string LLFloaterReg::declareVisibilityControl(const std::string& name)
  347. {
  348. std::string controlname = getVisibilityControlName(name);
  349. LLFloater::getControlGroup()->declareBOOL(controlname, FALSE,
  350. llformat("Window Visibility for %s", name.c_str()),
  351. TRUE);
  352. return controlname;
  353. }
  354. //static
  355. std::string LLFloaterReg::declareDockStateControl(const std::string& name)
  356. {
  357. std::string controlname = getDockStateControlName(name);
  358. LLFloater::getControlGroup()->declareBOOL(controlname, TRUE,
  359. llformat("Window Docking state for %s", name.c_str()),
  360. TRUE);
  361. return controlname;
  362. }
  363. //static
  364. std::string LLFloaterReg::getDockStateControlName(const std::string& name)
  365. {
  366. std::string res = std::string("floater_dock_") + name;
  367. LLStringUtil::replaceChar( res, ' ', '_' );
  368. return res;
  369. }
  370. //static
  371. void LLFloaterReg::registerControlVariables()
  372. {
  373. // Iterate through alll registered instance names and register rect and visibility control variables
  374. for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter)
  375. {
  376. const std::string& name = iter->first;
  377. if (LLFloater::getControlGroup()->controlExists(getRectControlName(name)))
  378. {
  379. declareRectControl(name);
  380. }
  381. if (LLFloater::getControlGroup()->controlExists(getVisibilityControlName(name)))
  382. {
  383. declareVisibilityControl(name);
  384. }
  385. }
  386. const LLSD& exclude_list = LLUI::sSettingGroups["config"]->getLLSD("always_showable_floaters");
  387. for (LLSD::array_const_iterator iter = exclude_list.beginArray();
  388. iter != exclude_list.endArray();
  389. iter++)
  390. {
  391. sAlwaysShowableList.insert(iter->asString());
  392. }
  393. }
  394. //static
  395. void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD& key)
  396. {
  397. //
  398. // Floaters controlled by the toolbar behave a bit differently from others.
  399. // Namely they have 3-4 states as defined in the design wiki page here:
  400. // https://wiki.lindenlab.com/wiki/FUI_Button_states
  401. //
  402. // The basic idea is this:
  403. // * If the target floater is minimized, this button press will un-minimize it.
  404. // * Else if the target floater is closed open it.
  405. // * Else if the target floater does not have focus, give it focus.
  406. // * Also, if it is not on top, bring it forward when focus is given.
  407. // * Else the target floater is open, close it.
  408. //
  409. std::string name = sdname.asString();
  410. LLFloater* instance = getInstance(name, key);
  411. if (!instance)
  412. {
  413. lldebugs << "Unable to get instance of floater '" << name << "'" << llendl;
  414. }
  415. else if (instance->isMinimized())
  416. {
  417. instance->setMinimized(FALSE);
  418. instance->setVisibleAndFrontmost();
  419. }
  420. else if (!instance->isShown())
  421. {
  422. instance->openFloater(key);
  423. instance->setVisibleAndFrontmost();
  424. }
  425. else if (!instance->isFrontmost())
  426. {
  427. instance->setVisibleAndFrontmost();
  428. }
  429. else
  430. {
  431. instance->closeFloater();
  432. }
  433. }
  434. // static
  435. U32 LLFloaterReg::getVisibleFloaterInstanceCount()
  436. {
  437. U32 count = 0;
  438. std::map<std::string,std::string>::const_iterator it = sGroupMap.begin(), it_end = sGroupMap.end();
  439. for( ; it != it_end; ++it)
  440. {
  441. const std::string& group_name = it->second;
  442. instance_list_t& instances = sInstanceMap[group_name];
  443. for (instance_list_t::const_iterator iter = instances.begin(); iter != instances.end(); ++iter)
  444. {
  445. LLFloater* inst = *iter;
  446. if (inst->getVisible() && !inst->isMinimized())
  447. {
  448. count++;
  449. }
  450. }
  451. }
  452. return count;
  453. }