From 17e3b2936a63f1242071ffcfe09069fcecc3b73b Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 2 Feb 2024 19:53:08 +0100 Subject: GH-68175 [SL-17986] Ability to drag Favorites to the Overflow menu --- indra/newview/llfavoritesbar.cpp | 364 +++++++++++++++++++++++++-------------- 1 file changed, 232 insertions(+), 132 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index cdce6f7156..f926a8a6d5 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -79,7 +79,7 @@ public: } void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } - const LLUUID& getLandmarkId() const { return mLandmarkID; } + const LLUUID& getLandmarkID() const { return mLandmarkID; } const std::string& getName() { @@ -192,7 +192,7 @@ public: } void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } - const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); } + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } void onMouseEnter(S32 x, S32 y, MASK mask) { @@ -237,7 +237,8 @@ public: return TRUE; } - void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } + void setLandmarkID(const LLUUID& id) { mLandmarkInfoGetter.setLandmarkID(id); } virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { @@ -285,15 +286,44 @@ private: class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu { public: - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) - { - *accept = ACCEPT_NO; - return TRUE; - } + // virtual + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, + void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override + { + mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + return TRUE; + } + + // virtual + BOOL handleHover(S32 x, S32 y, MASK mask) override + { + mIsHovering = true; + LLToggleableMenu::handleHover(x, y, mask); + mIsHovering = false; + return TRUE; + } + + // virtual + void setVisible(BOOL visible) override + { + // Avoid of hiding the menu during hovering + if (visible || !mIsHovering) + { + LLToggleableMenu::setVisible(visible); + } + } + + void setToolbar(LLFavoritesBarCtrl* toolbar) + { + mToolbar = toolbar; + } + + ~LLFavoriteLandmarkToggleableMenu() + { + // Enable subsequent setVisible(FALSE) + mIsHovering = false; + setVisible(FALSE); + } protected: LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p): @@ -301,6 +331,10 @@ protected: { } +private: + LLFavoritesBarCtrl* mToolbar { nullptr }; + bool mIsHovering { false }; + friend class LLUICtrlFactory; }; @@ -378,12 +412,12 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) mOverflowMenuHandle(), mContextMenuHandle(), mImageDragIndication(p.image_drag_indication), - mShowDragMarker(FALSE), + mShowDragMarker(false), mLandingTab(NULL), mLastTab(NULL), - mTabsHighlightEnabled(TRUE), mUpdateDropDownItems(true), mRestoreOverflowMenu(false), + mDragToOverflowMenu(false), mGetPrevItems(true), mMouseX(0), mMouseY(0), @@ -416,17 +450,16 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) LLFavoritesBarCtrl::~LLFavoritesBarCtrl() { - gInventory.removeObserver(this); + gInventory.removeObserver(this); - if (mOverflowMenuHandle.get()) mOverflowMenuHandle.get()->die(); - if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); + if (mOverflowMenuHandle.get()) + mOverflowMenuHandle.get()->die(); + if (mContextMenuHandle.get()) + mContextMenuHandle.get()->die(); } BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) { *accept = ACCEPT_NO; @@ -452,26 +485,52 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // Copy the item into the favorites folder (if it's not already there). LLInventoryItem *item = (LLInventoryItem *)cargo_data; - if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + if (mDragToOverflowMenu) { - setLandingTab(dest); + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + overflow_menu->handleHover(x, y, mask); + } } - else if (mLastTab && (x >= mLastTab->getRect().mRight)) + else // Drag to the toolbar itself { - /* - * the condition dest == NULL can be satisfied not only in the case - * of dragging to the right from the last tab of the favbar. there is a - * small gap between each tab. if the user drags something exactly there - * then mLandingTab will be set to NULL and the dragged item will be pushed - * to the end of the favorites bar. this is incorrect behavior. that's why - * we need an additional check which excludes the case described previously - * making sure that the mouse pointer is beyond the last tab. - */ - setLandingTab(NULL); + // Drag to a landmark button? + if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + { + setLandingTab(dest); + } + else + { + // Drag to the "More" button? + if (mMoreTextBox && mMoreTextBox->getVisible() && mMoreTextBox->getRect().pointInRect(x, y)) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible()) + { + showDropDownMenu(); + } + } + + // Drag to the right of the last landmark button? + if (mLastTab && (x >= mLastTab->getRect().mRight)) + { + /* + * the condition dest == NULL can be satisfied not only in the case + * of dragging to the right from the last tab of the favbar. there is a + * small gap between each tab. if the user drags something exactly there + * then mLandingTab will be set to NULL and the dragged item will be pushed + * to the end of the favorites bar. this is incorrect behavior. that's why + * we need an additional check which excludes the case described previously + * making sure that the mouse pointer is beyond the last tab. + */ + setLandingTab(NULL); + } + } } - // check if we are dragging an existing item from the favorites bar - bool existing_drop = false; + // Check whether we are dragging an existing item from the favorites bar + bool existing_item = false; if (item && mDragItemId == item->getUUID()) { // There is a chance of mDragItemId being obsolete @@ -479,21 +538,19 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // results in viewer not geting a 'mouse up' signal for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) { - LLViewerInventoryItem* currItem = *i; - - if (currItem->getUUID() == mDragItemId) + if ((*i)->getUUID() == mDragItemId) { - existing_drop = true; + existing_item = true; break; } } } - if (existing_drop) + if (existing_item) { *accept = ACCEPT_YES_SINGLE; - showDragMarker(TRUE); + showDragMarker(true); if (drop) { @@ -511,14 +568,14 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, *accept = ACCEPT_YES_COPY_MULTI; - showDragMarker(TRUE); + showDragMarker(true); if (drop) { if (mItems.empty()) { setLandingTab(NULL); - mLastTab = NULL; + mLastTab = NULL; } handleNewFavoriteDragAndDrop(item, favorites_id, x, y); } @@ -532,82 +589,56 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return TRUE; } +bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) +{ + mDragToOverflowMenu = true; + BOOL handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + mDragToOverflowMenu = false; + return handled; +} + void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) { - if (mItems.empty()) - { - // Isn't supposed to be empty + if (LL_UNLIKELY(mItems.empty())) return; - } - // Identify the button hovered and the side to drop - LLFavoriteLandmarkButton* dest = dynamic_cast(mLandingTab); - bool insert_before = true; - if (!dest) - { - insert_before = false; - dest = dynamic_cast(mLastTab); - } - - // There is no need to handle if an item was dragged onto itself - if (dest && dest->getLandmarkId() == mDragItemId) - { - return; - } - - // Insert the dragged item in the right place - if (dest) - { - LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before); - } - else - { - // This can happen when the item list is empty - mItems.push_back(gInventory.getItem(mDragItemId)); - } + LLUUID target_id; + bool insert_before = false; + if (!findDragAndDropTarget(target_id, insert_before, x, y)) + return; - LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); + // There is no need to handle if an item was dragged onto itself + if (target_id == mDragItemId) + return; - LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get(); + // Move the dragged item to the right place in the array + LLInventoryModel::updateItemsOrder(mItems, mDragItemId, target_id, insert_before); + LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); - if (menu && menu->getVisible()) - { - menu->setVisible(FALSE); - showDropDownMenu(); - } + LLView* menu = mOverflowMenuHandle.get(); + if (menu && !menu->isDead() && menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); + } } void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) { // Identify the button hovered and the side to drop - LLFavoriteLandmarkButton* dest = NULL; - bool insert_before = true; - if (!mItems.empty()) - { - // [MAINT-2386] When multiple landmarks are selected and dragged onto an empty favorites bar, - // the viewer would crash when casting mLastTab below, as mLastTab is still null when the - // second landmark is being added. - // To ensure mLastTab is valid, we need to call updateButtons() at the end of this function - dest = dynamic_cast(mLandingTab); - if (!dest) - { - insert_before = false; - dest = dynamic_cast(mLastTab); - } - } - - // There is no need to handle if an item was dragged onto itself - if (dest && dest->getLandmarkId() == mDragItemId) - { - return; - } - + LLUUID target_id; + bool insert_before = false; + // There is no need to handle if an item was dragged onto itself + if (findDragAndDropTarget(target_id, insert_before, x, y) && (target_id == mDragItemId)) + return; + LLPointer viewer_item = new LLViewerInventoryItem(item); - // Insert the dragged item in the right place - if (dest) + // Insert the dragged item to the right place + if (target_id.notNull()) { - insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before); + insertItem(mItems, target_id, viewer_item, insert_before); } else { @@ -663,10 +694,75 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con // This also ensures that mLastTab will be valid when dropping multiple // landmarks to an empty favorites bar. updateButtons(); - + + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); + } + LL_INFOS("FavoritesBar") << "Copied inventory item #" << item->getUUID() << " to favorites." << LL_ENDL; } +bool LLFavoritesBarCtrl::findDragAndDropTarget(LLUUID& target_id, bool& insert_before, S32 x, S32 y) +{ + if (mItems.empty()) + return false; + + if (mDragToOverflowMenu) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (LL_UNLIKELY(!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible())) + return false; + + // Identify the menu item hovered and the side to drop + LLFavoriteLandmarkMenuItem* target_item = dynamic_cast(overflow_menu->childFromPoint(x, y)); + if (target_item) + { + insert_before = true; + } + else + { + // Choose the bottom landmark menu item + auto begin = overflow_menu->getChildList()->begin(); + auto end = overflow_menu->getChildList()->end(); + auto check = [](const LLView* child) -> bool + { + return dynamic_cast(child); + }; + // Menu items are placed in the backward order, so the bottom goes first + auto it = std::find_if(begin, end, check); + if (LL_UNLIKELY(it == end)) + return false; + target_item = (LLFavoriteLandmarkMenuItem*)*it; + insert_before = false; + } + target_id = target_item->getLandmarkID(); + } + else + { + // Identify the button hovered and the side to drop + LLFavoriteLandmarkButton* hovered_button = dynamic_cast(mLandingTab); + if (hovered_button) + { + insert_before = true; + } + else + { + // Choose the right landmark button + hovered_button = dynamic_cast(mLastTab); + if (LL_UNLIKELY(!hovered_button)) + return false; + + insert_before = false; + } + target_id = hovered_button->getLandmarkID(); + } + + return true; +} + //virtual void LLFavoritesBarCtrl::changed(U32 mask) { @@ -737,7 +833,7 @@ void LLFavoritesBarCtrl::draw() mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h); } // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) - mShowDragMarker = FALSE; + mShowDragMarker = false; } if (mItemsChangedTimer.getStarted()) { @@ -833,7 +929,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) if (item) { // an child's order and mItems should be same - if (button->getLandmarkId() != item->getUUID() // sort order has been changed + if (button->getLandmarkID() != item->getUUID() // sort order has been changed || button->getLabelSelected() != item->getName()) // favorite's name has been changed { break; @@ -907,11 +1003,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) { // mMoreTextBox was removed, so LLFavoriteLandmarkButtons // should be the only ones in the list - LLFavoriteLandmarkButton* button = dynamic_cast (childs->back()); - if (button) - { - mLastTab = button; - } + mLastTab = dynamic_cast(childs->back()); } mFirstDropDownItem = j; @@ -919,15 +1011,13 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) if (mFirstDropDownItem < mItems.size()) { // if updateButton had been called it means: - //or there are some new favorites, or width had been changed + // or there are some new favorites, or width had been changed // so if we need to display chevron button, we must update dropdown items too. mUpdateDropDownItems = true; S32 buttonHGap = button_params.rect.left; // default value - LLRect rect; // Chevron button should stay right aligned - rect.setOriginAndSize(getRect().mRight - mMoreTextBox->getRect().getWidth() - buttonHGap, 0, - mMoreTextBox->getRect().getWidth(), - mMoreTextBox->getRect().getHeight()); + LLRect rect(mMoreTextBox->getRect()); + rect.translate(getRect().mRight - rect.mRight - buttonHGap, 0); addChild(mMoreTextBox); mMoreTextBox->setRect(rect); @@ -1060,14 +1150,16 @@ void LLFavoritesBarCtrl::showDropDownMenu() { if (mUpdateDropDownItems) { - updateMenuItems(menu); + updateOverflowMenuItems(); + } + else + { + menu->buildDrawLabels(); } - menu->buildDrawLabels(); menu->updateParent(LLMenuGL::sMenuContainer); menu->setButtonRect(mMoreTextBox->getRect(), this); - positionAndShowMenu(menu); - mDropDownItemsCount = menu->getItemCount(); + positionAndShowOverflowMenu(); } } @@ -1081,12 +1173,14 @@ void LLFavoritesBarCtrl::createOverflowMenu() menu_p.max_scrollable_items = 10; menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; - LLToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + LLFavoriteLandmarkToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + menu->setToolbar(this); mOverflowMenuHandle = menu->getHandle(); } -void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu) +void LLFavoritesBarCtrl::updateOverflowMenuItems() { + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); menu->empty(); U32 widest_item = 0; @@ -1115,6 +1209,8 @@ void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu) menu->addChild(menu_item); } + menu->buildDrawLabels(); + mDropDownItemsCount = menu->getItemCount(); addOpenLandmarksMenuItem(menu); mUpdateDropDownItems = false; } @@ -1171,8 +1267,9 @@ void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu) menu->addChild(menu_item); } -void LLFavoritesBarCtrl::positionAndShowMenu(LLToggleableMenu* menu) +void LLFavoritesBarCtrl::positionAndShowOverflowMenu() { + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); S32 menu_x = getRect().getWidth() - max_width; @@ -1460,7 +1557,7 @@ void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 } mDragItemId = id; - mStartDrag = TRUE; + mStartDrag = true; S32 screenX, screenY; localPointToScreen(x, y, &screenX, &screenY); @@ -1470,7 +1567,7 @@ void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { - mStartDrag = FALSE; + mStartDrag = false; mDragItemId = LLUUID::null; } @@ -1478,7 +1575,7 @@ void LLFavoritesBarCtrl::onEndDrag() { mEndDragConnection.disconnect(); - showDragMarker(FALSE); + showDragMarker(false); mDragItemId = LLUUID::null; LLView::getWindow()->setCursor(UI_CURSOR_ARROW); } @@ -1496,7 +1593,7 @@ BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) DAD_LANDMARK, mDragItemId, LLToolDragAndDrop::SOURCE_LIBRARY); - mStartDrag = FALSE; + mStartDrag = false; return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); } @@ -1525,6 +1622,7 @@ LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) } } } + return ctrl; } @@ -2134,8 +2232,10 @@ bool LLFavoritesOrderStorage::isStorageUpdateNeeded() void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) { - if (mTargetLandmarkId.isNull()) return; - - LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); + if (!mTargetLandmarkId.isNull()) + { + LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); + } } + // EOF -- cgit v1.2.3 From 2b31dad40026d8078ea30d0da0656a4078d0f5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Fri, 9 Feb 2024 22:26:02 +0100 Subject: miscellaneous: BOOL (int) to real bool --- indra/newview/llfavoritesbar.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index f926a8a6d5..1c9dd652d8 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -356,8 +356,8 @@ public: { LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField); - item->setComplete(TRUE); - item->updateServer(FALSE); + item->setComplete(true); + item->updateServer(false); gInventory.updateItem(item); gInventory.notifyObservers(); @@ -662,8 +662,8 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con { LLFavoritesOrderStorage::instance().setSortIndex(currItem, ++sortField); - currItem->setComplete(TRUE); - currItem->updateServer(FALSE); + currItem->setComplete(true); + currItem->updateServer(false); gInventory.updateItem(currItem); } @@ -1478,7 +1478,7 @@ bool LLFavoritesBarCtrl::onRenameCommit(const LLSD& notification, const LLSD& re { LLPointer new_item = new LLViewerInventoryItem(item); new_item->rename(landmark_name); - new_item->updateServer(FALSE); + new_item->updateServer(false); gInventory.updateItem(new_item); } } @@ -2039,8 +2039,8 @@ void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array setSortIndex(item, ++sortField); - item->setComplete(TRUE); - item->updateServer(FALSE); + item->setComplete(true); + item->updateServer(false); gInventory.updateItem(item); -- cgit v1.2.3 From c285f59ce2a05703e3a1232fcaf3ee3aea714b3f Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 18 Feb 2024 12:52:19 +0100 Subject: Replace BOOL with bool in llwindow and dependent classes --- indra/newview/llfavoritesbar.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 1c9dd652d8..84de9c594c 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -160,7 +160,7 @@ class LLFavoriteLandmarkButton : public LLButton { public: - BOOL handleToolTip(S32 x, S32 y, MASK mask) + bool handleToolTip(S32 x, S32 y, MASK mask) { std::string region_name = mLandmarkInfoGetter.getName(); @@ -176,10 +176,10 @@ public: LLToolTipMgr::instance().show(params); } - return TRUE; + return true; } - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) + /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) { LLFavoritesBarCtrl* fb = dynamic_cast(getParent()); @@ -224,7 +224,7 @@ private: class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL { public: - BOOL handleToolTip(S32 x, S32 y, MASK mask) + bool handleToolTip(S32 x, S32 y, MASK mask) { std::string region_name = mLandmarkInfoGetter.getName(); if (!region_name.empty()) @@ -234,34 +234,34 @@ public: params.sticky_rect = calcScreenRect(); LLToolTipMgr::instance().show(params); } - return TRUE; + return true; } const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } void setLandmarkID(const LLUUID& id) { mLandmarkInfoGetter.setLandmarkID(id); } - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) + virtual bool handleMouseDown(S32 x, S32 y, MASK mask) { if (mMouseDownSignal) (*mMouseDownSignal)(this, x, y, mask); return LLMenuItemCallGL::handleMouseDown(x, y, mask); } - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) + virtual bool handleMouseUp(S32 x, S32 y, MASK mask) { if (mMouseUpSignal) (*mMouseUpSignal)(this, x, y, mask); return LLMenuItemCallGL::handleMouseUp(x, y, mask); } - virtual BOOL handleHover(S32 x, S32 y, MASK mask) + virtual bool handleHover(S32 x, S32 y, MASK mask) { if (fb) { fb->handleHover(x, y, mask); } - return TRUE; + return true; } void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } @@ -295,12 +295,12 @@ public: } // virtual - BOOL handleHover(S32 x, S32 y, MASK mask) override + bool handleHover(S32 x, S32 y, MASK mask) override { mIsHovering = true; LLToggleableMenu::handleHover(x, y, mask); mIsHovering = false; - return TRUE; + return true; } // virtual @@ -1335,9 +1335,9 @@ void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S LLMenuGL::showPopup(fav_button, menu, x, y); } -BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +bool LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL; + bool handled = childrenHandleRightMouseDown( x, y, mask) != NULL; if(!handled && !gMenuHolder->hasVisibleMenu()) { show_navbar_context_menu(this,x,y); @@ -1580,7 +1580,7 @@ void LLFavoritesBarCtrl::onEndDrag() LLView::getWindow()->setCursor(UI_CURSOR_ARROW); } -BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) +bool LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) { if (mDragItemId != LLUUID::null && mStartDrag) { @@ -1599,7 +1599,7 @@ BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) } } - return TRUE; + return true; } LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) -- cgit v1.2.3 From a5261a5fa8fad810ecb5c260d92c3e771822bf58 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 20 Feb 2024 23:46:23 +0100 Subject: Convert BOOL to bool in llui --- indra/newview/llfavoritesbar.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 84de9c594c..8f658b7de9 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -287,7 +287,7 @@ class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu { public: // virtual - BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, + bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override { mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); @@ -304,7 +304,7 @@ public: } // virtual - void setVisible(BOOL visible) override + void setVisible(bool visible) override { // Avoid of hiding the menu during hovering if (visible || !mIsHovering) @@ -320,9 +320,9 @@ public: ~LLFavoriteLandmarkToggleableMenu() { - // Enable subsequent setVisible(FALSE) + // Enable subsequent setVisible(false) mIsHovering = false; - setVisible(FALSE); + setVisible(false); } protected: @@ -458,7 +458,7 @@ LLFavoritesBarCtrl::~LLFavoritesBarCtrl() mContextMenuHandle.get()->die(); } -BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, +bool LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) { *accept = ACCEPT_NO; @@ -586,7 +586,7 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, break; } - return TRUE; + return true; } bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, BOOL drop, @@ -801,7 +801,7 @@ void LLFavoritesBarCtrl::changed(U32 mask) } //virtual -void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +void LLFavoritesBarCtrl::reshape(S32 width, S32 height, bool called_from_parent) { S32 delta_width = width - getRect().getWidth(); S32 delta_height = height - getRect().getHeight(); @@ -1091,7 +1091,7 @@ LLButton* LLFavoritesBarCtrl::createButton(const LLPointercreateFromFile("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); @@ -1102,7 +1102,7 @@ BOOL LLFavoritesBarCtrl::postBuild() menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); mContextMenuHandle = menu->getHandle(); - return TRUE; + return true; } BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) -- cgit v1.2.3 From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/newview/llfavoritesbar.cpp | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 8f658b7de9..6f689a5dd9 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -279,7 +279,7 @@ private: /** * This class was introduced just for fixing the following issue: * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through. - * We must explicitly handle drag and drop event by returning TRUE + * We must explicitly handle drag and drop event by returning true * because otherwise LLToolDragAndDrop will initiate drag and drop operation * with the world. */ @@ -291,7 +291,7 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override { mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - return TRUE; + return true; } // virtual @@ -464,7 +464,7 @@ bool LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, *accept = ACCEPT_NO; LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return FALSE; + if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return false; switch (cargo_type) { @@ -589,11 +589,11 @@ bool LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, return true; } -bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, BOOL drop, +bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) { mDragToOverflowMenu = true; - BOOL handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + bool handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); mDragToOverflowMenu = false; return handled; } @@ -907,12 +907,12 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) if(mItems.empty()) { - mBarLabel->setVisible(TRUE); + mBarLabel->setVisible(true); mLastTab = NULL; } else { - mBarLabel->setVisible(FALSE); + mBarLabel->setVisible(false); } const child_list_t* childs = getChildList(); child_list_const_iter_t child_it = childs->begin(); @@ -1021,13 +1021,13 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) addChild(mMoreTextBox); mMoreTextBox->setRect(rect); - mMoreTextBox->setVisible(TRUE); + mMoreTextBox->setVisible(true); } // Update overflow menu LLToggleableMenu* overflow_menu = static_cast (mOverflowMenuHandle.get()); if (overflow_menu && overflow_menu->getVisible() && (overflow_menu->getItemCount() != mDropDownItemsCount)) { - overflow_menu->setVisible(FALSE); + overflow_menu->setVisible(false); if (mUpdateDropDownItems) { showDropDownMenu(); @@ -1105,11 +1105,11 @@ bool LLFavoritesBarCtrl::postBuild() return true; } -BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) +bool LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) { if (mFavoriteFolderId.isNull()) - return FALSE; + return false; LLInventoryModel::cat_array_t cats; @@ -1129,7 +1129,7 @@ BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &it LLFavoritesOrderStorage::instance().mSaveOnExit = true; } - return TRUE; + return true; } void LLFavoritesBarCtrl::onMoreTextBoxClicked() @@ -1486,11 +1486,11 @@ bool LLFavoritesBarCtrl::onRenameCommit(const LLSD& notification, const LLSD& re return false; } -BOOL LLFavoritesBarCtrl::isClipboardPasteable() const +bool LLFavoritesBarCtrl::isClipboardPasteable() const { if (!LLClipboard::instance().hasContents()) { - return FALSE; + return false; } std::vector objects; @@ -1504,16 +1504,16 @@ BOOL LLFavoritesBarCtrl::isClipboardPasteable() const const LLInventoryCategory *cat = gInventory.getCategory(item_id); if (cat) { - return FALSE; + return false; } const LLInventoryItem *item = gInventory.getItem(item_id); if (item && LLAssetType::AT_LANDMARK != item->getType()) { - return FALSE; + return false; } } - return TRUE; + return true; } void LLFavoritesBarCtrl::pasteFromClipboard() const @@ -1553,7 +1553,7 @@ void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); if(menu && menu->getVisible()) { - menu->setVisible(FALSE); + menu->setVisible(false); } mDragItemId = id; @@ -1626,16 +1626,16 @@ LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) return ctrl; } -BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) +bool LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) { - BOOL result = FALSE; + bool result = false; // if there is an item without sort order field set, we need to save items order for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) { if (LLFavoritesOrderStorage::instance().getSortIndex((*i)->getUUID()) < 0) { - result = TRUE; + result = true; break; } } @@ -2071,7 +2071,7 @@ void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_it saveItemsOrder(items); } -BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) +bool LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) { pref_changed |= mRecreateFavoriteStorage; mRecreateFavoriteStorage = false; @@ -2079,13 +2079,13 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) // Can get called before inventory is done initializing. if (!gInventory.isInventoryUsable()) { - return FALSE; + return false; } LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); if (favorite_folder.isNull()) { - return FALSE; + return false; } LLInventoryModel::item_array_t items; @@ -2197,11 +2197,11 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) mPrevFavorites = items; } - return TRUE; + return true; } -void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show) +void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(bool show) { if (show) { -- cgit v1.2.3 From a865d423974ea06dffa47798c81e98e7570b02ec Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 5 Mar 2024 17:03:11 +0100 Subject: viewer#819 Avoid reading the same XML file multiple times --- indra/newview/llfavoritesbar.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 6f689a5dd9..220ca69a47 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -860,10 +860,11 @@ const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() if (!params_initialized) { LLXMLNodePtr button_xml_node; - if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node)) + static const std::string filename("favorites_bar_button.xml"); + if (LLUICtrlFactory::getLayeredXMLNode(filename, button_xml_node, LLDir::CURRENT_SKIN, true)) { LLXUIParser parser; - parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml"); + parser.readXUI(button_xml_node, button_params, filename); } params_initialized = true; } -- cgit v1.2.3 From 2008f87f10d51a2f9372aa4a4d72e86ac94e1e81 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 13 May 2024 18:26:53 +0300 Subject: Revert "viewer#819 Avoid reading the same XML file multiple times" This reverts commit a865d423974ea06dffa47798c81e98e7570b02ec. Reason for revert: viewer#1420, reverting to not hold maint-A (is deepCopy not full?) --- indra/newview/llfavoritesbar.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index a46cc0ce30..727f5592cd 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -886,11 +886,10 @@ const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() if (!params_initialized) { LLXMLNodePtr button_xml_node; - static const std::string filename("favorites_bar_button.xml"); - if (LLUICtrlFactory::getLayeredXMLNode(filename, button_xml_node, LLDir::CURRENT_SKIN, true)) + if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node)) { LLXUIParser parser; - parser.readXUI(button_xml_node, button_params, filename); + parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml"); } params_initialized = true; } -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llfavoritesbar.cpp | 4536 +++++++++++++++++++------------------- 1 file changed, 2268 insertions(+), 2268 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 8207ec86b7..906d04691f 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1,2268 +1,2268 @@ -/** - * @file llfavoritesbar.cpp - * @brief LLFavoritesBarCtrl class implementation - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llfavoritesbar.h" - -#include "llfloaterreg.h" -#include "llfocusmgr.h" -#include "llinventory.h" -#include "lllandmarkactions.h" -#include "lltoolbarview.h" -#include "lltrans.h" -#include "lluictrlfactory.h" -#include "llmenugl.h" -#include "lltooltip.h" - -#include "llagent.h" -#include "llagentpicksinfo.h" -#include "llavatarnamecache.h" -#include "llclipboard.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" -#include "llfloatersidepanelcontainer.h" -#include "llfloaterworldmap.h" -#include "lllandmarkactions.h" -#include "lllogininstance.h" -#include "llnotificationsutil.h" -#include "lltoggleablemenu.h" -#include "llviewerinventory.h" -#include "llviewermenu.h" -#include "llviewernetwork.h" -#include "lltooldraganddrop.h" -#include "llsdserialize.h" - -static LLDefaultChildRegistry::Register r("favorites_bar"); - -const S32 DROP_DOWN_MENU_WIDTH = 250; -const S32 DROP_DOWN_MENU_TOP_PAD = 13; - -/** - * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem. - * Performing requests for SLURL for given Landmark ID - */ -class LLLandmarkInfoGetter -{ -public: - LLLandmarkInfoGetter() - : mLandmarkID(LLUUID::null), - mName("(Loading...)"), - mPosX(0), - mPosY(0), - mPosZ(0), - mLoaded(false) - { - mHandle.bind(this); - } - - void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } - const LLUUID& getLandmarkID() const { return mLandmarkID; } - - const std::string& getName() - { - if(!mLoaded) - requestNameAndPos(); - - return mName; - } - - S32 getPosX() - { - if (!mLoaded) - requestNameAndPos(); - return mPosX; - } - - S32 getPosY() - { - if (!mLoaded) - requestNameAndPos(); - return mPosY; - } - - S32 getPosZ() - { - if (!mLoaded) - requestNameAndPos(); - return mPosZ; - } - -private: - /** - * Requests landmark data from server. - */ - void requestNameAndPos() - { - if (mLandmarkID.isNull()) - return; - - LLVector3d g_pos; - if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) - { - LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos, - boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, static_cast >(mHandle), _1, _2, _3, _4)); - } - } - - static void landmarkNameCallback(LLHandle handle, const std::string& name, S32 x, S32 y, S32 z) - { - LLLandmarkInfoGetter* getter = handle.get(); - if (getter) - { - getter->mPosX = x; - getter->mPosY = y; - getter->mPosZ = z; - getter->mName = name; - getter->mLoaded = true; - } - } - - LLUUID mLandmarkID; - std::string mName; - S32 mPosX; - S32 mPosY; - S32 mPosZ; - bool mLoaded; - LLRootHandle mHandle; -}; - -/** - * This class is needed to override LLButton default handleToolTip function and - * show SLURL as button tooltip. - * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons - * in createButtons function but landmark data is not available when Favorites Bar is - * created. Thats why we are requesting landmark data after - */ -class LLFavoriteLandmarkButton : public LLButton -{ -public: - - bool handleToolTip(S32 x, S32 y, MASK mask) - { - std::string region_name = mLandmarkInfoGetter.getName(); - - if (!region_name.empty()) - { - std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), - mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ()); - - LLToolTip::Params params; - params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str()); - params.max_width = 1000; - params.sticky_rect = calcScreenRect(); - - LLToolTipMgr::instance().show(params); - } - return true; - } - - /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) - { - LLFavoritesBarCtrl* fb = dynamic_cast(getParent()); - - if (fb) - { - fb->handleHover(x, y, mask); - } - - return LLButton::handleHover(x, y, mask); - } - - void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } - const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } - - void onMouseEnter(S32 x, S32 y, MASK mask) - { - if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) - { - LLUICtrl::onMouseEnter(x, y, mask); - } - else - { - LLButton::onMouseEnter(x, y, mask); - } - } - -protected: - LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} - friend class LLUICtrlFactory; - -private: - LLLandmarkInfoGetter mLandmarkInfoGetter; -}; - -/** - * This class is needed to override LLMenuItemCallGL default handleToolTip function and - * show SLURL as button tooltip. - * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons - * in showDropDownMenu function but landmark data is not available when Favorites Bar is - * created. Thats why we are requesting landmark data after - */ -class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL -{ -public: - bool handleToolTip(S32 x, S32 y, MASK mask) - { - std::string region_name = mLandmarkInfoGetter.getName(); - if (!region_name.empty()) - { - LLToolTip::Params params; - params.message = llformat("%s\n%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY()); - params.sticky_rect = calcScreenRect(); - LLToolTipMgr::instance().show(params); - } - return true; - } - - const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } - void setLandmarkID(const LLUUID& id) { mLandmarkInfoGetter.setLandmarkID(id); } - - virtual bool handleMouseDown(S32 x, S32 y, MASK mask) - { - if (mMouseDownSignal) - (*mMouseDownSignal)(this, x, y, mask); - return LLMenuItemCallGL::handleMouseDown(x, y, mask); - } - - virtual bool handleMouseUp(S32 x, S32 y, MASK mask) - { - if (mMouseUpSignal) - (*mMouseUpSignal)(this, x, y, mask); - return LLMenuItemCallGL::handleMouseUp(x, y, mask); - } - - virtual bool handleHover(S32 x, S32 y, MASK mask) - { - if (fb) - { - fb->handleHover(x, y, mask); - } - - return true; - } - - void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } - -protected: - - LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} - friend class LLUICtrlFactory; - -private: - LLLandmarkInfoGetter mLandmarkInfoGetter; - LLFavoritesBarCtrl* fb; -}; - -/** - * This class was introduced just for fixing the following issue: - * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through. - * We must explicitly handle drag and drop event by returning true - * because otherwise LLToolDragAndDrop will initiate drag and drop operation - * with the world. - */ -class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu -{ -public: - // virtual - bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, - void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override - { - mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - return true; - } - - // virtual - bool handleHover(S32 x, S32 y, MASK mask) override - { - mIsHovering = true; - LLToggleableMenu::handleHover(x, y, mask); - mIsHovering = false; - return true; - } - - // virtual - void setVisible(bool visible) override - { - // Avoid of hiding the menu during hovering - if (visible || !mIsHovering) - { - LLToggleableMenu::setVisible(visible); - } - } - - void setToolbar(LLFavoritesBarCtrl* toolbar) - { - mToolbar = toolbar; - } - - ~LLFavoriteLandmarkToggleableMenu() - { - // Enable subsequent setVisible(false) - mIsHovering = false; - setVisible(false); - } - -protected: - LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p): - LLToggleableMenu(p) - { - } - -private: - LLFavoritesBarCtrl* mToolbar { nullptr }; - bool mIsHovering { false }; - - friend class LLUICtrlFactory; -}; - -/** - * This class is needed to update an item being copied to the favorites folder - * with a sort field value (required to save favorites bar's tabs order). - * See method handleNewFavoriteDragAndDrop for more details on how this class is used. - */ -class LLItemCopiedCallback : public LLInventoryCallback -{ -public: - LLItemCopiedCallback(S32 sortField): mSortField(sortField) {} - - virtual void fire(const LLUUID& inv_item) - { - LLViewerInventoryItem* item = gInventory.getItem(inv_item); - - if (item) - { - LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; - LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField); - - item->setComplete(true); - item->updateServer(false); - - gInventory.updateItem(item); - gInventory.notifyObservers(); - LLFavoritesOrderStorage::instance().saveOrder(); - } - - LLView::getWindow()->setCursor(UI_CURSOR_ARROW); - } - -private: - S32 mSortField; -}; - -// updateButtons's helper -struct LLFavoritesSort -{ - // Sorting by creation date and name - // TODO - made it customizible using gSavedSettings - bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) - { - S32 sortField1 = LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()); - S32 sortField2 = LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); - - if (!(sortField1 < 0 && sortField2 < 0)) - { - return sortField2 > sortField1; - } - - time_t first_create = a->getCreationDate(); - time_t second_create = b->getCreationDate(); - if (first_create == second_create) - { - return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0); - } - else - { - return (first_create > second_create); - } - } -}; - - -F64 LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; - -LLFavoritesBarCtrl::Params::Params() -: image_drag_indication("image_drag_indication"), - more_button("more_button"), - label("label") -{ -} - -LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) -: LLUICtrl(p), - mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), - mOverflowMenuHandle(), - mContextMenuHandle(), - mImageDragIndication(p.image_drag_indication), - mShowDragMarker(false), - mLandingTab(NULL), - mLastTab(NULL), - mItemsListDirty(false), - mUpdateDropDownItems(true), - mRestoreOverflowMenu(false), - mDragToOverflowMenu(false), - mGetPrevItems(true), - mMouseX(0), - mMouseY(0), - mItemsChangedTimer() -{ - // Register callback for menus with current registrar (will be parent panel's registrar) - LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", - boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2)); - - // Add this if we need to selectively enable items - LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected", - boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2)); - - gInventory.addObserver(this); - - //make chevron button - LLTextBox::Params more_button_params(p.more_button); - mMoreTextBox = LLUICtrlFactory::create (more_button_params); - mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::onMoreTextBoxClicked, this)); - addChild(mMoreTextBox); - LLRect rect = mMoreTextBox->getRect(); - mMoreTextBox->setRect(LLRect(rect.mLeft - rect.getWidth(), rect.mTop, rect.mRight, rect.mBottom)); - - mDropDownItemsCount = 0; - - LLTextBox::Params label_param(p.label); - mBarLabel = LLUICtrlFactory::create (label_param); - addChild(mBarLabel); -} - -LLFavoritesBarCtrl::~LLFavoritesBarCtrl() -{ - gInventory.removeObserver(this); - - if (mOverflowMenuHandle.get()) - mOverflowMenuHandle.get()->die(); - if (mContextMenuHandle.get()) - mContextMenuHandle.get()->die(); -} - -bool LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, - EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) -{ - *accept = ACCEPT_NO; - - LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return false; - - switch (cargo_type) - { - - case DAD_LANDMARK: - { - /* - * add a callback to the end drag event. - * the callback will disconnet itself immediately after execution - * this is done because LLToolDragAndDrop is a common tool so it shouldn't - * be overloaded with redundant callbacks. - */ - if (!mEndDragConnection.connected()) - { - mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this)); - } - - // Copy the item into the favorites folder (if it's not already there). - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - - if (mDragToOverflowMenu) - { - LLView* overflow_menu = mOverflowMenuHandle.get(); - if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) - { - overflow_menu->handleHover(x, y, mask); - } - } - else // Drag to the toolbar itself - { - // Drag to a landmark button? - if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) - { - setLandingTab(dest); - } - else - { - // Drag to the "More" button? - if (mMoreTextBox && mMoreTextBox->getVisible() && mMoreTextBox->getRect().pointInRect(x, y)) - { - LLView* overflow_menu = mOverflowMenuHandle.get(); - if (!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible()) - { - showDropDownMenu(); - } - } - - // Drag to the right of the last landmark button? - if (mLastTab && (x >= mLastTab->getRect().mRight)) - { - /* - * the condition dest == NULL can be satisfied not only in the case - * of dragging to the right from the last tab of the favbar. there is a - * small gap between each tab. if the user drags something exactly there - * then mLandingTab will be set to NULL and the dragged item will be pushed - * to the end of the favorites bar. this is incorrect behavior. that's why - * we need an additional check which excludes the case described previously - * making sure that the mouse pointer is beyond the last tab. - */ - setLandingTab(NULL); - } - } - } - - // Check whether we are dragging an existing item from the favorites bar - bool existing_item = false; - if (item && mDragItemId == item->getUUID()) - { - // There is a chance of mDragItemId being obsolete - // ex: can happen if something interrupts viewer, which - // results in viewer not geting a 'mouse up' signal - for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) - { - if ((*i)->getUUID() == mDragItemId) - { - existing_item = true; - break; - } - } - } - - if (existing_item) - { - *accept = ACCEPT_YES_SINGLE; - - showDragMarker(true); - - if (drop) - { - handleExistingFavoriteDragAndDrop(x, y); - } - } - else - { - const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - if (item->getParentUUID() == favorites_id) - { - LL_WARNS("FavoritesBar") << "Attemt to copy a favorite item into the same folder." << LL_ENDL; - break; - } - - *accept = ACCEPT_YES_COPY_MULTI; - - showDragMarker(true); - - if (drop) - { - if (mItems.empty()) - { - setLandingTab(NULL); - mLastTab = NULL; - } - handleNewFavoriteDragAndDrop(item, favorites_id, x, y); - } - } - } - break; - default: - break; - } - - return true; -} - -bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, bool drop, - EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) -{ - mDragToOverflowMenu = true; - bool handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - mDragToOverflowMenu = false; - return handled; -} - -void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) -{ - if (LL_UNLIKELY(mItems.empty())) - return; - - LLUUID target_id; - bool insert_before = false; - if (!findDragAndDropTarget(target_id, insert_before, x, y)) - return; - - // There is no need to handle if an item was dragged onto itself - if (target_id == mDragItemId) - return; - - // Move the dragged item to the right place in the array - LLInventoryModel::updateItemsOrder(mItems, mDragItemId, target_id, insert_before); - LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); - - LLView* menu = mOverflowMenuHandle.get(); - if (menu && !menu->isDead() && menu->getVisible()) - { - updateOverflowMenuItems(); - positionAndShowOverflowMenu(); - } -} - -void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) -{ - // Identify the button hovered and the side to drop - LLUUID target_id; - bool insert_before = false; - // There is no need to handle if an item was dragged onto itself - if (findDragAndDropTarget(target_id, insert_before, x, y) && (target_id == mDragItemId)) - return; - - LLPointer viewer_item = new LLViewerInventoryItem(item); - - // Insert the dragged item to the right place - if (target_id.notNull()) - { - insertItem(mItems, target_id, viewer_item, insert_before); - } - else - { - // This can happen when the item list is empty - mItems.push_back(viewer_item); - } - - int sortField = 0; - LLPointer cb; - - const F64 CALLBACK_WAIT_TIME = 30.f; - sWaitingForCallabck = LLTimer::getTotalSeconds() + CALLBACK_WAIT_TIME; - - // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field - for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) - { - LLViewerInventoryItem* currItem = *i; - - if (currItem->getUUID() == item->getUUID()) - { - cb = new LLItemCopiedCallback(++sortField); - } - else - { - LLFavoritesOrderStorage::instance().setSortIndex(currItem, ++sortField); - - currItem->setComplete(true); - currItem->updateServer(false); - - gInventory.updateItem(currItem); - } - } - - LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance(); - if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD) - { - viewer_item->setType(LLAssetType::AT_LANDMARK); - copy_inventory_from_notecard(favorites_id, - tool_dad->getObjectID(), - tool_dad->getSourceID(), - viewer_item.get(), - gInventoryCallbacks.registerCB(cb)); - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - favorites_id, - std::string(), - cb); - } - - // [MAINT-2386] Ensure the favorite button has been created and is valid. - // This also ensures that mLastTab will be valid when dropping multiple - // landmarks to an empty favorites bar. - updateButtons(); - - LLView* overflow_menu = mOverflowMenuHandle.get(); - if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) - { - updateOverflowMenuItems(); - positionAndShowOverflowMenu(); - } - - LL_INFOS("FavoritesBar") << "Copied inventory item #" << item->getUUID() << " to favorites." << LL_ENDL; -} - -bool LLFavoritesBarCtrl::findDragAndDropTarget(LLUUID& target_id, bool& insert_before, S32 x, S32 y) -{ - if (mItems.empty()) - return false; - - if (mDragToOverflowMenu) - { - LLView* overflow_menu = mOverflowMenuHandle.get(); - if (LL_UNLIKELY(!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible())) - return false; - - // Identify the menu item hovered and the side to drop - LLFavoriteLandmarkMenuItem* target_item = dynamic_cast(overflow_menu->childFromPoint(x, y)); - if (target_item) - { - insert_before = true; - } - else - { - // Choose the bottom landmark menu item - auto begin = overflow_menu->getChildList()->begin(); - auto end = overflow_menu->getChildList()->end(); - auto check = [](const LLView* child) -> bool - { - return dynamic_cast(child); - }; - // Menu items are placed in the backward order, so the bottom goes first - auto it = std::find_if(begin, end, check); - if (LL_UNLIKELY(it == end)) - return false; - target_item = (LLFavoriteLandmarkMenuItem*)*it; - insert_before = false; - } - target_id = target_item->getLandmarkID(); - } - else - { - // Identify the button hovered and the side to drop - LLFavoriteLandmarkButton* hovered_button = dynamic_cast(mLandingTab); - if (hovered_button) - { - insert_before = true; - } - else - { - // Choose the right landmark button - hovered_button = dynamic_cast(mLastTab); - if (LL_UNLIKELY(!hovered_button)) - return false; - - insert_before = false; - } - target_id = hovered_button->getLandmarkID(); - } - - return true; -} - -//virtual -void LLFavoritesBarCtrl::changed(U32 mask) -{ - if (mFavoriteFolderId.isNull()) - { - mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - - if (mFavoriteFolderId.notNull()) - { - gInventory.fetchDescendentsOf(mFavoriteFolderId); - } - } - else - { - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cats; - LLIsType is_type(LLAssetType::AT_LANDMARK); - gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - - for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) - { - LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID()); - } - - if (sWaitingForCallabck < LLTimer::getTotalSeconds()) - { - updateButtons(); - if (!mItemsChangedTimer.getStarted()) - { - mItemsChangedTimer.start(); - } - else - { - mItemsChangedTimer.reset(); - } - } - else - { - mItemsListDirty = true; - } - } -} - -//virtual -void LLFavoritesBarCtrl::reshape(S32 width, S32 height, bool called_from_parent) -{ - S32 delta_width = width - getRect().getWidth(); - S32 delta_height = height - getRect().getHeight(); - - bool force_update = delta_width || delta_height || sForceReshape; - LLUICtrl::reshape(width, height, called_from_parent); - updateButtons(force_update); -} - -void LLFavoritesBarCtrl::draw() -{ - LLUICtrl::draw(); - - if (mShowDragMarker) - { - S32 w = mImageDragIndication->getWidth(); - S32 h = mImageDragIndication->getHeight(); - - if (mLandingTab) - { - // mouse pointer hovers over an existing tab - LLRect rect = mLandingTab->getRect(); - mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h); - } - else if (mLastTab) - { - // mouse pointer hovers over the favbar empty space (right to the last tab) - LLRect rect = mLastTab->getRect(); - mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h); - } - // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) - mShowDragMarker = false; - } - if (mItemsChangedTimer.getStarted()) - { - if (mItemsChangedTimer.getElapsedTimeF32() > 1.f) - { - LLFavoritesOrderStorage::instance().saveFavoritesRecord(); - mItemsChangedTimer.stop(); - } - } - - if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired) - { - LLFavoritesOrderStorage::instance().mUpdateRequired = false; - mItemsChangedTimer.start(); - } - - if (mItemsListDirty && sWaitingForCallabck < LLTimer::getTotalSeconds()) - { - updateButtons(); - if (!mItemsChangedTimer.getStarted()) - { - mItemsChangedTimer.start(); - } - else - { - mItemsChangedTimer.reset(); - } - } -} - -const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() -{ - static LLButton::Params button_params; - static bool params_initialized = false; - - if (!params_initialized) - { - LLXMLNodePtr button_xml_node; - if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node)) - { - LLXUIParser parser; - parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml"); - } - params_initialized = true; - } - - return button_params; -} - -void LLFavoritesBarCtrl::updateButtons(bool force_update) -{ - if (LLApp::isExiting()) - { - return; - } - - mItemsListDirty = false; - mItems.clear(); - - if (!collectFavoriteItems(mItems)) - { - return; - } - - if(mGetPrevItems && gInventory.isCategoryComplete(mFavoriteFolderId)) - { - for (LLInventoryModel::item_array_t::iterator it = mItems.begin(); it != mItems.end(); it++) - { - LLFavoritesOrderStorage::instance().mFavoriteNames[(*it)->getUUID()]= (*it)->getName(); - } - LLFavoritesOrderStorage::instance().mPrevFavorites = mItems; - mGetPrevItems = false; - - if (LLFavoritesOrderStorage::instance().isStorageUpdateNeeded()) - { - if (!mItemsChangedTimer.getStarted()) - { - mItemsChangedTimer.start(); - } - } - } - - const LLButton::Params& button_params = getButtonParams(); - - if(mItems.empty()) - { - mBarLabel->setVisible(true); - mLastTab = NULL; - } - else - { - mBarLabel->setVisible(false); - } - const child_list_t* childs = getChildList(); - child_list_const_iter_t child_it = childs->begin(); - int first_changed_item_index = 0; - if (!force_update) - { - //lets find first changed button - while (child_it != childs->end() && first_changed_item_index < mItems.size()) - { - LLFavoriteLandmarkButton* button = dynamic_cast (*child_it); - if (button) - { - const LLViewerInventoryItem *item = mItems[first_changed_item_index].get(); - if (item) - { - // an child's order and mItems should be same - if (button->getLandmarkID() != item->getUUID() // sort order has been changed - || button->getLabelSelected() != item->getName()) // favorite's name has been changed - { - break; - } - } - first_changed_item_index++; - } - child_it++; - } - } - // now first_changed_item_index should contains a number of button that need to change - - if (first_changed_item_index <= mItems.size()) - { - // Rebuild the buttons only - // child_list_t is a linked list, so safe to erase from the middle if we pre-increment the iterator - - while (child_it != childs->end()) - { - //lets remove other landmarks button and rebuild it - child_list_const_iter_t cur_it = child_it++; - LLFavoriteLandmarkButton* button = - dynamic_cast (*cur_it); - if (button) - { - if (mLastTab == button) - { - mLastTab = NULL; - } - removeChild(button); - delete button; - } - } - // we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning - // keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton - if (mMoreTextBox->getParent() == this) - { - removeChild(mMoreTextBox); - } - int last_right_edge = 0; - //calculate new buttons offset - if (getChildList()->size() > 0) - { - //find last visible child to get the rightest button offset - child_list_const_reverse_iter_t last_visible_it = - std::find_if( - childs->rbegin(), childs->rend(), - [](const child_list_t::value_type& child) - { return child->getVisible(); }); - if(last_visible_it != childs->rend()) - { - last_right_edge = (*last_visible_it)->getRect().mRight; - } - } - //last_right_edge is saving coordinates - LLButton* last_new_button = NULL; - int j = first_changed_item_index; - for (; j < mItems.size(); j++) - { - last_new_button = createButton(mItems[j], button_params, last_right_edge); - if (!last_new_button) - { - break; - } - sendChildToBack(last_new_button); - last_right_edge = last_new_button->getRect().mRight; - - mLastTab = last_new_button; - } - if (!mLastTab && mItems.size() > 0) - { - // mMoreTextBox was removed, so LLFavoriteLandmarkButtons - // should be the only ones in the list - mLastTab = dynamic_cast(childs->back()); - } - - mFirstDropDownItem = j; - // Chevron button - if (mFirstDropDownItem < mItems.size()) - { - // if updateButton had been called it means: - // or there are some new favorites, or width had been changed - // so if we need to display chevron button, we must update dropdown items too. - mUpdateDropDownItems = true; - S32 buttonHGap = button_params.rect.left; // default value - // Chevron button should stay right aligned - LLRect rect(mMoreTextBox->getRect()); - rect.translate(getRect().mRight - rect.mRight - buttonHGap, 0); - - addChild(mMoreTextBox); - mMoreTextBox->setRect(rect); - mMoreTextBox->setVisible(true); - } - // Update overflow menu - LLToggleableMenu* overflow_menu = static_cast (mOverflowMenuHandle.get()); - if (overflow_menu && overflow_menu->getVisible() && (overflow_menu->getItemCount() != mDropDownItemsCount)) - { - overflow_menu->setVisible(false); - if (mUpdateDropDownItems) - { - showDropDownMenu(); - } - } - } - else - { - mUpdateDropDownItems = false; - } - -} - -LLButton* LLFavoritesBarCtrl::createButton(const LLPointer item, const LLButton::Params& button_params, S32 x_offset) -{ - S32 def_button_width = button_params.rect.width; - S32 button_x_delta = button_params.rect.left; // default value - S32 curr_x = x_offset; - - /** - * WORKAROUND: - * There are some problem with displaying of fonts in buttons. - * Empty space or ellipsis might be displayed instead of last symbols, even though the width of the button is enough. - * The problem disappears if we pad the button with 20 pixels. - */ - int required_width = mFont->getWidth(item->getName()) + 20; - int width = required_width > def_button_width? def_button_width : required_width; - LLFavoriteLandmarkButton* fav_btn = NULL; - - // do we have a place for next button + double buttonHGap + mMoreTextBox ? - if(curr_x + width + 2*button_x_delta + mMoreTextBox->getRect().getWidth() > getRect().mRight ) - { - return NULL; - } - LLButton::Params fav_btn_params(button_params); - fav_btn = LLUICtrlFactory::create(fav_btn_params); - if (NULL == fav_btn) - { - LL_WARNS("FavoritesBar") << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << LL_ENDL; - return NULL; - } - - addChild(fav_btn); - - LLRect butt_rect (fav_btn->getRect()); - fav_btn->setLandmarkID(item->getUUID()); - butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight()); - - fav_btn->setRect(butt_rect); - // change only left and save bottom - fav_btn->setFont(mFont); - fav_btn->setLabel(item->getName()); - fav_btn->setToolTip(item->getName()); - fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); - fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); - - fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); - fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); - - return fav_btn; -} - - -bool LLFavoritesBarCtrl::postBuild() -{ - // make the popup menu available - LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if (!menu) - { - menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); - } - menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); - mContextMenuHandle = menu->getHandle(); - - return true; -} - -bool LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) -{ - - if (mFavoriteFolderId.isNull()) - return false; - - - LLInventoryModel::cat_array_t cats; - - LLIsType is_type(LLAssetType::AT_LANDMARK); - gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - - std::sort(items.begin(), items.end(), LLFavoritesSort()); - - if (needToSaveItemsOrder(items)) - { - S32 sortField = 0; - for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) - { - LLFavoritesOrderStorage::instance().setSortIndex((*i), ++sortField); - } - LLFavoritesOrderStorage::instance().mSaveOnExit = true; - } - - return true; -} - -void LLFavoritesBarCtrl::onMoreTextBoxClicked() -{ - LLUI::getInstance()->getMousePositionScreen(&mMouseX, &mMouseY); - showDropDownMenu(); -} - -void LLFavoritesBarCtrl::showDropDownMenu() -{ - if (mOverflowMenuHandle.isDead()) - { - createOverflowMenu(); - } - - LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); - if (menu && menu->toggleVisibility()) - { - if (mUpdateDropDownItems) - { - updateOverflowMenuItems(); - } - else - { - menu->buildDrawLabels(); - } - - menu->updateParent(LLMenuGL::sMenuContainer); - menu->setButtonRect(mMoreTextBox->getRect(), this); - positionAndShowOverflowMenu(); - } -} - -void LLFavoritesBarCtrl::createOverflowMenu() -{ - LLToggleableMenu::Params menu_p; - menu_p.name("favorites menu"); - menu_p.can_tear_off(false); - menu_p.visible(false); - menu_p.scrollable(true); - menu_p.max_scrollable_items = 10; - menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; - - LLFavoriteLandmarkToggleableMenu* menu = LLUICtrlFactory::create(menu_p); - menu->setToolbar(this); - mOverflowMenuHandle = menu->getHandle(); -} - -void LLFavoritesBarCtrl::updateOverflowMenuItems() -{ - LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); - menu->empty(); - - U32 widest_item = 0; - - for (S32 i = mFirstDropDownItem; i < mItems.size(); i++) - { - LLViewerInventoryItem* item = mItems.at(i); - const std::string& item_name = item->getName(); - - LLFavoriteLandmarkMenuItem::Params item_params; - item_params.name(item_name); - item_params.label(item_name); - item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); - - LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create(item_params); - menu_item->initFavoritesBarPointer(this); - menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4)); - menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); - menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); - menu_item->setLandmarkID(item->getUUID()); - - fitLabelWidth(menu_item); - - widest_item = llmax(widest_item, menu_item->getNominalWidth()); - - menu->addChild(menu_item); - } - - menu->buildDrawLabels(); - mDropDownItemsCount = menu->getItemCount(); - addOpenLandmarksMenuItem(menu); - mUpdateDropDownItems = false; -} - -void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item) -{ - U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); - std::string item_name = menu_item->getName(); - - // Check whether item name wider than menu - if (menu_item->getNominalWidth() > max_width) - { - S32 chars_total = item_name.length(); - S32 chars_fitted = 1; - menu_item->setLabel(LLStringExplicit("")); - S32 label_space = max_width - menu_item->getFont()->getWidth("...") - - menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels) - - while (chars_fitted < chars_total - && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) - { - chars_fitted++; - } - chars_fitted--; // Rolling back one char, that doesn't fit - - menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); - } -} - -void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu) -{ - std::string label_untrans = "Open landmarks"; - std::string label_transl; - bool translated = LLTrans::findString(label_transl, label_untrans); - - LLMenuItemCallGL::Params item_params; - item_params.name("open_my_landmarks"); - item_params.label(translated ? label_transl: label_untrans); - LLSD key; - key["type"] = "open_landmark_tab"; - item_params.on_click.function(boost::bind(&LLFloaterSidePanelContainer::showPanel, "places", key)); - LLMenuItemCallGL* menu_item = LLUICtrlFactory::create(item_params); - - fitLabelWidth(menu_item); - - LLMenuItemSeparatorGL::Params sep_params; - sep_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); - sep_params.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); - sep_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); - sep_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); - LLMenuItemSeparatorGL* separator = LLUICtrlFactory::create(sep_params); - - menu->addChild(separator); - menu->addChild(menu_item); -} - -void LLFavoritesBarCtrl::positionAndShowOverflowMenu() -{ - LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); - U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); - - S32 menu_x = getRect().getWidth() - max_width; - S32 menu_y = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; - - // the menu should be offset of the right edge of the window - // so it's no covered by buttons in the right-side toolbar. - LLToolBar* right_toolbar = gToolBarView->getChild("toolbar_right"); - if (right_toolbar && right_toolbar->hasButtons()) - { - S32 toolbar_top = 0; - - if (LLView* top_border_panel = right_toolbar->getChild("button_panel")) - { - toolbar_top = top_border_panel->calcScreenRect().mTop; - } - - // Calculating the bottom (in screen coord) of the drop down menu - S32 menu_top = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; - S32 menu_bottom = menu_top - menu->getRect().getHeight(); - S32 menu_bottom_screen = 0; - - localPointToScreen(0, menu_bottom, &menu_top, &menu_bottom_screen); - - if (menu_bottom_screen < toolbar_top) - { - menu_x -= right_toolbar->getRect().getWidth(); - } - } - - LLMenuGL::showPopup(this, menu, menu_x, menu_y, mMouseX, mMouseY); -} - -void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) -{ - // We only have one Inventory, gInventory. Some day this should be better abstracted. - LLInvFVBridgeAction::doAction(item_id,&gInventory); -} - -void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask) -{ - mSelectedItemID = item_id; - - LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); - if (!menu) - { - return; - } - - // Remember that the context menu was shown simultaneously with the overflow menu, - // so that we can restore the overflow menu when user clicks a context menu item - // (which hides the overflow menu). - { - LLView* overflow_menu = mOverflowMenuHandle.get(); - mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible(); - } - - // Release mouse capture so hover events go to the popup menu - // because this is happening during a mouse down. - gFocusMgr.setMouseCapture(NULL); - - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(fav_button, menu, x, y); -} - -bool LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - bool handled = childrenHandleRightMouseDown( x, y, mask) != NULL; - if(!handled && !gMenuHolder->hasVisibleMenu()) - { - show_navbar_context_menu(this,x,y); - handled = true; - } - - return handled; -} -void copy_slurl_to_clipboard_cb(std::string& slurl) -{ - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); - - LLSD args; - args["SLURL"] = slurl; - LLNotificationsUtil::add("CopySLURL", args); -} - - -bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) -{ - std::string param = userdata.asString(); - - if (param == std::string("can_paste")) - { - return isClipboardPasteable(); - } - else if (param == "create_pick") - { - return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); - } - - return false; -} - -void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) -{ - std::string action = userdata.asString(); - LL_INFOS("FavoritesBar") << "Action = " << action << " Item = " << mSelectedItemID.asString() << LL_ENDL; - - LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID); - if (!item) - return; - - if (action == "open") - { - onButtonClick(item->getUUID()); - } - else if (action == "about") - { - LLSD key; - key["type"] = "landmark"; - key["id"] = mSelectedItemID; - - LLFloaterSidePanelContainer::showPanel("places", key); - } - else if (action == "copy_slurl") - { - LLVector3d posGlobal; - LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); - - if (!posGlobal.isExactlyZero()) - { - LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb); - } - } - else if (action == "show_on_map") - { - LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); - - LLVector3d posGlobal; - LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); - - if (!posGlobal.isExactlyZero() && worldmap_instance) - { - worldmap_instance->trackLocation(posGlobal); - LLFloaterReg::showInstance("world_map", "center"); - } - } - else if (action == "create_pick") - { - LLSD args; - args["type"] = "create_pick"; - args["item_id"] = item->getUUID(); - LLFloaterSidePanelContainer::showPanel("places", args); - } - else if (action == "cut") - { - } - else if (action == "copy") - { - LLClipboard::instance().copyToClipboard(mSelectedItemID, LLAssetType::AT_LANDMARK); - } - else if (action == "paste") - { - pasteFromClipboard(); - } - else if (action == "delete") - { - gInventory.removeItem(mSelectedItemID); - } - else if (action == "rename") - { - LLSD args; - args["NAME"] = item->getName(); - - LLSD payload; - payload["id"] = mSelectedItemID; - - LLNotificationsUtil::add("RenameLandmark", args, payload, boost::bind(onRenameCommit, _1, _2)); - } - else if (action == "move_to_landmarks") - { - change_item_parent(mSelectedItemID, gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); - } - - // Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item). - // See EXT-4217 and STORM-207. - LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get(); - if (mRestoreOverflowMenu && menu && !menu->getVisible()) - { - menu->resetScrollPositionOnShow(false); - showDropDownMenu(); - menu->resetScrollPositionOnShow(true); - } -} - -bool LLFavoritesBarCtrl::onRenameCommit(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLUUID id = notification["payload"]["id"].asUUID(); - LLInventoryItem *item = gInventory.getItem(id); - std::string landmark_name = response["new_name"].asString(); - LLStringUtil::trim(landmark_name); - - if (!landmark_name.empty() && item && item->getName() != landmark_name) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(landmark_name); - new_item->updateServer(false); - gInventory.updateItem(new_item); - } - } - - return false; -} - -bool LLFavoritesBarCtrl::isClipboardPasteable() const -{ - if (!LLClipboard::instance().hasContents()) - { - return false; - } - - std::vector objects; - LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - for(S32 i = 0; i < count; i++) - { - const LLUUID &item_id = objects.at(i); - - // Can't paste folders - const LLInventoryCategory *cat = gInventory.getCategory(item_id); - if (cat) - { - return false; - } - - const LLInventoryItem *item = gInventory.getItem(item_id); - if (item && LLAssetType::AT_LANDMARK != item->getType()) - { - return false; - } - } - return true; -} - -void LLFavoritesBarCtrl::pasteFromClipboard() const -{ - LLInventoryModel* model = &gInventory; - if(model && isClipboardPasteable()) - { - LLInventoryItem* item = NULL; - std::vector objects; - LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - LLUUID parent_id(mFavoriteFolderId); - for(S32 i = 0; i < count; i++) - { - item = model->getItem(objects.at(i)); - if (item) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - parent_id, - std::string(), - LLPointer(NULL)); - } - } - } -} - -void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) -{ - // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away) - // mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu. - // We have to check and set visibility of pop-up menu in such a way instead of using - // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but - // we need to close only pop-up menu while dropdown one should be still opened. - LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); - if(menu && menu->getVisible()) - { - menu->setVisible(false); - } - - mDragItemId = id; - mStartDrag = true; - - S32 screenX, screenY; - localPointToScreen(x, y, &screenX, &screenY); - - LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY); -} - -void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) -{ - mStartDrag = false; - mDragItemId = LLUUID::null; -} - -void LLFavoritesBarCtrl::onEndDrag() -{ - mEndDragConnection.disconnect(); - - showDragMarker(false); - mDragItemId = LLUUID::null; - LLView::getWindow()->setCursor(UI_CURSOR_ARROW); -} - -bool LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) -{ - if (mDragItemId != LLUUID::null && mStartDrag) - { - S32 screenX, screenY; - localPointToScreen(x, y, &screenX, &screenY); - - if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY)) - { - LLToolDragAndDrop::getInstance()->beginDrag( - DAD_LANDMARK, mDragItemId, - LLToolDragAndDrop::SOURCE_LIBRARY); - - mStartDrag = false; - - return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); - } - } - - return true; -} - -LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) -{ - LLUICtrl* ctrl = NULL; - const child_list_t* list = getChildList(); - - for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i) - { - // Look only for children that are favorite buttons - if ((*i)->getName() == "favorites_bar_btn") - { - LLRect rect = (*i)->getRect(); - // We consider a button hit if the cursor is left of the right side - // This makes the hit a bit less finicky than hitting directly on the button itself - if (x <= rect.mRight) - { - ctrl = dynamic_cast(*i); - break; - } - } - } - - return ctrl; -} - -bool LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) -{ - bool result = false; - - // if there is an item without sort order field set, we need to save items order - for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) - { - if (LLFavoritesOrderStorage::instance().getSortIndex((*i)->getUUID()) < 0) - { - result = true; - break; - } - } - - return result; -} - -void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before) -{ - // Get the iterator to the destination item - LLInventoryModel::item_array_t::iterator it_dest = LLInventoryModel::findItemIterByUUID(items, dest_item_id); - if (it_dest == items.end()) - return; - - // Go to the next element if one wishes to insert after the dest element - if (!insert_before) - { - ++it_dest; - } - - // Insert the source item in the right place - if (it_dest != items.end()) - { - items.insert(it_dest, insertedItem); - } - else - { - // Append to the list if it_dest reached the end - items.push_back(insertedItem); - } -} - -const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; -const S32 LLFavoritesOrderStorage::NO_INDEX = -1; -bool LLFavoritesOrderStorage::mSaveOnExit = false; - -void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index) -{ - mSortIndexes[inv_item->getUUID()] = sort_index; - mIsDirty = true; - getSLURL(inv_item->getAssetUUID()); -} - -S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) -{ - sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); - if (it != mSortIndexes.end()) - { - return it->second; - } - return NO_INDEX; -} - -void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) -{ - mSortIndexes.erase(inv_item_id); - mIsDirty = true; -} - -void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) -{ - slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id); - if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached - - LLLandmark* lm = gLandmarkList.getAsset(asset_id, - boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1)); - if (lm) - { - LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL; - onLandmarkLoaded(asset_id, lm); - } - return; -} - -// static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) -{ - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); - - return (user_dir.empty() ? "" - : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, - "stored_favorites_" - + grid - + ".xml") - ); -} - -// static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() -{ - return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); -} - -// static -void LLFavoritesOrderStorage::destroyClass() -{ - LLFavoritesOrderStorage::instance().cleanup(); - - - std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); - llifstream file; - file.open(old_filename.c_str()); - if (file.is_open()) - { - file.close(); - std::string new_filename = getStoredFavoritesFilename(); - LL_INFOS("FavoritesBar") << "moving favorites from old name '" << old_filename - << "' to new name '" << new_filename << "'" - << LL_ENDL; - LLFile::copy(old_filename,new_filename); - LLFile::remove(old_filename); - } - - std::string filename = getSavedOrderFileName(); - file.open(filename.c_str()); - if (file.is_open()) - { - file.close(); - LLFile::remove(filename); - } - if(mSaveOnExit || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) - { - LLFavoritesOrderStorage::instance().saveFavoritesRecord(true); - } -} - -std::string LLFavoritesOrderStorage::getSavedOrderFileName() -{ - // If we quit from the login screen we will not have an SL account - // name. Don't try to save, otherwise we'll dump a file in - // C:\Program Files\SecondLife\ or similar. JC - std::string user_dir = gDirUtilp->getLindenUserDir(); - return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME)); -} - -void LLFavoritesOrderStorage::load() -{ - std::string filename = getSavedOrderFileName(); - LLSD settings_llsd; - llifstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::fromXML(settings_llsd, file); - LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " - << (settings_llsd.isMap() ? "" : "un") << "successfully" - << LL_ENDL; - file.close(); - mSaveOnExit = true; - - for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); - iter != settings_llsd.endMap(); ++iter) - { - mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); - } - } - else - { - filename = getStoredFavoritesFilename(); - if (!filename.empty()) - { - llifstream in_file; - in_file.open(filename.c_str()); - LLSD fav_llsd; - if (in_file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, in_file); - LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " - << (fav_llsd.isMap() ? "" : "un") << "successfully" - << LL_ENDL; - in_file.close(); - if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) - { - mStorageFavorites = fav_llsd[gAgentUsername]; - - S32 index = 0; - bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); - for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); - iter != mStorageFavorites.endArray(); ++iter) - { - // Validation - LLUUID fv_id = iter->get("id").asUUID(); - if (needs_validation - && (fv_id.isNull() - || iter->get("asset_id").asUUID().isNull() - || iter->get("name").asString().empty() - || iter->get("slurl").asString().empty())) - { - mRecreateFavoriteStorage = true; - } - - mSortIndexes.insert(std::make_pair(fv_id, index)); - index++; - } - } - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; - } - } - } -} - -// static -void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) -{ - std::string filename = getStoredFavoritesFilename(grid); - if (!filename.empty()) - { - LLSD fav_llsd; - llifstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, file); - file.close(); - - // Note : use the "John Doe" and not the "john.doe" version of the name. - // See saveFavoritesSLURLs() here above for the reason why. - if (fav_llsd.has(user)) - { - LLSD user_llsd = fav_llsd[user]; - - if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) - { - for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) - { - LLSD value; - value["id"] = iter->get("id").asUUID(); - iter->assign(value); - } - fav_llsd[user] = user_llsd; - llofstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::toPrettyXML(fav_llsd, file); - file.close(); - } - } - else - { - LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; - fav_llsd.erase(user); - } - } - - llofstream out_file; - out_file.open(filename.c_str()); - if (out_file.is_open()) - { - LLSDSerialize::toPrettyXML(fav_llsd, out_file); - LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " - << LL_ENDL; - out_file.close(); - } - } - } -} - -// static -void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() -{ - std::string filename = getStoredFavoritesFilename(); - if (!filename.empty()) - { - LLSD fav_llsd; - llifstream file; - file.open(filename.c_str()); - if (file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, file); - file.close(); - - LLAvatarName av_name; - LLAvatarNameCache::get( gAgentID, &av_name ); - // Note : use the "John Doe" and not the "john.doe" version of the name. - // See saveFavoritesSLURLs() here above for the reason why. - if (fav_llsd.has(av_name.getUserName())) - { - LLSD user_llsd = fav_llsd[av_name.getUserName()]; - - if ((user_llsd.beginArray()!= user_llsd.endArray()) && user_llsd.beginArray()->has("id")) - { - for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter) - { - LLSD value; - value["id"]= iter->get("id").asUUID(); - iter->assign(value); - } - fav_llsd[av_name.getUserName()] = user_llsd; - llofstream file; - file.open(filename.c_str()); - if ( file.is_open() ) - { - LLSDSerialize::toPrettyXML(fav_llsd, file); - file.close(); - } - } - else - { - LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; - fav_llsd.erase(av_name.getUserName()); - } - } - - llofstream out_file; - out_file.open(filename.c_str()); - if ( out_file.is_open() ) - { - LLSDSerialize::toPrettyXML(fav_llsd, out_file); - LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " - << LL_ENDL; - out_file.close(); - } - } - } -} - -void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark) -{ - if (landmark) - { - LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL; - LLVector3d pos_global; - if (!landmark->getGlobalPos(pos_global)) - { - // If global position was unknown on first getGlobalPos() call - // it should be set for the subsequent calls. - landmark->getGlobalPos(pos_global); - } - - if (!pos_global.isExactlyZero()) - { - LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; - LLLandmarkActions::getSLURLfromPosGlobal(pos_global, - boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); - } - } -} - -void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl) -{ - LL_DEBUGS("FavoritesBar") << "Saving landmark SLURL '" << slurl << "' for " << asset_id << LL_ENDL; - mSLURLs[asset_id] = slurl; -} - -void LLFavoritesOrderStorage::cleanup() -{ - // nothing to clean - if (!mIsDirty) return; - - const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - - IsNotInFavorites is_not_in_fav(items); - - sort_index_map_t aTempMap; - //copy unremoved values from mSortIndexes to aTempMap - std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), - inserter(aTempMap, aTempMap.begin()), - is_not_in_fav); - - //Swap the contents of mSortIndexes and aTempMap - mSortIndexes.swap(aTempMap); -} - -// See also LLInventorySort where landmarks in the Favorites folder are sorted. -class LLViewerInventoryItemSort -{ -public: - bool operator()(const LLPointer& a, const LLPointer& b) - { - return LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()) - < LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); - } -}; - -void LLFavoritesOrderStorage::saveOrder() -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLIsType is_type(LLAssetType::AT_LANDMARK); - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); - saveItemsOrder(items); -} - -void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items ) -{ - - int sortField = 0; - // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field - for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) - { - LLViewerInventoryItem* item = *i; - - setSortIndex(item, ++sortField); - - item->setComplete(true); - item->updateServer(false); - - gInventory.updateItem(item); - - // Tell the parent folder to refresh its sort order. - gInventory.addChangedMask(LLInventoryObserver::SORT, item->getParentUUID()); - } - - gInventory.notifyObservers(); -} - - -// * @param source_item_id - LLUUID of the source item to be moved into new position -// * @param target_item_id - LLUUID of the target item before which source item should be placed. -void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLIsType is_type(LLAssetType::AT_LANDMARK); - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - - // ensure items are sorted properly before changing order. EXT-3498 - std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); - - // update order - gInventory.updateItemsOrder(items, source_item_id, target_item_id); - - saveItemsOrder(items); -} - -bool LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) -{ - pref_changed |= mRecreateFavoriteStorage; - mRecreateFavoriteStorage = false; - - // Can get called before inventory is done initializing. - if (!gInventory.isInventoryUsable()) - { - return false; - } - - LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - if (favorite_folder.isNull()) - { - return false; - } - - LLInventoryModel::item_array_t items; - LLInventoryModel::cat_array_t cats; - - LLIsType is_type(LLAssetType::AT_LANDMARK); - gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - - std::sort(items.begin(), items.end(), LLFavoritesSort()); - bool name_changed = false; - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) - { - if(mFavoriteNames[(*it)->getUUID()] != ((*it)->getName())) - { - mFavoriteNames[(*it)->getUUID()] = (*it)->getName(); - name_changed = true; - } - } - - for (std::set::iterator it = mMissingSLURLs.begin(); it != mMissingSLURLs.end(); it++) - { - slurls_map_t::iterator slurl_iter = mSLURLs.find(*it); - if (slurl_iter != mSLURLs.end()) - { - pref_changed = true; - break; - } - } - - if((items != mPrevFavorites) || name_changed || pref_changed || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) - { - std::string filename = getStoredFavoritesFilename(); - if (!filename.empty()) - { - llifstream in_file; - in_file.open(filename.c_str()); - LLSD fav_llsd; - if (in_file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, in_file); - in_file.close(); - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; - } - - LLSD user_llsd; - S32 fav_iter = 0; - mMissingSLURLs.clear(); - - LLSD save_pass; - save_pass["save_password"] = gSavedSettings.getBOOL("RememberPassword"); - user_llsd[fav_iter] = save_pass; - fav_iter++; - - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) - { - LLSD value; - if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) - { - value["name"] = (*it)->getName(); - value["asset_id"] = (*it)->getAssetUUID(); - value["id"] = (*it)->getUUID(); - slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); - if (slurl_iter != mSLURLs.end()) - { - value["slurl"] = slurl_iter->second; - user_llsd[fav_iter] = value; - } - else - { - getSLURL((*it)->getAssetUUID()); - value["slurl"] = ""; - user_llsd[fav_iter] = value; - mUpdateRequired = true; - mMissingSLURLs.insert((*it)->getAssetUUID()); - } - } - else - { - value["id"] = (*it)->getUUID(); - user_llsd[fav_iter] = value; - } - - fav_iter ++; - } - - LLAvatarName av_name; - LLAvatarNameCache::get( gAgentID, &av_name ); - // Note : use the "John Doe" and not the "john.doe" version of the name - // as we'll compare it with the stored credentials in the login panel. - fav_llsd[av_name.getUserName()] = user_llsd; - llofstream file; - file.open(filename.c_str()); - if ( file.is_open() ) - { - LLSDSerialize::toPrettyXML(fav_llsd, file); - file.close(); - mSaveOnExit = false; - } - else - { - LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() - << "' at '" << filename << "' " << LL_ENDL; - } - } - mPrevFavorites = items; - } - - return true; - -} - -void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(bool show) -{ - if (show) - { - saveFavoritesRecord(true); - } - else - { - removeFavoritesRecordOfUser(); - } -} - -bool LLFavoritesOrderStorage::isStorageUpdateNeeded() -{ - if (!mRecreateFavoriteStorage) - { - for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); - iter != mStorageFavorites.endArray(); ++iter) - { - if (mFavoriteNames[iter->get("id").asUUID()] != iter->get("name").asString()) - { - mRecreateFavoriteStorage = true; - return true; - } - } - } - return false; -} - -void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) -{ - if (!mTargetLandmarkId.isNull()) - { - LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); - } -} - -// EOF +/** + * @file llfavoritesbar.cpp + * @brief LLFavoritesBarCtrl class implementation + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfavoritesbar.h" + +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llinventory.h" +#include "lllandmarkactions.h" +#include "lltoolbarview.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llmenugl.h" +#include "lltooltip.h" + +#include "llagent.h" +#include "llagentpicksinfo.h" +#include "llavatarnamecache.h" +#include "llclipboard.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llfloatersidepanelcontainer.h" +#include "llfloaterworldmap.h" +#include "lllandmarkactions.h" +#include "lllogininstance.h" +#include "llnotificationsutil.h" +#include "lltoggleablemenu.h" +#include "llviewerinventory.h" +#include "llviewermenu.h" +#include "llviewernetwork.h" +#include "lltooldraganddrop.h" +#include "llsdserialize.h" + +static LLDefaultChildRegistry::Register r("favorites_bar"); + +const S32 DROP_DOWN_MENU_WIDTH = 250; +const S32 DROP_DOWN_MENU_TOP_PAD = 13; + +/** + * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem. + * Performing requests for SLURL for given Landmark ID + */ +class LLLandmarkInfoGetter +{ +public: + LLLandmarkInfoGetter() + : mLandmarkID(LLUUID::null), + mName("(Loading...)"), + mPosX(0), + mPosY(0), + mPosZ(0), + mLoaded(false) + { + mHandle.bind(this); + } + + void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + const LLUUID& getLandmarkID() const { return mLandmarkID; } + + const std::string& getName() + { + if(!mLoaded) + requestNameAndPos(); + + return mName; + } + + S32 getPosX() + { + if (!mLoaded) + requestNameAndPos(); + return mPosX; + } + + S32 getPosY() + { + if (!mLoaded) + requestNameAndPos(); + return mPosY; + } + + S32 getPosZ() + { + if (!mLoaded) + requestNameAndPos(); + return mPosZ; + } + +private: + /** + * Requests landmark data from server. + */ + void requestNameAndPos() + { + if (mLandmarkID.isNull()) + return; + + LLVector3d g_pos; + if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) + { + LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos, + boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, static_cast >(mHandle), _1, _2, _3, _4)); + } + } + + static void landmarkNameCallback(LLHandle handle, const std::string& name, S32 x, S32 y, S32 z) + { + LLLandmarkInfoGetter* getter = handle.get(); + if (getter) + { + getter->mPosX = x; + getter->mPosY = y; + getter->mPosZ = z; + getter->mName = name; + getter->mLoaded = true; + } + } + + LLUUID mLandmarkID; + std::string mName; + S32 mPosX; + S32 mPosY; + S32 mPosZ; + bool mLoaded; + LLRootHandle mHandle; +}; + +/** + * This class is needed to override LLButton default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in createButtons function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkButton : public LLButton +{ +public: + + bool handleToolTip(S32 x, S32 y, MASK mask) + { + std::string region_name = mLandmarkInfoGetter.getName(); + + if (!region_name.empty()) + { + std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), + mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ()); + + LLToolTip::Params params; + params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str()); + params.max_width = 1000; + params.sticky_rect = calcScreenRect(); + + LLToolTipMgr::instance().show(params); + } + return true; + } + + /*virtual*/ bool handleHover(S32 x, S32 y, MASK mask) + { + LLFavoritesBarCtrl* fb = dynamic_cast(getParent()); + + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLButton::handleHover(x, y, mask); + } + + void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } + + void onMouseEnter(S32 x, S32 y, MASK mask) + { + if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) + { + LLUICtrl::onMouseEnter(x, y, mask); + } + else + { + LLButton::onMouseEnter(x, y, mask); + } + } + +protected: + LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} + friend class LLUICtrlFactory; + +private: + LLLandmarkInfoGetter mLandmarkInfoGetter; +}; + +/** + * This class is needed to override LLMenuItemCallGL default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in showDropDownMenu function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL +{ +public: + bool handleToolTip(S32 x, S32 y, MASK mask) + { + std::string region_name = mLandmarkInfoGetter.getName(); + if (!region_name.empty()) + { + LLToolTip::Params params; + params.message = llformat("%s\n%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY()); + params.sticky_rect = calcScreenRect(); + LLToolTipMgr::instance().show(params); + } + return true; + } + + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } + void setLandmarkID(const LLUUID& id) { mLandmarkInfoGetter.setLandmarkID(id); } + + virtual bool handleMouseDown(S32 x, S32 y, MASK mask) + { + if (mMouseDownSignal) + (*mMouseDownSignal)(this, x, y, mask); + return LLMenuItemCallGL::handleMouseDown(x, y, mask); + } + + virtual bool handleMouseUp(S32 x, S32 y, MASK mask) + { + if (mMouseUpSignal) + (*mMouseUpSignal)(this, x, y, mask); + return LLMenuItemCallGL::handleMouseUp(x, y, mask); + } + + virtual bool handleHover(S32 x, S32 y, MASK mask) + { + if (fb) + { + fb->handleHover(x, y, mask); + } + + return true; + } + + void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } + +protected: + + LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} + friend class LLUICtrlFactory; + +private: + LLLandmarkInfoGetter mLandmarkInfoGetter; + LLFavoritesBarCtrl* fb; +}; + +/** + * This class was introduced just for fixing the following issue: + * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through. + * We must explicitly handle drag and drop event by returning true + * because otherwise LLToolDragAndDrop will initiate drag and drop operation + * with the world. + */ +class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu +{ +public: + // virtual + bool handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, EDragAndDropType cargo_type, + void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override + { + mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + return true; + } + + // virtual + bool handleHover(S32 x, S32 y, MASK mask) override + { + mIsHovering = true; + LLToggleableMenu::handleHover(x, y, mask); + mIsHovering = false; + return true; + } + + // virtual + void setVisible(bool visible) override + { + // Avoid of hiding the menu during hovering + if (visible || !mIsHovering) + { + LLToggleableMenu::setVisible(visible); + } + } + + void setToolbar(LLFavoritesBarCtrl* toolbar) + { + mToolbar = toolbar; + } + + ~LLFavoriteLandmarkToggleableMenu() + { + // Enable subsequent setVisible(false) + mIsHovering = false; + setVisible(false); + } + +protected: + LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p): + LLToggleableMenu(p) + { + } + +private: + LLFavoritesBarCtrl* mToolbar { nullptr }; + bool mIsHovering { false }; + + friend class LLUICtrlFactory; +}; + +/** + * This class is needed to update an item being copied to the favorites folder + * with a sort field value (required to save favorites bar's tabs order). + * See method handleNewFavoriteDragAndDrop for more details on how this class is used. + */ +class LLItemCopiedCallback : public LLInventoryCallback +{ +public: + LLItemCopiedCallback(S32 sortField): mSortField(sortField) {} + + virtual void fire(const LLUUID& inv_item) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + + if (item) + { + LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; + LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField); + + item->setComplete(true); + item->updateServer(false); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + LLFavoritesOrderStorage::instance().saveOrder(); + } + + LLView::getWindow()->setCursor(UI_CURSOR_ARROW); + } + +private: + S32 mSortField; +}; + +// updateButtons's helper +struct LLFavoritesSort +{ + // Sorting by creation date and name + // TODO - made it customizible using gSavedSettings + bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) + { + S32 sortField1 = LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()); + S32 sortField2 = LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); + + if (!(sortField1 < 0 && sortField2 < 0)) + { + return sortField2 > sortField1; + } + + time_t first_create = a->getCreationDate(); + time_t second_create = b->getCreationDate(); + if (first_create == second_create) + { + return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0); + } + else + { + return (first_create > second_create); + } + } +}; + + +F64 LLFavoritesBarCtrl::sWaitingForCallabck = 0.f; + +LLFavoritesBarCtrl::Params::Params() +: image_drag_indication("image_drag_indication"), + more_button("more_button"), + label("label") +{ +} + +LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) +: LLUICtrl(p), + mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), + mOverflowMenuHandle(), + mContextMenuHandle(), + mImageDragIndication(p.image_drag_indication), + mShowDragMarker(false), + mLandingTab(NULL), + mLastTab(NULL), + mItemsListDirty(false), + mUpdateDropDownItems(true), + mRestoreOverflowMenu(false), + mDragToOverflowMenu(false), + mGetPrevItems(true), + mMouseX(0), + mMouseY(0), + mItemsChangedTimer() +{ + // Register callback for menus with current registrar (will be parent panel's registrar) + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", + boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2)); + + // Add this if we need to selectively enable items + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected", + boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2)); + + gInventory.addObserver(this); + + //make chevron button + LLTextBox::Params more_button_params(p.more_button); + mMoreTextBox = LLUICtrlFactory::create (more_button_params); + mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::onMoreTextBoxClicked, this)); + addChild(mMoreTextBox); + LLRect rect = mMoreTextBox->getRect(); + mMoreTextBox->setRect(LLRect(rect.mLeft - rect.getWidth(), rect.mTop, rect.mRight, rect.mBottom)); + + mDropDownItemsCount = 0; + + LLTextBox::Params label_param(p.label); + mBarLabel = LLUICtrlFactory::create (label_param); + addChild(mBarLabel); +} + +LLFavoritesBarCtrl::~LLFavoritesBarCtrl() +{ + gInventory.removeObserver(this); + + if (mOverflowMenuHandle.get()) + mOverflowMenuHandle.get()->die(); + if (mContextMenuHandle.get()) + mContextMenuHandle.get()->die(); +} + +bool LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop, + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) +{ + *accept = ACCEPT_NO; + + LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); + if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return false; + + switch (cargo_type) + { + + case DAD_LANDMARK: + { + /* + * add a callback to the end drag event. + * the callback will disconnet itself immediately after execution + * this is done because LLToolDragAndDrop is a common tool so it shouldn't + * be overloaded with redundant callbacks. + */ + if (!mEndDragConnection.connected()) + { + mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this)); + } + + // Copy the item into the favorites folder (if it's not already there). + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + + if (mDragToOverflowMenu) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + overflow_menu->handleHover(x, y, mask); + } + } + else // Drag to the toolbar itself + { + // Drag to a landmark button? + if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + { + setLandingTab(dest); + } + else + { + // Drag to the "More" button? + if (mMoreTextBox && mMoreTextBox->getVisible() && mMoreTextBox->getRect().pointInRect(x, y)) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible()) + { + showDropDownMenu(); + } + } + + // Drag to the right of the last landmark button? + if (mLastTab && (x >= mLastTab->getRect().mRight)) + { + /* + * the condition dest == NULL can be satisfied not only in the case + * of dragging to the right from the last tab of the favbar. there is a + * small gap between each tab. if the user drags something exactly there + * then mLandingTab will be set to NULL and the dragged item will be pushed + * to the end of the favorites bar. this is incorrect behavior. that's why + * we need an additional check which excludes the case described previously + * making sure that the mouse pointer is beyond the last tab. + */ + setLandingTab(NULL); + } + } + } + + // Check whether we are dragging an existing item from the favorites bar + bool existing_item = false; + if (item && mDragItemId == item->getUUID()) + { + // There is a chance of mDragItemId being obsolete + // ex: can happen if something interrupts viewer, which + // results in viewer not geting a 'mouse up' signal + for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) + { + if ((*i)->getUUID() == mDragItemId) + { + existing_item = true; + break; + } + } + } + + if (existing_item) + { + *accept = ACCEPT_YES_SINGLE; + + showDragMarker(true); + + if (drop) + { + handleExistingFavoriteDragAndDrop(x, y); + } + } + else + { + const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if (item->getParentUUID() == favorites_id) + { + LL_WARNS("FavoritesBar") << "Attemt to copy a favorite item into the same folder." << LL_ENDL; + break; + } + + *accept = ACCEPT_YES_COPY_MULTI; + + showDragMarker(true); + + if (drop) + { + if (mItems.empty()) + { + setLandingTab(NULL); + mLastTab = NULL; + } + handleNewFavoriteDragAndDrop(item, favorites_id, x, y); + } + } + } + break; + default: + break; + } + + return true; +} + +bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, bool drop, + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) +{ + mDragToOverflowMenu = true; + bool handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + mDragToOverflowMenu = false; + return handled; +} + +void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) +{ + if (LL_UNLIKELY(mItems.empty())) + return; + + LLUUID target_id; + bool insert_before = false; + if (!findDragAndDropTarget(target_id, insert_before, x, y)) + return; + + // There is no need to handle if an item was dragged onto itself + if (target_id == mDragItemId) + return; + + // Move the dragged item to the right place in the array + LLInventoryModel::updateItemsOrder(mItems, mDragItemId, target_id, insert_before); + LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); + + LLView* menu = mOverflowMenuHandle.get(); + if (menu && !menu->isDead() && menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); + } +} + +void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) +{ + // Identify the button hovered and the side to drop + LLUUID target_id; + bool insert_before = false; + // There is no need to handle if an item was dragged onto itself + if (findDragAndDropTarget(target_id, insert_before, x, y) && (target_id == mDragItemId)) + return; + + LLPointer viewer_item = new LLViewerInventoryItem(item); + + // Insert the dragged item to the right place + if (target_id.notNull()) + { + insertItem(mItems, target_id, viewer_item, insert_before); + } + else + { + // This can happen when the item list is empty + mItems.push_back(viewer_item); + } + + int sortField = 0; + LLPointer cb; + + const F64 CALLBACK_WAIT_TIME = 30.f; + sWaitingForCallabck = LLTimer::getTotalSeconds() + CALLBACK_WAIT_TIME; + + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) + { + LLViewerInventoryItem* currItem = *i; + + if (currItem->getUUID() == item->getUUID()) + { + cb = new LLItemCopiedCallback(++sortField); + } + else + { + LLFavoritesOrderStorage::instance().setSortIndex(currItem, ++sortField); + + currItem->setComplete(true); + currItem->updateServer(false); + + gInventory.updateItem(currItem); + } + } + + LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance(); + if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD) + { + viewer_item->setType(LLAssetType::AT_LANDMARK); + copy_inventory_from_notecard(favorites_id, + tool_dad->getObjectID(), + tool_dad->getSourceID(), + viewer_item.get(), + gInventoryCallbacks.registerCB(cb)); + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + cb); + } + + // [MAINT-2386] Ensure the favorite button has been created and is valid. + // This also ensures that mLastTab will be valid when dropping multiple + // landmarks to an empty favorites bar. + updateButtons(); + + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); + } + + LL_INFOS("FavoritesBar") << "Copied inventory item #" << item->getUUID() << " to favorites." << LL_ENDL; +} + +bool LLFavoritesBarCtrl::findDragAndDropTarget(LLUUID& target_id, bool& insert_before, S32 x, S32 y) +{ + if (mItems.empty()) + return false; + + if (mDragToOverflowMenu) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (LL_UNLIKELY(!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible())) + return false; + + // Identify the menu item hovered and the side to drop + LLFavoriteLandmarkMenuItem* target_item = dynamic_cast(overflow_menu->childFromPoint(x, y)); + if (target_item) + { + insert_before = true; + } + else + { + // Choose the bottom landmark menu item + auto begin = overflow_menu->getChildList()->begin(); + auto end = overflow_menu->getChildList()->end(); + auto check = [](const LLView* child) -> bool + { + return dynamic_cast(child); + }; + // Menu items are placed in the backward order, so the bottom goes first + auto it = std::find_if(begin, end, check); + if (LL_UNLIKELY(it == end)) + return false; + target_item = (LLFavoriteLandmarkMenuItem*)*it; + insert_before = false; + } + target_id = target_item->getLandmarkID(); + } + else + { + // Identify the button hovered and the side to drop + LLFavoriteLandmarkButton* hovered_button = dynamic_cast(mLandingTab); + if (hovered_button) + { + insert_before = true; + } + else + { + // Choose the right landmark button + hovered_button = dynamic_cast(mLastTab); + if (LL_UNLIKELY(!hovered_button)) + return false; + + insert_before = false; + } + target_id = hovered_button->getLandmarkID(); + } + + return true; +} + +//virtual +void LLFavoritesBarCtrl::changed(U32 mask) +{ + if (mFavoriteFolderId.isNull()) + { + mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + + if (mFavoriteFolderId.notNull()) + { + gInventory.fetchDescendentsOf(mFavoriteFolderId); + } + } + else + { + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID()); + } + + if (sWaitingForCallabck < LLTimer::getTotalSeconds()) + { + updateButtons(); + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + else + { + mItemsChangedTimer.reset(); + } + } + else + { + mItemsListDirty = true; + } + } +} + +//virtual +void LLFavoritesBarCtrl::reshape(S32 width, S32 height, bool called_from_parent) +{ + S32 delta_width = width - getRect().getWidth(); + S32 delta_height = height - getRect().getHeight(); + + bool force_update = delta_width || delta_height || sForceReshape; + LLUICtrl::reshape(width, height, called_from_parent); + updateButtons(force_update); +} + +void LLFavoritesBarCtrl::draw() +{ + LLUICtrl::draw(); + + if (mShowDragMarker) + { + S32 w = mImageDragIndication->getWidth(); + S32 h = mImageDragIndication->getHeight(); + + if (mLandingTab) + { + // mouse pointer hovers over an existing tab + LLRect rect = mLandingTab->getRect(); + mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h); + } + else if (mLastTab) + { + // mouse pointer hovers over the favbar empty space (right to the last tab) + LLRect rect = mLastTab->getRect(); + mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h); + } + // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) + mShowDragMarker = false; + } + if (mItemsChangedTimer.getStarted()) + { + if (mItemsChangedTimer.getElapsedTimeF32() > 1.f) + { + LLFavoritesOrderStorage::instance().saveFavoritesRecord(); + mItemsChangedTimer.stop(); + } + } + + if(!mItemsChangedTimer.getStarted() && LLFavoritesOrderStorage::instance().mUpdateRequired) + { + LLFavoritesOrderStorage::instance().mUpdateRequired = false; + mItemsChangedTimer.start(); + } + + if (mItemsListDirty && sWaitingForCallabck < LLTimer::getTotalSeconds()) + { + updateButtons(); + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + else + { + mItemsChangedTimer.reset(); + } + } +} + +const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() +{ + static LLButton::Params button_params; + static bool params_initialized = false; + + if (!params_initialized) + { + LLXMLNodePtr button_xml_node; + if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node)) + { + LLXUIParser parser; + parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml"); + } + params_initialized = true; + } + + return button_params; +} + +void LLFavoritesBarCtrl::updateButtons(bool force_update) +{ + if (LLApp::isExiting()) + { + return; + } + + mItemsListDirty = false; + mItems.clear(); + + if (!collectFavoriteItems(mItems)) + { + return; + } + + if(mGetPrevItems && gInventory.isCategoryComplete(mFavoriteFolderId)) + { + for (LLInventoryModel::item_array_t::iterator it = mItems.begin(); it != mItems.end(); it++) + { + LLFavoritesOrderStorage::instance().mFavoriteNames[(*it)->getUUID()]= (*it)->getName(); + } + LLFavoritesOrderStorage::instance().mPrevFavorites = mItems; + mGetPrevItems = false; + + if (LLFavoritesOrderStorage::instance().isStorageUpdateNeeded()) + { + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + } + } + + const LLButton::Params& button_params = getButtonParams(); + + if(mItems.empty()) + { + mBarLabel->setVisible(true); + mLastTab = NULL; + } + else + { + mBarLabel->setVisible(false); + } + const child_list_t* childs = getChildList(); + child_list_const_iter_t child_it = childs->begin(); + int first_changed_item_index = 0; + if (!force_update) + { + //lets find first changed button + while (child_it != childs->end() && first_changed_item_index < mItems.size()) + { + LLFavoriteLandmarkButton* button = dynamic_cast (*child_it); + if (button) + { + const LLViewerInventoryItem *item = mItems[first_changed_item_index].get(); + if (item) + { + // an child's order and mItems should be same + if (button->getLandmarkID() != item->getUUID() // sort order has been changed + || button->getLabelSelected() != item->getName()) // favorite's name has been changed + { + break; + } + } + first_changed_item_index++; + } + child_it++; + } + } + // now first_changed_item_index should contains a number of button that need to change + + if (first_changed_item_index <= mItems.size()) + { + // Rebuild the buttons only + // child_list_t is a linked list, so safe to erase from the middle if we pre-increment the iterator + + while (child_it != childs->end()) + { + //lets remove other landmarks button and rebuild it + child_list_const_iter_t cur_it = child_it++; + LLFavoriteLandmarkButton* button = + dynamic_cast (*cur_it); + if (button) + { + if (mLastTab == button) + { + mLastTab = NULL; + } + removeChild(button); + delete button; + } + } + // we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning + // keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton + if (mMoreTextBox->getParent() == this) + { + removeChild(mMoreTextBox); + } + int last_right_edge = 0; + //calculate new buttons offset + if (getChildList()->size() > 0) + { + //find last visible child to get the rightest button offset + child_list_const_reverse_iter_t last_visible_it = + std::find_if( + childs->rbegin(), childs->rend(), + [](const child_list_t::value_type& child) + { return child->getVisible(); }); + if(last_visible_it != childs->rend()) + { + last_right_edge = (*last_visible_it)->getRect().mRight; + } + } + //last_right_edge is saving coordinates + LLButton* last_new_button = NULL; + int j = first_changed_item_index; + for (; j < mItems.size(); j++) + { + last_new_button = createButton(mItems[j], button_params, last_right_edge); + if (!last_new_button) + { + break; + } + sendChildToBack(last_new_button); + last_right_edge = last_new_button->getRect().mRight; + + mLastTab = last_new_button; + } + if (!mLastTab && mItems.size() > 0) + { + // mMoreTextBox was removed, so LLFavoriteLandmarkButtons + // should be the only ones in the list + mLastTab = dynamic_cast(childs->back()); + } + + mFirstDropDownItem = j; + // Chevron button + if (mFirstDropDownItem < mItems.size()) + { + // if updateButton had been called it means: + // or there are some new favorites, or width had been changed + // so if we need to display chevron button, we must update dropdown items too. + mUpdateDropDownItems = true; + S32 buttonHGap = button_params.rect.left; // default value + // Chevron button should stay right aligned + LLRect rect(mMoreTextBox->getRect()); + rect.translate(getRect().mRight - rect.mRight - buttonHGap, 0); + + addChild(mMoreTextBox); + mMoreTextBox->setRect(rect); + mMoreTextBox->setVisible(true); + } + // Update overflow menu + LLToggleableMenu* overflow_menu = static_cast (mOverflowMenuHandle.get()); + if (overflow_menu && overflow_menu->getVisible() && (overflow_menu->getItemCount() != mDropDownItemsCount)) + { + overflow_menu->setVisible(false); + if (mUpdateDropDownItems) + { + showDropDownMenu(); + } + } + } + else + { + mUpdateDropDownItems = false; + } + +} + +LLButton* LLFavoritesBarCtrl::createButton(const LLPointer item, const LLButton::Params& button_params, S32 x_offset) +{ + S32 def_button_width = button_params.rect.width; + S32 button_x_delta = button_params.rect.left; // default value + S32 curr_x = x_offset; + + /** + * WORKAROUND: + * There are some problem with displaying of fonts in buttons. + * Empty space or ellipsis might be displayed instead of last symbols, even though the width of the button is enough. + * The problem disappears if we pad the button with 20 pixels. + */ + int required_width = mFont->getWidth(item->getName()) + 20; + int width = required_width > def_button_width? def_button_width : required_width; + LLFavoriteLandmarkButton* fav_btn = NULL; + + // do we have a place for next button + double buttonHGap + mMoreTextBox ? + if(curr_x + width + 2*button_x_delta + mMoreTextBox->getRect().getWidth() > getRect().mRight ) + { + return NULL; + } + LLButton::Params fav_btn_params(button_params); + fav_btn = LLUICtrlFactory::create(fav_btn_params); + if (NULL == fav_btn) + { + LL_WARNS("FavoritesBar") << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << LL_ENDL; + return NULL; + } + + addChild(fav_btn); + + LLRect butt_rect (fav_btn->getRect()); + fav_btn->setLandmarkID(item->getUUID()); + butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight()); + + fav_btn->setRect(butt_rect); + // change only left and save bottom + fav_btn->setFont(mFont); + fav_btn->setLabel(item->getName()); + fav_btn->setToolTip(item->getName()); + fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + + fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + + return fav_btn; +} + + +bool LLFavoritesBarCtrl::postBuild() +{ + // make the popup menu available + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!menu) + { + menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); + } + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); + mContextMenuHandle = menu->getHandle(); + + return true; +} + +bool LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) +{ + + if (mFavoriteFolderId.isNull()) + return false; + + + LLInventoryModel::cat_array_t cats; + + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + std::sort(items.begin(), items.end(), LLFavoritesSort()); + + if (needToSaveItemsOrder(items)) + { + S32 sortField = 0; + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLFavoritesOrderStorage::instance().setSortIndex((*i), ++sortField); + } + LLFavoritesOrderStorage::instance().mSaveOnExit = true; + } + + return true; +} + +void LLFavoritesBarCtrl::onMoreTextBoxClicked() +{ + LLUI::getInstance()->getMousePositionScreen(&mMouseX, &mMouseY); + showDropDownMenu(); +} + +void LLFavoritesBarCtrl::showDropDownMenu() +{ + if (mOverflowMenuHandle.isDead()) + { + createOverflowMenu(); + } + + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); + if (menu && menu->toggleVisibility()) + { + if (mUpdateDropDownItems) + { + updateOverflowMenuItems(); + } + else + { + menu->buildDrawLabels(); + } + + menu->updateParent(LLMenuGL::sMenuContainer); + menu->setButtonRect(mMoreTextBox->getRect(), this); + positionAndShowOverflowMenu(); + } +} + +void LLFavoritesBarCtrl::createOverflowMenu() +{ + LLToggleableMenu::Params menu_p; + menu_p.name("favorites menu"); + menu_p.can_tear_off(false); + menu_p.visible(false); + menu_p.scrollable(true); + menu_p.max_scrollable_items = 10; + menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; + + LLFavoriteLandmarkToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + menu->setToolbar(this); + mOverflowMenuHandle = menu->getHandle(); +} + +void LLFavoritesBarCtrl::updateOverflowMenuItems() +{ + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); + menu->empty(); + + U32 widest_item = 0; + + for (S32 i = mFirstDropDownItem; i < mItems.size(); i++) + { + LLViewerInventoryItem* item = mItems.at(i); + const std::string& item_name = item->getName(); + + LLFavoriteLandmarkMenuItem::Params item_params; + item_params.name(item_name); + item_params.label(item_name); + item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + + LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create(item_params); + menu_item->initFavoritesBarPointer(this); + menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->setLandmarkID(item->getUUID()); + + fitLabelWidth(menu_item); + + widest_item = llmax(widest_item, menu_item->getNominalWidth()); + + menu->addChild(menu_item); + } + + menu->buildDrawLabels(); + mDropDownItemsCount = menu->getItemCount(); + addOpenLandmarksMenuItem(menu); + mUpdateDropDownItems = false; +} + +void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item) +{ + U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); + std::string item_name = menu_item->getName(); + + // Check whether item name wider than menu + if (menu_item->getNominalWidth() > max_width) + { + S32 chars_total = item_name.length(); + S32 chars_fitted = 1; + menu_item->setLabel(LLStringExplicit("")); + S32 label_space = max_width - menu_item->getFont()->getWidth("...") - + menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels) + + while (chars_fitted < chars_total + && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) + { + chars_fitted++; + } + chars_fitted--; // Rolling back one char, that doesn't fit + + menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); + } +} + +void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu) +{ + std::string label_untrans = "Open landmarks"; + std::string label_transl; + bool translated = LLTrans::findString(label_transl, label_untrans); + + LLMenuItemCallGL::Params item_params; + item_params.name("open_my_landmarks"); + item_params.label(translated ? label_transl: label_untrans); + LLSD key; + key["type"] = "open_landmark_tab"; + item_params.on_click.function(boost::bind(&LLFloaterSidePanelContainer::showPanel, "places", key)); + LLMenuItemCallGL* menu_item = LLUICtrlFactory::create(item_params); + + fitLabelWidth(menu_item); + + LLMenuItemSeparatorGL::Params sep_params; + sep_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor"); + sep_params.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor"); + sep_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor"); + sep_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor"); + LLMenuItemSeparatorGL* separator = LLUICtrlFactory::create(sep_params); + + menu->addChild(separator); + menu->addChild(menu_item); +} + +void LLFavoritesBarCtrl::positionAndShowOverflowMenu() +{ + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); + U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); + + S32 menu_x = getRect().getWidth() - max_width; + S32 menu_y = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; + + // the menu should be offset of the right edge of the window + // so it's no covered by buttons in the right-side toolbar. + LLToolBar* right_toolbar = gToolBarView->getChild("toolbar_right"); + if (right_toolbar && right_toolbar->hasButtons()) + { + S32 toolbar_top = 0; + + if (LLView* top_border_panel = right_toolbar->getChild("button_panel")) + { + toolbar_top = top_border_panel->calcScreenRect().mTop; + } + + // Calculating the bottom (in screen coord) of the drop down menu + S32 menu_top = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; + S32 menu_bottom = menu_top - menu->getRect().getHeight(); + S32 menu_bottom_screen = 0; + + localPointToScreen(0, menu_bottom, &menu_top, &menu_bottom_screen); + + if (menu_bottom_screen < toolbar_top) + { + menu_x -= right_toolbar->getRect().getWidth(); + } + } + + LLMenuGL::showPopup(this, menu, menu_x, menu_y, mMouseX, mMouseY); +} + +void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) +{ + // We only have one Inventory, gInventory. Some day this should be better abstracted. + LLInvFVBridgeAction::doAction(item_id,&gInventory); +} + +void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask) +{ + mSelectedItemID = item_id; + + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); + if (!menu) + { + return; + } + + // Remember that the context menu was shown simultaneously with the overflow menu, + // so that we can restore the overflow menu when user clicks a context menu item + // (which hides the overflow menu). + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible(); + } + + // Release mouse capture so hover events go to the popup menu + // because this is happening during a mouse down. + gFocusMgr.setMouseCapture(NULL); + + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(fav_button, menu, x, y); +} + +bool LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + bool handled = childrenHandleRightMouseDown( x, y, mask) != NULL; + if(!handled && !gMenuHolder->hasVisibleMenu()) + { + show_navbar_context_menu(this,x,y); + handled = true; + } + + return handled; +} +void copy_slurl_to_clipboard_cb(std::string& slurl) +{ + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); + + LLSD args; + args["SLURL"] = slurl; + LLNotificationsUtil::add("CopySLURL", args); +} + + +bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) +{ + std::string param = userdata.asString(); + + if (param == std::string("can_paste")) + { + return isClipboardPasteable(); + } + else if (param == "create_pick") + { + return !LLAgentPicksInfo::getInstance()->isPickLimitReached(); + } + + return false; +} + +void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) +{ + std::string action = userdata.asString(); + LL_INFOS("FavoritesBar") << "Action = " << action << " Item = " << mSelectedItemID.asString() << LL_ENDL; + + LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID); + if (!item) + return; + + if (action == "open") + { + onButtonClick(item->getUUID()); + } + else if (action == "about") + { + LLSD key; + key["type"] = "landmark"; + key["id"] = mSelectedItemID; + + LLFloaterSidePanelContainer::showPanel("places", key); + } + else if (action == "copy_slurl") + { + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero()) + { + LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb); + } + } + else if (action == "show_on_map") + { + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(posGlobal); + LLFloaterReg::showInstance("world_map", "center"); + } + } + else if (action == "create_pick") + { + LLSD args; + args["type"] = "create_pick"; + args["item_id"] = item->getUUID(); + LLFloaterSidePanelContainer::showPanel("places", args); + } + else if (action == "cut") + { + } + else if (action == "copy") + { + LLClipboard::instance().copyToClipboard(mSelectedItemID, LLAssetType::AT_LANDMARK); + } + else if (action == "paste") + { + pasteFromClipboard(); + } + else if (action == "delete") + { + gInventory.removeItem(mSelectedItemID); + } + else if (action == "rename") + { + LLSD args; + args["NAME"] = item->getName(); + + LLSD payload; + payload["id"] = mSelectedItemID; + + LLNotificationsUtil::add("RenameLandmark", args, payload, boost::bind(onRenameCommit, _1, _2)); + } + else if (action == "move_to_landmarks") + { + change_item_parent(mSelectedItemID, gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); + } + + // Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item). + // See EXT-4217 and STORM-207. + LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get(); + if (mRestoreOverflowMenu && menu && !menu->getVisible()) + { + menu->resetScrollPositionOnShow(false); + showDropDownMenu(); + menu->resetScrollPositionOnShow(true); + } +} + +bool LLFavoritesBarCtrl::onRenameCommit(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLUUID id = notification["payload"]["id"].asUUID(); + LLInventoryItem *item = gInventory.getItem(id); + std::string landmark_name = response["new_name"].asString(); + LLStringUtil::trim(landmark_name); + + if (!landmark_name.empty() && item && item->getName() != landmark_name) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->rename(landmark_name); + new_item->updateServer(false); + gInventory.updateItem(new_item); + } + } + + return false; +} + +bool LLFavoritesBarCtrl::isClipboardPasteable() const +{ + if (!LLClipboard::instance().hasContents()) + { + return false; + } + + std::vector objects; + LLClipboard::instance().pasteFromClipboard(objects); + S32 count = objects.size(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.at(i); + + // Can't paste folders + const LLInventoryCategory *cat = gInventory.getCategory(item_id); + if (cat) + { + return false; + } + + const LLInventoryItem *item = gInventory.getItem(item_id); + if (item && LLAssetType::AT_LANDMARK != item->getType()) + { + return false; + } + } + return true; +} + +void LLFavoritesBarCtrl::pasteFromClipboard() const +{ + LLInventoryModel* model = &gInventory; + if(model && isClipboardPasteable()) + { + LLInventoryItem* item = NULL; + std::vector objects; + LLClipboard::instance().pasteFromClipboard(objects); + S32 count = objects.size(); + LLUUID parent_id(mFavoriteFolderId); + for(S32 i = 0; i < count; i++) + { + item = model->getItem(objects.at(i)); + if (item) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer(NULL)); + } + } + } +} + +void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away) + // mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu. + // We have to check and set visibility of pop-up menu in such a way instead of using + // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but + // we need to close only pop-up menu while dropdown one should be still opened. + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); + if(menu && menu->getVisible()) + { + menu->setVisible(false); + } + + mDragItemId = id; + mStartDrag = true; + + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY); +} + +void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mStartDrag = false; + mDragItemId = LLUUID::null; +} + +void LLFavoritesBarCtrl::onEndDrag() +{ + mEndDragConnection.disconnect(); + + showDragMarker(false); + mDragItemId = LLUUID::null; + LLView::getWindow()->setCursor(UI_CURSOR_ARROW); +} + +bool LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) +{ + if (mDragItemId != LLUUID::null && mStartDrag) + { + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY)) + { + LLToolDragAndDrop::getInstance()->beginDrag( + DAD_LANDMARK, mDragItemId, + LLToolDragAndDrop::SOURCE_LIBRARY); + + mStartDrag = false; + + return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); + } + } + + return true; +} + +LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) +{ + LLUICtrl* ctrl = NULL; + const child_list_t* list = getChildList(); + + for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i) + { + // Look only for children that are favorite buttons + if ((*i)->getName() == "favorites_bar_btn") + { + LLRect rect = (*i)->getRect(); + // We consider a button hit if the cursor is left of the right side + // This makes the hit a bit less finicky than hitting directly on the button itself + if (x <= rect.mRight) + { + ctrl = dynamic_cast(*i); + break; + } + } + } + + return ctrl; +} + +bool LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) +{ + bool result = false; + + // if there is an item without sort order field set, we need to save items order + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + if (LLFavoritesOrderStorage::instance().getSortIndex((*i)->getUUID()) < 0) + { + result = true; + break; + } + } + + return result; +} + +void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before) +{ + // Get the iterator to the destination item + LLInventoryModel::item_array_t::iterator it_dest = LLInventoryModel::findItemIterByUUID(items, dest_item_id); + if (it_dest == items.end()) + return; + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Insert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, insertedItem); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(insertedItem); + } +} + +const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; +const S32 LLFavoritesOrderStorage::NO_INDEX = -1; +bool LLFavoritesOrderStorage::mSaveOnExit = false; + +void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index) +{ + mSortIndexes[inv_item->getUUID()] = sort_index; + mIsDirty = true; + getSLURL(inv_item->getAssetUUID()); +} + +S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) +{ + sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); + if (it != mSortIndexes.end()) + { + return it->second; + } + return NO_INDEX; +} + +void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) +{ + mSortIndexes.erase(inv_item_id); + mIsDirty = true; +} + +void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) +{ + slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id); + if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached + + LLLandmark* lm = gLandmarkList.getAsset(asset_id, + boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1)); + if (lm) + { + LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL; + onLandmarkLoaded(asset_id, lm); + } + return; +} + +// static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) +{ + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + + return (user_dir.empty() ? "" + : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + "stored_favorites_" + + grid + + ".xml") + ); +} + +// static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); +} + +// static +void LLFavoritesOrderStorage::destroyClass() +{ + LLFavoritesOrderStorage::instance().cleanup(); + + + std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + llifstream file; + file.open(old_filename.c_str()); + if (file.is_open()) + { + file.close(); + std::string new_filename = getStoredFavoritesFilename(); + LL_INFOS("FavoritesBar") << "moving favorites from old name '" << old_filename + << "' to new name '" << new_filename << "'" + << LL_ENDL; + LLFile::copy(old_filename,new_filename); + LLFile::remove(old_filename); + } + + std::string filename = getSavedOrderFileName(); + file.open(filename.c_str()); + if (file.is_open()) + { + file.close(); + LLFile::remove(filename); + } + if(mSaveOnExit || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) + { + LLFavoritesOrderStorage::instance().saveFavoritesRecord(true); + } +} + +std::string LLFavoritesOrderStorage::getSavedOrderFileName() +{ + // If we quit from the login screen we will not have an SL account + // name. Don't try to save, otherwise we'll dump a file in + // C:\Program Files\SecondLife\ or similar. JC + std::string user_dir = gDirUtilp->getLindenUserDir(); + return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME)); +} + +void LLFavoritesOrderStorage::load() +{ + std::string filename = getSavedOrderFileName(); + LLSD settings_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(settings_llsd, file); + LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " + << (settings_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + file.close(); + mSaveOnExit = true; + + for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); + iter != settings_llsd.endMap(); ++iter) + { + mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); + } + } + else + { + filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + LLSD fav_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " + << (fav_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + in_file.close(); + if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) + { + mStorageFavorites = fav_llsd[gAgentUsername]; + + S32 index = 0; + bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); + for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); + iter != mStorageFavorites.endArray(); ++iter) + { + // Validation + LLUUID fv_id = iter->get("id").asUUID(); + if (needs_validation + && (fv_id.isNull() + || iter->get("asset_id").asUUID().isNull() + || iter->get("name").asString().empty() + || iter->get("slurl").asString().empty())) + { + mRecreateFavoriteStorage = true; + } + + mSortIndexes.insert(std::make_pair(fv_id, index)); + index++; + } + } + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; + } + } + } +} + +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) +{ + std::string filename = getStoredFavoritesFilename(grid); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(user)) + { + LLSD user_llsd = fav_llsd[user]; + + if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"] = iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[user] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; + fav_llsd.erase(user); + } + } + + llofstream out_file; + out_file.open(filename.c_str()); + if (out_file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() +{ + std::string filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(av_name.getUserName())) + { + LLSD user_llsd = fav_llsd[av_name.getUserName()]; + + if ((user_llsd.beginArray()!= user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray();iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"]= iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[av_name.getUserName()] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; + fav_llsd.erase(av_name.getUserName()); + } + } + + llofstream out_file; + out_file.open(filename.c_str()); + if ( out_file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark) +{ + if (landmark) + { + LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL; + LLVector3d pos_global; + if (!landmark->getGlobalPos(pos_global)) + { + // If global position was unknown on first getGlobalPos() call + // it should be set for the subsequent calls. + landmark->getGlobalPos(pos_global); + } + + if (!pos_global.isExactlyZero()) + { + LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; + LLLandmarkActions::getSLURLfromPosGlobal(pos_global, + boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); + } + } +} + +void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl) +{ + LL_DEBUGS("FavoritesBar") << "Saving landmark SLURL '" << slurl << "' for " << asset_id << LL_ENDL; + mSLURLs[asset_id] = slurl; +} + +void LLFavoritesOrderStorage::cleanup() +{ + // nothing to clean + if (!mIsDirty) return; + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + IsNotInFavorites is_not_in_fav(items); + + sort_index_map_t aTempMap; + //copy unremoved values from mSortIndexes to aTempMap + std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), + inserter(aTempMap, aTempMap.begin()), + is_not_in_fav); + + //Swap the contents of mSortIndexes and aTempMap + mSortIndexes.swap(aTempMap); +} + +// See also LLInventorySort where landmarks in the Favorites folder are sorted. +class LLViewerInventoryItemSort +{ +public: + bool operator()(const LLPointer& a, const LLPointer& b) + { + return LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()) + < LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); + } +}; + +void LLFavoritesOrderStorage::saveOrder() +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_type(LLAssetType::AT_LANDMARK); + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); + saveItemsOrder(items); +} + +void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items ) +{ + + int sortField = 0; + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + setSortIndex(item, ++sortField); + + item->setComplete(true); + item->updateServer(false); + + gInventory.updateItem(item); + + // Tell the parent folder to refresh its sort order. + gInventory.addChangedMask(LLInventoryObserver::SORT, item->getParentUUID()); + } + + gInventory.notifyObservers(); +} + + +// * @param source_item_id - LLUUID of the source item to be moved into new position +// * @param target_item_id - LLUUID of the target item before which source item should be placed. +void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_type(LLAssetType::AT_LANDMARK); + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + // ensure items are sorted properly before changing order. EXT-3498 + std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); + + // update order + gInventory.updateItemsOrder(items, source_item_id, target_item_id); + + saveItemsOrder(items); +} + +bool LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) +{ + pref_changed |= mRecreateFavoriteStorage; + mRecreateFavoriteStorage = false; + + // Can get called before inventory is done initializing. + if (!gInventory.isInventoryUsable()) + { + return false; + } + + LLUUID favorite_folder= gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if (favorite_folder.isNull()) + { + return false; + } + + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(favorite_folder, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + std::sort(items.begin(), items.end(), LLFavoritesSort()); + bool name_changed = false; + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) + { + if(mFavoriteNames[(*it)->getUUID()] != ((*it)->getName())) + { + mFavoriteNames[(*it)->getUUID()] = (*it)->getName(); + name_changed = true; + } + } + + for (std::set::iterator it = mMissingSLURLs.begin(); it != mMissingSLURLs.end(); it++) + { + slurls_map_t::iterator slurl_iter = mSLURLs.find(*it); + if (slurl_iter != mSLURLs.end()) + { + pref_changed = true; + break; + } + } + + if((items != mPrevFavorites) || name_changed || pref_changed || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) + { + std::string filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + LLSD fav_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + in_file.close(); + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; + } + + LLSD user_llsd; + S32 fav_iter = 0; + mMissingSLURLs.clear(); + + LLSD save_pass; + save_pass["save_password"] = gSavedSettings.getBOOL("RememberPassword"); + user_llsd[fav_iter] = save_pass; + fav_iter++; + + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) + { + LLSD value; + if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) + { + value["name"] = (*it)->getName(); + value["asset_id"] = (*it)->getAssetUUID(); + value["id"] = (*it)->getUUID(); + slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); + if (slurl_iter != mSLURLs.end()) + { + value["slurl"] = slurl_iter->second; + user_llsd[fav_iter] = value; + } + else + { + getSLURL((*it)->getAssetUUID()); + value["slurl"] = ""; + user_llsd[fav_iter] = value; + mUpdateRequired = true; + mMissingSLURLs.insert((*it)->getAssetUUID()); + } + } + else + { + value["id"] = (*it)->getUUID(); + user_llsd[fav_iter] = value; + } + + fav_iter ++; + } + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + // Note : use the "John Doe" and not the "john.doe" version of the name + // as we'll compare it with the stored credentials in the login panel. + fav_llsd[av_name.getUserName()] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + mSaveOnExit = false; + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() + << "' at '" << filename << "' " << LL_ENDL; + } + } + mPrevFavorites = items; + } + + return true; + +} + +void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(bool show) +{ + if (show) + { + saveFavoritesRecord(true); + } + else + { + removeFavoritesRecordOfUser(); + } +} + +bool LLFavoritesOrderStorage::isStorageUpdateNeeded() +{ + if (!mRecreateFavoriteStorage) + { + for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); + iter != mStorageFavorites.endArray(); ++iter) + { + if (mFavoriteNames[iter->get("id").asUUID()] != iter->get("name").asString()) + { + mRecreateFavoriteStorage = true; + return true; + } + } + } + return false; +} + +void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) +{ + if (!mTargetLandmarkId.isNull()) + { + LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); + } +} + +// EOF -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/newview/llfavoritesbar.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/newview/llfavoritesbar.cpp') diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 906d04691f..377710c170 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1250,7 +1250,7 @@ void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item) // Check whether item name wider than menu if (menu_item->getNominalWidth() > max_width) { - S32 chars_total = item_name.length(); + S32 chars_total = static_cast(item_name.length()); S32 chars_fitted = 1; menu_item->setLabel(LLStringExplicit("")); S32 label_space = max_width - menu_item->getFont()->getWidth("...") - @@ -1375,7 +1375,7 @@ bool LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) } void copy_slurl_to_clipboard_cb(std::string& slurl) { - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl),0,slurl.size()); + LLClipboard::instance().copyToClipboard(utf8str_to_wstring(slurl), 0, static_cast(slurl.size())); LLSD args; args["SLURL"] = slurl; @@ -1522,8 +1522,8 @@ bool LLFavoritesBarCtrl::isClipboardPasteable() const std::vector objects; LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); - for(S32 i = 0; i < count; i++) + auto count = objects.size(); + for(size_t i = 0; i < count; i++) { const LLUUID &item_id = objects.at(i); @@ -1551,9 +1551,9 @@ void LLFavoritesBarCtrl::pasteFromClipboard() const LLInventoryItem* item = NULL; std::vector objects; LLClipboard::instance().pasteFromClipboard(objects); - S32 count = objects.size(); + auto count = objects.size(); LLUUID parent_id(mFavoriteFolderId); - for(S32 i = 0; i < count; i++) + for(size_t i = 0; i < count; i++) { item = model->getItem(objects.at(i)); if (item) -- cgit v1.2.3