Commits

dessie linden  committed a8c7030 Merge

reconciled .hgtags

  • Participants
  • Parent commits 34acc2f, 9e390d7
  • Tags 3.2.1-release, DRTVWR-99_3.2.1-release

Comments (0)

Files changed (252)

 glob:indra/newview/filters.xml
 glob:indra/newview/avatar_icons_cache.txt
 glob:indra/newview/avatar_lad.log
+glob:*.diff
 2a13d30ee50ccfed50268238e36bb90d738ccc9e 3.2.0-beta3
 3150219d229d628f0c15e58e8a51511cbd97e58d DRTVWR-94_3.2.0-release
 3150219d229d628f0c15e58e8a51511cbd97e58d 3.2.0-release
+c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start

File doc/contributions.txt

 	OPEN-50
 	OPEN-61
 	OPEN-76
+	STORM-959
 	STORM-1175
 Imnotgoing Sideways
 Inma Rau
 Lizzy Macarthur
 Luban Yiyuan
 Luc Starsider
+Luminous Luminos
+	STORM-959
 Lunita Savira
 Maccus McCullough
 maciek marksman

File indra/linux_crash_logger/llcrashloggerlinux.cpp

 	return true;
 }
 
+bool LLCrashLoggerLinux::cleanup()
+{
+	commonCleanup();
+	return true;
+}
+
 void LLCrashLoggerLinux::updateApplication(const std::string& message)
 {
 	LLCrashLogger::updateApplication(message);

File indra/linux_crash_logger/llcrashloggerlinux.h

 	virtual bool mainLoop();
 	virtual void updateApplication(const std::string& = LLStringUtil::null);
 	virtual void gatherPlatformSpecificFiles();
+	virtual bool cleanup();
 };
 
 #endif

File indra/llcommon/llversionviewer.h

 
 const S32 LL_VERSION_MAJOR = 3;
 const S32 LL_VERSION_MINOR = 2;
-const S32 LL_VERSION_PATCH = 0;
+const S32 LL_VERSION_PATCH = 1;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";

File indra/llcrashlogger/llcrashlogger.cpp

 #include "llpumpio.h"
 #include "llhttpclient.h"
 #include "llsdserialize.h"
+#include "llproxy.h"
 
 LLPumpIO* gServicePump;
 BOOL gBreak = false;
 	
 	return true;
 }
+
+// For cleanup code common to all platforms.
+void LLCrashLogger::commonCleanup()
+{
+	LLProxy::cleanupClass();
+}

File indra/llcrashlogger/llcrashlogger.h

 	virtual void updateApplication(const std::string& message = LLStringUtil::null);
 	virtual bool init();
 	virtual bool mainLoop() = 0;
-	virtual bool cleanup() { return true; }
+	virtual bool cleanup() = 0;
+	void commonCleanup();
 	void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }
 	S32 getCrashBehavior() { return mCrashBehavior; }
 	bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries, int timeout);

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

 	if (!mDockWidget) return;
 	LLRect dockRect = mDockWidget->calcScreenRect();
 	LLRect rootRect;
+	LLRect floater_rect = mDockableFloater->calcScreenRect();
 	mGetAllowedRectCallback(rootRect);
 
-	// recalculate dockable position if dock position changed, dock visibility changed,
-	// root view rect changed or recalculation is forced
-	if (mPrevDockRect != dockRect  || mDockWidgetVisible != isDockVisible()
-			|| mRootRect != rootRect || mRecalculateDocablePosition)
+	// recalculate dockable position if:
+	if (mPrevDockRect != dockRect					//dock position   changed
+		|| mDockWidgetVisible != isDockVisible()	//dock visibility changed
+		|| mRootRect != rootRect					//root view rect  changed
+		|| mFloaterRect != floater_rect				//floater rect    changed
+		|| mRecalculateDockablePosition				//recalculation is forced
+	)
 	{
 		// undock dockable and off() if dock not visible
 		if (!isDockVisible())
 
 		mPrevDockRect = dockRect;
 		mRootRect = rootRect;
-		mRecalculateDocablePosition = false;
+		mFloaterRect = floater_rect;
+		mRecalculateDockablePosition = false;
 		mDockWidgetVisible = isDockVisible();
 	}
 }
 	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);
 
 }
 
 	 if (isDockVisible())
 	{
 		mEnabled = true;
-		mRecalculateDocablePosition = true;
+		mRecalculateDockablePosition = true;
 	}
 }
 
 
 void LLDockControl::forceRecalculatePosition()
 {
-	mRecalculateDocablePosition = true;
+	mRecalculateDockablePosition = true;
 }
 
 void LLDockControl::drawToungue()

