llfloaterexperiencepicker.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /**
  2. * @file llfloaterexperiencepicker.cpp
  3. * @brief Implementation of LLFloaterExperiencePicker and
  4. * LLPanelExperiencePicker
  5. * @author [email protected]
  6. *
  7. * $LicenseInfo:firstyear=2014&license=viewergpl$
  8. *
  9. * Copyright (c) 2014, Linden Research, Inc.
  10. *
  11. * Second Life Viewer Source Code
  12. * The source code in this file ("Source Code") is provided by Linden Lab
  13. * to you under the terms of the GNU General Public License, version 2.0
  14. * ("GPL"), unless you have obtained a separate licensing agreement
  15. * ("Other License"), formally executed by you and Linden Lab. Terms of
  16. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18. *
  19. * There are special exceptions to the terms and conditions of the GPL as
  20. * it is applied to this Source Code. View the full text of the exception
  21. * in the file doc/FLOSS-exception.txt in this software distribution, or
  22. * online at
  23. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24. *
  25. * By copying, modifying or distributing this software, you acknowledge
  26. * that you have read and understood your obligations described above,
  27. * and agree to abide by those obligations.
  28. *
  29. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31. * COMPLETENESS OR PERFORMANCE.
  32. * $/LicenseInfo$
  33. */
  34. #include "llviewerprecompiledheaders.h"
  35. #include "llfloaterexperiencepicker.h"
  36. #include "llbutton.h"
  37. #include "llcombobox.h"
  38. #include "llexperiencecache.h"
  39. #include "lllineeditor.h"
  40. #include "llscrolllistctrl.h"
  41. #include "lltrans.h"
  42. #include "lluictrlfactory.h"
  43. #include "lluri.h"
  44. #include "llagent.h"
  45. #include "llfloaterexperienceprofile.h"
  46. #include "llviewercontrol.h"
  47. #include "llviewerregion.h"
  48. LLFloaterExperiencePicker::instances_map_t LLFloaterExperiencePicker::sInstancesMap;
  49. // LLPanelExperiencePicker class
  50. LLPanelExperiencePicker::LLPanelExperiencePicker()
  51. {
  52. LLUICtrlFactory::getInstance()->buildPanel(this,
  53. "panel_experience_search.xml");
  54. setDefaultFilters();
  55. }
  56. bool LLPanelExperiencePicker::postBuild()
  57. {
  58. mLineEditor = getChild<LLLineEditor>("edit");
  59. mLineEditor->setFocus(true);
  60. mSearchResultsList = getChild<LLScrollListCtrl>("search_results");
  61. mSearchResultsList->setCommitCallback(onList);
  62. mSearchResultsList->setDoubleClickCallback(onBtnSelect);
  63. mSearchResultsList->setCallbackUserData(this);
  64. mSearchResultsList->setEnabled(false);
  65. mSearchResultsList->addCommentText(getString("no_results"));
  66. mOkBtn = getChild<LLButton>("ok_btn");
  67. mOkBtn->setClickedCallback(onBtnSelect, this);
  68. mOkBtn->setEnabled(false);
  69. mCancelBtn = getChild<LLButton>("cancel_btn");
  70. mCancelBtn->setClickedCallback(onBtnClose, this);
  71. mProfileBtn = getChild<LLButton>("profile_btn");
  72. mProfileBtn->setClickedCallback(onBtnProfile, this);
  73. mProfileBtn->setEnabled(false);
  74. mMaturityCombo = getChild<LLComboBox>("maturity");
  75. mMaturityCombo->setCurrentByIndex(gSavedSettings.getS32("ExperiencesMaturity"));
  76. mMaturityCombo->setCommitCallback(onMaturity);
  77. mMaturityCombo->setCallbackUserData(this);
  78. mNextBtn = getChild<LLButton>("right_btn");
  79. mNextBtn->setClickedCallback(onNextPage, this);
  80. mPrevBtn = getChild<LLButton>("left_btn");
  81. mPrevBtn->setClickedCallback(onPrevPage, this);
  82. childSetAction("find", onBtnFind, this);
  83. // Start searching when Return is pressed in the line editor.
  84. setDefaultBtn("find");
  85. return true;
  86. }
  87. void LLPanelExperiencePicker::hideOkCancel()
  88. {
  89. mOkBtn->setVisible(false);
  90. mCancelBtn->setVisible(false);
  91. }
  92. void LLPanelExperiencePicker::find()
  93. {
  94. if (gAgent.hasRegionCapability("FindExperienceByName"))
  95. {
  96. std::string text = mLineEditor->getValue().asString();
  97. mQueryID.generate();
  98. LLExperienceCache* exp = LLExperienceCache::getInstance();
  99. exp->findExperienceByName(text, mCurrentPage,
  100. boost::bind(&LLPanelExperiencePicker::findResults,
  101. getDerivedHandle<LLPanelExperiencePicker>(),
  102. mQueryID, _1));
  103. }
  104. mSearchResultsList->deleteAllItems();
  105. mSearchResultsList->addCommentText(getString("searching"));
  106. mOkBtn->setEnabled(false);
  107. mProfileBtn->setEnabled(false);
  108. mNextBtn->setEnabled(false);
  109. mPrevBtn->setEnabled(false);
  110. }
  111. //static
  112. void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> handle,
  113. LLUUID query_id, LLSD result)
  114. {
  115. LLPanelExperiencePicker* self = handle.get();
  116. if (self)
  117. {
  118. self->processResponse(query_id, result);
  119. }
  120. }
  121. bool LLPanelExperiencePicker::isSelectButtonEnabled()
  122. {
  123. return mSearchResultsList->getFirstSelectedIndex() >= 0;
  124. }
  125. void LLPanelExperiencePicker::setAllowMultiple(bool allow_multiple)
  126. {
  127. mSearchResultsList->setAllowMultipleSelection(allow_multiple);
  128. }
  129. void LLPanelExperiencePicker::getSelectedExperienceIds(const LLScrollListCtrl* results,
  130. uuid_vec_t &experience_ids)
  131. {
  132. std::vector<LLScrollListItem*> items = results->getAllSelected();
  133. for (std::vector<LLScrollListItem*>::iterator it = items.begin(),
  134. end = items.end();
  135. it != end; ++it)
  136. {
  137. LLScrollListItem* item = *it;
  138. if (item && item->getUUID().notNull())
  139. {
  140. experience_ids.emplace_back(item->getUUID());
  141. }
  142. }
  143. }
  144. //static
  145. void LLPanelExperiencePicker::nameCallback(const LLHandle<LLPanelExperiencePicker>& floater,
  146. const LLUUID& experience_id,
  147. const LLUUID& agent_id,
  148. const LLAvatarName& av_name)
  149. {
  150. if (floater.isDead())
  151. {
  152. return;
  153. }
  154. LLPanelExperiencePicker* picker = floater.get();
  155. LLScrollListCtrl* search_results = picker->mSearchResultsList;
  156. LLScrollListItem* item = search_results->getItem(experience_id);
  157. if (item)
  158. {
  159. item->getColumn(2)->setValue(" " + av_name.getLegacyName());
  160. }
  161. }
  162. void LLPanelExperiencePicker::processResponse(const LLUUID& query_id,
  163. const LLSD& content)
  164. {
  165. if (query_id != mQueryID)
  166. {
  167. return;
  168. }
  169. mResponse = content;
  170. mNextBtn->setEnabled(content.has("next_page_url"));
  171. mPrevBtn->setEnabled(content.has("previous_page_url"));
  172. filterContent();
  173. }
  174. void LLPanelExperiencePicker::filterContent()
  175. {
  176. mSearchResultsList->deleteAllItems();
  177. LLSD item;
  178. std::string name;
  179. const LLSD& experiences = mResponse["experience_keys"];
  180. for (LLSD::array_const_iterator it = experiences.beginArray(),
  181. end = experiences.endArray();
  182. it != end; ++it)
  183. {
  184. const LLSD& experience = *it;
  185. if (isExperienceHidden(experience))
  186. {
  187. continue;
  188. }
  189. item["id"] = experience[LLExperienceCache::EXPERIENCE_ID];
  190. name = experience[LLExperienceCache::NAME].asString();
  191. if (name.empty())
  192. {
  193. name = LLTrans::getString("ExperienceNameUntitled");
  194. }
  195. LLSD& columns = item["columns"];
  196. columns[0]["column"] = "maturity";
  197. U8 maturity = (U8)experience[LLExperienceCache::MATURITY].asInteger();
  198. columns[0]["value"] = LLViewerRegion::getMaturityIconName(maturity);
  199. columns[0]["type"] = "icon";
  200. columns[0]["halign"] = "right";
  201. columns[1]["column"] = "experience_name";
  202. columns[1]["value"] = " " + name;
  203. columns[2]["column"] = "owner";
  204. columns[2]["value"] = " " + getString("loading");
  205. mSearchResultsList->addElement(item);
  206. LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID],
  207. boost::bind(&LLPanelExperiencePicker::nameCallback,
  208. getDerivedHandle<LLPanelExperiencePicker>(),
  209. experience[LLExperienceCache::EXPERIENCE_ID],
  210. _1, _2));
  211. }
  212. if (mSearchResultsList->isEmpty())
  213. {
  214. LLStringUtil::format_map_t map;
  215. std::string search_text = mLineEditor->getValue().asString();
  216. map["[TEXT]"] = search_text;
  217. if (search_text.empty())
  218. {
  219. mSearchResultsList->addCommentText(getString("no_results"));
  220. }
  221. else
  222. {
  223. mSearchResultsList->addCommentText(getString("not_found", map));
  224. }
  225. mSearchResultsList->setEnabled(false);
  226. mOkBtn->setEnabled(false);
  227. mProfileBtn->setEnabled(false);
  228. }
  229. else
  230. {
  231. mOkBtn->setEnabled(true);
  232. mSearchResultsList->setEnabled(true);
  233. mSearchResultsList->sortByColumnIndex(1, true);
  234. std::string text = mLineEditor->getValue().asString();
  235. if (!mSearchResultsList->selectItemByLabel(text, true, 1))
  236. {
  237. mSearchResultsList->selectFirstItem();
  238. }
  239. onList(mSearchResultsList, this);
  240. mSearchResultsList->setFocus(true);
  241. }
  242. }
  243. bool LLPanelExperiencePicker::isExperienceHidden(const LLSD& experience) const
  244. {
  245. for (filter_list::const_iterator it = mFilters.begin(),
  246. end = mFilters.end();
  247. it != end; ++it)
  248. {
  249. if ((*it)(experience))
  250. {
  251. return true;
  252. }
  253. }
  254. return false;
  255. }
  256. bool LLPanelExperiencePicker::FilterOverRating(const LLSD& experience)
  257. {
  258. S32 maturity = mMaturityCombo->getSelectedValue().asInteger();
  259. return experience[LLExperienceCache::MATURITY].asInteger() > maturity;
  260. }
  261. void LLPanelExperiencePicker::setDefaultFilters()
  262. {
  263. mFilters.clear();
  264. addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating,
  265. this, _1));
  266. }
  267. void LLPanelExperiencePicker::closeParent()
  268. {
  269. LLView* viewp = getParent();
  270. if (viewp)
  271. {
  272. LLFloater* floaterp = viewp->asFloater();
  273. if (floaterp)
  274. {
  275. floaterp->close();
  276. }
  277. }
  278. }
  279. //static
  280. void LLPanelExperiencePicker::onBtnClose(void* data)
  281. {
  282. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  283. if (self)
  284. {
  285. self->closeParent();
  286. }
  287. }
  288. //static
  289. void LLPanelExperiencePicker::onBtnFind(void* data)
  290. {
  291. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  292. if (self)
  293. {
  294. self->mCurrentPage = 1;
  295. self->find();
  296. }
  297. }
  298. //static
  299. void LLPanelExperiencePicker::onBtnProfile(void* data)
  300. {
  301. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  302. if (self)
  303. {
  304. LLScrollListItem* item = self->mSearchResultsList->getFirstSelected();
  305. if (item)
  306. {
  307. LLFloaterExperienceProfile::show(item->getUUID());
  308. }
  309. }
  310. }
  311. //static
  312. void LLPanelExperiencePicker::onNextPage(void* data)
  313. {
  314. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  315. if (self)
  316. {
  317. self->mCurrentPage++;
  318. self->find();
  319. }
  320. }
  321. //static
  322. void LLPanelExperiencePicker::onPrevPage(void* data)
  323. {
  324. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  325. if (self)
  326. {
  327. if (--self->mCurrentPage < 1)
  328. {
  329. self->mCurrentPage = 1;
  330. }
  331. self->find();
  332. }
  333. }
  334. //static
  335. void LLPanelExperiencePicker::onBtnSelect(void* data)
  336. {
  337. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  338. if (self)
  339. {
  340. if (!self->isSelectButtonEnabled())
  341. {
  342. return;
  343. }
  344. if (self->mSelectionCallback)
  345. {
  346. LLScrollListCtrl* results = self->mSearchResultsList;
  347. uuid_vec_t experience_ids;
  348. self->getSelectedExperienceIds(results, experience_ids);
  349. self->mSelectionCallback(experience_ids);
  350. results->deselectAllItems(true);
  351. if (self->mCloseOnSelect)
  352. {
  353. self->mCloseOnSelect = false;
  354. onBtnClose(data);
  355. }
  356. }
  357. else
  358. {
  359. onBtnProfile(data);
  360. }
  361. }
  362. }
  363. //static
  364. void LLPanelExperiencePicker::onList(LLUICtrl* ctrl, void* data)
  365. {
  366. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  367. if (self)
  368. {
  369. bool enabled = self->isSelectButtonEnabled();
  370. self->mOkBtn->setEnabled(enabled);
  371. enabled = enabled && self->mSearchResultsList->getNumSelected() == 1;
  372. self->mProfileBtn->setEnabled(enabled);
  373. }
  374. }
  375. //static
  376. void LLPanelExperiencePicker::onMaturity(LLUICtrl* ctrl, void* data)
  377. {
  378. LLPanelExperiencePicker* self = (LLPanelExperiencePicker*)data;
  379. if (self)
  380. {
  381. gSavedSettings.setS32("ExperiencesMaturity",
  382. self->mMaturityCombo->getCurrentIndex());
  383. if (self->mResponse.has("experience_keys"))
  384. {
  385. const LLSD& experiences = self->mResponse["experience_keys"];
  386. if (experiences.beginArray() != experiences.endArray())
  387. {
  388. self->filterContent();
  389. }
  390. }
  391. }
  392. }
  393. // LLFloaterExperiencePicker class
  394. //static
  395. LLFloaterExperiencePicker* LLFloaterExperiencePicker::show(select_callback_t callback,
  396. const LLUUID& key,
  397. bool allow_multiple,
  398. bool close_on_select,
  399. filter_list filters)
  400. {
  401. LLFloaterExperiencePicker* self;
  402. instances_map_t::iterator it = sInstancesMap.find(key);
  403. if (it == sInstancesMap.end())
  404. {
  405. self = new LLFloaterExperiencePicker(key);
  406. }
  407. else
  408. {
  409. self = it->second;
  410. }
  411. if (!self)
  412. {
  413. llwarns << "Cannot instantiate experience picker" << llendl;
  414. return NULL;
  415. }
  416. if (self->mSearchPanel)
  417. {
  418. self->mSearchPanel->mSelectionCallback = callback;
  419. self->mSearchPanel->mCloseOnSelect = close_on_select;
  420. self->mSearchPanel->setAllowMultiple(allow_multiple);
  421. self->mSearchPanel->setDefaultFilters();
  422. self->mSearchPanel->addFilters(filters.begin(), filters.end());
  423. self->mSearchPanel->filterContent();
  424. }
  425. return self;
  426. }
  427. //static
  428. void* LLFloaterExperiencePicker::createSearchPanel(void* data)
  429. {
  430. LLFloaterExperiencePicker* self = (LLFloaterExperiencePicker*)data;
  431. self->mSearchPanel = new LLPanelExperiencePicker();
  432. return self->mSearchPanel;
  433. }
  434. LLFloaterExperiencePicker::LLFloaterExperiencePicker(const LLUUID& key)
  435. : LLFloater(key.asString()),
  436. mKey(key),
  437. mSearchPanel(NULL)
  438. {
  439. sInstancesMap[key] = this;
  440. LLCallbackMap::map_t factory_map;
  441. factory_map["experience_search"] = LLCallbackMap(createSearchPanel, this);
  442. LLUICtrlFactory::getInstance()->buildFloater(this,
  443. "floater_experience_search.xml",
  444. &factory_map);
  445. }
  446. LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
  447. {
  448. gFocusMgr.releaseFocusIfNeeded(this);
  449. sInstancesMap.erase(mKey);
  450. }