summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llimfloater.cpp376
-rw-r--r--indra/newview/llimfloater.h7
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml6
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml14
4 files changed, 256 insertions, 147 deletions
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index cdd5ba6889..6f26f1daff 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -60,6 +60,10 @@
#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)
@@ -123,14 +127,13 @@ void LLIMFloater::refresh()
// virtual
void LLIMFloater::onClickCloseBtn()
{
- LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
- mSessionID);
+ LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID);
if (session == NULL)
{
llwarns << "Empty session with id: " << (mSessionID.asString()) << llendl;
return;
-}
+ }
bool is_call_with_chat = session->isGroupSessionType()
|| session->isAdHocSessionType() || session->isP2PSessionType();
@@ -186,49 +189,55 @@ void LLIMFloater::onVisibilityChange(const LLSD& new_visibility)
void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata )
{
LLIMFloater* self = (LLIMFloater*) userdata;
- self->sendMsg();
+ self->sendMsgFromInputEditor();
self->setTyping(false);
}
-void LLIMFloater::sendMsg()
+void LLIMFloater::sendMsgFromInputEditor()
{
if (gAgent.isGodlike()
|| (mDialog != IM_NOTHING_SPECIAL)
|| !mOtherParticipantUUID.isNull())
{
- if (mInputEditor)
- {
+ if (mInputEditor)
+ {
LLWString text = mInputEditor->getWText();
LLWStringUtil::trim(text);
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
- if(!text.empty())
- {
- // Truncate and convert to UTF8 for transport
- std::string utf8_text = wstring_to_utf8str(text);
- utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1);
-
- if (mSessionInitialized)
- {
- LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog);
- }
- else
+ if(!text.empty())
{
- //queue up the message to send once the session is initialized
- mQueuedMsgsForInit.append(utf8_text);
- }
+ // Truncate and convert to UTF8 for transport
+ std::string utf8_text = wstring_to_utf8str(text);
- mInputEditor->setText(LLStringUtil::null);
+ sendMsg(utf8_text);
- updateMessages();
+ mInputEditor->setText(LLStringUtil::null);
+ }
}
}
-}
else
{
llinfos << "Cannot send IM to everyone unless you're a god." << llendl;
}
}
+void LLIMFloater::sendMsg(const std::string& msg)
+{
+ const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1);
+
+ if (mSessionInitialized)
+ {
+ LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog);
+ }
+ else
+ {
+ //queue up the message to send once the session is initialized
+ mQueuedMsgsForInit.append(utf8_text);
+ }
+
+ updateMessages();
+}
+
LLIMFloater::~LLIMFloater()
{
mParticipantsListRefreshConnection.disconnect();
@@ -241,6 +250,7 @@ LLIMFloater::~LLIMFloater()
LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this);
}
+
void LLIMFloater::initIMSession(const LLUUID& session_id)
{
// Change the floater key to bind it to a new session.
@@ -250,7 +260,7 @@ void LLIMFloater::initIMSession(const LLUUID& session_id)
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
if (mSession)
- {
+ {
mIsP2PChat = mSession->isP2PSessionType();
mSessionInitialized = mSession->mSessionInitialized;
@@ -348,19 +358,19 @@ BOOL LLIMFloater::postBuild()
}
void LLIMFloater::onAddButtonClicked()
+{
+ LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::addSessionParticipants, this, _1), TRUE, TRUE);
+ if (!picker)
{
- LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::addSessionParticipants, this, _1), TRUE, TRUE);
- if (!picker)
- {
- return;
+ return;
}
- // Need to disable 'ok' button when selected users are already in conversation.
- picker->setOkBtnEnableCb(boost::bind(&LLIMFloater::canAddSelectedToChat, this, _1));
- LLFloater* root_floater = gFloaterView->getParentFloater(this);
- if (root_floater)
+ // Need to disable 'ok' button when selected users are already in conversation.
+ picker->setOkBtnEnableCb(boost::bind(&LLIMFloater::canAddSelectedToChat, this, _1));
+ LLFloater* root_floater = gFloaterView->getParentFloater(this);
+ if (root_floater)
{
- root_floater->addDependentFloater(picker);
+ root_floater->addDependentFloater(picker);
}
}
@@ -396,7 +406,7 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids)
if (speaker_mgr)
{
speaker_mgr->getSpeakerList(&speaker_list, true);
- }
+ }
for (uuid_vec_t::const_iterator id = uuids.begin();
id != uuids.end(); ++id)
@@ -417,42 +427,76 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids)
}
void LLIMFloater::addSessionParticipants(const uuid_vec_t& uuids)
- {
+{
if (mIsP2PChat)
{
- mStartConferenceInSameFloater = true;
+ LLSD payload;
+ LLSD args;
- uuid_vec_t temp_ids;
+ LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload,
+ boost::bind(&LLIMFloater::addP2PSessionParticipants, this, _1, _2, uuids));
+ }
+ else
+ {
+ // remember whom we have invited, to notify others later, when the invited ones actually join
+ mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+
+ inviteToSession(uuids);
+ }
+}
- // Add the initial participant of a P2P session
- temp_ids.push_back(mOtherParticipantUUID);
- temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end());
+void LLIMFloater::addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0)
+ {
+ return;
+ }
- LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
+ mStartConferenceInSameFloater = true;
- // first check whether this is a voice session
- bool is_voice_call = voice_channel != NULL && voice_channel->isActive();
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
- // then we can close the current session
- onClose(false);
+ // first check whether this is a voice session
+ bool is_voice_call = voice_channel != NULL && voice_channel->isActive();
- // Start a new ad hoc voice call if we invite new participants to a P2P call,
- // or start a text chat otherwise.
- if (is_voice_call)
- {
- LLAvatarActions::startAdhocCall(temp_ids, mSessionID);
- }
- else
+ uuid_vec_t temp_ids;
+
+ // Add the initial participant of a P2P session
+ temp_ids.push_back(mOtherParticipantUUID);
+ temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end());
+
+ // then we can close the current session
+ onClose(false);
+
+ // we start a new session so reset the initialization flag
+ mSessionInitialized = false;
+
+ // remember whom we have invited, to notify others later, when the invited ones actually join
+ mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
+
+ // Start a new ad hoc voice call if we invite new participants to a P2P call,
+ // or start a text chat otherwise.
+ if (is_voice_call)
{
- LLAvatarActions::startConference(temp_ids, mSessionID);
+ LLAvatarActions::startAdhocCall(temp_ids, mSessionID);
}
-}
else
{
- inviteToSession(uuids);
+ LLAvatarActions::startConference(temp_ids, mSessionID);
}
}
+void LLIMFloater::sendParticipantsAddedNotification(const uuid_vec_t& uuids)
+{
+ std::string names_string;
+ build_names_string(uuids, names_string);
+ LLStringUtil::format_map_t args;
+ args["[NAME]"] = names_string;
+
+ sendMsg(getString(uuids.size() > 1 ? "multiple_participants_added" : "participant_added", args));
+}
+
void LLIMFloater::boundVoiceChannel()
{
LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
@@ -547,13 +591,15 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
bool all_names_resolved = true;
std::vector<LLSD> participants_uuids;
+ uuid_vec_t temp_uuids; // uuids vector for building the added participants' names string
avatar_list->getValues(participants_uuids);
// Check whether we have all participants names in LLAvatarNameCache
for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it)
- {
+ {
const LLUUID& id = it->asUUID();
+ temp_uuids.push_back(id);
LLAvatarName av_name;
if (!LLAvatarNameCache::get(id, &av_name))
{
@@ -565,32 +611,15 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list));
break;
}
- }
+ }
if (all_names_resolved)
{
- std::vector<LLAvatarName> avatar_names;
- std::vector<LLSD>::const_iterator it = participants_uuids.begin();
- for (; it != participants_uuids.end(); ++it)
- {
- const LLUUID& id = it->asUUID();
- LLAvatarName av_name;
- if (LLAvatarNameCache::get(id, &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())
- {
- std::string ui_title;
- LLAvatarActions::buildResidentsString(avatar_names, ui_title);
- updateSessionName(ui_title, ui_title);
- }
+ std::string ui_title;
+ build_names_string(temp_uuids, ui_title);
+ updateSessionName(ui_title, ui_title);
+ }
}
-}
//static
LLIMFloater* LLIMFloater::addToIMContainer(const LLUUID& session_id)
@@ -840,18 +869,20 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB)
- //need to send delayed messaged collected while waiting for session initialization
+ //need to send delayed messages collected while waiting for session initialization
if (mQueuedMsgsForInit.size())
{
- LLSD::array_iterator iter;
- for ( iter = mQueuedMsgsForInit.beginArray();
- iter != mQueuedMsgsForInit.endArray(); ++iter)
- {
- LLIMModel::sendMessage(iter->asString(), mSessionID,
- mOtherParticipantUUID, mDialog);
+ LLSD::array_iterator iter;
+ for ( iter = mQueuedMsgsForInit.beginArray();
+ iter != mQueuedMsgsForInit.endArray(); ++iter)
+ {
+ LLIMModel::sendMessage(iter->asString(), mSessionID,
+ mOtherParticipantUUID, mDialog);
+ }
+
+ mQueuedMsgsForInit.clear();
}
}
-}
void LLIMFloater::appendMessage(const LLChat& chat, const LLSD &args)
{
@@ -1019,19 +1050,18 @@ void LLIMFloater::setTyping(bool typing)
{
LLIMModel::instance().sendTypingState(mSessionID,
mOtherParticipantUUID, mMeTyping);
- mShouldSendTypingState = false;
-
- }
+ mShouldSendTypingState = false;
}
+ }
if (!mIsNearbyChat)
+ {
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
{
- LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
- if (speaker_mgr)
- {
- speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE);
+ speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE);
}
-}
+ }
}
void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing)
@@ -1050,29 +1080,66 @@ void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing)
void LLIMFloater::processAgentListUpdates(const LLSD& body)
{
+ uuid_vec_t joined_uuids;
+
if (body.isMap() && body.has("agent_updates") && body["agent_updates"].isMap())
{
- LLSD agent_data = body["agent_updates"].get(gAgentID.asString());
- if (agent_data.isMap() && agent_data.has("info"))
+ LLSD::map_const_iterator update_it;
+ for(update_it = body["agent_updates"].beginMap();
+ update_it != body["agent_updates"].endMap();
+ ++update_it)
{
- LLSD agent_info = agent_data["info"];
+ LLUUID agent_id(update_it->first);
+ LLSD agent_data = update_it->second;
- if (agent_info.has("mutes"))
+ if (agent_data.isMap())
{
- BOOL moderator_muted_text = agent_info["mutes"]["text"].asBoolean();
- mInputEditor->setEnabled(!moderator_muted_text);
- std::string label;
- if (moderator_muted_text)
- label = LLTrans::getString("IM_muted_text_label");
- else
- label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID);
- mInputEditor->setLabel(label);
+ // store the new participants in joined_uuids
+ if (agent_data.has("transition") && agent_data["transition"].asString() == "ENTER")
+ {
+ joined_uuids.push_back(agent_id);
+ }
- if (moderator_muted_text)
- LLNotificationsUtil::add("TextChatIsMutedByModerator");
+ // process the moderator mutes
+ if (agent_id == gAgentID && agent_data.has("info") && agent_data["info"].has("mutes"))
+ {
+ BOOL moderator_muted_text = agent_data["info"]["mutes"]["text"].asBoolean();
+ mInputEditor->setEnabled(!moderator_muted_text);
+ std::string label;
+ if (moderator_muted_text)
+ label = LLTrans::getString("IM_muted_text_label");
+ else
+ label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID);
+ mInputEditor->setLabel(label);
+
+ if (moderator_muted_text)
+ LLNotificationsUtil::add("TextChatIsMutedByModerator");
+ }
}
}
}
+
+ // the vectors need to be sorted for computing the intersection and difference
+ std::sort(mInvitedParticipants.begin(), mInvitedParticipants.end());
+ std::sort(joined_uuids.begin(), joined_uuids.end());
+
+ uuid_vec_t intersection; // uuids of invited residents who have joined the conversation
+ std::set_intersection(mInvitedParticipants.begin(), mInvitedParticipants.end(),
+ joined_uuids.begin(), joined_uuids.end(),
+ std::back_inserter(intersection));
+
+ if (intersection.size() > 0)
+ {
+ sendParticipantsAddedNotification(intersection);
+ }
+
+ // Remove all joined participants from invited array.
+ // The difference between the two vectors (the elements in mInvitedParticipants which are not in joined_uuids)
+ // is placed at the beginning of mInvitedParticipants, then all other elements are erased.
+ mInvitedParticipants.erase(std::set_difference(mInvitedParticipants.begin(), mInvitedParticipants.end(),
+ joined_uuids.begin(), joined_uuids.end(),
+ mInvitedParticipants.begin()),
+ mInvitedParticipants.end());
}
void LLIMFloater::processSessionUpdate(const LLSD& session_update)
@@ -1110,19 +1177,19 @@ BOOL LLIMFloater::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
if (cargo_type == DAD_PERSON)
{
if (dropPerson(static_cast<LLUUID*>(cargo_data), drop))
- {
+ {
*accept = ACCEPT_YES_MULTI;
- }
+ }
else
- {
- *accept = ACCEPT_NO;
- }
+ {
+ *accept = ACCEPT_NO;
}
+ }
else if (mDialog == IM_NOTHING_SPECIAL)
- {
+ {
LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionID, drop,
cargo_type, cargo_data, accept);
- }
+ }
return TRUE;
}
@@ -1132,18 +1199,18 @@ bool LLIMFloater::dropPerson(LLUUID* person_id, bool drop)
bool res = person_id && person_id->notNull();
if(res)
{
- uuid_vec_t ids;
+ uuid_vec_t ids;
ids.push_back(*person_id);
res = canAddSelectedToChat(ids);
if(res && drop)
- {
+ {
addSessionParticipants(ids);
+ }
}
-}
return res;
- }
+}
BOOL LLIMFloater::isInviteAllowed() const
{
@@ -1177,37 +1244,32 @@ BOOL LLIMFloater::inviteToSession(const uuid_vec_t& ids)
if (is_region_exist)
{
- S32 count = ids.size();
-
- if( isInviteAllowed() && (count > 0) )
- {
- llinfos << "LLIMFloater::inviteToSession() - inviting participants" << llendl;
+ S32 count = ids.size();
- std::string url = region->getCapability("ChatSessionRequest");
+ if( isInviteAllowed() && (count > 0) )
+ {
+ llinfos << "LLIMFloater::inviteToSession() - inviting participants" << llendl;
- LLSD data;
+ std::string url = region->getCapability("ChatSessionRequest");
- data["params"] = LLSD::emptyArray();
- for (int i = 0; i < count; i++)
+ LLSD data;
+ data["params"] = LLSD::emptyArray();
+ for (int i = 0; i < count; i++)
+ {
+ data["params"].append(ids[i]);
+ }
+ data["method"] = "invite";
+ data["session-id"] = mSessionID;
+ LLHTTPClient::post(url, data,new LLSessionInviteResponder(mSessionID));
+ }
+ else
{
- data["params"].append(ids[i]);
+ llinfos << "LLIMFloater::inviteToSession -"
+ << " no need to invite agents for "
+ << mDialog << llendl;
+ // successful add, because everyone that needed to get added
+ // was added.
}
-
- data["method"] = "invite";
- data["session-id"] = mSessionID;
- LLHTTPClient::post(
- url,
- data,
- new LLSessionInviteResponder(mSessionID));
- }
- else
- {
- llinfos << "LLIMFloater::inviteToSession -"
- << " no need to invite agents for "
- << mDialog << llendl;
- // successful add, because everyone that needed to get added
- // was added.
- }
}
return is_region_exist;
@@ -1337,3 +1399,25 @@ 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 d528c77e8d..24a8f17feb 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -90,7 +90,8 @@ public:
void updateMessages();
void reloadMessages();
static void onSendMsg(LLUICtrl*, void*);
- void sendMsg();
+ void sendMsgFromInputEditor();
+ void sendMsg(const std::string& msg);
// callback for LLIMModel on new messages
// route to specific floater if it is visible
@@ -162,6 +163,8 @@ private:
void setTyping(bool typing);
void onAddButtonClicked();
void addSessionParticipants(const uuid_vec_t& uuids);
+ void addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids);
+ void sendParticipantsAddedNotification(const uuid_vec_t& uuids);
bool canAddSelectedToChat(const uuid_vec_t& uuids);
void onCallButtonClicked();
@@ -202,6 +205,8 @@ private:
bool mStartConferenceInSameFloater;
+ uuid_vec_t mInvitedParticipants;
+
// connection to voice channel state change signal
boost::signals2::connection mVoiceChannelStateChangeConnection;
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 37aa8bb787..d6d48130ab 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -31,6 +31,12 @@
<floater.string
name="return_icon"
value="Conv_toolbar_arrow_sw"/>
+ <floater.string
+ name="participant_added"
+ value="[NAME] was invited to the conversation."/>
+ <floater.string
+ name="multiple_participants_added"
+ value="[NAME] were invited to the conversation."/>
<view
follows="all"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 6df02a25af..64db7cd969 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4986,6 +4986,20 @@ Go to your [http://secondlife.com/account/ Dashboard] to see your account histor
<notification
icon="alertmodal.tga"
+ name="ConfirmAddingChatParticipants"
+ type="alertmodal">
+ <unique/>
+When you add a person to an existing conversation, a new conversation will be created. All participants will receive new conversation notifications.
+ <tag>confirm</tag>
+ <usetemplate
+ ignoretext="Confirm adding chat paticipants"
+ name="okcancelignore"
+ notext="Cancel"
+ yestext="Ok"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="ConfirmQuit"
type="alertmodal">
<unique/>