lllocationinputctrl.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:33k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file lllocationinputctrl.cpp
  3.  * @brief Combobox-like location input control
  4.  *
  5.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2009-2010, 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. // file includes
  34. #include "lllocationinputctrl.h"
  35. // common includes
  36. #include "llbutton.h"
  37. #include "llfocusmgr.h"
  38. #include "llmenugl.h"
  39. #include "llparcel.h"
  40. #include "llstring.h"
  41. #include "lltrans.h"
  42. #include "lluictrlfactory.h"
  43. #include "lltooltip.h"
  44. #include "llnotificationsutil.h"
  45. #include "llregionflags.h"
  46. // newview includes
  47. #include "llagent.h"
  48. #include "llinventoryobserver.h"
  49. #include "lllandmarkactions.h"
  50. #include "lllandmarklist.h"
  51. #include "lllocationhistory.h"
  52. #include "llteleporthistory.h"
  53. #include "llsidetray.h"
  54. #include "llslurl.h"
  55. #include "llstatusbar.h" // getHealth()
  56. #include "lltrans.h"
  57. #include "llviewerinventory.h"
  58. #include "llviewerparcelmgr.h"
  59. #include "llviewerregion.h"
  60. #include "llviewercontrol.h"
  61. #include "llviewermenu.h"
  62. #include "llurllineeditorctrl.h"
  63. #include "llagentui.h"
  64. //============================================================================
  65. /*
  66.  * "ADD LANDMARK" BUTTON UPDATING LOGIC
  67.  * 
  68.  * If the current parcel has been landmarked, we should draw
  69.  * a special image on the button.
  70.  * 
  71.  * To avoid determining the appropriate image on every draw() we do that
  72.  * only in the following cases:
  73.  * 1) Navbar is shown for the first time after login.
  74.  * 2) Agent moves to another parcel.
  75.  * 3) A landmark is created or removed.
  76.  * 
  77.  * The first case is handled by the handleLoginComplete() method.
  78.  * 
  79.  * The second case is handled by setting the "agent parcel changed" callback
  80.  * on LLViewerParcelMgr.
  81.  * 
  82.  * The third case is the most complex one. We have two inventory observers for that:
  83.  * one is designated to handle adding landmarks, the other handles removal.
  84.  * Let's see how the former works.
  85.  * 
  86.  * When we get notified about landmark addition, the landmark position is unknown yet. What we can
  87.  * do at that point is initiate loading the landmark data by LLLandmarkList and set the
  88.  * "loading finished" callback on it. Finally, when the callback is triggered,
  89.  * we can determine whether the landmark refers to a point within the current parcel
  90.  * and choose the appropriate image for the "Add landmark" button.
  91.  */
  92. /**
  93.  * Initiates loading the landmarks that have been just added.
  94.  *
  95.  * Once the loading is complete we'll be notified
  96.  * with the callback we set for LLLandmarkList.
  97.  */
  98. class LLAddLandmarkObserver : public LLInventoryAddedObserver
  99. {
  100. public:
  101. LLAddLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {}
  102. private:
  103. /*virtual*/ void done()
  104. {
  105. std::vector<LLUUID>::const_iterator it = mAdded.begin(), end = mAdded.end();
  106. for(; it != end; ++it)
  107. {
  108. LLInventoryItem* item = gInventory.getItem(*it);
  109. if (!item || item->getType() != LLAssetType::AT_LANDMARK)
  110. continue;
  111. // Start loading the landmark.
  112. LLLandmark* lm = gLandmarkList.getAsset(
  113. item->getAssetUUID(),
  114. boost::bind(&LLLocationInputCtrl::onLandmarkLoaded, mInput, _1));
  115. if (lm)
  116. {
  117. // Already loaded? Great, handle it immediately (the callback won't be called).
  118. mInput->onLandmarkLoaded(lm);
  119. }
  120. }
  121. mAdded.clear();
  122. }
  123. LLLocationInputCtrl* mInput;
  124. };
  125. /**
  126.  * Updates the "Add landmark" button once a landmark gets removed.
  127.  */
  128. class LLRemoveLandmarkObserver : public LLInventoryObserver
  129. {
  130. public:
  131. LLRemoveLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {}
  132. private:
  133. /*virtual*/ void changed(U32 mask)
  134. {
  135. if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD)))
  136. {
  137. mInput->updateAddLandmarkButton();
  138. }
  139. }
  140. LLLocationInputCtrl* mInput;
  141. };
  142. class LLParcelChangeObserver : public LLParcelObserver
  143. {
  144. public:
  145. LLParcelChangeObserver(LLLocationInputCtrl* input) : mInput(input) {}
  146. private:
  147. /*virtual*/ void changed()
  148. {
  149. if (mInput)
  150. {
  151. mInput->refreshParcelIcons();
  152. }
  153. }
  154. LLLocationInputCtrl* mInput;
  155. };
  156. //============================================================================
  157. static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input");
  158. LLLocationInputCtrl::Params::Params()
  159. : icon_maturity_general("icon_maturity_general"),
  160. icon_maturity_adult("icon_maturity_adult"),
  161. add_landmark_image_enabled("add_landmark_image_enabled"),
  162. add_landmark_image_disabled("add_landmark_image_disabled"),
  163. add_landmark_image_hover("add_landmark_image_hover"),
  164. add_landmark_image_selected("add_landmark_image_selected"),
  165. add_landmark_hpad("add_landmark_hpad", 0),
  166. icon_hpad("icon_hpad", 0),
  167. add_landmark_button("add_landmark_button"),
  168. for_sale_button("for_sale_button"),
  169. info_button("info_button"),
  170. maturity_icon("maturity_icon"),
  171. voice_icon("voice_icon"),
  172. fly_icon("fly_icon"),
  173. push_icon("push_icon"),
  174. build_icon("build_icon"),
  175. scripts_icon("scripts_icon"),
  176. damage_icon("damage_icon"),
  177. damage_text("damage_text")
  178. {
  179. }
  180. LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
  181. : LLComboBox(p),
  182. mIconHPad(p.icon_hpad),
  183. mAddLandmarkHPad(p.add_landmark_hpad),
  184. mLocationContextMenu(NULL),
  185. mAddLandmarkBtn(NULL),
  186. mForSaleBtn(NULL),
  187. mInfoBtn(NULL),
  188. mLandmarkImageOn(NULL),
  189. mLandmarkImageOff(NULL),
  190. mIconMaturityGeneral(NULL),
  191. mIconMaturityAdult(NULL)
  192. {
  193. // Lets replace default LLLineEditor with LLLocationLineEditor
  194. // to make needed escaping while copying and cutting url
  195. this->removeChild(mTextEntry);
  196. delete mTextEntry;
  197. // Can't access old mTextEntry fields as they are protected, so lets build new params
  198. // That is C&P from LLComboBox::createLineEditor function
  199. static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
  200. S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
  201. LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
  202. text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
  203. LLLineEditor::Params params = p.combo_editor;
  204. params.rect(text_entry_rect);
  205. params.default_text(LLStringUtil::null);
  206. params.max_length_bytes(p.max_chars);
  207. params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
  208. params.handle_edit_keys_directly(true);
  209. params.commit_on_focus_lost(false);
  210. params.follows.flags(FOLLOWS_ALL);
  211. mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params);
  212. mTextEntry->setContextMenu(NULL);
  213. addChild(mTextEntry);
  214. // LLLineEditor is replaced with LLLocationLineEditor
  215. // "Place information" button.
  216. LLButton::Params info_params = p.info_button;
  217. mInfoBtn = LLUICtrlFactory::create<LLButton>(info_params);
  218. mInfoBtn->setClickedCallback(boost::bind(&LLLocationInputCtrl::onInfoButtonClicked, this));
  219. addChild(mInfoBtn);
  220. // "Add landmark" button.
  221. LLButton::Params al_params = p.add_landmark_button;
  222. // Image for unselected state will be set in updateAddLandmarkButton(),
  223. // it will be either mLandmarkOn or mLandmarkOff
  224. if (p.add_landmark_image_enabled())
  225. {
  226. mLandmarkImageOn = p.add_landmark_image_enabled;
  227. }
  228. if (p.add_landmark_image_disabled())
  229. {
  230. mLandmarkImageOff = p.add_landmark_image_disabled;
  231. }
  232. if(p.add_landmark_image_selected)
  233. {
  234. al_params.image_selected = p.add_landmark_image_selected;
  235. }
  236. if (p.add_landmark_image_hover())
  237. {
  238. al_params.image_hover_unselected = p.add_landmark_image_hover;
  239. }
  240. al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this));
  241. mAddLandmarkBtn = LLUICtrlFactory::create<LLButton>(al_params);
  242. enableAddLandmarkButton(true);
  243. addChild(mAddLandmarkBtn);
  244. if (p.icon_maturity_general())
  245. {
  246. mIconMaturityGeneral = p.icon_maturity_general;
  247. }
  248. if (p.icon_maturity_adult())
  249. {
  250. mIconMaturityAdult = p.icon_maturity_adult;
  251. }
  252. LLIconCtrl::Params maturity_icon = p.maturity_icon;
  253. mMaturityIcon = LLUICtrlFactory::create<LLIconCtrl>(maturity_icon);
  254. addChild(mMaturityIcon);
  255. LLButton::Params for_sale_button = p.for_sale_button;
  256. for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip");
  257. for_sale_button.click_callback.function(
  258. boost::bind(&LLLocationInputCtrl::onForSaleButtonClicked, this));
  259. mForSaleBtn = LLUICtrlFactory::create<LLButton>( for_sale_button );
  260. addChild(mForSaleBtn);
  261. // Parcel property icons
  262. // Must be mouse-opaque so cursor stays as an arrow when hovering to
  263. // see tooltip.
  264. LLIconCtrl::Params voice_icon = p.voice_icon;
  265. voice_icon.tool_tip = LLTrans::getString("LocationCtrlVoiceTooltip");
  266. voice_icon.mouse_opaque = true;
  267. mParcelIcon[VOICE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(voice_icon);
  268. mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, VOICE_ICON));
  269. addChild(mParcelIcon[VOICE_ICON]);
  270. LLIconCtrl::Params fly_icon = p.fly_icon;
  271. fly_icon.tool_tip = LLTrans::getString("LocationCtrlFlyTooltip");
  272. fly_icon.mouse_opaque = true;
  273. mParcelIcon[FLY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(fly_icon);
  274. mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, FLY_ICON));
  275. addChild(mParcelIcon[FLY_ICON]);
  276. LLIconCtrl::Params push_icon = p.push_icon;
  277. push_icon.tool_tip = LLTrans::getString("LocationCtrlPushTooltip");
  278. push_icon.mouse_opaque = true;
  279. mParcelIcon[PUSH_ICON] = LLUICtrlFactory::create<LLIconCtrl>(push_icon);
  280. mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PUSH_ICON));
  281. addChild(mParcelIcon[PUSH_ICON]);
  282. LLIconCtrl::Params build_icon = p.build_icon;
  283. build_icon.tool_tip = LLTrans::getString("LocationCtrlBuildTooltip");
  284. build_icon.mouse_opaque = true;
  285. mParcelIcon[BUILD_ICON] = LLUICtrlFactory::create<LLIconCtrl>(build_icon);
  286. mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, BUILD_ICON));
  287. addChild(mParcelIcon[BUILD_ICON]);
  288. LLIconCtrl::Params scripts_icon = p.scripts_icon;
  289. scripts_icon.tool_tip = LLTrans::getString("LocationCtrlScriptsTooltip");
  290. scripts_icon.mouse_opaque = true;
  291. mParcelIcon[SCRIPTS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(scripts_icon);
  292. mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SCRIPTS_ICON));
  293. addChild(mParcelIcon[SCRIPTS_ICON]);
  294. LLIconCtrl::Params damage_icon = p.damage_icon;
  295. damage_icon.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
  296. damage_icon.mouse_opaque = true;
  297. mParcelIcon[DAMAGE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(damage_icon);
  298. mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, DAMAGE_ICON));
  299. addChild(mParcelIcon[DAMAGE_ICON]);
  300. LLTextBox::Params damage_text = p.damage_text;
  301. damage_text.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
  302. damage_text.mouse_opaque = true;
  303. mDamageText = LLUICtrlFactory::create<LLTextBox>(damage_text);
  304. addChild(mDamageText);
  305. // Register callbacks and load the location field context menu (NB: the order matters).
  306. LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2));
  307. LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2));
  308. setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2));
  309. getTextEntry()->setMouseUpCallback(boost::bind(&LLLocationInputCtrl::changeLocationPresentation, this));
  310. // Load the location field context menu
  311. mLocationContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  312. if (!mLocationContextMenu)
  313. {
  314. llwarns << "Error loading navigation bar context menu" << llendl;
  315. }
  316. getTextEntry()->setRightMouseUpCallback(boost::bind(&LLLocationInputCtrl::onTextEditorRightClicked,this,_2,_3,_4));
  317. updateWidgetlayout();
  318. // - Make the "Add landmark" button updated when either current parcel gets changed
  319. //   or a landmark gets created or removed from the inventory.
  320. // - Update the location string on parcel change.
  321. mParcelMgrConnection = LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(
  322. boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this));
  323. mLocationHistoryConnection = LLLocationHistory::getInstance()->setLoadedCallback(
  324. boost::bind(&LLLocationInputCtrl::onLocationHistoryLoaded, this));
  325. mRemoveLandmarkObserver = new LLRemoveLandmarkObserver(this);
  326. mAddLandmarkObserver = new LLAddLandmarkObserver(this);
  327. gInventory.addObserver(mRemoveLandmarkObserver);
  328. gInventory.addObserver(mAddLandmarkObserver);
  329. mParcelChangeObserver = new LLParcelChangeObserver(this);
  330. LLViewerParcelMgr::getInstance()->addObserver(mParcelChangeObserver);
  331. mAddLandmarkTooltip = LLTrans::getString("LocationCtrlAddLandmarkTooltip");
  332. mEditLandmarkTooltip = LLTrans::getString("LocationCtrlEditLandmarkTooltip");
  333. getChild<LLView>("Location History")->setToolTip(LLTrans::getString("LocationCtrlComboBtnTooltip"));
  334. getChild<LLView>("Place Information")->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));
  335. }
  336. LLLocationInputCtrl::~LLLocationInputCtrl()
  337. {
  338. gInventory.removeObserver(mRemoveLandmarkObserver);
  339. gInventory.removeObserver(mAddLandmarkObserver);
  340. delete mRemoveLandmarkObserver;
  341. delete mAddLandmarkObserver;
  342. LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangeObserver);
  343. delete mParcelChangeObserver;
  344. mParcelMgrConnection.disconnect();
  345. mLocationHistoryConnection.disconnect();
  346. }
  347. void LLLocationInputCtrl::setEnabled(BOOL enabled)
  348. {
  349. LLComboBox::setEnabled(enabled);
  350. mAddLandmarkBtn->setEnabled(enabled);
  351. }
  352. void LLLocationInputCtrl::hideList()
  353. {
  354. LLComboBox::hideList();
  355. if (mTextEntry && hasFocus())
  356. focusTextEntry();
  357. }
  358. BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, MASK mask)
  359. {
  360. if(mAddLandmarkBtn->parentPointInView(x,y))
  361. {
  362. updateAddLandmarkTooltip();
  363. }
  364. // Let the buttons show their tooltips.
  365. if (LLUICtrl::handleToolTip(x, y, mask))
  366. {
  367. if (mList->getRect().pointInRect(x, y)) 
  368. {
  369. S32 loc_x, loc_y;
  370. //x,y - contain coordinates related to the location input control, but without taking the expanded list into account
  371. //So we have to convert it again into local coordinates of mList
  372. localPointToOtherView(x,y,&loc_x,&loc_y,mList);
  373. LLScrollListItem* item =  mList->hitItem(loc_x,loc_y);
  374. if (item)
  375. {
  376. LLSD value = item->getValue();
  377. if (value.has("tooltip"))
  378. {
  379. LLToolTipMgr::instance().show(value["tooltip"]);
  380. }
  381. }
  382. }
  383. return TRUE;
  384. }
  385. return FALSE;
  386. }
  387. BOOL LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask)
  388. {
  389. BOOL result = LLComboBox::handleKeyHere(key, mask);
  390. if (key == KEY_DOWN && hasFocus() && mList->getItemCount() != 0 && !mList->getVisible())
  391. {
  392. showList();
  393. }
  394. return result;
  395. }
  396. void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor)
  397. {
  398. KEY key = gKeyboard->currentKey();
  399. if (line_editor->getText().empty())
  400. {
  401. prearrangeList(); // resets filter
  402. hideList();
  403. }
  404. // Typing? (moving cursor should not affect showing the list)
  405. else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END)
  406. {
  407. prearrangeList(line_editor->getText());
  408. if (mList->getItemCount() != 0)
  409. {
  410. showList();
  411. focusTextEntry();
  412. }
  413. else
  414. {
  415. // Hide the list if it's empty.
  416. hideList();
  417. }
  418. }
  419. LLComboBox::onTextEntry(line_editor);
  420. }
  421. /**
  422.  * Useful if we want to just set the text entry value, no matter what the list contains.
  423.  *
  424.  * This is faster than setTextEntry().
  425.  */
  426. void LLLocationInputCtrl::setText(const LLStringExplicit& text)
  427. {
  428. if (mTextEntry)
  429. {
  430. mTextEntry->setText(text);
  431. }
  432. mHasAutocompletedText = FALSE;
  433. }
  434. void LLLocationInputCtrl::setFocus(BOOL b)
  435. {
  436. LLComboBox::setFocus(b);
  437. if (mTextEntry && b && !mList->getVisible())
  438. {
  439. mTextEntry->setFocus(TRUE);
  440. }
  441. }
  442. void LLLocationInputCtrl::handleLoginComplete()
  443. {
  444. // An agent parcel update hasn't occurred yet, so we have to
  445. // manually set location and the appropriate "Add landmark" icon.
  446. refresh();
  447. }
  448. //== private methods =========================================================
  449. void LLLocationInputCtrl::onFocusReceived()
  450. {
  451. prearrangeList();
  452. }
  453. void LLLocationInputCtrl::onFocusLost()
  454. {
  455. LLUICtrl::onFocusLost();
  456. refreshLocation();
  457. if(mTextEntry->hasSelection()){
  458. mTextEntry->deselect();
  459. }
  460. }
  461. void LLLocationInputCtrl::draw()
  462. {
  463. static LLUICachedControl<bool> show_coords("NavBarShowCoordinates", false);
  464. if(!hasFocus() && show_coords)
  465. {
  466. refreshLocation();
  467. }
  468. static LLUICachedControl<bool> show_icons("NavBarShowParcelProperties", false);
  469. if (show_icons)
  470. {
  471. refreshHealth();
  472. }
  473. LLComboBox::draw();
  474. }
  475. void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
  476. {
  477. LLComboBox::reshape(width, height, called_from_parent);
  478. // Setting cursor to 0  to show the left edge of the text. See EXT-4967.
  479. mTextEntry->setCursor(0);
  480. if (mTextEntry->hasSelection())
  481. {
  482. // Deselecting because selection position is changed together with
  483. // cursor position change.
  484. mTextEntry->deselect();
  485. }
  486. if (isHumanReadableLocationVisible)
  487. {
  488. positionMaturityIcon();
  489. }
  490. }
  491. void LLLocationInputCtrl::onInfoButtonClicked()
  492. {
  493. LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
  494. }
  495. void LLLocationInputCtrl::onForSaleButtonClicked()
  496. {
  497. handle_buy_land();
  498. }
  499. void LLLocationInputCtrl::onAddLandmarkButtonClicked()
  500. {
  501. LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
  502. // Landmark exists, open it for preview and edit
  503. if(landmark && landmark->getUUID().notNull())
  504. {
  505. LLSD key;
  506. key["type"] = "landmark";
  507. key["id"] = landmark->getUUID();
  508. LLSideTray::getInstance()->showPanel("panel_places", key);
  509. }
  510. else
  511. {
  512. LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
  513. }
  514. }
  515. void LLLocationInputCtrl::onAgentParcelChange()
  516. {
  517. refresh();
  518. }
  519. void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm)
  520. {
  521. (void) lm;
  522. updateAddLandmarkButton();
  523. }
  524. void LLLocationInputCtrl::onLocationHistoryLoaded()
  525. {
  526. rebuildLocationHistory();
  527. }
  528. void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data)
  529. {
  530. std::string filter = data.asString();
  531. rebuildLocationHistory(filter);
  532. //Let's add landmarks to the top of the list if any
  533. if(!filter.empty() )
  534. {
  535. LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, TRUE);
  536. for(U32 i=0; i < landmark_items.size(); i++)
  537. {
  538. LLSD value;
  539. //TODO:: DO we need tooltip for Landmark??
  540. value["item_type"] = LANDMARK;
  541. value["AssetUUID"] =  landmark_items[i]->getAssetUUID(); 
  542. add(landmark_items[i]->getName(), value);
  543. }
  544. //Let's add teleport history items
  545. LLTeleportHistory* th = LLTeleportHistory::getInstance();
  546. LLTeleportHistory::slurl_list_t th_items = th->getItems();
  547. std::set<std::string> new_item_titles;// duplicate control
  548. LLTeleportHistory::slurl_list_t::iterator result = std::find_if(
  549. th_items.begin(), th_items.end(), boost::bind(
  550. &LLLocationInputCtrl::findTeleportItemsByTitle, this,
  551. _1, filter));
  552. while (result != th_items.end())
  553. {
  554. //mTitile format - region_name[, parcel_name]
  555. //mFullTitile format - region_name[, parcel_name] (local_x,local_y, local_z)
  556. if (new_item_titles.insert(result->mFullTitle).second)
  557. {
  558. LLSD value;
  559. value["item_type"] = TELEPORT_HISTORY;
  560. value["global_pos"] = result->mGlobalPos.getValue();
  561. std::string region_name = result->mTitle.substr(0, result->mTitle.find(','));
  562. //TODO*: add Surl to teleportitem or parse region name from title
  563. value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name,
  564. result->mGlobalPos, false);
  565. add(result->getTitle(), value); 
  566. }
  567. result = std::find_if(result + 1, th_items.end(), boost::bind(
  568. &LLLocationInputCtrl::findTeleportItemsByTitle, this,
  569. _1, filter));
  570. }
  571. }
  572. sortByName();
  573. mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item.
  574. }
  575. bool LLLocationInputCtrl::findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter)
  576. {
  577. return item.mTitle.find(filter) != std::string::npos;
  578. }
  579. void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask)
  580. {
  581. if (mLocationContextMenu)
  582. {
  583. updateContextMenu();
  584. mLocationContextMenu->buildDrawLabels();
  585. mLocationContextMenu->updateParent(LLMenuGL::sMenuContainer);
  586. hideList();
  587. setFocus(true);
  588. changeLocationPresentation();
  589. LLMenuGL::showPopup(this, mLocationContextMenu, x, y);
  590. }
  591. }
  592. void LLLocationInputCtrl::refresh()
  593. {
  594. refreshLocation(); // update location string
  595. refreshParcelIcons();
  596. updateAddLandmarkButton(); // indicate whether current parcel has been landmarked 
  597. }
  598. void LLLocationInputCtrl::refreshLocation()
  599. {
  600. // Is one of our children focused?
  601. if (LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() ||
  602.     (mTextEntry && mTextEntry->hasFocus()) ||
  603.     (mAddLandmarkBtn->hasFocus()))
  604. {
  605. llwarns << "Location input should not be refreshed when having focus" << llendl;
  606. return;
  607. }
  608. // Update location field.
  609. std::string location_name;
  610. LLAgentUI::ELocationFormat format =
  611. (gSavedSettings.getBOOL("NavBarShowCoordinates")
  612. ? LLAgentUI::LOCATION_FORMAT_FULL
  613. : LLAgentUI::LOCATION_FORMAT_NO_COORDS);
  614. if (!LLAgentUI::buildLocationString(location_name, format)) 
  615. {
  616. location_name = "???";
  617. }
  618. // store human-readable location to compare it in changeLocationPresentation()
  619. mHumanReadableLocation = location_name;
  620. setText(location_name);
  621. isHumanReadableLocationVisible = true;
  622. // Updating maturity rating icon.
  623. LLViewerRegion* region = gAgent.getRegion();
  624. if (!region)
  625. return;
  626. U8 sim_access = region->getSimAccess();
  627. switch(sim_access)
  628. {
  629. case SIM_ACCESS_PG:
  630. mMaturityIcon->setValue(mIconMaturityGeneral->getName());
  631. mMaturityIcon->setVisible(TRUE);
  632. break;
  633. case SIM_ACCESS_ADULT:
  634. mMaturityIcon->setValue(mIconMaturityAdult->getName());
  635. mMaturityIcon->setVisible(TRUE);
  636. break;
  637. default:
  638. mMaturityIcon->setVisible(FALSE);
  639. }
  640. if (mMaturityIcon->getVisible())
  641. {
  642. positionMaturityIcon();
  643. }
  644. }
  645. // returns new right edge
  646. static S32 layout_widget(LLUICtrl* widget, S32 right)
  647. {
  648. if (widget->getVisible())
  649. {
  650. LLRect rect = widget->getRect();
  651. rect.mLeft = right - rect.getWidth();
  652. rect.mRight = right;
  653. widget->setRect( rect );
  654. right -= rect.getWidth();
  655. }
  656. return right;
  657. }
  658. void LLLocationInputCtrl::refreshParcelIcons()
  659. {
  660. // Our "cursor" moving right to left
  661. S32 x = mAddLandmarkBtn->getRect().mLeft;
  662. static LLUICachedControl<bool> show_properties("NavBarShowParcelProperties", false);
  663. if (show_properties)
  664. {
  665. LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
  666. LLViewerRegion* agent_region = gAgent.getRegion();
  667. LLParcel* agent_parcel = vpm->getAgentParcel();
  668. if (!agent_region || !agent_parcel)
  669. return;
  670. LLParcel* current_parcel;
  671. LLViewerRegion* selection_region = vpm->getSelectionRegion();
  672. LLParcel* selected_parcel = vpm->getParcelSelection()->getParcel();
  673. // If agent is in selected parcel we use its properties because
  674. // they are updated more often by LLViewerParcelMgr than agent parcel properties.
  675. // See LLViewerParcelMgr::processParcelProperties().
  676. // This is needed to reflect parcel restrictions changes without having to leave
  677. // the parcel and then enter it again. See EXT-2987
  678. if (selected_parcel && selected_parcel->getLocalID() == agent_parcel->getLocalID()
  679. && selection_region == agent_region)
  680. {
  681. current_parcel = selected_parcel;
  682. }
  683. else
  684. {
  685. current_parcel = agent_parcel;
  686. }
  687. bool allow_buy      = vpm->canAgentBuyParcel(current_parcel, false);
  688. bool allow_voice = vpm->allowAgentVoice(agent_region, current_parcel);
  689. bool allow_fly = vpm->allowAgentFly(agent_region, current_parcel);
  690. bool allow_push = vpm->allowAgentPush(agent_region, current_parcel);
  691. bool allow_build = vpm->allowAgentBuild(current_parcel); // true when anyone is allowed to build. See EXT-4610.
  692. bool allow_scripts = vpm->allowAgentScripts(agent_region, current_parcel);
  693. bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
  694. // Most icons are "block this ability"
  695. mForSaleBtn->setVisible(allow_buy);
  696. mParcelIcon[VOICE_ICON]->setVisible(   !allow_voice );
  697. mParcelIcon[FLY_ICON]->setVisible(     !allow_fly );
  698. mParcelIcon[PUSH_ICON]->setVisible(    !allow_push );
  699. mParcelIcon[BUILD_ICON]->setVisible(   !allow_build );
  700. mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
  701. mParcelIcon[DAMAGE_ICON]->setVisible(  allow_damage );
  702. mDamageText->setVisible(allow_damage);
  703. x = layout_widget(mForSaleBtn, x);
  704. // Padding goes to left of both landmark star and for sale btn
  705. x -= mAddLandmarkHPad;
  706. // Slide the parcel icons rect from right to left, adjusting rectangles
  707. for (S32 i = 0; i < ICON_COUNT; ++i)
  708. {
  709. x = layout_widget(mParcelIcon[i], x);
  710. x -= mIconHPad;
  711. }
  712. x = layout_widget(mDamageText, x);
  713. x -= mIconHPad;
  714. }
  715. else
  716. {
  717. mForSaleBtn->setVisible(false);
  718. for (S32 i = 0; i < ICON_COUNT; ++i)
  719. {
  720. mParcelIcon[i]->setVisible(false);
  721. }
  722. mDamageText->setVisible(false);
  723. }
  724. if (mTextEntry)
  725. {
  726. S32 left_pad, right_pad;
  727. mTextEntry->getTextPadding(&left_pad, &right_pad);
  728. right_pad = mTextEntry->getRect().mRight - x;
  729. mTextEntry->setTextPadding(left_pad, right_pad);
  730. }
  731. }
  732. void LLLocationInputCtrl::refreshHealth()
  733. {
  734. // *FIXME: Status bar owns health information, should be in agent
  735. if (gStatusBar)
  736. {
  737. static S32 last_health = -1;
  738. S32 health = gStatusBar->getHealth();
  739. if (health != last_health)
  740. {
  741. std::string text = llformat("%d%%", health);
  742. mDamageText->setText(text);
  743. last_health = health;
  744. }
  745. }
  746. }
  747. void LLLocationInputCtrl::positionMaturityIcon()
  748. {
  749. const LLFontGL* font = mTextEntry->getFont();
  750. if (!font)
  751. return;
  752. S32 left_pad, right_pad;
  753. mTextEntry->getTextPadding(&left_pad, &right_pad);
  754. // Calculate the right edge of rendered text + a whitespace.
  755. left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" ");
  756. LLRect rect = mMaturityIcon->getRect();
  757. mMaturityIcon->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
  758. // Hide icon if it text area is not width enough to display it, show otherwise.
  759. mMaturityIcon->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
  760. }
  761. void LLLocationInputCtrl::rebuildLocationHistory(std::string filter)
  762. {
  763. LLLocationHistory::location_list_t filtered_items;
  764. const LLLocationHistory::location_list_t* itemsp = NULL;
  765. LLLocationHistory* lh = LLLocationHistory::getInstance();
  766. if (filter.empty())
  767. {
  768. itemsp = &lh->getItems();
  769. }
  770. else
  771. {
  772. lh->getMatchingItems(filter, filtered_items);
  773. itemsp = &filtered_items;
  774. }
  775. removeall();
  776. for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++)
  777. {
  778. LLSD value;
  779. value["tooltip"] = it->getToolTip();
  780. //location history can contain only typed locations
  781. value["item_type"] = TYPED_REGION_SURL;
  782. value["global_pos"] = it->mGlobalPos.getValue();
  783. add(it->getLocation(), value);
  784. }
  785. }
  786. void LLLocationInputCtrl::focusTextEntry()
  787. {
  788. // We can't use "mTextEntry->setFocus(TRUE)" instead because
  789. // if the "select_on_focus" parameter is true it places the cursor
  790. // at the beginning (after selecting text), thus screwing up updateSelection().
  791. if (mTextEntry)
  792. gFocusMgr.setKeyboardFocus(mTextEntry);
  793. }
  794. void LLLocationInputCtrl::enableAddLandmarkButton(bool val)
  795. {
  796. // We don't want to disable the button because it should be click able at any time, 
  797. // instead switch images.
  798. LLUIImage* img = val ? mLandmarkImageOn : mLandmarkImageOff;
  799. if(img)
  800. {
  801. mAddLandmarkBtn->setImageUnselected(img);
  802. }
  803. }
  804. // Change the "Add landmark" button image
  805. // depending on whether current parcel has been landmarked.
  806. void LLLocationInputCtrl::updateAddLandmarkButton()
  807. {
  808. enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark());
  809. }
  810. void LLLocationInputCtrl::updateAddLandmarkTooltip()
  811. {
  812. std::string tooltip;
  813. if(LLLandmarkActions::landmarkAlreadyExists())
  814. {
  815. tooltip = mEditLandmarkTooltip;
  816. }
  817. else
  818. {
  819. tooltip = mAddLandmarkTooltip;
  820. }
  821. mAddLandmarkBtn->setToolTip(tooltip);
  822. }
  823. void LLLocationInputCtrl::updateContextMenu(){
  824. if (mLocationContextMenu)
  825. {
  826. LLMenuItemGL* landmarkItem = mLocationContextMenu->getChild<LLMenuItemGL>("Landmark");
  827. if (!LLLandmarkActions::landmarkAlreadyExists())
  828. {
  829. landmarkItem->setLabel(LLTrans::getString("AddLandmarkNavBarMenu"));
  830. }
  831. else
  832. {
  833. landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
  834. }
  835. }
  836. }
  837. void LLLocationInputCtrl::updateWidgetlayout()
  838. {
  839. const LLRect& rect = getLocalRect();
  840. const LLRect& hist_btn_rect = mButton->getRect();
  841. // Info button is set in the XUI XML location_input.xml
  842. // "Add Landmark" button
  843. LLRect al_btn_rect = mAddLandmarkBtn->getRect();
  844. al_btn_rect.translate(
  845. hist_btn_rect.mLeft - mIconHPad - al_btn_rect.getWidth(),
  846. (rect.getHeight() - al_btn_rect.getHeight()) / 2);
  847. mAddLandmarkBtn->setRect(al_btn_rect);
  848. }
  849. void LLLocationInputCtrl::changeLocationPresentation()
  850. {
  851. if (!mTextEntry)
  852. return;
  853. //change location presentation only if user does not select/paste anything and 
  854. //human-readable region name is being displayed
  855. std::string text = mTextEntry->getText();
  856. LLStringUtil::trim(text);
  857. if(!mTextEntry->hasSelection() && text == mHumanReadableLocation)
  858. {
  859. //needs unescaped one
  860. mTextEntry->setText(LLAgentUI::buildSLURL(false));
  861. mTextEntry->selectAll();
  862. mMaturityIcon->setVisible(FALSE);
  863. isHumanReadableLocationVisible = false;
  864. }
  865. }
  866. void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata)
  867. {
  868. std::string item = userdata.asString();
  869. if (item == "show_coordinates")
  870. {
  871. gSavedSettings.setBOOL("NavBarShowCoordinates",!gSavedSettings.getBOOL("NavBarShowCoordinates"));
  872. }
  873. else if (item == "show_properties")
  874. {
  875. gSavedSettings.setBOOL("NavBarShowParcelProperties",
  876. !gSavedSettings.getBOOL("NavBarShowParcelProperties"));
  877. refreshParcelIcons();
  878. }
  879. else if (item == "landmark")
  880. {
  881. LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
  882. if(!landmark)
  883. {
  884. LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
  885. }
  886. else
  887. {
  888. LLSideTray::getInstance()->showPanel("panel_places", 
  889. LLSD().with("type", "landmark").with("id",landmark->getUUID()));
  890. }
  891. }
  892. else if (item == "cut")
  893. {
  894. mTextEntry->cut();
  895. }
  896. else if (item == "copy")
  897. {
  898. mTextEntry->copy();
  899. }
  900. else if (item == "paste")
  901. {
  902. mTextEntry->paste();
  903. }
  904. else if (item == "delete")
  905. {
  906. mTextEntry->deleteSelection();
  907. }
  908. else if (item == "select_all")
  909. {
  910. mTextEntry->selectAll();
  911. }
  912. }
  913. bool LLLocationInputCtrl::onLocationContextMenuItemEnabled(const LLSD& userdata)
  914. {
  915. std::string item = userdata.asString();
  916. if (item == "can_cut")
  917. {
  918. return mTextEntry->canCut();
  919. }
  920. else if (item == "can_copy")
  921. {
  922. return mTextEntry->canCopy();
  923. }
  924. else if (item == "can_paste")
  925. {
  926. return mTextEntry->canPaste();
  927. }
  928. else if (item == "can_delete")
  929. {
  930. return mTextEntry->canDeselect();
  931. }
  932. else if (item == "can_select_all")
  933. {
  934. return mTextEntry->canSelectAll() && (mTextEntry->getLength() > 0);
  935. }
  936. else if(item == "show_coordinates")
  937. {
  938. return gSavedSettings.getBOOL("NavBarShowCoordinates");
  939. }
  940. return false;
  941. }
  942. void LLLocationInputCtrl::onParcelIconClick(EParcelIcon icon)
  943. {
  944. switch (icon)
  945. {
  946. case VOICE_ICON:
  947. LLNotificationsUtil::add("NoVoice");
  948. break;
  949. case FLY_ICON:
  950. LLNotificationsUtil::add("NoFly");
  951. break;
  952. case PUSH_ICON:
  953. LLNotificationsUtil::add("PushRestricted");
  954. break;
  955. case BUILD_ICON:
  956. LLNotificationsUtil::add("NoBuild");
  957. break;
  958. case SCRIPTS_ICON:
  959. {
  960. LLViewerRegion* region = gAgent.getRegion();
  961. if(region && region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS)
  962. {
  963. LLNotificationsUtil::add("ScriptsStopped");
  964. }
  965. else if(region && region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS)
  966. {
  967. LLNotificationsUtil::add("ScriptsNotRunning");
  968. }
  969. else
  970. {
  971. LLNotificationsUtil::add("NoOutsideScripts");
  972. }
  973. break;
  974. }
  975. case DAMAGE_ICON:
  976. LLNotificationsUtil::add("NotSafe");
  977. break;
  978. case ICON_COUNT:
  979. break;
  980. // no default to get compiler warning when a new icon gets added
  981. }
  982. }