summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rwxr-xr-xindra/newview/llavataractions.cpp30
-rw-r--r--indra/newview/llavataractions.h10
-rw-r--r--indra/newview/llchiclet.h1
-rw-r--r--indra/newview/llchicletbar.h1
-rw-r--r--indra/newview/llconversationlog.h1
-rw-r--r--indra/newview/llconversationmodel.cpp68
-rwxr-xr-xindra/newview/llconversationmodel.h3
-rwxr-xr-xindra/newview/llconversationview.cpp43
-rwxr-xr-xindra/newview/llconversationview.h1
-rw-r--r--indra/newview/llimconversation.cpp34
-rw-r--r--indra/newview/llimconversation.h5
-rw-r--r--indra/newview/llimfloater.cpp61
-rw-r--r--indra/newview/llimfloater.h1
-rw-r--r--indra/newview/llimfloatercontainer.cpp191
-rw-r--r--indra/newview/llimfloatercontainer.h10
-rw-r--r--indra/newview/llimview.cpp22
-rw-r--r--indra/newview/llimview.h3
-rw-r--r--indra/newview/llnearbychat.cpp23
-rw-r--r--indra/newview/llnearbychat.h2
-rw-r--r--indra/newview/llsyswellwindow.h1
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml2
-rw-r--r--indra/newview/skins/default/xui/en/menu_conversation.xml1
-rw-r--r--indra/newview/skins/default/xui/en/menu_participant_view.xml11
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml25
24 files changed, 395 insertions, 155 deletions
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 248685b964..3326103d03 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -697,15 +697,15 @@ namespace action_give_inventory
}
// static
-void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
+void LLAvatarActions::buildResidentsString(std::vector<LLAvatarName> avatar_names, std::string& residents_string)
{
llassert(avatar_names.size() > 0);
-
+
+ std::sort(avatar_names.begin(), avatar_names.end());
const std::string& separator = LLTrans::getString("words_separator");
for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
{
- LLAvatarName av_name = *it;
- residents_string.append(av_name.mDisplayName);
+ residents_string.append((*it).mDisplayName);
if (++it == avatar_names.end())
{
break;
@@ -714,6 +714,28 @@ void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avata
}
}
+// static
+void LLAvatarActions::buildResidentsString(const uuid_vec_t& avatar_uuids, std::string& residents_string)
+{
+ std::vector<LLAvatarName> avatar_names;
+ uuid_vec_t::const_iterator it = avatar_uuids.begin();
+ for (; it != avatar_uuids.end(); ++it)
+ {
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(*it, &av_name))
+ {
+ avatar_names.push_back(av_name);
+ }
+ }
+
+ // We should check whether the vector is not empty to pass the assertion
+ // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString.
+ if (!avatar_names.empty())
+ {
+ LLAvatarActions::buildResidentsString(avatar_names, residents_string);
+ }
+}
+
//static
std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs()
{
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 6e60f624ad..6e1198cd09 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -216,7 +216,15 @@ public:
* @param avatar_names - a vector of given avatar names from which resulting string is built
* @param residents_string - the resulting string
*/
- static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string);
+ static void buildResidentsString(std::vector<LLAvatarName> avatar_names, std::string& residents_string);
+
+ /**
+ * Builds a string of residents' display names separated by "words_separator" string.
+ *
+ * @param avatar_uuids - a vector of given avatar uuids from which resulting string is built
+ * @param residents_string - the resulting string
+ */
+ static void buildResidentsString(const uuid_vec_t& avatar_uuids, std::string& residents_string);
/**
* Opens the chat history for avatar
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index f51d7b622c..6395f5b694 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -874,6 +874,7 @@ class LLIMWellChiclet : public LLSysWellChiclet, LLIMSessionObserver
friend class LLUICtrlFactory;
public:
/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}
+ /*virtual*/ void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}
/*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
/*virtual*/ void sessionRemoved(const LLUUID& session_id) { messageCountChanged(LLSD()); }
/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {}
diff --git a/indra/newview/llchicletbar.h b/indra/newview/llchicletbar.h
index 7d0d904810..a9a5b61ae7 100644
--- a/indra/newview/llchicletbar.h
+++ b/indra/newview/llchicletbar.h
@@ -51,6 +51,7 @@ public:
// LLIMSessionObserver observe triggers
/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ /*virtual*/ void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {};
/*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
/*virtual*/ void sessionRemoved(const LLUUID& session_id);
/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h
index 373406aa6f..b92cf0f5e2 100644
--- a/indra/newview/llconversationlog.h
+++ b/indra/newview/llconversationlog.h
@@ -124,6 +124,7 @@ public:
// LLIMSessionObserver triggers
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}; // Stub
virtual void sessionRemoved(const LLUUID& session_id){} // Stub
virtual void sessionVoiceOrIMStarted(const LLUUID& session_id){}; // Stub
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id){}; // Stub
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index 5fc305da81..e5232d730c 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -27,6 +27,11 @@
#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llavatarnamecache.h"
+#include "llavataractions.h"
+#include "llevents.h"
+#include "llsdutil.h"
#include "llconversationmodel.h"
#include "llimview.h" //For LLIMModel
@@ -64,6 +69,14 @@ LLConversationItem::LLConversationItem(LLFolderViewModelInterface& root_view_mod
{
}
+void LLConversationItem::postEvent(const std::string& event_type, LLConversationItemSession* session, LLConversationItemParticipant* participant)
+{
+ LLUUID session_id = (session ? session->getUUID() : LLUUID());
+ LLUUID participant_id = (participant ? participant->getUUID() : LLUUID());
+ LLSD event(LLSDMap("type", event_type)("session_uuid", session_id)("participant_uuid", participant_id));
+ LLEventPumps::instance().obtain("ConversationsEvents").post(event);
+}
+
// Virtual action callbacks
void LLConversationItem::performAction(LLInventoryModel* model, std::string action)
{
@@ -130,12 +143,55 @@ void LLConversationItemSession::addParticipant(LLConversationItemParticipant* pa
addChild(participant);
mIsLoaded = true;
mNeedsRefresh = true;
+ updateParticipantName(participant);
+ postEvent("add_participant", this, participant);
+}
+
+void LLConversationItemSession::updateParticipantName(LLConversationItemParticipant* participant)
+{
+ // We modify the session name only in the case of an ad-hoc session, exit otherwise (nothing to do)
+ if (getType() != CONV_SESSION_AD_HOC)
+ {
+ return;
+ }
+ // Avoid changing the default name if no participant present yet
+ if (mChildren.size() == 0)
+ {
+ return;
+ }
+ // Build a string containing the participants names and check if ready for display (we don't want "(waiting)" in there)
+ bool all_names_resolved = true;
+ uuid_vec_t temp_uuids; // uuids vector for building the added participants' names string
+ child_list_t::iterator iter = mChildren.begin();
+ while (iter != mChildren.end())
+ {
+ LLConversationItemParticipant* current_participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
+ temp_uuids.push_back(current_participant->getUUID());
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(current_participant->getUUID(), &av_name))
+ {
+ // If the name is not in the cache yet, bail out
+ // Note: we don't bind ourselves to the LLAvatarNameCache event as we are called by
+ // onAvatarNameCache() which is itself attached to the same event.
+ all_names_resolved = false;
+ break;
+ }
+ iter++;
+ }
+ if (all_names_resolved)
+ {
+ std::string new_session_name;
+ LLAvatarActions::buildResidentsString(temp_uuids, new_session_name);
+ renameItem(new_session_name);
+ postEvent("update_session", this, NULL);
+ }
}
void LLConversationItemSession::removeParticipant(LLConversationItemParticipant* participant)
{
removeChild(participant);
mNeedsRefresh = true;
+ postEvent("remove_participant", this, participant);
}
void LLConversationItemSession::removeParticipant(const LLUUID& participant_id)
@@ -319,7 +375,10 @@ void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags)
menuentry_vec_t items;
menuentry_vec_t disabled_items;
- buildParticipantMenuOptions(items);
+ if(gAgent.getID() != mUUID)
+ {
+ buildParticipantMenuOptions(items);
+ }
hide_context_entries(menu, items, disabled_items);
}
@@ -328,10 +387,13 @@ void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_nam
mName = (av_name.mUsername.empty() ? av_name.mDisplayName : av_name.mUsername);
mDisplayName = (av_name.mDisplayName.empty() ? av_name.mUsername : av_name.mDisplayName);
mNeedsRefresh = true;
- if (mParent)
+ LLConversationItemSession* parent_session = dynamic_cast<LLConversationItemSession*>(mParent);
+ if (parent_session)
{
- mParent->requestSort();
+ parent_session->requestSort();
+ parent_session->updateParticipantName(this);
}
+ postEvent("update_participant", parent_session, this);
}
void LLConversationItemParticipant::dumpDebugData()
diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h
index bc72cd96ea..1d082852f5 100755
--- a/indra/newview/llconversationmodel.h
+++ b/indra/newview/llconversationmodel.h
@@ -126,6 +126,8 @@ public:
void resetRefresh() { mNeedsRefresh = false; }
bool needsRefresh() { return mNeedsRefresh; }
+ void postEvent(const std::string& event_type, LLConversationItemSession* session, LLConversationItemParticipant* participant);
+
void buildParticipantMenuOptions(menuentry_vec_t& items);
protected:
@@ -147,6 +149,7 @@ public:
LLPointer<LLUIImage> getIcon() const { return NULL; }
void setSessionID(const LLUUID& session_id) { mUUID = session_id; mNeedsRefresh = true; }
void addParticipant(LLConversationItemParticipant* participant);
+ void updateParticipantName(LLConversationItemParticipant* participant);
void removeParticipant(LLConversationItemParticipant* participant);
void removeParticipant(const LLUUID& participant_id);
void clearParticipants();
diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp
index d4eb551f7a..b7ebb70e86 100755
--- a/indra/newview/llconversationview.cpp
+++ b/indra/newview/llconversationview.cpp
@@ -32,6 +32,8 @@
#include <boost/bind.hpp>
#include "llagentdata.h"
#include "llconversationmodel.h"
+#include "llimfloater.h"
+#include "llnearbychat.h"
#include "llimconversation.h"
#include "llimfloatercontainer.h"
#include "llfloaterreg.h"
@@ -181,10 +183,8 @@ void LLConversationViewSession::draw()
// draw highlight for selected items
drawHighlight(show_context, true, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
- // draw children if root folder, or any other folder that is open or animating to closed state
- bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this)
- || isOpen()
- || mCurHeight != mTargetHeight;
+ // Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap.
+ bool draw_children = getRoot() == static_cast<LLFolderViewFolder*>(this) || isOpen();
for (folders_t::iterator iter = mFolders.begin();
iter != mFolders.end();)
@@ -407,21 +407,50 @@ void LLConversationViewParticipant::draw()
static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
- const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled
const LLFontGL* font = getLabelFontForStyle(mLabelStyle);
F32 right_x = 0;
F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad;
F32 text_left = (F32)getLabelXPos();
- LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor;
+ LLColor4 color = mIsSelected ? sHighlightFgColor : sFgColor;
- drawHighlight(show_context, filled, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
+ drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor);
drawLabel(font, text_left, y, color, right_x);
LLView::draw();
}
+void LLConversationViewParticipant::selectItem()
+{
+ LLConversationItem* vmi = this->getParentFolder() ? static_cast<LLConversationItem*>(this->getParentFolder()->getViewModelItem()) : NULL;
+ LLIMFloaterContainer* container = LLIMFloaterContainer::getInstance();
+ LLFloater* session_floater;
+
+ //Only execute when switching floaters (conversations)
+ if(vmi && vmi->getUUID() != container->getSelectedSession())
+ {
+ //When null, show the nearby chat conversation floater
+ if(vmi->getUUID().isNull())
+ {
+ LLNearbyChat* nearbyChat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat");
+ nearbyChat->show();
+ }
+ //Otherwise, show the IM conversation floater
+ else
+ {
+ LLIMFloater::show(vmi->getUUID());
+ }
+ }
+ //Focus the current conversation floater (it is already visible so just focus it)
+ else
+ {
+ session_floater = LLIMConversation::getConversation(vmi->getUUID());
+ session_floater->setFocus(TRUE);
+ }
+
+ LLFolderViewItem::selectItem();
+}
void LLConversationViewParticipant::refresh()
{
diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h
index c81c70b456..bd95387bbe 100755
--- a/indra/newview/llconversationview.h
+++ b/indra/newview/llconversationview.h
@@ -113,6 +113,7 @@ public:
};
virtual ~LLConversationViewParticipant( void ) { }
+ void selectItem();
bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); }
virtual void refresh();
void addToFolder(LLFolderViewFolder* folder);
diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp
index 2ad7f9b193..bd2a2419a8 100644
--- a/indra/newview/llimconversation.cpp
+++ b/indra/newview/llimconversation.cpp
@@ -54,7 +54,6 @@ LLIMConversation::LLIMConversation(const LLSD& session_id)
, mInputEditor(NULL)
, mInputEditorTopPad(0)
, mRefreshTimer(new LLTimer())
- , mHasFocus(false)
{
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
@@ -216,21 +215,11 @@ void LLIMConversation::onFocusReceived()
}
LLTransientDockableFloater::onFocusReceived();
-
- mHadFocus = mHasFocus;
- mHasFocus = true;
-
- if (! mHadFocus)
- {
- LLIMFloaterContainer* container = LLIMFloaterContainer::getInstance();
- container->setConvItemSelect(mSessionID);
- }
}
void LLIMConversation::onFocusLost()
{
setBackgroundOpaque(false);
- mHasFocus = false;
LLTransientDockableFloater::onFocusLost();
}
@@ -393,7 +382,7 @@ void LLIMConversation::updateHeaderAndToolbar()
// prevent start conversation before its container
LLIMFloaterContainer::getInstance();
- bool is_torn_off = !getHost();
+ bool is_torn_off = checkIfTornOff();
if (!is_torn_off)
{
hideAllStandardButtons();
@@ -505,16 +494,12 @@ void LLIMConversation::onSlide(LLIMConversation* self)
/*virtual*/
void LLIMConversation::onOpen(const LLSD& key)
{
- LLIMFloaterContainer* host_floater = dynamic_cast<LLIMFloaterContainer*>(getHost());
- bool is_hosted = !!host_floater;
- if (is_hosted)
+ if (!checkIfTornOff())
{
+ LLIMFloaterContainer* host_floater = dynamic_cast<LLIMFloaterContainer*>(getHost());
// Show the messages pane when opening a floater hosted in the Conversations
host_floater->collapseMessagesPane(false);
}
-
- setTornOff(!is_hosted);
- updateHeaderAndToolbar();
}
// virtual
@@ -546,3 +531,16 @@ bool LLIMConversation::isChatMultiTab()
// Restart is required in order to change chat window type.
return true;
}
+
+bool LLIMConversation::checkIfTornOff()
+{
+ bool isTorn = !getHost();
+
+ if (isTorn != isTornOff())
+ {
+ setTornOff(isTorn);
+ updateHeaderAndToolbar();
+ }
+
+ return isTorn;
+}
diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h
index c54081d316..603e0d0197 100644
--- a/indra/newview/llimconversation.h
+++ b/indra/newview/llimconversation.h
@@ -138,10 +138,9 @@ private:
*/
void reshapeChatHistory();
- LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
+ bool checkIfTornOff();
- bool mHadFocus;
- bool mHasFocus;
+ LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
};
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 99337bd5f3..e4032738a7 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -60,10 +60,6 @@
#include "llnotificationmanager.h"
#include "llautoreplace.h"
-/// Helper function to resolve resident names from given uuids
-/// and form a string of names separated by "words_separator".
-static void build_names_string(const uuid_vec_t& uuids, std::string& names_string);
-
floater_showed_signal_t LLIMFloater::sIMFloaterShowedSignal;
LLIMFloater::LLIMFloater(const LLUUID& session_id)
@@ -476,7 +472,7 @@ void LLIMFloater::addP2PSessionParticipants(const LLSD& notification, const LLSD
void LLIMFloater::sendParticipantsAddedNotification(const uuid_vec_t& uuids)
{
std::string names_string;
- build_names_string(uuids, names_string);
+ LLAvatarActions::buildResidentsString(uuids, names_string);
LLStringUtil::format_map_t args;
args["[NAME]"] = names_string;
@@ -581,7 +577,7 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
if (all_names_resolved)
{
std::string ui_title;
- build_names_string(temp_uuids, ui_title);
+ LLAvatarActions::buildResidentsString(temp_uuids, ui_title);
updateSessionName(ui_title, ui_title);
}
}
@@ -719,6 +715,19 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
}
}
+void LLIMFloater::setFocus(BOOL focusFlag)
+{
+ LLTransientDockableFloater::setFocus(focusFlag);
+
+ //Redirect focus to input editor
+ if (focusFlag)
+ {
+ updateMessages();
+ mInputEditor->setFocus(TRUE);
+ }
+
+}
+
void LLIMFloater::setVisible(BOOL visible)
{
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
@@ -734,21 +743,6 @@ void LLIMFloater::setVisible(BOOL visible)
channel->redrawToasts();
}
- BOOL is_minimized = visible && isChatMultiTab()
- ? LLIMFloaterContainer::getInstance()->isMinimized()
- : !visible;
-
- if (!is_minimized && mChatHistory && mInputEditor)
- {
- //only if floater was construced and initialized from xml
- updateMessages();
- //prevent stealing focus when opening a background IM tab (EXT-5387, checking focus for EXT-6781)
- if (!isChatMultiTab() || hasFocus())
- {
- mInputEditor->setFocus(TRUE);
- }
- }
-
if(!visible)
{
LLIMChiclet* chiclet = LLChicletBar::getInstance()->getChicletPanel()->findChiclet<LLIMChiclet>(mSessionID);
@@ -761,7 +755,10 @@ void LLIMFloater::setVisible(BOOL visible)
if (visible && isInVisibleChain())
{
sIMFloaterShowedSignal(mSessionID);
+
}
+
+ setFocus(visible);
}
BOOL LLIMFloater::getVisible()
@@ -1334,25 +1331,3 @@ boost::signals2::connection LLIMFloater::setIMFloaterShowedCallback(const floate
{
return LLIMFloater::sIMFloaterShowedSignal.connect(cb);
}
-
-// static
-void build_names_string(const uuid_vec_t& uuids, std::string& names_string)
-{
- std::vector<LLAvatarName> avatar_names;
- uuid_vec_t::const_iterator it = uuids.begin();
- for (; it != uuids.end(); ++it)
- {
- LLAvatarName av_name;
- if (LLAvatarNameCache::get(*it, &av_name))
- {
- avatar_names.push_back(av_name);
- }
- }
-
- // We should check whether the vector is not empty to pass the assertion
- // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString.
- if (!avatar_names.empty())
- {
- LLAvatarActions::buildResidentsString(avatar_names, names_string);
- }
-}
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index 5ed1d1ab35..26daf00afd 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -65,6 +65,7 @@ public:
// LLView overrides
/*virtual*/ BOOL postBuild();
+ /*virtual*/ void setFocus(BOOL focusFlag);
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ BOOL getVisible();
// Check typing timeout timer.
diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp
index 4af170b3db..5c1105531e 100644
--- a/indra/newview/llimfloatercontainer.cpp
+++ b/indra/newview/llimfloatercontainer.cpp
@@ -50,6 +50,7 @@
#include "llcallbacklist.h"
#include "llworld.h"
+#include "llsdserialize.h"
//
// LLIMFloaterContainer
//
@@ -57,6 +58,7 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
: LLMultiFloater(seed),
mExpandCollapseBtn(NULL),
mConversationsRoot(NULL),
+ mConversationsEventStream("ConversationsEvents"),
mInitialized(false)
{
mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2));
@@ -77,6 +79,8 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
LLIMFloaterContainer::~LLIMFloaterContainer()
{
+ mConversationsEventStream.stopListening("ConversationsRefresh");
+
gIdleCallbacks.deleteFunction(idle, this);
mNewMessageConnection.disconnect();
@@ -94,19 +98,23 @@ LLIMFloaterContainer::~LLIMFloaterContainer()
void LLIMFloaterContainer::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
{
LLIMFloater::addToHost(session_id, true);
- addConversationListItem(session_id);
+ addConversationListItem(session_id, true);
+}
+
+void LLIMFloaterContainer::sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
+{
+ setItemSelect(session_id);
}
void LLIMFloaterContainer::sessionVoiceOrIMStarted(const LLUUID& session_id)
{
LLIMFloater::addToHost(session_id, true);
- addConversationListItem(session_id);
+ addConversationListItem(session_id, true);
}
void LLIMFloaterContainer::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
{
- removeConversationListItem(old_session_id);
- addConversationListItem(new_session_id);
+ addConversationListItem(new_session_id, removeConversationListItem(old_session_id));
}
void LLIMFloaterContainer::sessionRemoved(const LLUUID& session_id)
@@ -138,6 +146,9 @@ BOOL LLIMFloaterContainer::postBuild()
mConversationsListPanel = getChild<LLPanel>("conversations_list_panel");
+ // Open IM session with selected participant on double click event
+ mConversationsListPanel->setDoubleClickCallback(boost::bind(&LLIMFloaterContainer::doToSelected, this, LLSD("im")));
+
// Create the root model and view for all conversation sessions
LLConversationItem* base_item = new LLConversationItem(getRootViewModel());
@@ -155,6 +166,9 @@ BOOL LLIMFloaterContainer::postBuild()
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ // Add listener to conversation model events
+ mConversationsEventStream.listen("ConversationsRefresh", boost::bind(&LLIMFloaterContainer::onConversationModelEvent, this, _1));
+
// a scroller for folder view
LLRect scroller_view_rect = mConversationsListPanel->getRect();
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
@@ -397,62 +411,81 @@ void LLIMFloaterContainer::idle(void* user_data)
self->mConversationsRoot->update();
}
-void LLIMFloaterContainer::draw()
+bool LLIMFloaterContainer::onConversationModelEvent(const LLSD& event)
{
- // CHUI Notes
- // Currently, the model is not responsible for creating the view which is a good thing. This means that
- // the model could change substantially and the view could decide to echo only a portion of this model.
- // Consequently, the participant views need to be created either by the session view or by the container panel.
- // For the moment, we create them here (which makes for complicated code...) to conform to the pattern
- // implemented in llinventorypanel.cpp (see LLInventoryPanel::buildNewViews()).
- // The best however would be to have an observer on the model so that we would not pool on each draw to know
- // if the view needs refresh. The current implementation (testing for change on draw) is less
- // efficient perf wise than a listener/observer scheme. We will implement that shortly.
+ // For debug only
+ //std::ostringstream llsd_value;
+ //llsd_value << LLSDOStreamer<LLSDNotationFormatter>(event) << std::endl;
+ //llinfos << "Merov debug : onConversationModelEvent, event = " << llsd_value.str() << llendl;
+ // end debug
- // On each session in mConversationsItems
- for (conversations_items_map::iterator it_session = mConversationsItems.begin(); it_session != mConversationsItems.end(); it_session++)
+ // Note: In conversations, the model is not responsible for creating the view, which is a good thing. This means that
+ // the model could change substantially and the view could echo only a portion of this model (though currently the
+ // conversation view does echo the conversation model 1 to 1).
+ // Consequently, the participant views need to be created either by the session view or by the container panel.
+ // For the moment, we create them here, at the container level, to conform to the pattern implemented in llinventorypanel.cpp
+ // (see LLInventoryPanel::buildNewViews()).
+
+ std::string type = event.get("type").asString();
+ LLUUID session_id = event.get("session_uuid").asUUID();
+ LLUUID participant_id = event.get("participant_uuid").asUUID();
+
+ LLConversationViewSession* session_view = dynamic_cast<LLConversationViewSession*>(mConversationsWidgets[session_id]);
+ if (!session_view)
{
- // Get the current session descriptors
- LLConversationItem* session_model = it_session->second;
- LLUUID session_id = it_session->first;
- LLConversationViewSession* session_view = dynamic_cast<LLConversationViewSession*>(mConversationsWidgets[session_id]);
- // If the session model has been changed, refresh the corresponding view
- if (session_model->needsRefresh())
+ // We skip events that are not associated to a session
+ return false;
+ }
+ LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id);
+
+ if (type == "remove_participant")
+ {
+ if (participant_view)
{
+ session_view->extractItem(participant_view);
+ delete participant_view;
session_view->refresh();
+ mConversationsRoot->arrangeAll();
}
- // Iterate through each model participant child
- LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = session_model->getChildrenBegin();
- LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd();
- while (current_participant_model != end_participant_model)
+ }
+ else if (type == "add_participant")
+ {
+ if (!participant_view)
{
- LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
- LLUUID participant_id = participant_model->getUUID();
- LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id);
- // Is there a corresponding view? If not create it
- if (!participant_view)
+ LLConversationItemSession* session_model = dynamic_cast<LLConversationItemSession*>(mConversationsItems[session_id]);
+ if (session_model)
{
- participant_view = createConversationViewParticipant(participant_model);
- participant_view->addToFolder(session_view);
- participant_view->setVisible(TRUE);
- }
- else
- // Else, see if it needs refresh
- {
- if (participant_model->needsRefresh())
+ LLConversationItemParticipant* participant_model = session_model->findParticipant(participant_id);
+ if (participant_model)
{
- participant_view->refresh();
+ participant_view = createConversationViewParticipant(participant_model);
+ participant_view->addToFolder(session_view);
+ participant_view->setVisible(TRUE);
}
}
- // Reset the need for refresh
- session_model->resetRefresh();
- mConversationViewModel.requestSortAll();
- mConversationsRoot->arrangeAll();
- // Next participant
- current_participant_model++;
+
+ }
+ }
+ else if (type == "update_participant")
+ {
+ if (participant_view)
+ {
+ participant_view->refresh();
}
}
+ else if (type == "update_session")
+ {
+ session_view->refresh();
+ }
+ mConversationViewModel.requestSortAll();
+ mConversationsRoot->arrangeAll();
+
+ return false;
+}
+
+void LLIMFloaterContainer::draw()
+{
if (mTabContainer->getTabCount() == 0)
{
// Do not close the container when every conversation is torn off because the user
@@ -527,12 +560,25 @@ void LLIMFloaterContainer::collapseMessagesPane(bool collapse)
gSavedPerAccountSettings.setBOOL("ConversationsExpandMessagePaneFirst", mConversationsPane->isCollapsed());
}
+ // Save left pane rectangle before collapsing/expanding right pane.
+ LLRect prevRect = mConversationsPane->getRect();
+
// Show/hide the messages pane.
mConversationsStack->collapsePanel(mMessagesPane, collapse);
+ if (!collapse)
+ {
+ // Make sure layout is updated before resizing conversation pane.
+ mConversationsStack->updateLayout();
+ }
+
updateState(collapse, gSavedPerAccountSettings.getS32("ConversationsMessagePaneWidth"));
+ if (!collapse)
+ {
+ // Restore conversation's pane previous width after expanding messages pane.
+ mConversationsPane->setTargetDim(prevRect.getWidth());
+ }
}
-
void LLIMFloaterContainer::collapseConversationsPane(bool collapse)
{
if (mConversationsPane->isCollapsed() == collapse)
@@ -862,7 +908,13 @@ void LLIMFloaterContainer::doToSelectedConversation(const std::string& command,
}
else if("chat_history" == command)
{
- LLAvatarActions::viewChatHistory(conversationItem->getUUID());
+ const LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(conversationItem->getUUID());
+
+ if (NULL != session)
+ {
+ const LLUUID session_id = session->isOutgoingAdHoc() ? session->generateOutgouigAdHocHash() : session->mSessionID;
+ LLFloaterReg::showInstance("preview_conversation", session_id, true);
+ }
}
else
{
@@ -914,6 +966,12 @@ bool LLIMFloaterContainer::enableContextMenuItem(const LLSD& userdata)
uuid_vec_t mUUIDs;
getParticipantUUIDs(mUUIDs);
+ if(item == std::string("can_activate_group"))
+ {
+ LLUUID selected_group_id = getCurSelectedViewModelItem()->getUUID();
+ return gAgent.getGroupID() != selected_group_id;
+ }
+
if(mUUIDs.size() <= 0)
{
return false;
@@ -1014,6 +1072,7 @@ bool LLIMFloaterContainer::checkContextMenuItem(const LLSD& userdata)
return false;
}
+//Will select only the conversation item
void LLIMFloaterContainer::setConvItemSelect(const LLUUID& session_id)
{
LLFolderViewItem* widget = mConversationsWidgets[session_id];
@@ -1024,6 +1083,26 @@ void LLIMFloaterContainer::setConvItemSelect(const LLUUID& session_id)
}
}
+//Will select the conversation/participant item
+void LLIMFloaterContainer::setItemSelect(const LLUUID& session_id)
+{
+
+ if(mConversationsRoot->getCurSelectedItem() && mConversationsRoot->getCurSelectedItem()->getParentFolder())
+ {
+ //Retreive the conversation id. When a participant is selected, then have to to get the converation id from the parent.
+ LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(mConversationsRoot->getCurSelectedItem()->getParentFolder()->getViewModelItem());
+
+ //Will allow selection/highlighting of the conversation/participant
+ if(session_id != vmi->getUUID())
+ {
+ mSelectedSession = session_id;
+ LLFolderViewItem* widget = mConversationsWidgets[session_id];
+ (widget->getRoot())->setSelection(widget, FALSE, FALSE);
+ }
+ }
+}
+
+
void LLIMFloaterContainer::setTimeNow(const LLUUID& session_id, const LLUUID& participant_id)
{
conversations_items_map::iterator item_it = mConversationsItems.find(session_id);
@@ -1070,7 +1149,7 @@ void LLIMFloaterContainer::setNearbyDistances()
}
}
-void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
+void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid, bool isWidgetSelected /*= false*/)
{
bool is_nearby_chat = uuid.isNull();
@@ -1089,7 +1168,7 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
removeConversationListItem(uuid,false);
// Create a conversation session model
- LLConversationItem* item = NULL;
+ LLConversationItemSession* item = NULL;
LLSpeakerMgr* speaker_manager = (is_nearby_chat ? (LLSpeakerMgr*)(LLLocalSpeakerMgr::getInstance()) : LLIMModel::getInstance()->getSpeakerManager(uuid));
if (speaker_manager)
{
@@ -1101,6 +1180,7 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
return;
}
item->renameItem(display_name);
+ item->updateParticipantName(NULL);
mConversationsItems[uuid] = item;
@@ -1124,7 +1204,10 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
current_participant_model++;
}
- setConvItemSelect(uuid);
+ if (isWidgetSelected)
+ {
+ setConvItemSelect(uuid);
+ }
// set the widget to minimized mode if conversations pane is collapsed
widget->toggleMinimizedMode(mConversationsPane->isCollapsed());
@@ -1132,17 +1215,19 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid)
return;
}
-void LLIMFloaterContainer::removeConversationListItem(const LLUUID& uuid, bool change_focus)
+bool LLIMFloaterContainer::removeConversationListItem(const LLUUID& uuid, bool change_focus)
{
// Delete the widget and the associated conversation item
// Note : since the mConversationsItems is also the listener to the widget, deleting
// the widget will also delete its listener
+ bool isWidgetSelected = false;
conversations_widgets_map::iterator widget_it = mConversationsWidgets.find(uuid);
if (widget_it != mConversationsWidgets.end())
{
LLFolderViewItem* widget = widget_it->second;
if (widget)
{
+ isWidgetSelected = widget->isSelected();
widget->destroyView();
}
}
@@ -1158,10 +1243,12 @@ void LLIMFloaterContainer::removeConversationListItem(const LLUUID& uuid, bool c
conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin();
if (widget_it != mConversationsWidgets.end())
{
+ mSelectedSession = widget_it->first;
LLFolderViewItem* widget = widget_it->second;
widget->selectItem();
}
}
+ return isWidgetSelected;
}
LLConversationViewSession* LLIMFloaterContainer::createConversationItemWidget(LLConversationItem* item)
diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h
index 76e468f979..6643471d97 100644
--- a/indra/newview/llimfloatercontainer.h
+++ b/indra/newview/llimfloatercontainer.h
@@ -31,6 +31,7 @@
#include <vector>
#include "llimview.h"
+#include "llevents.h"
#include "llfloater.h"
#include "llmultifloater.h"
#include "llavatarpropertiesprocessor.h"
@@ -63,6 +64,7 @@ public:
BOOL select_added_floater,
LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
void setConvItemSelect(const LLUUID& session_id);
+ void setItemSelect(const LLUUID& session_id);
/*virtual*/ void tabClose();
static LLFloater* getCurrentVoiceFloater();
@@ -80,11 +82,13 @@ public:
// LLIMSessionObserver observe triggers
/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ /*virtual*/ void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
/*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id);
/*virtual*/ void sessionRemoved(const LLUUID& session_id);
/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
LLConversationViewModel& getRootViewModel() { return mConversationViewModel; }
+ LLUUID getSelectedSession() { return mSelectedSession; }
private:
typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t;
@@ -132,14 +136,15 @@ private:
// Conversation list implementation
public:
- void removeConversationListItem(const LLUUID& uuid, bool change_focus = true);
- void addConversationListItem(const LLUUID& uuid);
+ bool removeConversationListItem(const LLUUID& uuid, bool change_focus = true);
+ void addConversationListItem(const LLUUID& uuid, bool isWidgetSelected = false);
void setTimeNow(const LLUUID& session_id, const LLUUID& participant_id);
void setNearbyDistances();
private:
LLConversationViewSession* createConversationItemWidget(LLConversationItem* item);
LLConversationViewParticipant* createConversationViewParticipant(LLConversationItem* item);
+ bool onConversationModelEvent(const LLSD& event);
// Conversation list data
LLPanel* mConversationsListPanel; // This is the main widget we add conversation widget to
@@ -147,6 +152,7 @@ private:
conversations_widgets_map mConversationsWidgets;
LLConversationViewModel mConversationViewModel;
LLFolderView* mConversationsRoot;
+ LLEventStream mConversationsEventStream;
};
#endif // LL_LLIMFLOATERCONTAINER_H
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index b45903835a..115da54ec8 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -647,8 +647,6 @@ void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, con
{
mId2SessionMap.erase(old_session_id);
mId2SessionMap[new_session_id] = session;
-
- gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id);
}
LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id);
@@ -657,6 +655,11 @@ void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, con
im_floater->sessionInitReplyReceived(new_session_id);
}
+ if (old_session_id != new_session_id)
+ {
+ gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id);
+ }
+
// auto-start the call on session initialization?
if (session->mStartCallOnInitialize)
{
@@ -2650,10 +2653,17 @@ LLUUID LLIMMgr::addSession(
}
}
+ //Notify observers that a session was added
if (new_session)
{
LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids, voice);
}
+ //Notifies observers that the session was already added
+ else
+ {
+ std::string session_name = LLIMModel::getInstance()->getName(session_id);
+ LLIMMgr::getInstance()->notifyObserverSessionActivated(session_id, session_name, other_participant_id);
+ }
//we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions
if (!new_session) return session_id;
@@ -2956,6 +2966,14 @@ void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::st
}
}
+void LLIMMgr::notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
+{
+ for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++)
+ {
+ (*it)->sessionActivated(session_id, name, other_participant_id);
+ }
+}
+
void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id)
{
for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++)
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 82cfa394a6..00b67f520c 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -303,6 +303,7 @@ class LLIMSessionObserver
public:
virtual ~LLIMSessionObserver() {}
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0;
+ virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0;
virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0;
virtual void sessionRemoved(const LLUUID& session_id) = 0;
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0;
@@ -469,6 +470,8 @@ private:
static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group);
void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ //Triggers when a session has already been added
+ void notifyObserverSessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id);
void notifyObserverSessionRemoved(const LLUUID& session_id);
void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index b96b486868..a89ae4a2dc 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -271,14 +271,27 @@ void LLNearbyChat::removeScreenChat()
}
}
-void LLNearbyChat::setVisible(BOOL visible)
+void LLNearbyChat::setFocus(BOOL focusFlag)
{
- if(visible)
- {
- removeScreenChat();
- }
+ LLTransientDockableFloater::setFocus(focusFlag);
+
+ //Redirect focus to input editor
+ if (focusFlag)
+ {
+ mInputEditor->setFocus(TRUE);
+ }
+
+}
+void LLNearbyChat::setVisible(BOOL visible)
+{
LLIMConversation::setVisible(visible);
+
+ if(visible)
+ {
+ removeScreenChat();
+ }
+ setFocus(visible);
}
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index 93168ba96a..7ada4daea8 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -52,7 +52,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
-
+ /*virtual*/ void setFocus(BOOL focusFlag);
/*virtual*/ void setVisible(BOOL visible);
void loadHistory();
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index 6be12711ac..378d5e0aa2 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -171,6 +171,7 @@ public:
// LLIMSessionObserver observe triggers
/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ /*virtual*/ void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}
/*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
/*virtual*/ void sessionRemoved(const LLUUID& session_id);
/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
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 5c74f7f9bb..8cd0463de8 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -246,7 +246,7 @@
parse_highlights="true"
parse_urls="true"
width="230"
- left="0">
+ left="5">
</chat_history>
</layout_panel>
</layout_stack>
diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml
index 912ff811d9..682d70e4f0 100644
--- a/indra/newview/skins/default/xui/en/menu_conversation.xml
+++ b/indra/newview/skins/default/xui/en/menu_conversation.xml
@@ -117,6 +117,7 @@
layout="topleft"
name="activate_group">
<on_click function="Group.DoToSelected" parameter="activate_group"/>
+ <on_enable function="Avatar.EnableItem" parameter="can_activate_group" />
</menu_item_call>
<menu_item_call
label="Leave Group"
diff --git a/indra/newview/skins/default/xui/en/menu_participant_view.xml b/indra/newview/skins/default/xui/en/menu_participant_view.xml
index 0043c14479..6fa0707eea 100644
--- a/indra/newview/skins/default/xui/en/menu_participant_view.xml
+++ b/indra/newview/skins/default/xui/en/menu_participant_view.xml
@@ -59,17 +59,6 @@
function="IMFloaterContainer.Check"
parameter="sort_participants_by_recent" />
</menu_item_check>
- <menu_item_check
- label="Sort participants by distance from you"
- layout="topleft"
- name="sort_participants_by_distance">
- <on_click
- function="IMFloaterContainer.Action"
- parameter="sort_participants_by_distance" />
- <on_check
- function="IMFloaterContainer.Check"
- parameter="sort_participants_by_distance" />
- </menu_item_check>
<menu_item_separator
layout="topleft" />
<menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 88b30c8272..c805b6db42 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -218,8 +218,18 @@
label="Communicate"
name="Communicate"
tear_off="true">
- <menu_item_check
- label="Chat..."
+ <menu_item_check
+ label="Conversations..."
+ name="Conversations">
+ <menu_item_check.on_check
+ function="Floater.IsOpen"
+ parameter="im_container" />
+ <menu_item_check.on_click
+ function="Floater.ToggleOrBringToFront"
+ parameter="im_container" />
+ </menu_item_check>
+ <menu_item_check
+ label="Nearby Chat..."
name="Nearby Chat"
shortcut="control|H"
use_mac_ctrl="true">
@@ -244,6 +254,17 @@
parameter="speak" />
</menu_item_check>
<menu_item_check
+ label="Conversations Log..."
+ name="ConversationsLog">
+ <menu_item_check.on_check
+ function="Floater.Visible"
+ parameter="conversation" />
+ <menu_item_check.on_click
+ function="Floater.Toggle"
+ parameter="conversation" />
+ </menu_item_check>
+ <menu_item_separator/>
+ <menu_item_check
label="Voice morphing..."
name="ShowVoice"
visibility_control="VoiceMorphingEnabled">