File indra/llui/lldockcontrol.h

 	{
 		TOP,
 		LEFT,
+		RIGHT,
 		BOTTOM
 	};
 
 private:
 	get_allowed_rect_callback_t mGetAllowedRectCallback;
 	bool mEnabled;
-	bool mRecalculateDocablePosition;
+	bool mRecalculateDockablePosition;
 	bool mDockWidgetVisible;
 	DocAt mDockAt;
 	LLView* mDockWidget;
 	LLRect mPrevDockRect;
 	LLRect mRootRect;
+	LLRect mFloaterRect;
 	LLFloater* mDockableFloater;
 	LLUIImagePtr mDockTongue;
 	S32 mDockTongueX;

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/llkeywords.cpp

 {
 }
 
+inline BOOL LLKeywordToken::isTail(const llwchar* s) const
+{
+	BOOL res = TRUE;
+	const llwchar* t = mDelimiter.c_str();
+	S32 len = mDelimiter.size();
+	for (S32 i=0; i<len; i++)
+	{
+		if (s[i] != t[i])
+		{
+			res = FALSE;
+			break;
+		}
+	}
+	return res;
+}
+
 LLKeywords::~LLKeywords()
 {
 	std::for_each(mWordTokenMap.begin(), mWordTokenMap.end(), DeletePairedPointer());
 	std::string SOL_LINE("[line ");
 	std::string SOL_ONE_SIDED_DELIMITER("[one_sided_delimiter ");
 	std::string SOL_TWO_SIDED_DELIMITER("[two_sided_delimiter ");
+	std::string SOL_DOUBLE_QUOTATION_MARKS("[double_quotation_marks ");
 
 	LLColor3 cur_color( 1, 0, 0 );
 	LLKeywordToken::TOKEN_TYPE cur_type = LLKeywordToken::WORD;
 			cur_type = LLKeywordToken::TWO_SIDED_DELIMITER;
 			continue;
 		}
+		else if( line.find(SOL_DOUBLE_QUOTATION_MARKS) == 0 )
+		{
+			cur_color = readColor( line.substr(SOL_DOUBLE_QUOTATION_MARKS.size()) );
+			cur_type = LLKeywordToken::DOUBLE_QUOTATION_MARKS;
+			continue;
+		}
 		else if( line.find(SOL_ONE_SIDED_DELIMITER) == 0 )	
 		{
 			cur_color = readColor( line.substr(SOL_ONE_SIDED_DELIMITER.size()) );
 
 		if( !token_buffer.empty() && token_word_iter != word_tokens.end() )
 		{
-			// first word is keyword
+			// first word is the keyword or a left delimiter
 			std::string keyword = (*token_word_iter);
 			LLStringUtil::trim(keyword);
 
+			// second word may be a right delimiter
+			std::string delimiter;
+			if (cur_type == LLKeywordToken::TWO_SIDED_DELIMITER)
+			{
+				while (delimiter.length() == 0 && ++token_word_iter != word_tokens.end())
+				{
+					delimiter = *token_word_iter;
+					LLStringUtil::trim(delimiter);
+				}
+			}
+			else if (cur_type == LLKeywordToken::DOUBLE_QUOTATION_MARKS)
+			{
+				// Closing delimiter is identical to the opening one.
+				delimiter = keyword;
+			}
+
 			// following words are tooltip
 			std::string tool_tip;
 			while (++token_word_iter != word_tokens.end())
 			{
 				// Replace : with \n for multi-line tool tips.
 				LLStringUtil::replaceChar( tool_tip, ':', '\n' );
-				addToken(cur_type, keyword, cur_color, tool_tip );
+				addToken(cur_type, keyword, cur_color, tool_tip, delimiter );
 			}
 			else
 			{
-				addToken(cur_type, keyword, cur_color, LLStringUtil::null );
+				addToken(cur_type, keyword, cur_color, LLStringUtil::null, delimiter );
 			}
 		}
 	}
 void LLKeywords::addToken(LLKeywordToken::TOKEN_TYPE type,
 						  const std::string& key_in,
 						  const LLColor3& color,
-						  const std::string& tool_tip_in )
+						  const std::string& tool_tip_in,
+						  const std::string& delimiter_in)
 {
 	LLWString key = utf8str_to_wstring(key_in);
 	LLWString tool_tip = utf8str_to_wstring(tool_tip_in);
+	LLWString delimiter = utf8str_to_wstring(delimiter_in);
 	switch(type)
 	{
 	case LLKeywordToken::WORD:
-		mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip);
+		mWordTokenMap[key] = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null);
 		break;
 
 	case LLKeywordToken::LINE:
