Kent Quirk avatar Kent Quirk committed 7092702 Merge

Set hotfix build params for Release.

Comments (0)

Files changed (755)

doc/contributions.txt

 	CT-317
 	CT-352
 Aimee Trescothick
-	VWR-1813
 	VWR-3321
 	VWR-3336
 	VWR-3903
 	VWR-4083
+	VWR-4106
 	VWR-6348
 	VWR-6358
 	VWR-6360
 	VWR-11100
 	VWR-11111
 	VWR-11844
+	VWR-12631
+	VWR-12696
+	VWR-12748
+	VWR-14087
 	VWR-14267
 	VWR-14278
-	VWR-14087
 Alejandro Rosenthal
 	VWR-1184
 Aleric Inglewood

indra/llaudio/llaudioengine.cpp

 
 	if (buffer_id >= 0)
 	{
-		llinfos << "Taking over unused buffer " << buffer_id << llendl;
+		lldebugs << "Taking over unused buffer " << buffer_id << llendl;
 		//llinfos << "Flushing unused buffer!" << llendl;
 		mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL;
 		delete mBuffers[buffer_id];

indra/llcommon/llcursortypes.cpp

 		cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE;
 		cursor_string_table["UI_CURSOR_TOOLMEDIAOPEN"] = UI_CURSOR_TOOLMEDIAOPEN;
 		cursor_string_table["UI_CURSOR_PIPETTE"] = UI_CURSOR_PIPETTE;
+		cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT;
+		cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY;
+		cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN;
 	}
 
 	std::map<std::string,U32>::const_iterator iter = cursor_string_table.find(cursor_string);

indra/llcommon/llcursortypes.h

 	UI_CURSOR_TOOLPAUSE,
 	UI_CURSOR_TOOLMEDIAOPEN,
 	UI_CURSOR_PIPETTE,
+	UI_CURSOR_TOOLSIT,
+	UI_CURSOR_TOOLBUY,
+	UI_CURSOR_TOOLOPEN,
 	UI_CURSOR_COUNT			// Number of elements in this enum (NOT a cursor)
 };
 

indra/llcommon/llsys.cpp

 #endif
 }
 
-S32 LLDisplayInfo::getDisplayWidth() const
-{
-#if LL_WINDOWS
-	return  ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
-#elif LL_DARWIN
-	return 1024; //*FIXME
-#elif LL_SOLARIS
-	return 1024; //*FIXME
-#else
-	return 1024; //*FIXME
-#endif
-}
-
-S32 LLDisplayInfo::getDisplayHeight() const
-{
-#if LL_WINDOWS
-	return  ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
-#elif LL_DARWIN
-	return 768; //*FIXME
-#elif LL_SOLARIS
-	return 768; //*FIXME
-#else
-	return 768; //*FIXME
-#endif
-}
-
-
 std::ostream& operator<<(std::ostream& s, const LLOSInfo& info)
 {
 	info.stream(s);

indra/llcommon/llsys.h

 	U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes
 };
 
-//=============================================================================
-//
-//	CLASS		LLDisplayInfo
-class LL_COMMON_API LLDisplayInfo
-
-/*!	@brief		Class to query the information about some display settings
-*/
-{
-public:
-	LLDisplayInfo(){}; ///< Default constructor
-
-	S32 getDisplayWidth() const; ///< display width
-	S32 getDisplayHeight() const; ///< display height
-	
-};
 
 LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLOSInfo& info);
 LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info);

indra/llcommon/llworkerthread.cpp

 			{
 				mRequestHandle = LLWorkerThread::nullHandle();
 				clearFlags(WCF_HAVE_WORK);
-				return true ;
 			}
 			else
 			{
 				llassert_always(workreq);
 			}
+			return true ;
 		}
 
 		LLQueuedThread::status_t status = workreq->getStatus();

indra/llimage/llimage.cpp

 			llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
 		}
 	}
-	else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE))
+	if (size < 1 || (size > 4096*4096*16 && sSizeOverride == FALSE))
 	{
+		llinfos << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << llendl ;
 		llerrs << "LLImageBase::allocateData: bad size: " << size << llendl;
 	}
 	

indra/llmessage/llinstantmessage.cpp

 const S32 EMPTY_BINARY_BUCKET_SIZE = 1;
 const U32 NO_TIMESTAMP = 0;
 const std::string SYSTEM_FROM("Second Life");
