Commits

Anonymous committed 64ae3cd Merge

Merge with (specific revision) and head

  • Participants
  • Parent commits 2c49905, ba8bcf6

Comments (0)

Files changed (81)

indra/llui/lldockablefloater.cpp

 LLDockableFloater::LLDockableFloater(LLDockControl* dockControl,
 		const LLSD& key, const Params& params) :
 	LLFloater(key, params), mDockControl(dockControl), mUniqueDocking(true)
+	, mOverlapsScreenChannel(false)
 {
 	init(this);
 }

indra/llui/lldockablefloater.h

 	LOG_CLASS(LLDockableFloater);
 	LLDockableFloater(LLDockControl* dockControl, const LLSD& key,
 			const Params& params = getDefaultParams());
+
+	/**
+	 * Constructor.
+	 * @param dockControl a pointer to the doc control instance
+	 * @param uniqueDocking - a flag defines is docking should work as tab(at one
+	 * moment only one docked floater can be shown), also this flag defines is dock
+	 * tongue should be used.
+	 * @params key a floater key.
+ 	 * @params params a floater parameters
+	 */
 	LLDockableFloater(LLDockControl* dockControl, bool uniqueDocking,
 			const LLSD& key, const Params& params = getDefaultParams());
 	virtual ~LLDockableFloater();
 
 	LLDockControl* getDockControl();
 
+	/**
+	 * Returns true if screen channel should consider floater's size when drawing toasts.
+	 *
+	 * By default returns false.
+	 */
+	virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); }
+	virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; }
+
+	bool getUniqueDocking() { return mUniqueDocking;	}
 private:
 	/**
 	 * Provides unique of dockable floater.
 	 *  non exclusively.
 	 */
 	bool mUniqueDocking;
+
+	bool mOverlapsScreenChannel;
 };
 
 #endif /* LL_DOCKABLEFLOATER_H */

indra/llui/lldockcontrol.cpp

 	LLRect rootRect;
 	mGetAllowedRectCallback(rootRect);
 
+	bool unique_docking = false;
+	LLDockableFloater* dockable_floater =
+			dynamic_cast<LLDockableFloater*> (mDockableFloater);
+	if (dockable_floater != NULL)
+	{
+		unique_docking = dockable_floater->getUniqueDocking();
+	}
+
 	LLRect dockableRect = mDockableFloater->calcScreenRect();
 	S32 x = 0;
 	S32 y = 0;
 
 	case TOP:
 		x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
-		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
+		y = dockRect.mTop + dockableRect.getHeight();
+		// unique docking used with dock tongue, so add tongue height o the Y coordinate
+		if (unique_docking)
+		{
+			y += mDockTongue->getHeight();
+		}
+
 		// check is dockable inside root view rect
 		if (x < rootRect.mLeft)
 		{
 
 void LLDockControl::drawToungue()
 {
-	if (mEnabled)
+	bool unique_docking = false;
+	LLDockableFloater* dockable_floater =
+			dynamic_cast<LLDockableFloater*> (mDockableFloater);
+	if (dockable_floater != NULL)
+	{
+		unique_docking = dockable_floater->getUniqueDocking();
+	}
+
+	if (mEnabled && unique_docking)
 	{
 		mDockTongue->draw(mDockTongueX, mDockTongueY);
 	}

indra/llui/llflatlistview.cpp

 	return mItemsPanel->getRect(); 
 }
 
-bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/)
+bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/)
 {
 	if (!item) return false;
 	if (value.isUndefined()) return false;
 	// Children don't accept the focus
 	item->setTabStop(false);
 
-	rearrangeItems();
-	notifyParentItemsRectChanged();
+	if (rearrange)
+	{
+		rearrangeItems();
+		notifyParentItemsRectChanged();
+	}
 	return true;
 }
 
 			return 1;
 		}
 	}
+	else if (info.has("rearrange"))
+	{
+		rearrangeItems();
+		notifyParentItemsRectChanged();
+		return 1;
+	}
 	return 0;
 }
 
+void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items)
+{
+	LLSD action;
+	action.with("detach", LLSD());
+	// Clear detached_items list
+	detached_items.clear();
+	// Go through items and detach valid items, remove them from items panel
+	// and add to detached_items.
+	for (pairs_iterator_t
+			 iter = mItemPairs.begin(),
+			 iter_end = mItemPairs.end();
+		 iter != iter_end; ++iter)
+	{
+		LLPanel* pItem = (*iter)->first;
+		if (1 == pItem->notify(action))
+		{
+			selectItemPair((*iter), false);
+			mItemsPanel->removeChild(pItem);
+			detached_items.push_back(pItem);
+		}
+	}
+	if (!detached_items.empty())
+	{
+		// Some items were detached, clean ourself from unusable memory
+		if (detached_items.size() == mItemPairs.size())
+		{
+			// This way will be faster if all items were disconnected
+			for (pairs_iterator_t
+					 iter = mItemPairs.begin(),
+					 iter_end = mItemPairs.end();
+				 iter != iter_end; ++iter)
+			{
+				(*iter)->first = NULL;
+				delete *iter;
+			}
+			mItemPairs.clear();
+			// Also set items panel height to zero.
+			// Reshape it to allow reshaping of non-item children.
+			LLRect rc = mItemsPanel->getRect();
+			rc.mBottom = rc.mTop;
+			mItemsPanel->reshape(rc.getWidth(), rc.getHeight());
+			mItemsPanel->setRect(rc);
+			setNoItemsCommentVisible(true);
+		}
+		else
+		{
+			for (std::vector<LLPanel*>::const_iterator
+					 detached_iter = detached_items.begin(),
+					 detached_iter_end = detached_items.end();
+				 detached_iter != detached_iter_end; ++detached_iter)
+			{
+				LLPanel* pDetachedItem = *detached_iter;
+				for (pairs_iterator_t
+						 iter = mItemPairs.begin(),
+						 iter_end = mItemPairs.end();
+					 iter != iter_end; ++iter)
+				{
+					item_pair_t* item_pair = *iter;
+					if (item_pair->first == pDetachedItem)
+					{
+						mItemPairs.erase(iter);
+						item_pair->first = NULL;
+						delete item_pair;
+						break;
+					}
+				}
+			}
+			rearrangeItems();
+		}
+		notifyParentItemsRectChanged();
+	}
+}
+
 //EOF

indra/llui/llflatlistview.h

 	/** Returns full rect of child panel */
 	const LLRect& getItemsRect() const;
 
+	LLRect getRequiredRect() { return getItemsRect(); }
+
 	/** Returns distance between items */
 	const S32 getItemsPad() { return mItemPad; }
 
 	 * Adds and item and LLSD value associated with it to the list at specified position
 	 * @return true if the item was added, false otherwise 
 	 */
