diff options
-rw-r--r-- | indra/llui/llmenugl.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llavataractions.cpp | 12 | ||||
-rw-r--r-- | indra/newview/llavataractions.h | 5 | ||||
-rw-r--r-- | indra/newview/llchathistory.cpp | 264 | ||||
-rw-r--r-- | indra/newview/llfloaterimcontainer.cpp | 22 | ||||
-rw-r--r-- | indra/newview/llfloaterimcontainer.h | 1 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 38 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.h | 3 | ||||
-rw-r--r-- | indra/newview/llinventorypanel.cpp | 13 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 5 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_avatar_icon.xml | 44 |
11 files changed, 343 insertions, 67 deletions
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 022f814bbc..0d42f726fa 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3331,6 +3331,7 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) if (getHighlightedItem()) { clearHoverItem(); + LLMenuGL::setKeyboardMode(FALSE); } else { @@ -3777,10 +3778,10 @@ BOOL LLMenuHolderGL::hideMenus() { return FALSE; } + LLMenuGL::setKeyboardMode(FALSE); BOOL menu_visible = hasVisibleMenu(); if (menu_visible) { - LLMenuGL::setKeyboardMode(FALSE); // clicked off of menu, hide them all for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 219d9da01f..8fe684ad79 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -1005,7 +1005,7 @@ void LLAvatarActions::toggleBlock(const LLUUID& id) } // static -void LLAvatarActions::toggleMuteVoice(const LLUUID& id) +void LLAvatarActions::toggleMute(const LLUUID& id, U32 flags) { LLAvatarName av_name; LLAvatarNameCache::get(id, &av_name); @@ -1016,15 +1016,21 @@ void LLAvatarActions::toggleMuteVoice(const LLUUID& id) LLMute mute(id, av_name.getUserName(), LLMute::AGENT); if (!is_muted) { - mute_list->add(mute, LLMute::flagVoiceChat); + mute_list->add(mute, flags); } else { - mute_list->remove(mute, LLMute::flagVoiceChat); + mute_list->remove(mute, flags); } } // static +void LLAvatarActions::toggleMuteVoice(const LLUUID& id) +{ + toggleMute(id, LLMute::flagVoiceChat); +} + +// static bool LLAvatarActions::canOfferTeleport(const LLUUID& id) { // First use LLAvatarTracker::isBuddy() diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 256d44d820..b56d5b0fb9 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -131,6 +131,11 @@ public: static void toggleBlock(const LLUUID& id); /** + * Mute/unmute avatar. + */ + static void toggleMute(const LLUUID& id, U32 flags); + + /** * Block/unblock the avatar voice. */ static void toggleMuteVoice(const LLUUID& id); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 9798ef3529..5748eeec47 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -38,10 +38,14 @@ #include "llpanel.h" #include "lluictrlfactory.h" #include "llscrollcontainer.h" -#include "llavatariconctrl.h" -#include "llcallingcard.h" //for LLAvatarTracker +#include "llagent.h" #include "llagentdata.h" #include "llavataractions.h" +#include "llavatariconctrl.h" +#include "llcallingcard.h" //for LLAvatarTracker +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llspeakers.h" //for LLIMSpeakerMgr #include "lltrans.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" @@ -49,7 +53,6 @@ #include "llstylemap.h" #include "llslurl.h" #include "lllayoutstack.h" -#include "llagent.h" #include "llnotificationsutil.h" #include "lltoastnotifypanel.h" #include "lltooltip.h" @@ -61,7 +64,6 @@ #include "llurlaction.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" -#include "llmutelist.h" static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history"); @@ -187,6 +189,161 @@ public: return false; } + void banGroupMember(const LLUUID& participant_uuid) + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return; + } + + gdatap->banMemberById(participant_uuid); + } + + bool canBanInGroup() + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return false; + } + + if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + + return false; + } + + bool canBanGroupMember(const LLUUID& participant_uuid) + { + LLUUID group_uuid = mSessionID; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid); + if (!gdatap) + { + // Not a group + return false; + } + + if (gdatap->mPendingBanRequest) + { + return false; + } + + if (gAgentID == getAvatarId()) + { + //Don't ban self + return false; + } + + if (gdatap->isRoleMemberDataComplete()) + { + if (gdatap->mMembers.size()) + { + LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(participant_uuid); + if (mi != gdatap->mMembers.end()) + { + LLGroupMemberData* member_data = (*mi).second; + // Is the member an owner? + if (member_data && member_data->isInRole(gdatap->mOwnerRole)) + { + return false; + } + + if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + } + } + } + + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(participant_uuid).get(); + + if (speakerp + && gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER) + && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS)) + { + return true; + } + } + + return false; + } + + bool isGroupModerator() + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (!speaker_mgr) + { + LL_WARNS() << "Speaker manager is missing" << LL_ENDL; + return false; + } + + // Is session a group call/chat? + if(gAgent.isInGroup(mSessionID)) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(gAgentID).get(); + + // Is agent a moderator? + return speakerp && speakerp->mIsModerator; + } + + return false; + } + + bool canModerate(const std::string& userdata) + { + // only group moderators can perform actions related to this "enable callback" + if (!isGroupModerator() || gAgentID == getAvatarId()) + { + return false; + } + + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (!speaker_mgr) + { + return false; + } + + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (!speakerp) + { + return false; + } + + bool voice_channel = speakerp->isInVoiceChannel(); + + if ("can_moderate_voice" == userdata) + { + return voice_channel; + } + else if ("can_mute" == userdata) + { + return voice_channel && (speakerp->mStatus != LLSpeaker::STATUS_MUTED); + } + else if ("can_unmute" == userdata) + { + return speakerp->mStatus == LLSpeaker::STATUS_MUTED; + } + else if ("can_allow_text_chat" == userdata) + { + return true; + } + + return false; + } + void onAvatarIconContextMenuItemClicked(const LLSD& userdata) { std::string level = userdata.asString(); @@ -245,11 +402,36 @@ public: } else if(level == "block_unblock") { - mute(getAvatarId(), LLMute::flagVoiceChat); + LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagVoiceChat); } else if(level == "mute_unmute") { - mute(getAvatarId(), LLMute::flagTextChat); + LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagTextChat); + } + else if(level == "toggle_allow_text_chat") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + speaker_mgr->toggleAllowTextChat(getAvatarId()); + } + else if(level == "group_mute") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + speaker_mgr->moderateVoiceParticipant(getAvatarId(), false); + } + } + else if(level == "group_unmute") + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + speaker_mgr->moderateVoiceParticipant(getAvatarId(), true); + } + } + else if(level == "ban_member") + { + banGroupMember(getAvatarId()); } } @@ -265,24 +447,69 @@ public: { return LLMuteList::getInstance()->isMuted(getAvatarId(), LLMute::flagTextChat); } + else if (level == "is_allowed_text_chat") + { + if (gAgent.isInGroup(mSessionID)) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + const LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()); + + if (NULL != speakerp) + { + return !speakerp->mModeratorMutedText; + } + } + return false; + } return false; } - void mute(const LLUUID& participant_id, U32 flags) + bool onAvatarIconContextMenuItemEnabled(const LLSD& userdata) { - BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags); - LLAvatarName av_name; - LLAvatarNameCache::get(participant_id, &av_name); - LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT); + std::string level = userdata.asString(); - if (!is_muted) + if (level == "can_allow_text_chat" || level == "can_mute" || level == "can_unmute") { - LLMuteList::getInstance()->add(mute, flags); + return canModerate(userdata); } - else + else if (level == "can_ban_member") { - LLMuteList::getInstance()->remove(mute, flags); + return canBanGroupMember(getAvatarId()); } + return false; + } + + bool onAvatarIconContextMenuItemVisible(const LLSD& userdata) + { + std::string level = userdata.asString(); + + if (level == "show_mute") + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (speakerp) + { + return speakerp->isInVoiceChannel() && speakerp->mStatus != LLSpeaker::STATUS_MUTED; + } + } + return false; + } + else if (level == "show_unmute") + { + LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get(); + if (speakerp) + { + return speakerp->mStatus == LLSpeaker::STATUS_MUTED; + } + } + return false; + } + return false; } BOOL postBuild() @@ -292,6 +519,8 @@ public: registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); + registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); + registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); @@ -567,9 +796,14 @@ protected: if(menu) { bool is_friend = LLAvatarActions::isFriend(mAvatarID); + bool is_group_session = gAgent.isInGroup(mSessionID); menu->setItemEnabled("Add Friend", !is_friend); menu->setItemEnabled("Remove Friend", is_friend); + menu->setItemVisible("Moderator Options Separator", is_group_session && isGroupModerator()); + menu->setItemVisible("Moderator Options", is_group_session && isGroupModerator()); + menu->setItemVisible("Group Ban Separator", is_group_session && canBanInGroup()); + menu->setItemVisible("BanMember", is_group_session && canBanInGroup()); if(gAgentID == mAvatarID) { diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 3522932d03..333765f99f 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1150,11 +1150,11 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec } else if ("block_unblock" == command) { - toggleMute(userID, LLMute::flagVoiceChat); + LLAvatarActions::toggleMute(userID, LLMute::flagVoiceChat); } else if ("mute_unmute" == command) { - toggleMute(userID, LLMute::flagTextChat); + LLAvatarActions::toggleMute(userID, LLMute::flagTextChat); } else if ("selected" == command || "mute_all" == command || "unmute_all" == command) { @@ -2096,24 +2096,6 @@ void LLFloaterIMContainer::toggleAllowTextChat(const LLUUID& participant_uuid) } } -void LLFloaterIMContainer::toggleMute(const LLUUID& participant_id, U32 flags) -{ - BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags); - - LLAvatarName av_name; - LLAvatarNameCache::get(participant_id, &av_name); - LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT); - - if (!is_muted) - { - LLMuteList::getInstance()->add(mute, flags); - } - else - { - LLMuteList::getInstance()->remove(mute, flags); - } -} - void LLFloaterIMContainer::openNearbyChat() { // If there's only one conversation in the container and that conversation is the nearby chat diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 60cef83d9a..90fc0c2bdd 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -176,7 +176,6 @@ private: void moderateVoiceAllParticipants(bool unmute); void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute); void toggleAllowTextChat(const LLUUID& participant_uuid); - void toggleMute(const LLUUID& participant_id, U32 flags); void banSelectedMember(const LLUUID& participant_uuid); void openNearbyChat(); bool isParticipantListExpanded(); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e5fd126d53..7ee41140f0 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -799,22 +799,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } -U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(id, cats, items, LLInventoryModel::INCLUDE_TRASH); - - U32 items_found = items.size() + cats.size(); - - for (U32 i = 0; i < cats.size() && items_found <= max_item_limit; ++i) - { - items_found += getDescendentsCountRecursive(cats[i]->getUUID(), max_item_limit - items_found); - } - - return items_found; -} - void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { const LLInventoryObject *obj = getObject(object_id); @@ -3321,9 +3305,12 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT LLSD args; if(LLFolderType::FT_TRASH == preferred_type) { - static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity"); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; const LLUUID trash_id = findCategoryUUIDForType(preferred_type); - args["COUNT"] = (S32)getDescendentsCountRecursive(trash_id, trash_max_capacity); + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants + S32 item_count = items.size() + cats.size(); + args["COUNT"] = item_count; } LLNotificationsUtil::add(notification, args, LLSD(), boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type)); @@ -3433,9 +3420,20 @@ bool callback_preview_trash_folder(const LLSD& notification, const LLSD& respons void LLInventoryModel::checkTrashOverflow() { - static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity"); + static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity"); + + // Collect all descendants including those in subfolders. + // + // Note: Do we really need content of subfolders? + // This was made to prevent download of trash folder timeouting + // viewer and sub-folders are supposed to download independently. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (getDescendentsCountRecursive(trash_id, trash_max_capacity) >= trash_max_capacity) + gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + S32 item_count = items.size() + cats.size(); + + if (item_count >= trash_max_capacity) { if (LLFloaterPreviewTrash::isVisible()) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c558c0803b..01e0ed7e9b 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -265,9 +265,6 @@ public: // Follow parent chain to the top. bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; -private: - U32 getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit); - //-------------------------------------------------------------------- // Find //-------------------------------------------------------------------- diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4b117941a0..f9c91312ee 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1217,7 +1217,18 @@ void LLInventoryPanel::purgeSelectedItems() const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList(); if (inventory_selected.empty()) return; LLSD args; - args["COUNT"] = (S32)inventory_selected.size(); + S32 count = inventory_selected.size(); + for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end(); + it != end_it; + ++it) + { + LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID(); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH); + count += items.size() + cats.size(); + } + args["COUNT"] = count; LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(&LLInventoryPanel::callbackPurgeSelectedItems, this, _1, _2)); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 507087d1ae..2dc219a769 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1222,6 +1222,11 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam const LLUUID& obj_id = (*obj_iter); if(!highlight_offered_object(obj_id)) { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH)) + { + gInventory.checkTrashOverflow(); + } continue; } diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml index 410caa7290..05ab4d35a0 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<menu +<toggleable_menu height="101" layout="topleft" left="100" @@ -109,5 +109,43 @@ name="Mute Text"> <on_click function="AvatarIcon.Action" parameter="mute_unmute" /> <on_check function="AvatarIcon.Check" parameter="is_muted" /> - </menu_item_check> -</menu> + </menu_item_check> + <menu_item_separator layout="topleft" name="Moderator Options Separator"/> + <context_menu + label="Moderator Options" + layout="topleft" + name="Moderator Options"> + <menu_item_check + label="Allow text chat" + layout="topleft" + name="AllowTextChat"> + <on_check function="AvatarIcon.Check" parameter="is_allowed_text_chat" /> + <on_click function="AvatarIcon.Action" parameter="toggle_allow_text_chat" /> + <on_enable function="AvatarIcon.Enable" parameter="can_allow_text_chat" /> + </menu_item_check> + <menu_item_call + label="Mute this participant" + layout="topleft" + name="ModerateVoiceMuteSelected"> + <on_click function="AvatarIcon.Action" parameter="group_mute" /> + <on_enable function="AvatarIcon.Enable" parameter="can_mute" /> + <on_visible function="AvatarIcon.Visible" parameter="show_mute" /> + </menu_item_call> + <menu_item_call + label="Unmute this participant" + layout="topleft" + name="ModerateVoiceUnMuteSelected"> + <on_click function="AvatarIcon.Action" parameter="group_unmute" /> + <on_enable function="AvatarIcon.Enable" parameter="can_unmute" /> + <on_visible function="AvatarIcon.Visible" parameter="show_unmute" /> + </menu_item_call> + </context_menu> + <menu_item_separator layout="topleft" name="Group Ban Separator"/> + <menu_item_call + label="Ban member" + layout="topleft" + name="BanMember"> + <on_click function="AvatarIcon.Action" parameter="ban_member" /> + <on_enable function="AvatarIcon.Enable" parameter="can_ban_member" /> + </menu_item_call> +</toggleable_menu> |