Commits

Anonymous committed d0bab89 Merge
  • Participants
  • Parent commits 8b455c1, d7285c7

Comments (0)

Files changed (41)

File indra/llmath/lloctree.h

 
 		if (lt != 0x7)
 		{
-			OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+			//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
 			return false;
 		}
 

File indra/llui/lldockablefloater.cpp

 	setDocked(isDocked());
 }
 
-const LLUIImagePtr& LLDockableFloater::getDockTongue()
+const LLUIImagePtr& LLDockableFloater::getDockTongue(LLDockControl::DocAt dock_side)
 {
+	switch(dock_side)
+	{
+	case LLDockControl::LEFT:
+		mDockTongue = LLUI::getUIImage("windows/Flyout_Left.png");
+		break;
+	case LLDockControl::RIGHT:
+		mDockTongue = LLUI::getUIImage("windows/Flyout_Right.png");
+		break;
+	default:
+		mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png");
+		break;
+	}
+
 	return mDockTongue;
 }
 

File indra/llui/lldockablefloater.h

 
 	bool getUniqueDocking() { return mUniqueDocking;	}
 	bool getUseTongue() { return mUseTongue; }
+
+	void setUseTongue(bool use_tongue) { mUseTongue = use_tongue;}
 private:
 	/**
 	 * Provides unique of dockable floater.
 
 protected:
 	void setDockControl(LLDockControl* dockControl);
-	const LLUIImagePtr& getDockTongue();
+	const LLUIImagePtr& getDockTongue(LLDockControl::DocAt dock_side = LLDockControl::TOP);
 
 	// Checks if docking should be forced.
 	// It may be useful e.g. if floater created in mouselook mode (see EXT-5609)

File indra/llui/lldockcontrol.cpp

 	switch (mDockAt)
 	{
 	case LEFT:
-		x = dockRect.mLeft;
-		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
-		// check is dockable inside root view rect
-		if (x < rootRect.mLeft)
+
+		x = dockRect.mLeft - dockableRect.getWidth();
+		y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
+		
+		if (use_tongue)
 		{
-			x = rootRect.mLeft;
+			x -= mDockTongue->getWidth();
 		}
-		if (x + dockableRect.getWidth() > rootRect.mRight)
+
+		mDockTongueX = dockableRect.mRight;
+		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
+		
+		break;
+
+	case RIGHT:
+
+		x = dockRect.mRight;
+		y = dockRect.getCenterY() + dockableRect.getHeight() / 2;
+
+		if (use_tongue)
 		{
-			x = rootRect.mRight - dockableRect.getWidth();
+			x += mDockTongue->getWidth();
 		}
-		
-		mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2;
-		
-		mDockTongueY = dockRect.mTop;
+
+		mDockTongueX = dockRect.mRight;
+		mDockTongueY = dockableRect.getCenterY() - mDockTongue->getHeight() / 2;
+
 		break;
 
 	case TOP:
 		dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
 				dockableRect.getHeight());
 	}
+
 	LLRect localDocableParentRect;
-	mDockableFloater->getParent()->screenRectToLocal(dockableRect,
-			&localDocableParentRect);
+
+	mDockableFloater->getParent()->screenRectToLocal(dockableRect, &localDocableParentRect);
 	mDockableFloater->setRect(localDocableParentRect);
-
-	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY,
-			&mDockTongueX, &mDockTongueY);
+	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, &mDockTongueX, &mDockTongueY);
 
 }
 

File indra/llui/lldockcontrol.h

 	{
 		TOP,
 		LEFT,
+		RIGHT,
 		BOTTOM
 	};
 

File indra/llui/llfloater.cpp

 
 	case LLFloaterEnums::OPEN_POSITIONING_CASCADE_GROUP:
 	case LLFloaterEnums::OPEN_POSITIONING_CASCADING:
-		if (other != NULL)
+		if (other != NULL && other != this)
 		{
 			stackWith(*other);
 		}
 	const LLRect old_rect = getRect();
 	LLView::handleReshape(new_rect, by_user);
 
-	if (by_user)
+	if (by_user && !isMinimized())
 	{
 		storeRectControl();
 		mOpenPositioning = LLFloaterEnums::OPEN_POSITIONING_NONE;

File indra/llui/lltoolbar.cpp

 	mStartDragItemCallback(NULL),
 	mHandleDragItemCallback(NULL),
 	mHandleDropCallback(NULL),
+	mButtonAddSignal(NULL),
+	mButtonEnterSignal(NULL),
+	mButtonLeaveSignal(NULL),
+	mButtonRemoveSignal(NULL),
 	mDragAndDropTarget(false)
 {
 	mButtonParams[LLToolBarEnums::BTNTYPE_ICONS_WITH_TEXT] = p.button_icon_and_text;
 LLToolBar::~LLToolBar()
 {
 	delete mPopupMenuHandle.get();
+	delete mButtonAddSignal;
+	delete mButtonEnterSignal;
+	delete mButtonLeaveSignal;
+	delete mButtonRemoveSignal;
 }
 
 void LLToolBar::createContextMenu()
 	mButtonPanel->addChild(button);
 	mButtonMap.insert(std::make_pair(commandId.uuid(), button));
 
-
 	// Insert the command and button in the right place in their respective lists
 	if ((rank >= mButtonCommands.size()) || (rank == RANK_NONE))
 	{
 
 	mNeedsLayout = true;
 
+	updateLayoutAsNeeded();
+
+
+	if (mButtonAddSignal)
+	{
+		(*mButtonAddSignal)(button);
+	}
+
 	return true;
 }
 
 		++rank;
 	}
 	
+	if (mButtonRemoveSignal)
+	{
+		(*mButtonRemoveSignal)(*it_button);
+	}
+	
 	// Delete the button and erase the command and button records
 	delete (*it_button);
 	mButtonCommands.erase(it_command);
 	return (command_button != NULL);
 }
 
+bool LLToolBar::flashCommand(const LLCommandId& commandId, bool flash)
+{
+	LLButton * command_button = NULL;
+
+	if (commandId != LLCommandId::null)
+	{
+		command_id_map::iterator it = mButtonMap.find(commandId.uuid());
+		if (it != mButtonMap.end())
+		{
+			command_button = it->second;
+			command_button->setFlashing(flash ? TRUE : FALSE);
+		}
+	}
+
+	return (command_button != NULL);
+}
+
 BOOL LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	LLRect button_panel_rect;
 {
 	BOOST_FOREACH(LLToolBarButton* button, mButtons)
 	{
+		if (mButtonRemoveSignal)
+		{
+			(*mButtonRemoveSignal)(button);
+		}
+		
 		delete button;
 	}
 	mButtons.clear();
 		mButtons.push_back(button);
 		mButtonPanel->addChild(button);
 		mButtonMap.insert(std::make_pair(command_id.uuid(), button));
+		
+		if (mButtonAddSignal)
+		{
+			(*mButtonAddSignal)(button);
+		}
 	}
 	mNeedsLayout = true;
 }
 			button->setCommitCallback(executeParam);
 		}
 
-
-
+		// Set up "is running" query callback
 		const std::string& isRunningFunction = commandp->isRunningFunctionName();
 		if (isRunningFunction.length() > 0)
 		{
 	return button;
 }
 
+boost::signals2::connection connectSignal(LLToolBar::button_signal_t*& signal, const LLToolBar::button_signal_t::slot_type& cb)
+{
+	if (!signal)
+	{
+		signal = new LLToolBar::button_signal_t();
+	}
+
+	return signal->connect(cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonAddCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonAddSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonEnterCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonEnterSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonLeaveCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonLeaveSignal, cb);
+}
+
+boost::signals2::connection LLToolBar::setButtonRemoveCallback(const button_signal_t::slot_type& cb)
+{
+	return connectSignal(mButtonRemoveSignal, cb);
+}
+
 BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 										EDragAndDropType cargo_type,
 										void* cargo_data,
 	mOriginalImageOverlayColor(p.image_overlay_color),
 	mOriginalImageOverlaySelectedColor(p.image_overlay_selected_color)
 {
-	mButtonFlashRate = 0.0;
-	mButtonFlashCount = 0;
 }
 
 LLToolBarButton::~LLToolBarButton()
 	{
 		handled = LLButton::handleHover(x, y, mask);
 	}
+
 	return handled;
 }
 
 	{
 		mNeedsHighlight = TRUE;
 	}
+
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonEnterSignal)
+	{
+		(*(parent_toolbar->mButtonEnterSignal))(this);
+	}
+}
+
+void LLToolBarButton::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+	LLButton::onMouseLeave(x, y, mask);
+	
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonLeaveSignal)
+	{
+		(*(parent_toolbar->mButtonLeaveSignal))(this);
+	}	
 }
 
 void LLToolBarButton::onMouseCaptureLost()
 	}
 }
 
-
 const std::string LLToolBarButton::getToolTip() const	
 { 
 	std::string tooltip;
+
 	if (labelIsTruncated() || getCurrentLabel().empty())
 	{
-		return LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip();
+		tooltip = LLTrans::getString(LLCommandManager::instance().getCommand(mId)->labelRef()) + " -- " + LLView::getToolTip();
 	}
 	else
 	{
-		return LLView::getToolTip();
+		tooltip = LLView::getToolTip();
 	}
+
+	LLToolBar* parent_toolbar = getParentByType<LLToolBar>();
+	if (parent_toolbar && parent_toolbar->mButtonTooltipSuffix.length() > 0)
+	{
+		tooltip = tooltip + "\n(" + parent_toolbar->mButtonTooltipSuffix + ")";
+	}
+
+	return tooltip;
 }
 
-
-
-
-
-
-
-
-

File indra/llui/lltoolbar.h

 	void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; }
 
 	void onMouseEnter(S32 x, S32 y, MASK mask);
+	void onMouseLeave(S32 x, S32 y, MASK mask);
 	void onMouseCaptureLost();
 
 	void onCommit();
 		SIDE_RIGHT,
 		SIDE_TOP,
 	};
+
+	LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType);
 }
 
 // NOTE: This needs to occur before Param block declaration for proper compilation.
 class LLToolBar
 :	public LLUICtrl
 {
+	friend class LLToolBarButton;
 public:
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
 	bool hasCommand(const LLCommandId& commandId) const;
 	bool enableCommand(const LLCommandId& commandId, bool enabled);
 	bool stopCommandInProgress(const LLCommandId& commandId);
+	bool flashCommand(const LLCommandId& commandId, bool flash);
 
 	void setStartDragCallback(tool_startdrag_callback_t cb)   { mStartDragItemCallback  = cb; }
 	void setHandleDragCallback(tool_handledrag_callback_t cb) { mHandleDragItemCallback = cb; }
 
 	LLToolBarButton* createButton(const LLCommandId& id);
 
+	typedef boost::signals2::signal<void (LLView* button)> button_signal_t;
+	boost::signals2::connection setButtonAddCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonEnterCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonLeaveCallback(const button_signal_t::slot_type& cb);
+	boost::signals2::connection setButtonRemoveCallback(const button_signal_t::slot_type& cb);
+
+	void setTooltipButtonSuffix(const std::string& suffix) { mButtonTooltipSuffix = suffix; }
+
+	LLToolBarEnums::SideType getSideType() const { return mSideType; }
 	bool hasButtons() const { return !mButtons.empty(); }
 	bool isModified() const { return mModified; }
 
 
 	LLToolBarButton::Params			mButtonParams[LLToolBarEnums::BTNTYPE_COUNT];
 
-	LLHandle<class LLContextMenu>			mPopupMenuHandle;
+	LLHandle<class LLContextMenu>	mPopupMenuHandle;
+
+	button_signal_t*				mButtonAddSignal;
+	button_signal_t*				mButtonEnterSignal;
+	button_signal_t*				mButtonLeaveSignal;
+	button_signal_t*				mButtonRemoveSignal;
+
+	std::string						mButtonTooltipSuffix;
 };
 
 

File indra/newview/app_settings/settings.xml

       <key>Comment</key>
       <string>Settings that are a applied per session (not saved).</string>
       <key>Persist</key>
-      <integer>1</integer>
+      <integer>0</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
       <key>Comment</key>
       <string>User settings that are a applied per session (not saved).</string>
       <key>Persist</key>
-      <integer>1</integer>
+      <integer>0</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>

File indra/newview/app_settings/settings_per_account.xml

         <key>Value</key>
             <string />
         </map>
+    <key>DisplayDestinationsOnInitialRun</key>
+        <map>
+        <key>Comment</key>
+          <string>Display the destinations guide when a user first launches FUI.</string>
+        <key>Persist</key>
+          <integer>1</integer>
+        <key>Type</key>
+          <string>Boolean</string>
+        <key>Value</key>
+          <integer>1</integer>
+        </map>
     <key>LastInventoryInboxActivity</key>
         <map>
         <key>Comment</key>

File indra/newview/llfavoritesbar.cpp

 			{
 				setLandingTab(dest);
 			}
-			/*
-			 * 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.
-			 */
-			else if (mLastTab && x >= mLastTab->getRect().mRight)
+			else 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);
 			}
 
 				if (drop)
 				{
 					handleExistingFavoriteDragAndDrop(x, y);
-					showDragMarker(FALSE);
 				}
 			}
 			else
 						setLandingTab(NULL);
 					}
 					handleNewFavoriteDragAndDrop(item, favorites_id, x, y);