+const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B");
 const S32 IM_TTL = 1;
 
 

indra/llmessage/llinstantmessage.h

 
 extern const U32 NO_TIMESTAMP;
 extern const std::string SYSTEM_FROM;
+extern const std::string INTERACTIVE_SYSTEM_FROM;
 
 // Number of retry attempts on sending the im.
 extern const S32 IM_TTL;

indra/llmessage/lltemplatemessagebuilder.cpp

 			       << "(" << size << ").  Clamping size and truncating data." << llendl;
 			size = 255;
 			char *truncate = (char *)data;
-			truncate[255] = 0;
+			truncate[254] = 0; // array size is 255 but the last element index is 254
 		}
 
 		// no correct size for MVT_VARIABLE, instead we need to tell how many bytes the size will be encoded as

indra/llmessage/lltemplatemessagereader.cpp

 
 inline void LLTemplateMessageReader::getString(const char *block, const char *var, std::string& outstr, S32 blocknum )
 {
-	char s[MTUBYTES];
-	s[0] = '\0';
+	char s[MTUBYTES + 1]= {0}; // every element is initialized with 0
 	getData(block, var, s, 0, blocknum, MTUBYTES);
-	s[MTUBYTES - 1] = '\0';
+	s[MTUBYTES] = '\0';
 	outstr = s;
 }
 

indra/llplugin/llpluginclassmedia.cpp

 	reset();
 }
 
-bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
+bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
 {	
 	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
 	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-	LL_DEBUGS("Plugin") << "user_data_path: " << user_data_path << LL_ENDL;
 	
 	mPlugin = new LLPluginProcessParent(this);
 	mPlugin->setSleepTime(mSleepTime);
-	mPlugin->init(launcher_filename, plugin_filename, debug, user_data_path);
+	
+	// Queue up the media init message -- it will be sent after all the currently queued messages.
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
+	sendMessage(message);
+	
+	mPlugin->init(launcher_filename, plugin_filename, debug);
 
 	return true;
 }
 	sendMessage(message);
 }
 
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
+	message.setValue("path", user_data_path);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
+	message.setValue("language", language_code);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
 LLPluginClassMedia::ETargetType getTargetTypeFromLLQtWebkit(int target_type)
 {
 	// convert a LinkTargetType value from llqtwebkit to an ETargetType
 void LLPluginClassMedia::enable_cookies(bool enable)
 {
 	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
+	message.setValueBoolean("enable", enable);
 	sendMessage(message);
 }
 

indra/llplugin/llpluginclassmedia.h

 	virtual ~LLPluginClassMedia();
 
 	// local initialization, called by the media manager when creating a source
-	virtual bool init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path);
+	virtual bool init(const std::string &launcher_filename, 
+					  const std::string &plugin_filename, 
+					  bool debug);
 
 	// undoes everything init() didm called by the media manager when destroying a source
 	virtual void reset();
 
 	void	paste();
 	bool	canPaste() const { return mCanPaste; };
+	
+	// These can be called before init(), and they will be queued and sent before the media init message.
+	void	setUserDataPath(const std::string &user_data_path);
+	void	setLanguageCode(const std::string &language_code);
+	void	setPluginsEnabled(const bool enabled);
+	void	setJavascriptEnabled(const bool enabled);
 		
 	///////////////////////////////////
 	// media browser class functions

indra/llplugin/llpluginprocesschild.cpp

 				{
 					setState(STATE_PLUGIN_INITIALIZING);
 					LLPluginMessage message("base", "init");
-					message.setValue("user_data_path", mUserDataPath);
 					sendMessageToPlugin(message);
 				}
 			break;
 			if(message_name == "load_plugin")
 			{
 				mPluginFile = parsed.getValue("file");
-				mUserDataPath = parsed.getValue("user_data_path");
 			}
 			else if(message_name == "shm_add")
 			{

indra/llplugin/llpluginprocesschild.h

 	
 	std::string mPluginFile;
 
-	std::string mUserDataPath;
-	
 	LLPluginInstance *mInstance;
 
 	typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;

indra/llplugin/llpluginprocessparent.cpp

 		setState(STATE_ERROR);
 }
 
