diff options
Diffstat (limited to 'indra/newview/llimpanel.cpp')
-rw-r--r-- | indra/newview/llimpanel.cpp | 1352 |
1 files changed, 676 insertions, 676 deletions
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index c194dc05b0..3de18ba92f 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llimpanel.cpp * @brief LLIMPanel class definition * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -97,881 +97,881 @@ static std::string sSessionStartString = "Starting session with [NAME] please wa // LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, - const LLUUID& session_id, - const LLUUID& other_participant_id, - const std::vector<LLUUID>& ids, - EInstantMessage dialog) -: LLFloater(session_id), - mInputEditor(NULL), - mHistoryEditor(NULL), - mSessionUUID(session_id), - mSessionLabel(session_label), - mSessionInitialized(FALSE), - mSessionStartMsgPos(0), - mOtherParticipantUUID(other_participant_id), - mDialog(dialog), - mSessionInitialTargetIDs(ids), - mTyping(FALSE), - mOtherTyping(FALSE), - mTypingLineStartIndex(0), - mSentTypingState(TRUE), - mNumUnreadMessages(0), - mShowSpeakersOnConnect(TRUE), - mTextIMPossible(TRUE), - mProfileButtonEnabled(TRUE), - mCallBackEnabled(TRUE), - mSpeakerPanel(NULL), - mFirstKeystrokeTimer(), - mLastKeystrokeTimer() -{ - std::string xml_filename; - switch(mDialog) - { - case IM_SESSION_GROUP_START: - mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); - xml_filename = "floater_instant_message_group.xml"; - break; - case IM_SESSION_INVITE: - mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); - if (gAgent.isInGroup(mSessionUUID)) - { - xml_filename = "floater_instant_message_group.xml"; - } - else // must be invite to ad hoc IM - { - xml_filename = "floater_instant_message_ad_hoc.xml"; - } - break; - case IM_SESSION_P2P_INVITE: - xml_filename = "floater_instant_message.xml"; - break; - case IM_SESSION_CONFERENCE_START: - mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); - xml_filename = "floater_instant_message_ad_hoc.xml"; - break; - // just received text from another user - case IM_NOTHING_SPECIAL: - - xml_filename = "floater_instant_message.xml"; - - mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); - mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID); - mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); - break; - default: - LL_WARNS() << "Unknown session type" << LL_ENDL; - xml_filename = "floater_instant_message.xml"; - break; - } - - LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); - - setTitle(mSessionLabel); - mInputEditor->setMaxTextLength(DB_IM_MSG_STR_LEN); - // enable line history support for instant message bar - mInputEditor->setEnableLineHistory(TRUE); - - //*TODO we probably need the same "awaiting message" thing in LLFloaterIMSession - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(mSessionUUID); - if (!im_session) - { - llerror("im session with id " + mSessionUUID.asString() + " does not exist!", 0); - return; - } - - mSessionInitialized = im_session->mSessionInitialized; - if (!mSessionInitialized) - { - //locally echo a little "starting session" message - LLUIString session_start = sSessionStartString; - - session_start.setArg("[NAME]", getTitle()); - mSessionStartMsgPos = - mHistoryEditor->getWText().length(); - - addHistoryLine( - session_start, - LLUIColorTable::instance().getColor("SystemChatColor"), - false); - } + const LLUUID& session_id, + const LLUUID& other_participant_id, + const std::vector<LLUUID>& ids, + EInstantMessage dialog) +: LLFloater(session_id), + mInputEditor(NULL), + mHistoryEditor(NULL), + mSessionUUID(session_id), + mSessionLabel(session_label), + mSessionInitialized(FALSE), + mSessionStartMsgPos(0), + mOtherParticipantUUID(other_participant_id), + mDialog(dialog), + mSessionInitialTargetIDs(ids), + mTyping(FALSE), + mOtherTyping(FALSE), + mTypingLineStartIndex(0), + mSentTypingState(TRUE), + mNumUnreadMessages(0), + mShowSpeakersOnConnect(TRUE), + mTextIMPossible(TRUE), + mProfileButtonEnabled(TRUE), + mCallBackEnabled(TRUE), + mSpeakerPanel(NULL), + mFirstKeystrokeTimer(), + mLastKeystrokeTimer() +{ + std::string xml_filename; + switch(mDialog) + { + case IM_SESSION_GROUP_START: + mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); + xml_filename = "floater_instant_message_group.xml"; + break; + case IM_SESSION_INVITE: + mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); + if (gAgent.isInGroup(mSessionUUID)) + { + xml_filename = "floater_instant_message_group.xml"; + } + else // must be invite to ad hoc IM + { + xml_filename = "floater_instant_message_ad_hoc.xml"; + } + break; + case IM_SESSION_P2P_INVITE: + xml_filename = "floater_instant_message.xml"; + break; + case IM_SESSION_CONFERENCE_START: + mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); + xml_filename = "floater_instant_message_ad_hoc.xml"; + break; + // just received text from another user + case IM_NOTHING_SPECIAL: + + xml_filename = "floater_instant_message.xml"; + + mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); + mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID); + mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); + break; + default: + LL_WARNS() << "Unknown session type" << LL_ENDL; + xml_filename = "floater_instant_message.xml"; + break; + } + + LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); + + setTitle(mSessionLabel); + mInputEditor->setMaxTextLength(DB_IM_MSG_STR_LEN); + // enable line history support for instant message bar + mInputEditor->setEnableLineHistory(TRUE); + + //*TODO we probably need the same "awaiting message" thing in LLFloaterIMSession + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(mSessionUUID); + if (!im_session) + { + llerror("im session with id " + mSessionUUID.asString() + " does not exist!", 0); + return; + } + + mSessionInitialized = im_session->mSessionInitialized; + if (!mSessionInitialized) + { + //locally echo a little "starting session" message + LLUIString session_start = sSessionStartString; + + session_start.setArg("[NAME]", getTitle()); + mSessionStartMsgPos = + mHistoryEditor->getWText().length(); + + addHistoryLine( + session_start, + LLUIColorTable::instance().getColor("SystemChatColor"), + false); + } } LLFloaterIMPanel::~LLFloaterIMPanel() { - //delete focus lost callback - mFocusCallbackConnection.disconnect(); + //delete focus lost callback + mFocusCallbackConnection.disconnect(); } -BOOL LLFloaterIMPanel::postBuild() +BOOL LLFloaterIMPanel::postBuild() { - setVisibleCallback(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); - - mInputEditor = getChild<LLLineEditor>("chat_editor"); - mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); - mFocusCallbackConnection = mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this)); - mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); - mInputEditor->setCommitCallback( onCommitChat, this ); - mInputEditor->setCommitOnFocusLost( FALSE ); - mInputEditor->setRevertOnEsc( FALSE ); - mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); + setVisibleCallback(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); + + mInputEditor = getChild<LLLineEditor>("chat_editor"); + mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) ); + mFocusCallbackConnection = mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this)); + mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); + mInputEditor->setCommitCallback( onCommitChat, this ); + mInputEditor->setCommitOnFocusLost( FALSE ); + mInputEditor->setRevertOnEsc( FALSE ); + mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); - childSetAction("profile_callee_btn", onClickProfile, this); - childSetAction("group_info_btn", onClickGroupInfo, this); + childSetAction("profile_callee_btn", onClickProfile, this); + childSetAction("group_info_btn", onClickGroupInfo, this); - childSetAction("start_call_btn", onClickStartCall, this); - childSetAction("end_call_btn", onClickEndCall, this); - childSetAction("send_btn", onClickSend, this); - childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); + childSetAction("start_call_btn", onClickStartCall, this); + childSetAction("end_call_btn", onClickEndCall, this); + childSetAction("send_btn", onClickSend, this); + childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); - childSetAction("moderator_kick_speaker", onKickSpeaker, this); - //LLButton* close_btn = getChild<LLButton>("close_btn"); - //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this); + childSetAction("moderator_kick_speaker", onKickSpeaker, this); + //LLButton* close_btn = getChild<LLButton>("close_btn"); + //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this); - mHistoryEditor = getChild<LLViewerTextEditor>("im_history"); + mHistoryEditor = getChild<LLViewerTextEditor>("im_history"); - if ( IM_SESSION_GROUP_START == mDialog ) - { - childSetEnabled("profile_btn", FALSE); - } - - if(!mProfileButtonEnabled) - { - childSetEnabled("profile_callee_btn", FALSE); - } + if ( IM_SESSION_GROUP_START == mDialog ) + { + childSetEnabled("profile_btn", FALSE); + } - sTitleString = getString("title_string"); - sTypingStartString = getString("typing_start_string"); - sSessionStartString = getString("session_start_string"); + if(!mProfileButtonEnabled) + { + childSetEnabled("profile_callee_btn", FALSE); + } - if (mSpeakerPanel) - { - mSpeakerPanel->refreshSpeakers(); - } + sTitleString = getString("title_string"); + sTypingStartString = getString("typing_start_string"); + sSessionStartString = getString("session_start_string"); - if (mDialog == IM_NOTHING_SPECIAL) - { - childSetAction("mute_btn", onClickMuteVoice, this); - childSetCommitCallback("speaker_volume", onVolumeChange, this); - } + if (mSpeakerPanel) + { + mSpeakerPanel->refreshSpeakers(); + } - setDefaultBtn("send_btn"); - return TRUE; + if (mDialog == IM_NOTHING_SPECIAL) + { + childSetAction("mute_btn", onClickMuteVoice, this); + childSetCommitCallback("speaker_volume", onVolumeChange, this); + } + + setDefaultBtn("send_btn"); + return TRUE; } void* LLFloaterIMPanel::createSpeakersPanel(void* data) { - LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data; - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(floaterp->mSessionUUID); - floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(speaker_mgr, TRUE); - return floaterp->mSpeakerPanel; + LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data; + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(floaterp->mSessionUUID); + floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(speaker_mgr, TRUE); + return floaterp->mSpeakerPanel; } -//static +//static void LLFloaterIMPanel::onClickMuteVoice(void* user_data) { - LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; - if (floaterp) - { - BOOL is_muted = LLMuteList::getInstance()->isMuted(floaterp->mOtherParticipantUUID, LLMute::flagVoiceChat); + LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; + if (floaterp) + { + BOOL is_muted = LLMuteList::getInstance()->isMuted(floaterp->mOtherParticipantUUID, LLMute::flagVoiceChat); - LLMute mute(floaterp->mOtherParticipantUUID, floaterp->getTitle(), LLMute::AGENT); - if (!is_muted) - { - LLMuteList::getInstance()->add(mute, LLMute::flagVoiceChat); - } - else - { - LLMuteList::getInstance()->remove(mute, LLMute::flagVoiceChat); - } - } + LLMute mute(floaterp->mOtherParticipantUUID, floaterp->getTitle(), LLMute::AGENT); + if (!is_muted) + { + LLMuteList::getInstance()->add(mute, LLMute::flagVoiceChat); + } + else + { + LLMuteList::getInstance()->remove(mute, LLMute::flagVoiceChat); + } + } } -//static +//static void LLFloaterIMPanel::onVolumeChange(LLUICtrl* source, void* user_data) { - LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; - if (floaterp) - { - LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal()); - } + LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)user_data; + if (floaterp) + { + LLVoiceClient::getInstance()->setUserVolume(floaterp->mOtherParticipantUUID, (F32)source->getValue().asReal()); + } } // virtual void LLFloaterIMPanel::draw() -{ - LLViewerRegion* region = gAgent.getRegion(); - - BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") - && mSessionInitialized - && LLVoiceClient::getInstance()->voiceEnabled() - && mCallBackEnabled; - - // hide/show start call and end call buttons - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); - if (!voice_channel) - return; - - childSetVisible("end_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); - childSetVisible("start_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); - childSetEnabled("start_call_btn", enable_connect); - childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); - - LLPointer<LLSpeaker> self_speaker; - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); - if (speaker_mgr) - { - self_speaker = speaker_mgr->findSpeaker(gAgent.getID()); - } - if(!mTextIMPossible) - { - mInputEditor->setEnabled(FALSE); - mInputEditor->setLabel(getString("unavailable_text_label")); - } - else if (self_speaker.notNull() && self_speaker->mModeratorMutedText) - { - mInputEditor->setEnabled(FALSE); - mInputEditor->setLabel(getString("muted_text_label")); - } - else - { - mInputEditor->setEnabled(TRUE); - mInputEditor->setLabel(getString("default_text_label")); - } - - // show speakers window when voice first connects - if (mShowSpeakersOnConnect && voice_channel->isActive()) - { - childSetVisible("active_speakers_panel", TRUE); - mShowSpeakersOnConnect = FALSE; - } - childSetValue("toggle_active_speakers_btn", childIsVisible("active_speakers_panel")); - - if (mTyping) - { - // Time out if user hasn't typed for a while. - if (mLastKeystrokeTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS) - { - setTyping(FALSE); - } - - // If we are typing, and it's been a little while, send the - // typing indicator - if (!mSentTypingState - && mFirstKeystrokeTimer.getElapsedTimeF32() > 1.f) - { - sendTypingState(TRUE); - mSentTypingState = TRUE; - } - } - - // use embedded panel if available - if (mSpeakerPanel) - { - if (mSpeakerPanel->getVisible()) - { - mSpeakerPanel->refreshSpeakers(); - } - } - else - { - // refresh volume and mute checkbox - childSetVisible("speaker_volume", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); - childSetValue("speaker_volume", LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID)); - - childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); - childSetVisible("mute_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); - } - LLFloater::draw(); +{ + LLViewerRegion* region = gAgent.getRegion(); + + BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") + && mSessionInitialized + && LLVoiceClient::getInstance()->voiceEnabled() + && mCallBackEnabled; + + // hide/show start call and end call buttons + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + if (!voice_channel) + return; + + childSetVisible("end_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); + childSetVisible("start_call_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); + childSetEnabled("start_call_btn", enable_connect); + childSetEnabled("send_btn", !childGetValue("chat_editor").asString().empty()); + + LLPointer<LLSpeaker> self_speaker; + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); + if (speaker_mgr) + { + self_speaker = speaker_mgr->findSpeaker(gAgent.getID()); + } + if(!mTextIMPossible) + { + mInputEditor->setEnabled(FALSE); + mInputEditor->setLabel(getString("unavailable_text_label")); + } + else if (self_speaker.notNull() && self_speaker->mModeratorMutedText) + { + mInputEditor->setEnabled(FALSE); + mInputEditor->setLabel(getString("muted_text_label")); + } + else + { + mInputEditor->setEnabled(TRUE); + mInputEditor->setLabel(getString("default_text_label")); + } + + // show speakers window when voice first connects + if (mShowSpeakersOnConnect && voice_channel->isActive()) + { + childSetVisible("active_speakers_panel", TRUE); + mShowSpeakersOnConnect = FALSE; + } + childSetValue("toggle_active_speakers_btn", childIsVisible("active_speakers_panel")); + + if (mTyping) + { + // Time out if user hasn't typed for a while. + if (mLastKeystrokeTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS) + { + setTyping(FALSE); + } + + // If we are typing, and it's been a little while, send the + // typing indicator + if (!mSentTypingState + && mFirstKeystrokeTimer.getElapsedTimeF32() > 1.f) + { + sendTypingState(TRUE); + mSentTypingState = TRUE; + } + } + + // use embedded panel if available + if (mSpeakerPanel) + { + if (mSpeakerPanel->getVisible()) + { + mSpeakerPanel->refreshSpeakers(); + } + } + else + { + // refresh volume and mute checkbox + childSetVisible("speaker_volume", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); + childSetValue("speaker_volume", LLVoiceClient::getInstance()->getUserVolume(mOtherParticipantUUID)); + + childSetValue("mute_btn", LLMuteList::getInstance()->isMuted(mOtherParticipantUUID, LLMute::flagVoiceChat)); + childSetVisible("mute_btn", LLVoiceClient::getInstance()->voiceEnabled() && voice_channel->isActive()); + } + LLFloater::draw(); } class LLSessionInviteResponder : public LLHTTPClient::Responder { - LOG_CLASS(LLSessionInviteResponder); + LOG_CLASS(LLSessionInviteResponder); public: - LLSessionInviteResponder(const LLUUID& session_id) - { - mSessionID = session_id; - } + LLSessionInviteResponder(const LLUUID& session_id) + { + mSessionID = session_id; + } protected: - void httpFailure() - { - LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; - //throw something back to the viewer here? - } + void httpFailure() + { + LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; + //throw something back to the viewer here? + } private: - LLUUID mSessionID; + LLUUID mSessionID; }; BOOL LLFloaterIMPanel::inviteToSession(const std::vector<LLUUID>& ids) { - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - { - return FALSE; - } - - S32 count = ids.size(); - - if( isInviteAllowed() && (count > 0) ) - { - LL_INFOS() << "LLFloaterIMPanel::inviteToSession() - inviting participants" << LL_ENDL; - - std::string url = region->getCapability("ChatSessionRequest"); - - LLSD data; - - data["params"] = LLSD::emptyArray(); - for (int i = 0; i < count; i++) - { - data["params"].append(ids[i]); - } - - data["method"] = "invite"; - data["session-id"] = mSessionUUID; - LLHTTPClient::post( - url, - data, - new LLSessionInviteResponder( - mSessionUUID)); - } - else - { - LL_INFOS() << "LLFloaterIMPanel::inviteToSession -" - << " no need to invite agents for " - << mDialog << LL_ENDL; - // successful add, because everyone that needed to get added - // was added. - } - - return TRUE; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + return FALSE; + } + + S32 count = ids.size(); + + if( isInviteAllowed() && (count > 0) ) + { + LL_INFOS() << "LLFloaterIMPanel::inviteToSession() - inviting participants" << LL_ENDL; + + std::string url = region->getCapability("ChatSessionRequest"); + + LLSD data; + + data["params"] = LLSD::emptyArray(); + for (int i = 0; i < count; i++) + { + data["params"].append(ids[i]); + } + + data["method"] = "invite"; + data["session-id"] = mSessionUUID; + LLHTTPClient::post( + url, + data, + new LLSessionInviteResponder( + mSessionUUID)); + } + else + { + LL_INFOS() << "LLFloaterIMPanel::inviteToSession -" + << " no need to invite agents for " + << mDialog << LL_ENDL; + // successful add, because everyone that needed to get added + // was added. + } + + return TRUE; } void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4& color, bool log_to_file, const LLUUID& source, const std::string& name) { - // start tab flashing when receiving im for background session from user - if (source != LLUUID::null) - { - LLMultiFloater* hostp = getHost(); - if( !isInVisibleChain() - && hostp - && source != gAgent.getID()) - { - hostp->setFloaterFlashing(this, TRUE); - } - } - - // 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); - - // Actually add the line - std::string timestring; - bool prepend_newline = true; - if (gSavedSettings.getBOOL("IMShowTimestamps")) - { - timestring = mHistoryEditor->appendTime(prepend_newline); - prepend_newline = false; - } - - std::string separator_string(": "); - - // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. - if (!name.empty()) // If name exists, then add it to the front of the message. - { - // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. - if (name == SYSTEM_FROM) - { - mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyle::Params().color(color)); - } - else - { - // Convert the name to a hotlink and add to message. - mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyleMap::instance().lookupAgent(source)); - } - prepend_newline = false; - } - mHistoryEditor->appendText(utf8msg, prepend_newline, LLStyle::Params().color(color)); - mHistoryEditor->blockUndo(); - - if (!isInVisibleChain()) - { - mNumUnreadMessages++; - } + // start tab flashing when receiving im for background session from user + if (source != LLUUID::null) + { + LLMultiFloater* hostp = getHost(); + if( !isInVisibleChain() + && hostp + && source != gAgent.getID()) + { + hostp->setFloaterFlashing(this, TRUE); + } + } + + // 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); + + // Actually add the line + std::string timestring; + bool prepend_newline = true; + if (gSavedSettings.getBOOL("IMShowTimestamps")) + { + timestring = mHistoryEditor->appendTime(prepend_newline); + prepend_newline = false; + } + + std::string separator_string(": "); + + // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. + if (!name.empty()) // If name exists, then add it to the front of the message. + { + // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. + if (name == SYSTEM_FROM) + { + mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyle::Params().color(color)); + } + else + { + // Convert the name to a hotlink and add to message. + mHistoryEditor->appendText(name + separator_string, prepend_newline, LLStyleMap::instance().lookupAgent(source)); + } + prepend_newline = false; + } + mHistoryEditor->appendText(utf8msg, prepend_newline, LLStyle::Params().color(color)); + mHistoryEditor->blockUndo(); + + if (!isInVisibleChain()) + { + mNumUnreadMessages++; + } } void LLFloaterIMPanel::setInputFocus( BOOL b ) { - mInputEditor->setFocus( b ); + mInputEditor->setFocus( b ); } void LLFloaterIMPanel::selectAll() { - mInputEditor->selectAll(); + mInputEditor->selectAll(); } void LLFloaterIMPanel::selectNone() { - mInputEditor->deselect(); + mInputEditor->deselect(); } BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) { - BOOL handled = FALSE; - if( KEY_RETURN == key && mask == MASK_NONE) - { - sendMsg(); - handled = TRUE; - } - else if ( KEY_ESCAPE == key ) - { - handled = TRUE; - gFocusMgr.setKeyboardFocus(NULL); - } + BOOL handled = FALSE; + if( KEY_RETURN == key && mask == MASK_NONE) + { + sendMsg(); + handled = TRUE; + } + else if ( KEY_ESCAPE == key ) + { + handled = TRUE; + gFocusMgr.setKeyboardFocus(NULL); + } - // May need to call base class LLPanel::handleKeyHere if not handled - // in order to tab between buttons. JNC 1.2.2002 - return handled; + // May need to call base class LLPanel::handleKeyHere if not handled + // in order to tab between buttons. JNC 1.2.2002 + return handled; } BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - - if (mDialog == IM_NOTHING_SPECIAL) - { - LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionUUID, drop, - cargo_type, cargo_data, accept); - } - - // handle case for dropping calling cards (and folders of calling cards) onto invitation panel for invites - else if (isInviteAllowed()) - { - *accept = ACCEPT_NO; - - if (cargo_type == DAD_CALLINGCARD) - { - if (dropCallingCard((LLInventoryItem*)cargo_data, drop)) - { - *accept = ACCEPT_YES_MULTI; - } - } - else if (cargo_type == DAD_CATEGORY) - { - if (dropCategory((LLInventoryCategory*)cargo_data, drop)) - { - *accept = ACCEPT_YES_MULTI; - } - } - } - return TRUE; -} + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + + if (mDialog == IM_NOTHING_SPECIAL) + { + LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionUUID, drop, + cargo_type, cargo_data, accept); + } + + // handle case for dropping calling cards (and folders of calling cards) onto invitation panel for invites + else if (isInviteAllowed()) + { + *accept = ACCEPT_NO; + + if (cargo_type == DAD_CALLINGCARD) + { + if (dropCallingCard((LLInventoryItem*)cargo_data, drop)) + { + *accept = ACCEPT_YES_MULTI; + } + } + else if (cargo_type == DAD_CATEGORY) + { + if (dropCategory((LLInventoryCategory*)cargo_data, drop)) + { + *accept = ACCEPT_YES_MULTI; + } + } + } + return TRUE; +} BOOL LLFloaterIMPanel::dropCallingCard(LLInventoryItem* item, BOOL drop) { - BOOL rv = isInviteAllowed(); - if(rv && item && item->getCreatorUUID().notNull()) - { - if(drop) - { - std::vector<LLUUID> ids; - ids.push_back(item->getCreatorUUID()); - inviteToSession(ids); - } - } - else - { - // set to false if creator uuid is null. - rv = FALSE; - } - return rv; + BOOL rv = isInviteAllowed(); + if(rv && item && item->getCreatorUUID().notNull()) + { + if(drop) + { + std::vector<LLUUID> ids; + ids.push_back(item->getCreatorUUID()); + inviteToSession(ids); + } + } + else + { + // set to false if creator uuid is null. + rv = FALSE; + } + return rv; } BOOL LLFloaterIMPanel::dropCategory(LLInventoryCategory* category, BOOL drop) { - BOOL rv = isInviteAllowed(); - if(rv && category) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLUniqueBuddyCollector buddies; - gInventory.collectDescendentsIf(category->getUUID(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - buddies); - S32 count = items.count(); - if(count == 0) - { - rv = FALSE; - } - else if(drop) - { - std::vector<LLUUID> ids; - ids.reserve(count); - for(S32 i = 0; i < count; ++i) - { - ids.push_back(items.get(i)->getCreatorUUID()); - } - inviteToSession(ids); - } - } - return rv; + BOOL rv = isInviteAllowed(); + if(rv && category) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLUniqueBuddyCollector buddies; + gInventory.collectDescendentsIf(category->getUUID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + buddies); + S32 count = items.count(); + if(count == 0) + { + rv = FALSE; + } + else if(drop) + { + std::vector<LLUUID> ids; + ids.reserve(count); + for(S32 i = 0; i < count; ++i) + { + ids.push_back(items.get(i)->getCreatorUUID()); + } + inviteToSession(ids); + } + } + return rv; } BOOL LLFloaterIMPanel::isInviteAllowed() const { - return ( (IM_SESSION_CONFERENCE_START == mDialog) - || (IM_SESSION_INVITE == mDialog) ); + return ( (IM_SESSION_CONFERENCE_START == mDialog) + || (IM_SESSION_INVITE == mDialog) ); } // static void LLFloaterIMPanel::onTabClick(void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->setInputFocus(TRUE); + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + self->setInputFocus(TRUE); } // static void LLFloaterIMPanel::onClickProfile( void* userdata ) { - // Bring up the Profile window - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - - if (self->getOtherParticipantID().notNull()) - { - LLAvatarActions::showProfile(self->getOtherParticipantID()); - } + // Bring up the Profile window + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + + if (self->getOtherParticipantID().notNull()) + { + LLAvatarActions::showProfile(self->getOtherParticipantID()); + } } // static void LLFloaterIMPanel::onClickGroupInfo( void* userdata ) { - // Bring up the Profile window - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + // Bring up the Profile window + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - LLGroupActions::show(self->mSessionUUID); + LLGroupActions::show(self->mSessionUUID); } // static void LLFloaterIMPanel::onClickClose( void* userdata ) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - if(self) - { - self->closeFloater(); - } + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + if(self) + { + self->closeFloater(); + } } // static void LLFloaterIMPanel::onClickStartCall(void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - gIMMgr->startCall(self->mSessionUUID); + gIMMgr->startCall(self->mSessionUUID); } // static void LLFloaterIMPanel::onClickEndCall(void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - gIMMgr->endCall(self->mSessionUUID); + gIMMgr->endCall(self->mSessionUUID); } // static void LLFloaterIMPanel::onClickSend(void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; - self->sendMsg(); + LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; + self->sendMsg(); } // static void LLFloaterIMPanel::onClickToggleActiveSpeakers(void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; + LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; - self->childSetVisible("active_speakers_panel", !self->childIsVisible("active_speakers_panel")); + self->childSetVisible("active_speakers_panel", !self->childIsVisible("active_speakers_panel")); } // static void LLFloaterIMPanel::onCommitChat(LLUICtrl* caller, void* userdata) { - LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; - self->sendMsg(); + LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; + self->sendMsg(); } // static void LLFloaterIMPanel::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ) { - LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; - self->mHistoryEditor->setCursorAndScrollToEnd(); + LLFloaterIMPanel* self= (LLFloaterIMPanel*) userdata; + self->mHistoryEditor->setCursorAndScrollToEnd(); } // static void LLFloaterIMPanel::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->setTyping(FALSE); + LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + self->setTyping(FALSE); } // static void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller, void* userdata) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; - std::string text = self->mInputEditor->getText(); - if (!text.empty()) - { - self->setTyping(TRUE); - } - else - { - // Deleting all text counts as stopping typing. - self->setTyping(FALSE); - } + LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; + std::string text = self->mInputEditor->getText(); + if (!text.empty()) + { + self->setTyping(TRUE); + } + else + { + // Deleting all text counts as stopping typing. + self->setTyping(FALSE); + } } // virtual void LLFloaterIMPanel::onClose(bool app_quitting) { - setTyping(FALSE); + setTyping(FALSE); - gIMMgr->leaveSession(mSessionUUID); + gIMMgr->leaveSession(mSessionUUID); - // *HACK hide the voice floater - LLFloaterReg::hideInstance("voice_call", mSessionUUID); + // *HACK hide the voice floater + LLFloaterReg::hideInstance("voice_call", mSessionUUID); } void LLFloaterIMPanel::onVisibilityChange(const LLSD& new_visibility) { - if (new_visibility.asBoolean()) - { - mNumUnreadMessages = 0; - } - - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); - if (voice_channel && voice_channel->getState() == LLVoiceChannel::STATE_CONNECTED) - { - if (new_visibility.asBoolean()) - LLFloaterReg::showInstance("voice_call", mSessionUUID); - else - LLFloaterReg::hideInstance("voice_call", mSessionUUID); - } + if (new_visibility.asBoolean()) + { + mNumUnreadMessages = 0; + } + + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionUUID); + if (voice_channel && voice_channel->getState() == LLVoiceChannel::STATE_CONNECTED) + { + if (new_visibility.asBoolean()) + LLFloaterReg::showInstance("voice_call", mSessionUUID); + else + LLFloaterReg::hideInstance("voice_call", mSessionUUID); + } } void LLFloaterIMPanel::sendMsg() { - if (!gAgent.isGodlike() - && (mDialog == IM_NOTHING_SPECIAL) - && mOtherParticipantUUID.isNull()) - { - LL_INFOS() << "Cannot send IM to everyone unless you're a god." << LL_ENDL; - return; - } - - if (mInputEditor) - { - LLWString text = mInputEditor->getConvertedText(); - if(!text.empty()) - { - // store sent line in history, duplicates will get filtered - if (mInputEditor) mInputEditor->updateHistory(); - // 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, - mSessionUUID, - mOtherParticipantUUID, - mDialog); - - } - else - { - //queue up the message to send once the session is - //initialized - mQueuedMsgsForInit.append(utf8_text); - } - } - - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_IM_COUNT); - - mInputEditor->setText(LLStringUtil::null); - } - - // Don't need to actually send the typing stop message, the other - // client will infer it from receiving the message. - mTyping = FALSE; - mSentTypingState = TRUE; + if (!gAgent.isGodlike() + && (mDialog == IM_NOTHING_SPECIAL) + && mOtherParticipantUUID.isNull()) + { + LL_INFOS() << "Cannot send IM to everyone unless you're a god." << LL_ENDL; + return; + } + + if (mInputEditor) + { + LLWString text = mInputEditor->getConvertedText(); + if(!text.empty()) + { + // store sent line in history, duplicates will get filtered + if (mInputEditor) mInputEditor->updateHistory(); + // 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, + mSessionUUID, + mOtherParticipantUUID, + mDialog); + + } + else + { + //queue up the message to send once the session is + //initialized + mQueuedMsgsForInit.append(utf8_text); + } + } + + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_IM_COUNT); + + mInputEditor->setText(LLStringUtil::null); + } + + // Don't need to actually send the typing stop message, the other + // client will infer it from receiving the message. + mTyping = FALSE; + mSentTypingState = TRUE; } void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) { - if ( - session_update.has("moderated_mode") && - session_update["moderated_mode"].has("voice") ) - { - BOOL voice_moderated = session_update["moderated_mode"]["voice"]; + if ( + session_update.has("moderated_mode") && + session_update["moderated_mode"].has("voice") ) + { + BOOL voice_moderated = session_update["moderated_mode"]["voice"]; - if (voice_moderated) - { - setTitle(mSessionLabel + std::string(" ") + getString("moderated_chat_label")); - } - else - { - setTitle(mSessionLabel); - } + if (voice_moderated) + { + setTitle(mSessionLabel + std::string(" ") + getString("moderated_chat_label")); + } + else + { + setTitle(mSessionLabel); + } - //update the speakers dropdown too, if it's available - if (mSpeakerPanel) - { - mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); - } - } + //update the speakers dropdown too, if it's available + if (mSpeakerPanel) + { + mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); + } + } } void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) { - mSessionUUID = session_id; - mSessionInitialized = TRUE; - - //we assume the history editor hasn't moved at all since - //we added the starting session message - //so, we count how many characters to remove - S32 chars_to_remove = mHistoryEditor->getWText().length() - - mSessionStartMsgPos; - mHistoryEditor->removeTextFromEnd(chars_to_remove); - - //and now, send the queued msg - LLSD::array_iterator iter; - for ( iter = mQueuedMsgsForInit.beginArray(); - iter != mQueuedMsgsForInit.endArray(); - ++iter) - { - LLIMModel::sendMessage( - iter->asString(), - mSessionUUID, - mOtherParticipantUUID, - mDialog); - } + mSessionUUID = session_id; + mSessionInitialized = TRUE; + + //we assume the history editor hasn't moved at all since + //we added the starting session message + //so, we count how many characters to remove + S32 chars_to_remove = mHistoryEditor->getWText().length() - + mSessionStartMsgPos; + mHistoryEditor->removeTextFromEnd(chars_to_remove); + + //and now, send the queued msg + LLSD::array_iterator iter; + for ( iter = mQueuedMsgsForInit.beginArray(); + iter != mQueuedMsgsForInit.endArray(); + ++iter) + { + LLIMModel::sendMessage( + iter->asString(), + mSessionUUID, + mOtherParticipantUUID, + mDialog); + } } void LLFloaterIMPanel::setTyping(BOOL typing) { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); - if (typing) - { - // Every time you type something, reset this timer - mLastKeystrokeTimer.reset(); - - if (!mTyping) - { - // You just started typing. - mFirstKeystrokeTimer.reset(); - - // Will send typing state after a short delay. - mSentTypingState = FALSE; - } - - if (speaker_mgr) - speaker_mgr->setSpeakerTyping(gAgent.getID(), TRUE); - } - else - { - if (mTyping) - { - // you just stopped typing, send state immediately - sendTypingState(FALSE); - mSentTypingState = TRUE; - } - if (speaker_mgr) - speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); - } - - mTyping = typing; + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); + if (typing) + { + // Every time you type something, reset this timer + mLastKeystrokeTimer.reset(); + + if (!mTyping) + { + // You just started typing. + mFirstKeystrokeTimer.reset(); + + // Will send typing state after a short delay. + mSentTypingState = FALSE; + } + + if (speaker_mgr) + speaker_mgr->setSpeakerTyping(gAgent.getID(), TRUE); + } + else + { + if (mTyping) + { + // you just stopped typing, send state immediately + sendTypingState(FALSE); + mSentTypingState = TRUE; + } + if (speaker_mgr) + speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); + } + + mTyping = typing; } void LLFloaterIMPanel::sendTypingState(BOOL typing) { - // Don't want to send typing indicators to multiple people, potentially too - // much network traffic. Only send in person-to-person IMs. - if (mDialog != IM_NOTHING_SPECIAL) return; + // Don't want to send typing indicators to multiple people, potentially too + // much network traffic. Only send in person-to-person IMs. + if (mDialog != IM_NOTHING_SPECIAL) return; - LLIMModel::instance().sendTypingState(mSessionUUID, mOtherParticipantUUID, typing); + LLIMModel::instance().sendTypingState(mSessionUUID, mOtherParticipantUUID, typing); } void LLFloaterIMPanel::processIMTyping(const LLIMInfo* im_info, BOOL typing) { - if (typing) - { - // other user started typing - addTypingIndicator(im_info->mName); - } - else - { - // other user stopped typing - removeTypingIndicator(im_info); - } + if (typing) + { + // other user started typing + addTypingIndicator(im_info->mName); + } + else + { + // other user stopped typing + removeTypingIndicator(im_info); + } } void LLFloaterIMPanel::addTypingIndicator(const std::string &name) { - // we may have lost a "stop-typing" packet, don't add it twice - if (!mOtherTyping) - { - mTypingLineStartIndex = mHistoryEditor->getWText().length(); - LLUIString typing_start = sTypingStartString; - typing_start.setArg("[NAME]", name); - addHistoryLine(typing_start, LLUIColorTable::instance().getColor("SystemChatColor"), false); - mOtherTypingName = name; - mOtherTyping = 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); + // we may have lost a "stop-typing" packet, don't add it twice + if (!mOtherTyping) + { + mTypingLineStartIndex = mHistoryEditor->getWText().length(); + LLUIString typing_start = sTypingStartString; + typing_start.setArg("[NAME]", name); + addHistoryLine(typing_start, LLUIColorTable::instance().getColor("SystemChatColor"), false); + mOtherTypingName = name; + mOtherTyping = 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) { - 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) - { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); - if (speaker_mgr) - { - speaker_mgr->setSpeakerTyping(im_info->mFromID, FALSE); - } - } - } -} - -//static + 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) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionUUID); + if (speaker_mgr) + { + speaker_mgr->setSpeakerTyping(im_info->mFromID, FALSE); + } + } + } +} + +//static void LLFloaterIMPanel::onKickSpeaker(void* user_data) { |