diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5af83cf18..6e1128268 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -381,6 +381,7 @@ set(viewer_SOURCE_FILES llpanelvolume.cpp llpanelweb.cpp llparcelselection.cpp + llparticipantlist.cpp llpatchvertexarray.cpp llpathfindingcharacter.cpp llpathfindingcharacterlist.cpp @@ -884,6 +885,7 @@ set(viewer_HEADER_FILES llpanelvolume.h llpanelweb.h llparcelselection.h + llparticipantlist.h llpatchvertexarray.h llpathfindingcharacter.h llpathfindingcharacterlist.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 6cededf8d..6021f3676 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -77,6 +77,7 @@ #include "llviewerstats.h" #include "llviewerwindow.h" #include "llvoavatarself.h" +#include "llvoiceclient.h" #include "llworld.h" #include "llworldmap.h" #include "llworldmapmessage.h" @@ -85,11 +86,9 @@ #include "llurldispatcher.h" #include "llimview.h" //For gIMMgr //Floaters -#include "llfloateractivespeakers.h" #include "llfloateravatarinfo.h" #include "llfloaterchat.h" #include "llfloaterdirectory.h" -#include "llfloatergroupinfo.h" #include "llfloatergroups.h" #include "llfloaterland.h" #include "llfloatermap.h" diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 62023fce2..6bfbad3bf 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -510,6 +510,26 @@ void LLAvatarActions::toggleBlock(const LLUUID& id) } } +// static +void LLAvatarActions::toggleMuteVoice(const LLUUID& id) +{ + std::string name; + gCacheName->getFullName(id, name); // needed for mute + + LLMuteList* mute_list = LLMuteList::getInstance(); + bool is_muted = mute_list->isMuted(id, LLMute::flagVoiceChat); + + LLMute mute(id, name, LLMute::AGENT); + if (!is_muted) + { + mute_list->add(mute, LLMute::flagVoiceChat); + } + else + { + mute_list->remove(mute, LLMute::flagVoiceChat); + } +} + // static bool LLAvatarActions::canOfferTeleport(const LLUUID& id) { @@ -724,6 +744,12 @@ bool LLAvatarActions::isBlocked(const LLUUID& id) return LLMuteList::getInstance()->isMuted(id); } +// static +bool LLAvatarActions::isVoiceMuted(const LLUUID& id) +{ + return LLMuteList::getInstance()->isMuted(id, LLMute::flagVoiceChat); +} + // static bool LLAvatarActions::canBlock(const LLUUID& id) { diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 0fc76f3e4..64511e60e 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -104,6 +104,11 @@ public: */ static void toggleBlock(const LLUUID& id); + /** + * Block/unblock the avatar voice. + */ + static void toggleMuteVoice(const LLUUID& id); + /** * Return true if avatar with "id" is a friend */ @@ -114,6 +119,11 @@ public: */ static bool isBlocked(const LLUUID& id); + /** + * @return true if the avatar voice is blocked + */ + static bool isVoiceMuted(const LLUUID& id); + /** * @return true if you can block the avatar */ @@ -185,4 +195,3 @@ public: }; #endif // LL_LLAVATARACTIONS_H - diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index ad66838d1..7d9706ad4 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -33,30 +33,9 @@ #include "llfloateractivespeakers.h" -#include "llagent.h" -#include "llavataractions.h" -#include "llbutton.h" -#include "llmutelist.h" -#include "llscrolllistctrl.h" +#include "llparticipantlist.h" #include "llspeakers.h" -#include "lltextbox.h" #include "lluictrlfactory.h" -#include "llviewerobjectlist.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llworld.h" - -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - -using namespace LLOldEvents; - -const F32 RESORT_TIMEOUT = 5.f; // seconds of mouse inactivity before it's ok to sort regardless of mouse-in-view. - -// -// LLFloaterActiveSpeakers -// LLFloaterActiveSpeakers::LLFloaterActiveSpeakers(const LLSD& seed) : mPanel(NULL) { @@ -96,7 +75,7 @@ void LLFloaterActiveSpeakers::draw() BOOL LLFloaterActiveSpeakers::postBuild() { - mPanel = getChild("active_speakers_panel"); + mPanel = getChild("active_speakers_panel"); return TRUE; } @@ -108,588 +87,6 @@ void LLFloaterActiveSpeakers::onParticipantsChanged() //static void* LLFloaterActiveSpeakers::createSpeakersPanel(void* data) { - // don't show text only speakers - return new LLPanelActiveSpeakers(LLActiveSpeakerMgr::getInstance(), FALSE); -} - -// -// LLPanelActiveSpeakers::SpeakerMuteListener -// -bool LLPanelActiveSpeakers::SpeakerMuteListener::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLPointer speakerp = (LLSpeaker*)event->getSource(); - if (speakerp.isNull()) return false; - - // update UI on confirmation of moderator mutes - if (event->getValue().asString() == "voice") - { - mPanel->childSetValue("moderator_allow_voice", !speakerp->mModeratorMutedVoice); - } - if (event->getValue().asString() == "text") - { - mPanel->childSetValue("moderator_allow_text", !speakerp->mModeratorMutedText); - } - return true; -} - - -// -// LLPanelActiveSpeakers::SpeakerAddListener -// -bool LLPanelActiveSpeakers::SpeakerAddListener::handleEvent(LLPointer event, const LLSD& userdata) -{ - mPanel->addSpeaker(event->getValue().asUUID()); - return true; -} - - -// -// LLPanelActiveSpeakers::SpeakerRemoveListener -// -bool LLPanelActiveSpeakers::SpeakerRemoveListener::handleEvent(LLPointer event, const LLSD& userdata) -{ - mPanel->removeSpeaker(event->getValue().asUUID()); - return true; -} - -// -// LLPanelActiveSpeakers::SpeakerClearListener -// -bool LLPanelActiveSpeakers::SpeakerClearListener::handleEvent(LLPointer event, const LLSD& userdata) -{ - mPanel->mSpeakerList->clearRows(); - return true; -} - - -// -// LLPanelActiveSpeakers -// -LLPanelActiveSpeakers::LLPanelActiveSpeakers(LLSpeakerMgr* data_source, BOOL show_text_chatters) : - mSpeakerList(NULL), - mMuteVoiceCtrl(NULL), - mMuteTextCtrl(NULL), - mNameText(NULL), - mProfileBtn(NULL), - mShowTextChatters(show_text_chatters), - mSpeakerMgr(data_source) -{ - setMouseOpaque(FALSE); - mSpeakerMuteListener = new SpeakerMuteListener(this); - mSpeakerAddListener = new SpeakerAddListener(this); - mSpeakerRemoveListener = new SpeakerRemoveListener(this); - mSpeakerClearListener = new SpeakerClearListener(this); - - mSpeakerMgr->addListener(mSpeakerAddListener, "add"); - mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove"); - mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); -} - -BOOL LLPanelActiveSpeakers::postBuild() -{ - std::string sort_column = gSavedSettings.getString(std::string("FloaterActiveSpeakersSortColumn")); - BOOL sort_ascending = gSavedSettings.getBOOL( std::string("FloaterActiveSpeakersSortAscending")); - - mSpeakerList = getChild("speakers_list"); - mSpeakerList->sortByColumn(sort_column, sort_ascending); - mSpeakerList->setDoubleClickCallback(boost::bind(&onDoubleClickSpeaker,this)); - mSpeakerList->setCommitOnSelectionChange(TRUE); - mSpeakerList->setCommitCallback(boost::bind(&LLPanelActiveSpeakers::handleSpeakerSelect,this)); - mSpeakerList->setSortChangedCallback(boost::bind(&LLPanelActiveSpeakers::onSortChanged,this)); - mSpeakerList->setCallbackUserData(this); - - if ((mMuteTextCtrl = findChild("mute_text_btn"))) - childSetCommitCallback("mute_text_btn", onClickMuteTextCommit, this); - - mMuteVoiceCtrl = getChild("mute_btn"); - childSetCommitCallback("mute_btn", onClickMuteVoiceCommit, this); - - childSetCommitCallback("speaker_volume", onVolumeChange, this); - - mNameText = findChild("resident_name"); - - if ((mProfileBtn = findChild("profile_btn"))) - childSetAction("profile_btn", onClickProfile, this); - - if (findChild("moderator_allow_voice")) - childSetCommitCallback("moderator_allow_voice", onModeratorMuteVoice, this); - if (findChild("moderator_allow_text")) - childSetCommitCallback("moderator_allow_text", onModeratorMuteText, this); - if (findChild("moderator_mode")) - childSetCommitCallback("moderation_mode", onChangeModerationMode, this); - - mVolumeSlider.connect(this,"speaker_volume"); - - // update speaker UI - handleSpeakerSelect(); - - return TRUE; -} - -void LLPanelActiveSpeakers::addSpeaker(const LLUUID& speaker_id) -{ - if (mSpeakerList->getItemIndex(speaker_id) >= 0) - { - // already have this speaker - return; - } - - LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); - if (speakerp) - { - // since we are forced to sort by text, encode sort order as string - std::string speaking_order_sort_string = llformat("%010d", speakerp->mSortIndex); - - LLSD row; - row["id"] = speaker_id; - - LLSD& columns = row["columns"]; - - columns[0]["column"] = "icon_speaking_status"; - columns[0]["type"] = "icon"; - columns[0]["value"] = "icn_active-speakers-dot-lvl0.tga"; - - std::string speaker_name; - if (speakerp->mDisplayName.empty()) - { - speaker_name = LLCacheName::getDefaultName(); - } - else - { - speaker_name = speakerp->mDisplayName; - } - columns[1]["column"] = "speaker_name"; - columns[1]["type"] = "text"; - columns[1]["value"] = speaker_name; - - columns[2]["column"] = "speaking_status"; - columns[2]["type"] = "text"; - - // print speaking ordinal in a text-sorting friendly manner - columns[2]["value"] = speaking_order_sort_string; - - mSpeakerList->addElement(row); - } -} - -void LLPanelActiveSpeakers::removeSpeaker(const LLUUID& speaker_id) -{ - mSpeakerList->deleteSingleItem(mSpeakerList->getItemIndex(speaker_id)); -} - -void LLPanelActiveSpeakers::handleSpeakerSelect() -{ - LLUUID speaker_id = mSpeakerList->getValue().asUUID(); - LLPointer selected_speakerp = mSpeakerMgr->findSpeaker(speaker_id); - - if (selected_speakerp.notNull()) - { - // since setting these values is delayed by a round trip to the Vivox servers - // update them only when selecting a new speaker or - // asynchronously when an update arrives - childSetValue("moderator_allow_voice", selected_speakerp ? !selected_speakerp->mModeratorMutedVoice : TRUE); - childSetValue("moderator_allow_text", selected_speakerp ? !selected_speakerp->mModeratorMutedText : TRUE); - - mSpeakerMuteListener->clearDispatchers(); - selected_speakerp->addListener(mSpeakerMuteListener); - } -} - -void LLPanelActiveSpeakers::refreshSpeakers() -{ - // store off current selection and scroll state to preserve across list rebuilds - LLUUID selected_id = mSpeakerList->getSelectedValue().asUUID(); - S32 scroll_pos = mSpeakerList->getScrollInterface()->getScrollPos(); - - // decide whether it's ok to resort the list then update the speaker manager appropriately. - // rapid resorting by activity makes it hard to interact with speakers in the list - // so we freeze the sorting while the user appears to be interacting with the control. - // we assume this is the case whenever the mouse pointer is within the active speaker - // panel and hasn't been motionless for more than a few seconds. see DEV-6655 -MG - LLRect screen_rect; - localRectToScreen(getLocalRect(), &screen_rect); - BOOL mouse_in_view = screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()); - F32 mouses_last_movement = gMouseIdleTimer.getElapsedTimeF32(); - BOOL sort_ok = ! (mouse_in_view && mouses_last_movementupdate(sort_ok); - - const std::string icon_image_0 = "icn_active-speakers-dot-lvl0.tga"; - const std::string icon_image_1 = "icn_active-speakers-dot-lvl1.tga"; - const std::string icon_image_2 = "icn_active-speakers-dot-lvl2.tga"; - - std::vector items = mSpeakerList->getAllData(); - - std::string mute_icon_image = "mute_icon.tga"; - - LLSpeakerMgr::speaker_list_t speaker_list; - mSpeakerMgr->getSpeakerList(&speaker_list, mShowTextChatters); - for (std::vector::iterator item_it = items.begin(); - item_it != items.end(); - ++item_it) - { - LLScrollListItem* itemp = (*item_it); - LLUUID speaker_id = itemp->getUUID(); - - LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); - if (!speakerp) - { - continue; - } - - // since we are forced to sort by text, encode sort order as string - std::string speaking_order_sort_string = llformat("%010d", speakerp->mSortIndex); - - LLScrollListCell* icon_cell = itemp->getColumn(0); - if (icon_cell) - { - - std::string icon_image_id; - - S32 icon_image_idx = llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f)); - switch(icon_image_idx) - { - case 0: - icon_image_id = icon_image_0; - break; - case 1: - icon_image_id = icon_image_1; - break; - case 2: - icon_image_id = icon_image_2; - break; - } - - LLColor4 icon_color; - - if (speakerp->mStatus == LLSpeaker::STATUS_MUTED) - { - icon_cell->setValue(mute_icon_image); - if(speakerp->mModeratorMutedVoice) - { - icon_color.setVec(0.5f, 0.5f, 0.5f, 1.f); - } - else - { - icon_color.setVec(1.f, 71.f / 255.f, 71.f / 255.f, 1.f); - } - } - else - { - icon_cell->setValue(icon_image_id); - icon_color = speakerp->mDotColor; - - if (speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE) // if voice is disabled for this speaker - { - // non voice speakers have hidden icons, render as transparent - icon_color.setVec(0.f, 0.f, 0.f, 0.f); - } - } - - icon_cell->setColor(icon_color); - - if (speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE && speakerp->mStatus != LLSpeaker::STATUS_MUTED) // if voice is disabled for this speaker - { - // non voice speakers have hidden icons, render as transparent - icon_cell->setColor(LLColor4::transparent); - } - } - - // update name column - LLScrollListCell* name_cell = itemp->getColumn(1); - if (name_cell) - { - if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL) - { - // draw inactive speakers in different color - static LLCachedControl sSpeakersInactive(gColors, "SpeakersInactive"); - - name_cell->setColor(sSpeakersInactive); - } - else - { - static LLCachedControl sDefaultListText(gColors, "DefaultListText"); - - name_cell->setColor(sDefaultListText); - } - // - if(!mShowTextChatters && !(speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL) && speakerp->mID != gAgent.getID()) - { - bool found = false; - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* regionp = *iter; - // let us check to see if they are actually in the sim - if(regionp) - { - if(regionp->mMapAvatarIDs.find(speakerp->mID) != -1) - { - found = true; - break; - } - } - } - if(!found) - { - static LLCachedControl sSpeakersGhost(gColors, "SpeakersGhost"); - - name_cell->setColor(sSpeakersGhost); - } - } - // - - std::string speaker_name; - if (speakerp->mDisplayName.empty()) - { - speaker_name = LLCacheName::getDefaultName(); - } - else - { - speaker_name = speakerp->mDisplayName; - } - - if (speakerp->mIsModerator) - { - speaker_name += std::string(" ") + getString("moderator_label"); - } - - name_cell->setValue(speaker_name); - ((LLScrollListText*)name_cell)->setFontStyle(speakerp->mIsModerator ? LLFontGL::BOLD : LLFontGL::NORMAL); - } - - // update speaking order column - LLScrollListCell* speaking_status_cell = itemp->getColumn(2); - if (speaking_status_cell) - { - // print speaking ordinal in a text-sorting friendly manner - speaking_status_cell->setValue(speaking_order_sort_string); - } - } - - // we potentially modified the sort order by touching the list items - mSpeakerList->setNeedsSort(); - - LLPointer selected_speakerp = mSpeakerMgr->findSpeaker(selected_id); - // update UI for selected participant - if (mMuteVoiceCtrl) - { - mMuteVoiceCtrl->setValue(LLMuteList::getInstance()->isMuted(selected_id, LLMute::flagVoiceChat)); - mMuteVoiceCtrl->setEnabled(LLVoiceClient::getInstance()->voiceEnabled() - && LLVoiceClient::getInstance()->getVoiceEnabled(selected_id) - && selected_id.notNull() - && selected_id != gAgent.getID() - && (selected_speakerp.notNull() && (selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT || selected_speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL))); - - } - if (mMuteTextCtrl) - { - mMuteTextCtrl->setValue(LLMuteList::getInstance()->isMuted(selected_id, LLMute::flagTextChat)); - mMuteTextCtrl->setEnabled(selected_id.notNull() - && selected_id != gAgent.getID() - && selected_speakerp.notNull() - && selected_speakerp->mType != LLSpeaker::SPEAKER_EXTERNAL - && !LLMuteList::getInstance()->isLinden(selected_id)); - } - mVolumeSlider->setValue(LLVoiceClient::getInstance()->getUserVolume(selected_id)); - mVolumeSlider->setEnabled(LLVoiceClient::getInstance()->voiceEnabled() - && LLVoiceClient::getInstance()->getVoiceEnabled(selected_id) - && selected_id.notNull() - && selected_id != gAgent.getID() - && (selected_speakerp.notNull() && (selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT || selected_speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL))); - - if (LLView* view = findChild("moderator_controls_label")) - view->setEnabled(selected_id.notNull()); - - if (LLView* view = findChild("moderator_allow_voice")) - view->setEnabled(selected_id.notNull() && mSpeakerMgr->isVoiceActive() && LLVoiceClient::getInstance()->getVoiceEnabled(selected_id)); - - if (LLView* view = findChild("moderator_allow_text")) - view->setEnabled(selected_id.notNull()); - - if (mProfileBtn) - { - mProfileBtn->setEnabled(selected_id.notNull() && (selected_speakerp.notNull() && selected_speakerp->mType != LLSpeaker::SPEAKER_EXTERNAL) ); - } - - // show selected user name in large font - if (mNameText) - { - if (selected_speakerp) - { - mNameText->setValue(selected_speakerp->mDisplayName); - } - else - { - mNameText->setValue(LLStringUtil::null); - } - } - - //update moderator capabilities - LLPointer self_speakerp = mSpeakerMgr->findSpeaker(gAgent.getID()); - if(self_speakerp) - { - if (LLView* view = findChild("moderation_mode_panel")) - view->setVisible(self_speakerp->mIsModerator && mSpeakerMgr->isVoiceActive()); - if (LLView* view = findChild("moderator_controls")) - view->setVisible(self_speakerp->mIsModerator); - } - - // keep scroll value stable - mSpeakerList->getScrollInterface()->setScrollPos(scroll_pos); -} - -void LLPanelActiveSpeakers::setVoiceModerationCtrlMode( - const BOOL& moderated_voice) -{ - LLUICtrl* voice_moderation_ctrl = getChild("moderation_mode"); - - if ( voice_moderation_ctrl ) - { - std::string value; - - value = moderated_voice ? "moderated" : "unmoderated"; - voice_moderation_ctrl->setValue(value); - } -} - -//static -void LLPanelActiveSpeakers::onClickMuteTextCommit(LLUICtrl* ctrl, void* user_data) -{ - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID(); - BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, LLMute::flagTextChat); - std::string name; - - //fill in name using voice client's copy of name cache - LLPointer speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id); - if (speakerp.isNull()) - { - return; - } - - name = speakerp->mDisplayName; - - LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_AGENT ? LLMute::AGENT : LLMute::OBJECT); - - if (!is_muted) - { - LLMuteList::getInstance()->add(mute, LLMute::flagTextChat); - } - else - { - LLMuteList::getInstance()->remove(mute, LLMute::flagTextChat); - } -} - - -//static -void LLPanelActiveSpeakers::onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_data) -{ - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID(); - BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, LLMute::flagVoiceChat); - std::string name; - - LLPointer speakerp = panelp->mSpeakerMgr->findSpeaker(speaker_id); - if (speakerp.isNull()) - { - return; - } - - name = speakerp->mDisplayName; - - // muting voice means we're dealing with an agent or an external voice client which won't stay muted between sessions - LLMute mute(speaker_id, name, speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL ? LLMute::EXTERNAL : LLMute::AGENT); - - if (!is_muted) - { - LLMuteList::getInstance()->add(mute, LLMute::flagVoiceChat); - } - else - { - LLMuteList::getInstance()->remove(mute, LLMute::flagVoiceChat); - } -} - - -//static -void LLPanelActiveSpeakers::onVolumeChange(LLUICtrl* source, void* user_data) -{ - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - LLUUID speaker_id = panelp->mSpeakerList->getValue().asUUID(); - - F32 new_volume = (F32)panelp->childGetValue("speaker_volume").asReal(); - LLVoiceClient::getInstance()->setUserVolume(speaker_id, new_volume); -} - -//static -void LLPanelActiveSpeakers::onClickProfile(void* user_data) -{ -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - return; - } -// [/RLVa:KB] - - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - LLAvatarActions::showProfile(panelp->mSpeakerList->getValue().asUUID()); -} - -//static -void LLPanelActiveSpeakers::onDoubleClickSpeaker(void* user_data) -{ - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - LLAvatarActions::startIM(panelp->mSpeakerList->getValue().asUUID()); -} - -//static -void LLPanelActiveSpeakers::onSortChanged(void* user_data) -{ - LLPanelActiveSpeakers* panelp = (LLPanelActiveSpeakers*)user_data; - std::string sort_column = panelp->mSpeakerList->getSortColumnName(); - BOOL sort_ascending = panelp->mSpeakerList->getSortAscending(); - gSavedSettings.setString(std::string("FloaterActiveSpeakersSortColumn"), sort_column); - gSavedSettings.setBOOL( std::string("FloaterActiveSpeakersSortAscending"), sort_ascending); -} - - -//static -void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data) -{ - LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data; - LLUICtrl* speakers_list = self->getChild("speakers_list"); - if (!speakers_list || !gAgent.getRegion()) return; - if (LLIMSpeakerMgr* mgr = dynamic_cast(self->mSpeakerMgr)) - mgr->moderateVoiceParticipant(speakers_list->getValue(), ctrl->getValue()); -} - -//static -void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) -{ - LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data; - LLUICtrl* speakers_list = self->getChild("speakers_list"); - if (!speakers_list || !gAgent.getRegion()) return; - if (LLIMSpeakerMgr* mgr = dynamic_cast(self->mSpeakerMgr)) - mgr->toggleAllowTextChat(speakers_list->getValue()); -} - -//static -void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_data) -{ - LLPanelActiveSpeakers* self = (LLPanelActiveSpeakers*)user_data; - if (!gAgent.getRegion()) return; - // Singu Note: moderateVoiceAllParticipants ends up flipping the boolean passed to it before the actual post - if (LLIMSpeakerMgr* speaker_manager = dynamic_cast(self->mSpeakerMgr)) - { - if (ctrl->getValue().asString() == "unmoderated") - { - speaker_manager->moderateVoiceAllParticipants(true); - } - else if (ctrl->getValue().asString() == "moderated") - { - speaker_manager->moderateVoiceAllParticipants(false); - } - } + return new LLParticipantList(LLActiveSpeakerMgr::getInstance(), /*show_text_chatters=*/ false); } diff --git a/indra/newview/llfloateractivespeakers.h b/indra/newview/llfloateractivespeakers.h index 8fb66ee70..c8657f09a 100644 --- a/indra/newview/llfloateractivespeakers.h +++ b/indra/newview/llfloateractivespeakers.h @@ -34,15 +34,8 @@ #include "llfloater.h" #include "llvoiceclient.h" -#include "llframetimer.h" -#include "llevent.h" - -class LLScrollListCtrl; -class LLButton; -class LLPanelActiveSpeakers; -class LLSpeakerMgr; -class LLTextBox; +class LLParticipantList; class LLFloaterActiveSpeakers : public LLFloaterSingleton, @@ -67,95 +60,7 @@ public: protected: LLFloaterActiveSpeakers(const LLSD& seed); - LLPanelActiveSpeakers* mPanel; + LLParticipantList* mPanel; }; -class LLPanelActiveSpeakers : public LLPanel -{ -public: - LLPanelActiveSpeakers(LLSpeakerMgr* data_source, BOOL show_text_chatters); - - /*virtual*/ BOOL postBuild(); - - void handleSpeakerSelect(); - void refreshSpeakers(); - - void setVoiceModerationCtrlMode(const BOOL& moderated_voice); - - static void onClickMuteVoiceCommit(LLUICtrl* ctrl, void* user_data); - static void onClickMuteTextCommit(LLUICtrl* ctrl, void* user_data); - static void onVolumeChange(LLUICtrl* source, void* user_data); - static void onClickProfile(void* user_data); - static void onDoubleClickSpeaker(void* user_data); - static void onSortChanged(void* user_data); - static void onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data); - static void onModeratorMuteText(LLUICtrl* ctrl, void* user_data); - static void onChangeModerationMode(LLUICtrl* ctrl, void* user_data); - -protected: - class SpeakerMuteListener : public LLOldEvents::LLSimpleListener - { - public: - SpeakerMuteListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {} - - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - - LLPanelActiveSpeakers* mPanel; - }; - - friend class SpeakerAddListener; - class SpeakerAddListener : public LLOldEvents::LLSimpleListener - { - public: - SpeakerAddListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {} - - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - - LLPanelActiveSpeakers* mPanel; - }; - - friend class SpeakerRemoveListener; - class SpeakerRemoveListener : public LLOldEvents::LLSimpleListener - { - public: - SpeakerRemoveListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {} - - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - - LLPanelActiveSpeakers* mPanel; - }; - - - friend class SpeakerClearListener; - class SpeakerClearListener : public LLOldEvents::LLSimpleListener - { - public: - SpeakerClearListener(LLPanelActiveSpeakers* panel) : mPanel(panel) {} - - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - - LLPanelActiveSpeakers* mPanel; - }; - - void addSpeaker(const LLUUID& id); - void removeSpeaker(const LLUUID& id); - - - LLScrollListCtrl* mSpeakerList; - LLUICtrl* mMuteVoiceCtrl; - LLUICtrl* mMuteTextCtrl; - LLTextBox* mNameText; - LLButton* mProfileBtn; - BOOL mShowTextChatters; - LLSpeakerMgr* mSpeakerMgr; - LLFrameTimer mIconAnimationTimer; - LLPointer mSpeakerMuteListener; - LLPointer mSpeakerAddListener; - LLPointer mSpeakerRemoveListener; - LLPointer mSpeakerClearListener; - - CachedUICtrl mVolumeSlider; -}; - - #endif // LL_LLFLOATERACTIVESPEAKERS_H diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 89aa5dc51..6eb9dbe0f 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -52,12 +52,12 @@ #include "llagent.h" #include "llchatbar.h" #include "llconsole.h" -#include "llfloateractivespeakers.h" #include "llfloaterchatterbox.h" #include "llfloatermute.h" #include "llfloaterscriptdebug.h" #include "lllogchat.h" #include "llmutelist.h" +#include "llparticipantlist.h" #include "llspeakers.h" #include "llstylemap.h" #include "lluictrlfactory.h" @@ -127,7 +127,7 @@ void LLFloaterChat::draw() BOOL LLFloaterChat::postBuild() { - mPanel = (LLPanelActiveSpeakers*)getChild("active_speakers_panel"); + mPanel = getChild("active_speakers_panel"); LLChatBar* chat_barp = getChild("chat_panel", TRUE); if (chat_barp) @@ -628,7 +628,7 @@ void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type , std::string l //static void* LLFloaterChat::createSpeakersPanel(void* data) { - return new LLPanelActiveSpeakers(LLLocalSpeakerMgr::getInstance(), TRUE); + return new LLParticipantList(LLLocalSpeakerMgr::getInstance(), true); } //static diff --git a/indra/newview/llfloaterchat.h b/indra/newview/llfloaterchat.h index 3c7cbc4c5..7eaab1b16 100644 --- a/indra/newview/llfloaterchat.h +++ b/indra/newview/llfloaterchat.h @@ -48,7 +48,7 @@ class LLViewerTextEditor; class LLMessageSystem; class LLUUID; class LLCheckBoxCtrl; -class LLPanelActiveSpeakers; +class LLParticipantList; class LLLogChat; class LLChatBar; @@ -95,7 +95,7 @@ public: static void show(LLFloater* instance, const LLSD& key); static void hide(LLFloater* instance, const LLSD& key); - LLPanelActiveSpeakers* mPanel; + LLParticipantList* mPanel; BOOL mScrolledToEnd; BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 94d3bee71..edd499610 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -50,7 +50,6 @@ #include "llchat.h" #include "llconsole.h" #include "llgroupactions.h" -#include "llfloateractivespeakers.h" #include "llfloaterchat.h" #include "llimview.h" #include "llinventory.h" @@ -60,6 +59,7 @@ #include "llkeyboard.h" #include "lllineeditor.h" #include "llnotify.h" +#include "llparticipantlist.h" #include "llresmgr.h" #include "llspeakers.h" #include "lltrans.h" @@ -621,7 +621,7 @@ BOOL LLFloaterIMPanel::postBuild() void* LLFloaterIMPanel::createSpeakersPanel(void* data) { LLFloaterIMPanel* floaterp = (LLFloaterIMPanel*)data; - floaterp->mSpeakerPanel = new LLPanelActiveSpeakers(floaterp->mSpeakers, TRUE); + floaterp->mSpeakerPanel = new LLParticipantList(floaterp->mSpeakers, true); return floaterp->mSpeakerPanel; } diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 907993388..7d4d1fe71 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -46,8 +46,7 @@ class LLViewerTextEditor; class LLInventoryItem; class LLInventoryCategory; class LLIMSpeakerMgr; -class LLPanelActiveSpeakers; -class LLPanel; +class LLParticipantList; class LLButton; class LLVoiceChannel; @@ -244,7 +243,7 @@ private: BOOL mCallBackEnabled; LLIMSpeakerMgr* mSpeakers; - LLPanelActiveSpeakers* mSpeakerPanel; + LLParticipantList* mSpeakerPanel; // Optimization: Don't send "User is typing..." until the // user has actually been typing for a little while. Prevents diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp new file mode 100644 index 000000000..391499f26 --- /dev/null +++ b/indra/newview/llparticipantlist.cpp @@ -0,0 +1,597 @@ +/** + * @file llparticipantlist.cpp + * @brief LLParticipantList intended to update view(LLAvatarList) according to incoming messages + * + * $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 "llavataractions.h" +#include "llagent.h" +#include "llmutelist.h" +#include "llparticipantlist.h" +#include "llscrolllistctrl.h" +#include "llspeakers.h" +#include "llviewerwindow.h" +#include "llvoiceclient.h" +#include "llworld.h" // Edit: For ghost detection +// [RLVa:KB] +#include "rlvhandler.h" +// [/RLVa:KB] + +LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, + bool show_text_chatters) : + mSpeakerMgr(data_source), + mAvatarList(NULL), + mShowTextChatters(show_text_chatters), + mValidateSpeakerCallback(NULL) +{ + setMouseOpaque(false); + + /* Singu TODO: Avaline? + mAvalineUpdater = new LLAvalineUpdater(boost::bind(&LLParticipantList::onAvalineCallerFound, this, _1), + boost::bind(&LLParticipantList::onAvalineCallerRemoved, this, _1));*/ + + mSpeakerAddListener = new SpeakerAddListener(*this); + mSpeakerRemoveListener = new SpeakerRemoveListener(*this); + mSpeakerClearListener = new SpeakerClearListener(*this); + //mSpeakerModeratorListener = new SpeakerModeratorUpdateListener(*this); + mSpeakerMuteListener = new SpeakerMuteListener(*this); + + mSpeakerMgr->addListener(mSpeakerAddListener, "add"); + mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove"); + mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); + //mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator"); +} + +BOOL LLParticipantList::postBuild() +{ + mAvatarList = getChild("speakers_list"); + + mAvatarList->sortByColumn(gSavedSettings.getString("FloaterActiveSpeakersSortColumn"), gSavedSettings.getBOOL("FloaterActiveSpeakersSortAscending")); + mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this)); + mAvatarList->setCommitOnSelectionChange(true); + mAvatarList->setCommitCallback(boost::bind(&LLParticipantList::handleSpeakerSelect, this)); + mAvatarList->setSortChangedCallback(boost::bind(&LLParticipantList::onSortChanged, this)); + + if (LLUICtrl* ctrl = findChild("mute_text_btn")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleMuteText, this)); + if (LLUICtrl* ctrl = findChild("mute_btn")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleMuteVoice, this)); + if (LLUICtrl* ctrl = findChild("speaker_volume")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::onVolumeChange, this, _2)); + if (LLUICtrl* ctrl = findChild("profile_btn")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::onClickProfile, this)); + if (LLUICtrl* ctrl = findChild("moderator_allow_voice")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::moderateVoiceParticipant, this, _2)); + if (LLUICtrl* ctrl = findChild("moderator_allow_text")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::toggleAllowTextChat, this, _2)); + if (LLUICtrl* ctrl = findChild("moderator_mode")) + ctrl->setCommitCallback(boost::bind(&LLParticipantList::moderateVoiceAllParticipants, this, _2)); + + // update speaker UI + handleSpeakerSelect(); + + return true; +} + +LLParticipantList::~LLParticipantList() +{ + /* Singu TODO? + mAvatarListDoubleClickConnection.disconnect(); + mAvatarListRefreshConnection.disconnect(); + mAvatarListReturnConnection.disconnect(); + mAvatarListToggleIconsConnection.disconnect(); + + // It is possible Participant List will be re-created from LLCallFloater::onCurrentChannelChanged() + // See ticket EXT-3427 + // hide menu before deleting it to stop enable and check handlers from triggering. + if(mParticipantListMenu && !LLApp::isExiting()) + { + mParticipantListMenu->hide(); + } + + if (mParticipantListMenu) + { + delete mParticipantListMenu; + mParticipantListMenu = NULL; + } + + mAvatarList->setContextMenu(NULL); + mAvatarList->setComparator(NULL); + + delete mAvalineUpdater; + */ +} + +/*void LLParticipantList::setSpeakingIndicatorsVisible(BOOL visible) +{ + mAvatarList->setSpeakingIndicatorsVisible(visible); +}*/ + + +void LLParticipantList::onAvatarListDoubleClicked() +{ + LLAvatarActions::startIM(mAvatarList->getValue().asUUID()); +} + +void LLParticipantList::handleSpeakerSelect() +{ + const LLUUID& speaker_id = mAvatarList->getValue().asUUID(); + LLPointer selected_speakerp = mSpeakerMgr->findSpeaker(speaker_id); + if (speaker_id.isNull() || selected_speakerp.isNull()) + { + // Disable normal controls + if (LLView* view = findChild("mute_btn")) + view->setEnabled(false); + if (LLView* view = findChild("mute_text_btn")) + view->setEnabled(false); + if (LLView* view = findChild("speaker_volume")) + view->setEnabled(false); + // Hide moderator controls + if (LLView* view = findChild("moderation_mode_panel")) + view->setVisible(false); + if (LLView* view = findChild("moderator_controls")) + view->setVisible(false); + // Clear the name + if (LLUICtrl* ctrl = findChild("resident_name")) + ctrl->setValue(LLStringUtil::null); + return; + } + + mSpeakerMuteListener->clearDispatchers(); + + bool valid_speaker = selected_speakerp->mType == LLSpeaker::SPEAKER_AGENT || selected_speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL; + bool can_mute = valid_speaker && LLAvatarActions::canBlock(speaker_id); + bool voice_enabled = valid_speaker && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id); + // since setting these values is delayed by a round trip to the Vivox servers + // update them only when selecting a new speaker or + // asynchronously when an update arrives + if (LLUICtrl* ctrl = findChild("moderator_allow_voice")) + { + ctrl->setEnabled(voice_enabled); + ctrl->setValue(!selected_speakerp->mModeratorMutedVoice); + } + if (LLUICtrl* ctrl = findChild("moderator_allow_text")) + { + ctrl->setEnabled(true); + ctrl->setValue(!selected_speakerp->mModeratorMutedText); + } + if (LLView* view = findChild("moderator_controls_label")) + { + view->setEnabled(true); + } + // update UI for selected participant + if (LLUICtrl* ctrl = findChild("mute_btn")) + { + ctrl->setValue(LLAvatarActions::isVoiceMuted(speaker_id)); + ctrl->setEnabled(can_mute && voice_enabled); + } + if (LLUICtrl* ctrl = findChild("mute_text_btn")) + { + ctrl->setValue(LLAvatarActions::isBlocked(speaker_id)); + ctrl->setEnabled(can_mute); + } + if (LLUICtrl* ctrl = findChild("speaker_volume")) + { + // Singu Note: Allow modifying own voice volume during a voice session (Which is valued at half of what it should be) + ctrl->setValue(gAgentID == speaker_id ? gSavedSettings.getF32("AudioLevelMic")/2 : LLVoiceClient::getInstance()->getUserVolume(speaker_id)); + ctrl->setEnabled(valid_speaker && voice_enabled); + } + if (LLView* view = findChild("profile_btn")) + { + view->setEnabled(selected_speakerp->mType != LLSpeaker::SPEAKER_EXTERNAL); + } + // show selected user name in large font + if (LLUICtrl* ctrl = findChild("resident_name")) + { + ctrl->setValue(selected_speakerp->mDisplayName); + } + selected_speakerp->addListener(mSpeakerMuteListener); + + //update moderator capabilities + LLPointer self_speakerp = mSpeakerMgr->findSpeaker(gAgentID); + if (self_speakerp.isNull()) return; + + if (LLView* view = findChild("moderation_mode_panel")) + { + view->setVisible(self_speakerp->mIsModerator && mSpeakerMgr->isVoiceActive()); + } + if (LLView* view = findChild("moderator_controls")) + { + view->setVisible(self_speakerp->mIsModerator); + } +} + +void LLParticipantList::refreshSpeakers() +{ + // store off current selection and scroll state to preserve across list rebuilds + const S32 scroll_pos = mAvatarList->getScrollInterface()->getScrollPos(); + + // decide whether it's ok to resort the list then update the speaker manager appropriately. + // rapid resorting by activity makes it hard to interact with speakers in the list + // so we freeze the sorting while the user appears to be interacting with the control. + // we assume this is the case whenever the mouse pointer is within the active speaker + // panel and hasn't been motionless for more than a few seconds. see DEV-6655 -MG + LLRect screen_rect; + localRectToScreen(getLocalRect(), &screen_rect); + mSpeakerMgr->update(!(screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()) && gMouseIdleTimer.getElapsedTimeF32() < 5.f)); + + std::vector items = mAvatarList->getAllData(); + for (std::vector::iterator item_it = items.begin(); item_it != items.end(); ++item_it) + { + LLScrollListItem* itemp = (*item_it); + LLPointer speakerp = mSpeakerMgr->findSpeaker(itemp->getUUID()); + if (speakerp.isNull()) continue; + + if (LLScrollListCell* icon_cell = itemp->getColumn(0)) + { + if (speakerp->mStatus == LLSpeaker::STATUS_MUTED) + { + icon_cell->setValue("mute_icon.tga"); + static const LLCachedControl sAscentMutedColor(gColors, "AscentMutedColor"); + icon_cell->setColor(speakerp->mModeratorMutedVoice ? /*LLColor4::grey*/sAscentMutedColor : LLColor4(1.f, 71.f / 255.f, 71.f / 255.f, 1.f)); + } + else + { + switch(llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f))) + { + case 0: + icon_cell->setValue("icn_active-speakers-dot-lvl0.tga"); + break; + case 1: + icon_cell->setValue("icn_active-speakers-dot-lvl1.tga"); + break; + case 2: + icon_cell->setValue("icn_active-speakers-dot-lvl2.tga"); + break; + } + // non voice speakers have hidden icons, render as transparent + icon_cell->setColor(speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE ? LLColor4::transparent : speakerp->mDotColor); + } + } + // update name column + if (LLScrollListCell* name_cell = itemp->getColumn(1)) + { + if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL) + { + // draw inactive speakers in different color + static const LLCachedControl sSpeakersInactive(gColors, "SpeakersInactive"); + name_cell->setColor(sSpeakersInactive); + } + else + { + // + bool found = mShowTextChatters || speakerp->mID == gAgentID; + const LLWorld::region_list_t& regions = LLWorld::getInstance()->getRegionList(); + for (LLWorld::region_list_t::const_iterator iter = regions.begin(); !found && iter != regions.end(); ++iter) + { + // Are they in this sim? + if (const LLViewerRegion* regionp = *iter) + if (regionp->mMapAvatarIDs.find(speakerp->mID) != -1) + found = true; + } + if (!found) + { + static const LLCachedControl sSpeakersGhost(gColors, "SpeakersGhost"); + name_cell->setColor(sSpeakersGhost); + } + else + // + { + static const LLCachedControl sDefaultListText(gColors, "DefaultListText"); + name_cell->setColor(sDefaultListText); + } + } + + std::string speaker_name = speakerp->mDisplayName.empty() ? LLCacheName::getDefaultName() : speakerp->mDisplayName; + if (speakerp->mIsModerator) + speaker_name += " " + getString("moderator_label"); + name_cell->setValue(speaker_name); + static_cast(name_cell)->setFontStyle(speakerp->mIsModerator ? LLFontGL::BOLD : LLFontGL::NORMAL); + } + // update speaking order column + if (LLScrollListCell* speaking_status_cell = itemp->getColumn(2)) + { + // since we are forced to sort by text, encode sort order as string + // print speaking ordinal in a text-sorting friendly manner + speaking_status_cell->setValue(llformat("%010d", speakerp->mSortIndex)); + } + } + + // we potentially modified the sort order by touching the list items + mAvatarList->setNeedsSort(); + + // keep scroll value stable + mAvatarList->getScrollInterface()->setScrollPos(scroll_pos); +} + +void LLParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t cb) +{ + mValidateSpeakerCallback = cb; +} + +bool LLParticipantList::onAddItemEvent(LLPointer 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 event, const LLSD& userdata) +{ + const S32 pos = mAvatarList->getItemIndex(event->getValue().asUUID()); + if (pos != -1) + { + mAvatarList->deleteSingleItem(pos); + } + return true; +} + +bool LLParticipantList::onClearListEvent(LLPointer event, const LLSD& userdata) +{ + mAvatarList->clearRows(); + return true; +} + +bool LLParticipantList::onSpeakerMuteEvent(LLPointer event, const LLSD& userdata) +{ + LLPointer speakerp = (LLSpeaker*)event->getSource(); + if (speakerp.isNull()) return false; + + // update UI on confirmation of moderator mutes + if (event->getValue().asString() == "voice") + { + childSetValue("moderator_allow_voice", !speakerp->mModeratorMutedVoice); + } + else if (event->getValue().asString() == "text") + { + childSetValue("moderator_allow_text", !speakerp->mModeratorMutedText); + } + return true; +} + +void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) +{ + //if (mExcludeAgent && gAgent.getID() == avatar_id) return; + if (mAvatarList->getItemIndex(avatar_id) != -1) return; + + /* Singu TODO: Avaline? + bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(avatar_id); + + if (is_avatar) + { + mAvatarList->getIDs().push_back(avatar_id); + mAvatarList->setDirty(); + } + else + { + std::string display_name = LLVoiceClient::getInstance()->getDisplayName(avatar_id); + mAvatarList->addAvalineItem(avatar_id, mSpeakerMgr->getSessionID(), display_name.empty() ? LLTrans::getString("AvatarNameWaiting") : display_name); + mAvalineUpdater->watchAvalineCaller(avatar_id); + }*/ + adjustParticipant(avatar_id); +} + +void LLParticipantList::adjustParticipant(const LLUUID& speaker_id) +{ + LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); + if (speakerp.isNull()) return; + + LLSD row; + row["id"] = speaker_id; + LLSD& columns = row["columns"]; + columns[0]["column"] = "icon_speaking_status"; + columns[0]["type"] = "icon"; + columns[0]["value"] = "icn_active-speakers-dot-lvl0.tga"; + + const std::string& display_name = LLVoiceClient::getInstance()->getDisplayName(speaker_id); + columns[1]["column"] = "speaker_name"; + columns[1]["type"] = "text"; + columns[1]["value"] = display_name.empty() ? LLCacheName::getDefaultName() : display_name; + + columns[2]["column"] = "speaking_status"; + columns[2]["type"] = "text"; + columns[2]["value"] = llformat("%010d", speakerp->mSortIndex); // print speaking ordinal in a text-sorting friendly manner + mAvatarList->addElement(row); + + // add listener to process moderation changes + speakerp->addListener(mSpeakerMuteListener); +} + +// +// LLParticipantList::SpeakerAddListener +// +bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer 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 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 event, const LLSD& userdata) +{ + return mParent.onRemoveItemEvent(event, userdata); +} + +// +// LLParticipantList::SpeakerClearListener +// +bool LLParticipantList::SpeakerClearListener::handleEvent(LLPointer event, const LLSD& userdata) +{ + return mParent.onClearListEvent(event, userdata); +} + +// +// LLParticipantList::SpeakerMuteListener +// +bool LLParticipantList::SpeakerMuteListener::handleEvent(LLPointer event, const LLSD& userdata) +{ + return mParent.onSpeakerMuteEvent(event, userdata); +} + +// Singu Note: The following functions are actually of the LLParticipantListMenu class, but we haven't married lists with menus yet. +void LLParticipantList::toggleAllowTextChat(const LLSD& userdata) +{ + if (!gAgent.getRegion()) return; + LLIMSpeakerMgr* mgr = dynamic_cast(mSpeakerMgr); + if (mgr) + { + const LLUUID speaker_id = mAvatarList->getValue(); + mgr->toggleAllowTextChat(speaker_id); + } +} + +void LLParticipantList::toggleMute(const LLSD& userdata, U32 flags) +{ + const LLUUID speaker_id = userdata.asUUID(); //mUUIDs.front(); + BOOL is_muted = LLMuteList::getInstance()->isMuted(speaker_id, flags); + std::string name; + + //fill in name using voice client's copy of name cache + LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); + if (speakerp.isNull()) + { + LL_WARNS("Speakers") << "Speaker " << speaker_id << " not found" << llendl; + return; + } + + name = speakerp->mDisplayName; + + LLMute::EType mute_type; + switch (speakerp->mType) + { + case LLSpeaker::SPEAKER_AGENT: + mute_type = LLMute::AGENT; + break; + case LLSpeaker::SPEAKER_OBJECT: + mute_type = LLMute::OBJECT; + break; + case LLSpeaker::SPEAKER_EXTERNAL: + default: + mute_type = LLMute::EXTERNAL; + break; + } + LLMute mute(speaker_id, name, mute_type); + + if (!is_muted) + { + LLMuteList::getInstance()->add(mute, flags); + } + else + { + LLMuteList::getInstance()->remove(mute, flags); + } +} + +void LLParticipantList::toggleMuteText() +{ + toggleMute(mAvatarList->getValue(), LLMute::flagTextChat); +} + +void LLParticipantList::toggleMuteVoice() +{ + toggleMute(mAvatarList->getValue(), LLMute::flagVoiceChat); +} + +void LLParticipantList::moderateVoiceParticipant(const LLSD& param) +{ + if (!gAgent.getRegion()) return; + LLIMSpeakerMgr* mgr = dynamic_cast(mSpeakerMgr); + if (mgr) + { + mgr->moderateVoiceParticipant(mAvatarList->getValue(), param); + } +} + +void LLParticipantList::moderateVoiceAllParticipants(const LLSD& param) +{ + if (!gAgent.getRegion()) return; + // Singu Note: moderateVoiceAllParticipants ends up flipping the boolean passed to it before the actual post + if (LLIMSpeakerMgr* speaker_manager = dynamic_cast(mSpeakerMgr)) + { + if (param.asString() == "unmoderated") + { + speaker_manager->moderateVoiceAllParticipants(true); + } + else if (param.asString() == "moderated") + { + speaker_manager->moderateVoiceAllParticipants(false); + } + } +} + +// Singu Note: The following callbacks are not found upstream +void LLParticipantList::onVolumeChange(const LLSD& param) +{ + // Singu Note: Allow modifying own voice volume during a voice session (Which is valued at half of what it should be) + const LLUUID& speaker_id = mAvatarList->getValue().asUUID(); + if (gAgentID == speaker_id) + { + gSavedSettings.setF32("AudioLevelMic", param.asFloat()*2); + } + else + { + LLVoiceClient::getInstance()->setUserVolume(speaker_id, param.asFloat()); + } +} + +void LLParticipantList::onClickProfile() +{ +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) return; +// [/RLVa:KB] + LLAvatarActions::showProfile(mAvatarList->getValue().asUUID()); +} + +void LLParticipantList::onSortChanged() +{ + gSavedSettings.setString("FloaterActiveSpeakersSortColumn", mAvatarList->getSortColumnName()); + gSavedSettings.setBOOL("FloaterActiveSpeakersSortAscending", mAvatarList->getSortAscending()); +} + +void LLParticipantList::setVoiceModerationCtrlMode(const bool& moderated_voice) +{ + if (LLUICtrl* voice_moderation_ctrl = findChild("moderation_mode")) + { + voice_moderation_ctrl->setValue(moderated_voice ? "moderated" : "unmoderated"); + } +} + diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h new file mode 100644 index 000000000..1d4841bba --- /dev/null +++ b/indra/newview/llparticipantlist.h @@ -0,0 +1,210 @@ +/** + * @file llparticipantlist.h + * @brief LLParticipantList intended to update view(LLAvatarList) according to incoming messages + * + * $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$ + */ + +#ifndef LL_PARTICIPANTLIST_H +#define LL_PARTICIPANTLIST_H + +#include "llpanel.h" + +class LLSpeakerMgr; +class LLScrollListCtrl; +class LLUICtrl; + +class LLParticipantList : public LLPanel +{ + LOG_CLASS(LLParticipantList); +public: + + typedef boost::function validate_speaker_callback_t; + + LLParticipantList(LLSpeakerMgr* data_source, bool show_text_chatters); + /*virtual*/ BOOL postBuild(); + ~LLParticipantList(); + + /** + * Adds specified avatar ID to the existing list if it is not Agent's ID + * + * @param[in] avatar_id - Avatar UUID to be added into the list + */ + void addAvatarIDExceptAgent(const LLUUID& avatar_id); + + /** + * Refreshes the participant list. + */ + void refreshSpeakers(); + + /** + * Set a callback to be called before adding a speaker. Invalid speakers will not be added. + * + * If the callback is unset all speakers are considered as valid. + * + * @see onAddItemEvent() + */ + void setValidateSpeakerCallback(validate_speaker_callback_t cb); + + void setVoiceModerationCtrlMode(const bool& moderated_voice); + +protected: + /** + * LLSpeakerMgr event handlers + */ + bool onAddItemEvent(LLPointer event, const LLSD& userdata); + bool onRemoveItemEvent(LLPointer event, const LLSD& userdata); + bool onClearListEvent(LLPointer event, const LLSD& userdata); + //bool onModeratorUpdateEvent(LLPointer event, const LLSD& userdata); + bool onSpeakerMuteEvent(LLPointer event, const LLSD& userdata); + + /** + * List of listeners implementing LLOldEvents::LLSimpleListener. + * There is no way to handle all the events in one listener as LLSpeakerMgr registers + * listeners in such a way that one listener can handle only one type of event + **/ + class BaseSpeakerListener : public LLOldEvents::LLSimpleListener + { + public: + BaseSpeakerListener(LLParticipantList& parent) : mParent(parent) {} + protected: + LLParticipantList& mParent; + }; + + class SpeakerAddListener : public BaseSpeakerListener + { + public: + SpeakerAddListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + class SpeakerRemoveListener : public BaseSpeakerListener + { + public: + SpeakerRemoveListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + class SpeakerClearListener : public BaseSpeakerListener + { + public: + SpeakerClearListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + /*class SpeakerModeratorUpdateListener : public BaseSpeakerListener + { + public: + SpeakerModeratorUpdateListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + *virtual* bool handleEvent(LLPointer event, const LLSD& userdata); + };*/ + + class SpeakerMuteListener : public BaseSpeakerListener + { + public: + SpeakerMuteListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + /** + * Menu used in the participant list. + class LLParticipantListMenu : public LLListContextMenu + { + */ + private: + void toggleAllowTextChat(const LLSD& userdata); + void toggleMute(const LLSD& userdata, U32 flags); + void toggleMuteText(); + void toggleMuteVoice(); + + /** + * Processes Voice moderation menu items. + * + * It calls either moderateVoiceParticipant() or moderateVoiceParticipant() depend on + * passed parameter. + * + * @param userdata can be "selected" or "others". + * + * @see moderateVoiceParticipant() + * @see moderateVoiceAllParticipants() + */ + void moderateVoice(const LLSD& userdata); + + /** + * Mutes/Unmutes avatar for current group voice chat. + * + * It only marks avatar as muted for session and does not use local Agent's Block list. + * It does not mute Agent itself. + * + * @param[in] avatar_id UUID of avatar to be processed + * @param[in] unmute if true - specified avatar will be muted, otherwise - unmuted. + * + * @see moderateVoiceAllParticipants() + */ + void moderateVoiceParticipant(const LLSD& param); + + /** + * Mutes/Unmutes all avatars for current group voice chat. + * + * It only marks avatars as muted for session and does not use local Agent's Block list. + * + * @param[in] unmute if true - avatars will be muted, otherwise - unmuted. + * + * @see moderateVoiceParticipant() + */ + void moderateVoiceAllParticipants(const LLSD& param); + + //static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response); + //}; + +private: + void onAvatarListDoubleClicked(); + + /** + * Adjusts passed participant to work properly. + * + * Adds SpeakerMuteListener to process moderation actions. + */ + void adjustParticipant(const LLUUID& speaker_id); + + // Singu Note: The following callbacks are not found upstream + void handleSpeakerSelect(); + void onClickProfile(); + void onSortChanged(); + void onVolumeChange(const LLSD& param); + + LLSpeakerMgr* mSpeakerMgr; + LLScrollListCtrl* mAvatarList; + bool mShowTextChatters; + + LLPointer mSpeakerAddListener; + LLPointer mSpeakerRemoveListener; + LLPointer mSpeakerClearListener; + //LLPointer mSpeakerModeratorListener; + LLPointer mSpeakerMuteListener; + + validate_speaker_callback_t mValidateSpeakerCallback; +}; + +#endif // LL_PARTICIPANTLIST_H + diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 880a6c8f7..db1042031 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -419,7 +419,7 @@ void LLSpeakerMgr::update(BOOL resort_ok) if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) { // external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + setSpeakerNotInChannel(speakerp); // Singu Note: Don't just flag, call the flagging function and get them on the removal timer! } else { @@ -903,7 +903,7 @@ void LLActiveSpeakerMgr::updateSpeakerList() if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) { // automatically flag text only speakers for removal - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; + setSpeakerNotInChannel(speakerp); // Singu Note: Don't just flag, call the flagging function and get them on the removal timer! } } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 6f409b782..e8efa11a7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -58,7 +58,6 @@ // linden library includes #include "llaudioengine.h" // mute on minimize -#include "indra_constants.h" #include "llassetstorage.h" #include "llfontgl.h" #include "llmousehandler.h" @@ -77,12 +76,9 @@ #include "raytrace.h" // newview includes -#include "llagent.h" #include "llbox.h" #include "llchatbar.h" #include "llconsole.h" -#include "llviewercontrol.h" -#include "llcylinder.h" #include "lldebugview.h" #include "lldir.h" #include "lldrawable.h" @@ -93,20 +89,11 @@ #include "llface.h" #include "llfeaturemanager.h" #include "statemachine/aifilepicker.h" -#include "llfloater.h" -#include "llfloateractivespeakers.h" -#include "llfloaterbuildoptions.h" -#include "llfloaterbuyland.h" #include "llfloatercamera.h" #include "llfloaterchat.h" #include "llfloaterchatterbox.h" #include "llfloatercustomize.h" #include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor -#include "llfloaterland.h" -#include "llfloaterinspect.h" -#include "llfloaterinventory.h" -#include "llfloaternamedesc.h" -#include "llfloaterpreference.h" #include "llfloatersnapshot.h" #include "llfloaterteleporthistory.h" #include "llfloatertools.h" @@ -196,7 +183,6 @@ #include "llnotifications.h" #include "llnotificationsutil.h" -#include "llfloatertest.h" // HACK! #include "llfloaternotificationsconsole.h" // [RLVa:KB]