-		mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip));
+		mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null));
 		break;
 
 	case LLKeywordToken::TWO_SIDED_DELIMITER:
+	case LLKeywordToken::DOUBLE_QUOTATION_MARKS:
 	case LLKeywordToken::ONE_SIDED_DELIMITER:
-		mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip));
+		mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, delimiter));
 		break;
 
 	default:
 			}
 
 			// cur is now at the first non-whitespace character of a new line	
-		
+
 			// Line start tokens
 			{
 				BOOL line_done = FALSE;
 					S32 seg_end = 0;
 
 					seg_start = cur - base;
-					cur += cur_delimiter->getLength();
+					cur += cur_delimiter->getLengthHead();
 					
-					if( cur_delimiter->getType() == LLKeywordToken::TWO_SIDED_DELIMITER )
+					LLKeywordToken::TOKEN_TYPE type = cur_delimiter->getType();
+					if( type == LLKeywordToken::TWO_SIDED_DELIMITER || type == LLKeywordToken::DOUBLE_QUOTATION_MARKS )
 					{
-						while( *cur && !cur_delimiter->isHead(cur))
+						while( *cur && !cur_delimiter->isTail(cur))
 						{
 							// Check for an escape sequence.
-							if (*cur == '\\')
+							if (type == LLKeywordToken::DOUBLE_QUOTATION_MARKS && *cur == '\\')
 							{
 								// Count the number of backslashes.
 								S32 num_backslashes = 0;
 									between_delimiters++;
 									cur++;
 								}
-								// Is the next character the end delimiter?
-								if (cur_delimiter->isHead(cur))
+								// If the next character is the end delimiter?
+								if (cur_delimiter->isTail(cur))
 								{
-									// Is there was an odd number of backslashes, then this delimiter
+									// If there was an odd number of backslashes, then this delimiter
 									// does not end the sequence.
 									if (num_backslashes % 2 == 1)
 									{
 
 						if( *cur )
 						{
-							cur += cur_delimiter->getLength();
-							seg_end = seg_start + between_delimiters + 2 * cur_delimiter->getLength();
+							cur += cur_delimiter->getLengthHead();
+							seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead() + cur_delimiter->getLengthTail();
 						}
 						else
 						{
 							// eof
-							seg_end = seg_start + between_delimiters + cur_delimiter->getLength();
+							seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();
 						}
 					}
 					else
 							between_delimiters++;
 							cur++;
 						}
-						seg_end = seg_start + between_delimiters + cur_delimiter->getLength();
+						seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();
 					}
 
 					insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, defaultColor, editor);

File indra/llui/llkeywords.h

 class LLKeywordToken
 {
 public:
-	enum TOKEN_TYPE { WORD, LINE, TWO_SIDED_DELIMITER, ONE_SIDED_DELIMITER };
+	/** 
+	 * @brief Types of tokens/delimters being parsed.
+	 *
+	 * @desc Tokens/delimiters that need to be identified/highlighted. All are terminated if an EOF is encountered.
+	 * - WORD are keywords in the normal sense, i.e. constants, events, etc.
+	 * - LINE are for entire lines (currently only flow control labels use this).
+	 * - ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL.
+	 * - TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with.
+	 * - DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close.
+	 */
+	typedef enum TOKEN_TYPE
+	{
+		WORD,
+		LINE,
+		TWO_SIDED_DELIMITER,
+		ONE_SIDED_DELIMITER,
+		DOUBLE_QUOTATION_MARKS
+	};
 
-	LLKeywordToken( TOKEN_TYPE type, const LLColor3& color, const LLWString& token, const LLWString& tool_tip ) 
+	LLKeywordToken( TOKEN_TYPE type, const LLColor3& color, const LLWString& token, const LLWString& tool_tip, const LLWString& delimiter  ) 
 		:
 		mType( type ),
 		mToken( token ),
 		mColor( color ),
-		mToolTip( tool_tip )
+		mToolTip( tool_tip ),
+		mDelimiter( delimiter )		// right delimiter
 	{
 	}
 
-	S32					getLength() const		{ return mToken.size(); }
+	S32					getLengthHead() const	{ return mToken.size(); }
+	S32					getLengthTail() const	{ return mDelimiter.size(); }
 	BOOL				isHead(const llwchar* s) const;
+	BOOL				isTail(const llwchar* s) const;
 	const LLWString&	getToken() const		{ return mToken; }
 	const LLColor3&		getColor() const		{ return mColor; }
 	TOKEN_TYPE			getType()  const		{ return mType; }
 	const LLWString&	getToolTip() const		{ return mToolTip; }
+	const LLWString&	getDelimiter() const	{ return mDelimiter; }
 
 #ifdef _DEBUG
 	void		dump();
 	LLWString	mToken;
 	LLColor3	mColor;
 	LLWString	mToolTip;
+	LLWString	mDelimiter;
 };
 
 class LLKeywords
 	void addToken(LLKeywordToken::TOKEN_TYPE type,
 					const std::string& key,
 					const LLColor3& color,
-					const std::string& tool_tip = LLStringUtil::null);
+					const std::string& tool_tip = LLStringUtil::null,
+					const std::string& delimiter = LLStringUtil::null);
 	
 	// This class is here as a performance optimization.
 	// The word token map used to be defined as std::map<LLWString, LLKeywordToken*>.

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/mac_crash_logger/llcrashloggermac.cpp

 
 bool LLCrashLoggerMac::cleanup()
 {
+	commonCleanup();
 	return true;
 }

