summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/llurlentry.cpp3
-rw-r--r--indra/llui/tests/llurlentry_test.cpp4
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llfloaterland.cpp22
-rw-r--r--indra/newview/llgroupactions.cpp66
-rw-r--r--indra/newview/llgroupactions.h7
-rw-r--r--indra/newview/llgroupmgr.cpp9
-rw-r--r--indra/newview/llinspectgroup.cpp367
-rw-r--r--indra/newview/llinspectgroup.h41
-rw-r--r--indra/newview/llpanelgroup.cpp46
-rw-r--r--indra/newview/llpanelgroup.h2
-rw-r--r--indra/newview/llselectmgr.cpp3
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_inspectors.xml30
-rw-r--r--indra/newview/skins/default/xui/en/inspect_group.xml106
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml4
16 files changed, 649 insertions, 65 deletions
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index c1da73fa83..e04ccfbc2f 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -302,10 +302,11 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa
//
// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about
+// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect
//
LLUrlEntryGroup::LLUrlEntryGroup()
{
- mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/about",
+ mPattern = boost::regex("secondlife:///app/group/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_group.xml";
mIcon = "Generic_Group";
diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp
index 468fae2ec5..128cd134c1 100644
--- a/indra/llui/tests/llurlentry_test.cpp
+++ b/indra/llui/tests/llurlentry_test.cpp
@@ -308,6 +308,10 @@ namespace tut
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about",
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");
+ testRegex("Group Url ", r,
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect",
+ "secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect");
+
testRegex("Group Url in text", r,
"XXX secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about XXX",
"secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about");
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 37acdc3cef..c630a56c8d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -240,6 +240,7 @@ set(viewer_SOURCE_FILES
llimview.cpp
llimcontrolpanel.cpp
llinspectavatar.cpp
+ llinspectgroup.cpp
llinspectobject.cpp
llinventorybridge.cpp
llinventoryclipboard.cpp
@@ -709,6 +710,7 @@ set(viewer_HEADER_FILES
llimview.h
llimcontrolpanel.h
llinspectavatar.h
+ llinspectgroup.h
llinspectobject.h
llinventorybridge.h
llinventoryclipboard.h
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index c1031ee437..488d71aa70 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -744,6 +744,7 @@ void LLPanelLandGeneral::refreshNames()
if (!parcel)
{
mTextOwner->setText(LLStringUtil::null);
+ mTextGroup->setText(LLStringUtil::null);
return;
}
@@ -764,6 +765,13 @@ void LLPanelLandGeneral::refreshNames()
}
mTextOwner->setText(owner);
+ std::string group;
+ if (!parcel->getGroupID().isNull())
+ {
+ group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect");
+ }
+ mTextGroup->setText(group);
+
const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
if(auth_buyer_id.notNull())
{
@@ -781,20 +789,6 @@ void LLPanelLandGeneral::refreshNames()
// virtual
void LLPanelLandGeneral::draw()
{
- LLParcel *parcel = mParcel->getParcel();
- if (parcel)
- {
- std::string group;
- if (!parcel->getGroupID().isNull())
- {
- // *TODO: Change to "inspect" when we have group inspectors and
- // move into refreshNames() above
- // group = LLSLURL::buildCommand("group", parcel->getGroupID(), "inspect");
- gCacheName->getGroupName(parcel->getGroupID(), group);
- }
- mTextGroup->setText(group);
- }
-
LLPanel::draw();
}
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index d1cbe96906..220fb3c8a0 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -35,13 +35,14 @@
#include "llgroupactions.h"
+// Viewer includes
#include "llagent.h"
+#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llgroupmgr.h"
#include "llimview.h" // for gIMMgr
#include "llsidetray.h"
-
-#include "llcommandhandler.h"
+#include "llstatusbar.h" // can_afford_transaction()
//
// Globals
@@ -96,6 +97,13 @@ public:
return true;
}
+ if (tokens[1].asString() == "inspect")
+ {
+ LLSD key;
+ key["group_id"] = group_id;
+ LLFloaterReg::showInstance("inspect_group", key);
+ return true;
+ }
return false;
}
};
@@ -108,6 +116,52 @@ void LLGroupActions::search()
}
// static
+void LLGroupActions::join(const LLUUID& group_id)
+{
+ LLGroupMgrGroupData* gdatap =
+ LLGroupMgr::getInstance()->getGroupData(group_id);
+
+ if (gdatap)
+ {
+ S32 cost = gdatap->mMembershipFee;
+ LLSD args;
+ args["COST"] = llformat("%d", cost);
+ LLSD payload;
+ payload["group_id"] = group_id;
+
+ if (can_afford_transaction(cost))
+ {
+ LLNotifications::instance().add("JoinGroupCanAfford", args, payload, onJoinGroup);
+ }
+ else
+ {
+ LLNotifications::instance().add("JoinGroupCannotAfford", args, payload);
+ }
+ }
+ else
+ {
+ llwarns << "LLGroupMgr::getInstance()->getGroupData(" << group_id
+ << ") was NULL" << llendl;
+ }
+}
+
+// static
+bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+
+ if (option == 1)
+ {
+ // user clicked cancel
+ return false;
+ }
+
+ LLGroupMgr::getInstance()->
+ sendGroupMemberJoin(notification["payload"]["group_id"].asUUID());
+ return false;
+}
+
+// static
void LLGroupActions::leave(const LLUUID& group_id)
{
if (group_id.isNull())
@@ -240,6 +294,14 @@ void LLGroupActions::startChat(const LLUUID& group_id)
}
// static
+bool LLGroupActions::isInGroup(const LLUUID& group_id)
+{
+ // *TODO: Move all the LLAgent group stuff into another class, such as
+ // this one.
+ return gAgent.isInGroup(group_id);
+}
+
+// static
bool LLGroupActions::isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id)
{
if(group_id.isNull() || avatar_id.isNull())
diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h
index 9fe1da8af2..74c84d1561 100644
--- a/indra/newview/llgroupactions.h
+++ b/indra/newview/llgroupactions.h
@@ -47,6 +47,9 @@ public:
*/
static void search();
+ /// Join a group. Assumes LLGroupMgr has data for that group already.
+ static void join(const LLUUID& group_id);
+
/**
* Invokes "Leave Group" floater.
*/
@@ -87,6 +90,9 @@ public:
*/
static void startChat(const LLUUID& group_id);
+ /// Returns if the current user is a member of the group
+ static bool isInGroup(const LLUUID& group_id);
+
/**
* Returns true if avatar is in group.
*
@@ -97,6 +103,7 @@ public:
static bool isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id);
private:
+ static bool onJoinGroup(const LLSD& notification, const LLSD& response);
static bool onLeaveGroup(const LLSD& notification, const LLSD& response);
};
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 5e50fad008..01d0f2296a 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -1325,11 +1325,16 @@ void LLGroupMgr::notifyObservers(LLGroupChange gc)
{
for (group_map_t::iterator gi = mGroups.begin(); gi != mGroups.end(); ++gi)
{
+ LLUUID group_id = gi->first;
if (gi->second->mChanged)
{
+ // Copy the map because observers may remove themselves on update
+ observer_multimap_t observers = mObservers;
+
// find all observers for this group id
- observer_multimap_t::iterator oi = mObservers.find(gi->first);
- for (; oi != mObservers.end(); ++oi)
+ observer_multimap_t::iterator oi = observers.lower_bound(group_id);
+ observer_multimap_t::iterator end = observers.upper_bound(group_id);
+ for (; oi != end; ++oi)
{
oi->second->changed(gc);
}
diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp
new file mode 100644
index 0000000000..184d413743
--- /dev/null
+++ b/indra/newview/llinspectgroup.cpp
@@ -0,0 +1,367 @@
+/**
+ * @file llinspectgroup.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llinspectgroup.h"
+
+// viewer files
+#include "llgroupactions.h"
+#include "llgroupmgr.h"
+
+// Linden libraries
+#include "llcontrol.h" // LLCachedControl
+#include "llfloater.h"
+#include "llfloaterreg.h"
+#include "llresmgr.h" // getMonetaryString()
+#include "lltooltip.h" // positionViewNearMouse()
+#include "lltrans.h"
+#include "lluictrl.h"
+
+class LLFetchGroupData;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectGroup
+//////////////////////////////////////////////////////////////////////////////
+
+/// Group Inspector, a small information window used when clicking
+/// on group names in the 2D UI
+class LLInspectGroup : public LLFloater
+{
+ friend class LLFloaterReg;
+
+public:
+ // key["group_id"] - Group ID for which to show information
+ // Inspector will be positioned relative to current mouse position
+ LLInspectGroup(const LLSD& key);
+ virtual ~LLInspectGroup();
+
+ /*virtual*/ void draw();
+
+ // Because floater is single instance, need to re-parse data on each spawn
+ // (for example, inspector about same group but in different position)
+ /*virtual*/ void onOpen(const LLSD& group_id);
+
+ // When closing they should close their gear menu
+ /*virtual*/ void onClose(bool app_quitting);
+
+ // Inspectors close themselves when they lose focus
+ /*virtual*/ void onFocusLost();
+
+ // Update view based on information from group manager
+ void processGroupData();
+
+ // Make network requests for all the data to display in this view.
+ // Used on construction and if avatar id changes.
+ void requestUpdate();
+
+ // Callback for gCacheName to look up group name
+ // Faster than waiting for group properties to return
+ void nameUpdatedCallback(const LLUUID& id,
+ const std::string& first,
+ const std::string& last,
+ BOOL is_group);
+
+ // Button/menu callbacks
+ void onClickViewProfile();
+ void onClickJoin();
+ void onClickLeave();
+
+private:
+ LLUUID mGroupID;
+ // an in-flight network request for group properties
+ // is represented by this object
+ LLFetchGroupData* mPropertiesRequest;
+ LLFrameTimer mCloseTimer;
+ LLFrameTimer mOpenTimer;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// LLFetchGroupData
+//////////////////////////////////////////////////////////////////////////////
+
+// This object represents a pending request for avatar properties information
+class LLFetchGroupData : public LLGroupMgrObserver
+{
+public:
+ // If the inspector closes it will delete the pending request object, so the
+ // inspector pointer will be valid for the lifetime of this object
+ LLFetchGroupData(const LLUUID& group_id, LLInspectGroup* inspector)
+ : LLGroupMgrObserver(group_id),
+ mInspector(inspector)
+ {
+ LLGroupMgr* mgr = LLGroupMgr::getInstance();
+ // register ourselves as an observer
+ mgr->addObserver(this);
+ // send a request
+ mgr->sendGroupPropertiesRequest(group_id);
+ }
+
+ ~LLFetchGroupData()
+ {
+ // remove ourselves as an observer
+ LLGroupMgr::getInstance()->removeObserver(this);
+ }
+
+ void changed(LLGroupChange gc)
+ {
+ if (gc == GC_PROPERTIES)
+ {
+ mInspector->processGroupData();
+ }
+ }
+
+ LLInspectGroup* mInspector;
+};
+
+LLInspectGroup::LLInspectGroup(const LLSD& sd)
+: LLFloater( LLSD() ), // single_instance, doesn't really need key
+ mGroupID(), // set in onOpen()
+ mPropertiesRequest(NULL),
+ mCloseTimer()
+{
+ mCommitCallbackRegistrar.add("InspectGroup.ViewProfile",
+ boost::bind(&LLInspectGroup::onClickViewProfile, this));
+ mCommitCallbackRegistrar.add("InspectGroup.Join",
+ boost::bind(&LLInspectGroup::onClickJoin, this));
+ mCommitCallbackRegistrar.add("InspectGroup.Leave",
+ boost::bind(&LLInspectGroup::onClickLeave, this));
+
+ // can't make the properties request until the widgets are constructed
+ // as it might return immediately, so do it in postBuild.
+}
+
+LLInspectGroup::~LLInspectGroup()
+{
+ // clean up any pending requests so they don't call back into a deleted
+ // view
+ delete mPropertiesRequest;
+ mPropertiesRequest = NULL;
+}
+
+void LLInspectGroup::draw()
+{
+ static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
+ if (mOpenTimer.getStarted())
+ {
+ F32 alpha = clamp_rescale(mOpenTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 0.f, 1.f);
+ LLViewDrawContext context(alpha);
+ LLFloater::draw();
+ if (alpha == 1.f)
+ {
+ mOpenTimer.stop();
+ }
+
+ }
+ else if (mCloseTimer.getStarted())
+ {
+ F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
+ LLViewDrawContext context(alpha);
+ LLFloater::draw();
+ if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
+ {
+ closeFloater(false);
+ }
+ }
+ else
+ {
+ LLFloater::draw();
+ }
+}
+
+
+// Multiple calls to showInstance("inspect_avatar", foo) will provide different
+// LLSD for foo, which we will catch here.
+//virtual
+void LLInspectGroup::onOpen(const LLSD& data)
+{
+ mCloseTimer.stop();
+ mOpenTimer.start();
+
+ mGroupID = data["group_id"];
+
+ // Position the inspector relative to the mouse cursor
+ // Similar to how tooltips are positioned
+ // See LLToolTipMgr::createToolTip
+ if (data.has("pos"))
+ {
+ LLUI::positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger());
+ }
+ else
+ {
+ LLUI::positionViewNearMouse(this);
+ }
+
+ // can't call from constructor as widgets are not built yet
+ requestUpdate();
+}
+
+// virtual
+void LLInspectGroup::onClose(bool app_quitting)
+{
+}
+
+//virtual
+void LLInspectGroup::onFocusLost()
+{
+ // Start closing when we lose focus
+ mCloseTimer.start();
+ mOpenTimer.stop();
+}
+
+void LLInspectGroup::requestUpdate()
+{
+ // Don't make network requests when spawning from the debug menu at the
+ // login screen (which is useful to work on the layout).
+ if (mGroupID.isNull())
+ {
+ return;
+ }
+
+ // Clear out old data so it doesn't flash between old and new
+ getChild<LLUICtrl>("group_name")->setValue("");
+ getChild<LLUICtrl>("group_subtitle")->setValue("");
+ getChild<LLUICtrl>("group_details")->setValue("");
+ getChild<LLUICtrl>("group_cost")->setValue("");
+ // Must have a visible button so the inspector can take focus
+ getChild<LLUICtrl>("leave_btn")->setVisible(true);
+ getChild<LLUICtrl>("join_btn")->setVisible(false);
+
+ // Make a new request for properties
+ delete mPropertiesRequest;
+ mPropertiesRequest = new LLFetchGroupData(mGroupID, this);
+
+ // Name lookup will be faster out of cache, use that
+ gCacheName->get(mGroupID, TRUE,
+ boost::bind(&LLInspectGroup::nameUpdatedCallback,
+ this, _1, _2, _3, _4));
+}
+
+void LLInspectGroup::nameUpdatedCallback(
+ const LLUUID& id,
+ const std::string& first,
+ const std::string& last,
+ BOOL is_group)
+{
+ if (id == mGroupID)
+ {
+ // group names are returned as a first name
+ childSetValue("group_name", LLSD(first) );
+ }
+
+ // Otherwise possibly a request for an older inspector, ignore it
+}
+
+void LLInspectGroup::processGroupData()
+{
+ LLGroupMgrGroupData* data =
+ LLGroupMgr::getInstance()->getGroupData(mGroupID);
+
+ if (data)
+ {
+ // Noun pluralization depends on language
+ std::string lang = LLUI::getLanguage();
+ std::string members =
+ LLTrans::getCountString(lang, "GroupMembers", data->mMemberCount);
+ getChild<LLUICtrl>("group_subtitle")->setValue( LLSD(members) );
+
+ getChild<LLUICtrl>("group_details")->setValue( LLSD(data->mCharter) );
+
+ getChild<LLUICtrl>("group_icon")->setValue( LLSD(data->mInsigniaID) );
+
+ std::string cost;
+ bool is_member = LLGroupActions::isInGroup(mGroupID);
+ if (is_member)
+ {
+ cost = getString("YouAreMember");
+ }
+ else if (data->mOpenEnrollment)
+ {
+ if (data->mMembershipFee == 0)
+ {
+ cost = getString("FreeToJoin");
+ }
+ else
+ {
+ std::string amount =
+ LLResMgr::getInstance()->getMonetaryString(
+ data->mMembershipFee);
+ LLStringUtil::format_map_t args;
+ args["[AMOUNT]"] = amount;
+ cost = getString("CostToJoin", args);
+ }
+ }
+ else
+ {
+ cost = getString("PrivateGroup");
+ }
+ getChild<LLUICtrl>("group_cost")->setValue(cost);
+
+ getChild<LLUICtrl>("join_btn")->setVisible(!is_member);
+ getChild<LLUICtrl>("leave_btn")->setVisible(is_member);
+
+ // Only enable join button if you are allowed to join
+ bool can_join = !is_member && data->mOpenEnrollment;
+ getChild<LLUICtrl>("join_btn")->setEnabled(can_join);
+ }
+
+ // Delete the request object as it has been satisfied
+ delete mPropertiesRequest;
+ mPropertiesRequest = NULL;
+}
+
+void LLInspectGroup::onClickViewProfile()
+{
+ closeFloater();
+ LLGroupActions::show(mGroupID);
+}
+
+void LLInspectGroup::onClickJoin()
+{
+ closeFloater();
+ LLGroupActions::join(mGroupID);
+}
+
+void LLInspectGroup::onClickLeave()
+{
+ closeFloater();
+ LLGroupActions::leave(mGroupID);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// LLInspectGroupUtil
+//////////////////////////////////////////////////////////////////////////////
+void LLInspectGroupUtil::registerFloater()
+{
+ LLFloaterReg::add("inspect_group", "inspect_group.xml",
+ &LLFloaterReg::build<LLInspectGroup>);
+}
diff --git a/indra/newview/llinspectgroup.h b/indra/newview/llinspectgroup.h
new file mode 100644
index 0000000000..dfd5cbcd55
--- /dev/null
+++ b/indra/newview/llinspectgroup.h
@@ -0,0 +1,41 @@
+/**
+ * @file llinspectgroup.h
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 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$
+ */
+
+#ifndef LLINSPECTGROUP_H
+#define LLINSPECTGROUP_H
+
+namespace LLInspectGroupUtil
+{
+ // Register with LLFloaterReg
+ void registerFloater();
+}
+
+#endif
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index 206d8428be..f9e93a1d38 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -33,19 +33,22 @@
#include "llpanelgroup.h"
+// Library includes
#include "llbutton.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
-#include "llviewermessage.h"
#include "lluictrlfactory.h"
+
+// Viewer includes
+#include "llviewermessage.h"
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "llnotifications.h"
#include "llfloaterreg.h"
#include "llfloater.h"
+#include "llgroupactions.h"
#include "llagent.h"
-#include "llstatusbar.h" // can_afford_transaction()
#include "llsidetraypanelcontainer.h"
@@ -274,46 +277,11 @@ void LLPanelGroup::onBtnApply(void* user_data)
LLPanelGroup* self = static_cast<LLPanelGroup*>(user_data);
self->apply();
}
+
void LLPanelGroup::onBtnJoin()
{
lldebugs << "joining group: " << mID << llendl;
-
- LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID);
-
- if (gdatap)
- {
- S32 cost = gdatap->mMembershipFee;
- LLSD args;
- args["COST"] = llformat("%d", cost);
- LLSD payload;
- payload["group_id"] = mID;
-
- if (can_afford_transaction(cost))
- {
- LLNotifications::instance().add("JoinGroupCanAfford", args, payload, LLPanelGroup::joinDlgCB);
- }
- else
- {
- LLNotifications::instance().add("JoinGroupCannotAfford", args, payload);
- }
- }
- else
- {
- llwarns << "LLGroupMgr::getInstance()->getGroupData(" << mID << ") was NULL" << llendl;
- }
-}
-bool LLPanelGroup::joinDlgCB(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
-
- if (option == 1)
- {
- // user clicked cancel
- return false;
- }
-
- LLGroupMgr::getInstance()->sendGroupMemberJoin(notification["payload"]["group_id"].asUUID());
- return false;
+ LLGroupActions::join(mID);
}
void LLPanelGroup::onBtnCancel()
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 628e2389b6..5c7b0ddd06 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -101,8 +101,6 @@ protected:
static void onBtnApply(void*);
static void onBtnRefresh(void*);
- static bool joinDlgCB(const LLSD& notification, const LLSD& response);
-
void reposButton(const std::string& name);
void reposButtons();
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 5630e8a0e9..a7f0ce16d3 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2460,8 +2460,7 @@ BOOL LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name)
BOOL public_owner = (first_id.isNull() && !first_group_owned);
if (first_group_owned)
{
- // *TODO: We don't have group inspectors yet
- name = LLSLURL::buildCommand("group", first_id, "about");
+ name = LLSLURL::buildCommand("group", first_id, "inspect");
}
else if(!public_owner)
{
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 22081f9efa..26498ffc9b 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -109,6 +109,7 @@
#include "llfloaterwindlight.h"
#include "llfloaterworldmap.h"
#include "llinspectavatar.h"
+#include "llinspectgroup.h"
#include "llinspectobject.h"
#include "llmediaremotectrl.h"
#include "llmoveview.h"
@@ -172,6 +173,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInventory>);
LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterInspect>);
LLInspectAvatarUtil::registerFloater();
+ LLInspectGroupUtil::registerFloater();
LLInspectObjectUtil::registerFloater();
LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>);
diff --git a/indra/newview/skins/default/xui/en/floater_test_inspectors.xml b/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
index 2011f57d8b..126bca2074 100644
--- a/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_inspectors.xml
@@ -93,7 +93,9 @@
top_pad="10"
left_delta="0"
height="20"
- width="100"/>
+ width="100"
+ commit_callback.function="ShowGroupInspector"
+ commit_callback.parameter="" />
<button
name="place_btn"
label="Place"
@@ -112,13 +114,35 @@
follows="left|top"
font="SansSerif"
height="20"
- layout="topleft"
left="0"
max_length="65536"
name="slurl"
top_pad="4"
- width="100">
+ width="150">
secondlife:///app/agent/00000000-0000-0000-0000-000000000000/inspect
</text>
+ <text
+ follows="left|top"
+ font="SansSerif"
+ height="20"
+ left="0"
+ max_length="65536"
+ name="slurl_group"
+ top_pad="4"
+ width="150">
+ secondlife:///app/group/00000000-0000-0000-0000-000000000000/inspect
+ </text>
+
+ <text
+ follows="left|top"
+ font="SansSerif"
+ height="20"
+ left="0"
+ max_length="65536"
+ name="slurl_group_about"
+ top_pad="4"
+ width="150">
+ secondlife:///app/group/00000000-0000-0000-0000-000000000000/about
+ </text>
</floater>
diff --git a/indra/newview/skins/default/xui/en/inspect_group.xml b/indra/newview/skins/default/xui/en/inspect_group.xml
new file mode 100644
index 0000000000..d3f599cbbf
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/inspect_group.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater
+ bevel_style="in"
+ bg_opaque_color="MouseGray"
+ can_close="false"
+ can_minimize="false"
+ height="138"
+ layout="topleft"
+ name="inspect_group"
+ single_instance="true"
+ sound_flags="0"
+ visible="true"
+ width="245">
+ <string name="PrivateGroup">Private group</string>
+ <string name="FreeToJoin">Free to join</string>
+ <string name="CostToJoin">L$[AMOUNT] to join</string>
+ <string name="YouAreMember">You are a member</string>
+ <text
+ follows="all"
+ font="SansSerifLargeBold"
+ height="18"
+ left="8"
+ name="group_name"
+ top="5"
+ text_color="white"
+ use_ellipses="true"
+ width="240"
+ word_wrap="false">
+ Grumpity's Grumpy Group of Moose
+ </text>
+ <text
+ follows="all"
+ font="SansSerifSmallBold"
+ text_color="White"
+ height="18"
+ left="8"
+ name="group_subtitle"
+ use_ellipses="true"
+ top_pad="0"
+ width="170">
+ 123 members
+ </text>
+ <text
+ follows="all"
+ height="50"
+ left="8"
+ name="group_details"
+ top_pad="0"
+ width="170"
+ word_wrap="true">
+A group of folks charged with creating a room with a moose.
+Fear the moose! Fear it! And the mongoose too!
+ </text>
+ <text
+ follows="all"
+ height="15"
+ left="8"
+ name="group_cost"
+ top_pad="2"
+ width="170">
+L$123 to join
+ </text>
+ <icon
+ follows="all"
+ height="38"
+ right="-25"
+ mouse_opaque="true"
+ name="group_icon"
+ top="24"
+ width="38" />
+ <button
+ follows="top|left"
+ height="18"
+ image_disabled="ForwardArrow_Disabled"
+ image_selected="ForwardArrow_Press"
+ image_unselected="ForwardArrow_Off"
+ name="view_profile_btn"
+ picture_style="true"
+ right="-8"
+ top="35"
+ left_delta="110"
+ tab_stop="false"
+ width="18" />
+ <button
+ follows="bottom|left"
+ height="23"
+ label="Join"
+ left="8"
+ top="246"
+ name="join_btn"
+ width="100"
+ commit_callback.function="InspectGroup.Join"/>
+ <button
+ follows="bottom|left"
+ height="23"
+ label="Leave"
+ left="8"
+ top="246"
+ name="leave_btn"
+ width="100"
+ commit_callback.function="InspectGroup.Leave"/>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 2a616d8e2f..d13f5dbde3 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1951,6 +1951,10 @@ this texture in your inventory
<string name="AgeDaysA">[COUNT] day</string>
<string name="AgeDaysB">[COUNT] days</string>
<string name="AgeDaysC">[COUNT] days</string>
+ <!-- Group member counts -->
+ <string name="GroupMembersA">[COUNT] member</string>
+ <string name="GroupMembersB">[COUNT] members</string>
+ <string name="GroupMembersC">[COUNT] members</string>
<!-- Account types, see LLAvatarPropertiesProcessor -->
<string name="AcctTypeResident">Resident</string>