-void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
+void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug)
 {	
 	mProcess.setExecutable(launcher_filename);
 	mPluginFile = plugin_filename;
 	mCPUUsage = 0.0f;
-	mDebug = debug;
-	mUserDataPath = user_data_path;
-	
+	mDebug = debug;	
 	setState(STATE_INITIALIZED);
 }
 
 				{
 					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
 					message.setValue("file", mPluginFile);
-					message.setValue("user_data_path", mUserDataPath);
 					sendMessage(message);
 				}
 

indra/llplugin/llpluginprocessparent.h

 	LLPluginProcessParent(LLPluginProcessParentOwner *owner);
 	~LLPluginProcessParent();
 		
-	void init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path);
+	void init(const std::string &launcher_filename, 
+			  const std::string &plugin_filename, 
+			  bool debug);
+
 	void idle(void);
 	
 	// returns true if the plugin is on its way to steady state
 	
 	std::string mPluginFile;
 
-	std::string mUserDataPath;
-
 	LLPluginProcessParentOwner *mOwner;
 	
 	typedef std::map<std::string, LLPluginSharedMemory*> sharedMemoryRegionsType;

indra/llrender/llfontgl.cpp

 	target_x *= sScaleX;
 
 	// max_chars is S32_MAX by default, so make sure we don't get overflow
-	const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars);
+	const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1);
 
 	F32 scaled_max_pixels =	max_pixels * sScaleX;
 	

indra/llrender/llfontregistry.cpp

 			else
 			{
 				fontlist.push_back(fontp->mFontFreetype);
+				delete fontp;
+				fontp = NULL;
 			}
 		}
 	}

indra/llui/llbutton.h

 	void			setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
 	void 			setImageOverlay(const LLUUID& image_id, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);
 	LLPointer<LLUIImage> getImageOverlay() { return mImageOverlay; }
-
+	LLFontGL::HAlign getImageOverlayHAlign() const	{ return mImageOverlayAlignment; }
+	
 	void            autoResize();	// resize with label of current btn state 
 	void            resize(LLUIString label); // resize with label input
 	void			setLabel( const LLStringExplicit& label);

indra/llui/llcombobox.cpp

 		LLScrollListItem* item = mList->getFirstSelected();
 		if (item)
 		{
-			setLabel( mList->getSelectedItemLabel() );
+			setLabel(getSelectedItemLabel());
 		}
 		mLastSelectedIndex = mList->getFirstSelectedIndex();
 	}
+	else
+	{
+		mLastSelectedIndex = -1;
+	}
 }
 
 const std::string LLComboBox::getSimple() const
 {
-	const std::string res = mList->getSelectedItemLabel();
+	const std::string res = getSelectedItemLabel();
 	if (res.empty() && mAllowTextEntry)
 	{
 		return mTextEntry->getText();
 	if (index < mList->getItemCount())
 	{
 		mList->deleteSingleItem(index);
-		setLabel(mList->getSelectedItemLabel());
+		setLabel(getSelectedItemLabel());
 		return TRUE;
 	}
 	return FALSE;
 	BOOL found = mList->selectNthItem( index );
 	if (found)
 	{
-		setLabel(mList->getSelectedItemLabel());
+		setLabel(getSelectedItemLabel());
 		mLastSelectedIndex = index;
 	}
 	return found;
 
 void LLComboBox::onItemSelected(const LLSD& data)
 {
-	const std::string name = mList->getSelectedItemLabel();
-
-	S32 cur_id = getCurrentIndex();
-	mLastSelectedIndex = cur_id;
-	if (cur_id != -1)
+	mLastSelectedIndex = getCurrentIndex();
+	if (mLastSelectedIndex != -1)
 	{
-		setLabel(name);
+		setLabel(getSelectedItemLabel());
 
 		if (mAllowTextEntry)
-	{
-		gFocusMgr.setKeyboardFocus(mTextEntry);
-		mTextEntry->selectAll();
+		{
+			gFocusMgr.setKeyboardFocus(mTextEntry);
+			mTextEntry->selectAll();
+		}
 	}
-	}
-
 	// hiding the list reasserts the old value stored in the text editor/dropdown button
 	hideList();
 
 	}
 	else if (mList->selectItemByPrefix(left_wstring, FALSE))
 	{
-		LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
+		LLWString selected_item = utf8str_to_wstring(getSelectedItemLabel());
 		LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
 		mTextEntry->setText(wstring_to_utf8str(wtext));
 		mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
 
 	if (found)
 	{
-		setLabel(mList->getSelectedItemLabel());
+		setLabel(getSelectedItemLabel());
 		mLastSelectedIndex = mList->getFirstSelectedIndex();
 	}
 
 	BOOL found = mList->setSelectedByValue(value, selected);
 	if (found)
 	{
-		setLabel(mList->getSelectedItemLabel());
+		setLabel(getSelectedItemLabel());
 	}
 	return found;
 }
 {
 	return mList->selectItemRange(first, last);
 }
+
+
+static LLDefaultChildRegistry::Register<LLIconsComboBox> register_icons_combo_box("icons_combo_box");
+
+LLIconsComboBox::Params::Params()
+:	icon_column("icon_column", ICON_COLUMN),
+	label_column("label_column", LABEL_COLUMN)
+{}
+
+LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p)
+:	LLComboBox(p),
+	mIconColumnIndex(p.icon_column),
+	mLabelColumnIndex(p.label_column)
+{}
+
+const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const
+{
+	mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign());
+
+	return LLComboBox::getSelectedItemLabel(mLabelColumnIndex);
+}