-	virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM);
+	virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true);
 
 	/**
 	 * Insert item_to_add along with associated value to the list right after the after_item.
 	virtual void clear();
 
 	/**
+	 * Removes all items that can be detached from the list but doesn't destroy
+	 * them, caller responsible to manage items after they are detached.
+	 * Detachable item should accept "detach" action via notify() method,
+	 * where it disconnect all callbacks, does other valuable routines and
+	 * return 1.
+	 */
+	void detachItems(std::vector<LLPanel*>& detached_items);
+
+	/**
 	 * Set comparator to use for future sorts.
 	 * 
 	 * This class does NOT manage lifetime of the comparator

indra/llui/llfloater.cpp

 	if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
 	{
 		child->setFocus(TRUE);
+		// floater did not take focus, so relinquish focus to world
+		if (!child->hasFocus())
+		{
+			gFocusMgr.setKeyboardFocus(NULL);
+		}
 	}
 }
 

indra/llui/llmenugl.cpp

 
 	LLContextMenuBranch(const Params&);
 
+	virtual ~LLContextMenuBranch()
+	{
+		delete mBranch;
+	}
+
 	// called to rebuild the draw label
 	virtual void	buildDrawLabel( void );
 

indra/llui/lltextbase.h

 	bool					scrolledToEnd();
 
 	const LLFontGL*			getDefaultFont() const					{ return mDefaultFont; }
+	LLStyle::Params			getDefaultStyle();
 
 public:
 	// Fired when a URL link is clicked
 	LLTextBase(const Params &p);
 	virtual ~LLTextBase();
 	void							initFromParams(const Params& p);
-	LLStyle::Params					getDefaultStyle();
 	virtual void					onValueChange(S32 start, S32 end);
 
 	// draw methods

indra/newview/CMakeLists.txt

     llinventorymodel.cpp
     llinventoryobserver.cpp
     llinventorypanel.cpp
-    llinventorysubtreepanel.cpp
     lljoystickbutton.cpp
     lllandmarkactions.cpp
     lllandmarklist.cpp
     llparticipantlist.cpp
     llpatchvertexarray.cpp
     llplacesinventorybridge.cpp
+    llplacesinventorypanel.cpp
     llpolymesh.cpp
     llpolymorph.cpp
     llpreview.cpp
     llinventorymodel.h
     llinventoryobserver.h
     llinventorypanel.h
-    llinventorysubtreepanel.h
     lljoystickbutton.h
     lllandmarkactions.h
     lllandmarklist.h
     llparticipantlist.h
     llpatchvertexarray.h
     llplacesinventorybridge.h
+    llplacesinventorypanel.h
     llpolymesh.h
     llpolymorph.h
     llpreview.h

indra/newview/app_settings/settings.xml

       <key>Value</key>
       <string>Default</string>
     </map>
+    <key>VoiceParticipantLeftRemoveDelay</key>
+    <map>
+      <key>Comment</key>
+      <string>Timeout to remove participants who has left Voice chat from the list in Voice Controls Panel</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>10</integer>
+    </map>
     <key>VoicePort</key>
     <map>
       <key>Comment</key>

indra/newview/llavatarlist.cpp

 // Used to limit time spent for avatar list update per frame.
 static const unsigned ADD_LIMIT = 50;
 
+bool LLAvatarList::contains(const LLUUID& id)
+{
+	const uuid_vector_t& ids = getIDs();
+	return std::find(ids.begin(), ids.end(), id) != ids.end();
+}
+
 void LLAvatarList::toggleIcons()
 {
 	// Save the new value for new items to use.

indra/newview/llavatarlist.h

 	void setNameFilter(const std::string& filter);
 	void setDirty(bool val = true)						{ mDirty = val; }
 	uuid_vector_t& getIDs() 							{ return mIDs; }
+	bool contains(const LLUUID& id);
 
 	void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; }
 

indra/newview/llavatarlistitem.cpp

 void LLAvatarListItem::setOnline(bool online)
 {
 	// *FIX: setName() overrides font style set by setOnline(). Not an issue ATM.
-	// *TODO: Make the colors configurable via XUI.
 
 	if (mOnlineStatus != E_UNKNOWN && (bool) mOnlineStatus == online)
 		return;
 	mOnlineStatus = (EOnlineStatus) online;
 
 	// Change avatar name font style depending on the new online status.
-	mAvatarNameStyle.color = online ? LLColor4::white : LLColor4::grey;
-	setNameInternal(mAvatarName->getText(), mHighlihtSubstring);
-
-	// Make the icon fade if the avatar goes offline.
-	mAvatarIcon->setColor(online ? LLColor4::white : LLColor4::smoke);
+	setStyle(online ? IS_ONLINE : IS_OFFLINE);
 }
 
 void LLAvatarListItem::setName(const std::string& name)
 	setNameInternal(mAvatarName->getText(), mHighlihtSubstring = highlight);
 }
 
-void LLAvatarListItem::setStyle(const LLStyle::Params& new_style)
+void LLAvatarListItem::setStyle(EItemStyle item_style)
 {
-//	LLTextUtil::textboxSetHighlightedVal(mAvatarName, mAvatarNameStyle = new_style);
+	item_style_map_t& item_styles_params_map = getItemStylesParams();
 
-	// Active group should be bold.
-	LLFontDescriptor new_desc(mAvatarName->getDefaultFont()->getFontDesc());
-
-	new_desc.setStyle(new_style.font()->getFontDesc().getStyle());
-	// *NOTE dzaporozhan
-	// On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font 
-	// is predefined as bold (SansSerifSmallBold, for example)
-//	new_desc.setStyle(active ? LLFontGL::BOLD : LLFontGL::NORMAL);
-	LLFontGL* new_font = LLFontGL::getFont(new_desc);
-
-//	
-	mAvatarNameStyle.font = new_font;
+	mAvatarNameStyle = item_styles_params_map[item_style];
 
 	// *NOTE: You cannot set the style on a text box anymore, you must
 	// rebuild the text.  This will cause problems if the text contains
 	// hyperlinks, as their styles will be wrong.
-	mAvatarName->setText(mAvatarName->getText(), mAvatarNameStyle/* = new_style*/);
+	setNameInternal(mAvatarName->getText(), mHighlihtSubstring);
+
+	icon_color_map_t& item_icon_color_map = getItemIconColorMap();
+	mAvatarIcon->setColor(item_icon_color_map[item_style]);
 }
+
 void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes)
 {
 	if (mAvatarId.notNull())
 	args["[COUNT]"] = llformat("%u", count);
 	return getString(fmt, args);
 }