-					showDragMarker(FALSE);
 				}
 			}
 		}
 
 void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y)
 {
+	// Identify the button hovered and the side to drop
 	LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
+	bool insert_before = true;	
+	if (!dest)
+	{
+		insert_before = false;
+		dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
+	}
 
-	// there is no need to handle if an item was dragged onto itself
+	// 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());
+		LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before);
 	}
 	else
 	{
+		// This can happen when the item list is empty
 		mItems.push_back(gInventory.getItem(mDragItemId));
 	}
 
 
 void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y)
 {
-	LLFavoriteLandmarkButton* dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
-
-	// there is no need to handle if an item was dragged onto itself
+	// Identify the button hovered and the side to drop
+	LLFavoriteLandmarkButton* dest = NULL;
+	bool insert_before = true;
+	if (!mItems.empty())
+	{
+		dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLandingTab);
+		if (!dest)
+		{
+			insert_before = false;
+			dest = dynamic_cast<LLFavoriteLandmarkButton*>(mLastTab);
+		}
+	}
+	
+	// There is no need to handle if an item was dragged onto itself
 	if (dest && dest->getLandmarkId() == mDragItemId)
 	{
 		return;
 	}
-
+	
 	LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item);
 
+	// Insert the dragged item in the right place
 	if (dest)
 	{
-		insertBeforeItem(mItems, dest->getLandmarkId(), viewer_item);
+		insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before);
 	}
 	else
 	{
+		// This can happen when the item list is empty
 		mItems.push_back(viewer_item);
 	}
 
 		{
 			// mouse pointer hovers over an existing tab
 			LLRect rect = mLandingTab->getRect();
-			mImageDragIndication->draw(rect.mLeft - w/2, rect.getHeight(), w, h);
+			mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h);
 		}
 		else if (mLastTab)
 		{
 			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 (first_changed_item_index <= mItems.count())
 	{
 		// Rebuild the buttons only
-		// child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator
+		// 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())
 		{
 
 	/**
 	 * WORKAROUND:
-	 * there are some problem with displaying of fonts in buttons. 
-	 * Empty space (or ...) is displaying instead of last symbols, even though the width of the button is enough.
-	 * Problem will gone, if we  stretch out the button. For that reason I have to put additional  20 pixels.
+	 * 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;
 	fav_btn->setRect(butt_rect);
 	// change only left and save bottom
 	fav_btn->setFont(mFont);
-	fav_btn->setName(item->getName());
 	fav_btn->setLabel(item->getName());
 	fav_btn->setToolTip(item->getName());
 	fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
 
 LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y)
 {
-	LLUICtrl* ctrl = 0;
-	S32 screenX, screenY;
+	LLUICtrl* ctrl = NULL;
 	const child_list_t* list = getChildList();
 
-	localPointToScreen(x, y, &screenX, &screenY);
-
-	// look for a child which contains the point (screenX, screenY) in it's rectangle
 	for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
 	{
-		LLRect rect;
-		localRectToScreen((*i)->getRect(), &rect);
-
-		if (rect.pointInRect(screenX, screenY))
+		// Look only for children that are favorite buttons
+		if ((*i)->getName() == "favorites_bar_btn")
 		{
-			ctrl = dynamic_cast<LLUICtrl*>(*i);
-			break;
+			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<LLUICtrl*>(*i);
+				break;
+			}
 		}
 	}
-
 	return ctrl;
 }
 
 	return result;
 }
 
-LLInventoryModel::item_array_t::iterator LLFavoritesBarCtrl::findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id)
+void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before)
 {
-	LLInventoryModel::item_array_t::iterator result = items.end();
+	// 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;
 
-	for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
+	// Go to the next element if one wishes to insert after the dest element
+	if (!insert_before)
 	{
-		if ((*i)->getUUID() == id)
-		{
-			result = i;
-			break;
-		}
+		++it_dest;
 	}
-
-	return result;
-}
-
-void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem)
-{
-	LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId);
-	llassert(beforeItem);
-	if (beforeItem)
+	
+	// Insert the source item in the right place
+	if (it_dest != items.end())
 	{
-		items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem);
+		items.insert(it_dest, insertedItem);
+	}
+	else 
+	{
+		// Append to the list if it_dest reached the end
+		items.push_back(insertedItem);
 	}
 }
 

File indra/newview/llfavoritesbar.h

 	 * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId.
 	 * this function assumes that an item identified by insertedItemId doesn't exist in items array.
 	 */
-	void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem);
+	void insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before);
 
 	// finds an item by it's UUID in the items array
 	LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id);