indra/llui/llcombobox.h

 	// Get name of current item. Returns an empty string if not found.
 	const std::string	getSimple() const;
 	// Get contents of column x of selected row
-	const std::string getSelectedItemLabel(S32 column = 0) const;
+	virtual const std::string getSelectedItemLabel(S32 column = 0) const;
 
 	// Sets the label, which doesn't have to exist in the label.
 	// This is probably a UI abuse.
 	commit_callback_t	mPrearrangeCallback;
 	commit_callback_t	mTextEntryCallback;
 	commit_callback_t	mSelectionCallback;
-	boost::signals2::connection mTopLostSignalConnection;
-	S32                 mLastSelectedIndex;
+        boost::signals2::connection mTopLostSignalConnection;
+    S32					mLastSelectedIndex;
 };
+
+// A combo box with icons for the list of items.
+class LLIconsComboBox
+:	public LLComboBox
+{
+public:
+	struct Params
+	:	public LLInitParam::Block<Params, LLComboBox::Params>
+	{
+		Optional<S32>		icon_column,
+							label_column;
+		Params();
+	};
+
+	/*virtual*/ const std::string getSelectedItemLabel(S32 column = 0) const;
+
+private:
+	enum EColumnIndex
+	{
+		ICON_COLUMN = 0,
+		LABEL_COLUMN
+	};
+
+	friend class LLUICtrlFactory;
+	LLIconsComboBox(const Params&);
+	virtual ~LLIconsComboBox() {};
+
+	S32			mIconColumnIndex;
+	S32			mLabelColumnIndex;
+};
+
 #endif

indra/llui/llflatlistview.cpp

 {
 	if (!item_pair) return;
 
+	if (!item_pair->first) 
+	{
+		llwarning("Attempt to selet an item pair containing null panel item", 0);
+		return;
+	}
+
 	setFocus(TRUE);
 	
 	bool select_item = !isSelected(item_pair);

indra/llui/llmultifloater.cpp

 		if (floater && floater->canClose() && floater->isCloseable())
 		{
 			floater->closeFloater();
+
+			// EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
+			// bring back focus on tab container if there are any tab left
+			if(mTabContainer->getTabCount() > 0)
+			{
+				mTabContainer->setFocus(TRUE);
+			}
 		}
 		return TRUE;
 	}

indra/llui/llnotifications.cpp

 	mRespondedTo(false),
 	mPriority(p.priority),
 	mCancelled(false),
-	mIgnored(false)
+	mIgnored(false),
+	mResponderObj(NULL),
+	mIsReusable(false)
 {
 	if (p.functor.name.isChosen())
 	{
 		mTemporaryResponder = true;
 	}
 
+	if(p.responder.isProvided())
+	{
+		mResponderObj = p.responder;
+	}
+
 	mId.generate();
 	init(p.name, p.form_elements);
 }
 	mTemporaryResponder(false),
 	mRespondedTo(false),
 	mCancelled(false),