+
+// static
+LLAvatarListItem::item_style_map_t& LLAvatarListItem::getItemStylesParams()
+{
+	static item_style_map_t item_styles_params_map;
+	if (!item_styles_params_map.empty()) return item_styles_params_map;
+
+	LLPanel::Params params = LLUICtrlFactory::getDefaultParams<LLPanel>();
+	LLPanel* params_panel = LLUICtrlFactory::create<LLPanel>(params);
+
+	BOOL sucsess = LLUICtrlFactory::instance().buildPanel(params_panel, "panel_avatar_list_item_params.xml");
+
+	if (sucsess)
+	{
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_DEFAULT,
+			params_panel->getChild<LLTextBox>("default_style")->getDefaultStyle()));
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_VOICE_INVITED,
+			params_panel->getChild<LLTextBox>("voice_call_invited_style")->getDefaultStyle()));
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_VOICE_JOINED,
+			params_panel->getChild<LLTextBox>("voice_call_joined_style")->getDefaultStyle()));
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_VOICE_LEFT,
+			params_panel->getChild<LLTextBox>("voice_call_left_style")->getDefaultStyle()));
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_ONLINE,
+			params_panel->getChild<LLTextBox>("online_style")->getDefaultStyle()));
+
+		item_styles_params_map.insert(
+			std::make_pair(IS_OFFLINE,
+			params_panel->getChild<LLTextBox>("offline_style")->getDefaultStyle()));
+	}
+	else
+	{
+		item_styles_params_map.insert(std::make_pair(IS_DEFAULT, LLStyle::Params()));
+		item_styles_params_map.insert(std::make_pair(IS_VOICE_INVITED, LLStyle::Params()));
+		item_styles_params_map.insert(std::make_pair(IS_VOICE_JOINED, LLStyle::Params()));
+		item_styles_params_map.insert(std::make_pair(IS_VOICE_LEFT, LLStyle::Params()));
+		item_styles_params_map.insert(std::make_pair(IS_ONLINE, LLStyle::Params()));
+		item_styles_params_map.insert(std::make_pair(IS_OFFLINE, LLStyle::Params()));
+	}
+	if (params_panel) params_panel->die();
+
+	return item_styles_params_map;
+}
+
+// static
+LLAvatarListItem::icon_color_map_t& LLAvatarListItem::getItemIconColorMap()
+{
+	static icon_color_map_t item_icon_color_map;
+	if (!item_icon_color_map.empty()) return item_icon_color_map;
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_DEFAULT,
+		LLUIColorTable::instance().getColor("AvatarListItemIconDefaultColor", LLColor4::white)));
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_VOICE_INVITED,
+		LLUIColorTable::instance().getColor("AvatarListItemIconVoiceInvitedColor", LLColor4::white)));
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_VOICE_JOINED,
+		LLUIColorTable::instance().getColor("AvatarListItemIconVoiceJoinedColor", LLColor4::white)));
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_VOICE_LEFT,
+		LLUIColorTable::instance().getColor("AvatarListItemIconVoiceLeftColor", LLColor4::white)));
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_ONLINE,
+		LLUIColorTable::instance().getColor("AvatarListItemIconOnlineColor", LLColor4::white)));
+
+	item_icon_color_map.insert(
+		std::make_pair(IS_OFFLINE,
+		LLUIColorTable::instance().getColor("AvatarListItemIconOfflineColor", LLColor4::white)));
+
+	return item_icon_color_map;
+}
+
+// EOF

indra/newview/llavatarlistitem.h

 class LLAvatarListItem : public LLPanel, public LLFriendObserver
 {
 public:
+	typedef enum e_item_style_type {
+		IS_DEFAULT,
+		IS_VOICE_INVITED,
+		IS_VOICE_JOINED,
+		IS_VOICE_LEFT,
+		IS_ONLINE,
+		IS_OFFLINE,
+	} EItemStyle;
+
 	class ContextMenu
 	{
 	public:
 	void setOnline(bool online);
 	void setName(const std::string& name);
 	void setHighlight(const std::string& highlight);
-	void setStyle(const LLStyle::Params& new_style);
+	void setStyle(EItemStyle item_style);
 	void setAvatarId(const LLUUID& id, bool ignore_status_changes = false);
 	void setLastInteractionTime(U32 secs_since);
 	//Show/hide profile/info btn, translating speaker indicator and avatar name coordinates accordingly
 	 */
 	LLOutputMonitorCtrl* mSpeakingIndicator;
 
+	LLAvatarIconCtrl* mAvatarIcon;
+
 private:
 
 	typedef enum e_online_status {
 
 	std::string formatSeconds(U32 secs);
 
-	LLAvatarIconCtrl* mAvatarIcon;
+	typedef std::map<EItemStyle, LLStyle::Params> item_style_map_t;
+	static item_style_map_t& getItemStylesParams();
+
+	typedef std::map<EItemStyle, LLColor4> icon_color_map_t;
+	static icon_color_map_t& getItemIconColorMap();
+
 	LLTextBox* mAvatarName;
 	LLTextBox* mLastInteractionTime;
 	LLStyle::Params mAvatarNameStyle;

indra/newview/llbottomtray.cpp

 {
 	if (!getChicletPanel()) return;
 
+	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
+	if (!session) return;
+
+	// no need to spawn chiclets for participants in P2P calls called through Avaline
+	if (session->isP2P() && session->isOtherParticipantAvaline()) return;
+
 	if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
 
 	LLIMChiclet* chiclet = createIMChiclet(session_id);

indra/newview/llcallfloater.cpp

 
 #include "llagent.h"
 #include "llagentdata.h" // for gAgentID
+#include "llavatariconctrl.h"
 #include "llavatarlist.h"
 #include "llbottomtray.h"
 #include "llimfloater.h"
 #include "llspeakers.h"
 #include "lltransientfloatermgr.h"
 
+static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids);
 
 class LLNonAvatarCaller : public LLAvatarListItem
 {
 			showLastInteractionTime(false);
 			setShowProfileBtn(false);
 			setShowInfoBtn(false);
+			mAvatarIcon->setValue("Avaline_Icon");
+			mAvatarIcon->setToolTip(std::string(""));
 		}
 		return rv;
 	}
 	return TRUE;
 }
 
-
-LLCallFloater::Params::Params()
-: voice_left_remove_delay("voice_left_remove_delay", 10)
-{
-}
-
 LLCallFloater::LLCallFloater(const LLSD& key)
 : LLDockableFloater(NULL, false, key)
 , mSpeakerManager(NULL)
-, mPaticipants(NULL)
+, mParticipants(NULL)
 , mAvatarList(NULL)
 , mNonAvatarCaller(NULL)
 , mVoiceType(VC_LOCAL_CHAT)
 , mSpeakingIndicator(NULL)
 , mIsModeratorMutedVoice(false)
 , mInitParticipantsVoiceState(false)
-, mVoiceLeftRemoveDelay(10) // TODO: mantipov: make xml driven
+, mVoiceLeftRemoveDelay(10)
 {
+	static LLUICachedControl<S32> voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10);
+	mVoiceLeftRemoveDelay = voice_left_remove_delay;
+
 	mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
 	LLVoiceClient::getInstance()->addObserver(this);
 	LLTransientFloaterMgr::getInstance()->addControlView(this);
 {
 	resetVoiceRemoveTimers();
 
-	delete mPaticipants;
-	mPaticipants = NULL;
+	delete mParticipants;
+	mParticipants = NULL;
 
 	mAvatarListRefreshConnection.disconnect();
 
 	}
 
 	// Need to resort the participant list if it's in sort by recent speaker order.
-	if (mPaticipants)
-		mPaticipants->updateRecentSpeakersOrder();
+	if (mParticipants)
+		mParticipants->updateRecentSpeakersOrder();
 
 	LLDockableFloater::draw();
 }
 // virtual
 void LLCallFloater::onChange()
 {
-	if (NULL == mPaticipants) return;
+	if (NULL == mParticipants) return;
 
 	updateParticipantsVoiceState();
+
+	// Add newly joined participants.
+	std::vector<LLUUID> speakers_uuids;
+	get_voice_participants_uuids(speakers_uuids);
+	for (std::vector<LLUUID>::const_iterator it = speakers_uuids.begin(); it != speakers_uuids.end(); it++)
+	{
+		mParticipants->addAvatarIDExceptAgent(*it);
+	}
 }
 
 
 	bool is_local_chat = mVoiceType == VC_LOCAL_CHAT;
 	childSetVisible("leave_call_btn", !is_local_chat);
 	