File indra/newview/llfloatertoybox.cpp

 	mToolBar->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
 	mToolBar->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
 	mToolBar->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
+	mToolBar->setButtonEnterCallback(boost::bind(&LLFloaterToybox::onToolBarButtonEnter,this,_1));
 	
 	//
 	// Sort commands by localized labels so they will appear alphabetized in all languages
 	{
 		const LLCommandId& id = *it;
 
-		const bool commandOnToolbar = gToolBarView->hasCommand(id);
-		mToolBar->enableCommand(id, !commandOnToolbar);
+		const bool command_not_present = (gToolBarView->hasCommand(id) == LLToolBarView::TOOLBAR_NONE);
+		mToolBar->enableCommand(id, command_not_present);
 	}
 
 	LLFloater::draw();
 	return mToolBar->handleDragAndDrop(local_x, local_y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
 }
 
+void LLFloaterToybox::onToolBarButtonEnter(LLView* button)
+{
+	std::string suffix = "";
+
+	LLCommandId commandId(button->getName());
+	LLCommand* command = LLCommandManager::instance().getCommand(commandId);
+
+	if (command)
+	{
+		S32 command_loc = gToolBarView->hasCommand(commandId);
+
+		switch(command_loc)
+		{
+		case LLToolBarView::TOOLBAR_BOTTOM:	suffix = LLTrans::getString("Toolbar_Bottom_Tooltip");	break;
+		case LLToolBarView::TOOLBAR_LEFT:	suffix = LLTrans::getString("Toolbar_Left_Tooltip");	break;
+		case LLToolBarView::TOOLBAR_RIGHT:	suffix = LLTrans::getString("Toolbar_Right_Tooltip");	break;
+
+		default:
+			break;
+		}
+	}
+
+	mToolBar->setTooltipButtonSuffix(suffix);
+}
+
 
 // eof

File indra/newview/llfloatertoybox.h

 protected:
 	void onBtnRestoreDefaults();
 
+	void onToolBarButtonEnter(LLView* button);
+
 public:
 	LLToolBar *	mToolBar;
 };

File indra/newview/llimfloatercontainer.cpp

 
 LLIMFloaterContainer::~LLIMFloaterContainer()
 {
+	mNewMessageConnection.disconnect();
 	LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this);
 }
 
 BOOL LLIMFloaterContainer::postBuild()
 {
-	LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1));
+	mNewMessageConnection = LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1));
 	// Do not call base postBuild to not connect to mCloseSignal to not close all floaters via Close button
 	// mTabContainer will be initialized in LLMultiFloater::addChild()
 	return TRUE;

File indra/newview/llimfloatercontainer.h

 private:
 	typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t;
 	avatarID_panel_map_t mSessions;
-
+	boost::signals2::connection mNewMessageConnection;
 
 	void onNewMessageReceived(const LLSD& data);
 };

File indra/newview/llimview.cpp

 {
 	if (!LLDockableFloater::postBuild() || !gToolBarView)
 		return FALSE;
-
-	LLView *anchor_panel = gToolBarView->findChildView("speak");
-	setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(), LLDockControl::TOP));
-
+	
+	dockToToolbarButton("speak");
+	
 	return TRUE;
 }
 
+void LLCallDialog::dockToToolbarButton(const std::string& toolbarButtonName)
+{
+	LLDockControl::DocAt dock_pos = getDockControlPos(toolbarButtonName);
+	LLView *anchor_panel = gToolBarView->findChildView(toolbarButtonName);
+
+	setUseTongue(anchor_panel);
+
+	setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(dock_pos), dock_pos));
+}
+
+LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarButtonName)
+{
+	LLCommandId command_id(toolbarButtonName);
+	S32 toolbar_loc = gToolBarView->hasCommand(command_id);
+	
+	LLDockControl::DocAt doc_at = LLDockControl::TOP;
+	
+	switch (toolbar_loc)
+	{
+		case LLToolBarView::TOOLBAR_LEFT:
+			doc_at = LLDockControl::RIGHT;
+			break;
+			
+		case LLToolBarView::TOOLBAR_RIGHT:
+			doc_at = LLDockControl::LEFT;
+			break;
+	}
+	
+	return doc_at;
+}
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLOutgoingCallDialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