-	mIgnored(false)
+	mIgnored(false),
+	mResponderObj(NULL),
+	mIsReusable(false)
 { 
 	mId.generate();
 	mSubstitutions = sd["substitutions"];
 	output["expiry"] = mExpiresAt;
 	output["priority"] = (S32)mPriority;
 	output["responseFunctor"] = mResponseFunctorName;
+	output["reusable"] = mIsReusable;
 	return output;
 }
 
 	mForm = other->mForm;
 	mResponseFunctorName = other->mResponseFunctorName;
 	mRespondedTo = other->mRespondedTo;
+	mResponse = other->mResponse;
 	mTemporaryResponder = other->mTemporaryResponder;
+	mIsReusable = other->isReusable();
 
 	update();
 }
 
 void LLNotification::respond(const LLSD& response)
 {
+	// *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo()
 	mRespondedTo = true;
+	mResponse = response;
 	// look up the functor
 	LLNotificationFunctorRegistry::ResponseFunctor functor = 
 		LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName);
 	// and then call it
 	functor(asLLSD(), response);
 	
-	if (mTemporaryResponder)
+	if (mTemporaryResponder && !isReusable())
 	{
 		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
 		mResponseFunctorName = "";
 	mTemporaryResponder = false;
 }
 
+void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb)
+{
+	if(mTemporaryResponder)
+	{
+		LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
+	}
+
+	LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb);
+}
+
 bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const
 {
 	for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); 
 		if (wasFound)
 		{
 			abortProcessing = mChanged(payload);
-			mItems.erase(pNotification);
-			onDelete(pNotification);
+			// do not delete the notification to make LLChatHistory::appendMessage add notification panel to IM window
+			if( ! pNotification->isReusable() )
+			{
+				mItems.erase(pNotification);
+				onDelete(pNotification);
+			}
 		}
 	}
 	return abortProcessing;

indra/llui/llnotifications.h

 		Optional<LLSD>							form_elements;
 		Optional<LLDate>						time_stamp;
 		Optional<LLNotificationContext*>		context;
+		Optional<void*>							responder;
 
 		struct Functor : public LLInitParam::Choice<Functor>
 		{
 			form_elements("form_elements")
 		{
 			time_stamp = LLDate::now();
+			responder = NULL;
 		}
 
 		Params(const std::string& _name) 
 			functor.name = _name;
 			name = _name;
 			time_stamp = LLDate::now();
+			responder = NULL;
 		}
 	};
 
 	LLDate mExpiresAt;
 	bool mCancelled;
 	bool mRespondedTo; 	// once the notification has been responded to, this becomes true
+	LLSD mResponse;
 	bool mIgnored;
 	ENotificationPriority mPriority;
 	LLNotificationFormPtr mForm;
+	void* mResponderObj;
+	bool mIsReusable;
 	
 	// a reference to the template
 	LLNotificationTemplatePtr mTemplatep;
 
 	void setResponseFunctor(std::string const &responseFunctorName);
 
+	void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb);
+
 	typedef enum e_response_template_type
 	{
 		WITHOUT_DEFAULT_BUTTON,
 
 	void respond(const LLSD& sd);
 
+	void* getResponder() { return mResponderObj; }
+
+	void setResponder(void* responder) { mResponderObj = responder; }
+
 	void setIgnored(bool ignore);
 
 	bool isCancelled() const
 		return mRespondedTo;
 	}
 
+	const LLSD& getResponse() { return mResponse; }
+
 	bool isIgnored() const
 	{
 		return mIgnored;
 	{
 		return mId;
 	}
+
+	bool isReusable() { return mIsReusable; }
+
+	void setReusable(bool reusable) { mIsReusable = reusable; }
 	
 	// comparing two notifications normally means comparing them by UUID (so we can look them
 	// up quickly this way)

indra/llui/llradiogroup.cpp

 
 void LLRadioGroup::initFromParams(const Params& p)
 {
-	LLUICtrl::initFromParams(p);
 	for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
 		it != p.items().end();
 		++it)
 		LLRadioCtrl* item = LLUICtrlFactory::create<LLRadioCtrl>(item_params, this);
 		mRadioButtons.push_back(item);
 	}
+
+	// call this *after* setting up mRadioButtons so we can handle setValue() calls
+	LLUICtrl::initFromParams(p);
 }
 
 
 	{
 		mRadioButtons[0]->setTabStop(true);
 	}
