diff options
| author | Steve Bennetts <steve@lindenlab.com> | 2009-11-23 20:11:02 -0800 | 
|---|---|---|
| committer | Steve Bennetts <steve@lindenlab.com> | 2009-11-23 20:11:02 -0800 | 
| commit | 8de68b4a58df9882a39872a873d4d0b78b433682 (patch) | |
| tree | 0fc6e002f4be34b5fd58b997a86f7221f10121ab | |
| parent | db1631e4c0986a07cb9290ff4e910ba1d15f5fe9 (diff) | |
| parent | 9135bb7b0f7d194b8ffc0db3374a7e882fe39a94 (diff) | |
Merge from product-engine
33 files changed, 1174 insertions, 147 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e8302ab5eb..611875a1e2 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -239,6 +239,7 @@ set(viewer_SOURCE_FILES      llhudtext.cpp      llhudview.cpp      llimfloater.cpp +    llimfloatercontainer.cpp      llimhandler.cpp      llimpanel.cpp      llimview.cpp @@ -364,6 +365,7 @@ set(viewer_SOURCE_FILES      llremoteparcelrequest.cpp      llsavedsettingsglue.cpp      llscreenchannel.cpp +    llscriptfloater.cpp      llscrollingpanelparam.cpp      llsearchcombobox.cpp      llsearchhistory.cpp @@ -737,6 +739,7 @@ set(viewer_HEADER_FILES      llhudtext.h      llhudview.h      llimfloater.h +    llimfloatercontainer.h      llimpanel.h      llimview.h      llinspect.h @@ -860,6 +863,7 @@ set(viewer_HEADER_FILES      llrootview.h      llsavedsettingsglue.h      llscreenchannel.h +    llscriptfloater.h      llscrollingpanelparam.h      llsearchcombobox.h      llsearchhistory.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c7279a2e33..1eca897ea5 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5371,6 +5371,19 @@        <key>Value</key>        <real>1.0</real>      </map> +     +   <key>PlainTextChatHistory</key> +    <map> +      <key>Comment</key> +      <string>Enable/Disable plain text chat history style</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +          <key>PluginInstancesLow</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 0844cca766..a133bd6fe6 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -347,9 +347,9 @@ void LLAvatarActions::inviteToGroup(const LLUUID& id)  	LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance<LLFloaterGroupPicker>("group_picker", LLSD(id));  	if (widget)  	{ -		widget->removeNoneOption();  		widget->center();  		widget->setPowersMask(GP_MEMBER_INVITE); +		widget->removeNoneOption();  		widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, id));  	}  } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 4ce3b50ed5..422aae3c25 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -334,20 +334,14 @@ LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style  	return header;  } -void LLChatHistory::appendWidgetMessage(const LLChat& chat, const LLStyle::Params& input_append_params) +void LLChatHistory::clear()  { -	LLView* view = NULL; -	std::string view_text = "\n[" + chat.mTimeStr + "] "; -	if (utf8str_trim(chat.mFromName).size() != 0 && chat.mFromName != SYSTEM_FROM) -		view_text += chat.mFromName + ": "; - - -	LLInlineViewSegment::Params p; -	p.force_newline = true; -	p.left_pad = mLeftWidgetPad; -	p.right_pad = mRightWidgetPad; +	mLastFromName.clear(); +	LLTextEditor::clear(); +} -	 +void LLChatHistory::appendMessage(const LLChat& chat, const bool use_plain_text_chat_history, const LLStyle::Params& input_append_params) +{  	LLColor4 txt_color = LLUIColorTable::instance().getColor("White");  	LLViewerChat::getChatColor(chat,txt_color);  	LLFontGL* fontp = LLViewerChat::getChatFont();	 @@ -360,39 +354,63 @@ void LLChatHistory::appendWidgetMessage(const LLChat& chat, const LLStyle::Param  	style_params.font.size(font_size);	  	style_params.font.style(input_append_params.font.style); - +	std::string header_text = "[" + chat.mTimeStr + "] "; +	if (utf8str_trim(chat.mFromName).size() != 0 && chat.mFromName != SYSTEM_FROM) +		header_text += chat.mFromName + ": "; -	if (mLastFromName == chat.mFromName) +	if (use_plain_text_chat_history)  	{ -		view = getSeparator(); -		p.top_pad = mTopSeparatorPad; -		p.bottom_pad = mBottomSeparatorPad; +		appendText(header_text, getText().size() != 0, style_params);  	}  	else  	{ -		view = getHeader(chat,style_params); -		if (getText().size() == 0) -			p.top_pad = 0; +		LLView* view = NULL; +		LLInlineViewSegment::Params p; +		p.force_newline = true; +		p.left_pad = mLeftWidgetPad; +		p.right_pad = mRightWidgetPad; + +		if (mLastFromName == chat.mFromName) +		{ +			view = getSeparator(); +			p.top_pad = mTopSeparatorPad; +			p.bottom_pad = mBottomSeparatorPad; +		}  		else -			p.top_pad = mTopHeaderPad; -		p.bottom_pad = mBottomHeaderPad; -		 +		{ +			view = getHeader(chat, style_params); +			if (getText().size() == 0) +				p.top_pad = 0; +			else +				p.top_pad = mTopHeaderPad; +			p.bottom_pad = mBottomHeaderPad; +			 +		} +		p.view = view; + +		//Prepare the rect for the view +		LLRect target_rect = getDocumentView()->getRect(); +		// squeeze down the widget by subtracting padding off left and right +		target_rect.mLeft += mLeftWidgetPad + mHPad; +		target_rect.mRight -= mRightWidgetPad; +		view->reshape(target_rect.getWidth(), view->getRect().getHeight()); +		view->setOrigin(target_rect.mLeft, view->getRect().mBottom); + +		appendWidget(p, header_text, false); +		mLastFromName = chat.mFromName;  	} -	p.view = view; - -	//Prepare the rect for the view -	LLRect target_rect = getDocumentView()->getRect(); -	// squeeze down the widget by subtracting padding off left and right -	target_rect.mLeft += mLeftWidgetPad + mHPad; -	target_rect.mRight -= mRightWidgetPad; -	view->reshape(target_rect.getWidth(), view->getRect().getHeight()); -	view->setOrigin(target_rect.mLeft, view->getRect().mBottom); - -	appendWidget(p, view_text, false); - -	//Append the text message -	appendText(chat.mText, FALSE, style_params); +	//Handle IRC styled /me messages. +	std::string prefix = chat.mText.substr(0, 4); +	if (prefix == "/me " || prefix == "/me'") +	{ +		style_params.font.style = "ITALIC"; -	mLastFromName = chat.mFromName; +		if (chat.mFromName.size() > 0) +			appendText(chat.mFromName + " ", TRUE, style_params); +		appendText(chat.mText.substr(4), FALSE, style_params); +	} +	else +		appendText(chat.mText, FALSE, style_params);  	blockUndo();  } + diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index c89d4b4ec6..ef5839ff2f 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -106,10 +106,11 @@ class LLChatHistory : public LLTextEditor  		 * If last user appended message, concurs with current user,  		 * separator is added before the message, otherwise header is added.  		 * @param chat - base chat message. -		 * @param time time of a message. -		 * @param message message itself. +		 * @param use_plain_text_chat_history  - whether to add message as plain text. +		 * @param input_append_params - font style.  		 */ -		void appendWidgetMessage(const LLChat& chat, const LLStyle::Params& input_append_params = LLStyle::Params()); +		void appendMessage(const LLChat& chat, const bool use_plain_text_chat_history = false, const LLStyle::Params& input_append_params = LLStyle::Params()); +		/*virtual*/ void clear();  	private:  		std::string mLastFromName; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 6a5877f673..433f70700c 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -43,6 +43,7 @@  #include "lllocalcliprect.h"  #include "llmenugl.h"  #include "lloutputmonitorctrl.h" +#include "llscriptfloater.h"  #include "lltextbox.h"  #include "llvoiceclient.h"  #include "llvoicecontrolpanel.h" @@ -55,6 +56,7 @@ static LLDefaultChildRegistry::Register<LLNotificationChiclet> t2("chiclet_notif  static LLDefaultChildRegistry::Register<LLIMP2PChiclet> t3("chiclet_im_p2p");  static LLDefaultChildRegistry::Register<LLIMGroupChiclet> t4("chiclet_im_group");  static LLDefaultChildRegistry::Register<LLAdHocChiclet> t5("chiclet_im_adhoc"); +static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");  static const LLRect CHICLET_RECT(0, 25, 25, 0);  static const LLRect CHICLET_ICON_RECT(0, 22, 22, 0); @@ -1411,3 +1413,51 @@ LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p)   : LLOutputMonitorCtrl(p)  {  } + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLScriptChiclet::Params::Params() + : icon("icon") +{ +	// *TODO Vadim: Get rid of hardcoded values. + 	rect(CHICLET_RECT); +	icon.rect(CHICLET_ICON_RECT); +} + +LLScriptChiclet::LLScriptChiclet(const Params&p) + : LLIMChiclet(p) + , mChicletIconCtrl(NULL) +{ +	LLIconCtrl::Params icon_params = p.icon; +	mChicletIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params); +	// Let "new message" icon be on top, else it will be hidden behind chiclet icon. +	addChildInBack(mChicletIconCtrl); +} + +void LLScriptChiclet::setSessionId(const LLUUID& session_id) +{ +	setShowNewMessagesIcon( getSessionId() != session_id ); + +	LLIMChiclet::setSessionId(session_id); +	LLUUID notification_id = LLScriptFloaterManager::getInstance()->findNotificationId(session_id); +	LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id); +	if(notification) +	{ +		setToolTip(notification->getSubstitutions()["TITLE"].asString()); +	} +} + +void LLScriptChiclet::onMouseDown() +{ +	LLScriptFloaterManager::getInstance()->toggleScriptFloater(getSessionId()); +} + +BOOL LLScriptChiclet::handleMouseDown(S32 x, S32 y, MASK mask) +{ +	onMouseDown(); +	return LLChiclet::handleMouseDown(x, y, mask); +} + +// EOF diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 03935d21a6..1ea141e6c4 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -534,6 +534,46 @@ private:  };  /** + * Chiclet for script floaters. + */ +class LLScriptChiclet : public LLIMChiclet +{ +public: + +	struct Params : public LLInitParam::Block<Params, LLIMChiclet::Params> +	{ +		Optional<LLIconCtrl::Params> icon; + +		Params(); +	}; + +	/*virtual*/ void setSessionId(const LLUUID& session_id); + +	/*virtual*/ void setCounter(S32 counter){} + +	/*virtual*/ S32 getCounter() { return 0; } + +	/** +	 * Toggle script floater +	 */ +	/*virtual*/ void onMouseDown(); + +	/** +	 * Override default handler +	 */ +	/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + +protected: + +	LLScriptChiclet(const Params&); +	friend class LLUICtrlFactory; + +private: + +	LLIconCtrl* mChicletIconCtrl; +}; + +/**   * Implements Group chat chiclet.   */  class LLIMGroupChiclet : public LLIMChiclet, public LLGroupMgrObserver diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 6d2c35442a..e20249a737 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -56,6 +56,7 @@  #include "llfloaterabout.h"  #include "llfloaterhardwaresettings.h"  #include "llfloatervoicedevicesettings.h" +#include "llimfloater.h"  #include "llkeyboard.h"  #include "llmodaldialog.h"  #include "llnavigationbar.h" @@ -357,6 +358,8 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)  BOOL LLFloaterPreference::postBuild()  { +	gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&LLIMFloater::processChatHistoryStyleUpdate, _2)); +  	LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");  	if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab")))  		tabcontainer->selectFirstTab(); @@ -458,6 +461,8 @@ void LLFloaterPreference::apply()  //	LLWString busy_response = utf8str_to_wstring(getChild<LLUICtrl>("busy_response")->getValue().asString());  //	LLWStringUtil::replaceTabsWithSpaces(busy_response, 4); + +	gSavedSettings.setBOOL("PlainTextChatHistory", childGetValue("plain_text_chat_history").asBoolean());  	if(mGotPersonalInfo)  	{  @@ -1186,6 +1191,8 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im  	childSetLabelArg("online_visibility", "[DIR_VIS]", mDirectoryVisibility);  	childEnable("send_im_to_email");  	childSetValue("send_im_to_email", im_via_email); +	childEnable("plain_text_chat_history"); +	childSetValue("plain_text_chat_history", gSavedSettings.getBOOL("PlainTextChatHistory"));  	childEnable("log_instant_messages");  //	childEnable("log_chat");  //	childEnable("busy_response"); diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 4a487bd5a7..795770d3db 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -53,6 +53,10 @@  #include "lltransientfloatermgr.h"  #include "llinventorymodel.h" +#ifdef USE_IM_CONTAINER +	#include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container +#endif +  LLIMFloater::LLIMFloater(const LLUUID& session_id) @@ -106,10 +110,10 @@ void LLIMFloater::onFocusReceived()  // virtual  void LLIMFloater::onClose(bool app_quitting)  { +	if (!gIMMgr->hasSession(mSessionID)) return; +	  	setTyping(false); -	// SJB: We want the close button to hide the session window, not end it -	// *NOTE: Yhis is functional, but not ideal - it's still closing the floater; we really want to change the behavior of the X button instead. -	//gIMMgr->leaveSession(mSessionID); +	gIMMgr->leaveSession(mSessionID);  }  /* static */ @@ -257,7 +261,11 @@ BOOL LLIMFloater::postBuild()  	//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"  	//see LLFloaterIMPanel for how it is done (IB) +#ifdef USE_IM_CONTAINER +	return LLFloater::postBuild(); +#else  	return LLDockableFloater::postBuild(); +#endif  }  // virtual @@ -318,6 +326,11 @@ void LLIMFloater::onSlide()  //static  LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  { +#ifdef USE_IM_CONTAINER +	LLIMFloater* target_floater = findInstance(session_id); +	bool not_existed = NULL == target_floater; + +#else  	//hide all  	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel");  	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); @@ -329,12 +342,25 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  			floater->setVisible(false);  		}  	} +#endif  	LLIMFloater* floater = LLFloaterReg::showTypedInstance<LLIMFloater>("impanel", session_id);  	floater->updateMessages();  	floater->mInputEditor->setFocus(TRUE); +#ifdef USE_IM_CONTAINER +	// do not add existed floaters to avoid adding torn off instances +	if (not_existed) +	{ +		//		LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; +		// TODO: mantipov: use LLTabContainer::RIGHT_OF_CURRENT if it exists +		LLTabContainer::eInsertionPoint i_pt = LLTabContainer::END; + +		LLIMFloaterContainer* floater_container = LLFloaterReg::showTypedInstance<LLIMFloaterContainer>("im_container"); +		floater_container->addFloater(floater, TRUE, i_pt); +	} +#else  	if (floater->getDockControl() == NULL)  	{  		LLChiclet* chiclet = @@ -352,13 +378,14 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  		floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(),  				LLDockControl::TOP,  boost::bind(&LLIMFloater::getAllowedRect, floater, _1)));  	} +#endif  	return floater;  }  void LLIMFloater::getAllowedRect(LLRect& rect)  { -	rect = gViewerWindow->getWorldViewRectScaled(); +	rect = gViewerWindow->getWorldViewRectRaw();  }  void LLIMFloater::setDocked(bool docked, bool pop_on_undock) @@ -368,7 +395,9 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock)  		(LLNotificationsUI::LLChannelManager::getInstance()->  											findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); +#ifndef USE_IM_CONTAINER  	LLTransientDockableFloater::setDocked(docked, pop_on_undock); +#endif  	// update notification channel state  	if(channel) @@ -394,6 +423,7 @@ void LLIMFloater::setVisible(BOOL visible)  //static  bool LLIMFloater::toggle(const LLUUID& session_id)  { +#ifndef USE_IM_CONTAINER  	LLIMFloater* floater = LLFloaterReg::findTypedInstance<LLIMFloater>("impanel", session_id);  	if (floater && floater->getVisible() && floater->isDocked())  	{ @@ -409,6 +439,7 @@ bool LLIMFloater::toggle(const LLUUID& session_id)  		return true;  	}  	else +#endif  	{  		// ensure the list of messages is updated when floater is made visible  		show(session_id); @@ -451,6 +482,8 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)  void LLIMFloater::updateMessages()  { +	bool use_plain_text_chat_history = gSavedSettings.getBOOL("PlainTextChatHistory"); +  	std::list<LLSD> messages;  	LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1); @@ -476,39 +509,7 @@ void LLIMFloater::updateMessages()  			chat.mText = message;  			chat.mTimeStr = time; -			//Handle IRC styled /me messages. -			std::string prefix = message.substr(0, 4); -			if (prefix == "/me " || prefix == "/me'") -			{ -				 -				LLColor4 txt_color = LLUIColorTable::instance().getColor("White"); -				LLViewerChat::getChatColor(chat,txt_color); -				LLFontGL* fontp = LLViewerChat::getChatFont(); -				std::string font_name = LLFontGL::nameFromFont(fontp); -				std::string font_size = LLFontGL::sizeFromFont(fontp); -				LLStyle::Params append_style_params; -				append_style_params.color(txt_color); -				append_style_params.readonly_color(txt_color); -				append_style_params.font.name(font_name); -				append_style_params.font.size(font_size); -				 -				if (from.size() > 0) -				{ -					append_style_params.font.style = "ITALIC"; -					chat.mText = from; -					mChatHistory->appendWidgetMessage(chat, append_style_params); -				} -				 -				message = message.substr(3); -				append_style_params.font.style = "ITALIC"; -				mChatHistory->appendText(message, FALSE, append_style_params); -			} -			else -			{ -				chat.mText = message; -				mChatHistory->appendWidgetMessage(chat); -			} - +			mChatHistory->appendMessage(chat, use_plain_text_chat_history);  			mLastMessageIndex = msg["index"].asInteger();  		}  	} @@ -639,6 +640,28 @@ void LLIMFloater::processAgentListUpdates(const LLSD& body)  	}  } +void LLIMFloater::updateChatHistoryStyle() +{ +	mChatHistory->clear(); +	mLastMessageIndex = -1; +	updateMessages(); +} + +void LLIMFloater::processChatHistoryStyleUpdate(const LLSD& newvalue) +{ +	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel"); +	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); +		 iter != inst_list.end(); ++iter) +	{ +		LLIMFloater* floater = dynamic_cast<LLIMFloater*>(*iter); +		if (floater) +		{ +			floater->updateChatHistoryStyle(); +		} +	} + +} +  void LLIMFloater::processSessionUpdate(const LLSD& session_update)  {  	// *TODO : verify following code when moderated mode will be implemented diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index e2d500d821..9e1330ff49 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -33,6 +33,11 @@  #ifndef LL_IMFLOATER_H  #define LL_IMFLOATER_H +// This variable is used to show floaters related to chiclets in a Multi Floater Container +// So, this functionality does not require to have IM Floaters as Dockable & Transient +// See EXT-2640. +#define USE_IM_CONTAINER +  #include "lltransientdockablefloater.h"  #include "lllogchat.h"  #include "lltooldraganddrop.h" @@ -92,6 +97,9 @@ public:  	void processAgentListUpdates(const LLSD& body);  	void processSessionUpdate(const LLSD& session_update); +	void updateChatHistoryStyle(); +	static void processChatHistoryStyleUpdate(const LLSD& newvalue); +  	BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,  							   BOOL drop, EDragAndDropType cargo_type,  							   void *cargo_data, EAcceptance *accept, diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp new file mode 100644 index 0000000000..6e4b3ae214 --- /dev/null +++ b/indra/newview/llimfloatercontainer.cpp @@ -0,0 +1,96 @@ +/** 
 + * @file llimfloatercontainer.cpp
 + * @brief Multifloater containing active IM sessions in separate tab container tabs
 + *
 + * $LicenseInfo:firstyear=2009&license=viewergpl$
 + * 
 + * Copyright (c) 2009, Linden Research, Inc.
 + * 
 + * Second Life Viewer Source Code
 + * The source code in this file ("Source Code") is provided by Linden Lab
 + * to you under the terms of the GNU General Public License, version 2.0
 + * ("GPL"), unless you have obtained a separate licensing agreement
 + * ("Other License"), formally executed by you and Linden Lab.  Terms of
 + * the GPL can be found in doc/GPL-license.txt in this distribution, or
 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 + * 
 + * There are special exceptions to the terms and conditions of the GPL as
 + * it is applied to this Source Code. View the full text of the exception
 + * in the file doc/FLOSS-exception.txt in this software distribution, or
 + * online at
 + * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 + * 
 + * By copying, modifying or distributing this software, you acknowledge
 + * that you have read and understood your obligations described above,
 + * and agree to abide by those obligations.
 + * 
 + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 + * COMPLETENESS OR PERFORMANCE.
 + * $/LicenseInfo$
 + */
 +
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "llimfloatercontainer.h"
 +
 +//
 +// LLIMFloaterContainer
 +//
 +LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
 +:	LLMultiFloater(seed),
 +	mActiveVoiceFloater(NULL)
 +{
 +	mAutoResize = FALSE;
 +}
 +
 +LLIMFloaterContainer::~LLIMFloaterContainer()
 +{
 +}
 +
 +BOOL LLIMFloaterContainer::postBuild()
 +{
 +	// 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;
 +}
 +
 +void LLIMFloaterContainer::onOpen(const LLSD& key)
 +{
 +	LLMultiFloater::onOpen(key);
 +/*
 +	if (key.isDefined())
 +	{
 +		LLIMFloater* im_floater = LLIMFloater::findInstance(key.asUUID());
 +		if (im_floater)
 +		{
 +			im_floater->openFloater();
 +		}
 +	}
 +*/
 +}
 +
 +void LLIMFloaterContainer::addFloater(LLFloater* floaterp, 
 +									BOOL select_added_floater, 
 +									LLTabContainer::eInsertionPoint insertion_point)
 +{
 +	if(!floaterp) return;
 +
 +	// already here
 +	if (floaterp->getHost() == this)
 +	{
 +		openFloater(floaterp->getKey());
 +		return;
 +	}
 +
 +	LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point);
 +
 +	// make sure active voice icon shows up for new tab
 +	if (floaterp == mActiveVoiceFloater)
 +	{
 +		mTabContainer->setTabImage(floaterp, "active_voice_tab.tga");	
 +	}
 +}
 +
 +// EOF
 diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h new file mode 100644 index 0000000000..10cde56c6e --- /dev/null +++ b/indra/newview/llimfloatercontainer.h @@ -0,0 +1,61 @@ +/** 
 + * @file llimfloatercontainer.h
 + * @brief Multifloater containing active IM sessions in separate tab container tabs
 + *
 + * $LicenseInfo:firstyear=2009&license=viewergpl$
 + * 
 + * Copyright (c) 2009, Linden Research, Inc.
 + * 
 + * Second Life Viewer Source Code
 + * The source code in this file ("Source Code") is provided by Linden Lab
 + * to you under the terms of the GNU General Public License, version 2.0
 + * ("GPL"), unless you have obtained a separate licensing agreement
 + * ("Other License"), formally executed by you and Linden Lab.  Terms of
 + * the GPL can be found in doc/GPL-license.txt in this distribution, or
 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 + * 
 + * There are special exceptions to the terms and conditions of the GPL as
 + * it is applied to this Source Code. View the full text of the exception
 + * in the file doc/FLOSS-exception.txt in this software distribution, or
 + * online at
 + * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 + * 
 + * By copying, modifying or distributing this software, you acknowledge
 + * that you have read and understood your obligations described above,
 + * and agree to abide by those obligations.
 + * 
 + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 + * COMPLETENESS OR PERFORMANCE.
 + * $/LicenseInfo$
 + */
 +
 +#ifndef LL_LLIMFLOATERCONTAINER_H
 +#define LL_LLIMFLOATERCONTAINER_H
 +
 +#include "llfloater.h"
 +#include "llmultifloater.h"
 +
 +class LLTabContainer;
 +
 +class LLIMFloaterContainer : public LLMultiFloater
 +{
 +public:
 +	LLIMFloaterContainer(const LLSD& seed);
 +	virtual ~LLIMFloaterContainer();
 +	
 +	/*virtual*/ BOOL postBuild();
 +	/*virtual*/ void onOpen(const LLSD& key);
 +
 +	/*virtual*/ void addFloater(LLFloater* floaterp, 
 +								BOOL select_added_floater, 
 +								LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
 +
 +	static LLFloater* getCurrentVoiceFloater();
 +	
 +protected:
 +	
 +	LLFloater* mActiveVoiceFloater;
 +};
 +
 +#endif // LL_LLIMFLOATERCONTAINER_H
 diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 7e35cfa04c..9aefbcbbb0 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -188,7 +188,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)  	params.rect(text_entry_rect);  	params.default_text(LLStringUtil::null);  	params.max_length_bytes(p.max_chars); -	params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));  	params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));  	params.handle_edit_keys_directly(true);  	params.commit_on_focus_lost(false); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 114d26af8a..c032d01d2f 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -172,7 +172,8 @@ LLNavigationBar::LLNavigationBar()  	mBtnHome(NULL),  	mCmbLocation(NULL),  	mSearchComboBox(NULL), -	mPurgeTPHistoryItems(false) +	mPurgeTPHistoryItems(false), +	mSaveToLocationHistory(false)  {  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_navigation_bar.xml"); @@ -186,6 +187,7 @@ LLNavigationBar::LLNavigationBar()  LLNavigationBar::~LLNavigationBar()  {  	mTeleportFinishConnection.disconnect(); +	mTeleportFailedConnection.disconnect();  }  BOOL LLNavigationBar::postBuild() @@ -220,6 +222,12 @@ BOOL LLNavigationBar::postBuild()  	mSearchComboBox->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); +	mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> +		setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1)); + +	mTeleportFailedConnection = LLViewerParcelMgr::getInstance()-> +		setTeleportFailedCallback(boost::bind(&LLNavigationBar::onTeleportFailed, this)); +	  	mDefaultNbRect = getRect();  	mDefaultFpRect = getChild<LLFavoritesBarCtrl>("favorite")->getRect(); @@ -395,15 +403,19 @@ void LLNavigationBar::onLocationSelection()  	LLWorldMapMessage::url_callback_t cb = boost::bind(  			&LLNavigationBar::onRegionNameResponse, this,  			typed_location, region_name, local_coords, _1, _2, _3, _4); -	// connect the callback each time, when user enter new location to get real location of agent after teleport -	mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> -			setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1,typed_location)); +	mSaveToLocationHistory = true;  	LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);  } -void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location) +void LLNavigationBar::onTeleportFailed()  { -	// Location is valid. Add it to the typed locations history. +	mSaveToLocationHistory = false; +} + +void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos) +{ +	if (!mSaveToLocationHistory) +		return;  	LLLocationHistory* lh = LLLocationHistory::getInstance();  	//TODO*: do we need convert surl into readable format? @@ -426,8 +438,7 @@ void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, con  	lh->save(); -	if(mTeleportFinishConnection.connected()) -		mTeleportFinishConnection.disconnect(); +	mSaveToLocationHistory = false;  } diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 52f5a827e4..cd3ba08db3 100644 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -81,7 +81,8 @@ private:  	void onLocationSelection();  	void onLocationPrearrange(const LLSD& data);  	void onSearchCommit(); -	void onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location); +	void onTeleportFinished(const LLVector3d& global_agent_pos); +	void onTeleportFailed();  	void onRegionNameResponse(  			std::string typed_location,  			std::string region_name, @@ -99,8 +100,11 @@ private:  	LLLocationInputCtrl*		mCmbLocation;  	LLRect						mDefaultNbRect;  	LLRect						mDefaultFpRect; +	boost::signals2::connection	mTeleportFailedConnection;  	boost::signals2::connection	mTeleportFinishConnection;  	bool						mPurgeTPHistoryItems; +	// if true, save location to location history when teleport finishes +	bool						mSaveToLocationHistory;  };  #endif diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 09fd9b2949..80a6cc343f 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -173,7 +173,7 @@ void	LLNearbyChat::addMessage(const LLChat& chat)  				append_style_params.font.style = "ITALIC";  				LLChat add_chat=chat;  				add_chat.mText = chat.mFromName + " "; -				mChatHistory->appendWidgetMessage(add_chat, append_style_params); +				mChatHistory->appendMessage(add_chat, false, append_style_params);  			}  			message = message.substr(3); @@ -182,7 +182,7 @@ void	LLNearbyChat::addMessage(const LLChat& chat)  		}  		else  		{ -			mChatHistory->appendWidgetMessage(chat); +			mChatHistory->appendMessage(chat);  		}  	}  } diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 4be98201d1..f01f2e4441 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -38,9 +38,13 @@  #include "llviewercontrol.h"  #include "llviewerwindow.h"  #include "llnotificationmanager.h" +#include "llscriptfloater.h"  using namespace LLNotificationsUI; +static const std::string SCRIPT_DIALOG				("ScriptDialog"); +static const std::string SCRIPT_DIALOG_GROUP		("ScriptDialogGroup"); +  //--------------------------------------------------------------------------  LLScriptHandler::LLScriptHandler(e_notification_type type, const LLSD& id)  { @@ -90,25 +94,40 @@ bool LLScriptHandler::processNotification(const LLSD& notify)  	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")  	{ -		LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification); - -		LLToast::Params p; -		p.notif_id = notification->getID(); -		p.notification = notification; -		p.panel = notify_box;	 -		p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1); - -		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); -		if(channel) -			channel->addToast(p); - -		// send a signal to the counter manager -		mNewNotificationSignal(); - +		if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) +		{ +			LLScriptFloaterManager::getInstance()->onAddNotification(notification->getID()); +		} +		else +		{ +			LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification); + +			LLToast::Params p; +			p.notif_id = notification->getID(); +			p.notification = notification; +			p.panel = notify_box;	 +			p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1); + +			LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); +			if(channel) +			{ +				channel->addToast(p); +			} + +			// send a signal to the counter manager +			mNewNotificationSignal(); +		}  	}  	else if (notify["sigtype"].asString() == "delete")  	{ -		mChannel->killToastByNotificationID(notification->getID()); +		if(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) +		{ +			LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID()); +		} +		else +		{ +			mChannel->killToastByNotificationID(notification->getID()); +		}  	}  	return true;  } @@ -123,6 +142,14 @@ void LLScriptHandler::onDeleteToast(LLToast* toast)  	// send a signal to a listener to let him perform some action  	// in this case listener is a SysWellWindow and it will remove a corresponding item from its list  	mNotificationIDSignal(toast->getNotificationID()); + +	LLNotificationPtr notification = LLNotifications::getInstance()->find(toast->getNotificationID()); +	 +	if( notification &&  +		(SCRIPT_DIALOG == notification->getName() || SCRIPT_DIALOG_GROUP == notification->getName()) ) +	{ +		LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID()); +	}  }  //-------------------------------------------------------------------------- diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 10b419dfdb..e24fa14e1e 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -67,6 +67,27 @@ static const std::string TRASH_BUTTON_NAME = "trash_btn";  // helper functions  static void filter_list(LLInventorySubTreePanel* inventory_list, const std::string& string); +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLandmarksPanelObserver +// +// Bridge to support knowing when the inventory has changed to update +// landmarks accordions visibility. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLandmarksPanelObserver : public LLInventoryObserver +{ +public: +	LLLandmarksPanelObserver(LLLandmarksPanel* lp) : mLP(lp) {} +	virtual ~LLLandmarksPanelObserver() {} +	/*virtual*/ void changed(U32 mask); + +private: +	LLLandmarksPanel* mLP; +}; + +void LLLandmarksPanelObserver::changed(U32 mask) +{ +	mLP->updateFilteredAccordions(); +}  LLLandmarksPanel::LLLandmarksPanel()  	:	LLPanelPlacesTab() @@ -80,11 +101,16 @@ LLLandmarksPanel::LLLandmarksPanel()  	,	mGearLandmarkMenu(NULL)  	,	mDirtyFilter(false)  { +	mInventoryObserver = new LLLandmarksPanelObserver(this); +	gInventory.addObserver(mInventoryObserver); +  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");  }  LLLandmarksPanel::~LLLandmarksPanel()  { +	if (gInventory.containsObserver(mInventoryObserver)) +		gInventory.removeObserver(mInventoryObserver);  }  BOOL LLLandmarksPanel::postBuild() @@ -135,8 +161,14 @@ void LLLandmarksPanel::onSearchEdit(const std::string& string)  		LLAccordionCtrlTab* tab = *iter;  		tab->setVisible(true); -		// expand accordion to see matched items in all ones. See EXT-2014. +		// expand accordion to see matched items in each one. See EXT-2014.  		tab->changeOpenClose(false); + +		// refresh all accordions to display their contents in case of less restrictive filter +		LLInventorySubTreePanel* inventory_list = dynamic_cast<LLInventorySubTreePanel*>(tab->getAccordionView()); +		if (NULL == inventory_list) continue; +		LLFolderView* fv = inventory_list->getRootFolder(); +		fv->refresh();  	}  } @@ -223,6 +255,31 @@ void LLLandmarksPanel::onSelectorButtonClicked()  	}  } +void LLLandmarksPanel::updateFilteredAccordions() +{ +	LLInventoryPanel* inventory_list = NULL; +	LLAccordionCtrlTab* accordion_tab = NULL; +	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) +	{ +		accordion_tab = *iter; +		inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView()); +		if (NULL == inventory_list) continue; +		LLFolderView* fv = inventory_list->getRootFolder(); + +		bool has_descendants = fv->hasFilteredDescendants(); + +		accordion_tab->setVisible(has_descendants); +	} + +	// we have to arrange accordion tabs for cases when filter string is less restrictive but +	// all items are still filtered. +	static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); +	accordion->arrange(); + +	// now filter state is applied to accordion tabs +	mDirtyFilter = false; +} +  //////////////////////////////////////////////////////////////////////////  // PROTECTED METHODS  ////////////////////////////////////////////////////////////////////////// @@ -833,31 +890,6 @@ void LLLandmarksPanel::doIdle(void* landmarks_panel)  } -void LLLandmarksPanel::updateFilteredAccordions() -{ -	LLInventoryPanel* inventory_list = NULL; -	LLAccordionCtrlTab* accordion_tab = NULL; -	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) -	{ -		accordion_tab = *iter; -		inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView()); -		if (NULL == inventory_list) continue; -		LLFolderView* fv = inventory_list->getRootFolder(); - -		bool has_visible_children = fv->hasVisibleChildren(); - -		accordion_tab->setVisible(has_visible_children); -	} - -	// we have to arrange accordion tabs for cases when filter string is less restrictive but  -	// all items are still filtered. -	static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); -	accordion->arrange(); - -	// now filter state is applied to accordion tabs -	mDirtyFilter = false; -} -  void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark)  {  	LLVector3d landmark_global_pos; diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 777ee562d2..c65abc178b 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -46,6 +46,7 @@ class LLAccordionCtrlTab;  class LLFolderViewItem;  class LLMenuGL;  class LLInventoryPanel; +class LLInventoryObserver;  class LLInventorySubTreePanel;  class LLLandmarksPanel : public LLPanelPlacesTab, LLRemoteParcelInfoObserver @@ -62,7 +63,14 @@ public:  	void onSelectionChange(LLInventorySubTreePanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action);  	void onSelectorButtonClicked(); -	 + +	/** +	 * Updates accordions according to filtered items in lists. +	 * +	 * It hides accordion for empty lists +	 */ +	void updateFilteredAccordions(); +  protected:  	/**  	 * @return true - if current selected panel is not null and selected item is a landmark @@ -122,13 +130,6 @@ private:  	static void doIdle(void* landmarks_panel);  	/** -	 * Updates accordions according to filtered items in lists. -	 * -	 * It hides accordion for empty lists -	 */ -	void updateFilteredAccordions(); - -	/**  	 * Landmark actions callbacks. Fire when a landmark is loaded from the list.  	 */  	void doShowOnMap(LLLandmark* landmark); @@ -147,6 +148,7 @@ private:  	LLMenuGL*					mGearFolderMenu;  	LLMenuGL*					mMenuAdd;  	LLInventorySubTreePanel*	mCurrentSelectedList; +	LLInventoryObserver*		mInventoryObserver;  	LLPanel*					mListCommands;  	bool 						mSortByDate; diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 24505f6bd6..fb9db42cf6 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -46,6 +46,7 @@  #include "lldockablefloater.h"  #include "llsyswellwindow.h"  #include "llimfloater.h" +#include "llscriptfloater.h"  #include <algorithm> @@ -686,7 +687,8 @@ void LLScreenChannel::updateShowToastsState()  	}  	// for IM floaters showed in a docked state - prohibit showing of ani toast -	if(dynamic_cast<LLIMFloater*>(floater)) +	if(dynamic_cast<LLIMFloater*>(floater) +		|| dynamic_cast<LLScriptFloater*>(floater) )  	{  		setShowToasts(!(floater->getVisible() && floater->isDocked()));  		if (!getShowToasts()) diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp new file mode 100644 index 0000000000..bdea6ff459 --- /dev/null +++ b/indra/newview/llscriptfloater.cpp @@ -0,0 +1,335 @@ +/**  + * @file llscriptfloater.cpp + * @brief LLScriptFloater class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llscriptfloater.h" + +#include "llbottomtray.h" +#include "llchannelmanager.h" +#include "llchiclet.h" +#include "llfloaterreg.h" +#include "llscreenchannel.h" +#include "lltoastnotifypanel.h" +#include "llviewerwindow.h" + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLUUID notification_id_to_object_id(const LLUUID& notification_id) +{ +	LLNotificationPtr notification = LLNotifications::getInstance()->find(notification_id); +	if(notification) +	{ +		return notification->getPayload()["object_id"].asUUID(); +	} +	return LLUUID::null; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLScriptFloater::LLScriptFloater(const LLSD& key) +: LLTransientDockableFloater(NULL, true, key) +, mScriptForm(NULL) +, mObjectId(key.asUUID()) +{ +} + +bool LLScriptFloater::toggle(const LLUUID& object_id) +{ +	LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", object_id); + +	// show existing floater +	if(floater) +	{ +		if(floater->getVisible()) +		{ +			floater->setVisible(false); +			return false; +		} +		else +		{ +			floater->setVisible(TRUE); +			floater->setFocus(TRUE); +			return true; +		} +	} +	// create and show new floater +	else +	{ +		show(object_id); +		return true; +	} +} + +LLScriptFloater* LLScriptFloater::show(const LLUUID& object_id) +{ +	LLScriptFloater* floater = LLFloaterReg::showTypedInstance<LLScriptFloater>("script_floater", object_id); +	floater->createForm(object_id); + +	if (floater->getDockControl() == NULL) +	{ +		LLChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLChiclet>(object_id); +		if (chiclet == NULL) +		{ +			llerror("Dock chiclet for LLScriptFloater doesn't exist", 0); +		} +		else +		{ +			LLBottomTray::getInstance()->getChicletPanel()->scrollToChiclet(chiclet); +		} + +		floater->setDockControl(new LLDockControl(chiclet, floater, floater->getDockTongue(), +			LLDockControl::TOP,  boost::bind(&LLScriptFloater::getAllowedRect, floater, _1))); +	} + +	return floater; +} + +void LLScriptFloater::getAllowedRect(LLRect& rect) +{ +	rect = gViewerWindow->getWorldViewRectRaw(); +} + +void LLScriptFloater::createForm(const LLUUID& object_id) +{ +	// delete old form +	if(mScriptForm) +	{ +		removeChild(mScriptForm); +		mScriptForm->die(); +	} + +	LLNotificationPtr notification = LLNotifications::getInstance()->find( +		LLScriptFloaterManager::getInstance()->findNotificationId(object_id)); +	if(NULL == notification) +	{ +		return; +	} + +	// create new form +	mScriptForm = new LLToastNotifyPanel(notification); +	addChild(mScriptForm); + +	// position form on floater +	mScriptForm->setOrigin(0, 0); + +	// make floater size fit form size +	LLRect toast_rect = getRect(); +	LLRect panel_rect = mScriptForm->getRect(); +	toast_rect.setLeftTopAndSize(toast_rect.mLeft, toast_rect.mTop, panel_rect.getWidth(), panel_rect.getHeight() + getHeaderHeight()); +	setShape(toast_rect); +} + +void LLScriptFloater::onClose(bool app_quitting) +{ +	LLScriptFloaterManager::getInstance()->removeNotificationByObjectId(getObjectId()); +} + +void LLScriptFloater::setDocked(bool docked, bool pop_on_undock /* = true */) +{ +	LLTransientDockableFloater::setDocked(docked, pop_on_undock); + +	hideToastsIfNeeded(); +} + +void LLScriptFloater::setVisible(BOOL visible) +{ +	LLTransientDockableFloater::setVisible(visible); + +	hideToastsIfNeeded(); +} + +void LLScriptFloater::hideToastsIfNeeded() +{ +	using namespace LLNotificationsUI; + +	// find channel +	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID( +		LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); +	// update notification channel state +	if(channel) +	{ +		channel->updateShowToastsState(); +	} +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id) +{ +	// get scripted Object's ID +	LLUUID object_id = notification_id_to_object_id(notification_id); +	if(object_id.isNull()) +	{ +		llwarns << "Invalid notification, no object id" << llendl; +		return; +	} + +	// If an Object spawns more-than-one floater, only the newest one is shown.  +	// The previous is automatically closed. +	script_notification_map_t::iterator it = mNotifications.find(object_id); +	if(it != mNotifications.end()) +	{ +		onRemoveNotification(notification_id); +	} + +	LLNotificationData nd = {notification_id}; +	mNotifications.insert(std::make_pair(object_id, nd)); + +	LLBottomTray::getInstance()->getChicletPanel()->createChiclet<LLScriptChiclet>(object_id); +} + +void LLScriptFloaterManager::onRemoveNotification(const LLUUID& notification_id) +{ +	LLUUID object_id = notification_id_to_object_id(notification_id); +	if(object_id.isNull()) +	{ +		llwarns << "Invalid notification, no object id" << llendl; +		return; +	} + +	using namespace LLNotificationsUI; + +	// remove related toast +	LLUUID channel_id(gSavedSettings.getString("NotificationChannelUUID")); +	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*> +		(LLChannelManager::getInstance()->findChannelByID(channel_id)); +	if(channel) +	{ +		channel->killToastByNotificationID(findNotificationToastId(object_id)); +	} + +	mNotifications.erase(object_id); + +	// remove related chiclet +	LLBottomTray::getInstance()->getChicletPanel()->removeChiclet(object_id); + +	// close floater +	LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", object_id); +	if(floater) +	{ +		floater->closeFloater(); +	} +} + +void LLScriptFloaterManager::removeNotificationByObjectId(const LLUUID& object_id) +{ +	// Check we have not removed notification yet +	LLNotificationPtr notification = LLNotifications::getInstance()->find( +		findNotificationId(object_id)); +	if(notification) +	{ +		onRemoveNotification(notification->getID()); +	} +} + +void LLScriptFloaterManager::toggleScriptFloater(const LLUUID& object_id) +{ +	// hide "new message" icon from chiclet +	LLIMChiclet* chiclet = LLBottomTray::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(object_id); +	if(chiclet) +	{ +		chiclet->setShowNewMessagesIcon(false); +	} + +	// kill toast +	using namespace LLNotificationsUI; +	LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(LLChannelManager::getInstance()->findChannelByID( +		LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); +	if(channel) +	{ +		channel->killToastByNotificationID(findNotificationToastId(object_id)); +	} + +	// toggle floater +	LLScriptFloater::toggle(object_id); +} + +void LLScriptFloaterManager::setNotificationToastId(const LLUUID& object_id, const LLUUID& notification_id) +{ +	script_notification_map_t::iterator it = mNotifications.find(object_id); +	if(mNotifications.end() != it) +	{ +		it->second.toast_notification_id = notification_id; +	} +} + +LLUUID LLScriptFloaterManager::findNotificationId(const LLUUID& object_id) +{ +	script_notification_map_t::const_iterator it = mNotifications.find(object_id); +	if(mNotifications.end() != it) +	{ +		return it->second.notification_id; +	} +	return LLUUID::null; +} + +LLUUID LLScriptFloaterManager::findNotificationToastId(const LLUUID& object_id) +{ +	script_notification_map_t::const_iterator it = mNotifications.find(object_id); +	if(mNotifications.end() != it) +	{ +		return it->second.toast_notification_id; +	} +	return LLUUID::null; +} + +//static +void LLScriptFloaterManager::onToastButtonClick(const LLSD¬ification, const LLSD&response) +{ +	S32 option = LLNotification::getSelectedOption(notification, response); +	LLUUID object_id = notification["payload"]["object_id"].asUUID(); + +	switch(option) +	{ +	case 0: // "Open" +		LLScriptFloaterManager::getInstance()->toggleScriptFloater(object_id); +		break; +	case 1: // "Ignore" +		LLScriptFloaterManager::getInstance()->removeNotificationByObjectId(object_id); +		break; +	case 2: // "Block" +		LLMuteList::getInstance()->add(LLMute(object_id, notification["substitutions"]["TITLE"], LLMute::OBJECT)); +		LLScriptFloaterManager::getInstance()->removeNotificationByObjectId(object_id); +		break; +	default: +		llwarns << "Unexpected value" << llendl; +		break; +	} +} + +// EOF diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h new file mode 100644 index 0000000000..0e1a7f36b7 --- /dev/null +++ b/indra/newview/llscriptfloater.h @@ -0,0 +1,164 @@ +/**  + * @file llscriptfloater.h + * @brief LLScriptFloater class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_SCRIPTFLOATER_H +#define LL_SCRIPTFLOATER_H + +#include "lltransientdockablefloater.h" + +class LLToastNotifyPanel; + +/** + * Handles script notifications ("ScriptDialog" and "ScriptDialogGroup") + * and manages Script Floaters. + */ +class LLScriptFloaterManager : public LLSingleton<LLScriptFloaterManager> +{ +public: + +	/** +	 * Handles new notifications. +	 * Saves notification and object ids, removes old notification if needed, creates script chiclet +	 * Note that one object can spawn one script floater. +	 */ +	void onAddNotification(const LLUUID& notification_id); + +	/** +	 * Handles notification removal. +	 * Removes script notification toast, removes script chiclet, closes script floater +	 */ +	void onRemoveNotification(const LLUUID& notification_id); + +	/** +	 * Wrapper for onRemoveNotification, removes notification by object id. +	 */ +	void removeNotificationByObjectId(const LLUUID& object_id); + +	/** +	 * Toggles script floater. +	 * Removes "new message" icon from chiclet and removes notification toast. +	 */ +	void toggleScriptFloater(const LLUUID& object_id); + +	LLUUID findNotificationId(const LLUUID& object_id); + +	LLUUID findNotificationToastId(const LLUUID& object_id); + +	/** +	 * Associate notification toast id with object id. +	 */ +	void setNotificationToastId(const LLUUID& object_id, const LLUUID& notification_id); + +	/** +	* Callback for notification toast buttons. +	*/ +	static void onToastButtonClick(const LLSD¬ification, const LLSD&response); + +private: + +	struct LLNotificationData +	{ +		LLUUID notification_id; +		LLUUID toast_notification_id; +	}; + +	// <object_id, notification_data> +	typedef std::map<LLUUID, LLNotificationData> script_notification_map_t; + +	script_notification_map_t mNotifications; +}; + +/** + * Floater script forms. + * LLScriptFloater will create script form based on notification data and  + * will auto fit the form. + */ +class LLScriptFloater : public LLTransientDockableFloater +{ +public: + +	/** +	 * key - UUID of scripted Object +	 */ +	LLScriptFloater(const LLSD& key); + +	virtual ~LLScriptFloater(){}; + +	/** +	 * Toggle existing floater or create and show a new one. +	 */ +	static bool toggle(const LLUUID& object_id); + +	/** +	 * Creates and shows floater +	 */ +	static LLScriptFloater* show(const LLUUID& object_id); + +	const LLUUID& getObjectId() { return mObjectId; } + +	/** +	 * Close notification if script floater is closed. +	 */ +	/*virtual*/ void onClose(bool app_quitting); + +	/** +	 * Hide all notification toasts when we show dockable floater +	 */ +	/*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + +	/** +	 * Hide all notification toasts when we show dockable floater +	 */ +	/*virtual*/ void setVisible(BOOL visible); + +protected: + +	/** +	 * Creates script form, will delete old form if floater is shown for same object. +	 */ +	void createForm(const LLUUID& object_id); + +	/*virtual*/ void getAllowedRect(LLRect& rect); + +	/** +	 * Hide all notification toasts. +	 */ +	static void hideToastsIfNeeded(); + +	void setObjectId(const LLUUID& id) { mObjectId = id; } + +private: +	LLToastNotifyPanel* mScriptForm; +	LLUUID mObjectId; +}; + +#endif //LL_SCRIPTFLOATER_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 7772f613f0..642df92379 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -109,6 +109,7 @@  #include "llfloaterwhitelistentry.h"  #include "llfloaterwindlight.h"  #include "llfloaterworldmap.h" +#include "llimfloatercontainer.h"  #include "llinspectavatar.h"  #include "llinspectgroup.h"  #include "llinspectobject.h" @@ -124,6 +125,7 @@  #include "llpreviewsound.h"  #include "llpreviewtexture.h"  #include "llsyswellwindow.h" +#include "llscriptfloater.h"  // *NOTE: Please add files in alphabetical order to keep merges easy. @@ -171,6 +173,8 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);  	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>); +	LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>); +	LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLScriptFloater>);  	LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);  	LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>);  	LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c67af994a4..625b816125 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -5678,6 +5678,16 @@ class LLFloaterVisible : public view_listener_t  	}  }; +class LLShowSidetrayPanel : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		std::string panel_name = userdata.asString(); +		LLSideTray::getInstance()->showPanel(panel_name, LLSD()); +		return true; +	} +}; +  bool callback_show_url(const LLSD& notification, const LLSD& response)  {  	S32 option = LLNotification::getSelectedOption(notification, response); @@ -8039,6 +8049,7 @@ void initialize_menus()  	visible.add("Object.VisibleEdit", boost::bind(&enable_object_edit));  	view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); +	view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel");  	view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected");  	view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD");  	view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 8db6d5917a..4d7d3ee8ac 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -101,6 +101,7 @@  #include "llpanelgrouplandmoney.h"  #include "llpanelplaces.h"  #include "llrecentpeople.h" +#include "llscriptfloater.h"  #include "llselectmgr.h"  #include "llsidetray.h"  #include "llstartup.h" @@ -5380,6 +5381,17 @@ void process_script_dialog(LLMessageSystem* msg, void**)  		notification = LLNotifications::instance().add(  			LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD()));  	} + +	// "ScriptDialog" and "ScriptDialogGroup" are handles by LLScriptFloaterManager. +	// We want to inform user that there is a script floater, lets add "ScriptToast" +	LLNotification::Params p("ScriptToast"); +	p.substitutions(args).payload(payload).functor.function(boost::bind( +		LLScriptFloaterManager::onToastButtonClick, _1, _2)); + +	notification = LLNotifications::instance().add(p); + +	LLScriptFloaterManager::getInstance()->setNotificationToastId( +		object_id, notification->getID());  }  //--------------------------------------------------------------------------- diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index f4a239be62..6678918db8 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -161,7 +161,7 @@ with the same filename but different name    <texture name="Generic_Group" file_name="icons/Generic_Group.png" preload="false" />    <texture name="Generic_Group_Large" file_name="icons/Generic_Group_Large.png" preload="false" />    <texture name="Generic_Object_Medium" file_name="icons/Generic_Object_Medium.png" preload="false" /> -  <texture name="Generic_Object_Small" file_name="icons/ Generic_Object_Small.png" preload="false" /> +  <texture name="Generic_Object_Small" file_name="icons/Generic_Object_Small.png" preload="false" />    <texture name="Generic_Object_Large" file_name="icons/Generic_Object_Large.png" preload="false" />    <texture name="Generic_Person" file_name="icons/Generic_Person.png" preload="false" />    <texture name="Generic_Person_Large" file_name="icons/Generic_Person_Large.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml new file mode 100644 index 0000000000..cf6a4e45bd --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 +<multi_floater
 +background_visible="true"
 +bg_color="yellow" 
 + can_resize="true"
 + height="390"
 + layout="topleft"
 + name="floater_im_box"
 + help_topic="floater_im_box"
 + save_rect="true"
 + save_visibility="true"
 + single_instance="true"
 + title="Instant Messages"
 + width="392">
 +    <tab_container
 +     follows="left|right|top|bottom"
 +     height="390"
 +     layout="topleft"
 +     left="1"
 +     name="im_box_tab_container"
 +     tab_position="bottom"
 +     tab_width="80"
 +     top="0"
 +     width="390" />
 +    <icon
 +     color="DefaultShadowLight"
 +     enabled="false"
 +     follows="left|right|bottom"
 +     height="17"
 +     image_name="tabarea.tga"
 +     layout="bottomleft"
 +     left="1"
 +     name="im_box_tab_container_icon"
 +     bottom="10"
 +     width="390" />
 +</multi_floater>
 diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 95d40d297b..7f2f37409c 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -8,9 +8,9 @@   left="0"   name="panel_im"   top="0" - can_close="false" - can_dock="true" - can_minimize="true" + can_close="true" + can_dock="false" + can_minimize="false"   visible="true"   width="300"   can_resize="true" diff --git a/indra/newview/skins/default/xui/en/floater_script.xml b/indra/newview/skins/default/xui/en/floater_script.xml new file mode 100644 index 0000000000..f44ba6d873 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_script.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + background_visible="true" + follows="left|top|right|bottom" + height="369" + layout="topleft" + left="0" + name="script_floater" + help_topic="script_floater" + top="0" + can_dock="true" + can_minimize="true" + visible="true"  + width="520" + can_resize="true" + min_width="350" + min_height="369"> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8ab5fb1659..e19e11a1b8 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -59,7 +59,7 @@           label="My Inventory"           layout="topleft"           name="Inventory" -         shortcut="control|I"> +         shortcut="control|shift|I">              <menu_item_check.on_check               function="Floater.Visible"               parameter="inventory" /> @@ -68,6 +68,15 @@               parameter="inventory" />          </menu_item_check>          <menu_item_call +         label="Show Sidetray Inventory" +         name="ShowSidetrayInventory" +         shortcut="control|I" +         visible="false"> +            <menu_item_call.on_click +             function="ShowSidetrayPanel" +             parameter="sidepanel_inventory" /> +        </menu_item_call> +        <menu_item_call           label="My Gestures"           layout="topleft"           name="Gestures" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 90e32cdd9c..9d1bcb8f60 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -5307,6 +5307,27 @@ Grant this request?    <notification     icon="notify.tga" +   name="ScriptToast" +   type="notify"> +    [FIRST] [LAST]'s '[TITLE]' is requesting user input. +    <form name="form"> +      <button +       index="0" +       name="Open" +       text="Open Dialog"/> +      <button +       index="1" +       name="Ignore" +       text="Ignore"/> +      <button +       index="2" +       name="Block" +       text="Block"/> +    </form> +  </notification> + +  <notification +   icon="notify.tga"     name="FirstBalanceIncrease"     type="notify">  You just received L$[AMOUNT]. diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 5a4b0a3892..fac0d5c60f 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -309,4 +309,13 @@       name="send_im_to_email"       top_pad="5"       width="400" /> +    <check_box +     enabled="false" +     height="16" +     label="Enable plain text chat history" +     layout="topleft" +     left_delta="0" +     name="plain_text_chat_history" +     top_pad="5" +     width="400" />  </panel> diff --git a/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml new file mode 100644 index 0000000000..5011bf6a61 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/chiclet_script.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 +<chiclet_script
 + name="script_chiclet">
 + <icon
 +  name="chiclet_icon"
 +  follows="all"
 +  mouse_opaque="false"
 +  image_name="Generic_Object_Small" />
 +</expandable_text>
\ No newline at end of file | 