-	refreshPartisipantList();
+	refreshParticipantList();
 	updateAgentModeratorState();
 
 	//show floater for voice calls
 		if (show_me) 
 		{
 			setVisible(true);
-			// Workaround(EM): Set current call dialog to front most because
-			// connect/leaving popups should appear on top of VCP.
-			// See bug EXT-3628.
-			LLOutgoingCallDialog* instance =
-				LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", LLOutgoingCallDialog::OCD_KEY);
-			if(instance && instance->getVisible())
-			{
-				instance->setFrontmost();
-			}
 		}
 	}
 }
 
-void LLCallFloater::refreshPartisipantList()
+void LLCallFloater::refreshParticipantList()
 {
 	// lets forget states from the previous session
 	// for timers...
 	// ...and for speaker state
 	mSpeakerStateMap.clear();
 
-	delete mPaticipants;
-	mPaticipants = NULL;
+	delete mParticipants;
+	mParticipants = NULL;
 	mAvatarList->clear();
 
 	bool non_avatar_caller = false;
 
 	if (!non_avatar_caller)
 	{
-		mPaticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT);
+		mParticipants = new LLParticipantList(mSpeakerManager, mAvatarList, true, mVoiceType != VC_GROUP_CHAT && mVoiceType != VC_AD_HOC_CHAT);
+		mParticipants->setValidateSpeakerCallback(boost::bind(&LLCallFloater::validateSpeaker, this, _1));
 
 		if (LLLocalSpeakerMgr::getInstance() == mSpeakerManager)
 		{
 	mAgentPanel->childSetValue("user_text", name);
 }
 
-void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids)
+static void get_voice_participants_uuids(std::vector<LLUUID>& speakers_uuids)
 {
 	// Get a list of participants from VoiceClient
 	LLVoiceClient::participantMap *voice_map = gVoiceClient->getParticipantList();
 			// HAS LEFT the call.
 			if ((getState(participant_id) == STATE_JOINED))
 			{
-				setState(item, STATE_LEFT);
+				if (mVoiceType == VC_LOCAL_CHAT)
+				{
+					// Don't display avatars that aren't in our nearby chat range anymore as "left". Remove them immediately.
+					removeVoiceLeftParticipant(participant_id);
+				}
+				else
+				{
+					setState(item, STATE_LEFT);
 
-				LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId());
-				if (speaker.isNull())
-					continue;
+					LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId());
+					if (speaker.isNull())
+					{
+						continue;
+					}
 
-				speaker->mHasLeftCurrentCall = TRUE;
+					speaker->mHasLeftCurrentCall = TRUE;
+				}
 			}
 			// If an avatarID is not found in a speakers list from VoiceClient and
 			// a panel with this ID has a LEFT status this means that this person
 			{
 				setState(item, STATE_INVITED);
 			}
+			else
+			{
+				llwarns << "Unsupported (" << getState(participant_id) << ") state: " << item->getAvatarName()  << llendl;
+			}
 		}
 	}
-
 }
 
 void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state)
 
 	setState(item->getAvatarId(), state);
 
-	LLStyle::Params speaker_style;
-	LLFontDescriptor new_desc(speaker_style.font()->getFontDesc());
-
 	switch (state)
 	{
 	case STATE_INVITED:
-		new_desc.setStyle(LLFontGL::NORMAL);
+		item->setStyle(LLAvatarListItem::IS_VOICE_INVITED);
 		break;
 	case STATE_JOINED:
 		removeVoiceRemoveTimer(item->getAvatarId());
-		new_desc.setStyle(LLFontGL::NORMAL);
+		item->setStyle(LLAvatarListItem::IS_VOICE_JOINED);
 		break;
 	case STATE_LEFT:
 		{
 			setVoiceRemoveTimer(item->getAvatarId());
-			new_desc.setStyle(LLFontGL::ITALIC);
+			item->setStyle(LLAvatarListItem::IS_VOICE_LEFT);
 		}
 		break;
 	default:
 		llwarns << "Unrecognized avatar panel state (" << state << ")" << llendl;
 		break;
 	}
-
-	LLFontGL* new_font = LLFontGL::getFont(new_desc);
-	speaker_style.font = new_font;
-	item->setStyle(speaker_style);
-
-//	if ()
-	{
-		// found speaker is in voice, mark him as online
-		item->setOnline(STATE_JOINED == state);
-	}
 }
 
 void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id)
 	}
 }
 
+bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id)
+{
+	if (mVoiceType != VC_LOCAL_CHAT)
+		return true;
+
+	// A nearby chat speaker is considered valid it it's known to LLVoiceClient (i.e. has enabled voice).
+	std::vector<LLUUID> speakers;
+	get_voice_participants_uuids(speakers);
+	return std::find(speakers.begin(), speakers.end(), speaker_id) != speakers.end();
+}
+
 //EOF

