/** * @file llparticipantlist.cpp * @brief LLParticipantList : model of a conversation session with added speaker events handling * * $LicenseInfo:firstyear=2009&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$ */ #include "llviewerprecompiledheaders.h" #include "llavatarnamecache.h" #include "llerror.h" #include "llimview.h" #include "llfloaterimcontainer.h" #include "llparticipantlist.h" #include "llspeakers.h" //LLParticipantList retrieves add, clear and remove events and updates view accordingly #if LL_MSVC #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally #endif LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLFolderViewModelInterface& root_view_model) : LLConversationItemSession(data_source->getSessionID(), root_view_model), mSpeakerMgr(data_source), mValidateSpeakerCallback(NULL) { mSpeakerAddListener = new SpeakerAddListener(*this); mSpeakerRemoveListener = new SpeakerRemoveListener(*this); mSpeakerClearListener = new SpeakerClearListener(*this); mSpeakerModeratorListener = new SpeakerModeratorUpdateListener(*this); mSpeakerUpdateListener = new SpeakerUpdateListener(*this); mSpeakerMuteListener = new SpeakerMuteListener(*this); mSpeakerMgr->addListener(mSpeakerAddListener, "add"); mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove"); mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator"); mSpeakerMgr->addListener(mSpeakerUpdateListener, "update_speaker"); setSessionID(mSpeakerMgr->getSessionID()); //Lets fill avatarList with existing speakers LLSpeakerMgr::speaker_list_t speaker_list; mSpeakerMgr->getSpeakerList(&speaker_list, true); for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) { const LLPointer<LLSpeaker>& speakerp = *it; addAvatarIDExceptAgent(speakerp->mID); if ( speakerp->mIsModerator ) { mModeratorList.insert(speakerp->mID); } else { mModeratorToRemoveList.insert(speakerp->mID); } } // Identify and store what kind of session we are LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(data_source->getSessionID()); if (im_session) { // By default, sessions that can't be identified as group or ad-hoc will be considered P2P (i.e. 1 on 1) mConvType = CONV_SESSION_1_ON_1; if (im_session->isAdHocSessionType()) { mConvType = CONV_SESSION_AD_HOC; } else if (im_session->isGroupSessionType()) { mConvType = CONV_SESSION_GROUP; } } else { // That's the only session that doesn't get listed in the LLIMModel as a session... mConvType = CONV_SESSION_NEARBY; } } LLParticipantList::~LLParticipantList() { } void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb) { mValidateSpeakerCallback = cb; } void LLParticipantList::update() { mSpeakerMgr->update(true); } bool LLParticipantList::onAddItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { LLUUID uu_id = event->getValue().asUUID(); if (mValidateSpeakerCallback && !mValidateSpeakerCallback(uu_id)) { return true; } addAvatarIDExceptAgent(uu_id); return true; } bool LLParticipantList::onRemoveItemEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { LLUUID avatar_id = event->getValue().asUUID(); removeParticipant(avatar_id); return true; } bool LLParticipantList::onClearListEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { clearParticipants(); return true; } bool LLParticipantList::onSpeakerUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { const LLSD& evt_data = event->getValue(); if ( evt_data.has("id") ) { LLUUID participant_id = evt_data["id"]; LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance(); if (im_box) { im_box->setTimeNow(mUUID,participant_id); } } return true; } bool LLParticipantList::onModeratorUpdateEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { const LLSD& evt_data = event->getValue(); if ( evt_data.has("id") && evt_data.has("is_moderator") ) { LLUUID id = evt_data["id"]; bool is_moderator = evt_data["is_moderator"]; if ( id.notNull() ) { if ( is_moderator ) mModeratorList.insert(id); else { std::set<LLUUID>::iterator it = mModeratorList.find (id); if ( it != mModeratorList.end () ) { mModeratorToRemoveList.insert(id); mModeratorList.erase(id); } } // *TODO : do we have to fire an event so that LLFloaterIMSessionTab::refreshConversation() gets called } } return true; } bool LLParticipantList::onSpeakerMuteEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { LLPointer<LLSpeaker> speakerp = (LLSpeaker*)event->getSource(); if (speakerp.isNull()) return false; // update UI on confirmation of moderator mutes if (event->getValue().asString() == "voice") { setParticipantIsMuted(speakerp->mID, speakerp->mModeratorMutedVoice); } return true; } void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) { // Do not add if already in there, is the session id (hence not an avatar) or excluded for some reason if (findParticipant(avatar_id) || (avatar_id == mUUID)) { return; } bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(avatar_id); LLConversationItemParticipant* participant = NULL; if (is_avatar) { // Create a participant view model instance LLAvatarName avatar_name; bool has_name = LLAvatarNameCache::get(avatar_id, &avatar_name); participant = new LLConversationItemParticipant(!has_name ? LLTrans::getString("AvatarNameWaiting") : avatar_name.getDisplayName() , avatar_id, mRootViewModel); participant->fetchAvatarName(); } else { std::string display_name = LLVoiceClient::getInstance()->getDisplayName(avatar_id); // Create a participant view model instance participant = new LLConversationItemParticipant(display_name.empty() ? LLTrans::getString("AvatarNameWaiting") : display_name, avatar_id, mRootViewModel); } // *TODO : Need to update the online/offline status of the participant // Hack for this: LLAvatarTracker::instance().isBuddyOnline(avatar_id)) // Add the participant model to the session's children list // This will post "add_participant" event addParticipant(participant); adjustParticipant(avatar_id); } static LLFastTimer::DeclareTimer FTM_FOLDERVIEW_TEST("add test avatar agents"); void LLParticipantList::adjustParticipant(const LLUUID& speaker_id) { LLPointer<LLSpeaker> speakerp = mSpeakerMgr->findSpeaker(speaker_id); if (speakerp.isNull()) return; // add listener to process moderation changes speakerp->addListener(mSpeakerMuteListener); } // // LLParticipantList::SpeakerAddListener // bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { /** * We need to filter speaking objects. These objects shouldn't appear in the list. * @see LLFloaterChat::addChat() in llviewermessage.cpp to get detailed call hierarchy */ const LLUUID& speaker_id = event->getValue().asUUID(); LLPointer<LLSpeaker> speaker = mParent.mSpeakerMgr->findSpeaker(speaker_id); if (speaker.isNull() || (speaker->mType == LLSpeaker::SPEAKER_OBJECT)) { return false; } return mParent.onAddItemEvent(event, userdata); } // // LLParticipantList::SpeakerRemoveListener // bool LLParticipantList::SpeakerRemoveListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { return mParent.onRemoveItemEvent(event, userdata); } // // LLParticipantList::SpeakerClearListener // bool LLParticipantList::SpeakerClearListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { return mParent.onClearListEvent(event, userdata); } // // LLParticipantList::SpeakerUpdateListener // bool LLParticipantList::SpeakerUpdateListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { return mParent.onSpeakerUpdateEvent(event, userdata); } // // LLParticipantList::SpeakerModeratorListener // bool LLParticipantList::SpeakerModeratorUpdateListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { return mParent.onModeratorUpdateEvent(event, userdata); } bool LLParticipantList::SpeakerMuteListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) { return mParent.onSpeakerMuteEvent(event, userdata); } //EOF