-	if (mControlVariable)
-	{
-		setSelectedIndex(mControlVariable->getValue().asInteger());
-	}
 	return TRUE;
 }
 

indra/llui/llsearcheditor.h

 		}
 	};
 
+	void setCommitOnFocusLost(BOOL b)	{ if (mSearchEditor) mSearchEditor->setCommitOnFocusLost(b); }
+
 protected:
 	LLSearchEditor(const Params&);
 	friend class LLUICtrlFactory;

indra/llui/lltextbase.cpp

 					S32 segment_line_start = segmentp->getStart() + segment_offset;
 					S32 segment_line_end = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd);
 
+					if (segment_line_start > segment_line_end) break;
+
 					S32 segment_width = 0;
 					S32 segment_height = 0;
 
 						selection_rect.mLeft += segment_width;
 					}
 
-					// if selection spans end of current segment...
-					if (selection_right > segment_line_end)
+					// if selection_right == segment_line_end then that means we are the first character of the next segment
+					// or first character of the next line, in either case we want to add the length of the current segment
+					// to the selection rectangle and continue.
+					// if selection right > segment_line_end then selection spans end of current segment...
+					if (selection_right >= segment_line_end)
 					{
 						// extend selection slightly beyond end of line
 						// to indicate selection of newline character (use "n" character to determine width)
 		const LLTextSegmentPtr segmentp = *line_seg_iter;
 
 		S32 segment_line_start = segmentp->getStart() + line_seg_offset;
-		S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd - 1) - segment_line_start;
+		S32 segment_line_length = llmin(segmentp->getEnd(), line_iter->mDocIndexEnd) - segment_line_start;
 		S32 text_width, text_height;
-		segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height);
-		if (local_x < start_x + text_width						// cursor to left of right edge of text
-			|| (hit_past_end_of_line && (segmentp->getEnd() >= line_iter->mDocIndexEnd - 1)))	// or this segment wraps to next line
+		bool newline = segmentp->getDimensions(line_seg_offset, segment_line_length, text_width, text_height);
+
+		// if we've reached a line of text *below* the mouse cursor, doc index is first character on that line
+		if (hit_past_end_of_line && local_y - mVisibleTextRect.mBottom + visible_region.mBottom > line_iter->mRect.mTop)
+		{
+			pos = segment_line_start;
+			break;
+		}
+		if (local_x < start_x + text_width			// cursor to left of right edge of text
+			|| newline)								// or this line ends with a newline, set doc pos to newline char
 		{
 			// Figure out which character we're nearest to.
 			S32 offset;
 			pos = segment_line_start + offset;
 			break;
 		}
+		else if (hit_past_end_of_line && segmentp->getEnd() >= line_iter->mDocIndexEnd - 1)	
+		{
+			// segment wraps to next line, so just set doc pos to start of next line (represented by mDocIndexEnd)
+			pos = llmin(getLength(), line_iter->mDocIndexEnd);
+			break;
+		}
+
 		start_x += text_width;
 	}
 

File contents unchanged.

indra/llui/llurlentry.cpp

 							boost::regex::perl|boost::regex::icase);
 	mMenuName = "menu_url_agent.xml";
 	mIcon = "Generic_Person";
-	mTooltip = LLTrans::getString("TooltipAgentUrl");
 	mColor = LLUIColorTable::instance().getColor("AgentLinkColor");
 }
 
 	callObservers(id.asString(), first + " " + last);
 }
 
+std::string LLUrlEntryAgent::getTooltip(const std::string &string) const
+{
+	// return a tooltip corresponding to the URL type instead of the generic one
+	std::string url = getUrl(string);
+
+	if (LLStringUtil::endsWith(url, "/mute"))
+	{
+		return LLTrans::getString("TooltipAgentMute");
+	}
+	if (LLStringUtil::endsWith(url, "/unmute"))
+	{
+		return LLTrans::getString("TooltipAgentUnmute");
+	}
+	if (LLStringUtil::endsWith(url, "/im"))
+	{
+		return LLTrans::getString("TooltipAgentIM");
+	}
+	if (LLStringUtil::endsWith(url, "/pay"))
+	{
+		return LLTrans::getString("TooltipAgentPay");