File indra/newview/CMakeLists.txt

     llfloatertopobjects.cpp
     llfloatertos.cpp
     llfloatertoybox.cpp
+    llfloatertranslationsettings.cpp
     llfloateruipreview.cpp
     llfloaterurlentry.cpp
     llfloatervoiceeffect.cpp
     llfloatertopobjects.h
     llfloatertos.h
     llfloatertoybox.h
+    llfloatertranslationsettings.h
     llfloateruipreview.h
     llfloaterurlentry.h
     llfloatervoiceeffect.h
     llmediadataclient.cpp
     lllogininstance.cpp
     llremoteparcelrequest.cpp
+    lltranslate.cpp
     llviewerhelputil.cpp
     llversioninfo.cpp
     llworldmap.cpp
     llworldmipmap.cpp
   )
 
+  set_source_files_properties(
+    lltranslate.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}"
+  )
+
   ##################################################
   # DISABLING PRECOMPILED HEADERS USAGE FOR TESTS
   ##################################################

File indra/newview/app_settings/keywords.ini

 # Comment
 [one_sided_delimiter .8, .3, .15]
 //					Comment:Non-functional commentary or disabled code
+[two_sided_delimiter .8, .3, .15]
+/* */				Comment:Non-functional commentary or disabled code
 
 # String literals
-[two_sided_delimiter 0, .2, 0]
+[double_quotation_marks 0, .2, 0]
 "					String literal
 
 #functions are supplied by the program now

File indra/newview/app_settings/settings.xml

       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>TranslationService</key>
+    <map>
+      <key>Comment</key>
+      <string>Translation API to use. (google|bing)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>bing</string>
+    </map>
+    <key>GoogleTranslateAPIKey</key>
+    <map>
+      <key>Comment</key>
+      <string>Google Translate API key</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
+    <key>BingTranslateAPIKey</key>
+    <map>
+      <key>Comment</key>
+      <string>Bing AppID to use with the Microsoft Translator API</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string></string>
+    </map>
     <key>TutorialURL</key>
     <map>
       <key>Comment</key>
       <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/character/avatar_lad.xml

        max_attachment_offset="2.0"
        visible_in_first_person="true" />
        
-
+    <attachment_point
+       id="39"
+       group="9"
+       pie_slice="1"
+       name="Neck"
+       joint="mNeck"
+       position="0 0 0"
+       rotation="0 0 0"
+       visible_in_first_person="true" />
+  	
+  	<attachment_point
+       id="40"
+       group="9"
+       pie_slice="2"
+       name="Avatar Center"
+       joint="mRoot"
+       position="0 0 0"
+       rotation="0 0 0"
+       visible_in_first_person="true" />
+  	
     <param
        id="32"
        group="1"

File indra/newview/installers/windows/lang_ru.nsi

Binary file modified.

File indra/newview/installers/windows/lang_tr.nsi

Binary file modified.