indra/newview/llcallfloater.h

 class LLCallFloater : public LLDockableFloater, LLVoiceClientParticipantObserver
 {
 public:
-	struct Params :	public LLInitParam::Block<Params, LLDockableFloater::Params>
-	{
-		Optional<S32>			voice_left_remove_delay;
-
-		Params();
-	};
 
 	LOG_CLASS(LLCallFloater);
 
 	/**
 	 * Refreshes participant list according to current Voice Channel
 	 */
-	void refreshPartisipantList();
+	void refreshParticipantList();
 
 	/**
 	 * Handles event on avatar list is refreshed after it was marked dirty.
 	/**
 	 * Sets initial participants voice states in avatar list (Invited, Joined, Has Left).
 	 *
-	 * @see refreshPartisipantList()
+	 * @see refreshParticipantList()
 	 * @see onAvatarListRefreshed()
 	 * @see mInitParticipantsVoiceState
 	 */
 	 */
 	void removeVoiceRemoveTimer(const LLUUID& voice_speaker_id);
 
+	/**
+	 * Called by LLParticipantList before adding a speaker to the participant list.
+	 *
+	 * If false is returned, the speaker will not be added to the list.
+	 *
+	 * @param speaker_id Speaker to validate.
+	 * @return true if this is a valid speaker, false otherwise.
+	 */
+	bool validateSpeaker(const LLUUID& speaker_id);
+
 private:
 	speaker_state_map_t mSpeakerStateMap;
 	LLSpeakerMgr* mSpeakerManager;
-	LLParticipantList* mPaticipants;
+	LLParticipantList* mParticipants;
 	LLAvatarList* mAvatarList;
 	LLNonAvatarCaller* mNonAvatarCaller;
 	EVoiceControls mVoiceType;

indra/newview/llchiclet.cpp

 static LLDefaultChildRegistry::Register<LLScriptChiclet> t6("chiclet_script");
 static LLDefaultChildRegistry::Register<LLInvOfferChiclet> t7("chiclet_offer");
 
-static const LLRect CHICLET_RECT(0, 25, 25, 0);
-static const LLRect CHICLET_ICON_RECT(0, 22, 22, 0);
-static const LLRect VOICE_INDICATOR_RECT(50, 25, 70, 0);
-static const LLRect COUNTER_RECT(25, 25, 50, 0);
-static const S32 OVERLAY_ICON_SHIFT = 2;	// used for shifting of an overlay icon for new massages in a chiclet
-static const S32 SCROLL_BUTTON_PAD = 5;
-
-// static
-const S32 LLChicletPanel::s_scroll_ratio = 10;
-const S32 LLChicletNotificationCounterCtrl::MAX_DISPLAYED_COUNT = 99;
-
-
 boost::signals2::signal<LLChiclet* (const LLUUID&),
 		LLIMChiclet::CollectChicletCombiner<std::list<LLChiclet*> > >
 		LLIMChiclet::sFindChicletsSignal;
 
 void LLSysWellChiclet::setCounter(S32 counter)
 {
+	// do nothing if the same counter is coming. EXT-3678.
+	if (counter == mCounter) return;
+
 	// note same code in LLChicletNotificationCounterCtrl::setCounter(S32 counter)
 	std::string s_count;
 	if(counter != 0)
 //////////////////////////////////////////////////////////////////////////
 
 LLChiclet::Params::Params()
- : show_counter("show_counter")
+ : show_counter("show_counter", true)
+ , enable_counter("enable_counter", false)
 {
-	show_counter = true;
 }
 
 LLChiclet::LLChiclet(const Params& p)
 LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)
 : LLChiclet(p)
 , mShowSpeaker(false)
+, mDefaultWidth(p.rect().getWidth())
 , mNewMessagesIcon(NULL)
 , mSpeakerCtrl(NULL)
 , mCounterCtrl(NULL)
 {
-	// initialize an overlay icon for new messages
-	LLIconCtrl::Params icon_params;
-	icon_params.visible = false;
-	icon_params.image = LLUI::getUIImage(p.new_messages_icon_name);
-	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
-	addChild(mNewMessagesIcon);
-
-	// adjust size and position of an icon
-	LLRect chiclet_rect = p.rect;
-	LLRect overlay_icon_rect = LLRect(chiclet_rect.getWidth()/2, chiclet_rect.getHeight(), chiclet_rect.getWidth(), chiclet_rect.getHeight()/2); 
-	mNewMessagesIcon->setRect(overlay_icon_rect);
-	
-	// shift an icon a little bit to the right and up corner of a chiclet
-	overlay_icon_rect.translate(OVERLAY_ICON_SHIFT, OVERLAY_ICON_SHIFT);
-
-	enableCounterControl(false);
+	enableCounterControl(p.enable_counter);
 }
 
 void LLIMChiclet::setShowSpeaker(bool show)
 	{		
 		mShowSpeaker = show;
 		toggleSpeakerControl();
-		onChicletSizeChanged();		
 	}
 }
 
 	{		
 		LLChiclet::setShowCounter(show);
 		toggleCounterControl();
-		onChicletSizeChanged();		
 	}
 }
 
 {
 	bool show_speaker = getShowSpeaker();
 	bool show_counter = getShowCounter();
-	S32 required_width = CHICLET_RECT.getWidth();
+	S32 required_width = mDefaultWidth;
 
 	if (show_counter)
 	{
-		required_width += COUNTER_RECT.getWidth();
+		required_width += mCounterCtrl->getRect().getWidth();
 	}
 	if (show_speaker)
 	{
-		required_width += VOICE_INDICATOR_RECT.getWidth();
+		required_width += mSpeakerCtrl->getRect().getWidth();
 	} 
 
 	reshape(required_width, getRect().getHeight());
+
+	onChicletSizeChanged();
 }
 
 void LLIMChiclet::toggleSpeakerControl()
 {
 	if(getShowSpeaker())
 	{
+		// move speaker to the right of chiclet icon
+		LLRect speaker_rc = mSpeakerCtrl->getRect();
+		speaker_rc.setLeftTopAndSize(mDefaultWidth, speaker_rc.mTop, speaker_rc.getWidth(), speaker_rc.getHeight());
+		mSpeakerCtrl->setRect(speaker_rc);
+
 		if(getShowCounter())
 		{
-			mSpeakerCtrl->setRect(VOICE_INDICATOR_RECT);
+			// move speaker to the right of counter
+			mSpeakerCtrl->translate(mCounterCtrl->getRect().getWidth(), 0);
 		}
-		else
-		{
-			mSpeakerCtrl->setRect(COUNTER_RECT);
-		}
+
 		initSpeakerControl();		
 	}
 
 	{
 		mNewMessagesIcon->setVisible(show);
 	}
+	setRequiredWidth();
 }
 
 bool LLIMChiclet::getShowNewMessagesIcon()
 : avatar_icon("avatar_icon")
 , unread_notifications("unread_notifications")
 , speaker("speaker")
+, new_message_icon("new_message_icon")
 , show_speaker("show_speaker")
 {
-	// *TODO Vadim: Get rid of hardcoded values.
-	rect(CHICLET_RECT);
-
-	avatar_icon.name("avatar_icon");
-	avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
-
-	// *NOTE dzaporozhan
-	// Changed icon height from 25 to 24 to fix ticket EXT-794.
-	// In some cases(after changing UI scale) 25 pixel height icon was 
-	// drawn incorrectly, i'm not sure why.
-	avatar_icon.rect(CHICLET_ICON_RECT);
-	avatar_icon.mouse_opaque(false);
-
-	unread_notifications.name("unread");
-	unread_notifications.font(LLFontGL::getFontSansSerif());
-	unread_notifications.font_halign(LLFontGL::HCENTER);
-	unread_notifications.v_pad(5);
-	unread_notifications.text_color(LLColor4::white);
-	unread_notifications.mouse_opaque(false);
-	unread_notifications.rect(COUNTER_RECT);
-	unread_notifications.visible(false);
-
-	speaker.name("speaker");
-	speaker.rect(VOICE_INDICATOR_RECT);
-	speaker.auto_update(true);
-	speaker.draw_border(false);
-
-	show_speaker = false;
 }
 
 LLIMP2PChiclet::LLIMP2PChiclet(const Params& p)
 , mChicletIconCtrl(NULL)
 , mPopupMenu(NULL)
 {
+	LLIconCtrl::Params new_msg_params = p.new_message_icon;
+	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+	addChild(mNewMessagesIcon);
+
 	LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
 	mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
 	addChild(mChicletIconCtrl);
 
 	sendChildToFront(mNewMessagesIcon);
 	setShowSpeaker(p.show_speaker);
-
-	//since mShowSpeaker initialized with false 
-	//setShowSpeaker(false) will not hide mSpeakerCtrl
-	mSpeakerCtrl->setVisible(getShowSpeaker());
 }
 
 void LLIMP2PChiclet::initSpeakerControl()
 	if(getSessionId().isNull())
 		return;
 
+	LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId());
+	bool open_window_exists = open_im_floater && open_im_floater->getVisible();
+	mPopupMenu->getChild<LLUICtrl>("Send IM")->setEnabled(!open_window_exists);
+	
 	bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId());
-
 	mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend);
 }
 
 : avatar_icon("avatar_icon")
 , unread_notifications("unread_notifications")
 , speaker("speaker")
