diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index c6234d00e..a42adc582 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -801,7 +801,7 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol // Now we're adding the actual line of text, so erase the // "Foo is typing..." text segment, and the optional timestamp // if it was present. JC - removeTypingIndicator(NULL); + removeTypingIndicator(source); // Actually add the line bool prepend_newline = true; @@ -1458,7 +1458,7 @@ void LLFloaterIMPanel::onSendMsg() bool other_was_typing = mOtherTyping; addHistoryLine(utf8_text, gSavedSettings.getColor("UserChatColor"), true, gAgentID, name); - if (other_was_typing) addTypingIndicator(mOtherTypingName); + if (other_was_typing) addTypingIndicator(mOtherParticipantUUID); } } else @@ -1588,53 +1588,84 @@ void LLFloaterIMPanel::sendTypingState(bool typing) } -void LLFloaterIMPanel::processIMTyping(const LLIMInfo* im_info, bool typing) +void LLFloaterIMPanel::processIMTyping(const LLUUID& from_id, BOOL typing) { if (typing) { // other user started typing - std::string name; - if (!LLAvatarNameCache::getNSName(im_info->mFromID, name)) name = im_info->mName; - addTypingIndicator(name); + addTypingIndicator(from_id); } else { // other user stopped typing - removeTypingIndicator(im_info); + removeTypingIndicator(from_id); } } -void LLFloaterIMPanel::addTypingIndicator(const std::string &name) +void LLFloaterIMPanel::addTypingIndicator(const LLUUID& from_id) { - // we may have lost a "stop-typing" packet, don't add it twice - if (!mOtherTyping) + // Singu TODO: Actually implement this? +/* Operation of " is typing" state machine: +Not Typing state: + + User types in P2P IM chat ... Send Start Typing, save Started time, + start Idle Timer (N seconds) go to Typing state + +Typing State: + + User enters a non-return character: if Now - Started > ME_TYPING_TIMEOUT, send + Start Typing, restart Idle Timer + User enters a return character: stop Idle Timer, send IM and Stop + Typing, go to Not Typing state + Idle Timer expires: send Stop Typing, go to Not Typing state + +The recipient has a complementary state machine in which a Start Typing +that is not followed by either an IM or another Start Typing within OTHER_TYPING_TIMEOUT +seconds switches the sender out of typing state. + +This has the nice quality of being self-healing for lost start/stop +messages while adding messages only for the (relatively rare) case of a +user who types a very long message (one that takes more than ME_TYPING_TIMEOUT seconds +to type). + +Note: OTHER_TYPING_TIMEOUT must be > ME_TYPING_TIMEOUT for proper operation of the state machine + +*/ + + // We may have lost a "stop-typing" packet, don't add it twice + if (from_id.notNull() && !mOtherTyping) { + mOtherTyping = true; + // Save im_info so that removeTypingIndicator can be properly called because a timeout has occurred + LLAvatarNameCache::getNSName(from_id, mOtherTypingName); + mTypingLineStartIndex = mHistoryEditor->getWText().length(); LLUIString typing_start = sTypingStartString; - typing_start.setArg("[NAME]", name); + typing_start.setArg("[NAME]", mOtherTypingName); addHistoryLine(typing_start, gSavedSettings.getColor4("SystemChatColor"), false); - mOtherTypingName = name; - mOtherTyping = true; + + // Update speaker + LLIMSpeakerMgr* speaker_mgr = mSpeakers; + if ( speaker_mgr ) + { + speaker_mgr->setSpeakerTyping(from_id, TRUE); + } } - // MBW -- XXX -- merge from release broke this (argument to this function changed from an LLIMInfo to a name) - // Richard will fix. -// mSpeakers->setSpeakerTyping(im_info->mFromID, TRUE); } - -void LLFloaterIMPanel::removeTypingIndicator(const LLIMInfo* im_info) +void LLFloaterIMPanel::removeTypingIndicator(const LLUUID& from_id) { if (mOtherTyping) { - // Must do this first, otherwise addHistoryLine calls us again. mOtherTyping = false; S32 chars_to_remove = mHistoryEditor->getWText().length() - mTypingLineStartIndex; mHistoryEditor->removeTextFromEnd(chars_to_remove); - if (im_info) + + if (from_id.notNull()) { - mSpeakers->setSpeakerTyping(im_info->mFromID, FALSE); + mSpeakers->setSpeakerTyping(from_id, FALSE); } } } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index a13918f9c..ba6273695 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -126,7 +126,7 @@ public: void sessionInitReplyReceived(const LLUUID& im_session_id); // Handle other participant in the session typing. - void processIMTyping(const LLIMInfo* im_info, bool typing); + void processIMTyping(const LLUUID& from_id, BOOL typing); static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); //show error statuses to the user @@ -177,10 +177,10 @@ private: void setTyping(bool typing); // Add the "User is typing..." indicator. - void addTypingIndicator(const std::string &name); + void addTypingIndicator(const LLUUID& from_id); // Remove the "User is typing..." indicator. - void removeTypingIndicator(const LLIMInfo* im_info); + void removeTypingIndicator(const LLUUID& from_id = LLUUID::null); void sendTypingState(bool typing); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 5f30bcf94..36e1ef95d 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -641,8 +641,7 @@ void LLIMProcessing::processNewMessage(const LLUUID& from_id, { RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); + gIMMgr->processIMTypingStop(from_id, dialog); } // [/RLVa:KB] else if (offline == IM_ONLINE @@ -918,16 +917,15 @@ void LLIMProcessing::processNewMessage(const LLUUID& from_id, autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); } } - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStart(im_info); + + gIMMgr->processIMTypingStart(from_id, dialog); script_msg_api(from_id.asString() + ", 4"); } break; case IM_TYPING_STOP: { - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); + gIMMgr->processIMTypingStop(from_id, dialog); script_msg_api(from_id.asString() + ", 5"); } break; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d56cf58c7..351cdaadf 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1138,23 +1138,23 @@ void LLIMMgr::noteMutedUsers(LLFloaterIMPanel* floater, } } -void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info) +void LLIMMgr::processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(im_info, TRUE); + processIMTypingCore(from_id, im_type, TRUE); } -void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info) +void LLIMMgr::processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(im_info, FALSE); + processIMTypingCore(from_id, im_type, FALSE); } -void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing) +void LLIMMgr::processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing) { - LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID); - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if (floater) + LLUUID session_id = computeSessionID(im_type, from_id); + LLFloaterIMPanel* im_floater = findFloaterBySession(session_id); + if (im_floater) { - floater->processIMTyping(im_info, typing); + im_floater->processIMTyping(from_id, typing); } } @@ -1275,10 +1275,10 @@ LLFloaterChatterBox* LLIMMgr::getFloater() return LLFloaterChatterBox::getInstance(LLSD()); } -class LLViewerChatterBoxSessionStartReply : public LLHTTPNode +class LLViewerChatterBoxSessionStartReply final : public LLHTTPNode { public: - virtual void describe(Description& desc) const + void describe(Description& desc) const override { desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); desc.postAPI(); @@ -1287,18 +1287,15 @@ public: desc.source(__FILE__, __LINE__); } - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLSD body; - LLUUID temp_session_id; LLUUID session_id; - bool success; - body = input["body"]; - success = body["success"].asBoolean(); - temp_session_id = body["temp_session_id"].asUUID(); + LLSD body = input["body"]; + bool success = body["success"].asBoolean(); + LLUUID temp_session_id = body["temp_session_id"].asUUID(); if ( success ) { @@ -1336,10 +1333,10 @@ public: } }; -class LLViewerChatterBoxSessionEventReply : public LLHTTPNode +class LLViewerChatterBoxSessionEventReply final : public LLHTTPNode { public: - virtual void describe(Description& desc) const + void describe(Description& desc) const override { desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); desc.postAPI(); @@ -1348,24 +1345,18 @@ public: desc.source(__FILE__, __LINE__); } - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLUUID session_id; - bool success; - LLSD body = input["body"]; - success = body["success"].asBoolean(); - session_id = body["session_id"].asUUID(); + bool success = body["success"].asBoolean(); + LLUUID session_id = body["session_id"].asUUID(); if ( !success ) { //throw an error dialog - LLFloaterIMPanel* floater = - gIMMgr->findFloaterBySession(session_id); - - if (floater) + if (auto* floater = gIMMgr->findFloaterBySession(session_id)) { floater->showSessionEventError( body["event"].asString(), @@ -1378,46 +1369,40 @@ public: class LLViewerForceCloseChatterBoxSession: public LLHTTPNode { public: - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLUUID session_id; - std::string reason; + LLUUID session_id = input["body"]["session_id"].asUUID(); + std::string reason = input["body"]["reason"].asString(); - session_id = input["body"]["session_id"].asUUID(); - reason = input["body"]["reason"].asString(); - - LLFloaterIMPanel* floater = - gIMMgr ->findFloaterBySession(session_id); - - if ( floater ) + if (auto* floater = gIMMgr ->findFloaterBySession(session_id)) { floater->showSessionForceClose(reason); } } }; -class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode +class LLViewerChatterBoxSessionAgentListUpdates final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr responder, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { const LLUUID& session_id = input["body"]["session_id"].asUUID(); gIMMgr->processAgentListUpdates(session_id, input["body"]); } }; -class LLViewerChatterBoxSessionUpdate : public LLHTTPNode +class LLViewerChatterBoxSessionUpdate final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr responder, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLUUID session_id = input["body"]["session_id"].asUUID(); LLFloaterIMPanel* im_floater = gIMMgr->findFloaterBySession(session_id); @@ -1445,14 +1430,14 @@ void leave_group_chat(const LLUUID& from_id, const LLUUID& session_id) gIMMgr->removeSession(session_id); } -class LLViewerChatterBoxInvitation : public LLHTTPNode +class LLViewerChatterBoxInvitation final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { //for backwards compatiblity reasons...we need to still //check for 'text' or 'voice' invitations...bleh @@ -1582,10 +1567,9 @@ public: LLFloaterChat::addChat(chat, TRUE, is_this_agent); //K now we want to accept the invitation - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - if ( url != "" ) + if (!url.empty()) { LLSD data; data["method"] = "accept invitation"; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index be10c57ff..4f0159c2f 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -42,7 +42,7 @@ class LLFloaterChatterBox; class LLFloaterIMPanel; -class LLIMMgr : public LLSingleton +class LLIMMgr final : public LLSingleton { public: enum EInvitationType @@ -121,8 +121,8 @@ public: void updateFloaterSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id); - void processIMTypingStart(const LLIMInfo* im_info); - void processIMTypingStop(const LLIMInfo* im_info); + void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); + void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); void clearNewIMNotification(); @@ -209,7 +209,7 @@ private: void noteOfflineUsers(LLFloaterIMPanel* panel, const uuid_vec_t& ids); void noteMutedUsers(LLFloaterIMPanel* panel, const uuid_vec_t& ids); - void processIMTypingCore(const LLIMInfo* im_info, BOOL typing); + void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); private: std::set > mFloaters;