llfloaterexperiences.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /**
  2. * @file llfloaterexperiences.cpp
  3. * @brief LLFloaterExperiences class implementation
  4. *
  5. * $LicenseInfo:firstyear=2012&license=viewergpl$
  6. *
  7. * Copyright (c) 2012, 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 "llviewerprecompiledheaders.h"
  33. #include "boost/signals2.hpp"
  34. #include "llfloaterexperiences.h"
  35. #include "llbutton.h"
  36. #include "llevents.h"
  37. #include "llexperiencecache.h"
  38. #include "llnotifications.h"
  39. #include "llscrolllistctrl.h"
  40. #include "lltabcontainer.h"
  41. #include "lltrans.h"
  42. #include "lluictrlfactory.h"
  43. #include "llagent.h"
  44. #include "llexperiencelog.h" // For PUMP_EXPERIENCE
  45. #include "llfloaterexperiencepicker.h" // For LLPanelExperiencePicker class
  46. #include "llfloaterexperienceprofile.h"
  47. #include "llfloaterregioninfo.h"
  48. #include "llpanelexperiencelog.h"
  49. #include "llviewerregion.h"
  50. //static
  51. S32 LLFloaterExperiences::sLastTab = 0;
  52. // LLFloaterExperiences class proper
  53. LLFloaterExperiences::LLFloaterExperiences(const LLSD&)
  54. {
  55. LLUICtrlFactory::getInstance()->buildFloater(this,
  56. "floater_experiences.xml");
  57. }
  58. LLFloaterExperiences::~LLFloaterExperiences()
  59. {
  60. sLastTab = mTabContainer->getCurrentPanelIndex();
  61. }
  62. LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name,
  63. bool select)
  64. {
  65. LLPanelExperiences* panel = LLPanelExperiences::create(name);
  66. mTabContainer->addTabPanel(panel, LLTrans::getString(name), select);
  67. return panel;
  68. }
  69. bool LLFloaterExperiences::postBuild()
  70. {
  71. mTabContainer = getChild<LLTabContainer>("xp_tabs");
  72. // Add the experiences picker panel and set it in non-picker (list) mode
  73. LLPanelExperiencePicker* picker = new LLPanelExperiencePicker();
  74. mTabContainer->addTabPanel(picker, picker->getLabel());
  75. picker->hideOkCancel();
  76. // Add the filtered experiences panels
  77. addTab("Allowed_Experiences_Tab", true);
  78. addTab("Blocked_Experiences_Tab", false);
  79. addTab("Admin_Experiences_Tab", false);
  80. addTab("Contrib_Experiences_Tab", false);
  81. LLPanelExperiences* owned = addTab("Owned_Experiences_Tab", false);
  82. owned->setButtonAction("acquire", LLFloaterExperiences::sendPurchaseRequest,
  83. this);
  84. owned->enableButton(false);
  85. // Add the events log panel
  86. LLPanelExperienceLog* logs = new LLPanelExperienceLog();
  87. mTabContainer->addTabPanel(logs, logs->getLabel());
  88. childSetAction("close_btn", onCloseBtn, this);
  89. LLEventPump& pump = gEventPumps.obtain(PUMP_EXPERIENCE);
  90. pump.listen("LLFloaterExperiences",
  91. boost::bind(&LLFloaterExperiences::updatePermissions,
  92. this, _1));
  93. if (sLastTab < mTabContainer->getTabCount())
  94. {
  95. mTabContainer->selectTab(sLastTab);
  96. }
  97. else
  98. {
  99. sLastTab = 0;
  100. }
  101. return true;
  102. }
  103. void LLFloaterExperiences::refreshContents()
  104. {
  105. LLHandle<LLFloaterExperiences> handle =
  106. getDerivedHandle<LLFloaterExperiences>();
  107. name_map_t name_map;
  108. const std::string& url = gAgent.getRegionCapability("GetExperiences");
  109. if (!url.empty())
  110. {
  111. name_map["experiences"] = "Allowed_Experiences_Tab";
  112. name_map["blocked"] = "Blocked_Experiences_Tab";
  113. retrieveExperienceList(url, handle, name_map);
  114. }
  115. updateInfo("GetAdminExperiences", "Admin_Experiences_Tab");
  116. updateInfo("GetCreatorExperiences", "Contrib_Experiences_Tab");
  117. const std::string& url2 = gAgent.getRegionCapability("AgentExperiences");
  118. if (!url2.empty())
  119. {
  120. name_map["experience_ids"] = "Owned_Experiences_Tab";
  121. retrieveExperienceList(url2, handle, name_map,
  122. "ExperienceAcquireFailed",
  123. boost::bind(&LLFloaterExperiences::checkPurchaseInfo,
  124. this, _1, _2));
  125. }
  126. }
  127. void LLFloaterExperiences::onOpen()
  128. {
  129. LLViewerRegion* regionp = gAgent.getRegion();
  130. if (!regionp)
  131. {
  132. return;
  133. }
  134. if (regionp->capabilitiesReceived())
  135. {
  136. refreshContents();
  137. return;
  138. }
  139. // Register our callback for when capabilities will have been received.
  140. regionp->setCapsReceivedCB(boost::bind(&LLFloaterExperiences::refreshContents,
  141. this));
  142. }
  143. bool LLFloaterExperiences::updatePermissions(const LLSD& permission)
  144. {
  145. LLUUID experience;
  146. std::string permission_string;
  147. if (permission.has("experience"))
  148. {
  149. experience = permission["experience"].asUUID();
  150. permission_string = permission[experience.asString()]["permission"].asString();
  151. }
  152. LLPanelExperiences* tab;
  153. tab = (LLPanelExperiences*)mTabContainer->getPanelByName("Allowed_Experiences_Tab");
  154. if (tab)
  155. {
  156. if (permission.has("experiences"))
  157. {
  158. tab->setExperienceList(permission["experiences"]);
  159. }
  160. else if (experience.notNull())
  161. {
  162. if (permission_string != "Allow")
  163. {
  164. tab->removeExperience(experience);
  165. }
  166. else
  167. {
  168. tab->addExperience(experience);
  169. }
  170. }
  171. }
  172. tab = (LLPanelExperiences*)mTabContainer->getPanelByName("Blocked_Experiences_Tab");
  173. if (tab)
  174. {
  175. if (permission.has("blocked"))
  176. {
  177. tab->setExperienceList(permission["blocked"]);
  178. }
  179. else if (experience.notNull())
  180. {
  181. if (permission_string != "Block")
  182. {
  183. tab->removeExperience(experience);
  184. }
  185. else
  186. {
  187. tab->addExperience(experience);
  188. }
  189. }
  190. }
  191. return false;
  192. }
  193. void LLFloaterExperiences::onClose(bool app_quitting)
  194. {
  195. LLEventPump& pump = gEventPumps.obtain(PUMP_EXPERIENCE);
  196. pump.stopListening("LLFloaterExperiences");
  197. LLFloater::onClose(app_quitting);
  198. }
  199. void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel,
  200. const LLSD& content)
  201. {
  202. if (panel)
  203. {
  204. panel->enableButton(content.has("purchase"));
  205. updateInfo("GetAdminExperiences", "Admin_Experiences_Tab");
  206. updateInfo("GetCreatorExperiences", "Contrib_Experiences_Tab");
  207. }
  208. }
  209. void LLFloaterExperiences::updateInfo(const char* exp_cap, const char* tab)
  210. {
  211. const std::string& url = gAgent.getRegionCapability(exp_cap);
  212. if (!url.empty())
  213. {
  214. name_map_t name_map;
  215. name_map["experience_ids"] = tab;
  216. retrieveExperienceList(url, getDerivedHandle<LLFloaterExperiences>(),
  217. name_map);
  218. }
  219. }
  220. void LLFloaterExperiences::doSendPurchaseRequest()
  221. {
  222. const std::string& url = gAgent.getRegionCapability("AgentExperiences");
  223. if (!url.empty())
  224. {
  225. name_map_t name_map;
  226. name_map["experience_ids"] = "Owned_Experiences_Tab";
  227. requestNewExperience(url, getDerivedHandle<LLFloaterExperiences>(),
  228. name_map, "ExperienceAcquireFailed",
  229. boost::bind(&LLFloaterExperiences::checkPurchaseInfo,
  230. this, _1, _2));
  231. }
  232. }
  233. //static
  234. void LLFloaterExperiences::sendPurchaseRequest(void* data)
  235. {
  236. LLFloaterExperiences* self = findInstance();
  237. if (self && self == (LLFloaterExperiences*)data)
  238. {
  239. self->doSendPurchaseRequest();
  240. }
  241. }
  242. //static
  243. void LLFloaterExperiences::onCloseBtn(void* data)
  244. {
  245. LLFloaterExperiences* self = (LLFloaterExperiences*)data;
  246. if (self)
  247. {
  248. self->close();
  249. }
  250. }
  251. // LLPanelExperiences class
  252. //static
  253. LLPanelExperiences* LLPanelExperiences::create(const std::string& name)
  254. {
  255. LLPanelExperiences* panel= new LLPanelExperiences();
  256. panel->setName(name);
  257. return panel;
  258. }
  259. LLPanelExperiences::LLPanelExperiences()
  260. : mListEmpty(true)
  261. {
  262. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experiences.xml");
  263. }
  264. bool LLPanelExperiences::postBuild()
  265. {
  266. mExperiencesList = getChild<LLScrollListCtrl>("experiences_list");
  267. mExperiencesList->addCommentText(getString("no_experiences_text"));
  268. mExperiencesList->setDoubleClickCallback(onDoubleClickProfile);
  269. mExperiencesList->setCallbackUserData(this);
  270. mActionBtn = getChild<LLButton>("btn_action");
  271. mActionBtn->setVisible(false);
  272. return true;
  273. }
  274. //static
  275. void LLPanelExperiences::cacheCallback(LLHandle<LLPanelExperiences> handle,
  276. const LLSD& experience)
  277. {
  278. LLPanelExperiences* self = handle.get();
  279. if (self)
  280. {
  281. if (self->mListEmpty)
  282. {
  283. // Remove the entry containing the "no experiences" comment
  284. self->mExperiencesList->deleteAllItems();
  285. self->mListEmpty = false;
  286. }
  287. const LLUUID& id = experience[LLExperienceCache::EXPERIENCE_ID];
  288. const LLSD& name = experience[LLExperienceCache::NAME];
  289. LLScrollListItem* item = self->mExperiencesList->getItem(id);
  290. if (item)
  291. {
  292. // Update the existing entry
  293. item->getColumn(0)->setValue(name);
  294. }
  295. else
  296. {
  297. // Create a new entry
  298. LLSD entry;
  299. entry["id"] = id;
  300. LLSD& columns = entry["columns"];
  301. columns[0]["column"] = "experience_name";
  302. columns[0]["value"] = name.asString();
  303. self->mExperiencesList->addElement(entry);
  304. }
  305. }
  306. }
  307. void LLPanelExperiences::addExperience(const LLUUID& id)
  308. {
  309. if (!mExperiencesList->getItem(id))
  310. {
  311. LLExperienceCache* exp = LLExperienceCache::getInstance();
  312. exp->get(id,
  313. boost::bind(&LLPanelExperiences::cacheCallback,
  314. getDerivedHandle<LLPanelExperiences>(), _1));
  315. if (mListEmpty)
  316. {
  317. mExperiencesList->deleteAllItems();
  318. mExperiencesList->addCommentText(getString("loading_experiences"));
  319. }
  320. }
  321. }
  322. void LLPanelExperiences::setExperienceList(const LLSD& experiences)
  323. {
  324. mExperiencesList->deleteAllItems();
  325. mListEmpty = true;
  326. mExperiencesList->addCommentText(getString("no_experiences_text"));
  327. for (LLSD::array_const_iterator it = experiences.beginArray(),
  328. end = experiences.endArray();
  329. it != end; ++it)
  330. {
  331. addExperience(it->asUUID());
  332. }
  333. }
  334. void LLPanelExperiences::removeExperience(const LLUUID& id)
  335. {
  336. LLScrollListItem* item = mExperiencesList->getItem(id);
  337. if (item)
  338. {
  339. mExperiencesList->deleteSingleItem(mExperiencesList->getItemIndex(item));
  340. }
  341. }
  342. void LLPanelExperiences::removeExperiences(const LLSD& ids)
  343. {
  344. for (LLSD::array_const_iterator it = ids.beginArray(),
  345. end = ids.endArray();
  346. it != end; ++it)
  347. {
  348. removeExperience(it->asUUID());
  349. }
  350. }
  351. void LLPanelExperiences::enableButton(bool enable)
  352. {
  353. mActionBtn->setEnabled(enable);
  354. }
  355. void LLPanelExperiences::setButtonAction(const std::string& label,
  356. void (*cb)(void*), void* data)
  357. {
  358. if (label.empty())
  359. {
  360. mActionBtn->setVisible(false);
  361. }
  362. else
  363. {
  364. mActionBtn->setVisible(true);
  365. mActionBtn->setClickedCallback(cb, data);
  366. mActionBtn->setLabel(getString(label));
  367. }
  368. }
  369. #if 0 // not used
  370. std::string LLPanelExperiences::getSelectedExperienceName() const
  371. {
  372. std::string name;
  373. LLScrollListItem* item = mExperiencesList->getFirstSelected();
  374. if (item)
  375. {
  376. name = item->mExperiencesList->getSelectedItemLabel();
  377. }
  378. return name;
  379. }
  380. LLUUID LLPanelExperiences::getSelectedExperienceId() const
  381. {
  382. LLUUID id;
  383. LLScrollListItem* item = mExperiencesList->getFirstSelected();
  384. if (item)
  385. {
  386. id = item->mExperiencesList->getUUID();
  387. }
  388. return id;
  389. }
  390. #endif
  391. //static
  392. void LLPanelExperiences::onDoubleClickProfile(void* data)
  393. {
  394. LLPanelExperiences* self = (LLPanelExperiences*)data;
  395. if (self)
  396. {
  397. LLScrollListItem* item = self->mExperiencesList->getFirstSelected();
  398. if (item)
  399. {
  400. LLFloaterExperienceProfile::show(item->getUUID());
  401. }
  402. }
  403. }
  404. #define COROCAST(T) static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(const std::string&, const LLSD&, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>(T)
  405. #define COROCAST2(T) static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(const std::string&, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>(T)
  406. void LLFloaterExperiences::retrieveExperienceList(const std::string& url,
  407. const LLHandle<LLFloaterExperiences>& handle,
  408. const name_map_t& tab_map,
  409. const std::string& error_notify,
  410. Callback_t cb)
  411. {
  412. invokationFn_t getfn =
  413. boost::bind(COROCAST2(&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend),
  414. // _1 -> adapter
  415. // _2 -> url
  416. // _3 -> options
  417. // _4 -> headers
  418. _1, _2, _3, _4);
  419. gCoros.launch("LLFloaterExperiences::retrieveExperienceList",
  420. boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
  421. url, handle, tab_map, error_notify, cb, getfn));
  422. }
  423. void LLFloaterExperiences::requestNewExperience(const std::string& url,
  424. const LLHandle<LLFloaterExperiences>& handle,
  425. const name_map_t& tab_map,
  426. const std::string& error_notify,
  427. Callback_t cb)
  428. {
  429. invokationFn_t postfn =
  430. boost::bind(COROCAST(&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend),
  431. // _1 -> adapter
  432. // _2 -> url
  433. // _3 -> options
  434. // _4 -> headers
  435. _1, _2, LLSD(), _3, _4);
  436. gCoros.launch("LLFloaterExperiences::requestNewExperience",
  437. boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro,
  438. url, handle, tab_map, error_notify, cb, postfn));
  439. }
  440. //static
  441. void LLFloaterExperiences::retrieveExperienceListCoro(std::string url,
  442. LLHandle<LLFloaterExperiences> handle,
  443. name_map_t tab_map,
  444. std::string error_notify,
  445. Callback_t cb,
  446. invokationFn_t invoker)
  447. {
  448. if (url.empty())
  449. {
  450. llwarns << "Capability is empty !" << llendl;
  451. return;
  452. }
  453. LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
  454. adapter(new LLCoreHttpUtil::HttpCoroutineAdapter("retrieveExperienceListCoro"));
  455. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  456. LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders);
  457. LLSD result = invoker(adapter, url, options, headers);
  458. LLCore::HttpStatus status =
  459. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  460. if (!status)
  461. {
  462. LLSD args;
  463. args["ERROR_MESSAGE"] = status.getType();
  464. gNotifications.add(error_notify, args);
  465. return;
  466. }
  467. LLFloaterExperiences* self = handle.get();
  468. if (!self || !self->mTabContainer)
  469. {
  470. return;
  471. }
  472. LLTabContainer* tabs = self->mTabContainer;
  473. LLPanelExperiences* tab;
  474. for (name_map_t::iterator it = tab_map.begin(), end = tab_map.end();
  475. it != end; ++it)
  476. {
  477. if (result.has(it->first))
  478. {
  479. tab = dynamic_cast<LLPanelExperiences*>(tabs->getPanelByName(it->second));
  480. if (tab)
  481. {
  482. const LLSD& ids = result[it->first];
  483. tab->setExperienceList(ids);
  484. if (!cb.empty())
  485. {
  486. cb(tab, result);
  487. }
  488. }
  489. }
  490. }
  491. }