hbfloatersearch.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  1. /**
  2. * @file hbfloatersearch.cpp
  3. * @brief The "Search" floater and its Web tab implementation.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc. (c) 2009-2021, Henri Beauchamp.
  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. // This used to be LL's v1 viewer "Directory" floater (llfloaterdirectory.cpp),
  33. // and was modified/expanded by Henri Beauchamp to add web search, showcase and
  34. // Marketplace when LL added them to their own v2+ viewers, as well as support
  35. // for OpenSim grids (optional) web search.
  36. #include "llviewerprecompiledheaders.h"
  37. #include "hbfloatersearch.h"
  38. #include "llbutton.h"
  39. #include "llkeyboard.h"
  40. #include "lldir.h"
  41. #include "llpluginclassmedia.h"
  42. #include "llradiogroup.h"
  43. #include "llresizehandle.h"
  44. #include "llscrollcontainer.h"
  45. #include "llscrollbar.h"
  46. #include "lltabcontainer.h"
  47. #include "lluictrlfactory.h"
  48. #include "llagent.h"
  49. #include "llcommandhandler.h"
  50. #include "llfloateravatarinfo.h"
  51. #include "llgridmanager.h" // For gIsInSecondLife
  52. #include "llmediactrl.h"
  53. #include "llpanelavatar.h"
  54. #include "llpanelevent.h"
  55. #include "llpanelclassified.h"
  56. #include "llpaneldirclassified.h"
  57. #include "llpaneldirevents.h"
  58. #include "llpaneldirfind.h"
  59. #include "llpaneldirgroups.h"
  60. #include "llpaneldirland.h"
  61. #include "llpaneldirpeople.h"
  62. #include "llpaneldirplaces.h"
  63. #include "llpanelgroup.h"
  64. #include "llpanelpick.h"
  65. #include "llpanelplace.h"
  66. #include "llviewercontrol.h"
  67. #include "llviewerparcelmgr.h"
  68. #include "llweb.h"
  69. ///////////////////////////////////////////////////////////////////////////////
  70. // Command handler for search SLURLs
  71. ///////////////////////////////////////////////////////////////////////////////
  72. // Support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps
  73. class LLSearchHandler final : public LLCommandHandler
  74. {
  75. public:
  76. LLSearchHandler()
  77. : LLCommandHandler("search", UNTRUSTED_THROTTLE)
  78. {
  79. }
  80. bool handle(const LLSD& tokens, const LLSD&, LLMediaCtrl*) override
  81. {
  82. const size_t parts = tokens.size();
  83. #if 0 // The category is now (11-2021) ignored since not possible to pass
  84. // "as is" to the newest SL web-based search
  85. // Get the (optional) category for the search
  86. std::string category = "all";
  87. if (parts > 0)
  88. {
  89. category = tokens[0].asString();
  90. }
  91. #endif
  92. // Get the (optional) search string
  93. std::string search_text;
  94. if (parts > 1)
  95. {
  96. search_text = tokens[1].asString();
  97. }
  98. HBFloaterSearch::showFindAll(search_text);
  99. return true;
  100. }
  101. };
  102. LLSearchHandler gSearchHandler;
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // HBPanelWebSearch class, for the Web search panel. Implemented in this module
  105. // since no other module is using it... This tab merely displays a web browser.
  106. ///////////////////////////////////////////////////////////////////////////////
  107. class HBPanelWebSearch : public LLPanelDirBrowser, public LLViewerMediaObserver
  108. {
  109. protected:
  110. LOG_CLASS(HBPanelWebSearch);
  111. public:
  112. HBPanelWebSearch(const std::string& name, HBFloaterSearch* floater);
  113. ~HBPanelWebSearch() override;
  114. bool postBuild() override;
  115. void draw() override;
  116. void onVisibilityChange(bool new_visibility) override;
  117. void reshape(S32 width, S32 height, bool call_from_parent = true) override;
  118. void search(const std::string& text = LLStringUtil::null);
  119. LL_INLINE static void setOSSearchURL(const std::string& url)
  120. {
  121. sOSSearchURL = url;
  122. }
  123. LL_INLINE static std::string getOSSearchURL()
  124. {
  125. return sOSSearchURL;
  126. }
  127. protected:
  128. static void onClickBack(void* data);
  129. static void onClickForward(void* data);
  130. static void onClickReload(void* data);
  131. static void onCommitSelectionRadio(LLUICtrl* ctrl, void* data);
  132. // Inherited from LLViewerMediaObserver
  133. void handleMediaEvent(LLPluginClassMedia*, EMediaEvent event) override;
  134. protected:
  135. LLMediaCtrl* mWebBrowser;
  136. LLButton* mBackButton;
  137. LLButton* mForwardButton;
  138. LLButton* mReloadButton;
  139. LLRadioGroup* mSelectionRadio;
  140. bool mReloading;
  141. static std::string sOSSearchURL;
  142. };
  143. //static
  144. std::string HBPanelWebSearch::sOSSearchURL;
  145. HBPanelWebSearch::HBPanelWebSearch(const std::string& name,
  146. HBFloaterSearch* floater)
  147. : LLPanelDirBrowser(name, floater),
  148. // NOTE: a reshape() event occurs before mWebBrowser is created, so we must
  149. // check for NULL whenever reshape() is called...
  150. mWebBrowser(NULL),
  151. mReloading(false)
  152. {
  153. }
  154. bool HBPanelWebSearch::postBuild()
  155. {
  156. LLPanelDirBrowser::postBuild();
  157. mBackButton = getChild<LLButton>("back_btn");
  158. mBackButton->setClickedCallback(onClickBack, this);
  159. mForwardButton = getChild<LLButton>("forward_btn");
  160. mForwardButton->setClickedCallback(onClickForward, this);
  161. mReloadButton = getChild<LLButton>("reload_btn");
  162. mReloadButton->setClickedCallback(onClickReload, this);
  163. mSelectionRadio = getChild<LLRadioGroup>("web_site");
  164. if (gIsInSecondLife)
  165. {
  166. U32 selection = gSavedSettings.getU32("WebSearchSiteSelection");
  167. mSelectionRadio->selectNthItem(selection);
  168. mSelectionRadio->setCommitCallback(onCommitSelectionRadio);
  169. mSelectionRadio->setCallbackUserData(this);
  170. }
  171. else
  172. {
  173. mSelectionRadio->setVisible(false);
  174. }
  175. mWebBrowser = getChild<LLMediaCtrl>("find_browser");
  176. mWebBrowser->addObserver(this);
  177. // We need to handle secondlife:///app/ URLs for direct teleports
  178. mWebBrowser->setTrusted(true);
  179. // Redirect 404 pages from S3 somewhere else
  180. mWebBrowser->setErrorPageURL(getString("redirect_404_url"));
  181. search();
  182. return true;
  183. }
  184. HBPanelWebSearch::~HBPanelWebSearch()
  185. {
  186. if (mWebBrowser)
  187. {
  188. mWebBrowser->remObserver(this);
  189. }
  190. }
  191. //virtual
  192. void HBPanelWebSearch::draw()
  193. {
  194. if (mWebBrowser)
  195. {
  196. // Enable/disable buttons depending on state
  197. mBackButton->setEnabled(mWebBrowser->canNavigateBack());
  198. mForwardButton->setEnabled(mWebBrowser->canNavigateForward());
  199. }
  200. LLPanelDirBrowser::draw();
  201. }
  202. //virtual
  203. void HBPanelWebSearch::reshape(S32 width, S32 height, bool called_from_parent)
  204. {
  205. #if 0
  206. handleMediaEvent(NULL, MEDIA_EVENT_NAVIGATE_BEGIN);
  207. #endif
  208. if (mWebBrowser)
  209. {
  210. mWebBrowser->navigateTo(mWebBrowser->getCurrentNavUrl());
  211. }
  212. LLUICtrl::reshape(width, height, called_from_parent);
  213. }
  214. // When we show any web browser-based view, we want to hide all the right-side
  215. // XUI detail panels.
  216. //virtual
  217. void HBPanelWebSearch::onVisibilityChange(bool new_visibility)
  218. {
  219. if (new_visibility)
  220. {
  221. mFloaterSearch->hideAllDetailPanels();
  222. }
  223. LLPanel::onVisibilityChange(new_visibility);
  224. }
  225. // Note: we actually do not use any more the search_text in the viewer code
  226. // calling this method (which is now limited to this panel code). This is
  227. // because LL broke simple category/query searches in its latest (Nov 2021) web
  228. // search engine version... Searches from the status bar (which was the only
  229. // consumer of this method outside this module) are now done via the old (but
  230. // universal and stable for the past 15 years) non-web interface. HB
  231. void HBPanelWebSearch::search(const std::string& search_text)
  232. {
  233. std::string url;
  234. if (gIsInSecondLife)
  235. {
  236. S32 selection = mSelectionRadio->getSelectedIndex();
  237. if (selection == 1)
  238. {
  239. url = getString("showcase_url");
  240. mWebBrowser->navigateTo(url);
  241. }
  242. else if (selection == 2)
  243. {
  244. url = getString("marketplace_url");
  245. }
  246. else
  247. {
  248. url = gSavedSettings.getString("SearchURL");
  249. }
  250. }
  251. else
  252. {
  253. url = sOSSearchURL;
  254. }
  255. if (url.empty())
  256. {
  257. // This happens when the panel is created while logged in an OpenSim
  258. // grid without a search URL.
  259. return;
  260. }
  261. LLStringUtil::format_map_t subs;
  262. #if 0 // Not used: see the note above. HB
  263. if (!search_text.empty() || url.find("[QUERY]" != std::string::npos))
  264. {
  265. if (!gIsInSecondLife)
  266. {
  267. // By default, do a standard search in places...
  268. subs["[SEARCH_TYPE]"] = "standard";
  269. subs["[COLLECTION]"] = "places";
  270. }
  271. else if (url.find("[QUERY]") == std::string::npos)
  272. {
  273. // Missing query field in the search url (seen in Speculoos), let's
  274. // add one (assumption is made that that field is "q=<querry>",
  275. // which is reasonnable enough):
  276. llwarns_sparse << "Missing query field in the search URL... Using SL's OLD search engine query format..."
  277. << llendl;
  278. if (url.find('?') == std::string::npos)
  279. {
  280. url += "?";
  281. }
  282. else if (url.rfind('&') != url.length() - 1)
  283. {
  284. url += "&";
  285. }
  286. url += "q=[QUERY]";
  287. }
  288. subs["[QUERY]"] = LLURI::escape(search_text);
  289. }
  290. #else // Make any query parameter a no-operation
  291. if (!gIsInSecondLife && url.find("[QUERY]") != std::string::npos)
  292. {
  293. // Make sure we will not search for "[QUERY]" in OpenSim grids !
  294. subs["[QUERY]"] = LLStringUtil::null;
  295. }
  296. #endif
  297. if (!gIsInSecondLife && url.find("[CATEGORY]") != std::string::npos)
  298. {
  299. subs["[CATEGORY]"] = "search"; // Means "everything"
  300. // Warn when not in SL, since we do not have a documented list of
  301. // allowed categories in search queries...
  302. llwarns_sparse << "There is a category field in the search URL, but valid categories for this grid are unknown: using SL's old search engine global category..."
  303. << llendl;
  304. }
  305. if (url.find("[MATURITY]") != std::string::npos)
  306. {
  307. std::string maturity;
  308. if (gAgent.prefersAdult())
  309. {
  310. maturity = gIsInSecondLife ? "gma" : "42"; // PG, Mature, Adult
  311. }
  312. else if (gAgent.prefersMature())
  313. {
  314. maturity = gIsInSecondLife ? "gm" : "21"; // PG, Mature
  315. }
  316. else
  317. {
  318. maturity = gIsInSecondLife ? "g" : "13"; // PG
  319. }
  320. // Add the user's maturity preferences/ranking
  321. subs["[MATURITY]"] = maturity;
  322. // Warn when not in SL, since we do not have a documented way to encode
  323. // the maturity rating in search queries...
  324. if (!gIsInSecondLife)
  325. {
  326. llwarns_sparse << "There is a maturity field in the search URL, but its encoding for this grid is unknown: using SL's old search engine encoding conventions..."
  327. << llendl;
  328. }
  329. }
  330. if (url.find("[TEEN]") != std::string::npos)
  331. {
  332. // Add the agent's teen status
  333. subs["[TEEN]"] = gAgent.isTeen() ? "y" : "n";
  334. }
  335. // Expand all our substitutions and also [LANGUAGE], [VERSION], etc...
  336. url = LLWeb::expandURLSubstitutions(url, subs);
  337. handleMediaEvent(NULL, MEDIA_EVENT_NAVIGATE_BEGIN);
  338. mWebBrowser->navigateTo(url);
  339. }
  340. //static
  341. void HBPanelWebSearch::onClickBack(void* data)
  342. {
  343. HBPanelWebSearch* self = (HBPanelWebSearch*)data;
  344. if (self)
  345. {
  346. self->handleMediaEvent(NULL, MEDIA_EVENT_NAVIGATE_BEGIN);
  347. self->mWebBrowser->navigateBack();
  348. }
  349. }
  350. //static
  351. void HBPanelWebSearch::onClickForward(void* data)
  352. {
  353. HBPanelWebSearch* self = (HBPanelWebSearch*)data;
  354. if (self)
  355. {
  356. self->handleMediaEvent(NULL, MEDIA_EVENT_NAVIGATE_BEGIN);
  357. self->mWebBrowser->navigateForward();
  358. }
  359. }
  360. //static
  361. void HBPanelWebSearch::onClickReload(void* data)
  362. {
  363. HBPanelWebSearch* self = (HBPanelWebSearch*)data;
  364. if (self)
  365. {
  366. std::string url = self->mWebBrowser->getCurrentNavUrl();
  367. self->mReloading = true;
  368. self->mWebBrowser->navigateTo("about:blank");
  369. self->mWebBrowser->navigateTo(url);
  370. self->handleMediaEvent(NULL, MEDIA_EVENT_NAVIGATE_BEGIN);
  371. }
  372. }
  373. //static
  374. void HBPanelWebSearch::onCommitSelectionRadio(LLUICtrl* ctrl, void* data)
  375. {
  376. HBPanelWebSearch* self = (HBPanelWebSearch*)data;
  377. if (self)
  378. {
  379. S32 selection = self->mSelectionRadio->getSelectedIndex();
  380. if (selection >= 0)
  381. {
  382. gSavedSettings.setU32("WebSearchSiteSelection", selection);
  383. }
  384. self->search();
  385. }
  386. }
  387. //virtual
  388. void HBPanelWebSearch::handleMediaEvent(LLPluginClassMedia*,
  389. EMediaEvent event)
  390. {
  391. switch (event)
  392. {
  393. case MEDIA_EVENT_NAVIGATE_BEGIN:
  394. {
  395. mReloadButton->setEnabled(false);
  396. childSetText("status_text", getString("loading_text"));
  397. break;
  398. }
  399. case MEDIA_EVENT_NAVIGATE_COMPLETE:
  400. {
  401. std::string url = mWebBrowser->getCurrentNavUrl();
  402. if (!mReloading || url != "about:blank")
  403. {
  404. mReloading = false;
  405. mReloadButton->setEnabled(true);
  406. childSetText("status_text", getString("done_text"));
  407. }
  408. break;
  409. }
  410. default: // Let's ignore other events
  411. break;
  412. }
  413. }
  414. ///////////////////////////////////////////////////////////////////////////////
  415. // HBFloaterSearch class proper
  416. ///////////////////////////////////////////////////////////////////////////////
  417. //static
  418. bool HBFloaterSearch::sSearchURLSetOnLogin = false;
  419. HBFloaterSearch::HBFloaterSearch(const LLSD&)
  420. : mSearchWebPanel(NULL),
  421. mFindAllPanel(NULL),
  422. mEventsPanel(NULL),
  423. mLandPanel(NULL),
  424. mPanelAvatarp(NULL),
  425. mPanelEventp(NULL),
  426. mPanelGroupp(NULL),
  427. mPanelGroupHolderp(NULL),
  428. mPanelPlacep(NULL),
  429. mPanelPlaceSmallp(NULL),
  430. mPanelClassifiedp(NULL)
  431. {
  432. // Build the floater with our tab panel classes
  433. LLCallbackMap::map_t factory_map;
  434. factory_map["find_all_panel"] = LLCallbackMap(createFindAll, this);
  435. factory_map["classified_panel"] = LLCallbackMap(createClassified, this);
  436. factory_map["events_panel"] = LLCallbackMap(createEvents, this);
  437. factory_map["places_panel"] = LLCallbackMap(createPlaces, this);
  438. factory_map["land_sales_panel"] = LLCallbackMap(createLand, this);
  439. factory_map["people_panel"] = LLCallbackMap(createPeople, this);
  440. factory_map["groups_panel"] = LLCallbackMap(createGroups, this);
  441. factory_map["web_search_panel"] = LLCallbackMap(createWebSearch, this);
  442. factory_map["classified_details_panel"] =
  443. LLCallbackMap(createClassifiedDetail, this);
  444. factory_map["event_details_panel"] =
  445. LLCallbackMap(createEventDetail, this);
  446. factory_map["group_details_panel"] =
  447. LLCallbackMap(createGroupDetail, this);
  448. factory_map["group_details_panel_holder"] =
  449. LLCallbackMap(createGroupDetailHolder, this);
  450. factory_map["place_details_panel"] =
  451. LLCallbackMap(createPlaceDetail, this);
  452. factory_map["place_details_small_panel"] =
  453. LLCallbackMap(createPlaceDetailSmall, this);
  454. factory_map["Panel Avatar"] = LLCallbackMap(createPanelAvatar, this);
  455. LLUICtrlFactory::getInstance()->buildFloater(this,
  456. "floater_directory.xml",
  457. &factory_map);
  458. moveResizeHandlesToFront();
  459. mTabsContainer = getChild<LLTabContainer>("Directory Tabs");
  460. // There is not always a web search URL in OpenSim drids...
  461. if (!gIsInSecondLife && mSearchWebPanel &&
  462. HBPanelWebSearch::getOSSearchURL().empty())
  463. {
  464. mTabsContainer->removeTabPanel(mSearchWebPanel);
  465. delete mSearchWebPanel;
  466. mSearchWebPanel = NULL;
  467. }
  468. if (mPanelAvatarp)
  469. {
  470. mPanelAvatarp->selectTab(0);
  471. }
  472. childSetTabChangeCallback("Directory Tabs", "find_all_panel",
  473. onTabChanged, this);
  474. childSetTabChangeCallback("Directory Tabs", "classified_panel",
  475. onTabChanged, this);
  476. childSetTabChangeCallback("Directory Tabs", "events_panel",
  477. onTabChanged, this);
  478. childSetTabChangeCallback("Directory Tabs", "places_panel",
  479. onTabChanged, this);
  480. childSetTabChangeCallback("Directory Tabs", "land_sales_panel",
  481. onTabChanged, this);
  482. childSetTabChangeCallback("Directory Tabs", "people_panel",
  483. onTabChanged, this);
  484. childSetTabChangeCallback("Directory Tabs", "groups_panel",
  485. onTabChanged, this);
  486. childSetTabChangeCallback("Directory Tabs", "web_search_panel",
  487. onTabChanged, this);
  488. mTeleportArrivingConnection =
  489. gViewerParcelMgr.setTPArrivingCallback(boost::bind(&HBFloaterSearch::onTeleportArriving));
  490. }
  491. //virtual
  492. HBFloaterSearch::~HBFloaterSearch()
  493. {
  494. mTeleportArrivingConnection.disconnect();
  495. // Note: this function is defined in the class LLFloater. However, it
  496. // causes crash if this line is postponed to ~LLFloater() because it uses
  497. // some pointers deleted below. That is, those pointers are used again
  498. // after deleting.
  499. setMinimized(false);
  500. delete mPanelAvatarp;
  501. mPanelAvatarp = NULL;
  502. delete mPanelEventp;
  503. mPanelEventp = NULL;
  504. delete mPanelGroupp;
  505. mPanelGroupp = NULL;
  506. delete mPanelGroupHolderp;
  507. mPanelGroupHolderp = NULL;
  508. delete mPanelPlacep;
  509. mPanelPlacep = NULL;
  510. delete mPanelPlaceSmallp;
  511. mPanelPlaceSmallp = NULL;
  512. delete mPanelClassifiedp;
  513. mPanelClassifiedp = NULL;
  514. gSavedSettings.setBool("ShowSearch", false);
  515. }
  516. //virtual
  517. void HBFloaterSearch::setVisible(bool visible)
  518. {
  519. gSavedSettings.setBool("ShowSearch", visible);
  520. LLFloater::setVisible(visible);
  521. }
  522. void HBFloaterSearch::focusCurrentPanel()
  523. {
  524. LLPanel* panel = mTabsContainer->getCurrentPanel();
  525. if (panel)
  526. {
  527. panel->setFocus(true);
  528. }
  529. }
  530. //static
  531. void* HBFloaterSearch::createFindAll(void* userdata)
  532. {
  533. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  534. self->mFindAllPanel = new LLPanelDirFind("find_all_panel", self);
  535. return self->mFindAllPanel;
  536. }
  537. //static
  538. void* HBFloaterSearch::createClassified(void* userdata)
  539. {
  540. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  541. self->mClassifiedPanel = new LLPanelDirClassified("classified_panel",
  542. self);
  543. return self->mClassifiedPanel;
  544. }
  545. //static
  546. void* HBFloaterSearch::createEvents(void* userdata)
  547. {
  548. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  549. self->mEventsPanel = new LLPanelDirEvents("events_panel", self);
  550. return self->mEventsPanel;
  551. }
  552. //static
  553. void* HBFloaterSearch::createPlaces(void* userdata)
  554. {
  555. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  556. return new LLPanelDirPlaces("places_panel", self);
  557. }
  558. //static
  559. void* HBFloaterSearch::createLand(void* userdata)
  560. {
  561. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  562. self->mLandPanel = new LLPanelDirLand("land_panel", self);
  563. return self->mLandPanel;
  564. }
  565. //static
  566. void* HBFloaterSearch::createPeople(void* userdata)
  567. {
  568. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  569. return new LLPanelDirPeople("people_panel", self);
  570. }
  571. //static
  572. void* HBFloaterSearch::createGroups(void* userdata)
  573. {
  574. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  575. return new LLPanelDirGroups("groups_panel", self);
  576. }
  577. //static
  578. void* HBFloaterSearch::createWebSearch(void* userdata)
  579. {
  580. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  581. self->mSearchWebPanel = new HBPanelWebSearch("web_search_panel", self);
  582. return self->mSearchWebPanel;
  583. }
  584. //static
  585. void* HBFloaterSearch::createClassifiedDetail(void* userdata)
  586. {
  587. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  588. self->mPanelClassifiedp = new LLPanelClassified(true, false);
  589. self->mPanelClassifiedp->setVisible(false);
  590. return self->mPanelClassifiedp;
  591. }
  592. //static
  593. void* HBFloaterSearch::createPanelAvatar(void* userdata)
  594. {
  595. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  596. // Note: false to disallow editing in search context (SL-48632):
  597. self->mPanelAvatarp = new LLPanelAvatar("Avatar", LLRect(), false);
  598. self->mPanelAvatarp->setVisible(false);
  599. return self->mPanelAvatarp;
  600. }
  601. //static
  602. void* HBFloaterSearch::createEventDetail(void* userdata)
  603. {
  604. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  605. self->mPanelEventp = new LLPanelEvent();
  606. LLUICtrlFactory::getInstance()->buildPanel(self->mPanelEventp,
  607. "panel_event.xml");
  608. self->mPanelEventp->setVisible(false);
  609. return self->mPanelEventp;
  610. }
  611. //static
  612. void* HBFloaterSearch::createGroupDetail(void* userdata)
  613. {
  614. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  615. self->mPanelGroupp = new LLPanelGroup("panel_group.xml",
  616. "PanelGroup",
  617. gAgent.getGroupID());
  618. // Gods can always edit panels
  619. self->mPanelGroupp->setAllowEdit(gAgent.isGodlike());
  620. self->mPanelGroupp->setVisible(false);
  621. return self->mPanelGroupp;
  622. }
  623. //static
  624. void* HBFloaterSearch::createGroupDetailHolder(void* userdata)
  625. {
  626. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  627. self->mPanelGroupHolderp = new LLPanel(std::string("PanelGroupHolder"));
  628. self->mPanelGroupHolderp->setVisible(false);
  629. return self->mPanelGroupHolderp;
  630. }
  631. //static
  632. void* HBFloaterSearch::createPlaceDetail(void* userdata)
  633. {
  634. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  635. self->mPanelPlacep = new LLPanelPlace(false);
  636. LLUICtrlFactory::getInstance()->buildPanel(self->mPanelPlacep,
  637. "panel_place.xml");
  638. self->mPanelPlacep->setVisible(false);
  639. return self->mPanelPlacep;
  640. }
  641. //static
  642. void* HBFloaterSearch::createPlaceDetailSmall(void* userdata)
  643. {
  644. HBFloaterSearch* self = (HBFloaterSearch*)userdata;
  645. self->mPanelPlaceSmallp = new LLPanelPlace(false);
  646. LLUICtrlFactory::getInstance()->buildPanel(self->mPanelPlaceSmallp,
  647. "panel_place_small.xml");
  648. self->mPanelPlaceSmallp->setVisible(false);
  649. return self->mPanelPlaceSmallp;
  650. }
  651. //static
  652. void HBFloaterSearch::setSearchURL(const std::string& url, bool on_login)
  653. {
  654. sSearchURLSetOnLogin = on_login;
  655. if (gIsInSecondLife)
  656. {
  657. // Nothing else to do: SL got its own, hard-coded search URL...
  658. return;
  659. }
  660. HBPanelWebSearch::setOSSearchURL(url);
  661. HBFloaterSearch* self = findInstance();
  662. if (!self)
  663. {
  664. // Nothing else to do: the tabs will be created as needed on floater
  665. // opening...
  666. return;
  667. }
  668. bool url_is_empty = url.empty();
  669. if (url_is_empty && self->mSearchWebPanel)
  670. {
  671. // No web search available... Remove the tab.
  672. self->mTabsContainer->removeTabPanel(self->mSearchWebPanel);
  673. delete self->mSearchWebPanel;
  674. self->mSearchWebPanel = NULL;
  675. }
  676. else if (!url_is_empty && !self->mSearchWebPanel)
  677. {
  678. // No "Web search" tab while the URL is not empty... We need to destroy
  679. // the floater in order to get back the tab after the floater will be
  680. // re-opened...
  681. self->close();
  682. }
  683. }
  684. //static
  685. bool HBFloaterSearch::wasSearchURLSetOnLogin()
  686. {
  687. return sSearchURLSetOnLogin;
  688. }
  689. //static
  690. void HBFloaterSearch::requestClassifieds()
  691. {
  692. HBFloaterSearch* self = findInstance();
  693. if (self && self->mClassifiedPanel)
  694. {
  695. self->mClassifiedPanel->performQuery();
  696. }
  697. }
  698. //static
  699. void HBFloaterSearch::showFindAll(const std::string& text)
  700. {
  701. showPanel("find_all_panel");
  702. HBFloaterSearch* self = findInstance();
  703. if (self && self->mFindAllPanel)
  704. {
  705. self->mFindAllPanel->search(text);
  706. }
  707. }
  708. //static
  709. void HBFloaterSearch::showClassified(const LLUUID& classified_id)
  710. {
  711. showPanel("classified_panel");
  712. HBFloaterSearch* self = findInstance();
  713. if (self && self->mClassifiedPanel)
  714. {
  715. self->mClassifiedPanel->selectByUUID(classified_id);
  716. }
  717. }
  718. //static
  719. void HBFloaterSearch::showEvents(S32 event_id)
  720. {
  721. showPanel("events_panel");
  722. HBFloaterSearch* self = findInstance();
  723. if (self && self->mEventsPanel)
  724. {
  725. if (event_id != 0)
  726. {
  727. self->mEventsPanel->selectEventByID(event_id);
  728. }
  729. else
  730. {
  731. // Force a query for today's events
  732. self->mEventsPanel->setDay(0);
  733. self->mEventsPanel->performQuery();
  734. }
  735. }
  736. }
  737. //static
  738. void HBFloaterSearch::showLandForSale(const LLUUID& parcel_id)
  739. {
  740. showPanel("land_sales_panel");
  741. HBFloaterSearch* self = findInstance();
  742. if (self && self->mLandPanel)
  743. {
  744. self->mLandPanel->selectByUUID(parcel_id);
  745. }
  746. }
  747. //static
  748. void HBFloaterSearch::showGroups()
  749. {
  750. showPanel("groups_panel");
  751. }
  752. //static
  753. void HBFloaterSearch::refreshGroup(const LLUUID& group_id)
  754. {
  755. HBFloaterSearch* self = findInstance();
  756. if (self && self->mPanelGroupp && self->mPanelGroupp->getID() == group_id)
  757. {
  758. self->mPanelGroupp->refreshData();
  759. }
  760. }
  761. //static
  762. void HBFloaterSearch::showPanel(const std::string& tabname)
  763. {
  764. // This function gets called when web browser clicks are processed, so we
  765. // do not delete the existing panel, which would delete the web browser
  766. // instance currently handling the click. JC
  767. // Get current instance or create a new one if none exist yet.
  768. HBFloaterSearch* self = getInstance();
  769. if (self) // Paranoia (could happen when out of memory)
  770. {
  771. self->open();
  772. self->childShowTab("Directory Tabs", tabname);
  773. self->focusCurrentPanel();
  774. }
  775. }
  776. //static
  777. void HBFloaterSearch::toggle()
  778. {
  779. HBFloaterSearch* self = findInstance();
  780. if (self)
  781. {
  782. if (self->getVisible())
  783. {
  784. self->setVisible(false);
  785. }
  786. else
  787. {
  788. self->open();
  789. self->focusCurrentPanel();
  790. }
  791. return;
  792. }
  793. std::string panel = gSavedSettings.getString("LastFindPanel");
  794. // These panels got renamed...
  795. if (panel == "find_all_old_panel")
  796. {
  797. panel = "find_all_panel";
  798. }
  799. if (panel == "sl_panel")
  800. {
  801. panel = "web_search_panel";
  802. }
  803. if (!gIsInSecondLife && panel == "web_search_panel" &&
  804. HBPanelWebSearch::getOSSearchURL().empty())
  805. {
  806. panel = "find_all_panel";
  807. }
  808. showPanel(panel); // Creates a new instance
  809. // *HACK: force query for today's events
  810. self = findInstance();
  811. if (self && self->mEventsPanel)
  812. {
  813. self->mEventsPanel->setDay(0);
  814. }
  815. }
  816. //static
  817. void HBFloaterSearch::onTeleportArriving()
  818. {
  819. HBFloaterSearch* self = findInstance();
  820. if (self && !self->isMinimized() &&
  821. gSavedSettings.getBool("HideFloatersOnTPSuccess"))
  822. {
  823. self->setVisible(false);
  824. }
  825. }
  826. //static
  827. void HBFloaterSearch::onTabChanged(void* data, bool from_click)
  828. {
  829. HBFloaterSearch* self = (HBFloaterSearch*)data;
  830. if (!self) return;
  831. LLPanel* panel = self->childGetVisibleTab("Directory Tabs");
  832. if (panel)
  833. {
  834. gSavedSettings.setString("LastFindPanel", panel->getName());
  835. }
  836. }
  837. void HBFloaterSearch::hideAllDetailPanels()
  838. {
  839. if (mPanelAvatarp)
  840. {
  841. mPanelAvatarp->setVisible(false);
  842. }
  843. if (mPanelEventp)
  844. {
  845. mPanelEventp->setVisible(false);
  846. }
  847. if (mPanelGroupp)
  848. {
  849. mPanelGroupp->setVisible(false);
  850. }
  851. if (mPanelGroupHolderp)
  852. {
  853. mPanelGroupHolderp->setVisible(false);
  854. }
  855. if (mPanelPlacep)
  856. {
  857. mPanelPlacep->setVisible(false);
  858. }
  859. if (mPanelPlaceSmallp)
  860. {
  861. mPanelPlaceSmallp->setVisible(false);
  862. }
  863. if (mPanelClassifiedp)
  864. {
  865. mPanelClassifiedp->setVisible(false);
  866. }
  867. }