diff options
27 files changed, 620 insertions, 71 deletions
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index ce1bc5914c..9a4a90206b 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -138,7 +138,8 @@ LLFolderView::Params::Params()  	use_label_suffix("use_label_suffix"),  	allow_multiselect("allow_multiselect", true),  	show_empty_message("show_empty_message", true), -	use_ellipses("use_ellipses", false) +	use_ellipses("use_ellipses", false), +    options_menu("options_menu", "")  {  	folder_indentation = -4;  } @@ -228,7 +229,7 @@ LLFolderView::LLFolderView(const Params& p)  	// make the popup menu available -	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); +	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());  	if (!menu)  	{  		menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu"); @@ -1530,14 +1531,18 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )  		&& menu )  	{  		if (mCallbackRegistrar) +        {  			mCallbackRegistrar->pushScope(); +        }  		updateMenuOptions(menu);  		menu->updateParent(LLMenuGL::sMenuContainer);  		LLMenuGL::showPopup(this, menu, x, y);  		if (mCallbackRegistrar) +        {  			mCallbackRegistrar->popScope(); +        }  	}  	else  	{ diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 81b0f087e8..487391a477 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -94,6 +94,8 @@ public:  								use_ellipses,  								show_item_link_overlays;  		Mandatory<LLFolderViewModelInterface*>	view_model; +        Mandatory<std::string>   options_menu; +  		Params();  	}; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 5639c4d5a3..0b04288950 100755 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -537,7 +537,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )  		if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()   			&& root->getCurSelectedItem()  			&& root->startDrag()) -			{ +		{  					// RN: when starting drag and drop, clear out last auto-open  					root->autoOpenTest(NULL);  					root->setShowSelectionContext(TRUE); @@ -548,13 +548,13 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )  					gFocusMgr.setKeyboardFocus(NULL);  			getWindow()->setCursor(UI_CURSOR_ARROW); -			return TRUE; -				} -		else +		} +		else if (x != mDragStartX || y != mDragStartY)  		{  			getWindow()->setCursor(UI_CURSOR_NOLOCKED); -			return TRUE;  		} + +		return TRUE;  	}  	else  	{ diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 4c730286da..be6d359c9a 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -767,7 +767,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&  			{	// freeze new size as fraction  				F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)  					? MAX_FRACTIONAL_SIZE -					: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); +					: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim() - 1) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);  				fraction_given_up -= new_fractional_size - panelp->mFractionalSize;  				fraction_remaining -= panelp->mFractionalSize;  				panelp->mFractionalSize = new_fractional_size; diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 51211a8ce5..d4bbd84d0f 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -239,14 +239,4 @@             is_running_function="Floater.IsOpen"             is_running_parameters="camera"             /> -  <command name="voice" -           available_in_toybox="true" -           icon="Command_Voice_Icon" -           label_ref="Command_Voice_Label" -           tooltip_ref="Command_Voice_Tooltip" -           execute_function="Floater.ToggleOrBringToFront" -           execute_parameters="voice_controls" -           is_running_function="Floater.IsOpen" -           is_running_parameters="voice_controls" -           />  </commands> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 08a1a237f5..6b15e4b21a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -42,6 +42,7 @@  #include "llagentcamera.h"  #include "llagentlanguage.h"  #include "llagentwearables.h" +#include "llimfloatercontainer.h"  #include "llwindow.h"  #include "llviewerstats.h"  #include "llviewerstatsrecorder.h" @@ -1204,7 +1205,7 @@ bool LLAppViewer::mainLoop()  	LLVoiceChannel::initClass();  	LLVoiceClient::getInstance()->init(gServicePump); -	LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::sOnCurrentChannelChanged, _1), true); +	LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLIMFloaterContainer::onCurrentChannelChanged, _1), true);  	LLTimer frameTimer,idleTimer;  	LLTimer debugTime;  	LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index a76dbcac53..248685b964 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -42,6 +42,7 @@  #include "llappviewer.h"		// for gLastVersionChannel  #include "llcachename.h"  #include "llcallingcard.h"		// for LLAvatarTracker +#include "llconversationlog.h"  #include "llfloateravatarpicker.h"	// for LLFloaterAvatarPicker  #include "llfloatergroupinvite.h"  #include "llfloatergroups.h" @@ -900,7 +901,17 @@ void LLAvatarActions::inviteToGroup(const LLUUID& id)  // static  void LLAvatarActions::viewChatHistory(const LLUUID& id)  { -	LLFloaterReg::showInstance("preview_conversation", id, true); +	const std::vector<LLConversation>& conversations = LLConversationLog::instance().getConversations(); +	std::vector<LLConversation>::const_iterator iter = conversations.begin(); + +	for (; iter != conversations.end(); ++iter) +	{ +		if (iter->getParticipantID() == id) +		{ +			LLFloaterReg::showInstance("preview_conversation", iter->getSessionID(), true); +			break; +		} +	}  }  //== private methods ======================================================================================== diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 38b755004c..e767609d74 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -364,7 +364,8 @@ void LLCallFloater::onAvatarListRefreshed()  }  // static -void LLCallFloater::sOnCurrentChannelChanged(const LLUUID& /*session_id*/) +// This entry point now disable, but left for later use. +void LLCallFloater::onCurrentChannelChanged(const LLUUID& /*session_id*/)  {  	LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel(); diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index 181c92276d..e1c7b3f43a 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -74,7 +74,7 @@ public:  	 */  	/*virtual*/ void onParticipantsChanged(); -	static void sOnCurrentChannelChanged(const LLUUID& session_id); +	static void onCurrentChannelChanged(const LLUUID& session_id);  private:  	typedef enum e_voice_controls_type @@ -260,7 +260,7 @@ private:  	 *  	 * Is used to ignore voice channel changed callback for the same channel.  	 * -	 * @see sOnCurrentChannelChanged() +	 * @see onCurrentChannelChanged()  	 */  	static LLVoiceChannel* sCurrentVoiceChannel; diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 7ddb725fb1..0f29ffe77f 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -29,6 +29,7 @@  #include "llevents.h"  #include "llconversationmodel.h" +#include "llimview.h" //For LLIMModel  //  // Conversation items : common behaviors @@ -95,6 +96,24 @@ void LLConversationItem::showProperties(void)  {  } +void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t&   items) +{ +    items.push_back(std::string("view_profile")); +    items.push_back(std::string("im")); +    items.push_back(std::string("offer_teleport")); +    items.push_back(std::string("voice_call")); +    items.push_back(std::string("chat_history")); +    items.push_back(std::string("separator_chat_history")); +    items.push_back(std::string("add_friend")); +    items.push_back(std::string("remove_friend")); +    items.push_back(std::string("invite_to_group")); +    items.push_back(std::string("separator_invite_to_group")); +    items.push_back(std::string("map")); +    items.push_back(std::string("share")); +    items.push_back(std::string("pay")); +    items.push_back(std::string("block_unblock")); +} +  //  // LLConversationItemSession  //  @@ -204,6 +223,52 @@ void LLConversationItemSession::setDistance(const LLUUID& participant_id, F64 di  	}  } +void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags) +{ +    lldebugs << "LLConversationItemParticipant::buildContextMenu()" << llendl; +    menuentry_vec_t items; +    menuentry_vec_t disabled_items; + +    if(this->getType() == CONV_SESSION_1_ON_1) +    { +        items.push_back(std::string("close_conversation")); +        items.push_back(std::string("separator_disconnect_from_voice")); +        buildParticipantMenuOptions(items); +    } +    else if(this->getType() == CONV_SESSION_GROUP) +    { +        items.push_back(std::string("close_conversation")); +        addVoiceOptions(items); +        items.push_back(std::string("chat_history")); +        items.push_back(std::string("separator_chat_history")); +        items.push_back(std::string("group_profile")); +        items.push_back(std::string("activate_group")); +        items.push_back(std::string("leave_group")); +    } +    else if(this->getType() == CONV_SESSION_AD_HOC) +    { +        items.push_back(std::string("close_conversation")); +        addVoiceOptions(items); +        items.push_back(std::string("chat_history")); +    } + +    hide_context_entries(menu, items, disabled_items); +} + +void LLConversationItemSession::addVoiceOptions(menuentry_vec_t& items) +{ +    LLVoiceChannel* voice_channel = LLIMModel::getInstance() ? LLIMModel::getInstance()->getVoiceChannel(this->getUUID()) : NULL; + +    if(voice_channel != LLVoiceChannel::getCurrentVoiceChannel()) +    { +        items.push_back(std::string("open_voice_conversation")); +    } +    else +    { +        items.push_back(std::string("disconnect_from_voice")); +    } +} +  // The time of activity of a session is the time of the most recent activity, session and participants included  const bool LLConversationItemSession::getTime(F64& time) const  { @@ -262,6 +327,15 @@ LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid,  	mConvType = CONV_PARTICIPANT;  } +void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags) +{ +    menuentry_vec_t items; +    menuentry_vec_t disabled_items; + +    buildParticipantMenuOptions(items); +    hide_context_entries(menu, items, disabled_items); +} +  void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_name)  {  	mName = (av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername); diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 32280f3293..7218cdf25a 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -41,6 +41,8 @@ class LLConversationItemParticipant;  typedef std::map<LLUUID, LLConversationItem*> conversations_items_map;  typedef std::map<LLUUID, LLFolderViewItem*> conversations_widgets_map; +typedef std::vector<std::string> menuentry_vec_t; +  // Conversation items: we hold a list of those and create an LLFolderViewItem widget for each    // that we tuck into the mConversationsListPanel.   class LLConversationItem : public LLFolderViewModelItemCommon @@ -126,6 +128,8 @@ public:  	void postEvent(const std::string& event_type, LLConversationItemParticipant* participant); +    void buildParticipantMenuOptions(menuentry_vec_t&   items); +  protected:  	std::string mName;	// Name of the session or the participant  	LLUUID mUUID;		// UUID of the session or the participant @@ -157,6 +161,8 @@ public:  	bool isLoaded() { return mIsLoaded; } +    void buildContextMenu(LLMenuGL& menu, U32 flags); +    void addVoiceOptions(menuentry_vec_t& items);  	virtual const bool getTime(F64& time) const;  	void dumpDebugData(); @@ -180,7 +186,8 @@ public:  	void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; }  	void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; }  	void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; } -	 + +    void buildContextMenu(LLMenuGL& menu, U32 flags);  	void onAvatarNameCache(const LLAvatarName& av_name);  	virtual const bool getDistanceToAgent(F64& dist) const { dist = mDistToAgent; return (dist >= 0.0); } @@ -275,4 +282,15 @@ public:  private:  }; +// Utility function to hide all entries except those in the list +// Can be called multiple times on the same menu (e.g. if multiple items +// are selected).  If "append" is false, then only common enabled items +// are set as enabled. + +//(defined in inventorybridge.cpp) +//TODO: Gilbert Linden - Refactor to make this function non-global +void hide_context_entries(LLMenuGL& menu,  +    const menuentry_vec_t &entries_to_show,  +    const menuentry_vec_t &disabled_entries); +  #endif // LL_LLCONVERSATIONMODEL_H diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index d11504d312..99337bd5f3 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -111,23 +111,25 @@ void LLIMFloater::onClickCloseBtn()  {  	LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID); -	if (session == NULL) +	if (session != NULL)  	{ -		llwarns << "Empty session with id: " << (mSessionID.asString()) << llendl; -		return; -	} +		bool is_call_with_chat = session->isGroupSessionType() +				|| session->isAdHocSessionType() || session->isP2PSessionType(); -	bool is_call_with_chat = session->isGroupSessionType() -			|| session->isAdHocSessionType() || session->isP2PSessionType(); +		LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); -	LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); - -	if (is_call_with_chat && voice_channel != NULL -			&& voice_channel->isActive()) +		if (is_call_with_chat && voice_channel != NULL +				&& voice_channel->isActive()) +		{ +			LLSD payload; +			payload["session_id"] = mSessionID; +			LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback); +			return; +		} +	} +	else  	{ -		LLSD payload; -		payload["session_id"] = mSessionID; -		LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback); +		llwarns << "Empty session with id: " << (mSessionID.asString()) << llendl;  		return;  	} diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index d444270716..5ed1d1ab35 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -127,6 +127,7 @@ public:  	static void onIMChicletCreated(const LLUUID& session_id);  	bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; } +    const LLUUID& getOtherParticipantUUID() {return mOtherParticipantUUID;}  	static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb);  	static floater_showed_signal_t sIMFloaterShowedSignal; diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index e58154b2a2..da4d1afb2b 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -39,6 +39,7 @@  #include "llavatariconctrl.h"  #include "llavatarnamecache.h"  #include "llcallbacklist.h" +#include "llgroupactions.h"  #include "llgroupiconctrl.h"  #include "llfloateravatarpicker.h"  #include "llfloaterpreference.h" @@ -60,8 +61,14 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)  	mStream("ConversationsEvents"),  	mInitialized(false)  { +    mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));  	mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLIMFloaterContainer::onCustomAction,  this, _2)); -	mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2)); +	 +    mEnableCallbackRegistrar.add("Avatar.CheckItem",  boost::bind(&LLIMFloaterContainer::checkContextMenuItem,	this, _2)); +    mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLIMFloaterContainer::enableContextMenuItem,	this, _2)); +    mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelected, this, _2)); +     +    mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelectedGroup, this, _2));  	// Firstly add our self to IMSession observers, so we catch session events      LLIMMgr::getInstance()->addSessionObserver(this); @@ -109,6 +116,16 @@ void LLIMFloaterContainer::sessionRemoved(const LLUUID& session_id)  	removeConversationListItem(session_id);  } +// static +void LLIMFloaterContainer::onCurrentChannelChanged(const LLUUID& session_id) +{ +    if (session_id != LLUUID::null) +    { +    	LLIMFloater::show(session_id); +    } +} + +  BOOL LLIMFloaterContainer::postBuild()  {  	mNewMessageConnection = LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1)); @@ -136,7 +153,9 @@ BOOL LLIMFloaterContainer::postBuild()      p.view_model = &mConversationViewModel;      p.root = NULL;      p.use_ellipses = true; +    p.options_menu = "menu_conversation.xml";  	mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p); +    mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);  	// Add listener to conversation model events  	mStream.listen("ConversationsRefresh", boost::bind(&LLIMFloaterContainer::onConversationModelEvent, this, _1)); @@ -494,21 +513,26 @@ void LLIMFloaterContainer::tabClose()  }  void LLIMFloaterContainer::setVisible(BOOL visible) -{ +{	LLNearbyChat* nearby_chat;  	if (visible)  	{  		// Make sure we have the Nearby Chat present when showing the conversation container -		LLIMConversation* nearby_chat = LLFloaterReg::findTypedInstance<LLIMConversation>("nearby_chat"); +		nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat");  		if (nearby_chat == NULL)  		{  			// If not found, force the creation of the nearby chat conversation panel  			// *TODO: find a way to move this to XML as a default panel or something like that  			LLSD name("nearby_chat");  			LLFloaterReg::toggleInstanceOrBringToFront(name); -			LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat")->addToHost();  		}  	} +	nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat"); +	if (nearby_chat && !nearby_chat->isHostSet()) +	{ +		nearby_chat->addToHost(); +	} +  	// We need to show/hide all the associated conversations that have been torn off  	// (and therefore, are not longer managed by the multifloater),  	// so that they show/hide with the conversations manager. @@ -587,7 +611,7 @@ void LLIMFloaterContainer::collapseConversationsPane(bool collapse)  		    {  		    	widget->setOpen(false);  		    } -		} +}  	}  } @@ -751,6 +775,274 @@ void LLIMFloaterContainer::setSortOrder(const LLConversationSort& order)  	gSavedSettings.setU32("ConversationSortOrder", (U32)order);  } +void LLIMFloaterContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids) +{ +    const std::set<LLFolderViewItem*> selectedItems = mConversationsRoot->getSelectionList(); + +    std::set<LLFolderViewItem*>::const_iterator it = selectedItems.begin(); +    const std::set<LLFolderViewItem*>::const_iterator it_end = selectedItems.end(); +    LLConversationItem * conversationItem; + +    for (; it != it_end; ++it) +    { +        conversationItem = static_cast<LLConversationItem *>((*it)->getViewModelItem()); +        selected_uuids.push_back(conversationItem->getUUID()); +    } +} + +const LLConversationItem * LLIMFloaterContainer::getCurSelectedViewModelItem() +{ +    LLConversationItem * conversationItem = NULL; + +    if(mConversationsRoot &&  +        mConversationsRoot->getCurSelectedItem() &&  +        mConversationsRoot->getCurSelectedItem()->getViewModelItem()) +    { +        conversationItem = static_cast<LLConversationItem *>(mConversationsRoot->getCurSelectedItem()->getViewModelItem()); +    } + +    return conversationItem; +} + +void LLIMFloaterContainer::doToUsers(const std::string& command, uuid_vec_t selectedIDS) +{ +    LLUUID userID; +    userID = selectedIDS.front(); + +    if ("view_profile" == command) +    { +        LLAvatarActions::showProfile(userID); +    } +    else if("im" == command) +    { +        LLAvatarActions::startIM(userID); +    } +    else if("offer_teleport" == command) +    { +        LLAvatarActions::offerTeleport(selectedIDS); +    } +    else if("voice_call" == command) +    { +        LLAvatarActions::startCall(userID); +    } +    else if("chat_history" == command) +    { +        LLAvatarActions::viewChatHistory(userID); +    } +    else if("add_friend" == command) +    { +        LLAvatarActions::requestFriendshipDialog(userID); +    } +    else if("remove_friend" == command) +    { +        LLAvatarActions::removeFriendDialog(userID); +    } +    else if("invite_to_group" == command) +    { +        LLAvatarActions::inviteToGroup(userID); +    } +    else if("map" == command) +    { +        LLAvatarActions::showOnMap(userID); +    } +    else if("share" == command) +    { +        LLAvatarActions::share(userID); +    } +    else if("pay" == command) +    { +        LLAvatarActions::pay(userID); +    } +    else if("block_unblock" == command) +    { +        LLAvatarActions::toggleBlock(userID); +    } +} + +void LLIMFloaterContainer::doToSelectedParticipant(const std::string& command) +{ +    uuid_vec_t selected_uuids; +    getSelectedUUIDs(selected_uuids); +    +    doToUsers(command, selected_uuids); +} + +void LLIMFloaterContainer::doToSelectedConversation(const std::string& command) +{ +    LLUUID participantID; + +    //Find the conversation floater associated with the selected id +    const LLConversationItem * conversationItem = getCurSelectedViewModelItem(); +    LLIMFloater *conversationFloater = LLIMFloater::findInstance(conversationItem->getUUID()); + +    if(conversationFloater) +    { +        //When a one-on-one conversation exists, retrieve the participant id from the conversation floater b/c +        //selected_uuids.front() does not pertain to the UUID of the person you are having the conversation with. +        if(conversationItem->getType() == LLConversationItem::CONV_SESSION_1_ON_1) +        { +            participantID = conversationFloater->getOtherParticipantUUID(); +        } + +        //Close the selected conversation +        if("close_conversation" == command) +        { +            LLFloater::onClickClose(conversationFloater); +        } +        else if("open_voice_conversation" == command) +        { +            gIMMgr->startCall(conversationItem->getUUID()); +        } +        else if("disconnect_from_voice" == command) +        { +            gIMMgr->endCall(conversationItem->getUUID()); +        } +        else if("chat_history" == command) +        { +            LLAvatarActions::viewChatHistory(conversationItem->getUUID()); +        } +        else +        { +            uuid_vec_t selected_uuids; +            selected_uuids.push_back(participantID); +            doToUsers(command, selected_uuids); +        } +    } +} + +void LLIMFloaterContainer::doToSelected(const LLSD& userdata) +{ +    std::string command = userdata.asString(); +    const LLConversationItem * conversationItem = getCurSelectedViewModelItem(); + +    if(conversationItem->getType() == LLConversationItem::CONV_SESSION_1_ON_1 || +        conversationItem->getType() == LLConversationItem::CONV_SESSION_GROUP || +        conversationItem->getType() == LLConversationItem::CONV_SESSION_AD_HOC) +    { +        doToSelectedConversation(command); +    } +    else +    { +        doToSelectedParticipant(command); +    } +} + +void LLIMFloaterContainer::doToSelectedGroup(const LLSD& userdata) +{ +    std::string action = userdata.asString(); +    LLUUID selected_group = getCurSelectedViewModelItem()->getUUID(); + +    if (action == "group_profile") +    { +        LLGroupActions::show(selected_group); +    } +    else if (action == "activate_group") +    { +        LLGroupActions::activate(selected_group); +    } +    else if (action == "leave_group") +    { +        LLGroupActions::leave(selected_group); +    } +} + +bool LLIMFloaterContainer::enableContextMenuItem(const LLSD& userdata) +{ +    std::string item = userdata.asString(); +    uuid_vec_t mUUIDs; +    getSelectedUUIDs(mUUIDs); + +    // Note: can_block and can_delete is used only for one person selected menu +    // so we don't need to go over all uuids. + +    if (item == std::string("can_block")) +    { +        const LLUUID& id = mUUIDs.front(); +        return LLAvatarActions::canBlock(id); +    } +    else if (item == std::string("can_add")) +    { +        // We can add friends if: +        // - there are selected people +        // - and there are no friends among selection yet. + +        //EXT-7389 - disable for more than 1 +        if(mUUIDs.size() > 1) +        { +            return false; +        } + +        bool result = (mUUIDs.size() > 0); + +        uuid_vec_t::const_iterator +            id = mUUIDs.begin(), +            uuids_end = mUUIDs.end(); + +        for (;id != uuids_end; ++id) +        { +            if ( LLAvatarActions::isFriend(*id) ) +            { +                result = false; +                break; +            } +        } + +        return result; +    } +    else if (item == std::string("can_delete")) +    { +        // We can remove friends if: +        // - there are selected people +        // - and there are only friends among selection. + +        bool result = (mUUIDs.size() > 0); + +        uuid_vec_t::const_iterator +            id = mUUIDs.begin(), +            uuids_end = mUUIDs.end(); + +        for (;id != uuids_end; ++id) +        { +            if ( !LLAvatarActions::isFriend(*id) ) +            { +                result = false; +                break; +            } +        } + +        return result; +    } +    else if (item == std::string("can_call")) +    { +        return LLAvatarActions::canCall(); +    } +    else if (item == std::string("can_show_on_map")) +    { +        const LLUUID& id = mUUIDs.front(); + +        return (LLAvatarTracker::instance().isBuddyOnline(id) && is_agent_mappable(id)) +            || gAgent.isGodlike(); +    } +    else if(item == std::string("can_offer_teleport")) +    { +        return LLAvatarActions::canOfferTeleport(mUUIDs); +    } +    return false; +} + +bool LLIMFloaterContainer::checkContextMenuItem(const LLSD& userdata) +{ +    std::string item = userdata.asString(); +    const LLUUID& id = getCurSelectedViewModelItem()->getUUID(); + +    if (item == std::string("is_blocked")) +    { +        return LLAvatarActions::isBlocked(id); +    } + +    return false; +} +  void LLIMFloaterContainer::setConvItemSelect(const LLUUID& session_id)  {  	LLFolderViewItem* widget = mConversationsWidgets[session_id]; diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index 8e953025bc..5702b88a48 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -67,11 +67,11 @@ public:  	/*virtual*/ void tabClose();  	static LLFloater* getCurrentVoiceFloater(); -  	static LLIMFloaterContainer* findInstance(); -  	static LLIMFloaterContainer* getInstance(); +	static void onCurrentChannelChanged(const LLUUID& session_id); +  	virtual void setMinimized(BOOL b);  	void collapseMessagesPane(bool collapse); @@ -112,6 +112,16 @@ private:  	void setSortOrderParticipants(const LLConversationFilter::ESortOrderType order);  	void setSortOrder(const LLConversationSort& order); +    void getSelectedUUIDs(uuid_vec_t& selected_uuids); +    const LLConversationItem * getCurSelectedViewModelItem(); +    void doToSelected(const LLSD& userdata); +    void doToSelectedConversation(const std::string& command); +    void doToSelectedParticipant(const std::string& command); +    void doToUsers(const std::string& command, uuid_vec_t selectedIDS); +    void doToSelectedGroup(const LLSD& userdata); +    bool checkContextMenuItem(const LLSD& userdata); +    bool enableContextMenuItem(const LLSD& userdata); +  	LLButton* mExpandCollapseBtn;  	LLLayoutPanel* mMessagesPane;  	LLLayoutPanel* mConversationsPane; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 72c54e5ce2..139713b96e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1531,6 +1531,15 @@ LLUIImagePtr LLItemBridge::getIcon() const  	return LLInventoryIcon::getIcon(LLInventoryIcon::ICONNAME_OBJECT);  } +LLUIImagePtr LLItemBridge::getIconOverlay() const +{ +	if (getItem() && getItem()->getIsLinkType()) +	{ +		return LLUI::getUIImage("Inv_Link"); +	} +	return NULL; +} +  PermissionMask LLItemBridge::getPermissionMask() const  {  	LLViewerInventoryItem* item = getItem(); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 6beccf19ae..b33972167c 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -228,6 +228,7 @@ public:  	virtual BOOL isItemCopyable() const;  	virtual bool hasChildren() const { return FALSE; }  	virtual BOOL isUpToDate() const { return TRUE; } +	virtual LLUIImagePtr getIconOverlay() const;  	LLViewerInventoryItem* getItem() const; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index a77b57638f..a8d99ad7de 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -172,6 +172,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )      p.show_empty_message = mShowEmptyMessage;      p.show_item_link_overlays = mShowItemLinkOverlays;      p.root = NULL; +    p.options_menu = "menu_inventory.xml";      return LLUICtrlFactory::create<LLFolderView>(p);  } diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 4b35092f2d..b96b486868 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -91,7 +91,8 @@ LLNearbyChat::LLNearbyChat(const LLSD& llsd)  :	LLIMConversation(llsd),  	//mOutputMonitor(NULL),  	mSpeakerMgr(NULL), -	mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT) +	mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT), +	mIsHostSet(false)  {      mIsP2PChat = false;  	mIsNearbyChat = true; @@ -100,6 +101,12 @@ LLNearbyChat::LLNearbyChat(const LLSD& llsd)  	mSessionID = LLUUID();  } +//static +LLNearbyChat* LLNearbyChat::buildFloater(const LLSD& key) +{ +    LLFloaterReg::getInstance("im_container"); +    return new LLNearbyChat(key); +}  //virtual  BOOL LLNearbyChat::postBuild() @@ -304,9 +311,16 @@ void LLNearbyChat::addToHost()  				setHost(NULL);  			}  		} + +		mIsHostSet = true;  	}  } +bool LLNearbyChat::isHostSet() +{ +    return mIsHostSet; +} +  // virtual  void LLNearbyChat::onOpen(const LLSD& key)  { diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index 3987212e4c..93168ba96a 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -48,6 +48,8 @@ public:  	LLNearbyChat(const LLSD& key = LLSD(LLUUID()));  	~LLNearbyChat() {} +	static LLNearbyChat* buildFloater(const LLSD& key); +  	/*virtual*/ BOOL postBuild();  	/*virtual*/ void onOpen(const LLSD& key); @@ -76,6 +78,8 @@ public:  	static void startChat(const char* line);  	static void stopChat(); +	bool isHostSet(); +  	static void sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate);  	static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate); @@ -117,6 +121,7 @@ private:  	LLHandle<LLView>	mPopupMenuHandle;  	std::vector<LLChat> mMessageArchive; +    bool mIsHostSet;  };  #endif diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index f3e17ea61b..7834f6d320 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -487,6 +487,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg,  	if(chat_msg.mText.empty())  		return;//don't process empty messages +    LLFloaterReg::getInstance("im_container");  	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat");  	// Build notification data  diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 4cd5ecc754..c751550523 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -194,7 +194,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);  	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>); -	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>); +	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLNearbyChat::buildFloater);  	LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);  	LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index a993d195b5..6da9296ea3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3466,7 +3466,8 @@ class LLTogglePanelPeopleTab : public view_listener_t  		if (   panel_name == "friends_panel"  			|| panel_name == "groups_panel" -			|| panel_name == "nearby_panel") +			|| panel_name == "nearby_panel" +			|| panel_name == "blocked_panel")  		{  			return togglePeoplePanel(panel_name, param);  		} @@ -5490,16 +5491,6 @@ void toggle_debug_menus(void*)  // 	gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");  // }  // - -class LLCommunicateBlockList : public view_listener_t -{ -	bool handleEvent(const LLSD& userdata) -	{ -		LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD()); -		return true; -	} -}; -  class LLWorldSetHomeLocation : public view_listener_t  {  	bool handleEvent(const LLSD& userdata) @@ -8290,9 +8281,6 @@ void initialize_menus()  	// Me > Movement  	view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); -	// Communicate -	view_listener_t::addMenu(new LLCommunicateBlockList(), "Communicate.BlockList"); -	  	// World menu  	view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");  	view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); diff --git a/indra/newview/skins/default/xui/en/floater_conversation_log.xml b/indra/newview/skins/default/xui/en/floater_conversation_log.xml index 12d17e6b37..c9c52e5ce5 100644 --- a/indra/newview/skins/default/xui/en/floater_conversation_log.xml +++ b/indra/newview/skins/default/xui/en/floater_conversation_log.xml @@ -49,6 +49,7 @@            menu_filename="menu_conversation_log_view.xml"            menu_position="bottomleft"            name="conversation_view_btn" +          tool_tip="View/sort options"            top="3"            width="31" />          <menu_button @@ -61,6 +62,7 @@            layout="topleft"            left_pad="2"            name="conversations_gear_btn" +          tool_tip="Actions on selected person or group"            top="3"            width="31" />      </panel> diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml new file mode 100644 index 0000000000..912ff811d9 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_conversation.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + bottom="806" + layout="topleft" + left="0" + mouse_opaque="false" + name="menu_conversation_participant" + visible="false"> +     <menu_item_call +     label="Close conversation" +     layout="topleft" +     name="close_conversation"> +        <on_click function="Avatar.DoToSelected" parameter="close_conversation"/> +	 </menu_item_call> +     <menu_item_call +     label="Open voice conversation" +     layout="topleft" +     name="open_voice_conversation"> +        <on_click function="Avatar.DoToSelected" parameter="open_voice_conversation"/> +     </menu_item_call>	 +     <menu_item_call +     label="Disconnect from voice" +     layout="topleft" +     name="disconnect_from_voice"> +        <on_click function="Avatar.DoToSelected" parameter="disconnect_from_voice"/> +    </menu_item_call>	 +	<menu_item_separator layout="topleft" name="separator_disconnect_from_voice"/>	 +    <menu_item_call +     label="View Profile" +     layout="topleft" +     name="view_profile"> +        <on_click function="Avatar.DoToSelected" parameter="view_profile"/> +    </menu_item_call> +    <menu_item_call +     label="IM" +     layout="topleft" +     name="im"> +        <on_click function="Avatar.DoToSelected" parameter="im"/> +    </menu_item_call> +    <menu_item_call +     label="Offer teleport" +     layout="topleft" +     name="offer_teleport"> +        <on_click function="Avatar.DoToSelected" parameter="offer_teleport"/> +        <on_enable function="Avatar.EnableItem" parameter="can_offer_teleport"/> +    </menu_item_call> +    <menu_item_call +     label="Voice call" +     layout="topleft" +     name="voice_call"> +        <on_click function="Avatar.DoToSelected" parameter="voice_call"/> +        <on_enable function="Avatar.EnableItem" parameter="can_call" /> +    </menu_item_call> +    <menu_item_call +     label="Chat history..." +     layout="topleft" +     name="chat_history"> +        <on_click function="Avatar.DoToSelected" parameter="chat_history"/> +    </menu_item_call>	 +    <menu_item_separator layout="topleft" name="separator_chat_history"/>	 +    <menu_item_call +     label="Add friend" +     layout="topleft" +     name="add_friend"> +        <on_click function="Avatar.DoToSelected" parameter="add_friend"/> +        <on_enable function="Avatar.EnableItem" parameter="can_add" /> +    </menu_item_call> +    <menu_item_call +     label="Remove friend" +     layout="topleft" +     name="remove_friend"> +        <on_click function="Avatar.DoToSelected" parameter="remove_friend" /> +        <on_enable function="Avatar.EnableItem" parameter="can_delete" /> +    </menu_item_call>	 +    <menu_item_call +     label="Invite to group..." +     layout="topleft" +     name="invite_to_group"> +        <on_click function="Avatar.DoToSelected" parameter="invite_to_group" /> +    </menu_item_call> +    <menu_item_separator layout="topleft" name="separator_invite_to_group"/>		 +    <menu_item_call +     label="Map" +     layout="topleft" +     name="map"> +        <on_click function="Avatar.DoToSelected" parameter="map" /> +        <on_enable function="Avatar.EnableItem" parameter="can_show_on_map" /> +    </menu_item_call> +    <menu_item_call +     label="Share" +     layout="topleft" +     name="share"> +        <on_click function="Avatar.DoToSelected" parameter="share" /> +    </menu_item_call> +    <menu_item_call +     label="Pay" +     layout="topleft" +     name="pay"> +        <on_click function="Avatar.DoToSelected" parameter="pay" /> +    </menu_item_call> +    <menu_item_check +     label="Block / unblock" +     layout="topleft" +     name="block_unblock"> +        <on_click function="Avatar.DoToSelected" parameter="block_unblock" /> +		<on_check function="Avatar.CheckItem" parameter="is_blocked" /> +		<on_enable  function="Avatar.EnableItem" parameter="can_block" /> +    </menu_item_check> +	<menu_item_call +     label="Group Profile" +     layout="topleft" +     name="group_profile"> +        <on_click function="Group.DoToSelected" parameter="group_profile"/> +    </menu_item_call>	 +    <menu_item_call +     label="Activate Group" +     layout="topleft" +     name="activate_group"> +        <on_click function="Group.DoToSelected" parameter="activate_group"/> +    </menu_item_call>		 +    <menu_item_call +     label="Leave Group" +     layout="topleft" +     name="leave_group"> +        <on_click function="Group.DoToSelected" parameter="leave_group"/> +    </menu_item_call> +</toggleable_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index aa131035ed..88b30c8272 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -244,16 +244,6 @@               parameter="speak" />          </menu_item_check>          <menu_item_check -         label="Voice settings..." -         name="Nearby Voice"> -            <menu_item_check.on_check -             function="Floater.Visible" -             parameter="voice_controls" /> -            <menu_item_check.on_click -             function="Floater.Toggle" -             parameter="voice_controls" /> -        </menu_item_check> -        <menu_item_check           label="Voice morphing..."           name="ShowVoice"           visibility_control="VoiceMorphingEnabled"> @@ -304,7 +294,8 @@           label="Block List"           name="Block List">              <menu_item_call.on_click -              function="Communicate.BlockList" /> +              function="SideTray.PanelPeopleTab" +              parameter="blocked_panel" />          </menu_item_call>      </menu>      <menu diff --git a/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml b/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml index 8a58eb1ca6..78d4c174d2 100644 --- a/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml +++ b/indra/newview/skins/default/xui/en/panel_conversation_log_list_item.xml @@ -35,6 +35,7 @@       image_name="Conv_toolbar_open_call"       mouse_opaque="true"       name="voice_session_icon" +     tool_tip="Included a voice conversation"       top="2"       visible="false"       width="20" /> @@ -46,6 +47,7 @@       image_name="Conv_log_inbox"       mouse_opaque="false"       name="unread_ims_icon" +     tool_tip="Messages arrived while you were logged out"       top="2"       visible="false"       width="20" /> @@ -92,6 +94,7 @@       width="110"/>      <button       name="delete_btn" +     tool_tip="Remove this entry"       layout="topleft"       follows="top|right"       image_unselected="Conv_toolbar_close"  | 