+, new_message_icon("new_message_icon")
 , show_speaker("show_speaker")
 , avatar_icon_color("avatar_icon_color", LLColor4::green)
 {
-	// *TODO Vadim: Get rid of hardcoded values.
-	rect(CHICLET_RECT);
-
-	avatar_icon.name("avatar_icon");
-	avatar_icon.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
-
-	// *NOTE dzaporozhan
-	// Changed icon height from 25 to 24 to fix ticket EXT-794.
-	// In some cases(after changing UI scale) 25 pixel height icon was 
-	// drawn incorrectly, i'm not sure why.
-	avatar_icon.rect(CHICLET_ICON_RECT);
-	avatar_icon.mouse_opaque(false);
-
-	unread_notifications.name("unread");
-	unread_notifications.font(LLFontGL::getFontSansSerif());
-	unread_notifications.font_halign(LLFontGL::HCENTER);
-	unread_notifications.v_pad(5);
-	unread_notifications.text_color(LLColor4::white);
-	unread_notifications.mouse_opaque(false);
-	unread_notifications.rect(COUNTER_RECT);
-	unread_notifications.visible(false);
-
-
-	speaker.name("speaker");
-	speaker.rect(VOICE_INDICATOR_RECT);
-	speaker.auto_update(true);
-	speaker.draw_border(false);
-
-	show_speaker = false;
 }
 
 LLAdHocChiclet::LLAdHocChiclet(const Params& p)
 , mChicletIconCtrl(NULL)
 , mPopupMenu(NULL)
 {
+	LLIconCtrl::Params new_msg_params = p.new_message_icon;
+	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+	addChild(mNewMessagesIcon);
+
 	LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon;
 	mChicletIconCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params);
 	//Make the avatar modified
 : group_icon("group_icon")
 , unread_notifications("unread_notifications")
 , speaker("speaker")
+, new_message_icon("new_message_icon")
 , show_speaker("show_speaker")
 {
-	rect(CHICLET_RECT);
-
-	group_icon.name("group_icon");
-	
-	// *NOTE dzaporozhan
-	// Changed icon height from 25 to 24 to fix ticket EXT-794.
-	// In some cases(after changing UI scale) 25 pixel height icon was 
-	// drawn incorrectly, i'm not sure why.
-	group_icon.rect(CHICLET_ICON_RECT);
-
-	unread_notifications.name("unread");
-	unread_notifications.font(LLFontGL::getFontSansSerif());
-	unread_notifications.font_halign(LLFontGL::HCENTER);
-	unread_notifications.v_pad(5);
-	unread_notifications.text_color(LLColor4::white);
-	unread_notifications.rect(COUNTER_RECT);
-	unread_notifications.visible(false);
-
-	speaker.name("speaker");
-	speaker.rect(VOICE_INDICATOR_RECT);
-	speaker.auto_update(true);
-	speaker.draw_border(false);
-
-	show_speaker = false;
 }
 
 LLIMGroupChiclet::LLIMGroupChiclet(const Params& p)
 , mChicletIconCtrl(NULL)
 , mPopupMenu(NULL)
 {
+	LLIconCtrl::Params new_msg_params = p.new_message_icon;
+	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+	addChild(mNewMessagesIcon);
+
 	LLChicletGroupIconCtrl::Params avatar_params = p.group_icon;
 	mChicletIconCtrl = LLUICtrlFactory::create<LLChicletGroupIconCtrl>(avatar_params);
 	addChild(mChicletIconCtrl);
 	}
 }
 
+void LLIMGroupChiclet::updateMenuItems()
+{
+	if(!mPopupMenu)
+		return;
+	if(getSessionId().isNull())
+		return;
+
+	LLIMFloater* open_im_floater = LLIMFloater::findInstance(getSessionId());
+	bool open_window_exists = open_im_floater && open_im_floater->getVisible();
+	mPopupMenu->getChild<LLUICtrl>("Chat")->setEnabled(!open_window_exists);
+}
+
 BOOL LLIMGroupChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	if(!mPopupMenu)
 
 	if (mPopupMenu)
 	{
+		updateMenuItems();
 		mPopupMenu->arrangeAndClear();
 		LLMenuGL::showPopup(this, mPopupMenu, x, y);
 	}
 LLChicletPanel::Params::Params()
 : chiclet_padding("chiclet_padding")
 , scrolling_offset("scrolling_offset")
+, scroll_button_hpad("scroll_button_hpad")
+, scroll_ratio("scroll_ratio")
 , min_width("min_width")
 {
-	chiclet_padding = 3;
-	scrolling_offset = 40;
-
-	if (!min_width.isProvided())
-	{
-		// min_width = 4 chiclets + 3 paddings
-		min_width = 180 + 3*chiclet_padding;
-	}
 };
 
 LLChicletPanel::LLChicletPanel(const Params&p)
 , mRightScrollButton(NULL)
 , mChicletPadding(p.chiclet_padding)
 , mScrollingOffset(p.scrolling_offset)
+, mScrollButtonHPad(p.scroll_button_hpad)
+, mScrollRatio(p.scroll_ratio)
 , mMinWidth(p.min_width)
 , mShowControls(true)
 {
 	bool need_show_scroll = needShowScroll();
 	if(need_show_scroll)
 	{
-		mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD,
-			height, width - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0));
+		mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad,
+			height, width - scroll_button_rect.getWidth() - mScrollButtonHPad, 0));
 	}
 	else
 	{
 
 }
 
+S32	LLChicletPanel::notifyParent(const LLSD& info)
+{
+	if(info.has("notification"))
+	{
+		std::string str_notification = info["notification"];
+		if(str_notification == "size_changes")
+		{
+			arrange();
+			return 1;
+		}
+	}
+	return LLPanel::notifyParent(info);
+}
+
 void LLChicletPanel::arrange()
 {
 	if(mChicletList.empty())
 	bool need_show_scroll = needShowScroll();
 	if(need_show_scroll)
 	{
-		mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD,
-			rect.getHeight(), rect.getWidth() - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0));
+		mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + mScrollButtonHPad,
+			rect.getHeight(), rect.getWidth() - scroll_button_rect.getWidth() - mScrollButtonHPad, 0));
 	}
 	else
 	{
 void LLChicletPanel::onLeftScrollHeldDown()
 {
 	S32 offset = mScrollingOffset;
-	mScrollingOffset = mScrollingOffset / s_scroll_ratio;
+	mScrollingOffset = mScrollingOffset / mScrollRatio;
 	scrollLeft();
 	mScrollingOffset = offset;
 }
 void LLChicletPanel::onRightScrollHeldDown()
 {
 	S32 offset = mScrollingOffset;
-	mScrollingOffset = mScrollingOffset / s_scroll_ratio;
+	mScrollingOffset = mScrollingOffset / mScrollRatio;
 	scrollRight();
 	mScrollingOffset = offset;
 }
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 LLChicletNotificationCounterCtrl::Params::Params()
-: max_displayed_count("max_displayed_count", MAX_DISPLAYED_COUNT)
+: max_displayed_count("max_displayed_count", 99)
 {
 }
 
 : LLIconCtrl(p)
 , mDefaultIcon(p.default_icon)
 {
+	setValue(LLUUID::null);
 }
 
 void LLChicletGroupIconCtrl::setValue(const LLSD& value )
 
 LLScriptChiclet::Params::Params()
  : icon("icon")
+ , new_message_icon("new_message_icon")
 {
-	// *TODO Vadim: Get rid of hardcoded values.
- 	rect(CHICLET_RECT);
-	icon.rect(CHICLET_ICON_RECT);
 }
 
 LLScriptChiclet::LLScriptChiclet(const Params&p)
  : LLIMChiclet(p)
  , mChicletIconCtrl(NULL)
 {
+	LLIconCtrl::Params new_msg_params = p.new_message_icon;
+	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+	addChild(mNewMessagesIcon);
+
 	LLIconCtrl::Params icon_params = p.icon;
 	mChicletIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params);
-	// Let "new message" icon be on top, else it will be hidden behind chiclet icon.
-	addChildInBack(mChicletIconCtrl);
+	addChild(mChicletIconCtrl);
+
+	sendChildToFront(mNewMessagesIcon);
 }
 
 void LLScriptChiclet::setSessionId(const LLUUID& session_id)
 static const std::string INVENTORY_USER_OFFER	("UserGiveItem");
 
 LLInvOfferChiclet::Params::Params()
