/** * @file llfloatergroups.cpp * @brief LLPanelGroups class implementation * * $LicenseInfo:firstyear=2002&license=viewergpl$ * * Copyright (c) 2002-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ /* * Shown from Edit -> Groups... * Shows the agent's groups and allows the edit window to be invoked. * Also overloaded to allow picking of a single group for assigning * objects and land to groups. */ #include "llviewerprecompiledheaders.h" #include "llfloatergroups.h" #include "llfloatergroupinvite.h" #include "message.h" #include "roles_constants.h" #include "hbfloatergrouptitles.h" #include "llagent.h" #include "llbutton.h" #include "llfloatergroupinfo.h" #include "llfloaterdirectory.h" #include "llfocusmgr.h" #include "llalertdialog.h" #include "llselectmgr.h" #include "llscrolllistctrl.h" #include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llimview.h" #include "hippoLimits.h" // static std::map LLFloaterGroupPicker::sInstances; // helper functions void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, const std::string& none_text, bool group_picker, U64 powers_mask = GP_ALL_POWERS); ///---------------------------------------------------------------------------- /// Class LLFloaterGroupPicker ///---------------------------------------------------------------------------- // static LLFloaterGroupPicker* LLFloaterGroupPicker::findInstance(const LLSD& seed) { instance_map_t::iterator found_it = sInstances.find(seed.asUUID()); if (found_it != sInstances.end()) { return found_it->second; } return NULL; } // static LLFloaterGroupPicker* LLFloaterGroupPicker::createInstance(const LLSD &seed) { LLFloaterGroupPicker* pickerp = new LLFloaterGroupPicker(seed); LLUICtrlFactory::getInstance()->buildFloater(pickerp, "floater_choose_group.xml"); return pickerp; } LLFloaterGroupPicker::LLFloaterGroupPicker(const LLSD& seed) : mSelectCallback(NULL), mCallbackUserdata(NULL), mPowersMask(GP_ALL_POWERS) { mID = seed.asUUID(); sInstances.insert(std::make_pair(mID, this)); } LLFloaterGroupPicker::~LLFloaterGroupPicker() { sInstances.erase(mID); } void LLFloaterGroupPicker::setSelectCallback(void (*callback)(LLUUID, void*), void* userdata) { mSelectCallback = callback; mCallbackUserdata = userdata; } void LLFloaterGroupPicker::setPowersMask(U64 powers_mask) { mPowersMask = powers_mask; postBuild(); } BOOL LLFloaterGroupPicker::postBuild() { const std::string none_text = getString("none"); init_group_list(getChild("group list"), gAgent.getGroupID(), none_text, true, mPowersMask); childSetAction("OK", onBtnOK, this); childSetAction("Cancel", onBtnCancel, this); setDefaultBtn("OK"); childSetDoubleClickCallback("group list", onBtnOK); childSetUserData("group list", this); childEnable("OK"); return TRUE; } void LLFloaterGroupPicker::onBtnOK(void* userdata) { LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata; if(self) self->ok(); } void LLFloaterGroupPicker::onBtnCancel(void* userdata) { LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata; if(self) self->close(); } void LLFloaterGroupPicker::ok() { LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list) { group_id = group_list->getCurrentID(); } if(mSelectCallback) { mSelectCallback(group_id, mCallbackUserdata); } close(); } ///---------------------------------------------------------------------------- /// Class LLPanelGroups ///---------------------------------------------------------------------------- //LLEventListener //virtual bool LLPanelGroups::handleEvent(LLPointer event, const LLSD& userdata) { if (event->desc() == "new group") { reset(); return true; } return false; } // Default constructor LLPanelGroups::LLPanelGroups() : LLPanel() { gAgent.addListener(this, "new group"); } LLPanelGroups::~LLPanelGroups() { gAgent.removeListener(this); } // clear the group list, and get a fresh set of info. void LLPanelGroups::reset() { LLCtrlListInterface *group_list = childGetListInterface("group list"); if (group_list) { group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); } childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count())); childSetTextArg("groupcount", "[MAX]", llformat("%d", gHippoLimits->getMaxAgentGroups())); const std::string none_text = getString("none"); init_group_list(getChild("group list"), gAgent.getGroupID(), none_text, false); enableButtons(); } BOOL LLPanelGroups::postBuild() { childSetCommitCallback("group list", onGroupList, this); childSetTextArg("groupcount", "[COUNT]", llformat("%d",gAgent.mGroups.count())); childSetTextArg("groupcount", "[MAX]", llformat("%d", gHippoLimits->getMaxAgentGroups())); const std::string none_text = getString("none"); init_group_list(getChild("group list"), gAgent.getGroupID(), none_text, false); childSetAction("Activate", onBtnActivate, this); childSetAction("Info", onBtnInfo, this); childSetAction("IM", onBtnIM, this); childSetAction("Leave", onBtnLeave, this); childSetAction("Create", onBtnCreate, this); childSetAction("Search...", onBtnSearch, this); childSetAction("Invite...", onBtnInvite, this); childSetAction("Titles...", onBtnTitles, this); setDefaultBtn("IM"); childSetDoubleClickCallback("group list", onBtnIM); childSetUserData("group list", this); reset(); return TRUE; } void LLPanelGroups::enableButtons() { LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list) { group_id = group_list->getCurrentID(); } if(group_id != gAgent.getGroupID()) { childEnable("Activate"); } else { childDisable("Activate"); } if (group_id.notNull()) { childEnable("Info"); childEnable("IM"); childEnable("Leave"); } else { childDisable("Info"); childDisable("IM"); childDisable("Leave"); } if(gAgent.mGroups.count() < gHippoLimits->getMaxAgentGroups()) { childEnable("Create"); } else { childDisable("Create"); } if (group_id.notNull() && gAgent.hasPowerInGroup(group_id, GP_MEMBER_INVITE)) { LLPanelGroups::childEnable("Invite..."); } else { LLPanelGroups::childDisable("Invite..."); } } void LLPanelGroups::onBtnCreate(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->create(); } void LLPanelGroups::onBtnInvite(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->invite(); } void LLPanelGroups::onBtnActivate(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->activate(); } void LLPanelGroups::onBtnInfo(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->info(); } void LLPanelGroups::onBtnIM(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->startIM(); } void LLPanelGroups::onBtnLeave(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->leave(); } void LLPanelGroups::onBtnSearch(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->search(); } void LLPanelGroups::onBtnTitles(void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if(self) self->titles(); } void LLPanelGroups::create() { //llinfos << "LLPanelGroups::create" << llendl; LLFloaterGroupInfo::showCreateGroup(NULL); } void LLPanelGroups::activate() { //llinfos << "LLPanelGroups::activate" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list) { group_id = group_list->getCurrentID(); } LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ActivateGroup); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addUUIDFast(_PREHASH_GroupID, group_id); gAgent.sendReliableMessage(); } void LLPanelGroups::info() { //llinfos << "LLPanelGroups::info" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { LLFloaterGroupInfo::showFromUUID(group_id); } } void LLPanelGroups::startIM() { //llinfos << "LLPanelFriends::onClickIM()" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { LLGroupData group_data; if (gAgent.getGroupData(group_id, group_data)) { gIMMgr->setFloaterOpen(TRUE); gIMMgr->addSession( group_data.mName, IM_SESSION_GROUP_START, group_id); make_ui_sound("UISndStartIM"); } else { // this should never happen, as starting a group IM session // relies on you belonging to the group and hence having the group data make_ui_sound("UISndInvalidOp"); } } } void LLPanelGroups::leave() { //llinfos << "LLPanelGroups::leave" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { S32 count = gAgent.mGroups.count(); S32 i; for(i = 0; i < count; ++i) { if(gAgent.mGroups.get(i).mID == group_id) break; } if(i < count) { LLSD args; args["GROUP"] = gAgent.mGroups.get(i).mName; LLSD payload; payload["group_id"] = group_id; LLNotifications::instance().add("GroupLeaveConfirmMember", args, payload, callbackLeaveGroup); } } } void LLPanelGroups::search() { LLFloaterDirectory::showGroups(); } void LLPanelGroups::invite() { LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; //if (group_list && (group_id = group_list->getCurrentID()).notNull()) if (group_list) { group_id = group_list->getCurrentID(); } LLFloaterGroupInvite::showForGroup(group_id); } void LLPanelGroups::titles() { HBFloaterGroupTitles::toggle(); } // static bool LLPanelGroups::callbackLeaveGroup(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); LLUUID group_id = notification["payload"]["group_id"].asUUID(); if(option == 0) { LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_LeaveGroupRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_GroupData); msg->addUUIDFast(_PREHASH_GroupID, group_id); gAgent.sendReliableMessage(); } return false; } void LLPanelGroups::onGroupList(LLUICtrl* ctrl, void* userdata) { LLPanelGroups* self = (LLPanelGroups*)userdata; if (self) { self->enableButtons(); // check to see if group checkboxes have changed self->applyChangesToGroups(); } } void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, const std::string& none_text, bool group_picker, U64 powers_mask) { S32 count = gAgent.mGroups.count(); LLUUID id; LLCtrlListInterface *group_list = ctrl->getListInterface(); if (!group_list) return; group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); for(S32 i = 0; i < count; ++i) { id = gAgent.mGroups.get(i).mID; LLGroupData* group_datap = &gAgent.mGroups.get(i); if ((powers_mask == GP_ALL_POWERS) || ((group_datap->mPowers & powers_mask) != 0)) { std::string style = "NORMAL"; if(highlight_id == id) { style = "BOLD"; } // 0 - Group Name // 1 - Group Notices // 2 - Group Chat // 3 - Group Listing in Profile LLSD element; element["id"] = id; element["columns"][0]["column"] = "name"; element["columns"][0]["value"] = group_datap->mName; element["columns"][0]["font"] = "SANSSERIF"; element["columns"][0]["font-style"] = style; if (!group_picker) { LLSD& receive_notices_column = element["columns"][1]; receive_notices_column["column"] = "receive_notices"; receive_notices_column["type"] = "checkbox"; receive_notices_column["value"] = group_datap->mAcceptNotices; LLSD& join_group_chat_column = element["columns"][2]; join_group_chat_column["column"] = "join_group_chat"; join_group_chat_column["type"] = "checkbox"; join_group_chat_column["value"] = !gIMMgr->getIgnoreGroup(id); LLSD& list_in_profile_column = element["columns"][3]; list_in_profile_column["column"] = "list_in_profile"; list_in_profile_column["type"] = "checkbox"; list_in_profile_column["value"] = group_datap->mListInProfile; } group_list->addElement(element, ADD_SORTED); } } // add "none" to list at top std::string style = "NORMAL"; if (highlight_id.isNull()) { style = "BOLD"; } LLSD element; element["id"] = LLUUID::null; element["columns"][0]["column"] = "name"; //UGLY hack to make sure "none" is always on top -- MC element["columns"][0]["value"] = " (" + none_text + ")"; element["columns"][0]["font"] = "SANSSERIF"; element["columns"][0]["font-style"] = style; if (!group_picker) { LLSD& receive_notices_column = element["columns"][1]; receive_notices_column["column"] = "receive_notices"; receive_notices_column["type"] = "checkbox"; receive_notices_column["value"] = FALSE; receive_notices_column["enabled"] = FALSE; LLSD& join_group_chat_column = element["columns"][2]; join_group_chat_column["column"] = "join_group_chat"; join_group_chat_column["type"] = "checkbox"; join_group_chat_column["value"] = FALSE; join_group_chat_column["enabled"] = FALSE; LLSD& list_in_profile_column = element["columns"][3]; list_in_profile_column["column"] = "list_in_profile"; list_in_profile_column["type"] = "checkbox"; list_in_profile_column["value"] = FALSE; list_in_profile_column["enabled"] = FALSE; } group_list->addElement(element, ADD_TOP); group_list->selectByValue(highlight_id); } void LLPanelGroups::applyChangesToGroups() { LLScrollListCtrl* group_list = getChild("group list"); if (group_list) { // just in case we want to allow selecting multiple groups ever -- MC std::vector selected = group_list->getAllSelected(); for (std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) { LLUUID group_id = (*itr)->getValue(); BOOL receive_notices = (*itr)->getColumn(1)->getValue().asBoolean(); BOOL join_group_chat = (*itr)->getColumn(2)->getValue().asBoolean(); BOOL list_in_profile = (*itr)->getColumn(3)->getValue().asBoolean(); LLGroupData group_datap; if (gAgent.getGroupData(group_id, group_datap)) { // notices and profile if ((receive_notices != group_datap.mAcceptNotices) || (list_in_profile != group_datap.mListInProfile)) { gAgent.setUserGroupFlags(group_id, receive_notices, list_in_profile); } // chat if (join_group_chat != (!gIMMgr->getIgnoreGroup(group_id))) { gIMMgr->updateIgnoreGroup(group_id, join_group_chat); } } } } }