File indra/newview/llimview.h

 {
 public:
 	LLCallDialog(const LLSD& payload);
-	~LLCallDialog();
+	virtual ~LLCallDialog();
 
 	virtual BOOL postBuild();
 
+	void dockToToolbarButton(const std::string& toolbarButtonName);
+	
 	// check timer state
 	/*virtual*/ void draw();
 	/*virtual*/ void onOpen(const LLSD& key);
-
+	
 protected:
 	// lifetime timer for a notification
 	LLTimer	mLifetimeTimer;
 	void setIcon(const LLSD& session_id, const LLSD& participant_id);
 
 	LLSD mPayload;
+
+private:
+	LLDockControl::DocAt getDockControlPos(const std::string& toolbarButtonName);
 };
 
 class LLIncomingCallDialog : public LLCallDialog

File indra/newview/llinventorymodel.cpp

 	return sFirstTimeInViewer2;
 }
 
-static LLInventoryModel::item_array_t::iterator find_item_iter_by_uuid(LLInventoryModel::item_array_t& items, const LLUUID& id)
+LLInventoryModel::item_array_t::iterator LLInventoryModel::findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id)
 {
-	LLInventoryModel::item_array_t::iterator result = items.end();
+	LLInventoryModel::item_array_t::iterator curr_item = items.begin();
 
-	for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
+	while (curr_item != items.end())
 	{
-		if ((*i)->getUUID() == id)
+		if ((*curr_item)->getUUID() == id)
 		{
-			result = i;
 			break;
 		}
+		++curr_item;
 	}
 
-	return result;
+	return curr_item;
 }
 
 // static
 // * @param[in, out] items - vector with items to be updated. It should be sorted in a right way
 // * before calling this method.
 // * @param src_item_id - LLUUID of inventory item to be moved in new position
-// * @param dest_item_id - LLUUID of inventory item before which source item should be placed.
-void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id)
+// * @param dest_item_id - LLUUID of inventory item before (or after) which source item should 
+// * be placed.
+// * @param insert_before - bool indicating if src_item_id should be placed before or after 
+// * dest_item_id. Default is true.
+void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, bool insert_before)
 {
-	LLInventoryModel::item_array_t::iterator it_src = find_item_iter_by_uuid(items, src_item_id);
-	LLInventoryModel::item_array_t::iterator it_dest = find_item_iter_by_uuid(items, dest_item_id);
+	LLInventoryModel::item_array_t::iterator it_src = findItemIterByUUID(items, src_item_id);
+	LLInventoryModel::item_array_t::iterator it_dest = findItemIterByUUID(items, dest_item_id);
 
-	if (it_src == items.end() || it_dest == items.end()) return;
+	// If one of the passed UUID is not in the item list, bail out
+	if ((it_src == items.end()) || (it_dest == items.end())) 
+		return;
 
+	// Erase the source element from the list, keep a copy before erasing.
 	LLViewerInventoryItem* src_item = *it_src;
 	items.erase(it_src);
 	
-	// target iterator can not be valid because the container was changed, so update it.
-	it_dest = find_item_iter_by_uuid(items, dest_item_id);
-	items.insert(it_dest, src_item);
+	// Note: Target iterator is not valid anymore because the container was changed, so update it.
+	it_dest = findItemIterByUUID(items, dest_item_id);
+	
+	// Go to the next element if one wishes to insert after the dest element
+	if (!insert_before)
+	{
+		++it_dest;
+	}
+	
+	// Reinsert the source item in the right place
+	if (it_dest != items.end())
+	{
+		items.insert(it_dest, src_item);
+	}
+	else 
+	{
+		// Append to the list if it_dest reached the end
+		items.push_back(src_item);
+	}
 }
 
 //* @param[in] items vector of items in order to be saved.

File indra/newview/llinventorymodel.h

 	//--------------------------------------------------------------------
 public:
 	// Changes items order by insertion of the item identified by src_item_id
-	// before the item identified by dest_item_id. Both items must exist in items array.
-	// Sorting is stored after method is finished. Only src_item_id is moved before dest_item_id.
+	// before (or after) the item identified by dest_item_id. Both items must exist in items array.
+	// Sorting is stored after method is finished. Only src_item_id is moved before (or after) dest_item_id.
+	// The parameter "insert_before" controls on which side of dest_item_id src_item_id gets rensinserted.
 	static void updateItemsOrder(LLInventoryModel::item_array_t& items, 
 								 const LLUUID& src_item_id, 
-								 const LLUUID& dest_item_id);
+								 const LLUUID& dest_item_id,
+								 bool insert_before = true);
+	// Gets an iterator on an item vector knowing only the item UUID.
+	// Returns end() of the vector if not found.
+	static LLInventoryModel::item_array_t::iterator findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id);
 
 	// Saves current order of the passed items using inventory item sort field.
 	// Resets 'items' sort fields and saves them on server.

File indra/newview/llnearbychatbar.cpp

 
 void LLNearbyChatBar::showHistory()
 {
+	openFloater();
+
 	if (!getChildView("nearby_chat")->getVisible())
 	{
 		onToggleNearbyChatPanel();
 	}
-	
-	openFloater();
 }
 
 void LLNearbyChatBar::draw()
 
 	if (nearby_chat->getVisible())
 	{
-		mExpandedHeight = getRect().getHeight();
+		if (!isMinimized())
+		{
+			mExpandedHeight = getRect().getHeight();
+		}
 		setResizeLimits(getMinWidth(), COLLAPSED_HEIGHT);
 		nearby_chat->setVisible(FALSE);
 		reshape(getRect().getWidth(), COLLAPSED_HEIGHT);
 	}
 }
 
+void LLNearbyChatBar::setMinimized(BOOL b)
+{
+	if (b != LLFloater::isMinimized())
+	{
+		LLFloater::setMinimized(b);
+		getChildView("nearby_chat")->setVisible(!b);
+	}
+}
+
 void LLNearbyChatBar::onChatBoxCommit()
 {
 	if (mChatBox->getText().length() > 0)

File indra/newview/llnearbychatbar.h

 	static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate);
 
 	void showHistory();
+	/*virtual*/void setMinimized(BOOL b);
 
 protected:
 	static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str);

File indra/newview/llnearbychathandler.cpp

 	sChatWatcher->post(notification);
 
 
-	if( chat_bar->getVisible() && nearby_chat->getVisible() 
+	if( !chat_bar->isMinimized()
+		&& nearby_chat->isInVisibleChain() 
 		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
 			&& gSavedSettings.getBOOL("UseChatBubbles") )
 		|| !mChannel->getShowToasts() ) // to prevent toasts in Busy mode

File indra/newview/llpanelmaininventory.cpp

 	mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
 	mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
 	mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2));
- 	mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this));
+ 	//mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this));
 	mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this));
 	mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this));
 	mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2));

File indra/newview/lltoolbarview.cpp

 #include "lltoolbarview.h"
 
 #include "llappviewer.h"
+#include "llbutton.h"
+#include "llclipboard.h"
 #include "lldir.h"
+#include "lldockablefloater.h"
+#include "lldockcontrol.h"
+#include "llimview.h"
+#include "lltransientfloatermgr.h"
+#include "lltoolbar.h"
+#include "lltooldraganddrop.h"
 #include "llxmlnode.h"
