diff options
30 files changed, 638 insertions, 419 deletions
| diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp index 9dc7861992..63faf44f9d 100644 --- a/indra/llui/lldockablefloater.cpp +++ b/indra/llui/lldockablefloater.cpp @@ -38,8 +38,6 @@  //static  LLHandle<LLFloater> LLDockableFloater::sInstanceHandle; -static const std::string VOICE_FLOATER("floater_voice_controls"), IM_FLOATER("panel_im"); -  //static  void LLDockableFloater::init(LLDockableFloater* thiz)  { @@ -116,11 +114,9 @@ void LLDockableFloater::resetInstance()  {  	if (mUniqueDocking && sInstanceHandle.get() != this)  	{ -		if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked() -				&& (getName() != VOICE_FLOATER || sInstanceHandle.get()->getName() != IM_FLOATER) -					&& (getName() !=  IM_FLOATER || sInstanceHandle.get()->getName() != VOICE_FLOATER)) +		if (sInstanceHandle.get() != NULL && sInstanceHandle.get()->isDocked())  		{ -				sInstanceHandle.get()->setVisible(FALSE); +			sInstanceHandle.get()->setVisible(FALSE);  		}  		sInstanceHandle = getHandle();  	} diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 636b1de4d4..c5a1ffdcb3 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -264,11 +264,8 @@ bool LLAvatarActions::isCalling(const LLUUID &id)  //static  bool LLAvatarActions::canCall(const LLUUID &id)  { -	if(isFriend(id)) -	{ -		return LLAvatarTracker::instance().isBuddyOnline(id) && LLVoiceClient::voiceEnabled(); -	} -	else +	// For now we do not need to check whether passed UUID is ID of agent's friend. +	// Use common check of Voice Client state.  	{  		// don't need to check online/offline status because "usual resident" (resident that is not a friend)  		// can be only ONLINE. There is no way to see "usual resident" in OFFLINE status. If we see "usual diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index 8389895479..6f2e666cc7 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -215,6 +215,10 @@ void LLBottomTray::onNewIM(const LLSD& data)  	}  } +S32 LLBottomTray::getTotalUnreadIMCount() +{ +	return getChicletPanel()->getTotalUnreadIMCount(); +}  // virtual  void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, bool proximal) diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index 1adea24ee4..5cd3f15746 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -77,6 +77,8 @@ public:  	void onNewIM(const LLSD& data); +	S32 getTotalUnreadIMCount(); +  	virtual void reshape(S32 width, S32 height, BOOL called_from_parent);  	virtual void onFocusLost(); @@ -92,6 +94,11 @@ public:  	void showMoveButton(BOOL visible);  	void showCameraButton(BOOL visible);  	void showSnapshotButton(BOOL visible); +	 +	/** +	 * Creates IM Chiclet based on session type (IM chat or Group chat) +	 */ +	LLIMChiclet* createIMChiclet(const LLUUID& session_id);  private:  	typedef enum e_resize_status_type @@ -184,11 +191,6 @@ protected:  	void onContextMenuItemClicked(const LLSD& userdata);  	bool onContextMenuItemEnabled(const LLSD& userdata); -	/** -	 * Creates IM Chiclet based on session type (IM chat or Group chat) -	 */ -	LLIMChiclet* createIMChiclet(const LLUUID& session_id); -  	LLChicletPanel* 	mChicletPanel;  	LLPanel*			mSpeakPanel;  	LLSpeakButton* 		mSpeakBtn; diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index 2f5523e04d..1f23840109 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -44,6 +44,7 @@  #include "llbottomtray.h"  #include "llparticipantlist.h"  #include "llspeakers.h" +#include "lltransientfloatermgr.h"  class LLNonAvatarCaller : public LLAvatarListItem @@ -77,7 +78,7 @@ static void* create_non_avatar_caller(void*)  }  LLCallFloater::LLCallFloater(const LLSD& key) -: LLDockableFloater(NULL, key) +: LLDockableFloater(NULL, false, key)  , mSpeakerManager(NULL)  , mPaticipants(NULL)  , mAvatarList(NULL) @@ -89,6 +90,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)  {  	mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);  	LLVoiceClient::getInstance()->addObserver(this); +	LLTransientFloaterMgr::getInstance()->addControlView(this);  }  LLCallFloater::~LLCallFloater() @@ -103,6 +105,7 @@ LLCallFloater::~LLCallFloater()  	{  		gVoiceClient->removeObserver(this);  	} +	LLTransientFloaterMgr::getInstance()->removeControlView(this);  }  // virtual @@ -238,7 +241,7 @@ void LLCallFloater::updateSession()  	//hide "Leave Call" button for nearby chat  	bool is_local_chat = mVoiceType == VC_LOCAL_CHAT; -	childSetVisible("leave_btn_panel", !is_local_chat); +	childSetVisible("leave_call_btn", !is_local_chat);  	refreshPartisipantList();  	updateModeratorState(); diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index c7f77810df..c6fe076911 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -250,8 +250,7 @@ LLIMWellChiclet::~LLIMWellChiclet()  void LLIMWellChiclet::messageCountChanged(const LLSD& session_data)  { -	S32 total_unread = LLIMMgr::instance().getNumberOfUnreadParticipantMessages(); -	setCounter(total_unread); +	setCounter(LLBottomTray::getInstance()->getTotalUnreadIMCount());  }  /************************************************************************/ @@ -1529,6 +1528,21 @@ bool LLChicletPanel::isAnyIMFloaterDoked()  	return res;  } +S32 LLChicletPanel::getTotalUnreadIMCount() +{ +	S32 count = 0; +	chiclet_list_t::const_iterator it = mChicletList.begin(); +	for( ; mChicletList.end() != it; ++it) +	{ +		LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it); +		if(chiclet) +		{ +			count += chiclet->getCounter(); +		} +	} +	return count; +} +  //////////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////////  ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 353fc01c34..b3341f78a8 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -963,6 +963,8 @@ public:  	S32 getMinWidth() const { return mMinWidth; } +	S32 getTotalUnreadIMCount(); +  protected:  	LLChicletPanel(const Params&p);  	friend class LLUICtrlFactory; diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 9c37c953fe..9f6412c0ab 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -322,6 +322,13 @@ void LLExpandableTextBox::expandTextBox()  	// hide "more" link, and show full text contents  	mTextBox->hideExpandText(); +	// *HACK dz +	// hideExpandText brakes text styles (replaces hyper-links with plain text), see ticket EXT-3290 +	// Set text again to make text box re-apply styles. +	// *TODO Find proper solution to fix this issue. +	// Maybe add removeSegment to LLTextBase +	mTextBox->setTextBase(mText); +  	S32 text_delta = mTextBox->getVerticalTextDelta();  	text_delta += mTextBox->getVPad() * 2;  	text_delta += mScroll->getBorderWidth() * 2; diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h index 7c989cfa50..2b4f9e527c 100644 --- a/indra/newview/llexpandabletextbox.h +++ b/indra/newview/llexpandabletextbox.h @@ -61,6 +61,7 @@ protected:  		// adds or removes "More" link as needed  		/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);  		/*virtual*/ void setText(const LLStringExplicit& text, const LLStyle::Params& input_params = LLStyle::Params()); +		void setTextBase(const std::string& text) { LLTextBase::setText(text); }  		/**  		 * Returns difference between text box height and text height. diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 17b0710813..da0a9727a9 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -370,6 +370,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)  	mLandingTab(NULL),  	mLastTab(NULL),  	mTabsHighlightEnabled(TRUE) +  , mUpdateDropDownItems(true)  {  	// Register callback for menus with current registrar (will be parent panel's registrar)  	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", @@ -589,16 +590,15 @@ void LLFavoritesBarCtrl::changed(U32 mask)  	}	  	else  	{ -		updateButtons(getRect().getWidth()); +		updateButtons();  	}  }  //virtual  void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)  { -	updateButtons(width); -  	LLUICtrl::reshape(width, height, called_from_parent); +	updateButtons();  }  void LLFavoritesBarCtrl::draw() @@ -637,7 +637,7 @@ LLXMLNodePtr LLFavoritesBarCtrl::getButtonXMLNode()  	return buttonXMLNode;  } -void LLFavoritesBarCtrl::updateButtons(U32 bar_width) +void LLFavoritesBarCtrl::updateButtons()  {  	mItems.clear(); @@ -652,139 +652,142 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width)  		return;  	} -	S32 buttonWidth = 120; //default value -	buttonXMLNode->getAttributeS32("width", buttonWidth); -	S32 buttonHGap = 2; // default value -	buttonXMLNode->getAttributeS32("left", buttonHGap); -	 -	S32 count = mItems.count(); -	S32 buttons_space = bar_width - buttonHGap; - -	S32 first_drop_down_item = count; - -	// Calculating, how much buttons can fit in the bar -	S32 buttons_width = 0; -	for (S32 i = 0; i < count; ++i) +	const child_list_t* childs = getChildList(); +	child_list_const_iter_t child_it = childs->begin(); +	int first_changed_item_index = 0; +	int rightest_point = getRect().mRight - mChevronButton->getRect().getWidth(); +	//lets find first changed button +	while (child_it != childs->end())  	{ -		buttons_width += buttonWidth + buttonHGap; -		if (buttons_width > buttons_space) +		LLFavoriteLandmarkButton* button = dynamic_cast<LLFavoriteLandmarkButton*> (*child_it); +		if (button)  		{ -			// There is no space for all buttons. -			// Calculating the number of buttons, that are fit with chevron button -			buttons_space -= mChevronButton->getRect().getWidth() + buttonHGap; -			while (i >= 0 && buttons_width > buttons_space) +			// an child's order  and mItems  should be same    +			if (button->getLandmarkId() != mItems[first_changed_item_index]->getUUID() // sort order has been changed +					|| button->getLabelSelected() != mItems[first_changed_item_index]->getDisplayName() // favorite's name has been changed +					|| button->getRect().mRight < rightest_point) // favbar's width has been changed  			{ -				buttons_width -= buttonWidth + buttonHGap; -				i--; +				break;  			} -			first_drop_down_item = i + 1; // First item behind visible items -			 -			break; +			first_changed_item_index++;  		} +		child_it++;  	} +	// now first_changed_item_index should contains a number of button that need to change -	bool recreate_buttons = true; - -	// If inventory items are not changed up to mFirstDropDownItem, no need to recreate them -	if (mFirstDropDownItem == first_drop_down_item && (mItemNamesCache.size() == count || mItemNamesCache.size() == mFirstDropDownItem)) +	if (first_changed_item_index < mItems.count())  	{ -		S32 i; -		for (i = 0; i < mFirstDropDownItem; ++i) +		mUpdateDropDownItems = true; +		// Rebuild the buttons only +		// child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator + +		while (child_it != childs->end())  		{ -			if (mItemNamesCache.get(i) != mItems.get(i)->getName()) +			//lets remove other landmarks button and rebuild it +			child_list_const_iter_t cur_it = child_it++; +			LLFavoriteLandmarkButton* button = +					dynamic_cast<LLFavoriteLandmarkButton*> (*cur_it); +			if (button)  			{ -				break; +				removeChild(button); +				delete button;  			}  		} -		if (i == mFirstDropDownItem) +		// we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning +		if (mChevronButton->getParent() == this)  		{ -			recreate_buttons = false; +			removeChild(mChevronButton);  		} -	} - -	if (recreate_buttons) -	{ -		mFirstDropDownItem = first_drop_down_item; - -		mItemNamesCache.clear(); -		for (S32 i = 0; i < mFirstDropDownItem; i++) +		int last_right_edge = 0; +		if (getChildList()->size() > 0)  		{ -			mItemNamesCache.put(mItems.get(i)->getName()); +			last_right_edge = getChildList()->back()->getRect().mRight;  		} - -		// Rebuild the buttons only -		// child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator -		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ) +		//last_right_edge is saving coordinates +		LLButton* last_new_button = NULL; +		int j = first_changed_item_index; +		for (; j < mItems.count(); j++)  		{ -			child_list_const_iter_t cur_it = child_it++; -			LLView* viewp = *cur_it; -			LLButton* button = dynamic_cast<LLButton*>(viewp); -			if (button && (button != mChevronButton)) +			last_new_button = createButton(mItems[j], buttonXMLNode, last_right_edge); +			if (!last_new_button)  			{ -				removeChild(button); -				delete button; +				break;  			} -		} - -		createButtons(mItems, buttonXMLNode, buttonWidth, buttonHGap); -	} +			sendChildToBack(last_new_button); +			last_right_edge = last_new_button->getRect().mRight; -	// Chevron button -	if (mFirstDropDownItem != count) -	{ -		// Chevron button should stay right aligned -		LLRect rect; -		rect.setOriginAndSize(bar_width - mChevronButton->getRect().getWidth() - buttonHGap, 0, mChevronButton->getRect().getWidth(), mChevronButton->getRect().getHeight()); -		mChevronButton->setRect(rect); -		mChevronButton->setVisible(TRUE); +			mLastTab = last_new_button; +		} +		mFirstDropDownItem = j; +		// Chevron button +		if (mFirstDropDownItem < mItems.count()) +		{ +			S32 buttonHGap = 2; // default value +			buttonXMLNode->getAttributeS32("left", buttonHGap); +			LLRect rect; +			// Chevron button should stay right aligned +			rect.setOriginAndSize(getRect().mRight - mChevronButton->getRect().getWidth() - buttonHGap, 0, +					mChevronButton->getRect().getWidth(), +					mChevronButton->getRect().getHeight()); + +			addChild(mChevronButton); +			mChevronButton->setRect(rect); +			mChevronButton->setVisible(TRUE); +		}  	}  	else  	{ -		// Hide chevron button if all items are visible on bar -		mChevronButton->setVisible(FALSE); +		mUpdateDropDownItems = false;  	}  } - -void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &items, const LLXMLNodePtr &buttonXMLNode, S32 buttonWidth, S32 buttonHGap) +LLButton* LLFavoritesBarCtrl::createButton(const LLPointer<LLViewerInventoryItem> item, LLXMLNodePtr &buttonXMLNode, S32 x_offset)  { -	S32 curr_x = buttonHGap; -	// Adding buttons +	S32 def_button_width = 120; +	buttonXMLNode->getAttributeS32("width", def_button_width); +	S32 button_x_delta = 2; // default value +	buttonXMLNode->getAttributeS32("left", button_x_delta); +	S32 curr_x = x_offset; +	/** +	 * WORKAROUND: +	 * there are some problem with displaying of fonts in buttons.  +	 * Empty space (or ...) is displaying instead of last symbols, even though the width of the button is enough. +	 * Problem will gone, if we  stretch out the button. For that reason I have to put additional  10 pixels.  +	 */ +	int requred_width = mFont->getWidth(item->getDisplayName()) + 10;  +	int width = requred_width > def_button_width? def_button_width : requred_width;  	LLFavoriteLandmarkButton* fav_btn = NULL; -	mLandingTab = mLastTab = NULL; -	for(S32 i = mFirstDropDownItem -1, j = 0; i >= 0; i--) +	// do we have a place for next button + double buttonHGap + mChevronButton ?  +	if(curr_x + width + 2*button_x_delta +  mChevronButton->getRect().getWidth() > getRect().mRight )  	{ -		LLViewerInventoryItem* item = items.get(j++); - -		fav_btn = LLUICtrlFactory::defaultBuilder<LLFavoriteLandmarkButton>(buttonXMLNode, this, NULL); -		if (NULL == fav_btn) -		{ -			llwarns << "Unable to create button for landmark: " << item->getName() << llendl; -			continue; -		} - -		fav_btn->setLandmarkID(item->getUUID()); -		 -		// change only left and save bottom -		fav_btn->setOrigin(curr_x, fav_btn->getRect().mBottom); -		fav_btn->setFont(mFont); -		fav_btn->setName(item->getName()); -		fav_btn->setLabel(item->getName()); -		fav_btn->setToolTip(item->getName()); -		fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); -		fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); - -		fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); -		fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); - -		sendChildToBack(fav_btn); - -		curr_x += buttonWidth + buttonHGap; +		return NULL;  	} - -	mLastTab = fav_btn; +	fav_btn = LLUICtrlFactory::defaultBuilder<LLFavoriteLandmarkButton>(buttonXMLNode, this, NULL); +	if (NULL == fav_btn) +	{ +		llwarns << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << llendl; +		return NULL; +	} +	 +	LLRect butt_rect (fav_btn->getRect()); +	fav_btn->setLandmarkID(item->getUUID()); +	butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight()); +	 +	fav_btn->setRect(butt_rect); +	// change only left and save bottom +	fav_btn->setFont(mFont); +	fav_btn->setName(item->getName()); +	fav_btn->setLabel(item->getName()); +	fav_btn->setToolTip(item->getName()); +	fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); +	fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + +	fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); +	fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + +	return fav_btn;  } @@ -844,99 +847,61 @@ void LLFavoritesBarCtrl::showDropDownMenu()  	LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get(); -	if(menu) +	if (menu)  	{  		if (!menu->toggleVisibility())  			return; -		mItems.clear(); - -		if (!collectFavoriteItems(mItems)) -		{ -			return; -		} - -		S32 count = mItems.count(); - -		// Check it there are changed items, since last call -		if (mItemNamesCache.size() == count) -		{ -			S32 i; -			for (i = mFirstDropDownItem; i < count; i++) -			{ -				if (mItemNamesCache.get(i) != mItems.get(i)->getName()) -				{ -					break; -				} -			} - -			// Check passed, just show the menu -			if (i == count) -			{ -				menu->buildDrawLabels(); -				menu->updateParent(LLMenuGL::sMenuContainer); - -				if (menu->getButtonRect().isEmpty()) -				{ -					menu->setButtonRect(mChevronButton->getRect(), this); -				} - -				LLMenuGL::showPopup(this, menu, getRect().getWidth() - menu->getRect().getWidth(), 0); -				return; -			} -		} - -		// Add menu items to cache, if there is only names of buttons -		if (mItemNamesCache.size() == mFirstDropDownItem) +		U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); +		if (mUpdateDropDownItems)  		{ -			for (S32 i = mFirstDropDownItem; i < count; i++) -			{ -				mItemNamesCache.put(mItems.get(i)->getName()); -			} -		} - -		menu->empty(); +			menu->empty(); -		U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); -		U32 widest_item = 0; +			U32 widest_item = 0; -		for(S32 i = mFirstDropDownItem; i < count; i++) -		{ -			LLViewerInventoryItem* item = mItems.get(i); -			const std::string& item_name = item->getName(); - -			LLFavoriteLandmarkMenuItem::Params item_params; -			item_params.name(item_name); -			item_params.label(item_name); -			 -			item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); -			LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params); -			menu_item->initFavoritesBarPointer(this); -			menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this,item->getUUID(),_1,_2,_3,_4)); -			menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); -			menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); -			menu_item->setLandmarkID(item->getUUID()); - -			// Check whether item name wider than menu -			if (menu_item->getNominalWidth() > max_width) +			for (S32 i = mFirstDropDownItem; i < mItems.count(); i++)  			{ -				S32 chars_total = item_name.length(); -				S32 chars_fitted = 1; -				menu_item->setLabel(LLStringExplicit("")); -				S32 label_space = max_width - menu_item->getFont()->getWidth("...") - -					menu_item->getNominalWidth(); // This returns width of menu item with empty label (pad pixels) - -				while (chars_fitted < chars_total && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) +				LLViewerInventoryItem* item = mItems.get(i); +				const std::string& item_name = item->getName(); + +				LLFavoriteLandmarkMenuItem::Params item_params; +				item_params.name(item_name); +				item_params.label(item_name); + +				item_params.on_click.function(boost::bind( +						&LLFavoritesBarCtrl::onButtonClick, this, +						item->getUUID())); +				LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create<LLFavoriteLandmarkMenuItem>(item_params); +				menu_item->initFavoritesBarPointer(this); +				menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4)); +				menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); +				menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); +				menu_item->setLandmarkID(item->getUUID()); + +				// Check whether item name wider than menu +				if (menu_item->getNominalWidth() > max_width)  				{ -					chars_fitted++; +					S32 chars_total = item_name.length(); +					S32 chars_fitted = 1; +					menu_item->setLabel(LLStringExplicit("")); +					S32 label_space = max_width - menu_item->getFont()->getWidth("...") -  +							menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels)  + +					while (chars_fitted < chars_total +							&& menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) +					{ +						chars_fitted++; +					} +					chars_fitted--; // Rolling back one char, that doesn't fit + +					menu_item->setLabel(item_name.substr(0, chars_fitted) +							+ "...");  				} -				chars_fitted--; // Rolling back one char, that doesn't fit +				widest_item = llmax(widest_item, menu_item->getNominalWidth()); -				menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); +				menu->addChild(menu_item);  			} -			widest_item = llmax(widest_item, menu_item->getNominalWidth()); - -			menu->addChild(menu_item); +			mUpdateDropDownItems = false;  		}  		menu->buildDrawLabels(); @@ -945,7 +910,6 @@ void LLFavoritesBarCtrl::showDropDownMenu()  		menu->setButtonRect(mChevronButton->getRect(), this);  		LLMenuGL::showPopup(this, menu, getRect().getWidth() - max_width, 0); -		  	}  } diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index b2fe3cc651..9ac734baff 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -74,8 +74,8 @@ public:  	void setLandingTab(LLUICtrl* tab) { mLandingTab = tab; }  protected: -	void updateButtons(U32 bar_width); -	void createButtons(const LLInventoryModel::item_array_t &items, const LLXMLNodePtr &root, S32 buttonWidth, S32 buttonHGap); +	void updateButtons(); +	LLButton* createButton(const LLPointer<LLViewerInventoryItem> item, LLXMLNodePtr &root, S32 x_offset );  	LLXMLNodePtr getButtonXMLNode();  	BOOL collectFavoriteItems(LLInventoryModel::item_array_t &items); @@ -101,9 +101,7 @@ protected:  	LLUUID mFavoriteFolderId;  	const LLFontGL *mFont;  	S32 mFirstDropDownItem; - -	typedef LLDynamicArray<std::string> item_names_array_t; -	item_names_array_t mItemNamesCache; +	bool mUpdateDropDownItems;  	LLUUID mSelectedItemID; diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 7dc21e6e23..ca43833530 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -49,6 +49,7 @@  #include "lllogchat.h"  #include "llpanelimcontrolpanel.h"  #include "llscreenchannel.h" +#include "llsyswellwindow.h"  #include "lltrans.h"  #include "llchathistory.h"  #include "llviewerwindow.h" @@ -339,6 +340,29 @@ void LLIMFloater::onSlide()  //static  LLIMFloater* LLIMFloater::show(const LLUUID& session_id)  { +	if (!gIMMgr->hasSession(session_id)) return NULL; + +	// we should make sure all related chiclets are in place when the session is a voice call +	// chiclets come firts, then comes IM window +	if (gIMMgr->isVoiceCall(session_id)) +	{ +		LLIMModel* im_model = LLIMModel::getInstance(); +		LLBottomTray* b_tray = LLBottomTray::getInstance(); +		 +		//*TODO hide that into Bottom tray +		if (!b_tray->getChicletPanel()->findChiclet<LLChiclet>(session_id)) +		{ +			LLIMChiclet* chiclet = b_tray->createIMChiclet(session_id); +			if(chiclet) +			{ +				chiclet->setIMSessionName(im_model->getName(session_id)); +				chiclet->setOtherParticipantId(im_model->getOtherParticipantID(session_id)); +			} +		} + +		LLIMWellWindow::getInstance()->addIMRow(session_id); +	} +		  	bool not_existed = true;  	if(isChatMultiTab()) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 1d56fc0cab..9e878f8c75 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -93,7 +93,8 @@ const static std::string ADHOC_NAME_SUFFIX(" Conference");  std::string LLCallDialogManager::sPreviousSessionlName = "";  std::string LLCallDialogManager::sCurrentSessionlName = "";  LLIMModel::LLIMSession* LLCallDialogManager::sSession = NULL; - +LLVoiceChannel::EState LLCallDialogManager::sOldState = LLVoiceChannel::STATE_READY; +const LLUUID LLOutgoingCallDialog::OCD_KEY = LLUUID("7CF78E11-0CFE-498D-ADB9-1417BF03DDB4");  //  // Globals  // @@ -1273,19 +1274,32 @@ void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id)  	}  	sSession = session;  	sSession->mVoiceChannel->setStateChangedCallback(LLCallDialogManager::onVoiceChannelStateChanged); -	sPreviousSessionlName = sCurrentSessionlName; -	sCurrentSessionlName = session->mName; +	if(sCurrentSessionlName != session->mName) +	{ +		sPreviousSessionlName = sCurrentSessionlName; +		sCurrentSessionlName = session->mName; +	}  }  void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction)  {  	LLSD mCallDialogPayload; -	LLOutgoingCallDialog* ocd; +	LLOutgoingCallDialog* ocd = NULL; + +	if(sOldState == new_state) +	{ +		return; +	} + +	sOldState = new_state;  	mCallDialogPayload["session_id"] = sSession->mSessionID;  	mCallDialogPayload["session_name"] = sSession->mName;  	mCallDialogPayload["other_user_id"] = sSession->mOtherParticipantID;  	mCallDialogPayload["old_channel_name"] = sPreviousSessionlName; +	mCallDialogPayload["state"] = new_state; +	mCallDialogPayload["disconnected_channel_name"] = sSession->mName; +	mCallDialogPayload["session_type"] = sSession->mSessionType;  	switch(new_state)  	{			 @@ -1295,46 +1309,10 @@ void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EStat  		{  			return;  		} - -		ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); -		if (ocd) -		{ -			ocd->getChild<LLTextBox>("calling")->setVisible(true); -			ocd->getChild<LLTextBox>("leaving")->setVisible(true); -			ocd->getChild<LLTextBox>("connecting")->setVisible(false); -			ocd->getChild<LLTextBox>("noanswer")->setVisible(false); -			ocd->getChild<LLButton>("Cancel")->setVisible(true); -		} -		return; - -	case LLVoiceChannel::STATE_RINGING : -		ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); -		if (ocd) -		{ -			ocd->getChild<LLTextBox>("calling")->setVisible(false); -			ocd->getChild<LLTextBox>("leaving")->setVisible(true); -			ocd->getChild<LLTextBox>("connecting")->setVisible(true); -			ocd->getChild<LLTextBox>("noanswer")->setVisible(false); -			ocd->getChild<LLButton>("Cancel")->setVisible(true); -		} -		return; - -	case LLVoiceChannel::STATE_ERROR : -		mCallDialogPayload["start_timer"] = true; -		ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); -		if (ocd) -		{ -			ocd->getChild<LLTextBox>("calling")->setVisible(false); -			ocd->getChild<LLTextBox>("leaving")->setVisible(false); -			ocd->getChild<LLTextBox>("connecting")->setVisible(false); -			ocd->getChild<LLTextBox>("noanswer")->setVisible(true); -			ocd->getChild<LLButton>("Cancel")->setVisible(false); -		} -		return; +		break;  	case LLVoiceChannel::STATE_CONNECTED : -	case LLVoiceChannel::STATE_HUNG_UP : -		ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); +		ocd = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY);  		if (ocd)  		{  			ocd->closeFloater(); @@ -1345,6 +1323,11 @@ void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EStat  		break;  	} +	ocd = LLFloaterReg::getTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY); +	if(ocd) +	{ +		ocd->show(mCallDialogPayload); +	}	  }  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1374,12 +1357,13 @@ void LLCallDialog::onOpen(const LLSD& key)  LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) :  LLCallDialog(payload)  { -	LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", payload); +	LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY);  	if(instance && instance->getVisible())  	{  		instance->onCancel(instance);  	}	  } +  void LLOutgoingCallDialog::draw()  {  	if (lifetimeHasExpired()) @@ -1408,10 +1392,14 @@ void LLOutgoingCallDialog::onLifetimeExpired()  	closeFloater();  } -void LLOutgoingCallDialog::onOpen(const LLSD& key) +void LLOutgoingCallDialog::show(const LLSD& key)  { -	LLCallDialog::onOpen(key); +	mPayload = key; + +	// hide all text at first +	hideAllText(); +	// customize text strings  	// tell the user which voice channel they are leaving  	if (!mPayload["old_channel_name"].asString().empty())  	{ @@ -1422,6 +1410,12 @@ void LLOutgoingCallDialog::onOpen(const LLSD& key)  		childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat"));  	} +	if (!mPayload["disconnected_channel_name"].asString().empty()) +	{ +		childSetTextArg("nearby", "[VOICE_CHANNEL_NAME]", mPayload["disconnected_channel_name"].asString()); +		childSetTextArg("nearby_P2P", "[VOICE_CHANNEL_NAME]", mPayload["disconnected_channel_name"].asString()); +	} +  	std::string callee_name = mPayload["session_name"].asString();  	if (callee_name == "anonymous")  	{ @@ -1438,12 +1432,48 @@ void LLOutgoingCallDialog::onOpen(const LLSD& key)  	// stop timer by default  	mLifetimeTimer.stop(); -	if(mPayload.has("start_timer")) + +	// show only necessary strings and controls +	switch(mPayload["state"].asInteger())  	{ -		mLifetimeTimer.reset(); +	case LLVoiceChannel::STATE_CALL_STARTED : +		getChild<LLTextBox>("calling")->setVisible(true); +		getChild<LLTextBox>("leaving")->setVisible(true); +		break; +	case LLVoiceChannel::STATE_RINGING : +		getChild<LLTextBox>("leaving")->setVisible(true); +		getChild<LLTextBox>("connecting")->setVisible(true); +		break; +	case LLVoiceChannel::STATE_ERROR : +		getChild<LLTextBox>("noanswer")->setVisible(true); +		getChild<LLButton>("Cancel")->setVisible(false); +		mLifetimeTimer.start(); +		break; +	case LLVoiceChannel::STATE_HUNG_UP : +		if (mPayload["session_type"].asInteger() == LLIMModel::LLIMSession::P2P_SESSION) +		{ +			getChild<LLTextBox>("nearby_P2P")->setVisible(true); +		}  +		else +		{ +			getChild<LLTextBox>("nearby")->setVisible(true); +		} +		getChild<LLButton>("Cancel")->setVisible(false); +		mLifetimeTimer.start();  	} + +	openFloater(LLOutgoingCallDialog::OCD_KEY);  } +void LLOutgoingCallDialog::hideAllText() +{ +	getChild<LLTextBox>("calling")->setVisible(false); +	getChild<LLTextBox>("leaving")->setVisible(false); +	getChild<LLTextBox>("connecting")->setVisible(false); +	getChild<LLTextBox>("nearby_P2P")->setVisible(false); +	getChild<LLTextBox>("nearby")->setVisible(false); +	getChild<LLTextBox>("noanswer")->setVisible(false); +}  //static  void LLOutgoingCallDialog::onCancel(void* user_data) @@ -2733,6 +2763,11 @@ public:  		{  			im_floater->processSessionUpdate(input["body"]["info"]);  		} +		LLIMSpeakerMgr* im_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); +		if (im_mgr) +		{ +			im_mgr->processSessionUpdate(input["body"]["info"]); +		}  	}  }; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 6eb3f3d07f..09f0c9df71 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -467,6 +467,7 @@ protected:  	static std::string sPreviousSessionlName;  	static std::string sCurrentSessionlName;  	static LLIMModel::LLIMSession* sSession; +	static LLVoiceChannel::EState sOldState;  };  class LLCallDialog : public LLDockableFloater @@ -504,14 +505,18 @@ public:  	LLOutgoingCallDialog(const LLSD& payload);  	/*virtual*/ BOOL postBuild(); -	/*virtual*/ void onOpen(const LLSD& key); +	void show(const LLSD& key);  	static void onCancel(void* user_data); +	static const LLUUID OCD_KEY;  	// check timer state  	/*virtual*/ void draw();  private: + +	// hide all text boxes +	void hideAllText();  	// lifetime timer for NO_ANSWER notification  	LLTimer	mLifetimeTimer;  	// lifetime duration for NO_ANSWER notification diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index bacc685130..35ae4dee8e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2929,6 +2929,27 @@ LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_a  	return result;  } +// See also LLInventorySort where landmarks in the Favorites folder are sorted. +class LLViewerInventoryItemSort +{ +public: +	bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b) +	{ +		return a->getSortField() < b->getSortField(); +	} +}; + +/** + * Sorts passed items by LLViewerInventoryItem sort field. + * + * @param[in, out] items - array of items, not sorted. + */ +void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& items) +{ +	static LLViewerInventoryItemSort sort_functor; +	std::sort(items.begin(), items.end(), sort_functor); +} +  void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId)  {  	LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId); @@ -3044,6 +3065,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,  					LLUUID srcItemId = inv_item->getUUID();  					LLUUID destItemId = itemp->getListener()->getUUID(); +					// ensure items are sorted properly before changing order. EXT-3498 +					rearrange_item_order_by_sort_field(items); +  					// update order  					updateItemsOrder(items, srcItemId, destItemId); diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 39381e3faa..fa16cb6473 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -243,7 +243,8 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id)  		}  		else  		{ -			setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId)); +			// check only blocking on voice. EXT-3542 +			setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat));  			LLMuteList::getInstance()->addObserver(this);  		}  	} @@ -251,5 +252,6 @@ void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id)  void LLOutputMonitorCtrl::onChange()  { -	setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId)); +	// check only blocking on voice. EXT-3542 +	setIsMuted(LLMuteList::getInstance()->isMuted(mSpeakerId, LLMute::flagVoiceChat));  } diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 4f76d32ad5..70e4798079 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -194,6 +194,7 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)  		childSetEnabled("pay_btn", FALSE);          getChild<LLTextBox>("avatar_name")->setValue(im_session->mName); +        getChild<LLTextBox>("avatar_name")->setToolTip(im_session->mName);  	}  	else  	{ @@ -217,6 +218,7 @@ void LLPanelIMControlPanel::nameUpdatedCallback(const LLUUID& id, const std::str  		avatar_name.append(" ");  		avatar_name.append(last);  		getChild<LLTextBox>("avatar_name")->setValue(avatar_name); +		getChild<LLTextBox>("avatar_name")->setToolTip(avatar_name);  	}  } diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 2c5f1b094e..93e5b8fa15 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -49,43 +49,6 @@  #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally  #endif -class ModerationResponder : public LLHTTPClient::Responder -{ -public: -	ModerationResponder(const LLUUID& session_id) -	{ -		mSessionID = session_id; -	} - -	virtual void error(U32 status, const std::string& reason) -	{ -		llwarns << status << ": " << reason << llendl; - -		if ( gIMMgr ) -		{ -			//403 == you're not a mod -			//should be disabled if you're not a moderator -			if ( 403 == status ) -			{ -				gIMMgr->showSessionEventError( -					"mute", -					"not_a_mod_error", -					mSessionID); -			} -			else -			{ -				gIMMgr->showSessionEventError( -					"mute", -					"generic_request_error", -					mSessionID); -			} -		} -	} - -private: -	LLUUID mSessionID; -}; -  LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list,  bool use_context_menu/* = true*/):  	mSpeakerMgr(data_source),  	mAvatarList(avatar_list), @@ -471,22 +434,13 @@ void LLParticipantList::LLParticipantListMenu::show(LLView* spawning_view, const  void LLParticipantList::LLParticipantListMenu::toggleAllowTextChat(const LLSD& userdata)  { -	const LLUUID speaker_id = mUUIDs.front(); -	std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); -	LLSD data; -	data["method"] = "mute update"; -	data["session-id"] = mParent.mSpeakerMgr->getSessionID(); -	data["params"] = LLSD::emptyMap(); -	data["params"]["agent_id"] = speaker_id; -	data["params"]["mute_info"] = LLSD::emptyMap(); -	//current value represents ability to type, so invert -	data["params"]["mute_info"]["text"] = !mParent.mSpeakerMgr->findSpeaker(speaker_id)->mModeratorMutedText; - -	LLHTTPClient::post( -		url, -		data, -		new ModerationResponder(mParent.mSpeakerMgr->getSessionID())); +	LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mParent.mSpeakerMgr); +	if (mgr) +	{ +		const LLUUID speaker_id = mUUIDs.front(); +		mgr->toggleAllowTextChat(speaker_id); +	}  }  void LLParticipantList::LLParticipantListMenu::toggleMute(const LLSD& userdata, U32 flags) @@ -565,47 +519,19 @@ void LLParticipantList::LLParticipantListMenu::moderateVoice(const LLSD& userdat  void LLParticipantList::LLParticipantListMenu::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute)  { -	if (gAgentID == avatar_id) return; // do not process myself - -	LLPointer<LLSpeaker> speakerp = mParent.mSpeakerMgr->findSpeaker(avatar_id); -	if (!speakerp) return; - -	// *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for -	// text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) -	bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; - -	// do not send voice moderation changes for avatars not in voice channel -	if (!is_in_voice) return; - -	std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); -	LLSD data; -	data["method"] = "mute update"; -	data["session-id"] = mParent.mSpeakerMgr->getSessionID(); -	data["params"] = LLSD::emptyMap(); -	data["params"]["agent_id"] = avatar_id; -	data["params"]["mute_info"] = LLSD::emptyMap(); -	data["params"]["mute_info"]["voice"] = !unmute; - -	LLHTTPClient::post( -		url, -		data, -		new ModerationResponder(mParent.mSpeakerMgr->getSessionID())); +	LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mParent.mSpeakerMgr); +	if (mgr) +	{ +		mgr->moderateVoiceParticipant(avatar_id, unmute); +	}  }  void LLParticipantList::LLParticipantListMenu::moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute)  { -	LLSpeakerMgr::speaker_list_t speakers; -	mParent.mSpeakerMgr->getSpeakerList(&speakers, FALSE); - -	for (LLSpeakerMgr::speaker_list_t::iterator iter = speakers.begin(); -		iter != speakers.end(); ++iter) +	LLIMSpeakerMgr* mgr = dynamic_cast<LLIMSpeakerMgr*>(mParent.mSpeakerMgr); +	if (mgr)  	{ -		LLSpeaker* speakerp = (*iter).get(); -		LLUUID speaker_id = speakerp->mID; - -		if (excluded_avatar_id == speaker_id) continue; - -		moderateVoiceParticipant(speaker_id, unmute); +		mgr->moderateVoiceOtherParticipants(excluded_avatar_id, unmute);  	}  } diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 261bdbcfc0..3861a96355 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -36,6 +36,7 @@  #include "llagent.h"  #include "llappviewer.h" +#include "llimview.h"  #include "llmutelist.h"  #include "llsdutil.h"  #include "lluicolortable.h" @@ -575,6 +576,143 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  	}  } +class ModerationResponder : public LLHTTPClient::Responder +{ +public: +	ModerationResponder(const LLUUID& session_id) +	{ +		mSessionID = session_id; +	} + +	virtual void error(U32 status, const std::string& reason) +	{ +		llwarns << status << ": " << reason << llendl; + +		if ( gIMMgr ) +		{ +			//403 == you're not a mod +			//should be disabled if you're not a moderator +			if ( 403 == status ) +			{ +				gIMMgr->showSessionEventError( +					"mute", +					"not_a_mod_error", +					mSessionID); +			} +			else +			{ +				gIMMgr->showSessionEventError( +					"mute", +					"generic_request_error", +					mSessionID); +			} +		} +	} + +private: +	LLUUID mSessionID; +}; + +void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) +{ +	std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); +	LLSD data; +	data["method"] = "mute update"; +	data["session-id"] = getSessionID(); +	data["params"] = LLSD::emptyMap(); +	data["params"]["agent_id"] = speaker_id; +	data["params"]["mute_info"] = LLSD::emptyMap(); +	//current value represents ability to type, so invert +	data["params"]["mute_info"]["text"] = !findSpeaker(speaker_id)->mModeratorMutedText; + +	LLHTTPClient::post(url, data, new ModerationResponder(getSessionID())); +} + +void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) +{ +	if (gAgentID == avatar_id) return; // do not process myself + +	LLPointer<LLSpeaker> speakerp = findSpeaker(avatar_id); +	if (!speakerp) return; + +	// *NOTE: mantipov: probably this condition will be incorrect when avatar will be blocked for +	// text chat via moderation (LLSpeaker::mModeratorMutedText == TRUE) +	bool is_in_voice = speakerp->mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || speakerp->mStatus == LLSpeaker::STATUS_MUTED; + +	// do not send voice moderation changes for avatars not in voice channel +	if (!is_in_voice) return; + +	std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); +	LLSD data; +	data["method"] = "mute update"; +	data["session-id"] = getSessionID(); +	data["params"] = LLSD::emptyMap(); +	data["params"]["agent_id"] = avatar_id; +	data["params"]["mute_info"] = LLSD::emptyMap(); +	data["params"]["mute_info"]["voice"] = !unmute; + +	LLHTTPClient::post( +		url, +		data, +		new ModerationResponder(getSessionID())); +} + +void LLIMSpeakerMgr::moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute_everyone_else) +{ +	// *TODO: mantipov: add more intellectual processing of several following requests if it is needed. +	/* +		Such situation should be tested: +		 "Moderator sends the same second request before first response is come" +		Moderator sends "mute everyone else" for A and then for B +			two requests to disallow voice chat are sent +			UUID of B is stored. +		Then first response (to disallow voice chat) is come +			request to allow voice for stored avatar (B) +		Then second response (to disallow voice chat) is come +			have nothing to do, the latest selected speaker is already enabled + +			What can happen? +		If request to allow voice for stored avatar (B) is processed on server BEFORE  +		second request to disallow voice chat all speakers will be disabled on voice. +		But I'm not sure such situation is possible.  +		See EXT-3431. +	*/ + +	mReverseVoiceModeratedAvatarID = excluded_avatar_id; +	moderateVoiceSession(getSessionID(), !unmute_everyone_else); +} + +void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update) +{ +	if (mReverseVoiceModeratedAvatarID.isNull()) return; + +	if (session_update.has("moderated_mode") && +		session_update["moderated_mode"].has("voice")) +	{ +		BOOL voice_moderated = session_update["moderated_mode"]["voice"]; + +		moderateVoiceParticipant(mReverseVoiceModeratedAvatarID, voice_moderated); + +		mReverseVoiceModeratedAvatarID = LLUUID::null; +	} +} + +void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice) +{ +	std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); +	LLSD data; +	data["method"] = "session update"; +	data["session-id"] = session_id; +	data["params"] = LLSD::emptyMap(); + +	data["params"]["update_info"] = LLSD::emptyMap(); + +	data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); +	data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; + +	LLHTTPClient::post(url, data, new ModerationResponder(session_id)); +} +  //  // LLActiveSpeakerMgr diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 04046a8587..1a8c23f56a 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -158,8 +158,43 @@ public:  	void updateSpeakers(const LLSD& update);  	void setSpeakers(const LLSD& speakers); + +	void toggleAllowTextChat(const LLUUID& speaker_id); + +	/** +	 * Mutes/Unmutes avatar for current group voice chat. +	 * +	 * It only marks avatar as muted for session and does not use local Agent's Block list. +	 * It does not mute Agent itself. +	 * +	 * @param[in] avatar_id UUID of avatar to be processed +	 * @param[in] unmute if false - specified avatar will be muted, otherwise - unmuted. +	 * +	 * @see moderateVoiceOtherParticipants() +	 */ +	void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); + +	/** +	 * Mutes/Unmutes all avatars except specified for current group voice chat. +	 * +	 * It only marks avatars as muted for session and does not use local Agent's Block list. +	 * It based call moderateVoiceParticipant() for each avatar should be muted/unmuted. +	 * +	 * @param[in] excluded_avatar_id UUID of avatar NOT to be processed +	 * @param[in] unmute_everyone_else if false - avatars will be muted, otherwise - unmuted. +	 * +	 * @see moderateVoiceParticipant() +	 */ +	void moderateVoiceOtherParticipants(const LLUUID& excluded_avatar_id, bool unmute_everyone_else); + +	void processSessionUpdate(const LLSD& session_update); +  protected:  	virtual void updateSpeakerList(); + +	void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); + +	LLUUID mReverseVoiceModeratedAvatarID;  };  class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index f49e7ef0da..3769ddb1cc 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -32,6 +32,8 @@  #include "llviewerprecompiledheaders.h" // must be first include +#include "llagent.h" +  #include "llflatlistview.h"  #include "llfloaterreg.h"  #include "llnotifications.h" @@ -709,8 +711,8 @@ BOOL LLIMWellWindow::postBuild()  void LLIMWellWindow::sessionAdded(const LLUUID& session_id,  								   const std::string& name, const LLUUID& other_participant_id)  { -	if (!mMessageList->getItemByValue(session_id)) return; -	 +	if (mMessageList->getItemByValue(session_id)) return; +  	// For im sessions started as voice call chiclet gets created on the first incoming message  	if (gIMMgr->isVoiceCall(session_id)) return; @@ -857,4 +859,36 @@ void LLIMWellWindow::removeObjectRow(const LLUUID& object_id)  	}  } + +void LLIMWellWindow::addIMRow(const LLUUID& session_id) +{ +	if (hasIMRow(session_id)) return; + +	LLIMModel* im_model = LLIMModel::getInstance(); +	addIMRow(session_id, 0, im_model->getName(session_id), im_model->getOtherParticipantID(session_id)); +	reshapeWindow(); +} + +bool LLIMWellWindow::hasIMRow(const LLUUID& session_id) +{ +	return mMessageList->getItemByValue(session_id); +} + +void LLIMWellWindow::onNewIM(const LLSD& data) +{ +	LLUUID from_id = data["from_id"]; +	if (from_id.isNull() || gAgentID == from_id) return; + +	LLUUID session_id = data["session_id"]; +	if (session_id.isNull()) return; + +	if (!gIMMgr->isVoiceCall(session_id)) return; + +	if (hasIMRow(session_id)) return; + +	//first real message, time to create chiclet +	addIMRow(session_id); +} + +  // EOF diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index fea145a17e..736b1b9fb4 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -188,9 +188,14 @@ public:  	/*virtual*/ void sessionRemoved(const LLUUID& session_id);  	/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id); +	void onNewIM(const LLSD& data); +  	void addObjectRow(const LLUUID& object_id, bool new_message = false);  	void removeObjectRow(const LLUUID& object_id); +	void addIMRow(const LLUUID& session_id); +	bool hasIMRow(const LLUUID& session_id); +  protected:  	/*virtual*/ const std::string& getAnchorViewName() { return IM_WELL_ANCHOR_NAME; } diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index fd4e7bb91f..60a2c3b638 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -229,7 +229,6 @@ void LLVoiceChannel::handleStatusChange(EStatusType type)  		{  			// if forceably removed from channel  			// update the UI and revert to default channel -			LLNotificationsUtil::add("VoiceChannelDisconnected", mNotifyArgs);  			deactivate();  		}  		mIgnoreNextSessionLeave = FALSE; @@ -741,6 +740,7 @@ void LLVoiceChannelP2P::handleStatusChange(EStatusType type)  	case STATUS_LEFT_CHANNEL:  		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)  		{ +			// *TODO: use it to show DECLINE voice notification  			if (mState == STATE_RINGING)  			{  				// other user declined call @@ -748,8 +748,7 @@ void LLVoiceChannelP2P::handleStatusChange(EStatusType type)  			}  			else  			{ -				// other user hung up -				LLNotificationsUtil::add("VoiceChannelDisconnectedP2P", mNotifyArgs); +				// other user hung up				  			}  			deactivate();  		} 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 a4ade9d0df..156370a459 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -30,14 +30,15 @@        layout="topleft"        follows="left"        label="IM Control Panel" +      min_width="115"         auto_resize="false" -      user_resize="false" /> +      user_resize="true" />      <layout_panel         left="0"         top="0"         height="200"  	     width="245" -       user_resize="false"> +       user_resize="true">          <button            height="20"            follows="left|top" diff --git a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml index ae4d5042ef..c6bc093c6c 100644 --- a/indra/newview/skins/default/xui/en/floater_outgoing_call.xml +++ b/indra/newview/skins/default/xui/en/floater_outgoing_call.xml @@ -69,7 +69,29 @@ Calling [CALLEE_NAME]       word_wrap="true">  No Answer.  Please try again later.      </text> -    <text +  <text +   font="SansSerifLarge" +   height="40" +   layout="topleft" +   left="77" +   name="nearby" +   top="27" +   width="315" +   word_wrap="true"> +    You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat. +  </text> +  <text +   font="SansSerifLarge" +   height="40" +   layout="topleft" +   left="77" +   name="nearby_P2P" +   top="27" +   width="315" +   word_wrap="true"> +    [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat. +  </text> +  <text       font="SansSerif"       height="50"       layout="topleft" @@ -80,7 +102,7 @@ No Answer.  Please try again later.       word_wrap="true">  Leaving [CURRENT_CHAT].      </text> -    <button +  <button       height="24"       label="Cancel"       label_selected="Cancel" diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml index c1a211967c..a86126227e 100644 --- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml +++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml @@ -31,12 +31,14 @@          No one near      </string>      <panel -     bevel_style="in" +     bevel_style="out" +     border="true"       follows="left|right|top"       height="62"       layout="topleft"       left="0"       name="control_panel" +     top="0"       width="282">          <panel           height="18" @@ -79,51 +81,14 @@               visible="true"               width="20" />          </panel> -        <layout_stack -         animate="false" -         bottom="10" -         clip="false" +        <button           follows="left|right|top"           height="24" -         layout="bottomleft" -         orientation="horizontal" -         width="262"> -            <layout_panel -             auto_resize="false"  -             follows="left" -             layout="topleft" -             min_width="24" -             name="microphone_icon_panel"  -             top="0" -             user_resize="false" -             width="24"> -                <icon -                 height="24" -                 image_name="Microphone_On" -                 layout="topleft" -                 name="Microphone_On" -                 top="0" -                 width="24" /> -            </layout_panel> -            <layout_panel -             auto_resize="false" -             layout="topleft" -             min_width="100"  -             name="leave_btn_panel"  -             top="0" -             user_resize="false" -             visible="false"  -             width="100"> -                <button -                 follows="left|right|top" -                 height="24" -                 label="Leave Call" -                 left="0"  -                 name="leave_call_btn" -                 top="0"  -                 width="100" /> -            </layout_panel> -        </layout_stack> +         label="Leave Call" +         left="91"  +         name="leave_call_btn" +         top_pad="6"  +         width="100" />      </panel>      <avatar_list       follows="all" @@ -143,4 +108,12 @@       name="non_avatar_caller"       top="70"       width="282" /> +    <view_border +     bevel_style="out" +     follows="left|top|right|bottom" +     height="206" +     layout="topleft" +     left="0" +     top="63" +     width="282" />  </floater> diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml index f5fce65c73..f3a2297151 100644 --- a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml @@ -36,9 +36,9 @@           follows="all"           height="20"           label="Call" -         left_delta="40" +         left_delta="10"           name="call_btn" -         width="100" /> +         width="160" />          <button           bottom="40"           follows="all" @@ -46,14 +46,15 @@           label="Leave Call"           name="end_call_btn"           visible="false" -         width="100" /> +          />          <button           follows="all"           bottom="10"           height="20"           label="Voice Controls"           name="voice_ctrls_btn" +         use_ellipses="true"            visible="false" -         width="100" /> +          />      </panel>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 034f685ee9..3e2910458f 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -351,9 +351,9 @@ image_pressed_selected  "Lit" + "Selected" - there are new messages and the Well                   height="23"                   image_overlay="Unread_IM"                   image_overlay_alignment="center" -                 image_pressed="WellButton_Lit_Selected" -                 image_pressed_selected="WellButton_Lit" -                 image_selected="WellButton_Lit" +                 image_pressed="WellButton_Lit" +                 image_pressed_selected="WellButton_Lit_Selected" +                 image_selected="PushButton_Selected_Press"                   label_color="Black"                   left="0"                   max_displayed_count="99" @@ -391,9 +391,9 @@ image_pressed_selected  "Lit" + "Selected" - there are new messages and the Well               width="35">                <button                   bottom_pad="3" -                 image_selected="WellButton_Lit" -                 image_pressed="WellButton_Lit_Selected" -                 image_pressed_selected="WellButton_Lit " +                 image_pressed="WellButton_Lit" +                 image_pressed_selected="WellButton_Lit_Selected" +                 image_selected="PushButton_Selected_Press"                auto_resize="true"                 halign="center"                 height="23" diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml index a5445a5783..86b30ebfce 100644 --- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml @@ -24,9 +24,10 @@       follows="left|right|bottom"       height="23"       label="Group Profile" -     left_delta="28" +     left_delta="10"       name="group_info_btn" -     width="125" /> +     use_ellipses="true"  +     width="160" />      <panel       background_visible="true"       bg_alpha_color="DkGray2" @@ -43,24 +44,27 @@           follows="all"           height="23"           label="Call Group" -         left_delta="28" +         left_delta="10"           name="call_btn" -         width="125" /> +         use_ellipses="true"  +         width="160" />          <button           bottom="40"           follows="all"           height="23"           label="Leave Call"           name="end_call_btn" +         use_ellipses="true"            visible="false" -         width="125" /> +          />          <button           bottom="10"           follows="all"           height="23"           label="Open Voice Controls"           name="voice_ctrls_btn" +         use_ellipses="true"            visible="false" -         width="125" /> +          />      </panel>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index e8e4a9dbb2..74265a51ca 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -149,6 +149,7 @@      <favorites_bar       follows="left|right|top" +     font="SansSerif"       height="15"       layout="topleft"       left="0" | 