File indra/newview/llappviewer.cpp

 
 void LLAppViewer::checkForCrash(void)
 {
-    
 #if LL_SEND_CRASH_REPORTS
 	if (gLastExecEvent == LAST_EXEC_FROZE)
     {
-        llinfos << "Last execution froze, requesting to send crash report." << llendl;
-        //
-        // Pop up a freeze or crash warning dialog
-        //
-        S32 choice;
-	const S32 cb = gCrashSettings.getS32("CrashSubmitBehavior");
-        if(cb == CRASH_BEHAVIOR_ASK)
-        {
-            std::ostringstream msg;
-			msg << LLTrans::getString("MBFrozenCrashed");
-			std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert");
-            choice = OSMessageBox(msg.str(),
-                                  alert,
-                                  OSMB_YESNO);
-        } 
-        else if(cb == CRASH_BEHAVIOR_NEVER_SEND)
-        {
-            choice = OSBTN_NO;
-        }
-        else
-        {
-            choice = OSBTN_YES;
-        }
-
-        if (OSBTN_YES == choice)
-        {
-            llinfos << "Sending crash report." << llendl;
+        llinfos << "Last execution froze, sending a crash report." << llendl;
             
-            bool report_freeze = true;
-            handleCrashReporting(report_freeze);
-        }
-        else
-        {
-            llinfos << "Not sending crash report." << llendl;
-        }
+		bool report_freeze = true;
+		handleCrashReporting(report_freeze);
     }
 #endif // LL_SEND_CRASH_REPORTS    
-    
 }
 
 //

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/llfloaterabout.cpp

 	// Render the LLSD from getInfo() as a format_map_t
 	LLStringUtil::format_map_t args;
 
+	// allow the "Release Notes" URL label to be localized
+	args["ReleaseNotes"] = LLTrans::getString("ReleaseNotes");
+
 	for (LLSD::map_const_iterator ii(info.beginMap()), iend(info.endMap());
 		 ii != iend; ++ii)
 	{

File indra/newview/llfloaterpreference.cpp

 	mCommitCallbackRegistrar.add("Pref.MaturitySettings",		boost::bind(&LLFloaterPreference::onChangeMaturity, this));
 	mCommitCallbackRegistrar.add("Pref.BlockList",				boost::bind(&LLFloaterPreference::onClickBlockList, this));
 	mCommitCallbackRegistrar.add("Pref.Proxy",					boost::bind(&LLFloaterPreference::onClickProxySettings, this));
+	mCommitCallbackRegistrar.add("Pref.TranslationSettings",	boost::bind(&LLFloaterPreference::onClickTranslationSettings, this));
 	
 	sSkin = gSavedSettings.getString("SkinCurrent");
 
 	}
 	// hide joystick pref floater
 	LLFloaterReg::hideInstance("pref_joystick");
+
+	// hide translation settings floater
+	LLFloaterReg::hideInstance("prefs_translation");
 	
 	// cancel hardware menu
 	LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance<LLFloaterHardwareSettings>("prefs_hardware_settings");
 	LLFloaterReg::showInstance("prefs_proxy");
 }
 