-#include "lltoolbar.h"
-#include "llbutton.h"
-#include "lltooldraganddrop.h"
-#include "llclipboard.h"
 
 #include "llagent.h"  // HACK for destinations guide on startup
 #include "llfloaterreg.h"  // HACK for destinations guide on startup
 
 LLToolBarView::LLToolBarView(const LLToolBarView::Params& p)
 :	LLUICtrl(p),
-	mToolbarLeft(NULL),
-	mToolbarRight(NULL),
-	mToolbarBottom(NULL),
 	mDragStarted(false),
-	mDragToolbarButton(NULL)
+	mDragToolbarButton(NULL),
+	mToolbarsLoaded(false)
 {
+	for (S32 i = 0; i < TOOLBAR_COUNT; i++)
+	{
+		mToolbars[i] = NULL;
+	}
 }
 
 void LLToolBarView::initFromParams(const LLToolBarView::Params& p)
 
 BOOL LLToolBarView::postBuild()
 {
-	mToolbarLeft   = getChild<LLToolBar>("toolbar_left");
-	mToolbarRight  = getChild<LLToolBar>("toolbar_right");
-	mToolbarBottom = getChild<LLToolBar>("toolbar_bottom");
+	mToolbars[TOOLBAR_LEFT]   = getChild<LLToolBar>("toolbar_left");
+	mToolbars[TOOLBAR_RIGHT]  = getChild<LLToolBar>("toolbar_right");
+	mToolbars[TOOLBAR_BOTTOM] = getChild<LLToolBar>("toolbar_bottom");
 
-	mToolbarLeft->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarLeft->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarLeft->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
-	
-	mToolbarRight->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarRight->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarRight->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
-	
-	mToolbarBottom->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
-	mToolbarBottom->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
-	mToolbarBottom->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
+	for (int i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		mToolbars[i]->setStartDragCallback(boost::bind(LLToolBarView::startDragTool,_1,_2,_3));
+		mToolbars[i]->setHandleDragCallback(boost::bind(LLToolBarView::handleDragTool,_1,_2,_3,_4));
+		mToolbars[i]->setHandleDropCallback(boost::bind(LLToolBarView::handleDropTool,_1,_2,_3,_4));
+		mToolbars[i]->setButtonAddCallback(boost::bind(LLToolBarView::onToolBarButtonAdded,_1));
+		mToolbars[i]->setButtonRemoveCallback(boost::bind(LLToolBarView::onToolBarButtonRemoved,_1));
+	}
 
 	LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&handleLoginToolbarSetup));
 	
 	return TRUE;
 }
 
-bool LLToolBarView::hasCommand(const LLCommandId& commandId) const
+S32 LLToolBarView::hasCommand(const LLCommandId& commandId) const
 {
-	bool has_command = false;
-	if (mToolbarLeft && !has_command)
+	S32 command_location = TOOLBAR_NONE;
+
+	for (S32 loc = TOOLBAR_FIRST; loc <= TOOLBAR_LAST; loc++)
 	{
-		has_command = mToolbarLeft->hasCommand(commandId);
+		if (mToolbars[loc]->hasCommand(commandId))
+		{
+			command_location = loc;
+			break;
+		}
 	}
-	if (mToolbarRight && !has_command)
-	{
-		has_command = mToolbarRight->hasCommand(commandId);
-	}
-	if (mToolbarBottom && !has_command)
-	{
-		has_command = mToolbarBottom->hasCommand(commandId);
-	}
-	return has_command;
+
+	return command_location;
 }
 
-bool LLToolBarView::addCommand(const LLCommandId& command, LLToolBar* toolbar)
+S32 LLToolBarView::addCommand(const LLCommandId& commandId, EToolBarLocation toolbar, int rank)
+{
+	int old_rank;
+	removeCommand(commandId, old_rank);
+
+	S32 command_location = mToolbars[toolbar]->addCommand(commandId, rank);
+
+	return command_location;
+}
+
+S32 LLToolBarView::removeCommand(const LLCommandId& commandId, int& rank)
+{
+	S32 command_location = hasCommand(commandId);
+	rank = LLToolBar::RANK_NONE;
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		rank = mToolbars[command_location]->removeCommand(commandId);
+	}
+
+	return command_location;
+}
+
+S32 LLToolBarView::enableCommand(const LLCommandId& commandId, bool enabled)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		mToolbars[command_location]->enableCommand(commandId, enabled);
+	}
+
+	return command_location;
+}
+
+S32 LLToolBarView::stopCommandInProgress(const LLCommandId& commandId)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		mToolbars[command_location]->stopCommandInProgress(commandId);
+	}
+
+	return command_location;
+}
+
+S32 LLToolBarView::flashCommand(const LLCommandId& commandId, bool flash)
+{
+	S32 command_location = hasCommand(commandId);
+
+	if (command_location != TOOLBAR_NONE)
+	{
+		mToolbars[command_location]->flashCommand(commandId, flash);
+	}
+
+	return command_location;
+}
+
+bool LLToolBarView::addCommandInternal(const LLCommandId& command, LLToolBar* toolbar)
 {
 	LLCommandManager& mgr = LLCommandManager::instance();
 	if (mgr.getCommand(command))
 bool LLToolBarView::loadToolbars(bool force_default)
 {
 	LLToolBarView::ToolbarSet toolbar_set;
+	bool err = false;
 	
 	// Load the toolbars.xml file
 	std::string toolbar_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml");
 	if(!LLXMLNode::parseFile(toolbar_file, root, NULL))
 	{
 		llwarns << "Unable to load toolbars from file: " << toolbar_file << llendl;
-		return false;
+		err = true;
 	}
-	if(!root->hasName("toolbars"))
+	
+	if (!err && !root->hasName("toolbars"))
 	{
 		llwarns << toolbar_file << " is not a valid toolbars definition file" << llendl;
-		return false;
+		err = true;
 	}
 	
 	// Parse the toolbar settings
 	LLXUIParser parser;
+	if (!err)
+	{
 	parser.readXUI(root, toolbar_set, toolbar_file);
-	if (!toolbar_set.validateBlock())
+	}
+	if (!err && !toolbar_set.validateBlock())
 	{
-		llerrs << "Unable to validate toolbars from file: " << toolbar_file << llendl;
+		llwarns << "Unable to validate toolbars from file: " << toolbar_file << llendl;
+		err = true;
+	}
+	
+	if (err)
+	{
+		if (force_default)
+		{
+			llerrs << "Unable to load toolbars from default file : " << toolbar_file << llendl;
 		return false;
 	}
+		// Try to load the default toolbars
+		return loadToolbars(true);
+	}
 	
 	// Clear the toolbars now before adding the loaded commands and settings
-	if (mToolbarLeft)
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
 	{
-		mToolbarLeft->clearCommandsList();
-	}
-	if (mToolbarRight)
-	{
-		mToolbarRight->clearCommandsList();
-	}
-	if (mToolbarBottom)
-	{
-		mToolbarBottom->clearCommandsList();
+		if (mToolbars[i])
+		{
+			mToolbars[i]->clearCommandsList();
+		}
 	}
 	
 	// Add commands to each toolbar
-	if (toolbar_set.left_toolbar.isProvided() && mToolbarLeft)
+	if (toolbar_set.left_toolbar.isProvided() && mToolbars[TOOLBAR_LEFT])
 	{
 		if (toolbar_set.left_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.left_toolbar.button_display_mode;
-			mToolbarLeft->setButtonType(button_type);
+			mToolbars[TOOLBAR_LEFT]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.left_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.left_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarLeft) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_LEFT]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to left toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to left toolbar." << llendl;
 			}
 		}
 	}