+ : icon("icon")
+ , new_message_icon("new_message_icon")
 {
-	// *TODO Vadim: Get rid of hardcoded values.
-	rect(CHICLET_RECT);
-	icon.rect(CHICLET_ICON_RECT);
 }
 
 LLInvOfferChiclet::LLInvOfferChiclet(const Params&p)
  : LLIMChiclet(p)
  , mChicletIconCtrl(NULL)
 {
+	LLIconCtrl::Params new_msg_params = p.new_message_icon;
+	mNewMessagesIcon = LLUICtrlFactory::create<LLIconCtrl>(new_msg_params);
+	addChild(mNewMessagesIcon);
+
 	LLChicletInvOfferIconCtrl::Params icon_params = p.icon;
 	mChicletIconCtrl = LLUICtrlFactory::create<LLChicletInvOfferIconCtrl>(icon_params);
-	// Let "new message" icon be on top, else it will be hidden behind chiclet icon.
-	addChildInBack(mChicletIconCtrl);
+	addChild(mChicletIconCtrl);
+
+	sendChildToFront(mNewMessagesIcon);
 }
 
 void LLInvOfferChiclet::setSessionId(const LLUUID& session_id)

indra/newview/llchiclet.h

 {
 public:
 
-	static const S32 MAX_DISPLAYED_COUNT;
-
 	struct Params :	public LLInitParam::Block<Params, LLTextBox::Params>
 	{
 		/**
 
 	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
 	{
-		Optional<bool> show_counter;
+		Optional<bool> show_counter,
+					   enable_counter;
 
 		Params();
 	};
 	};
 	struct Params : public LLInitParam::Block<Params, LLChiclet::Params>
 	{
-		Optional<std::string> new_messages_icon_name;
-
-		Params() : new_messages_icon_name("new_messages_icon_name", "Unread_IM")
-		{}
+		Params(){}
 	};
 
 	
 
 	bool mShowSpeaker;
 	bool mCounterEnabled;
+	/* initial width of chiclet, should not include counter or speaker width */
+	S32 mDefaultWidth;
 
 	LLIconCtrl* mNewMessagesIcon;
 	LLChicletNotificationCounterCtrl* mCounterCtrl;
 
 		Optional<LLChicletSpeakerCtrl::Params> speaker;
 
+		Optional<LLIconCtrl::Params> new_message_icon;
+
 		Optional<bool>	show_speaker;
 
 		Params();
 
 	/** 
 	 * Enables/disables menus based on relationship with other participant.
+	 * Enables/disables "show session" menu item depending on visible IM floater existence.
 	 */
 	virtual void updateMenuItems();
 
 
 		Optional<LLChicletSpeakerCtrl::Params> speaker;
 
+		Optional<LLIconCtrl::Params> new_message_icon;
+
 		Optional<bool>	show_speaker;
 
 		Optional<LLColor4>	avatar_icon_color;
 	{
 		Optional<LLIconCtrl::Params> icon;
 
+		Optional<LLIconCtrl::Params> new_message_icon;
+
 		Params();
 	};
 
 	{
 		Optional<LLChicletInvOfferIconCtrl::Params> icon;
 
+		Optional<LLIconCtrl::Params> new_message_icon;
+
 		Params();
 	};
 
 
 		Optional<LLChicletSpeakerCtrl::Params> speaker;
 
+		Optional<LLIconCtrl::Params> new_message_icon;
+
 		Optional<bool>	show_speaker;
 
 		Params();
 	virtual void onMenuItemClicked(const LLSD& user_data);
 
 	/**
+	 * Enables/disables "show session" menu item depending on visible IM floater existence.
+	 */
+	virtual void updateMenuItems();
+
+	/**
 	 * Displays popup menu.
 	 */
 	/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
 	struct Params :	public LLInitParam::Block<Params, LLPanel::Params>
 	{
 		Optional<S32> chiclet_padding,
-					  scrolling_offset;
+					  scrolling_offset,
+					  scroll_button_hpad,
+					  scroll_ratio;
 
 		Optional<S32> min_width;
 
 
 	S32 getTotalUnreadIMCount();
 
+	S32	notifyParent(const LLSD& info);
+
 protected:
 	LLChicletPanel(const Params&p);
 	friend class LLUICtrlFactory;
 
 	S32 mChicletPadding;
 	S32 mScrollingOffset;
+	S32 mScrollButtonHPad;
+	S32 mScrollRatio;
 	S32 mMinWidth;
 	bool mShowControls;
 	static const S32 s_scroll_ratio;

indra/newview/llfavoritesbar.cpp

 		if (!region_name.empty())
 		{
 			LLToolTip::Params params;
-			params.message = llformat("%s\n%s (%d, %d, %d)", getLabelSelected().c_str(), region_name.c_str(), 
+			std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), 
 				mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ());
-			params.sticky_rect = calcScreenRect();
+
+			params.message = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str());
+			
+			LLRect rect = calcScreenRect();
+			LLFontGL* standart_font = LLFontGL::getFontSansSerif();
+			if(standart_font)
+			{
+				S32 w = llmax((S32)(standart_font->getWidthF32(getLabelSelected())+0.5),(S32)(standart_font->getWidthF32(extra_message)+0.5));
+				rect.mRight = rect.mLeft + w;
+				params.max_width = w;
+			}
+			
+			params.sticky_rect = rect; 
+
 			LLToolTipMgr::instance().show(params);
 		}
 		return TRUE;
 	
 	if (action == "open")
 	{
-		teleport_via_landmark(item->getAssetUUID());
+		onButtonClick(item->getUUID());
 	}
 	else if (action == "about")
 	{

indra/newview/llfolderview.cpp

 	BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data,
 											 accept, tooltip_msg);
 
+	// When there are no visible children drag and drop is handled
+	// by the folder which is the hierarchy root.
+	if (!handled && !hasVisibleChildren())
+	{
+		handled = mFolders.front()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg);
+	}
+
 	if (handled)
 	{
 		lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderView" << llendl;

indra/newview/llimfloater.cpp

 		default: break;
 		}
 	}
+	setOverlapsScreenChannel(true);
 }
 
 void LLIMFloater::onFocusLost()

indra/newview/llimview.cpp

 	std::string joined_call = LLTrans::getString("joined_call");
 	std::string other_avatar_name = "";
 
+	std::string message;
+
 	switch(mSessionType)
 	{
 	case AVALINE_SESSION:
-		// *TODO: test avaline calls (EXT-2211)
+		// no text notifications
+		break;
 	case P2P_SESSION:
 		gCacheName->getFullName(mOtherParticipantID, other_avatar_name);
 
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, started_call);
+				message = other_avatar_name + " " + started_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
+				
 				break;
 			case LLVoiceChannel::STATE_CONNECTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), joined_call);
+				message = you + " " + joined_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
 			default:
 				break;
 			}
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), started_call);
+				message = you + " " + started_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
 				break;
 			case LLVoiceChannel::STATE_CONNECTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, joined_call);
+				message = other_avatar_name + " " + joined_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
 			default:
 				break;
 			}
 		}
-
-		// Update speakers list when connected
-		if (LLVoiceChannel::STATE_CONNECTED == new_state)
-		{
-			mSpeakers->update(true);
-		}
-
 		break;
 
 	case GROUP_SESSION:
 	case ADHOC_SESSION:
