diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 4bafe70705f9697abbf43db656e95c0d1d276ec7..7139b0ea0e5b6285b19e956a2ae902a89a683a65 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -511,9 +511,10 @@ void LLBottomTray::showSnapshotButton(BOOL visible)
 
 void LLBottomTray::showSpeakButton(bool visible)
 {
+	// Show/hide the button
 	setTrayButtonVisible(RS_BUTTON_SPEAK, visible);
 
-	// Adjust other panels.
+	// and adjust other panels according to the occupied/freed space.
 	const S32 panel_width = mSpeakPanel->getRect().getWidth();
 	if (visible)
 	{
@@ -687,10 +688,7 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
 	// (and according to future possible changes in the way button order is saved between sessions).
 	state_object_map_t::const_iterator it = mStateProcessedObjectMap.begin();
 	state_object_map_t::const_iterator it_end = mStateProcessedObjectMap.end();
-	// Speak button is currently the only draggable button not in mStateProcessedObjectMap,
-	// so if dragged_state is not found in that map, it should be RS_BUTTON_SPEAK. Change this code if any other
-	// exclusions from mStateProcessedObjectMap will become draggable.
-	EResizeState dragged_state = RS_BUTTON_SPEAK;
+	EResizeState dragged_state = RS_NORESIZE;
 	EResizeState landing_state = RS_NORESIZE;
 	bool landing_state_found = false;
 	// Find states for dragged item and landing tab
@@ -706,7 +704,17 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
 			landing_state_found = true;
 		}
 	}
-	
+
+	if (dragged_state == RS_NORESIZE)
+	{
+		llwarns << "Cannot determine what button is being dragged" << llendl;
+		llassert(dragged_state != RS_NORESIZE);
+		return;
+	}
+
+	lldebugs << "Will place " << resizeStateToString(dragged_state)
+		<< " before " << resizeStateToString(landing_state) << llendl;
+
 	// Update order of buttons according to drag'n'drop
 	mButtonsOrder.erase(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), dragged_state));
 	if (!landing_state_found && mLandingTab == getChild<LLPanel>(PANEL_CHICLET_NAME))
@@ -715,7 +723,7 @@ void LLBottomTray::updateButtonsOrdersAfterDnD()
 	}
 	else
 	{
-		if (!landing_state_found) landing_state = RS_BUTTON_SPEAK;
+		if (!landing_state_found) landing_state = RS_BUTTON_SPEAK; // just a random fallback
 		mButtonsOrder.insert(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), landing_state), dragged_state);
 	}
 
@@ -799,7 +807,7 @@ void LLBottomTray::loadButtonsOrder()
 		mToolbarStack->movePanel(panel_to_move, NULL, true); // prepend 		
 	}
 	// Nearbychat is not stored in order settings file, but it must be the first of the panels, so moving it
-	// manually here
+	// (along with its drag handle) manually here.
 	mToolbarStack->movePanel(getChild<LLLayoutPanel>("chat_bar_resize_handle_panel"), NULL, true);
 	mToolbarStack->movePanel(mChatBarContainer, NULL, true);
 }
@@ -1200,9 +1208,8 @@ void LLBottomTray::processShowButtons(S32& available_width)
 bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
 {
 	lldebugs << "Trying to show object type: " << shown_object_type << llendl;
-	llassert(mStateProcessedObjectMap[shown_object_type] != NULL);
 
-	LLPanel* panel = mStateProcessedObjectMap[shown_object_type];
+	LLPanel* panel = getButtonPanel(shown_object_type);
 	if (NULL == panel)
 	{
 		lldebugs << "There is no object to process for state: " << shown_object_type << llendl;
@@ -1248,9 +1255,7 @@ void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_wi
 void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width)
 {
 	lldebugs << "Trying to hide object type: " << processed_object_type << llendl;
-	llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
-
-	LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
 		lldebugs << "There is no object to process for state: " << processed_object_type << llendl;
@@ -1330,8 +1335,7 @@ void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_
 
 void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32& required_width)
 {
-	llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
-	LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
 		lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
@@ -1432,8 +1436,7 @@ void LLBottomTray::processExtendButtons(S32& available_width)
 
 void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
 {
-	llassert(mStateProcessedObjectMap[processed_object_type] != NULL);
-	LLPanel* panel = mStateProcessedObjectMap[processed_object_type];
+	LLPanel* panel = getButtonPanel(processed_object_type);
 	if (NULL == panel)
 	{
 		lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
@@ -1501,6 +1504,7 @@ bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
 void LLBottomTray::initResizeStateContainers()
 {
 	// init map with objects should be processed for each type
+	mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPEAK, getChild<LLPanel>("speak_panel")));
 	mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLPanel>("gesture_panel")));
 	mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLPanel>("movement_panel")));
 	mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLPanel>("cam_panel")));