-	if (toolbar_set.right_toolbar.isProvided() && mToolbarRight)
+	if (toolbar_set.right_toolbar.isProvided() && mToolbars[TOOLBAR_RIGHT])
 	{
 		if (toolbar_set.right_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.right_toolbar.button_display_mode;
-			mToolbarRight->setButtonType(button_type);
+			mToolbars[TOOLBAR_RIGHT]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.right_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.right_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarRight) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_RIGHT]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to right toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to right toolbar." << llendl;
 			}
 		}
 	}
-	if (toolbar_set.bottom_toolbar.isProvided() && mToolbarBottom)
+	if (toolbar_set.bottom_toolbar.isProvided() && mToolbars[TOOLBAR_BOTTOM])
 	{
 		if (toolbar_set.bottom_toolbar.button_display_mode.isProvided())
 		{
 			LLToolBarEnums::ButtonType button_type = toolbar_set.bottom_toolbar.button_display_mode;
-			mToolbarBottom->setButtonType(button_type);
+			mToolbars[TOOLBAR_BOTTOM]->setButtonType(button_type);
 		}
-		BOOST_FOREACH(const LLCommandId::Params& command_name_param, toolbar_set.bottom_toolbar.commands)
+		BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.bottom_toolbar.commands)
 		{
-			if (addCommand(LLCommandId(command_name_param), mToolbarBottom) == false)
+			if (addCommandInternal(LLCommandId(command_params), mToolbars[TOOLBAR_BOTTOM]))
 			{
-				llwarns << "Error adding command '" << command_name_param.name() << "' to bottom toolbar." << llendl;
+				llwarns << "Error adding command '" << command_params.name() << "' to bottom toolbar." << llendl;
 			}
 		}
 	}
+	mToolbarsLoaded = true;
 	return true;
 }
 
 	if (gToolBarView)
 	{
 		retval = gToolBarView->loadToolbars(true);
+		if (retval)
+		{
+			gToolBarView->saveToolbars();
+		}
 	}
 
 	return retval;
 
 void LLToolBarView::saveToolbars() const
 {
+	if (!mToolbarsLoaded)
+		return;
+	
 	// Build the parameter tree from the toolbar data
 	LLToolBarView::ToolbarSet toolbar_set;
-	if (mToolbarLeft)
+	if (mToolbars[TOOLBAR_LEFT])
 	{
-		toolbar_set.left_toolbar.button_display_mode = mToolbarLeft->getButtonType();
-		addToToolset(mToolbarLeft->getCommandsList(),toolbar_set.left_toolbar);
+		toolbar_set.left_toolbar.button_display_mode = mToolbars[TOOLBAR_LEFT]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_LEFT]->getCommandsList(), toolbar_set.left_toolbar);
 	}
-	if (mToolbarRight)
+	if (mToolbars[TOOLBAR_RIGHT])
 	{
-		toolbar_set.right_toolbar.button_display_mode = mToolbarRight->getButtonType();
-		addToToolset(mToolbarRight->getCommandsList(),toolbar_set.right_toolbar);
+		toolbar_set.right_toolbar.button_display_mode = mToolbars[TOOLBAR_RIGHT]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_RIGHT]->getCommandsList(), toolbar_set.right_toolbar);
 	}
-	if (mToolbarBottom)
+	if (mToolbars[TOOLBAR_BOTTOM])
 	{
-		toolbar_set.bottom_toolbar.button_display_mode = mToolbarBottom->getButtonType();
-		addToToolset(mToolbarBottom->getCommandsList(),toolbar_set.bottom_toolbar);
+		toolbar_set.bottom_toolbar.button_display_mode = mToolbars[TOOLBAR_BOTTOM]->getButtonType();
+		addToToolset(mToolbars[TOOLBAR_BOTTOM]->getCommandsList(), toolbar_set.bottom_toolbar);
 	}
 	
 	// Serialize the parameter tree
 	}
 }
 