-		// *TODO: determine call starter's name "other_avatar_name" (EXT-2211)
-		//        decide how to show notifications for a group/adhoc chat already opened
-		//		  for now there is no notification from voice channel for this case
 		if(direction == LLVoiceChannel::INCOMING_CALL)
 		{
 			switch(new_state)
 			{
-			case LLVoiceChannel::STATE_CALL_STARTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, other_avatar_name, mOtherParticipantID, started_call);
-				break;
 			case LLVoiceChannel::STATE_CONNECTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), joined_call);
+				message = you + " " + joined_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
 			default:
 				break;
 			}
 			switch(new_state)
 			{
 			case LLVoiceChannel::STATE_CALL_STARTED :
-				LLIMModel::getInstance()->addMessageSilently(mSessionID, you, gAgent.getID(), started_call);
+				message = you + " " + started_call;
+				LLIMModel::getInstance()->addMessageSilently(mSessionID, SYSTEM_FROM, LLUUID::null, message);
 				break;
 			default:
 				break;
 			}
 		}
-
-		// Update speakers list when connected
-		if (LLVoiceChannel::STATE_CONNECTED == new_state)
-		{
-			mSpeakers->update(true);
-		}
-		break;
+	}
+	// Update speakers list when connected
+	if (LLVoiceChannel::STATE_CONNECTED == new_state)
+	{
+		mSpeakers->update(true);
 	}
 }
 
 	return IM_SESSION_CONFERENCE_START == mType || (IM_SESSION_INVITE == mType && !gAgent.isInGroup(mSessionID));
 }
 
+bool LLIMModel::LLIMSession::isP2P()
+{
+	return IM_NOTHING_SPECIAL == mType;
+}
+
+bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
+{
+	return !mOtherParticipantIsAvatar;
+}
+
+
 void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id)
 {
 	LLIMSession* session = findIMSession(old_session_id);
 	}	
 }
 
-void LLOutgoingCallDialog::draw()
+void LLCallDialog::draw()
 {
 	if (lifetimeHasExpired())
 	{
 		onLifetimeExpired();
 	}
-	LLDockableFloater::draw();
+
+	if (getDockControl() != NULL)
+	{
+		LLDockableFloater::draw();
+	}
 }
 
 bool LLOutgoingCallDialog::lifetimeHasExpired()
 	if (mLifetimeTimer.getStarted())
 	{
 		F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32();
-		if (elapsed_time > LIFETIME) 
+		if (elapsed_time > mLifetime) 
 		{
 			return true;
 		}
 	// hide all text at first
 	hideAllText();
 
+	// init notification's lifetime
+	std::istringstream ss( getString("lifetime") );
+	if (!(ss >> mLifetime))
+	{
+		mLifetime = DEFAULT_LIFETIME;
+	}
+
 	// customize text strings
 	// tell the user which voice channel they are leaving
 	if (!mPayload["old_channel_name"].asString().empty())
 {
 }
 
+bool LLIncomingCallDialog::lifetimeHasExpired()
+{
+	if (mLifetimeTimer.getStarted())
+	{
+		F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32();
+		if (elapsed_time > mLifetime) 
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+void LLIncomingCallDialog::onLifetimeExpired()
+{
+	// check whether a call is valid or not
+	if (LLVoiceClient::getInstance()->findSession(mPayload["caller_id"].asUUID()))
+	{
+		// restart notification's timer if call is still valid
+		mLifetimeTimer.start();
+	}
+	else
+	{
+		// close invitation if call is already not valid
+		mLifetimeTimer.stop();
+		closeFloater();
+	}
+}
+
 BOOL LLIncomingCallDialog::postBuild()
 {
 	LLCallDialog::postBuild();
 	LLSD caller_id = mPayload["caller_id"];
 	std::string caller_name = mPayload["caller_name"].asString();
 	
+	// init notification's lifetime
+	std::istringstream ss( getString("lifetime") );
+	if (!(ss >> mLifetime))
+	{
+		mLifetime = DEFAULT_LIFETIME;
+	}
+
 	std::string call_type;
 	if (gAgent.isInGroup(session_id))
 	{
 	LLUICtrl* caller_name_widget = getChild<LLUICtrl>("caller name");
 	caller_name_widget->setValue(caller_name + " " + call_type);
 	LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
-	icon->setValue(caller_id);
+	if (is_avatar)
+	{
+		icon->setValue(caller_id);
+	}
+	else
+	{
+		icon->setValue("Avaline_Icon");
+	}
 
 	childSetAction("Accept", onAccept, this);
 	childSetAction("Reject", onReject, this);
 	childSetAction("Start IM", onStartIM, this);
 	childSetFocus("Accept");
 
+	if(mPayload["notify_box_type"] != "VoiceInviteGroup" && mPayload["notify_box_type"] != "VoiceInviteAdHoc")
+	{
+		// starting notification's timer for P2P and AVALINE invitations
+		mLifetimeTimer.start();
+	}
+	else
+	{
+		mLifetimeTimer.stop();
+	}
+
 	return TRUE;
 }
 
 					new LLViewerChatterBoxInvitationAcceptResponder(
 						session_id,
 						inv_type));
+
+				// send notification message to the corresponding chat 
+				if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc")
+				{
+					std::string started_call = LLTrans::getString("started_call");
+					std::string message = mPayload["caller_name"].asString() + " " + started_call;
+					LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message);
+				}
 			}
 		}
 		if (voice)
 	if (speaker_mgr)
 	{
 		speaker_mgr->updateSpeakers(body);
+
+		// also the same call is added into LLVoiceClient::participantUpdatedEvent because
+		// sometimes it is called AFTER LLViewerChatterBoxSessionAgentListUpdates::post()
+		// when moderation state changed too late. See EXT-3544.
+		speaker_mgr->update(true);
 	}
 	else
 	{

indra/newview/llimview.h

 		static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata);
 
 		bool isAdHoc();
+		bool isP2P();
+		bool isOtherParticipantAvaline();
 
 		LLUUID mSessionID;
 		std::string mName;
 
 	virtual BOOL postBuild();
 
+	// check timer state
+	/*virtual*/ void draw();
+
 protected:
+	// lifetime timer for a notification
+	LLTimer	mLifetimeTimer;
+	// notification's lifetime in seconds
+	S32		mLifetime;
+	static const S32 DEFAULT_LIFETIME = 5;
+	virtual bool lifetimeHasExpired() {return false;};
+	virtual void onLifetimeExpired() {};
+
 	virtual void getAllowedRect(LLRect& rect);
 	LLSD mPayload;
 };
 	static void onStartIM(void* user_data);
 
 private:
+	/*virtual*/ bool lifetimeHasExpired();
+	/*virtual*/ void onLifetimeExpired();
 	void processCallResponse(S32 response);
 };
 
 	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
-	static const S32 LIFETIME = 5;
-	bool lifetimeHasExpired();
-	void onLifetimeExpired();
+	/*virtual*/ bool lifetimeHasExpired();
+	/*virtual*/ void onLifetimeExpired();
 };
 
 // Globals

indra/newview/llinventorymodel.cpp

 		cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id);
 		if(catsp)
 		{
+			// *HACK - fix root inventory folder
+			// some accounts has pbroken inventory root folders
+			
+			std::string name = "My Inventory";
+			LLUUID prev