@@ -1533,11 +1537,11 @@ void LLBottomTray::initResizeStateContainers()
 	{
 		const EResizeState button_type = *it;
 		// is there an appropriate object?
-		llassert(mStateProcessedObjectMap.count(button_type) > 0);
-		if (0 == mStateProcessedObjectMap.count(button_type)) continue;
+		LLPanel* button_panel = getButtonPanel(button_type);
+		if (!button_panel) continue;
 
 		// set default width for it.
-		mObjectDefaultWidthMap[button_type] = mStateProcessedObjectMap[button_type]->getRect().getWidth();
+		mObjectDefaultWidthMap[button_type] = button_panel->getRect().getWidth();
 	}
 
 	// ... and add Speak button because it also can be shrunk.
@@ -1621,7 +1625,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 		return true;
 	}
 
-	LLPanel* cur_panel = mStateProcessedObjectMap[object_type];
+	LLPanel* cur_panel = getButtonPanel(object_type);
 	if (NULL == cur_panel)
 	{
 		lldebugs << "There is no object to process for state: " << object_type << llendl;
@@ -1666,7 +1670,7 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 
 			for (; it != it_end; ++it)
 			{
-				LLPanel * cur_panel = mStateProcessedObjectMap[*it];
+				LLPanel* cur_panel = getButtonPanel(*it);
 				sum_of_min_widths += get_panel_min_width(mToolbarStack, cur_panel);
 				sum_of_curr_widths += get_curr_width(cur_panel);
 			}
@@ -1726,12 +1730,14 @@ bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible
 
 LLPanel* LLBottomTray::getButtonPanel(EResizeState button_type)
 {
-	if (button_type == RS_BUTTON_SPEAK)
+	// Don't use the operator[] because it inserts a NULL value if the key is not found.
+	if (mStateProcessedObjectMap.count(button_type) == 0)
 	{
-		return mSpeakPanel;
+		llwarns << "Cannot find a panel for " << resizeStateToString(button_type) << llendl;
+		llassert(mStateProcessedObjectMap.count(button_type) == 1);
+		return NULL;
 	}
 
-	llassert(mStateProcessedObjectMap[button_type] != NULL);
 	return mStateProcessedObjectMap[button_type];
 }
 
@@ -1792,4 +1798,29 @@ void LLBottomTray::processChatbarCustomization(S32 new_width)
 	}
 }
 
+// static
+std::string LLBottomTray::resizeStateToString(EResizeState state)
+{
+	switch (state)
+	{
+	case RS_NORESIZE:				return "RS_NORESIZE";
+	case RS_CHICLET_PANEL:			return "RS_CHICLET_PANEL";
+	case RS_CHATBAR_INPUT:			return "RS_CHATBAR_INPUT";
+	case RS_BUTTON_SNAPSHOT:		return "RS_BUTTON_SNAPSHOT";
+	case RS_BUTTON_CAMERA:			return "RS_BUTTON_CAMERA";
+	case RS_BUTTON_MOVEMENT:		return "RS_BUTTON_MOVEMENT";
+	case RS_BUTTON_GESTURES:		return "RS_BUTTON_GESTURES";
+	case RS_BUTTON_SPEAK:			return "RS_BUTTON_SPEAK";
+	case RS_IM_WELL:				return "RS_IM_WELL";
+	case RS_NOTIFICATION_WELL:		return "RS_NOTIFICATION_WELL";
+	case RS_BUTTON_BUILD:			return "RS_BUTTON_BUILD";
+	case RS_BUTTON_SEARCH:			return "RS_BUTTON_SEARCH";
+	case RS_BUTTON_WORLD_MAP:		return "RS_BUTTON_WORLD_MAP";
+	case RS_BUTTON_MINI_MAP:		return "RS_BUTTON_MINI_MAP";
+	case RS_BUTTONS_CAN_BE_HIDDEN:	return "RS_BUTTONS_CAN_BE_HIDDEN";
+	// No default to track additions.
+	}
+	return "UNKNOWN_BUTTON";
+}
+
 //EOF
diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h
index 32d4968521190f80acbd1ac82c128d705f1830ee..76d80b8e0b97bae06f754fc014c6b0c0453d5aba 100644
--- a/indra/newview/llbottomtray.h
+++ b/indra/newview/llbottomtray.h
@@ -393,6 +393,8 @@ class LLBottomTray
 
 	/**
 	 * Get panel containing the given button.
+	 *
+	 * @see mStateProcessedObjectMap
 	 */
 	LLPanel* getButtonPanel(EResizeState button_type);
 
@@ -415,13 +417,21 @@ class LLBottomTray
 	 */
 	void processChatbarCustomization(S32 new_width);
 
+	/// Get button name for debugging.
+	static std::string resizeStateToString(EResizeState state);
 
 	/// Buttons automatically hidden due to lack of space.
 	MASK mResizeState;
 
+	/**
+	 * Mapping of button types to the layout panels the buttons are wrapped in.
+	 *
+	 * Used by getButtonPanel().
+	 */
 	typedef std::map<EResizeState, LLPanel*> state_object_map_t;
 	state_object_map_t mStateProcessedObjectMap;
 
+	/// Default (maximum) widths of the layout panels.
 	typedef std::map<EResizeState, S32> state_object_width_map_t;
 	state_object_width_map_t mObjectDefaultWidthMap;