+void LLToolBarView::onToolBarButtonAdded(LLView* button)
+{
+	llassert(button);
+	
+	if (button->getName() == "speak")
+	{
+		// Add the "Speak" button as a control view in LLTransientFloaterMgr
+		// to prevent hiding the transient IM floater upon pressing "Speak".
+		LLTransientFloaterMgr::getInstance()->addControlView(button);
+		
+		// Redock incoming and/or outgoing call windows, if applicable
+		
+		LLFloater* incoming_floater = LLFloaterReg::getLastFloaterInGroup("incoming_call");
+		LLFloater* outgoing_floater = LLFloaterReg::getLastFloaterInGroup("outgoing_call");
+		
+		if (incoming_floater && incoming_floater->isShown())
+		{
+			LLCallDialog* incoming = dynamic_cast<LLCallDialog *>(incoming_floater);
+			llassert(incoming);
+			
+			LLDockControl* dock_control = incoming->getDockControl();
+			if (dock_control->getDock() == NULL)
+			{
+				incoming->dockToToolbarButton("speak");
+			}
+		}
+		
+		if (outgoing_floater && outgoing_floater->isShown())
+		{
+			LLCallDialog* outgoing = dynamic_cast<LLCallDialog *>(outgoing_floater);
+			llassert(outgoing);
+			
+			LLDockControl* dock_control = outgoing->getDockControl();
+			if (dock_control->getDock() == NULL)
+			{
+				outgoing->dockToToolbarButton("speak");
+			}
+		}
+	}
+	else if (button->getName() == "voice")
+	{
+		// Add the "Voice controls" button as a control view in LLTransientFloaterMgr
+		// to prevent hiding the transient IM floater upon pressing "Voice controls".
+		LLTransientFloaterMgr::getInstance()->addControlView(button);
+	}
+}
+
+void LLToolBarView::onToolBarButtonRemoved(LLView* button)
+{
+	llassert(button);
+
+	if (button->getName() == "speak")
+	{
+		LLTransientFloaterMgr::getInstance()->removeControlView(button);
+		
+		// Undock incoming and/or outgoing call windows
+		
+		LLFloater* incoming_floater = LLFloaterReg::getLastFloaterInGroup("incoming_call");
+		LLFloater* outgoing_floater = LLFloaterReg::getLastFloaterInGroup("outgoing_call");
+		
+		if (incoming_floater && incoming_floater->isShown())
+		{
+			LLDockableFloater* incoming = dynamic_cast<LLDockableFloater *>(incoming_floater);
+			llassert(incoming);
+
+			LLDockControl* dock_control = incoming->getDockControl();
+			dock_control->setDock(NULL);
+		}
+		
+		if (outgoing_floater && outgoing_floater->isShown())
+		{
+			LLDockableFloater* outgoing = dynamic_cast<LLDockableFloater *>(outgoing_floater);
+			llassert(outgoing);
+
+			LLDockControl* dock_control = outgoing->getDockControl();
+			dock_control->setDock(NULL);
+		}
+	}
+	else if (button->getName() == "voice")
+	{
+		LLTransientFloaterMgr::getInstance()->removeControlView(button);
+	}
+}
+
 void LLToolBarView::draw()
 {
-	//LLPanel* sizer_left = getChild<LLPanel>("sizer_left");
+	LLRect toolbar_rects[TOOLBAR_COUNT];
 	
-	LLRect bottom_rect, left_rect, right_rect;
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		if (mToolbars[i])
+		{
+			LLLayoutStack::ELayoutOrientation orientation = LLToolBarEnums::getOrientation(mToolbars[i]->getSideType());
 
-	if (mToolbarBottom) 
-	{
-		mToolbarBottom->getParent()->reshape(mToolbarBottom->getParent()->getRect().getWidth(), mToolbarBottom->getRect().getHeight());
-		mToolbarBottom->localRectToOtherView(mToolbarBottom->getLocalRect(), &bottom_rect, this);
-	}
-	if (mToolbarLeft)   
-	{
-		mToolbarLeft->getParent()->reshape(mToolbarLeft->getRect().getWidth(), mToolbarLeft->getParent()->getRect().getHeight());
-		mToolbarLeft->localRectToOtherView(mToolbarLeft->getLocalRect(), &left_rect, this);
-	}
-	if (mToolbarRight)  
-	{
-		mToolbarRight->getParent()->reshape(mToolbarRight->getRect().getWidth(), mToolbarRight->getParent()->getRect().getHeight());
-		mToolbarRight->localRectToOtherView(mToolbarRight->getLocalRect(), &right_rect, this);
+			if (orientation == LLLayoutStack::HORIZONTAL)
+			{
+				mToolbars[i]->getParent()->reshape(mToolbars[i]->getParent()->getRect().getWidth(), mToolbars[i]->getRect().getHeight());
+			}
+			else
+			{
+				mToolbars[i]->getParent()->reshape(mToolbars[i]->getRect().getWidth(), mToolbars[i]->getParent()->getRect().getHeight());
+			}
+
+			mToolbars[i]->localRectToOtherView(mToolbars[i]->getLocalRect(), &toolbar_rects[i], this);
+		}
 	}
 	
 	// Draw drop zones if drop of a tool is active
 	if (isToolDragged())
 	{
 		LLColor4 drop_color = LLUIColorTable::instance().getColor( "ToolbarDropZoneColor" );
-		gl_rect_2d(bottom_rect, drop_color, TRUE);
-		gl_rect_2d(left_rect, drop_color, TRUE);
-		gl_rect_2d(right_rect, drop_color, TRUE);
+
+		for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+		{
+			gl_rect_2d(toolbar_rects[i], drop_color, TRUE);
+		}
 	}
 	
 	LLUICtrl::draw();
 // ----------------------------------------
 
 
-void LLToolBarView::startDragTool(S32 x, S32 y, LLToolBarButton* button)
+void LLToolBarView::startDragTool(S32 x, S32 y, LLToolBarButton* toolbarButton)
 {
-	resetDragTool(button);
+	resetDragTool(toolbarButton);
 
 	// Flag the tool dragging but don't start it yet
 	LLToolDragAndDrop::getInstance()->setDragStart( x, y );
 
 			// Second, stop the command if it is in progress and requires stopping!
 			LLCommandId command_id = LLCommandId(uuid);
-			gToolBarView->mToolbarLeft->stopCommandInProgress(command_id);
-			gToolBarView->mToolbarRight->stopCommandInProgress(command_id);
-			gToolBarView->mToolbarBottom->stopCommandInProgress(command_id);
+			gToolBarView->stopCommandInProgress(command_id);
 
 			gToolBarView->mDragStarted = true;
 			return TRUE;
 		{
 			// Suppress the command from the toolbars (including the one it's dropped in, 
 			// this will handle move position).
-			bool command_present = gToolBarView->hasCommand(command_id);
+			S32 old_toolbar_loc = gToolBarView->hasCommand(command_id);
 			LLToolBar* old_toolbar = NULL;
 
-			if (command_present)
+			if (old_toolbar_loc != TOOLBAR_NONE)
 			{
 				llassert(gToolBarView->mDragToolbarButton);
 				old_toolbar = gToolBarView->mDragToolbarButton->getParentByType<LLToolBar>();
 				}
 				else
 				{
-					gToolBarView->mToolbarBottom->removeCommand(command_id);
-					gToolBarView->mToolbarLeft->removeCommand(command_id);
-					gToolBarView->mToolbarRight->removeCommand(command_id);
+					int old_rank = LLToolBar::RANK_NONE;
+					gToolBarView->removeCommand(command_id, old_rank);
 				}
 			}
 
 				int new_rank = toolbar->getRankFromPosition(x,y);
 				toolbar->addCommand(command_id, new_rank);
 			}
+			
+			// Save the new toolbars configuration
+			gToolBarView->saveToolbars();
 		}
 		else
 		{
 	return handled;
 }
 
-void LLToolBarView::resetDragTool(LLToolBarButton* button)
+void LLToolBarView::resetDragTool(LLToolBarButton* toolbarButton)
 {
 	// Clear the saved command, toolbar and rank
 	gToolBarView->mDragStarted = false;
-	gToolBarView->mDragToolbarButton = button;
+	gToolBarView->mDragToolbarButton = toolbarButton;
 }
 
 void LLToolBarView::setToolBarsVisible(bool visible)
 {
-	mToolbarBottom->getParent()->setVisible(visible);
-	mToolbarLeft->getParent()->setVisible(visible);
-	mToolbarRight->getParent()->setVisible(visible);
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		mToolbars[i]->getParent()->setVisible(visible);
+	}
 }
 
 bool LLToolBarView::isModified() const
 {
 	bool modified = false;
 
-	modified |= mToolbarBottom->isModified();
-	modified |= mToolbarLeft->isModified();
-	modified |= mToolbarRight->isModified();
+	for (S32 i = TOOLBAR_FIRST; i <= TOOLBAR_LAST; i++)
+	{
+		modified |= mToolbars[i]->isModified();
+	}
 
 	return modified;
 }
 void handleLoginToolbarSetup()
 {
 	// Open the destinations guide by default on first login, per Rhett
-	if (gSavedSettings.getBOOL("FirstLoginThisInstall") || gAgent.isFirstLogin())
+	if (gSavedPerAccountSettings.getBOOL("DisplayDestinationsOnInitialRun") || gAgent.isFirstLogin())
 	{
 		LLFloaterReg::showInstance("destinations");
+
+		gSavedPerAccountSettings.setBOOL("DisplayDestinationsOnInitialRun", FALSE);
 	}
 }
 

File indra/newview/lltoolbarview.h

 class LLToolBarView : public LLUICtrl
 {
 public:
+	typedef enum
+	{
+		TOOLBAR_NONE = 0,
+		TOOLBAR_LEFT,
+		TOOLBAR_RIGHT,
+		TOOLBAR_BOTTOM,
+
+		TOOLBAR_COUNT,
+
+		TOOLBAR_FIRST = TOOLBAR_LEFT,
+		TOOLBAR_LAST = TOOLBAR_BOTTOM,
+	} EToolBarLocation;
+
 	// Xui structure of the toolbar panel
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> {};
 
 	{
 		Mandatory<LLToolBarEnums::ButtonType>	button_display_mode;
 		Multiple<LLCommandId::Params>	commands;
+
 		Toolbar();
 	};
 	struct ToolbarSet : public LLInitParam::Block<ToolbarSet>
 		Optional<Toolbar>	left_toolbar,
 							right_toolbar,
 							bottom_toolbar;
+
 		ToolbarSet();
 	};
 
 	virtual ~LLToolBarView();
 	virtual BOOL postBuild();
 	virtual void draw();
