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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfavoritesbar.cpp
  3.  * @brief LLFavoritesBarCtrl class implementation
  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. #include "llfavoritesbar.h"
  34. #include "llfloaterreg.h"
  35. #include "llfocusmgr.h"
  36. #include "llinventory.h"
  37. #include "lllandmarkactions.h"
  38. #include "lltrans.h"
  39. #include "lluictrlfactory.h"
  40. #include "llmenugl.h"
  41. #include "lltooltip.h"
  42. #include "llagent.h"
  43. #include "llclipboard.h"
  44. #include "llinventoryclipboard.h"
  45. #include "llinventorybridge.h"
  46. #include "llfloaterworldmap.h"
  47. #include "lllandmarkactions.h"
  48. #include "llnotificationsutil.h"
  49. #include "llsidetray.h"
  50. #include "lltoggleablemenu.h"
  51. #include "llviewerinventory.h"
  52. #include "llviewermenu.h"
  53. #include "llviewermenu.h"
  54. #include "lltooldraganddrop.h"
  55. static LLDefaultChildRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar");
  56. const S32 DROP_DOWN_MENU_WIDTH = 250;
  57. /**
  58.  * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem.
  59.  * Performing requests for SLURL for given Landmark ID
  60.  */
  61. class LLLandmarkInfoGetter
  62. {
  63. public:
  64. LLLandmarkInfoGetter()
  65. : mLandmarkID(LLUUID::null),
  66. mName("(Loading...)"),
  67. mPosX(0),
  68. mPosY(0),
  69. mPosZ(0),
  70. mLoaded(false) 
  71. {}
  72. void setLandmarkID(const LLUUID& id) { mLandmarkID = id; }
  73. const LLUUID& getLandmarkId() const { return mLandmarkID; }
  74. const std::string& getName()
  75. {
  76. if(!mLoaded)
  77. requestNameAndPos();
  78. return mName;
  79. }
  80. S32 getPosX()
  81. {
  82. if (!mLoaded)
  83. requestNameAndPos();
  84. return mPosX;
  85. }
  86. S32 getPosY()
  87. {
  88. if (!mLoaded)
  89. requestNameAndPos();
  90. return mPosY;
  91. }
  92. S32 getPosZ()
  93. {
  94. if (!mLoaded)
  95. requestNameAndPos();
  96. return mPosZ;
  97. }
  98. private:
  99. /**
  100.  * Requests landmark data from server.
  101.  */
  102. void requestNameAndPos()
  103. {
  104. if (mLandmarkID.isNull())
  105. return;
  106. LLVector3d g_pos;
  107. if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos))
  108. {
  109. LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos,
  110. boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, this, _1, _2, _3, _4));
  111. }
  112. }
  113. void landmarkNameCallback(const std::string& name, S32 x, S32 y, S32 z)
  114. {
  115. mPosX = x;
  116. mPosY = y;
  117. mPosZ = z;
  118. mName = name;
  119. mLoaded = true;
  120. }
  121. LLUUID mLandmarkID;
  122. std::string mName;
  123. S32 mPosX;
  124. S32 mPosY;
  125. S32 mPosZ;
  126. bool mLoaded;
  127. };
  128. /**
  129.  * This class is needed to override LLButton default handleToolTip function and
  130.  * show SLURL as button tooltip.
  131.  * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
  132.  * in createButtons function but landmark data is not available when Favorites Bar is
  133.  * created. Thats why we are requesting landmark data after 
  134.  */
  135. class LLFavoriteLandmarkButton : public LLButton
  136. {
  137. public:
  138. BOOL handleToolTip(S32 x, S32 y, MASK mask)
  139. {
  140. std::string region_name = mLandmarkInfoGetter.getName();
  141. if (!region_name.empty())
  142. {
  143. LLToolTip::Params params;
  144. std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), 
  145. mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ());
  146. params.message = llformat("%sn%s", getLabelSelected().c_str(), extra_message.c_str());
  147. LLRect rect = calcScreenRect();
  148. LLFontGL* standart_font = LLFontGL::getFontSansSerif();
  149. if(standart_font)
  150. {
  151. S32 w = llmax((S32)(standart_font->getWidthF32(getLabelSelected())+0.5),(S32)(standart_font->getWidthF32(extra_message)+0.5));
  152. rect.mRight = rect.mLeft + w;
  153. params.max_width = w;
  154. }
  155. params.sticky_rect = rect; 
  156. LLToolTipMgr::instance().show(params);
  157. }
  158. return TRUE;
  159. }
  160. /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask)
  161. {
  162. LLFavoritesBarCtrl* fb = dynamic_cast<LLFavoritesBarCtrl*>(getParent());
  163. if (fb)
  164. {
  165. fb->handleHover(x, y, mask);
  166. }
  167. return LLButton::handleHover(x, y, mask);
  168. }
  169. void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
  170. const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); }
  171. void onMouseEnter(S32 x, S32 y, MASK mask)
  172. {
  173. if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
  174. {
  175. LLUICtrl::onMouseEnter(x, y, mask);
  176. }
  177. else
  178. {
  179. LLButton::onMouseEnter(x, y, mask);
  180. }
  181. }
  182. protected:
  183. LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {}
  184. friend class LLUICtrlFactory;
  185. private:
  186. LLLandmarkInfoGetter mLandmarkInfoGetter;
  187. };
  188. /**
  189.  * This class is needed to override LLMenuItemCallGL default handleToolTip function and
  190.  * show SLURL as button tooltip.
  191.  * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
  192.  * in showDropDownMenu function but landmark data is not available when Favorites Bar is
  193.  * created. Thats why we are requesting landmark data after 
  194.  */
  195. class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL
  196. {
  197. public:
  198. BOOL handleToolTip(S32 x, S32 y, MASK mask)
  199. {
  200. std::string region_name = mLandmarkInfoGetter.getName();
  201. if (!region_name.empty())
  202. {
  203. LLToolTip::Params params;
  204. params.message = llformat("%sn%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY());
  205. params.sticky_rect = calcScreenRect();
  206. LLToolTipMgr::instance().show(params);
  207. }
  208. return TRUE;
  209. }
  210. void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
  211. virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask)
  212. {
  213. if (mMouseDownSignal)
  214. (*mMouseDownSignal)(this, x, y, mask);
  215. return LLMenuItemCallGL::handleMouseDown(x, y, mask);
  216. }
  217. virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
  218. {
  219. if (mMouseUpSignal)
  220. (*mMouseUpSignal)(this, x, y, mask);
  221. return LLMenuItemCallGL::handleMouseUp(x, y, mask);
  222. }
  223. virtual BOOL handleHover(S32 x, S32 y, MASK mask)
  224. {
  225. if (fb)
  226. {
  227. fb->handleHover(x, y, mask);
  228. }
  229. return TRUE;
  230. }
  231. void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; }
  232. protected:
  233. LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {}
  234. friend class LLUICtrlFactory;
  235. private:
  236. LLLandmarkInfoGetter mLandmarkInfoGetter;
  237. LLFavoritesBarCtrl* fb;
  238. };
  239. /**
  240.  * This class was introduced just for fixing the following issue:
  241.  * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through.
  242.  * We must explicitly handle drag and drop event by returning TRUE
  243.  * because otherwise LLToolDragAndDrop will initiate drag and drop operation
  244.  * with the world.
  245.  */
  246. class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu
  247. {
  248. public:
  249. virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  250.    EDragAndDropType cargo_type,
  251.    void* cargo_data,
  252.    EAcceptance* accept,
  253.    std::string& tooltip_msg)
  254. {
  255. *accept = ACCEPT_NO;
  256. return TRUE;
  257. }
  258. void setVisible(BOOL b)
  259. {
  260. // Overflow menu shouldn't hide when it still has focus. See EXT-4217.
  261. if (!b && hasFocus())
  262. return;
  263. LLToggleableMenu::setVisible(b);
  264. setFocus(b);
  265. }
  266. void onFocusLost()
  267. {
  268. setVisible(FALSE);
  269. }
  270. protected:
  271. LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p):
  272. LLToggleableMenu(p)
  273. {
  274. }
  275. friend class LLUICtrlFactory;
  276. };
  277. /**
  278.  * This class is needed to update an item being copied to the favorites folder
  279.  * with a sort field value (required to save favorites bar's tabs order).
  280.  * See method handleNewFavoriteDragAndDrop for more details on how this class is used.
  281.  */
  282. class LLItemCopiedCallback : public LLInventoryCallback
  283. {
  284. public:
  285. LLItemCopiedCallback(S32 sortField): mSortField(sortField) {}
  286. virtual void fire(const LLUUID& inv_item)
  287. {
  288. LLViewerInventoryItem* item = gInventory.getItem(inv_item);
  289. if (item)
  290. {
  291. item->setSortField(mSortField);
  292. item->setComplete(TRUE);
  293. item->updateServer(FALSE);
  294. gInventory.updateItem(item);
  295. gInventory.notifyObservers();
  296. }
  297. LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
  298. }
  299. private:
  300. S32 mSortField;
  301. };
  302. // updateButtons's helper
  303. struct LLFavoritesSort
  304. {
  305. // Sorting by creation date and name
  306. // TODO - made it customizible using gSavedSettings
  307. bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b)
  308. {
  309. S32 sortField1 = a->getSortField();
  310. S32 sortField2 = b->getSortField();
  311. if (!(sortField1 < 0 && sortField2 < 0))
  312. {
  313. return sortField2 > sortField1;
  314. }
  315. time_t first_create = a->getCreationDate();
  316. time_t second_create = b->getCreationDate();
  317. if (first_create == second_create)
  318. {
  319. return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0);
  320. }
  321. else
  322. {
  323. return (first_create > second_create);
  324. }
  325. }
  326. };
  327. LLFavoritesBarCtrl::Params::Params()
  328. : image_drag_indication("image_drag_indication"),
  329.   chevron_button("chevron_button"),
  330.   label("label")
  331. {
  332. }
  333. LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
  334. : LLUICtrl(p),
  335. mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
  336. mPopupMenuHandle(),
  337. mInventoryItemsPopupMenuHandle(),
  338. mImageDragIndication(p.image_drag_indication),
  339. mShowDragMarker(FALSE),
  340. mLandingTab(NULL),
  341. mLastTab(NULL),
  342. mTabsHighlightEnabled(TRUE)
  343.   , mUpdateDropDownItems(true)
  344. {
  345. // Register callback for menus with current registrar (will be parent panel's registrar)
  346. LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
  347. boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2));
  348. // Add this if we need to selectively enable items
  349. LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected",
  350. boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2));
  351. gInventory.addObserver(this);
  352. //make chevron button                                                                                                                               
  353. LLButton::Params chevron_button_params(p.chevron_button);                                         
  354. chevron_button_params.click_callback.function(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this));     
  355. mChevronButton = LLUICtrlFactory::create<LLButton> (chevron_button_params);
  356. addChild(mChevronButton); 
  357. LLTextBox::Params label_param(p.label);
  358. mBarLabel = LLUICtrlFactory::create<LLTextBox> (label_param);
  359. addChild(mBarLabel);
  360. }
  361. LLFavoritesBarCtrl::~LLFavoritesBarCtrl()
  362. {
  363. gInventory.removeObserver(this);
  364. LLView::deleteViewByHandle(mPopupMenuHandle);
  365. LLView::deleteViewByHandle(mInventoryItemsPopupMenuHandle);
  366. }
  367. BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  368.    EDragAndDropType cargo_type,
  369.    void* cargo_data,
  370.    EAcceptance* accept,
  371.    std::string& tooltip_msg)
  372. {
  373. *accept = ACCEPT_NO;
  374. switch (cargo_type)
  375. {
  376. case DAD_LANDMARK:
  377. {
  378. /*
  379.  * add a callback to the end drag event.
  380.  * the callback will disconnet itself immediately after execution
  381.  * this is done because LLToolDragAndDrop is a common tool so it shouldn't
  382.  * be overloaded with redundant callbacks.
  383.  */
  384. if (!mEndDragConnection.connected())
  385. {
  386. mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this));
  387. }
  388. // Copy the item into the favorites folder (if it's not already there).
  389. LLInventoryItem *item = (LLInventoryItem *)cargo_data;
  390. if (LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(findChildByLocalCoords(x, y)))
  391. {
  392. setLandingTab(dest);
  393. }
  394. /*
  395.  * the condition dest == NULL can be satisfied not only in the case
  396.  * of dragging to the right from the last tab of the favbar. there is a
  397.  * small gap between each tab. if the user drags something exactly there
  398.  * then mLandingTab will be set to NULL and the dragged item will be pushed
  399.  * to the end of the favorites bar. this is incorrect behavior. that's why
  400.  * we need an additional check which excludes the case described previously
  401.  * making sure that the mouse pointer is beyond the last tab.
  402.  */
  403. else if (mLastTab && x >= mLastTab->getRect().mRight)
  404. {
  405. setLandingTab(NULL);
  406. }
  407. // check if we are dragging an existing item from the favorites bar
  408. if (item && mDragItemId == item->getUUID())
  409. {
  410. *accept = ACCEPT_YES_SINGLE;
  411. showDragMarker(TRUE);
  412. if (drop)
  413. {
  414. handleExistingFavoriteDragAndDrop(x, y);
  415. showDragMarker(FALSE);
  416. }
  417. }
  418. else
  419. {
  420. const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  421. if (item->getParentUUID() == favorites_id)
  422. {
  423. llwarns << "Attemt to copy a favorite item into the same folder." << llendl;
  424. break;
  425. }
  426. *accept = ACCEPT_YES_COPY_MULTI;
  427. showDragMarker(TRUE);
  428. if (drop)
  429. {
  430. if (mItems.empty())
  431. {
  432. setLandingTab(NULL);
  433. }
  434. handleNewFavoriteDragAndDrop(item, favorites_id, x, y);
  435. showDragMarker(FALSE);
  436. }
  437. }
  438. }
  439. break;
  440. default:
  441. break;
  442. }
  443. return TRUE;
  444. }
  445. void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
  446. {
  447. LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
  448. // there is no need to handle if an item was dragged onto itself
  449. if (dest && dest->getLandmarkId() == mDragItemId)
  450. {
  451. return;
  452. }
  453. if (dest)
  454. {
  455. LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId());
  456. }
  457. else
  458. {
  459. mItems.push_back(gInventory.getItem(mDragItemId));
  460. }
  461. gInventory.saveItemsOrder(mItems);
  462. LLToggleableMenu* menu = (LLToggleableMenu*) mPopupMenuHandle.get();
  463. if (menu && menu->getVisible())
  464. {
  465. menu->setVisible(FALSE);
  466. showDropDownMenu();
  467. }
  468. }
  469. void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y)
  470. {
  471. LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
  472. // there is no need to handle if an item was dragged onto itself
  473. if (dest && dest->getLandmarkId() == mDragItemId)
  474. {
  475. return;
  476. }
  477. LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item);
  478. if (dest)
  479. {
  480. insertBeforeItem(mItems, dest->getLandmarkId(), viewer_item);
  481. }
  482. else
  483. {
  484. mItems.push_back(viewer_item);
  485. }
  486. int sortField = 0;
  487. LLPointer<LLItemCopiedCallback> cb;
  488. // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
  489. for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i)
  490. {
  491. LLViewerInventoryItem* currItem = *i;
  492. if (currItem->getUUID() == item->getUUID())
  493. {
  494. cb = new LLItemCopiedCallback(++sortField);
  495. }
  496. else
  497. {
  498. currItem->setSortField(++sortField);
  499. currItem->setComplete(TRUE);
  500. currItem->updateServer(FALSE);
  501. gInventory.updateItem(currItem);
  502. }
  503. }
  504. LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance();
  505. if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD)
  506. {
  507. viewer_item->setType(LLAssetType::AT_LANDMARK);
  508. copy_inventory_from_notecard(tool_dad->getObjectID(), tool_dad->getSourceID(), viewer_item.get(), gInventoryCallbacks.registerCB(cb));
  509. }
  510. else
  511. {
  512. copy_inventory_item(
  513. gAgent.getID(),
  514. item->getPermissions().getOwner(),
  515. item->getUUID(),
  516. favorites_id,
  517. std::string(),
  518. cb);
  519. }
  520. llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;
  521. }
  522. //virtual
  523. void LLFavoritesBarCtrl::changed(U32 mask)
  524. {
  525. if (mFavoriteFolderId.isNull())
  526. {
  527. mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  528. if (mFavoriteFolderId.notNull())
  529. {
  530. gInventory.fetchDescendentsOf(mFavoriteFolderId);
  531. }
  532. }
  533. else
  534. {
  535. updateButtons();
  536. }
  537. }
  538. //virtual
  539. void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
  540. {
  541. LLUICtrl::reshape(width, height, called_from_parent);
  542. updateButtons();
  543. }
  544. void LLFavoritesBarCtrl::draw()
  545. {
  546. LLUICtrl::draw();
  547. if (mShowDragMarker)
  548. {
  549. S32 w = mImageDragIndication->getWidth();
  550. S32 h = mImageDragIndication->getHeight();
  551. if (mLandingTab)
  552. {
  553. // mouse pointer hovers over an existing tab
  554. LLRect rect = mLandingTab->getRect();
  555. mImageDragIndication->draw(rect.mLeft - w/2, rect.getHeight(), w, h);
  556. }
  557. else if (mLastTab)
  558. {
  559. // mouse pointer hovers over the favbar empty space (right to the last tab)
  560. LLRect rect = mLastTab->getRect();
  561. mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h);
  562. }
  563. }
  564. }
  565. LLXMLNodePtr LLFavoritesBarCtrl::getButtonXMLNode()
  566. {
  567. LLXMLNodePtr buttonXMLNode = NULL;
  568. bool success = LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", buttonXMLNode);
  569. if (!success)
  570. {
  571. llwarns << "Failed to create Favorites Bar button from favorites_bar_button.xml" << llendl;
  572. buttonXMLNode = NULL;
  573. }
  574. return buttonXMLNode;
  575. }
  576. void LLFavoritesBarCtrl::updateButtons()
  577. {
  578. mItems.clear();
  579. if (!collectFavoriteItems(mItems))
  580. {
  581. return;
  582. }
  583. static LLXMLNodePtr buttonXMLNode = getButtonXMLNode();
  584. if (buttonXMLNode.isNull())
  585. {
  586. return;
  587. }
  588. if(mItems.empty())
  589. {
  590. mBarLabel->setVisible(TRUE);
  591. }
  592. else
  593. {
  594. mBarLabel->setVisible(FALSE);
  595. }
  596. const child_list_t* childs = getChildList();
  597. child_list_const_iter_t child_it = childs->begin();
  598. int first_changed_item_index = 0;
  599. int rightest_point = getRect().mRight - mChevronButton->getRect().getWidth();
  600. //lets find first changed button
  601. while (child_it != childs->end() && first_changed_item_index < mItems.count())
  602. {
  603. LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it);
  604. if (button)
  605. {
  606. const LLViewerInventoryItem *item = mItems[first_changed_item_index].get();
  607. if (item)
  608. {
  609. // an child's order  and mItems  should be same   
  610. if (button->getLandmarkId() != item->getUUID() // sort order has been changed
  611. || button->getLabelSelected() != item->getName() // favorite's name has been changed
  612. || button->getRect().mRight < rightest_point) // favbar's width has been changed
  613. {
  614. break;
  615. }
  616. }
  617. first_changed_item_index++;
  618. }
  619. child_it++;
  620. }
  621. // now first_changed_item_index should contains a number of button that need to change
  622. if (first_changed_item_index <= mItems.count())
  623. {
  624. // Rebuild the buttons only
  625. // child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator
  626. while (child_it != childs->end())
  627. {
  628. //lets remove other landmarks button and rebuild it
  629. child_list_const_iter_t cur_it = child_it++;
  630. LLFavoriteLandmarkButton* button =
  631. dynamic_cast<LLFavoriteLandmarkButton*> (*cur_it);
  632. if (button)
  633. {
  634. removeChild(button);
  635. delete button;
  636. }
  637. }
  638. // we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning
  639. // keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton
  640. if (mChevronButton->getParent() == this)
  641. {
  642. removeChild(mChevronButton);
  643. }
  644. int last_right_edge = 0;
  645. //calculate new buttons offset
  646. if (getChildList()->size() > 0)
  647. {
  648. //find last visible child to get the rightest button offset
  649. child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(), 
  650. std::mem_fun(&LLView::getVisible));
  651. if(last_visible_it != childs->rend())
  652. {
  653. last_right_edge = (*last_visible_it)->getRect().mRight;
  654. }
  655. }
  656. //last_right_edge is saving coordinates
  657. LLButton* last_new_button = NULL;
  658. int j = first_changed_item_index;
  659. for (; j < mItems.count(); j++)
  660. {
  661. last_new_button = createButton(mItems[j], buttonXMLNode, last_right_edge);
  662. if (!last_new_button)
  663. {
  664. break;
  665. }
  666. sendChildToBack(last_new_button);
  667. last_right_edge = last_new_button->getRect().mRight;
  668. mLastTab = last_new_button;
  669. }
  670. mFirstDropDownItem = j;
  671. // Chevron button
  672. if (mFirstDropDownItem < mItems.count())
  673. {
  674. // if updateButton had been called it means:
  675. //or there are some new favorites, or width had been changed
  676. // so if we need to display chevron button,  we must update dropdown items too. 
  677. mUpdateDropDownItems = true;
  678. S32 buttonHGap = 2; // default value
  679. buttonXMLNode->getAttributeS32("left", buttonHGap);
  680. LLRect rect;
  681. // Chevron button should stay right aligned
  682. rect.setOriginAndSize(getRect().mRight - mChevronButton->getRect().getWidth() - buttonHGap, 0,
  683. mChevronButton->getRect().getWidth(),
  684. mChevronButton->getRect().getHeight());
  685. addChild(mChevronButton);
  686. mChevronButton->setRect(rect);
  687. mChevronButton->setVisible(TRUE);
  688. }
  689. // Update overflow menu
  690. LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mPopupMenuHandle.get());
  691. if (overflow_menu && overflow_menu->getVisible())
  692. {
  693. overflow_menu->setFocus(FALSE);
  694. overflow_menu->setVisible(FALSE);
  695. if (mUpdateDropDownItems)
  696. showDropDownMenu();
  697. }
  698. }
  699. else
  700. {
  701. mUpdateDropDownItems = false;
  702. }
  703. }
  704. LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, LLXMLNodePtr &buttonXMLNode, S32 x_offset)
  705. {
  706. S32 def_button_width = 120;
  707. buttonXMLNode->getAttributeS32("width", def_button_width);
  708. S32 button_x_delta = 2; // default value
  709. buttonXMLNode->getAttributeS32("left", button_x_delta);
  710. S32 curr_x = x_offset;
  711. /**
  712.  * WORKAROUND:
  713.  * there are some problem with displaying of fonts in buttons. 
  714.  * Empty space (or ...) is displaying instead of last symbols, even though the width of the button is enough.
  715.  * Problem will gone, if we  stretch out the button. For that reason I have to put additional  20 pixels.
  716.  */
  717. int required_width = mFont->getWidth(item->getName()) + 20;
  718. int width = required_width > def_button_width? def_button_width : required_width;
  719. LLFavoriteLandmarkButton* fav_btn = NULL;
  720. // do we have a place for next button + double buttonHGap + mChevronButton ? 
  721. if(curr_x + width + 2*button_x_delta +  mChevronButton->getRect().getWidth() > getRect().mRight )
  722. {
  723. return NULL;
  724. }
  725. fav_btn = LLUICtrlFactory::defaultBuilder<LLFavoriteLandmarkButton>(buttonXMLNode, this, NULL);
  726. if (NULL == fav_btn)
  727. {
  728. llwarns << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << llendl;
  729. return NULL;
  730. }
  731. LLRect butt_rect (fav_btn->getRect());
  732. fav_btn->setLandmarkID(item->getUUID());
  733. butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight());
  734. fav_btn->setRect(butt_rect);
  735. // change only left and save bottom
  736. fav_btn->setFont(mFont);
  737. fav_btn->setName(item->getName());
  738. fav_btn->setLabel(item->getName());
  739. fav_btn->setToolTip(item->getName());
  740. fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
  741. fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 ));
  742. fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
  743. fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
  744. return fav_btn;
  745. }
  746. BOOL LLFavoritesBarCtrl::postBuild()
  747. {
  748. // make the popup menu available
  749. LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  750. if (!menu)
  751. {
  752. menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
  753. }
  754. menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
  755. mInventoryItemsPopupMenuHandle = menu->getHandle();
  756. return TRUE;
  757. }
  758. BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
  759. {
  760. if (mFavoriteFolderId.isNull())
  761. return FALSE;
  762. LLInventoryModel::cat_array_t cats;
  763. LLIsType is_type(LLAssetType::AT_LANDMARK);
  764. gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
  765. std::sort(items.begin(), items.end(), LLFavoritesSort());
  766. if (needToSaveItemsOrder(items))
  767. {
  768. S32 sortField = 0;
  769. for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
  770. {
  771. (*i)->setSortField(++sortField);
  772. }
  773. }
  774. return TRUE;
  775. }
  776. void LLFavoritesBarCtrl::showDropDownMenu()
  777. {
  778. if (mPopupMenuHandle.isDead())
  779. {
  780. LLToggleableMenu::Params menu_p;
  781. menu_p.name("favorites menu");
  782. menu_p.can_tear_off(false);
  783. menu_p.visible(false);
  784. menu_p.scrollable(true);
  785. menu_p.max_scrollable_items = 10;
  786. menu_p.preferred_width = DROP_DOWN_MENU_WIDTH;
  787. LLToggleableMenu* menu = LLUICtrlFactory::create<LLFavoriteLandmarkToggleableMenu>(menu_p);
  788. mPopupMenuHandle = menu->getHandle();
  789. }
  790. LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get();
  791. if (menu)
  792. {
  793. // Release focus to allow changing of visibility.
  794. menu->setFocus(FALSE);
  795. if (!menu->toggleVisibility())
  796. return;
  797. U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth());
  798. if (mUpdateDropDownItems)
  799. {
  800. menu->empty();
  801. U32 widest_item = 0;
  802. for (S32 i = mFirstDropDownItem; i < mItems.count(); i++)
  803. {
  804. LLViewerInventoryItem* item = mItems.get(i);
  805. const std::string& item_name = item->getName();
  806. LLFavoriteLandmarkMenuItem::Params item_params;
  807. item_params.name(item_name);
  808. item_params.label(item_name);
  809. item_params.on_click.function(boost::bind(
  810. &LLFavoritesBarCtrl::onButtonClick, this,
  811. item->getUUID()));
  812. LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params);
  813. menu_item->initFavoritesBarPointer(this);
  814. menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4));
  815. menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
  816. menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
  817. menu_item->setLandmarkID(item->getUUID());
  818. // Check whether item name wider than menu
  819. if (menu_item->getNominalWidth() > max_width)
  820. {
  821. S32 chars_total = item_name.length();
  822. S32 chars_fitted = 1;
  823. menu_item->setLabel(LLStringExplicit(""));
  824. S32 label_space = max_width - menu_item->getFont()->getWidth("...") - 
  825. menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels) 
  826. while (chars_fitted < chars_total
  827. && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space)
  828. {
  829. chars_fitted++;
  830. }
  831. chars_fitted--; // Rolling back one char, that doesn't fit
  832. menu_item->setLabel(item_name.substr(0, chars_fitted)
  833. + "...");
  834. }
  835. widest_item = llmax(widest_item, menu_item->getNominalWidth());
  836. menu->addChild(menu_item);
  837. }
  838. mUpdateDropDownItems = false;
  839. }
  840. menu->buildDrawLabels();
  841. menu->updateParent(LLMenuGL::sMenuContainer);
  842. menu->setButtonRect(mChevronButton->getRect(), this);
  843. LLMenuGL::showPopup(this, menu, getRect().getWidth() - max_width, 0);
  844. }
  845. }
  846. void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id)
  847. {
  848. // We only have one Inventory, gInventory. Some day this should be better abstracted.
  849. LLInvFVBridgeAction::doAction(item_id,&gInventory);
  850. }
  851. void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask)
  852. {
  853. mSelectedItemID = item_id;
  854. LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get();
  855. if (!menu)
  856. {
  857. return;
  858. }
  859. // Release mouse capture so hover events go to the popup menu
  860. // because this is happening during a mouse down.
  861. gFocusMgr.setMouseCapture(NULL);
  862. menu->updateParent(LLMenuGL::sMenuContainer);
  863. LLMenuGL::showPopup(fav_button, menu, x, y);
  864. }
  865. BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
  866. {
  867. BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL;
  868. if(!handled && !gMenuHolder->hasVisibleMenu())
  869. {
  870. show_navbar_context_menu(this,x,y);
  871. handled = true;
  872. }
  873. return handled;
  874. }
  875. void copy_slurl_to_clipboard_cb(std::string& slurl)
  876. {
  877. gClipboard.copyFromString(utf8str_to_wstring(slurl));
  878. LLSD args;
  879. args["SLURL"] = slurl;
  880. LLNotificationsUtil::add("CopySLURL", args);
  881. }
  882. bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata)
  883. {
  884.     std::string param = userdata.asString();
  885.     if (param == std::string("can_paste"))
  886.     {
  887.         return isClipboardPasteable();
  888.     }
  889.     return false;
  890. }
  891. void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
  892. {
  893. std::string action = userdata.asString();
  894. llinfos << "Action = " << action << " Item = " << mSelectedItemID.asString() << llendl;
  895. LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID);
  896. if (!item)
  897. return;
  898. if (action == "open")
  899. {
  900. onButtonClick(item->getUUID());
  901. }
  902. else if (action == "about")
  903. {
  904. LLSD key;
  905. key["type"] = "landmark";
  906. key["id"] = mSelectedItemID;
  907. LLSideTray::getInstance()->showPanel("panel_places", key);
  908. }
  909. else if (action == "copy_slurl")
  910. {
  911. LLVector3d posGlobal;
  912. LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
  913. if (!posGlobal.isExactlyZero())
  914. {
  915. LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb);
  916. }
  917. }
  918. else if (action == "show_on_map")
  919. {
  920. LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
  921. LLVector3d posGlobal;
  922. LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
  923. if (!posGlobal.isExactlyZero() && worldmap_instance)
  924. {
  925. worldmap_instance->trackLocation(posGlobal);
  926. LLFloaterReg::showInstance("world_map", "center");
  927. }
  928. }
  929. else if (action == "cut")
  930. {
  931. }
  932. else if (action == "copy")
  933. {
  934. LLInventoryClipboard::instance().store(mSelectedItemID);
  935. }
  936. else if (action == "paste")
  937. {
  938. pastFromClipboard();
  939. }
  940. else if (action == "delete")
  941. {
  942. gInventory.removeItem(mSelectedItemID);
  943. }
  944. }
  945. BOOL LLFavoritesBarCtrl::isClipboardPasteable() const
  946. {
  947. if (!LLInventoryClipboard::instance().hasContents())
  948. {
  949. return FALSE;
  950. }
  951. LLDynamicArray<LLUUID> objects;
  952. LLInventoryClipboard::instance().retrieve(objects);
  953. S32 count = objects.count();
  954. for(S32 i = 0; i < count; i++)
  955. {
  956. const LLUUID &item_id = objects.get(i);
  957. // Can't paste folders
  958. const LLInventoryCategory *cat = gInventory.getCategory(item_id);
  959. if (cat)
  960. {
  961. return FALSE;
  962. }
  963. const LLInventoryItem *item = gInventory.getItem(item_id);
  964. if (item && LLAssetType::AT_LANDMARK != item->getType())
  965. {
  966. return FALSE;
  967. }
  968. }
  969. return TRUE;
  970. }
  971. void LLFavoritesBarCtrl::pastFromClipboard() const
  972. {
  973. LLInventoryModel* model = &gInventory;
  974. if(model && isClipboardPasteable())
  975. {
  976. LLInventoryItem* item = NULL;
  977. LLDynamicArray<LLUUID> objects;
  978. LLInventoryClipboard::instance().retrieve(objects);
  979. S32 count = objects.count();
  980. LLUUID parent_id(mFavoriteFolderId);
  981. for(S32 i = 0; i < count; i++)
  982. {
  983. item = model->getItem(objects.get(i));
  984. if (item)
  985. {
  986. copy_inventory_item(
  987. gAgent.getID(),
  988. item->getPermissions().getOwner(),
  989. item->getUUID(),
  990. parent_id,
  991. std::string(),
  992. LLPointer<LLInventoryCallback>(NULL));
  993. }
  994. }
  995. }
  996. }
  997. void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
  998. {
  999. mDragItemId = id;
  1000. mStartDrag = TRUE;
  1001. S32 screenX, screenY;
  1002. localPointToScreen(x, y, &screenX, &screenY);
  1003. LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY);
  1004. }
  1005. void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
  1006. {
  1007. mStartDrag = FALSE;
  1008. mDragItemId = LLUUID::null;
  1009. }
  1010. void LLFavoritesBarCtrl::onEndDrag()
  1011. {
  1012. mEndDragConnection.disconnect();
  1013. showDragMarker(FALSE);
  1014. mDragItemId = LLUUID::null;
  1015. LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
  1016. }
  1017. BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask)
  1018. {
  1019. if (mDragItemId != LLUUID::null && mStartDrag)
  1020. {
  1021. S32 screenX, screenY;
  1022. localPointToScreen(x, y, &screenX, &screenY);
  1023. if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY))
  1024. {
  1025. LLToolDragAndDrop::getInstance()->beginDrag(
  1026. DAD_LANDMARK, mDragItemId,
  1027. LLToolDragAndDrop::SOURCE_LIBRARY);
  1028. mStartDrag = FALSE;
  1029. return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask);
  1030. }
  1031. }
  1032. return TRUE;
  1033. }
  1034. LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y)
  1035. {
  1036. LLUICtrl* ctrl = 0;
  1037. S32 screenX, screenY;
  1038. const child_list_t* list = getChildList();
  1039. localPointToScreen(x, y, &screenX, &screenY);
  1040. // look for a child which contains the point (screenX, screenY) in it's rectangle
  1041. for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
  1042. {
  1043. LLRect rect;
  1044. localRectToScreen((*i)->getRect(), &rect);
  1045. if (rect.pointInRect(screenX, screenY))
  1046. {
  1047. ctrl = dynamic_cast<LLUICtrl*>(*i);
  1048. break;
  1049. }
  1050. }
  1051. return ctrl;
  1052. }
  1053. BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items)
  1054. {
  1055. BOOL result = FALSE;
  1056. // if there is an item without sort order field set, we need to save items order
  1057. for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
  1058. {
  1059. if ((*i)->getSortField() < 0)
  1060. {
  1061. result = TRUE;
  1062. break;
  1063. }
  1064. }
  1065. return result;
  1066. }
  1067. LLInventoryModel::item_array_t::iterator LLFavoritesBarCtrl::findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id)
  1068. {
  1069. LLInventoryModel::item_array_t::iterator result = items.end();
  1070. for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
  1071. {
  1072. if ((*i)->getUUID() == id)
  1073. {
  1074. result = i;
  1075. break;
  1076. }
  1077. }
  1078. return result;
  1079. }
  1080. void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem)
  1081. {
  1082. LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId);
  1083. llassert(beforeItem);
  1084. if (beforeItem)
  1085. {
  1086. items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem);
  1087. }
  1088. }
  1089. // EOF