+void LLFloaterPreference::onClickTranslationSettings()
+{
+	LLFloaterReg::showInstance("prefs_translation");
+}
+
 void LLFloaterPreference::onClickActionChange()
 {
 	mClickActionDirty = true;

File indra/newview/llfloaterpreference.h

 	void onChangeMaturity();
 	void onClickBlockList();
 	void onClickProxySettings();
+	void onClickTranslationSettings();
 	void applyUIColor(LLUICtrl* ctrl, const LLSD& param);
 	void getUIColor(LLUICtrl* ctrl, const LLSD& param);
 	

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/llfloatertranslationsettings.cpp

+/** 
+ * @file llfloatertranslationsettings.cpp
+ * @brief Machine translation settings for chat
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfloatertranslationsettings.h"
+
+// Viewer includes
+#include "lltranslate.h"
+#include "llviewercontrol.h" // for gSavedSettings
+
+// Linden library includes
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llcombobox.h"
+#include "llfloaterreg.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "llradiogroup.h"
+
+class EnteredKeyVerifier : public LLTranslate::KeyVerificationReceiver
+{
+public:
+	EnteredKeyVerifier(LLTranslate::EService service, bool alert)
+	:	LLTranslate::KeyVerificationReceiver(service)
+	,	mAlert(alert)
+	{
+	}
+
+private:
+	/*virtual*/ void setVerificationStatus(bool ok)
+	{
+		LLFloaterTranslationSettings* floater =
+			LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation");
+
+		if (!floater)
+		{
+			llwarns << "Cannot find translation settings floater" << llendl;
+			return;
+		}
+
+		switch (getService())
+		{
+		case LLTranslate::SERVICE_BING:
+			floater->setBingVerified(ok, mAlert);
+			break;
+		case LLTranslate::SERVICE_GOOGLE:
+			floater->setGoogleVerified(ok, mAlert);
+			break;
+		}
+	}
+
+	bool mAlert;
+};
+
+LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key)
+:	LLFloater(key)
+,	mMachineTranslationCB(NULL)
+,	mLanguageCombo(NULL)
+,	mTranslationServiceRadioGroup(NULL)
+,	mBingAPIKeyEditor(NULL)
+,	mGoogleAPIKeyEditor(NULL)
+,	mBingVerifyBtn(NULL)
+,	mGoogleVerifyBtn(NULL)
+,	mOKBtn(NULL)
+,	mBingKeyVerified(false)
+,	mGoogleKeyVerified(false)
+{
+}
+
+// virtual
+BOOL LLFloaterTranslationSettings::postBuild()
+{
+	mMachineTranslationCB = getChild<LLCheckBoxCtrl>("translate_chat_checkbox");
+	mLanguageCombo = getChild<LLComboBox>("translate_language_combo");
+	mTranslationServiceRadioGroup = getChild<LLRadioGroup>("translation_service_rg");
+	mBingAPIKeyEditor = getChild<LLLineEditor>("bing_api_key");
+	mGoogleAPIKeyEditor = getChild<LLLineEditor>("google_api_key");
+	mBingVerifyBtn = getChild<LLButton>("verify_bing_api_key_btn");
+	mGoogleVerifyBtn = getChild<LLButton>("verify_google_api_key_btn");
+	mOKBtn = getChild<LLButton>("ok_btn");
+
+	mMachineTranslationCB->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
+	mTranslationServiceRadioGroup->setCommitCallback(boost::bind(&LLFloaterTranslationSettings::updateControlsEnabledState, this));
+	mOKBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnOK, this));
+	getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloater::closeFloater, this, false));
+	mBingVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnBingVerify, this));
+	mGoogleVerifyBtn->setClickedCallback(boost::bind(&LLFloaterTranslationSettings::onBtnGoogleVerify, this));
+
+	mBingAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+	mBingAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onBingKeyEdited, this), NULL);
+	mGoogleAPIKeyEditor->setFocusReceivedCallback(boost::bind(&LLFloaterTranslationSettings::onEditorFocused, this, _1));
+	mGoogleAPIKeyEditor->setKeystrokeCallback(boost::bind(&LLFloaterTranslationSettings::onGoogleKeyEdited, this), NULL);
+
+	center();
+	return TRUE;
+}
+
+// virtual
+void LLFloaterTranslationSettings::onOpen(const LLSD& key)
+{
+	mMachineTranslationCB->setValue(gSavedSettings.getBOOL("TranslateChat"));
+	mLanguageCombo->setSelectedByValue(gSavedSettings.getString("TranslateLanguage"), TRUE);
+	mTranslationServiceRadioGroup->setSelectedByValue(gSavedSettings.getString("TranslationService"), TRUE);
+
+	std::string bing_key = gSavedSettings.getString("BingTranslateAPIKey");
+	if (!bing_key.empty())
+	{
+		mBingAPIKeyEditor->setText(bing_key);
+		mBingAPIKeyEditor->setTentative(FALSE);
+		verifyKey(LLTranslate::SERVICE_BING, bing_key, false);
+	}
+	else
+	{
+		mBingAPIKeyEditor->setTentative(TRUE);
+		mBingKeyVerified = FALSE;
+	}
+
+	std::string google_key = gSavedSettings.getString("GoogleTranslateAPIKey");
+	if (!google_key.empty())
+	{
+		mGoogleAPIKeyEditor->setText(google_key);
+		mGoogleAPIKeyEditor->setTentative(FALSE);
+		verifyKey(LLTranslate::SERVICE_GOOGLE, google_key, false);
+	}
+	else
+	{
+		mGoogleAPIKeyEditor->setTentative(TRUE);
+		mGoogleKeyVerified = FALSE;
+	}
+
+	updateControlsEnabledState();
+}
+
+void LLFloaterTranslationSettings::setBingVerified(bool ok, bool alert)
+{
+	if (alert)
+	{
+		showAlert(ok ? "bing_api_key_verified" : "bing_api_key_not_verified");
+	}
+
+	mBingKeyVerified = ok;