+
 	// Toolbar view interface with the rest of the world
-	// Checks if the commandId is being used somewhere in one of the toolbars
-	bool hasCommand(const LLCommandId& commandId) const;
+	// Checks if the commandId is being used somewhere in one of the toolbars, returns EToolBarLocation
+	S32 hasCommand(const LLCommandId& commandId) const;
+	S32 addCommand(const LLCommandId& commandId, EToolBarLocation toolbar, int rank = LLToolBar::RANK_NONE);
+	S32 removeCommand(const LLCommandId& commandId, int& rank);	// Sets the rank the removed command was at, RANK_NONE if not found
+	S32 enableCommand(const LLCommandId& commandId, bool enabled);
+	S32 stopCommandInProgress(const LLCommandId& commandId);
+	S32 flashCommand(const LLCommandId& commandId, bool flash);
+
 	// Loads the toolbars from the existing user or default settings
 	bool loadToolbars(bool force_default = false);	// return false if load fails
 	
 
 	static bool loadDefaultToolbars();
 	
-	static void startDragTool(S32 x, S32 y, LLToolBarButton* button);
+	static void startDragTool(S32 x, S32 y, LLToolBarButton* toolbarButton);
 	static BOOL handleDragTool(S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type);
 	static BOOL handleDropTool(void* cargo_data, S32 x, S32 y, LLToolBar* toolbar);
-	static void resetDragTool(LLToolBarButton* button);
+	static void resetDragTool(LLToolBarButton* toolbarButton);
 
 	bool isModified() const;
 	
 
 private:
 	void	saveToolbars() const;
-	bool	addCommand(const LLCommandId& commandId, LLToolBar*	toolbar);
+	bool	addCommandInternal(const LLCommandId& commandId, LLToolBar*	toolbar);
 	void	addToToolset(command_id_list_t& command_list, Toolbar& toolbar) const;
 
+	static void	onToolBarButtonAdded(LLView* button);
+	static void onToolBarButtonRemoved(LLView* button);
+
 	// Pointers to the toolbars handled by the toolbar view
-	LLToolBar*	mToolbarLeft;
-	LLToolBar*	mToolbarRight;
-	LLToolBar*	mToolbarBottom;
+	LLToolBar*  mToolbars[TOOLBAR_COUNT];
+	bool		mToolbarsLoaded;
 	
 	bool				mDragStarted;
 	LLToolBarButton*	mDragToolbarButton;

File indra/newview/lltransientfloatermgr.cpp

 			&LLTransientFloaterMgr::leftMouseClickCallback, this, _2, _3, _4));
 	}
 
-	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>()));
-	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>()));
-	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(IM, std::set<LLView*>()));
+	mGroupControls.insert(std::pair<ETransientGroup, controls_set_t >(GLOBAL, controls_set_t()));
+	mGroupControls.insert(std::pair<ETransientGroup, controls_set_t >(DOCKED, controls_set_t()));
+	mGroupControls.insert(std::pair<ETransientGroup, controls_set_t >(IM, controls_set_t()));
 }
 
 void LLTransientFloaterMgr::registerTransientFloater(LLTransientFloater* floater)
 
 void LLTransientFloaterMgr::addControlView(ETransientGroup group, LLView* view)
 {
-	mGroupControls.find(group)->second.insert(view);
+	if (!view) return;
+
+	mGroupControls.find(group)->second.insert(view->getHandle());
 }
 
 void LLTransientFloaterMgr::removeControlView(ETransientGroup group, LLView* view)
 {
-	mGroupControls.find(group)->second.erase(view);
+	if (!view) return;
+
+	mGroupControls.find(group)->second.erase(view->getHandle());
 }
 
 void LLTransientFloaterMgr::addControlView(LLView* view)
 		{
 			ETransientGroup group = floater->getGroup();
 
-			bool hide = isControlClicked(mGroupControls.find(group)->second, x, y);
+			bool hide = isControlClicked(group, mGroupControls.find(group)->second, x, y);
 			if (hide)
 			{
 				floater->setTransientVisible(FALSE);
 	}
 }
 
-bool LLTransientFloaterMgr::isControlClicked(std::set<LLView*>& set, S32 x, S32 y)
+bool LLTransientFloaterMgr::isControlClicked(ETransientGroup group, controls_set_t& set, S32 x, S32 y)
 {
+	std::list< LLHandle<LLView> > dead_handles;
+	
 	bool res = true;
 	for (controls_set_t::iterator it = set.begin(); it
 			!= set.end(); it++)
 	{
-		LLView* control_view = *it;
+		LLView* control_view = NULL;
+
+		LLHandle<LLView> handle = *it;
+		if (handle.isDead())
+		{
+			dead_handles.push_back(handle);
+			continue;
+		}
+
+		control_view = handle.get();
+
 		if (!control_view->getVisible())
 		{
 			continue;
 			break;
 		}
 	}
+
+	for (std::list< LLHandle<LLView> >::iterator it = dead_handles.begin(); it != dead_handles.end(); ++it)
+	{
+		LLHandle<LLView> handle = *it;
+		mGroupControls.find(group)->second.erase(handle);
+	}
+	
 	return res;
 }
 
 		return;
 	}
 
-	bool hide = isControlClicked(mGroupControls.find(DOCKED)->second, x, y)
-			&& isControlClicked(mGroupControls.find(GLOBAL)->second, x, y);
+	bool hide = isControlClicked(DOCKED, mGroupControls.find(DOCKED)->second, x, y)
+			&& isControlClicked(GLOBAL, mGroupControls.find(GLOBAL)->second, x, y);
 	if (hide)
 	{
 		hideTransientFloaters(x, y);

File indra/newview/lltransientfloatermgr.h

 	void removeControlView(LLView* view);
 
 private:
+	typedef std::set<LLHandle<LLView> > controls_set_t;
+	typedef std::map<ETransientGroup, controls_set_t > group_controls_t;
+
 	void hideTransientFloaters(S32 x, S32 y);
 	void leftMouseClickCallback(S32 x, S32 y, MASK mask);
-	bool isControlClicked(std::set<LLView*>& set, S32 x, S32 y);
-private:
+	bool isControlClicked(ETransientGroup group, controls_set_t& set, S32 x, S32 y);
+
 	std::set<LLTransientFloater*> mTransSet;
 
-	typedef std::set<LLView*> controls_set_t;
-	typedef std::map<ETransientGroup, std::set<LLView*> > group_controls_t;
 	group_controls_t mGroupControls;
 };
 

File indra/newview/llviewermenu.cpp

 
 	view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
 
+
+	commit.add("Inventory.NewWindow", boost::bind(&LLFloaterInventory::showAgentInventory));
+
 	// Agent
 	commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
 	enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying));
 	view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
 	commit.add("PayObject", boost::bind(&handle_give_money_dialog));
 
+	commit.add("Inventory.NewWindow", boost::bind(&LLFloaterInventory::showAgentInventory));
+
 	enable.add("EnablePayObject", boost::bind(&enable_pay_object));
 	enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
 	enable.add("EnableEdit", boost::bind(&enable_object_edit));

File indra/newview/skins/default/textures/windows/Flyout_Left.png

Added
New image

File indra/newview/skins/default/textures/windows/Flyout_Right.png

Added
New image

File indra/newview/skins/default/xui/en/floater_chat_bar.xml

      image_pressed="ComboButton_UpSelected"