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, gSavedSettings.getColor4("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); }
// // LLFloaterIMPanel // LLFloaterIMPanel::LLFloaterIMPanel( const std::string& log_label, const LLUUID& session_id, const LLUUID& other_participant_id, const EInstantMessage& dialog, const LLDynamicArray<LLUUID>& ids) : LLFloater(log_label, LLRect(), log_label), mStartCallOnInitialize(false), mInputEditor(NULL), mHistoryEditor(NULL), mSessionInitialized(false), mSessionStartMsgPos(0), mSessionType(P2P_SESSION), mSessionUUID(session_id), mLogLabel(log_label), mQueuedMsgsForInit(), mOtherParticipantUUID(other_participant_id), mDialog(dialog), mTyping(false), mTypingLineStartIndex(0), mOtherTyping(false), mOtherTypingName(), mNumUnreadMessages(0), mSentTypingState(true), mShowSpeakersOnConnect(true), mDing(false), mRPMode(false), mTextIMPossible(true), mCallBackEnabled(true), mSpeakers(NULL), mSpeakerPanel(NULL), mVoiceChannel(NULL), mFirstKeystrokeTimer(), mLastKeystrokeTimer() { if (mOtherParticipantUUID.isNull()) { llwarns << "Other participant is NULL" << llendl; } // set P2P type by default static LLCachedControl<bool> concise_im("UseConciseIMButtons"); std::string xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml"; switch(mDialog) { case IM_SESSION_GROUP_START: case IM_SESSION_INVITE: case IM_SESSION_CONFERENCE_START: mCommitCallbackRegistrar.add("FlipDing", boost::bind<void>(boost::lambda::_1 = !boost::lambda::_1, boost::ref(mDing))); // determine whether it is group or conference session if (gAgent.isInGroup(mSessionUUID)) { static LLCachedControl<bool> concise("UseConciseGroupChatButtons"); xml_filename = concise ? "floater_instant_message_group_concisebuttons.xml" : "floater_instant_message_group.xml"; mSessionType = GROUP_SESSION; } else { static LLCachedControl<bool> concise("UseConciseConferenceButtons"); xml_filename = concise ? "floater_instant_message_ad_hoc_concisebuttons.xml" : "floater_instant_message_ad_hoc.xml"; mSessionType = ADHOC_SESSION; } mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mLogLabel); break; // just received text from another user case IM_NOTHING_SPECIAL: mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); // fallthrough case IM_SESSION_P2P_INVITE: mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mLogLabel, mOtherParticipantUUID); LLAvatarTracker::instance().addParticularFriendObserver(mOtherParticipantUUID, this); break; default: llwarns << "Unknown session type" << llendl; break; } mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, &getFactoryMap(), FALSE); // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { LLLogChat::loadHistory(mLogLabel, &chatFromLogFile, (void *)this); } if ( !mSessionInitialized ) { if ( !send_start_session_messages( mSessionUUID, mOtherParticipantUUID, ids, mDialog) ) { //we don't need to need to wait for any responses //so we're already initialized mSessionInitialized = true; } else { //locally echo a little "starting session" message LLUIString session_start = sSessionStartString; session_start.setArg("[NAME]", getTitle()); mSessionStartMsgPos = mHistoryEditor->getWText().length(); addHistoryLine( session_start, gSavedSettings.getColor4("SystemChatColor"), false); } } }
// Singu Note: LLFloaterIMSession::sendMsg void LLFloaterIMPanel::onSendMsg() { if (!gAgent.isGodlike() && (mSessionType == P2P_SESSION) && mOtherParticipantUUID.isNull()) { llinfos << "Cannot send IM to everyone unless you're a god." << llendl; 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); bool action = convert_roleplay_text(utf8_text); if (!action && mRPMode) utf8_text = "((" + utf8_text + "))"; // [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) ) { bool fRlvFilter = false; switch (mSessionType) { case P2P_SESSION: // One-on-one IM fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID); break; case GROUP_SESSION: // Group chat fRlvFilter = !RlvActions::canSendIM(mSessionUUID); break; case ADHOC_SESSION: // Conference chat: allow if all participants can be sent an IM { if (!mSpeakers) { fRlvFilter = true; break; } LLSpeakerMgr::speaker_list_t speakers; mSpeakers->getSpeakerList(&speakers, TRUE); for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); itSpeaker != speakers.end(); ++itSpeaker) { const LLSpeaker* pSpeaker = *itSpeaker; if ( (gAgentID != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) ) { fRlvFilter = true; break; } } } break; default: fRlvFilter = true; break; } if (fRlvFilter) { utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM); } } // [/RLVa:KB] if ( mSessionInitialized ) { // Split messages that are too long, same code like in llimpanel.cpp U32 split = MAX_MSG_BUF_SIZE - 1; U32 pos = 0; U32 total = utf8_text.length(); while (pos < total) { U32 next_split = split; if (pos + next_split > total) { next_split = total - pos; } else { // don't split utf-8 bytes while (U8(utf8_text[pos + next_split]) != 0x20 // space && U8(utf8_text[pos + next_split]) != 0x21 // ! && U8(utf8_text[pos + next_split]) != 0x2C // , && U8(utf8_text[pos + next_split]) != 0x2E // . && U8(utf8_text[pos + next_split]) != 0x3F // ? && next_split > 0) { --next_split; } if (next_split == 0) { next_split = split; LL_WARNS("Splitting") << "utf-8 couldn't be split correctly" << LL_ENDL; } else { ++next_split; } } std::string send = utf8_text.substr(pos, next_split); pos += next_split; LL_DEBUGS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_ENDL; deliver_message(send, mSessionUUID, mOtherParticipantUUID, mDialog); } // local echo if((mSessionType == P2P_SESSION) && (mOtherParticipantUUID.notNull())) { std::string name; gAgent.buildFullname(name); // Look for actions here. if (action) { utf8_text.replace(0,3,""); } else { utf8_text.insert(0, ": "); } bool other_was_typing = mOtherTyping; addHistoryLine(utf8_text, gSavedSettings.getColor("UserChatColor"), true, gAgentID, name); if (other_was_typing) addTypingIndicator(mOtherTypingName); } } 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; }
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: llwarns << "Unknown session type" << llendl; xml_filename = "floater_instant_message.xml"; break; } LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); setTitle(mSessionLabel); mInputEditor->setMaxTextLength(1023); // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); //*TODO we probably need the same "awaiting message" thing in LLIMFloater 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); } }