PageRenderTime 167ms CodeModel.GetById 2ms app.highlight 146ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llfavoritesbar.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1393 lines | 1045 code | 200 blank | 148 comment | 182 complexity | 1607c7cf2302cd8c5029ec2ec2f63d50 MD5 | raw file
   1/** 
   2 * @file llfavoritesbar.cpp
   3 * @brief LLFavoritesBarCtrl class implementation
   4 *
   5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28#include "llfavoritesbar.h"
  29
  30#include "llfloaterreg.h"
  31#include "llfocusmgr.h"
  32#include "llinventory.h"
  33#include "lllandmarkactions.h"
  34#include "lltoolbarview.h"
  35#include "lltrans.h"
  36#include "lluictrlfactory.h"
  37#include "llmenugl.h"
  38#include "lltooltip.h"
  39
  40#include "llagent.h"
  41#include "llclipboard.h"
  42#include "llinventoryclipboard.h"
  43#include "llinventorybridge.h"
  44#include "llinventoryfunctions.h"
  45#include "llfloatersidepanelcontainer.h"
  46#include "llfloaterworldmap.h"
  47#include "lllandmarkactions.h"
  48#include "llnotificationsutil.h"
  49#include "lltoggleablemenu.h"
  50#include "llviewerinventory.h"
  51#include "llviewermenu.h"
  52#include "llviewermenu.h"
  53#include "lltooldraganddrop.h"
  54
  55static LLDefaultChildRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar");
  56
  57const S32 DROP_DOWN_MENU_WIDTH = 250;
  58const S32 DROP_DOWN_MENU_TOP_PAD = 13;
  59
  60/**
  61 * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem.
  62 * Performing requests for SLURL for given Landmark ID
  63 */
  64class LLLandmarkInfoGetter
  65{
  66public:
  67	LLLandmarkInfoGetter()
  68	:	mLandmarkID(LLUUID::null),
  69		mName("(Loading...)"),
  70		mPosX(0),
  71		mPosY(0),
  72		mPosZ(0),
  73		mLoaded(false) 
  74	{
  75		mHandle.bind(this);
  76	}
  77
  78	void setLandmarkID(const LLUUID& id) { mLandmarkID = id; }
  79	const LLUUID& getLandmarkId() const { return mLandmarkID; }
  80
  81	const std::string& getName()
  82	{
  83		if(!mLoaded)
  84			requestNameAndPos();
  85
  86		return mName;
  87	}
  88
  89	S32 getPosX()
  90	{
  91		if (!mLoaded)
  92			requestNameAndPos();
  93		return mPosX;
  94	}
  95
  96	S32 getPosY()
  97	{
  98		if (!mLoaded)
  99			requestNameAndPos();
 100		return mPosY;
 101	}
 102
 103	S32 getPosZ()
 104	{
 105		if (!mLoaded)
 106			requestNameAndPos();
 107		return mPosZ;
 108	}
 109
 110private:
 111	/**
 112	 * Requests landmark data from server.
 113	 */
 114	void requestNameAndPos()
 115	{
 116		if (mLandmarkID.isNull())
 117			return;
 118
 119		LLVector3d g_pos;
 120		if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos))
 121		{
 122			LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos,
 123				boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, static_cast<LLHandle<LLLandmarkInfoGetter> >(mHandle), _1, _2, _3, _4));
 124		}
 125	}
 126
 127	static void landmarkNameCallback(LLHandle<LLLandmarkInfoGetter> handle, const std::string& name, S32 x, S32 y, S32 z)
 128	{
 129		LLLandmarkInfoGetter* getter = handle.get();
 130		if (getter)
 131		{
 132			getter->mPosX = x;
 133			getter->mPosY = y;
 134			getter->mPosZ = z;
 135			getter->mName = name;
 136			getter->mLoaded = true;
 137		}
 138	}
 139
 140	LLUUID mLandmarkID;
 141	std::string mName;
 142	S32 mPosX;
 143	S32 mPosY;
 144	S32 mPosZ;
 145	bool mLoaded;
 146	LLRootHandle<LLLandmarkInfoGetter> mHandle;
 147};
 148
 149/**
 150 * This class is needed to override LLButton default handleToolTip function and
 151 * show SLURL as button tooltip.
 152 * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
 153 * in createButtons function but landmark data is not available when Favorites Bar is
 154 * created. Thats why we are requesting landmark data after 
 155 */
 156class LLFavoriteLandmarkButton : public LLButton
 157{
 158public:
 159
 160	BOOL handleToolTip(S32 x, S32 y, MASK mask)
 161	{
 162		std::string region_name = mLandmarkInfoGetter.getName();
 163		
 164		if (!region_name.empty())
 165		{
 166			std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), 
 167				mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ());
 168
 169			LLToolTip::Params params;
 170			params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str());
 171			params.max_width = 1000;			
 172			params.sticky_rect = calcScreenRect(); 
 173
 174			LLToolTipMgr::instance().show(params);
 175		}
 176		return TRUE;
 177	}
 178
 179	/*virtual*/ BOOL	handleHover(S32 x, S32 y, MASK mask)
 180	{
 181		LLFavoritesBarCtrl* fb = dynamic_cast<LLFavoritesBarCtrl*>(getParent());
 182
 183		if (fb)
 184		{
 185			fb->handleHover(x, y, mask);
 186		}
 187
 188		return LLButton::handleHover(x, y, mask);
 189	}
 190	
 191	void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
 192	const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); }
 193
 194	void onMouseEnter(S32 x, S32 y, MASK mask)
 195	{
 196		if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
 197		{
 198			LLUICtrl::onMouseEnter(x, y, mask);
 199		}
 200		else
 201		{
 202			LLButton::onMouseEnter(x, y, mask);
 203		}
 204	}
 205
 206protected:
 207	LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {}
 208	friend class LLUICtrlFactory;
 209
 210private:
 211	LLLandmarkInfoGetter mLandmarkInfoGetter;
 212};
 213
 214/**
 215 * This class is needed to override LLMenuItemCallGL default handleToolTip function and
 216 * show SLURL as button tooltip.
 217 * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons
 218 * in showDropDownMenu function but landmark data is not available when Favorites Bar is
 219 * created. Thats why we are requesting landmark data after 
 220 */
 221class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL
 222{
 223public:
 224	BOOL handleToolTip(S32 x, S32 y, MASK mask)
 225	{
 226		std::string region_name = mLandmarkInfoGetter.getName();
 227		if (!region_name.empty())
 228		{
 229			LLToolTip::Params params;
 230			params.message = llformat("%s\n%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY());
 231			params.sticky_rect = calcScreenRect();
 232			LLToolTipMgr::instance().show(params);
 233		}
 234		return TRUE;
 235	}
 236	
 237	void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); }
 238
 239	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask)
 240	{
 241		if (mMouseDownSignal)
 242			(*mMouseDownSignal)(this, x, y, mask);
 243		return LLMenuItemCallGL::handleMouseDown(x, y, mask);
 244	}
 245
 246	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
 247	{
 248		if (mMouseUpSignal)
 249			(*mMouseUpSignal)(this, x, y, mask);
 250		return LLMenuItemCallGL::handleMouseUp(x, y, mask);
 251	}
 252
 253	virtual BOOL handleHover(S32 x, S32 y, MASK mask)
 254	{
 255		if (fb)
 256		{
 257			fb->handleHover(x, y, mask);
 258		}
 259
 260		return TRUE;
 261	}
 262
 263	void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; }
 264
 265protected:
 266
 267	LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {}
 268	friend class LLUICtrlFactory;
 269
 270private:
 271	LLLandmarkInfoGetter mLandmarkInfoGetter;
 272	LLFavoritesBarCtrl* fb;
 273};
 274
 275/**
 276 * This class was introduced just for fixing the following issue:
 277 * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through.
 278 * We must explicitly handle drag and drop event by returning TRUE
 279 * because otherwise LLToolDragAndDrop will initiate drag and drop operation
 280 * with the world.
 281 */
 282class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu
 283{
 284public:
 285	virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 286								   EDragAndDropType cargo_type,
 287								   void* cargo_data,
 288								   EAcceptance* accept,
 289								   std::string& tooltip_msg)
 290	{
 291		*accept = ACCEPT_NO;
 292		return TRUE;
 293	}
 294
 295protected:
 296	LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p):
 297		LLToggleableMenu(p)
 298	{
 299	}
 300
 301	friend class LLUICtrlFactory;
 302};
 303
 304/**
 305 * This class is needed to update an item being copied to the favorites folder
 306 * with a sort field value (required to save favorites bar's tabs order).
 307 * See method handleNewFavoriteDragAndDrop for more details on how this class is used.
 308 */
 309class LLItemCopiedCallback : public LLInventoryCallback
 310{
 311public:
 312	LLItemCopiedCallback(S32 sortField): mSortField(sortField) {}
 313
 314	virtual void fire(const LLUUID& inv_item)
 315	{
 316		LLViewerInventoryItem* item = gInventory.getItem(inv_item);
 317
 318		if (item)
 319		{
 320			item->setSortField(mSortField);
 321			item->setComplete(TRUE);
 322			item->updateServer(FALSE);
 323
 324			gInventory.updateItem(item);
 325			gInventory.notifyObservers();
 326		}
 327
 328		LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
 329	}
 330
 331private:
 332	S32 mSortField;
 333};
 334
 335// updateButtons's helper
 336struct LLFavoritesSort
 337{
 338	// Sorting by creation date and name
 339	// TODO - made it customizible using gSavedSettings
 340	bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b)
 341	{
 342		S32 sortField1 = a->getSortField();
 343		S32 sortField2 = b->getSortField();
 344
 345		if (!(sortField1 < 0 && sortField2 < 0))
 346		{
 347			return sortField2 > sortField1;
 348		}
 349
 350		time_t first_create = a->getCreationDate();
 351		time_t second_create = b->getCreationDate();
 352		if (first_create == second_create)
 353		{
 354			return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0);
 355		}
 356		else
 357		{
 358			return (first_create > second_create);
 359		}
 360	}
 361};
 362
 363LLFavoritesBarCtrl::Params::Params()
 364: image_drag_indication("image_drag_indication"),
 365  more_button("more_button"),
 366  label("label")
 367{
 368}
 369
 370LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
 371:	LLUICtrl(p),
 372	mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
 373	mOverflowMenuHandle(),
 374	mContextMenuHandle(),
 375	mImageDragIndication(p.image_drag_indication),
 376	mShowDragMarker(FALSE),
 377	mLandingTab(NULL),
 378	mLastTab(NULL),
 379	mTabsHighlightEnabled(TRUE)
 380  , mUpdateDropDownItems(true)
 381,	mRestoreOverflowMenu(false)
 382{
 383	// Register callback for menus with current registrar (will be parent panel's registrar)
 384	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
 385		boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2));
 386
 387	// Add this if we need to selectively enable items
 388	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected",
 389		boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2));
 390	
 391	gInventory.addObserver(this);
 392
 393	//make chevron button                                                                                                                               
 394	LLTextBox::Params more_button_params(p.more_button);
 395	mMoreTextBox = LLUICtrlFactory::create<LLTextBox> (more_button_params);
 396	mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this));
 397	addChild(mMoreTextBox);
 398
 399	LLTextBox::Params label_param(p.label);
 400	mBarLabel = LLUICtrlFactory::create<LLTextBox> (label_param);
 401	addChild(mBarLabel);
 402}
 403
 404LLFavoritesBarCtrl::~LLFavoritesBarCtrl()
 405{
 406	gInventory.removeObserver(this);
 407
 408	if (mOverflowMenuHandle.get()) mOverflowMenuHandle.get()->die();
 409	if (mContextMenuHandle.get()) mContextMenuHandle.get()->die();
 410}
 411
 412BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 413								   EDragAndDropType cargo_type,
 414								   void* cargo_data,
 415								   EAcceptance* accept,
 416								   std::string& tooltip_msg)
 417{
 418	*accept = ACCEPT_NO;
 419
 420	LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource();
 421	if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return FALSE;
 422
 423	switch (cargo_type)
 424	{
 425
 426	case DAD_LANDMARK:
 427		{
 428			/*
 429			 * add a callback to the end drag event.
 430			 * the callback will disconnet itself immediately after execution
 431			 * this is done because LLToolDragAndDrop is a common tool so it shouldn't
 432			 * be overloaded with redundant callbacks.
 433			 */
 434			if (!mEndDragConnection.connected())
 435			{
 436				mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this));
 437			}
 438
 439			// Copy the item into the favorites folder (if it's not already there).
 440			LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 441
 442			if (LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(findChildByLocalCoords(x, y)))
 443			{
 444				setLandingTab(dest);
 445			}
 446			else if (mLastTab && (x >= mLastTab->getRect().mRight))
 447			{
 448				/*
 449				 * the condition dest == NULL can be satisfied not only in the case
 450				 * of dragging to the right from the last tab of the favbar. there is a
 451				 * small gap between each tab. if the user drags something exactly there
 452				 * then mLandingTab will be set to NULL and the dragged item will be pushed
 453				 * to the end of the favorites bar. this is incorrect behavior. that's why
 454				 * we need an additional check which excludes the case described previously
 455				 * making sure that the mouse pointer is beyond the last tab.
 456				 */
 457				setLandingTab(NULL);
 458			}
 459
 460			// check if we are dragging an existing item from the favorites bar
 461			if (item && mDragItemId == item->getUUID())
 462			{
 463				*accept = ACCEPT_YES_SINGLE;
 464
 465				showDragMarker(TRUE);
 466
 467				if (drop)
 468				{
 469					handleExistingFavoriteDragAndDrop(x, y);
 470				}
 471			}
 472			else
 473			{
 474				const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
 475				if (item->getParentUUID() == favorites_id)
 476				{
 477					llwarns << "Attemt to copy a favorite item into the same folder." << llendl;
 478					break;
 479				}
 480
 481				*accept = ACCEPT_YES_COPY_MULTI;
 482
 483				showDragMarker(TRUE);
 484
 485				if (drop)
 486				{
 487					if (mItems.empty())
 488					{
 489						setLandingTab(NULL);
 490					}
 491					handleNewFavoriteDragAndDrop(item, favorites_id, x, y);
 492				}
 493			}
 494		}
 495		break;
 496	default:
 497		break;
 498	}
 499
 500	return TRUE;
 501}
 502
 503void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
 504{
 505	// Identify the button hovered and the side to drop
 506	LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
 507	bool insert_before = true;	
 508	if (!dest)
 509	{
 510		insert_before = false;
 511		dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
 512	}
 513
 514	// There is no need to handle if an item was dragged onto itself
 515	if (dest && dest->getLandmarkId() == mDragItemId)
 516	{
 517		return;
 518	}
 519
 520	// Insert the dragged item in the right place
 521	if (dest)
 522	{
 523		LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before);
 524	}
 525	else
 526	{
 527		// This can happen when the item list is empty
 528		mItems.push_back(gInventory.getItem(mDragItemId));
 529	}
 530
 531	gInventory.saveItemsOrder(mItems);
 532
 533	LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
 534
 535	if (menu && menu->getVisible())
 536	{
 537		menu->setVisible(FALSE);
 538		showDropDownMenu();
 539	}
 540}
 541
 542void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y)
 543{
 544	// Identify the button hovered and the side to drop
 545	LLFavoriteLandmarkButton* dest = NULL;
 546	bool insert_before = true;
 547	if (!mItems.empty())
 548	{
 549		dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
 550		if (!dest)
 551		{
 552			insert_before = false;
 553			dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
 554		}
 555	}
 556	
 557	// There is no need to handle if an item was dragged onto itself
 558	if (dest && dest->getLandmarkId() == mDragItemId)
 559	{
 560		return;
 561	}
 562	
 563	LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item);
 564
 565	// Insert the dragged item in the right place
 566	if (dest)
 567	{
 568		insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before);
 569	}
 570	else
 571	{
 572		// This can happen when the item list is empty
 573		mItems.push_back(viewer_item);
 574	}
 575
 576	int sortField = 0;
 577	LLPointer<LLItemCopiedCallback> cb;
 578
 579	// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
 580	for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i)
 581	{
 582		LLViewerInventoryItem* currItem = *i;
 583
 584		if (currItem->getUUID() == item->getUUID())
 585		{
 586			cb = new LLItemCopiedCallback(++sortField);
 587		}
 588		else
 589		{
 590			currItem->setSortField(++sortField);
 591			currItem->setComplete(TRUE);
 592			currItem->updateServer(FALSE);
 593
 594			gInventory.updateItem(currItem);
 595		}
 596	}
 597
 598	LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance();
 599	if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD)
 600	{
 601		viewer_item->setType(LLAssetType::AT_LANDMARK);
 602		copy_inventory_from_notecard(favorites_id,
 603									 tool_dad->getObjectID(),
 604									 tool_dad->getSourceID(),
 605									 viewer_item.get(),
 606									 gInventoryCallbacks.registerCB(cb));
 607	}
 608	else
 609	{
 610		copy_inventory_item(
 611				gAgent.getID(),
 612				item->getPermissions().getOwner(),
 613				item->getUUID(),
 614				favorites_id,
 615				std::string(),
 616				cb);
 617	}
 618
 619	llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;
 620}
 621
 622//virtual
 623void LLFavoritesBarCtrl::changed(U32 mask)
 624{
 625	if (mFavoriteFolderId.isNull())
 626	{
 627		mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
 628		
 629		if (mFavoriteFolderId.notNull())
 630		{
 631			gInventory.fetchDescendentsOf(mFavoriteFolderId);
 632		}
 633	}	
 634	else
 635	{
 636		LLInventoryModel::item_array_t items;
 637		LLInventoryModel::cat_array_t cats;
 638		LLIsType is_type(LLAssetType::AT_LANDMARK);
 639		gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
 640		
 641		for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
 642		{
 643			(*i)->getSLURL();
 644		}
 645		updateButtons();
 646	}
 647}
 648
 649//virtual
 650void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
 651{
 652	LLUICtrl::reshape(width, height, called_from_parent);
 653	updateButtons();
 654}
 655
 656void LLFavoritesBarCtrl::draw()
 657{
 658	LLUICtrl::draw();
 659
 660	if (mShowDragMarker)
 661	{
 662		S32 w = mImageDragIndication->getWidth();
 663		S32 h = mImageDragIndication->getHeight();
 664
 665		if (mLandingTab)
 666		{
 667			// mouse pointer hovers over an existing tab
 668			LLRect rect = mLandingTab->getRect();
 669			mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h);
 670		}
 671		else if (mLastTab)
 672		{
 673			// mouse pointer hovers over the favbar empty space (right to the last tab)
 674			LLRect rect = mLastTab->getRect();
 675			mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h);
 676		}
 677		// Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again)
 678		mShowDragMarker = FALSE;
 679	}
 680}
 681
 682const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
 683{
 684	static LLButton::Params button_params;
 685	static bool params_initialized = false;
 686
 687	if (!params_initialized)
 688	{
 689		LLXMLNodePtr button_xml_node;
 690		if(LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", button_xml_node))
 691		{
 692			LLXUIParser parser;
 693			parser.readXUI(button_xml_node, button_params, "favorites_bar_button.xml");
 694		}
 695		params_initialized = true;
 696	}
 697
 698	return button_params;
 699}
 700
 701void LLFavoritesBarCtrl::updateButtons()
 702{
 703	mItems.clear();
 704
 705	if (!collectFavoriteItems(mItems))
 706	{
 707		return;
 708	}
 709
 710	const LLButton::Params& button_params = getButtonParams();
 711
 712	if(mItems.empty())
 713	{
 714		mBarLabel->setVisible(TRUE);
 715	}
 716	else
 717	{
 718		mBarLabel->setVisible(FALSE);
 719	}
 720	const child_list_t* childs = getChildList();
 721	child_list_const_iter_t child_it = childs->begin();
 722	int first_changed_item_index = 0;
 723	int rightest_point = getRect().mRight - mMoreTextBox->getRect().getWidth();
 724	//lets find first changed button
 725	while (child_it != childs->end() && first_changed_item_index < mItems.count())
 726	{
 727		LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it);
 728		if (button)
 729		{
 730			const LLViewerInventoryItem *item = mItems[first_changed_item_index].get();
 731			if (item)
 732			{
 733				// an child's order  and mItems  should be same   
 734				if (button->getLandmarkId() != item->getUUID() // sort order has been changed
 735					|| button->getLabelSelected() != item->getName() // favorite's name has been changed
 736					|| button->getRect().mRight < rightest_point) // favbar's width has been changed
 737				{
 738					break;
 739				}
 740			}
 741			first_changed_item_index++;
 742		}
 743		child_it++;
 744	}
 745	// now first_changed_item_index should contains a number of button that need to change
 746
 747	if (first_changed_item_index <= mItems.count())
 748	{
 749		// Rebuild the buttons only
 750		// child_list_t is a linked list, so safe to erase from the middle if we pre-increment the iterator
 751
 752		while (child_it != childs->end())
 753		{
 754			//lets remove other landmarks button and rebuild it
 755			child_list_const_iter_t cur_it = child_it++;
 756			LLFavoriteLandmarkButton* button =
 757					dynamic_cast<LLFavoriteLandmarkButton*> (*cur_it);
 758			if (button)
 759			{
 760				removeChild(button);
 761				delete button;
 762			}
 763		}
 764		// we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning
 765		// keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton
 766		if (mMoreTextBox->getParent() == this)
 767		{
 768			removeChild(mMoreTextBox);
 769		}
 770		int last_right_edge = 0;
 771		//calculate new buttons offset
 772		if (getChildList()->size() > 0)
 773		{
 774			//find last visible child to get the rightest button offset
 775			child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(), 
 776					std::mem_fun(&LLView::getVisible));
 777			if(last_visible_it != childs->rend())
 778			{
 779				last_right_edge = (*last_visible_it)->getRect().mRight;
 780			}
 781		}
 782		//last_right_edge is saving coordinates
 783		LLButton* last_new_button = NULL;
 784		int j = first_changed_item_index;
 785		for (; j < mItems.count(); j++)
 786		{
 787			last_new_button = createButton(mItems[j], button_params, last_right_edge);
 788			if (!last_new_button)
 789			{
 790				break;
 791			}
 792			sendChildToBack(last_new_button);
 793			last_right_edge = last_new_button->getRect().mRight;
 794
 795			mLastTab = last_new_button;
 796		}
 797		mFirstDropDownItem = j;
 798		// Chevron button
 799		if (mFirstDropDownItem < mItems.count())
 800		{
 801			// if updateButton had been called it means:
 802			//or there are some new favorites, or width had been changed
 803			// so if we need to display chevron button,  we must update dropdown items too. 
 804			mUpdateDropDownItems = true;
 805			S32 buttonHGap = button_params.rect.left; // default value
 806			LLRect rect;
 807			// Chevron button should stay right aligned
 808			rect.setOriginAndSize(getRect().mRight - mMoreTextBox->getRect().getWidth() - buttonHGap, 0,
 809					mMoreTextBox->getRect().getWidth(),
 810					mMoreTextBox->getRect().getHeight());
 811
 812			addChild(mMoreTextBox);
 813			mMoreTextBox->setRect(rect);
 814			mMoreTextBox->setVisible(TRUE);
 815		}
 816		// Update overflow menu
 817		LLToggleableMenu* overflow_menu = static_cast <LLToggleableMenu*> (mOverflowMenuHandle.get());
 818		if (overflow_menu && overflow_menu->getVisible())
 819		{
 820			overflow_menu->setVisible(FALSE);
 821			if (mUpdateDropDownItems)
 822				showDropDownMenu();
 823		}
 824	}
 825	else
 826	{
 827		mUpdateDropDownItems = false;
 828	}
 829}
 830
 831LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, const LLButton::Params& button_params, S32 x_offset)
 832{
 833	S32 def_button_width = button_params.rect.width;
 834	S32 button_x_delta = button_params.rect.left; // default value
 835	S32 curr_x = x_offset;
 836
 837	/**
 838	 * WORKAROUND:
 839	 * There are some problem with displaying of fonts in buttons. 
 840	 * Empty space or ellipsis might be displayed instead of last symbols, even though the width of the button is enough.
 841	 * The problem disappears if we pad the button with 20 pixels.
 842	 */
 843	int required_width = mFont->getWidth(item->getName()) + 20;
 844	int width = required_width > def_button_width? def_button_width : required_width;
 845	LLFavoriteLandmarkButton* fav_btn = NULL;
 846
 847	// do we have a place for next button + double buttonHGap + mMoreTextBox ?
 848	if(curr_x + width + 2*button_x_delta +  mMoreTextBox->getRect().getWidth() > getRect().mRight )
 849	{
 850		return NULL;
 851	}
 852	LLButton::Params fav_btn_params(button_params);
 853	fav_btn = LLUICtrlFactory::create<LLFavoriteLandmarkButton>(fav_btn_params);
 854	if (NULL == fav_btn)
 855	{
 856		llwarns << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << llendl;
 857		return NULL;
 858	}
 859	
 860	addChild(fav_btn);
 861
 862	LLRect butt_rect (fav_btn->getRect());
 863	fav_btn->setLandmarkID(item->getUUID());
 864	butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight());
 865	
 866	fav_btn->setRect(butt_rect);
 867	// change only left and save bottom
 868	fav_btn->setFont(mFont);
 869	fav_btn->setLabel(item->getName());
 870	fav_btn->setToolTip(item->getName());
 871	fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
 872	fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 ));
 873
 874	fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
 875	fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
 876
 877	return fav_btn;
 878}
 879
 880
 881BOOL LLFavoritesBarCtrl::postBuild()
 882{
 883	// make the popup menu available
 884	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 885	if (!menu)
 886	{
 887		menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
 888	}
 889	menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
 890	mContextMenuHandle = menu->getHandle();
 891
 892	return TRUE;
 893}
 894
 895BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
 896{
 897	if (mFavoriteFolderId.isNull())
 898		return FALSE;
 899	
 900	LLInventoryModel::cat_array_t cats;
 901
 902	LLIsType is_type(LLAssetType::AT_LANDMARK);
 903	gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
 904
 905	std::sort(items.begin(), items.end(), LLFavoritesSort());
 906
 907	if (needToSaveItemsOrder(items))
 908	{
 909		S32 sortField = 0;
 910		for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
 911		{
 912			(*i)->setSortField(++sortField);
 913		}
 914	}
 915
 916	return TRUE;
 917}
 918
 919void LLFavoritesBarCtrl::showDropDownMenu()
 920{
 921	if (mOverflowMenuHandle.isDead())
 922	{
 923		createOverflowMenu();
 924	}
 925
 926	LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get();
 927	if (menu && menu->toggleVisibility())
 928	{
 929		if (mUpdateDropDownItems)
 930		{
 931			updateMenuItems(menu);
 932		}
 933
 934		menu->buildDrawLabels();
 935		menu->updateParent(LLMenuGL::sMenuContainer);
 936		menu->setButtonRect(mMoreTextBox->getRect(), this);
 937		positionAndShowMenu(menu);
 938	}
 939}
 940
 941void LLFavoritesBarCtrl::createOverflowMenu()
 942{
 943	LLToggleableMenu::Params menu_p;
 944	menu_p.name("favorites menu");
 945	menu_p.can_tear_off(false);
 946	menu_p.visible(false);
 947	menu_p.scrollable(true);
 948	menu_p.max_scrollable_items = 10;
 949	menu_p.preferred_width = DROP_DOWN_MENU_WIDTH;
 950
 951	LLToggleableMenu* menu = LLUICtrlFactory::create<LLFavoriteLandmarkToggleableMenu>(menu_p);
 952	mOverflowMenuHandle = menu->getHandle();
 953}
 954
 955void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu)
 956{
 957	menu->empty();
 958
 959	U32 widest_item = 0;
 960
 961	for (S32 i = mFirstDropDownItem; i < mItems.count(); i++)
 962	{
 963		LLViewerInventoryItem* item = mItems.get(i);
 964		const std::string& item_name = item->getName();
 965
 966		LLFavoriteLandmarkMenuItem::Params item_params;
 967		item_params.name(item_name);
 968		item_params.label(item_name);
 969		item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
 970
 971		LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params);
 972		menu_item->initFavoritesBarPointer(this);
 973		menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4));
 974		menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4));
 975		menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4));
 976		menu_item->setLandmarkID(item->getUUID());
 977
 978		fitLabelWidth(menu_item);
 979
 980		widest_item = llmax(widest_item, menu_item->getNominalWidth());
 981
 982		menu->addChild(menu_item);
 983	}
 984
 985	addOpenLandmarksMenuItem(menu);
 986	mUpdateDropDownItems = false;
 987}
 988
 989void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item)
 990{
 991	U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth());
 992	std::string item_name = menu_item->getName();
 993
 994	// Check whether item name wider than menu
 995	if (menu_item->getNominalWidth() > max_width)
 996	{
 997		S32 chars_total = item_name.length();
 998		S32 chars_fitted = 1;
 999		menu_item->setLabel(LLStringExplicit(""));
1000		S32 label_space = max_width - menu_item->getFont()->getWidth("...") -
1001				menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels)
1002
1003		while (chars_fitted < chars_total
1004				&& menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space)
1005		{
1006			chars_fitted++;
1007		}
1008		chars_fitted--; // Rolling back one char, that doesn't fit
1009
1010		menu_item->setLabel(item_name.substr(0, chars_fitted) + "...");
1011	}
1012}
1013
1014void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu)
1015{
1016	std::string label_untrans = "Open landmarks";
1017	std::string	label_transl;
1018	bool translated = LLTrans::findString(label_transl, label_untrans);
1019
1020	LLMenuItemCallGL::Params item_params;
1021	item_params.name("open_my_landmarks");
1022	item_params.label(translated ? label_transl: label_untrans);
1023	LLSD key;
1024	key["type"] = "open_landmark_tab";
1025	item_params.on_click.function(boost::bind(&LLFloaterSidePanelContainer::showPanel, "places", key));
1026	LLMenuItemCallGL* menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
1027
1028	fitLabelWidth(menu_item);
1029
1030	LLMenuItemSeparatorGL::Params sep_params;
1031	sep_params.enabled_color=LLUIColorTable::instance().getColor("MenuItemEnabledColor");
1032	sep_params.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
1033	sep_params.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
1034	sep_params.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
1035	LLMenuItemSeparatorGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(sep_params);
1036
1037	menu->addChild(separator);
1038	menu->addChild(menu_item);
1039}
1040
1041void LLFavoritesBarCtrl::positionAndShowMenu(LLToggleableMenu* menu)
1042{
1043	U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth());
1044
1045	S32 menu_x = getRect().getWidth() - max_width;
1046	S32 menu_y = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD;
1047
1048	// the menu should be offset of the right edge of the window
1049	// so it's no covered by buttons in the right-side toolbar.
1050	LLToolBar* right_toolbar = gToolBarView->getChild<LLToolBar>("toolbar_right");
1051	if (right_toolbar && right_toolbar->hasButtons())
1052	{
1053		S32 toolbar_top = 0;
1054
1055		if (LLView* top_border_panel = right_toolbar->getChild<LLView>("button_panel"))
1056		{
1057			toolbar_top = top_border_panel->calcScreenRect().mTop;
1058		}
1059
1060		// Calculating the bottom (in screen coord) of the drop down menu
1061		S32 menu_top = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD;
1062		S32 menu_bottom = menu_top - menu->getRect().getHeight();
1063		S32 menu_bottom_screen = 0;
1064
1065		localPointToScreen(0, menu_bottom, &menu_top, &menu_bottom_screen);
1066
1067		if (menu_bottom_screen < toolbar_top)
1068		{
1069			menu_x -= right_toolbar->getRect().getWidth();
1070		}
1071	}
1072
1073	LLMenuGL::showPopup(this, menu, menu_x, menu_y);
1074}
1075
1076void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id)
1077{
1078	// We only have one Inventory, gInventory. Some day this should be better abstracted.
1079	LLInvFVBridgeAction::doAction(item_id,&gInventory);
1080}
1081
1082void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask)
1083{
1084	mSelectedItemID = item_id;
1085	
1086	LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
1087	if (!menu)
1088	{
1089		return;
1090	}
1091
1092	// Remember that the context menu was shown simultaneously with the overflow menu,
1093	// so that we can restore the overflow menu when user clicks a context menu item
1094	// (which hides the overflow menu).
1095	{
1096		LLView* overflow_menu = mOverflowMenuHandle.get();
1097		mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible();
1098	}
1099	
1100	// Release mouse capture so hover events go to the popup menu
1101	// because this is happening during a mouse down.
1102	gFocusMgr.setMouseCapture(NULL);
1103
1104	menu->updateParent(LLMenuGL::sMenuContainer);
1105	LLMenuGL::showPopup(fav_button, menu, x, y);
1106}
1107
1108BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
1109{
1110	BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL;
1111	if(!handled && !gMenuHolder->hasVisibleMenu())
1112	{
1113		show_navbar_context_menu(this,x,y);
1114		handled = true;
1115	}
1116	
1117	return handled;
1118}
1119void copy_slurl_to_clipboard_cb(std::string& slurl)
1120{
1121	gClipboard.copyFromString(utf8str_to_wstring(slurl));
1122
1123	LLSD args;
1124	args["SLURL"] = slurl;
1125	LLNotificationsUtil::add("CopySLURL", args);
1126}
1127
1128
1129bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata)
1130{
1131    std::string param = userdata.asString();
1132
1133    if (param == std::string("can_paste"))
1134    {
1135        return isClipboardPasteable();
1136    }
1137
1138    return false;
1139}
1140
1141void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
1142{
1143	std::string action = userdata.asString();
1144	llinfos << "Action = " << action << " Item = " << mSelectedItemID.asString() << llendl;
1145	
1146	LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID);
1147	if (!item)
1148		return;
1149	
1150	if (action == "open")
1151	{
1152		onButtonClick(item->getUUID());
1153	}
1154	else if (action == "about")
1155	{
1156		LLSD key;
1157		key["type"] = "landmark";
1158		key["id"] = mSelectedItemID;
1159
1160		LLFloaterSidePanelContainer::showPanel("places", key);
1161	}
1162	else if (action == "copy_slurl")
1163	{
1164		LLVector3d posGlobal;
1165		LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
1166
1167		if (!posGlobal.isExactlyZero())
1168		{
1169			LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb);
1170		}
1171	}
1172	else if (action == "show_on_map")
1173	{
1174		LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
1175
1176		LLVector3d posGlobal;
1177		LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal);
1178
1179		if (!posGlobal.isExactlyZero() && worldmap_instance)
1180		{
1181			worldmap_instance->trackLocation(posGlobal);
1182			LLFloaterReg::showInstance("world_map", "center");
1183		}
1184	}
1185	else if (action == "cut")
1186	{
1187	}
1188	else if (action == "copy")
1189	{
1190		LLInventoryClipboard::instance().store(mSelectedItemID);
1191	}
1192	else if (action == "paste")
1193	{
1194		pastFromClipboard();
1195	}
1196	else if (action == "delete")
1197	{
1198		gInventory.removeItem(mSelectedItemID);
1199	}
1200
1201	// Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item).
1202	// See EXT-4217 and STORM-207.
1203	LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get();
1204	if (mRestoreOverflowMenu && menu && !menu->getVisible())
1205	{
1206		menu->resetScrollPositionOnShow(false);
1207		showDropDownMenu();
1208		menu->resetScrollPositionOnShow(true);
1209	}
1210}
1211
1212BOOL LLFavoritesBarCtrl::isClipboardPasteable() const
1213{
1214	if (!LLInventoryClipboard::instance().hasContents())
1215	{
1216		return FALSE;
1217	}
1218
1219	LLDynamicArray<LLUUID> objects;
1220	LLInventoryClipboard::instance().retrieve(objects);
1221	S32 count = objects.count();
1222	for(S32 i = 0; i < count; i++)
1223	{
1224		const LLUUID &item_id = objects.get(i);
1225
1226		// Can't paste folders
1227		const LLInventoryCategory *cat = gInventory.getCategory(item_id);
1228		if (cat)
1229		{
1230			return FALSE;
1231		}
1232
1233		const LLInventoryItem *item = gInventory.getItem(item_id);
1234		if (item && LLAssetType::AT_LANDMARK != item->getType())
1235		{
1236			return FALSE;
1237		}
1238	}
1239	return TRUE;
1240}
1241
1242void LLFavoritesBarCtrl::pastFromClipboard() const
1243{
1244	LLInventoryModel* model = &gInventory;
1245	if(model && isClipboardPasteable())
1246	{
1247		LLInventoryItem* item = NULL;
1248		LLDynamicArray<LLUUID> objects;
1249		LLInventoryClipboard::instance().retrieve(objects);
1250		S32 count = objects.count();
1251		LLUUID parent_id(mFavoriteFolderId);
1252		for(S32 i = 0; i < count; i++)
1253		{
1254			item = model->getItem(objects.get(i));
1255			if (item)
1256			{
1257				copy_inventory_item(
1258					gAgent.getID(),
1259					item->getPermissions().getOwner(),
1260					item->getUUID(),
1261					parent_id,
1262					std::string(),
1263					LLPointer<LLInventoryCallback>(NULL));
1264			}
1265		}
1266	}
1267}
1268
1269void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
1270{
1271	// EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away)
1272	// mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu.
1273	// We have to check and set visibility of pop-up menu in such a way instead of using
1274	// LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but
1275	// we need to close only pop-up menu while dropdown one should be still opened.
1276	LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get();
1277	if(menu && menu->getVisible())
1278	{
1279		menu->setVisible(FALSE);
1280	}
1281
1282	mDragItemId = id;
1283	mStartDrag = TRUE;
1284
1285	S32 screenX, screenY;
1286	localPointToScreen(x, y, &screenX, &screenY);
1287
1288	LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY);
1289}
1290
1291void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
1292{
1293	mStartDrag = FALSE;
1294	mDragItemId = LLUUID::null;
1295}
1296
1297void LLFavoritesBarCtrl::onEndDrag()
1298{
1299	mEndDragConnection.disconnect();
1300
1301	showDragMarker(FALSE);
1302	mDragItemId = LLUUID::null;
1303	LLView::getWindow()->setCursor(UI_CURSOR_ARROW);
1304}
1305
1306BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask)
1307{
1308	if (mDragItemId != LLUUID::null && mStartDrag)
1309	{
1310		S32 screenX, screenY;
1311		localPointToScreen(x, y, &screenX, &screenY);
1312
1313		if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY))
1314		{
1315			LLToolDragAndDrop::getInstance()->beginDrag(
1316				DAD_LANDMARK, mDragItemId,
1317				LLToolDragAndDrop::SOURCE_LIBRARY);
1318
1319			mStartDrag = FALSE;
1320
1321			return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask);
1322		}
1323	}
1324
1325	return TRUE;
1326}
1327
1328LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y)
1329{
1330	LLUICtrl* ctrl = NULL;
1331	const child_list_t* list = getChildList();
1332
1333	for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
1334	{
1335		// Look only for children that are favorite buttons
1336		if ((*i)->getName() == "favorites_bar_btn")
1337		{
1338			LLRect rect = (*i)->getRect();
1339			// We consider a button hit if the cursor is left of the right side
1340			// This makes the hit a bit less finicky than hitting directly on the button itself
1341			if (x <= rect.mRight)
1342			{
1343				ctrl = dynamic_cast<LLUICtrl*>(*i);
1344				break;
1345			}
1346		}
1347	}
1348	return ctrl;
1349}
1350
1351BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items)
1352{
1353	BOOL result = FALSE;
1354
1355	// if there is an item without sort order field set, we need to save items order
1356	for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
1357	{
1358		if ((*i)->getSortField() < 0)
1359		{
1360			result = TRUE;
1361			break;
1362		}
1363	}
1364
1365	return result;
1366}
1367
1368void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before)
1369{
1370	// Get the iterator to the destination item
1371	LLInventoryModel::item_array_t::iterator it_dest = LLInventoryModel::findItemIterByUUID(items, dest_item_id);
1372	if (it_dest == items.end())
1373		return;
1374
1375	// Go to the next element if one wishes to insert after the dest element
1376	if (!insert_before)
1377	{
1378		++it_dest;
1379	}
1380	
1381	// Insert the source item in the right place
1382	if (it_dest != items.end())
1383	{
1384		items.insert(it_dest, insertedItem);
1385	}
1386	else 
1387	{
1388		// Append to the list if it_dest reached the end
1389		items.push_back(insertedItem);
1390	}
1391}
1392
1393// EOF