diff --git a/.hgtags b/.hgtags
index bf77143bf1..e6be1cb17d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -335,3 +335,4 @@ fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2
af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169
4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3
6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release
+0c8f23b2c4cf96d1a08bd527b3ccb6339a9fdb60 RLVa-1.4.6
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index edee3ac94b..0211774929 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1507,7 +1507,8 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
// pushWearable(type,new_wearable);
// }
// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
- else if ( (!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.hasLockedWearable(type)) || (!remove) )
+ else if ( (!rlv_handler_t::isEnabled()) || (!remove) ||
+ ((gRlvWearableLocks.canWear(type)) && (!gRlvWearableLocks.hasLockedWearable(type))) )
{
// Sanity check: there shouldn't be any worn wearables for this type the first time we encounter it
RLV_ASSERT( (!remove) || (0 != idxCurPerType[type]) || (0 == getWearableCount(type)) );
@@ -1521,7 +1522,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
{
// Skip adding if @addoutfit=n restricted *unless* the wearable made it into COF [see LLAppMgr::updateAgentWearables()]
if ( (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(type)) &&
- (!gInventory.isObjectDescendentOf(new_item->getUUID(), LLAppearanceMgr::instance().getCOF())) )
+ (!LLAppearanceMgr::instance().isLinkInCOF(new_wearable->getItemID())) )
{
continue;
}
diff --git a/indra/newview/llpanelappearancetab.cpp b/indra/newview/llpanelappearancetab.cpp
index 8fa8867c69..fdb331163b 100644
--- a/indra/newview/llpanelappearancetab.cpp
+++ b/indra/newview/llpanelappearancetab.cpp
@@ -32,6 +32,10 @@
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llviewerinventory.h"
+// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7)
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
//virtual
bool LLPanelAppearanceTab::canTakeOffSelected()
@@ -46,6 +50,11 @@ bool LLPanelAppearanceTab::canTakeOffSelected()
LLViewerInventoryItem* item = gInventory.getItem(*it);
if (!item) continue;
+// [RLVa:KB] - Checked: 2012-07-08 (RLVa-1.4.7)
+ if ( (rlv_handler_t::isEnabled()) && (rlvPredCanNotRemoveItem(item)) )
+ return false;
+// [/RLVa:KB]
+
if (is_worn(NULL, item)) return true;
}
return false;
diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp
index ef7f51242a..a25a4450f6 100644
--- a/indra/newview/llpanelwearing.cpp
+++ b/indra/newview/llpanelwearing.cpp
@@ -40,6 +40,10 @@
#include "llwearableitemslist.h"
#include "llsdserialize.h"
#include "llclipboard.h"
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+// [/RLVa:KB]
// Context menu and Gear menu helper.
static void edit_outfit()
@@ -144,6 +148,9 @@ protected:
bool bp_selected = false; // true if body parts selected
bool clothes_selected = false;
bool attachments_selected = false;
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ S32 rlv_locked_count = 0;
+// [/RLVa:KB]
// See what types of wearables are selected.
for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it)
@@ -169,9 +176,18 @@ protected:
{
attachments_selected = true;
}
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(item)) )
+ {
+ rlv_locked_count++;
+ }
+// [/RLVa:KB]
}
// Enable/disable some menu items depending on the selection.
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ bool rlv_blocked = (mUUIDs.size() == rlv_locked_count);
+// [/RLVa:KB]
bool allow_detach = !bp_selected && !clothes_selected && attachments_selected;
bool allow_take_off = !bp_selected && clothes_selected && !attachments_selected;
@@ -184,6 +200,10 @@ protected:
// [SL:KB] - Patch: Inventory-AttachmentEdit - Checked: 2010-09-04 (Catznip-2.2.0a) | Added: Catznip-2.1.2a
menu->setItemVisible("take_off_or_detach", (!allow_detach) && (!allow_take_off) && (clothes_selected) && (attachments_selected));
// [/SL:KB]
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ menu->setItemEnabled("take_off", !rlv_blocked);
+ menu->setItemEnabled("detach", !rlv_blocked);
+// [/RLVa:KB]
menu->setItemVisible("edit_outfit_separator", allow_take_off || allow_detach);
}
};
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 72d58f759d..c2aae813ee 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -6831,7 +6831,11 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
std::string perms;
for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
{
- if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && SCRIPT_QUESTION_IS_CAUTION[i])
+// if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && SCRIPT_QUESTION_IS_CAUTION[i])
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ if ( (orig_questions & LSCRIPTRunTimePermissionBits[i]) &&
+ ((SCRIPT_QUESTION_IS_CAUTION[i]) || (notification["payload"]["rlv_notify"].asBoolean())) )
+// [/RLVa:KB]
{
count++;
caution = TRUE;
@@ -6851,11 +6855,25 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
// log a chat message as long as at least one requested permission
// is a caution permission
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
if (caution)
{
- LLChat chat(notice.getString());
- // LLFloaterChat::addChat(chat, FALSE, FALSE);
+ LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
+ if(nearby_chat)
+ {
+ LLChat chat_msg(notice.getString());
+ chat_msg.mFromName = SYSTEM_FROM;
+ chat_msg.mFromID = LLUUID::null;
+ chat_msg.mSourceType = CHAT_SOURCE_SYSTEM;
+ nearby_chat->addMessage(chat_msg);
+ }
}
+// [/RLVa:KB]
+// if (caution)
+// {
+// LLChat chat(notice.getString());
+// // LLFloaterChat::addChat(chat, FALSE, FALSE);
+// }
}
}
@@ -6901,12 +6919,22 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
// only log a chat message if caution prompts are enabled
- if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+// if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ if ( (gSavedSettings.getBOOL("PermissionsCautionEnabled")) || (notification["payload"]["rlv_notify"].asBoolean()) )
+// [/RLVa:KB]
{
// log a chat message, if appropriate
notify_cautioned_script_question(notification, response, orig, allowed);
}
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ if ( (allowed) && (notification["payload"].has("rlv_blocked")) )
+ {
+ RlvUtil::notifyBlocked(notification["payload"]["rlv_blocked"], LLSD().with("OBJECT", notification["payload"]["object_name"]));
+ }
+// [/RLVa:KB]
+
if ( response["Mute"] ) // mute
{
LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT));
@@ -7037,42 +7065,44 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
payload["object_name"] = object_name;
payload["owner_name"] = owner_name;
-// [RLVa:KB] - Checked: 2011-07-25 (RLVa-1.4.0a) | Added: RLVa-1.4.0a
- if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canAttach()) )
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ if (rlv_handler_t::isEnabled())
{
- // If only the attachment permission is requested we'll auto-deny it; otherwise let the user decide over remaining permissions
- if (LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH] == questions)
+ if ( (!gRlvAttachmentLocks.canAttach()) && (LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH] & questions) )
{
- RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_PERMATTACH, LLSD().with("OBJECT", object_name));
- LLNotifications::instance().forceResponse(
- LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 1/*NO*/);
- return;
+ // Notify the user that we blocked it since they're not allowed to wear any new attachments
+ payload["rlv_blocked"] = RLV_STRING_BLOCKED_PERMATTACH;
+ // If only attach is requested we'll auto-deny it; otherwise let the user decide over remaining permissions
+ if (LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH] == questions)
+ {
+ payload["questions"] = 0;
+ LLNotifications::instance().forceResponse(
+ LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/);
+ return;
+ }
+ else
+ {
+ questions &= ~LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH];
+ payload["questions"] = questions;
+ }
}
- else
- {
- questions &= ~LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH];
- payload["questions"] = questions;
- }
- }
-// [/RLVa:KB]
-// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0e
- // FIRE-6762: Automatically grant sit permissions if same owner
- S32 questionsOther = questions;
- // FIRE-6762
- if (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION))
- {
- const LLViewerObject* pObj = gObjectList.findObject(taskid);
- if (pObj)
+ if (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION))
{
-// if (pObj->permYouOwner())
-// {
- // PERMISSION_TAKE_CONTROLS and PERMISSION_ATTACH are only auto-granted to objects this avie owns
- // FIRE-6762: Automatically grant sit permissions if same owner
- questionsOther &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] |
- // FIRE-6762
- LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]);
-// }
+ const LLViewerObject* pObj = gObjectList.findObject(taskid);
+ if (pObj)
+ {
+ if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) )
+ {
+ questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] |
+ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]);
+ }
+ else
+ {
+ questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS]);
+ }
+ payload["rlv_notify"] = !pObj->permYouOwner();
+ }
}
}
// [SA] Same automatic permissions for the objects owned by the owner of the object the avatar is sat on.
@@ -7081,7 +7111,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
{
if (gAgentAvatarp->isSitting() && LLCacheName::cleanFullName(owner_name) == gSitOwnerName)
{
- questionsOther &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] |
+ questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] |
LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TRIGGER_ANIMATION] |
LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TRACK_CAMERA] |
LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_CONTROL_CAMERA]);
@@ -7096,7 +7126,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
}
// FIRE-6762
// [/SA]
- if ( (!caution) && (!questionsOther) )
+ if ( (!caution) && (!questions) )
{
LLNotifications::instance().forceResponse(
LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/);
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 778461690e..5209ed763c 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -180,6 +180,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
const LLPCode pcode,
LLViewerRegion* regionp) :
LLVOAvatar(id, pcode, regionp),
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ mAttachmentSignal(NULL),
+// [/RLVa:KB]
mScreenp(NULL),
mLastRegionHandle(0),
mRegionCrossingCount(0),
@@ -799,6 +802,10 @@ void LLVOAvatarSelf::cleanup()
LLVOAvatarSelf::~LLVOAvatarSelf()
{
cleanup();
+
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ delete mAttachmentSignal;
+// [/RLVa:KB]
}
/**
@@ -1408,6 +1415,14 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id)
return NULL;
}
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+boost::signals2::connection LLVOAvatarSelf::setAttachmentCallback(const attachment_signal_t::slot_type& cb)
+{
+ if (!mAttachmentSignal)
+ mAttachmentSignal = new attachment_signal_t();
+ return mAttachmentSignal->connect(cb);
+}
+// [/RLVa:KB]
// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& idItem) const
{
@@ -1474,6 +1489,10 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
// NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject()
+ if (mAttachmentSignal)
+ {
+ (*mAttachmentSignal)(viewer_object, attachment, ACTION_ATTACH);
+ }
if (rlv_handler_t::isEnabled())
{
RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment);
@@ -1515,6 +1534,10 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt);
gRlvHandler.onDetach(viewer_object, pAttachPt);
}
+ if (mAttachmentSignal)
+ {
+ (*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH);
+ }
//-TT Client LSL Bridge
if (pAttachPt->getName() == "Bridge" && gSavedSettings.getBOOL("UseLSLBridge"))
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 0e52fbb5a6..74127649cd 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -313,9 +313,17 @@ public:
/*virtual*/ BOOL detachObject(LLViewerObject *viewer_object);
static BOOL detachAttachmentIntoInventory(const LLUUID& item_id);
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ enum EAttachAction { ACTION_ATTACH, ACTION_DETACH };
+ typedef boost::signals2::signal attachment_signal_t;
+ boost::signals2::connection setAttachmentCallback(const attachment_signal_t::slot_type& cb);
+// [/RLVa:KB]
private:
// Track attachments that have been requested but have not arrived yet.
mutable std::map mAttachmentRequests;
+// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
+ attachment_signal_t* mAttachmentSignal;
+// [/RLVa:KB]
//--------------------------------------------------------------------
// HUDs
diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp
index 2a02e699a8..79e364ff22 100644
--- a/indra/newview/rlvcommon.cpp
+++ b/indra/newview/rlvcommon.cpp
@@ -224,6 +224,8 @@ const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet)
return "unset";
case RLV_RET_SUCCESS_DUPLICATE:
return "duplicate";
+ case RLV_RET_SUCCESS_DELAYED:
+ return "delayed";
case RLV_RET_FAILED_SYNTAX:
return "thingy error";
case RLV_RET_FAILED_OPTION:
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 3dfb07db7f..9d1eb4f2f1 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -66,7 +66,7 @@ const S32 RLV_VERSION_BUILD = 0;
// Implementation version
const S32 RLVa_VERSION_MAJOR = 1;
const S32 RLVa_VERSION_MINOR = 4;
-const S32 RLVa_VERSION_PATCH = 6;
+const S32 RLVa_VERSION_PATCH = 7;
const S32 RLVa_VERSION_BUILD = 0;
// Uncomment before a final release
@@ -245,6 +245,7 @@ enum ERlvCmdRet {
RLV_RET_SUCCESS = 0x0100, // Command executed succesfully
RLV_RET_SUCCESS_UNSET, // Command executed succesfully (RLV_TYPE_REMOVE for an unrestricted behaviour)
RLV_RET_SUCCESS_DUPLICATE, // Command executed succesfully (RLV_TYPE_ADD for an already restricted behaviour)
+ RLV_RET_SUCCESS_DELAYED, // Command parsed valid but will execute at a later time
RLV_RET_FAILED = 0x0200, // Command failed (general failure)
RLV_RET_FAILED_SYNTAX, // Command failed (syntax error)
RLV_RET_FAILED_OPTION, // Command failed (invalid option)
diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp
index 51d8319c90..3fd2ac27ae 100644
--- a/indra/newview/rlvfloaters.cpp
+++ b/indra/newview/rlvfloaters.cpp
@@ -15,8 +15,10 @@
*/
#include "llviewerprecompiledheaders.h"
+#include "llappearancemgr.h"
#include "llavatarnamecache.h"
#include "llclipboard.h"
+#include "llinventoryfunctions.h"
#include "llscrolllistctrl.h"
#include "llviewerjointattachment.h"
#include "llviewerobjectlist.h"
@@ -31,6 +33,35 @@
// Helper functions
//
+// Checked: 2012-07-14 (RLVa-1.4.7)
+std::string rlvGetItemName(const LLViewerInventoryItem* pItem)
+{
+ if ( (pItem) && ((LLAssetType::AT_BODYPART == pItem->getType()) || (LLAssetType::AT_CLOTHING == pItem->getType())) )
+ return llformat("%s (%s)", pItem->getName().c_str(), LLWearableType::getTypeName(pItem->getWearableType()).c_str());
+ else if ( (pItem) && (LLAssetType::AT_OBJECT == pItem->getType()) && (isAgentAvatarValid()) )
+ return llformat("%s (%s)", pItem->getName().c_str(), gAgentAvatarp->getAttachedPointName(pItem->getUUID()).c_str());
+ return (pItem) ? pItem->getName() : LLStringUtil::null;
+}
+
+// Checked: 2012-07-14 (RLVa-1.4.7)
+std::string rlvGetItemType(const LLViewerInventoryItem* pItem)
+{
+ if (pItem)
+ {
+ switch (pItem->getType())
+ {
+ case LLAssetType::AT_BODYPART:
+ case LLAssetType::AT_CLOTHING:
+ return "Wearable";
+ case LLAssetType::AT_OBJECT:
+ return "Attachment";
+ default:
+ break;
+ }
+ }
+ return "Unknown";
+}
+
// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g
std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true)
{
@@ -66,6 +97,88 @@ bool rlvGetShowException(ERlvBehaviour eBhvr)
}
}
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvLockMaskToString(ERlvLockMask eLockType)
+{
+ switch (eLockType)
+ {
+ case RLV_LOCK_ADD:
+ return "add";
+ case RLV_LOCK_REMOVE:
+ return "rem";
+ default:
+ return "unknown";
+ }
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockPermissionToString(RlvFolderLocks::ELockPermission eLockPermission)
+{
+ switch (eLockPermission)
+ {
+ case RlvFolderLocks::PERM_ALLOW:
+ return "allow";
+ case RlvFolderLocks::PERM_DENY:
+ return "deny";
+ default:
+ return "unknown";
+ }
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockScopeToString(RlvFolderLocks::ELockScope eLockScope)
+{
+ switch (eLockScope)
+ {
+ case RlvFolderLocks::SCOPE_NODE:
+ return "node";
+ case RlvFolderLocks::SCOPE_SUBTREE:
+ return "subtree";
+ default:
+ return "unknown";
+ }
+}
+
+// Checked: 2012-07-29 (RLVa-1.4.7)
+std::string rlvFolderLockSourceToTarget(RlvFolderLocks::folderlock_source_t lockSource)
+{
+ switch (lockSource.first)
+ {
+ case RlvFolderLocks::ST_ATTACHMENT:
+ {
+ std::string strAttachName = rlvGetItemNameFromObjID(boost::get(lockSource.second));
+ return llformat("Attachment (%s)", strAttachName.c_str());
+ }
+ case RlvFolderLocks::ST_ATTACHMENTPOINT:
+ {
+ const LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(boost::get(lockSource.second));
+ return llformat("Attachment point (%s)", (pAttachPt) ? pAttachPt->getName().c_str() : "Unknown");
+ }
+ case RlvFolderLocks::ST_FOLDER:
+ {
+ return "Folder: ";
+ }
+ case RlvFolderLocks::ST_ROOTFOLDER:
+ {
+ return "Root folder";
+ }
+ case RlvFolderLocks::ST_SHAREDPATH:
+ {
+ const std::string& strPath = boost::get(lockSource.second);
+ return llformat("Shared path (#RLV%s%s)", (!strPath.empty()) ? "/" : "", strPath.c_str());
+ }
+ case RlvFolderLocks::ST_WEARABLETYPE:
+ {
+ const std::string& strTypeName = LLWearableType::getTypeName(boost::get(lockSource.second));
+ return llformat("Wearable type (%s)", strTypeName.c_str());
+ }
+ default:
+ {
+ return "(Unknown)";
+ }
+ }
+}
+
// ============================================================================
// RlvFloaterBehaviours member functions
//
@@ -232,7 +345,7 @@ void RlvFloaterBehaviours::refreshAll()
// RlvFloaterLocks member functions
//
-// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+// Checked: 2010-03-11 (RLVa-1.2.0)
void RlvFloaterLocks::onOpen(const LLSD& sdKey)
{
m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterLocks::onRlvCommand, this, _1, _2));
@@ -240,12 +353,20 @@ void RlvFloaterLocks::onOpen(const LLSD& sdKey)
refreshAll();
}
-// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+// Checked: 2010-03-11 (RLVa-1.2.0)
void RlvFloaterLocks::onClose(bool fQuitting)
{
m_ConnRlvCommand.disconnect();
}
+// Checked: 2012-07-14 (RLVa-1.4.7)
+BOOL RlvFloaterLocks::postBuild()
+{
+ getChild("refresh_btn")->setCommitCallback(boost::bind(&RlvFloaterLocks::refreshAll, this));
+
+ return TRUE;
+}
+
// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
{
@@ -267,12 +388,10 @@ void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
}
}
-// Checked: 2010-03-18 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+// Checked: 2010-03-18 (RLVa-1.2.0)
void RlvFloaterLocks::refreshAll()
{
- LLCtrlListInterface* pLockList = childGetListInterface("lock_list");
- if (!pLockList)
- return;
+ LLScrollListCtrl* pLockList = getChild("lock_list");
pLockList->operateOnAll(LLCtrlListInterface::OP_DELETE);
if (!isAgentAvatarValid())
@@ -361,6 +480,76 @@ void RlvFloaterLocks::refreshAll()
pLockList->addElement(sdRow, ADD_BOTTOM);
}
+
+ //
+ // List "nostrip" (soft) locks
+ //
+ sdColumns[1]["value"] = "nostrip";
+ sdColumns[3]["value"] = "(Agent)";
+
+ LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+ LLFindWearablesEx f(true, true);
+ gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, FALSE, f);
+
+ for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+ {
+ const LLViewerInventoryItem* pItem = *itItem;
+ if (!RlvForceWear::instance().isStrippable(pItem->getUUID()))
+ {
+ sdColumns[0]["value"] = rlvGetItemType(pItem);
+ sdColumns[2]["value"] = rlvGetItemName(pItem);
+
+ pLockList->addElement(sdRow, ADD_BOTTOM);
+ }
+ }
+
+ //
+ // List folder locks
+ //
+ {
+ // Folder lock descriptors
+ const RlvFolderLocks::folderlock_list_t& folderLocks = RlvFolderLocks::instance().getFolderLocks();
+ for (RlvFolderLocks::folderlock_list_t::const_iterator itFolderLock = folderLocks.begin();
+ itFolderLock != folderLocks.end(); ++itFolderLock)
+ {
+ const RlvFolderLocks::folderlock_descr_t* pLockDescr = *itFolderLock;
+ if (pLockDescr)
+ {
+ sdColumns[0]["value"] = "Folder Descriptor";
+ sdColumns[1]["value"] =
+ rlvLockMaskToString(pLockDescr->eLockType) + "/" +
+ rlvFolderLockPermissionToString(pLockDescr->eLockPermission) + "/" +
+ rlvFolderLockScopeToString(pLockDescr->eLockScope);
+ sdColumns[2]["value"] = rlvFolderLockSourceToTarget(pLockDescr->lockSource);
+ sdColumns[3]["value"] = rlvGetItemNameFromObjID(pLockDescr->idRlvObj);
+
+ pLockList->addElement(sdRow, ADD_BOTTOM);
+ }
+ }
+ }
+
+ {
+ // Folder locked attachments and wearables
+ uuid_vec_t idItems;
+ const uuid_vec_t& folderLockAttachmentsIds = RlvFolderLocks::instance().getAttachmentLookups();
+ idItems.insert(idItems.end(), folderLockAttachmentsIds.begin(), folderLockAttachmentsIds.end());
+ const uuid_vec_t& folderLockWearabels = RlvFolderLocks::instance().getWearableLookups();
+ idItems.insert(idItems.end(), folderLockWearabels.begin(), folderLockWearabels.end());
+
+ for (uuid_vec_t::const_iterator itItemId = idItems.begin(); itItemId != idItems.end(); ++itItemId)
+ {
+ const LLViewerInventoryItem* pItem = gInventory.getItem(*itItemId);
+ if (pItem)
+ {
+ sdColumns[0]["value"] = rlvGetItemType(pItem);
+ sdColumns[1]["value"] = rlvLockMaskToString(RLV_LOCK_REMOVE);
+ sdColumns[2]["value"] = rlvGetItemName(pItem);
+ sdColumns[3]["value"] = "";
+
+ pLockList->addElement(sdRow, ADD_BOTTOM);
+ }
+ }
+ }
}
// ============================================================================
diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h
index 82cb156009..cc8a644dc7 100644
--- a/indra/newview/rlvfloaters.h
+++ b/indra/newview/rlvfloaters.h
@@ -71,19 +71,15 @@ private:
* LLFloater overrides
*/
public:
- virtual void onOpen(const LLSD& sdKey);
- virtual void onClose(bool fQuitting);
-
- /*
- * Event handlers
- */
-protected:
- void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
+ /*virtual*/ void onOpen(const LLSD& sdKey);
+ /*virtual*/ void onClose(bool fQuitting);
+ /*virtual*/ BOOL postBuild();
/*
* Member functions
*/
protected:
+ void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
void refreshAll();
/*
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index 0e85efe212..39ccae1d98 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -1645,15 +1645,9 @@ ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
case RLV_BHVR_ATTACHALLTHISOVER:
case RLV_BHVR_DETACHALLTHIS:
{
- RlvCommandOptionGetPath rlvGetPathOption(rlvCmd);
+ RlvCommandOptionGetPath rlvGetPathOption(rlvCmd, boost::bind(&RlvHandler::onForceWearCallback, this, _1, rlvCmd.getBehaviourType()));
VERIFY_OPTION(rlvGetPathOption.isValid());
-
- LLInventoryModel::cat_array_t folders;
- if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders))
- {
- for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
- onForceWear(folders.get(idxFolder), rlvCmd.getBehaviourType());
- }
+ eRet = (!rlvGetPathOption.isCallback()) ? RLV_RET_SUCCESS : RLV_RET_SUCCESS_DELAYED;
}
break;
case RLV_BHVR_DETACHME: // @detachme=force - Checked: 2010-09-04 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
@@ -1811,6 +1805,20 @@ ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, ERl
return RLV_RET_SUCCESS;
}
+void RlvHandler::onForceWearCallback(const uuid_vec_t& idItems, ERlvBehaviour eBhvr) const
+{
+ LLInventoryModel::cat_array_t folders;
+ if (RlvInventory::instance().getPath(idItems, folders))
+ {
+ for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+ onForceWear(folders.get(idxFolder), eBhvr);
+
+ // If we're not executing a command then we're a delayed callback and need to manually call done()
+ if ( (!getCurrentCommand()) && (RlvForceWear::instanceExists()) )
+ RlvForceWear::instance().done();
+ }
+}
+
// ============================================================================
// Command handlers (RLV_TYPE_REPLY)
//
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
index d1d0c319d4..f04bd0df8d 100644
--- a/indra/newview/rlvhandler.h
+++ b/indra/newview/rlvhandler.h
@@ -173,6 +173,7 @@ protected:
ERlvCmdRet onForceGroup(const RlvCommand& rlvCmd) const;
ERlvCmdRet onForceSit(const RlvCommand& rlvCmd) const;
ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const;
+ void onForceWearCallback(const uuid_vec_t& idItems, ERlvBehaviour eBhvr) const;
// Command handlers (RLV_TYPE_REPLY)
ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const;
ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const;
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
index d506250701..402d7eddcc 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -210,8 +210,52 @@ RlvCommandOptionGeneric::RlvCommandOptionGeneric(const std::string& strOption)
m_fValid = true;
}
+// Checked: 2012-07-28 (RLVa-1.4.7)
+class RlvCommandOptionGetPathCallback
+{
+public:
+ RlvCommandOptionGetPathCallback(const LLUUID& idAttachObj, RlvCommandOptionGetPath::getpath_callback_t cb)
+ : mObjectId(idAttachObj), mCallback(cb)
+ {
+ if (isAgentAvatarValid())
+ mAttachmentConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(&RlvCommandOptionGetPathCallback::onAttachment, this, _1, _3));
+ gIdleCallbacks.addFunction(&onIdle, this);
+ }
+
+ ~RlvCommandOptionGetPathCallback()
+ {
+ if (mAttachmentConnection.connected())
+ mAttachmentConnection.disconnect();
+ gIdleCallbacks.deleteFunction(&onIdle, this);
+ }
+
+ void onAttachment(LLViewerObject* pAttachObj, LLVOAvatarSelf::EAttachAction eAction)
+ {
+ if ( (LLVOAvatarSelf::ACTION_ATTACH == eAction) && (pAttachObj->getID() == mObjectId) )
+ {
+ uuid_vec_t idItems(1, pAttachObj->getAttachmentItemID());
+ mCallback(idItems);
+ delete this;
+ }
+ }
+
+ static void onIdle(void* pData)
+ {
+ RlvCommandOptionGetPathCallback* pInstance = reinterpret_cast(pData);
+ if (pInstance->mExpirationTimer.getElapsedTimeF32() > 30.0f)
+ delete pInstance;
+ }
+
+protected:
+ LLUUID mObjectId;
+ RlvCommandOptionGetPath::getpath_callback_t mCallback;
+ boost::signals2::connection mAttachmentConnection;
+ LLFrameTimer mExpirationTimer;
+};
+
// Checked: 2010-11-30 (RLVa-1.3.0b) | Modified: RLVa-1.3.0b
-RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd)
+RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb)
+ : m_fCallback(false)
{
m_fValid = true; // Assume the option will be a valid one until we find out otherwise
@@ -228,12 +272,27 @@ RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd)
else if (rlvCmdOption.isEmpty()) // ... or it can be empty (in which case we act on the object that issued the command)
{
const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID());
- if ( (pObj) || (pObj->isAttachment()) )
- m_idItems.push_back(pObj->getAttachmentItemID());
+ if (pObj)
+ {
+ if (pObj->isAttachment())
+ m_idItems.push_back(pObj->getAttachmentItemID());
+ }
+ else if (!cb.empty())
+ {
+ new RlvCommandOptionGetPathCallback(rlvCmd.getObjectID(), cb);
+ m_fCallback = true;
+ return;
+ }
}
else // ... but anything else isn't a valid option
{
m_fValid = false;
+ return;
+ }
+
+ if (!cb.empty())
+ {
+ cb(getItemIDs());
}
}
@@ -437,6 +496,9 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAc
RlvWearableItemCollector f(pFolder, eAction, eFlags);
gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f, TRUE);
+ // TRUE if we've already encountered this LLWearableType::EType (used only on wear actions and only for AT_CLOTHING)
+ bool fSeenWType[LLWearableType::WT_COUNT] = { false };
+
EWearAction eCurAction = eAction;
for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
{
@@ -450,6 +512,8 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAc
// Each folder can specify its own EWearAction override
if (isWearAction(eAction))
eCurAction = f.getWearAction(pRlvItem->getParentUUID());
+ else
+ eCurAction = eAction;
// NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending)
// * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn
@@ -460,6 +524,10 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAc
case LLAssetType::AT_CLOTHING:
if (isWearAction(eAction))
{
+ // The first time we encounter any given clothing type we use 'eCurAction' (replace or add)
+ // The second time we encounter a given clothing type we'll always add (rather than replace the previous iteration)
+ eCurAction = (!fSeenWType[pItem->getWearableType()]) ? eCurAction : ACTION_WEAR_ADD;
+
ERlvWearMask eWearMask = gRlvWearableLocks.canWear(pRlvItem);
if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) ||
((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) )
@@ -467,6 +535,7 @@ void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAc
// The check for whether we're replacing a currently worn composite item happens in onWearableArrived()
if (!isAddWearable(pItem))
addWearable(pRlvItem, eCurAction);
+ fSeenWType[pItem->getWearableType()] = true;
}
}
else
@@ -698,13 +767,15 @@ bool RlvForceWear::isStrippable(const LLInventoryItem* pItem)
}
LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
- while ( (pFolder) && (gInventory.getRootFolderID() != pFolder->getParentUUID()) )
+ while (pFolder)
{
if (std::string::npos != pFolder->getName().find(RLV_FOLDER_FLAG_NOSTRIP))
return false;
// If the item's parent is a folded folder then we need to check its parent as well
- pFolder =
- (RlvInventory::isFoldedFolder(pFolder, true)) ? gInventory.getCategory(pFolder->getParentUUID()) : NULL;
+ if ( (gInventory.getRootFolderID() != pFolder->getParentUUID()) && (RlvInventory::isFoldedFolder(pFolder, true)) )
+ pFolder = gInventory.getCategory(pFolder->getParentUUID());
+ else
+ pFolder = NULL;
}
}
return true;
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
index cb0275e375..2cf44f3de1 100644
--- a/indra/newview/rlvhelper.h
+++ b/indra/newview/rlvhelper.h
@@ -137,8 +137,10 @@ protected:
struct RlvCommandOptionGetPath : public RlvCommandOption
{
- RlvCommandOptionGetPath(const RlvCommand& rlvCmd);
+ typedef boost::function getpath_callback_t;
+ RlvCommandOptionGetPath(const RlvCommand& rlvCmd, getpath_callback_t cb = NULL);
+ bool isCallback() const { return m_fCallback; }
/*virtual*/ bool isEmpty() const { return m_idItems.empty(); }
const uuid_vec_t& getItemIDs() const { return m_idItems; }
@@ -146,6 +148,7 @@ struct RlvCommandOptionGetPath : public RlvCommandOption
static bool getItemIDs(LLWearableType::EType wtType, uuid_vec_t& idItems, bool fClear = true);
protected:
+ bool m_fCallback; // TRUE if a callback is schedueled
uuid_vec_t m_idItems;
};
diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h
index 2dbfa4f082..31b4d23cc9 100644
--- a/indra/newview/rlvlocks.h
+++ b/indra/newview/rlvlocks.h
@@ -297,7 +297,7 @@ public:
// Specifies options for the folder lock
enum ELockPermission { PERM_ALLOW = 0x1, PERM_DENY = 0x2, PERM_MASK_ANY = 0x3 };
enum ELockScope { SCOPE_NODE, SCOPE_SUBTREE } ;
-protected:
+
struct folderlock_descr_t
{
LLUUID idRlvObj;
@@ -360,9 +360,14 @@ protected:
/*
* Member variables
*/
+public:
+ typedef std::list folderlock_list_t;
+ // Accessors for RlvFloaterLocks
+ const folderlock_list_t& getFolderLocks() { return m_FolderLocks; }
+ const uuid_vec_t& getAttachmentLookups() { return m_LockedAttachmentRem; }
+ const uuid_vec_t& getWearableLookups() { return m_LockedWearableRem; }
protected:
// Map of folder locks (idRlvObj -> lockDescr)
- typedef std::list folderlock_list_t;
folderlock_list_t m_FolderLocks; // List of add and remove locked folder descriptions
S32 m_cntLockAdd; // Number of RLV_LOCK_ADD locked folders in m_FolderLocks
S32 m_cntLockRem; // Number of RLV_LOCK_REMOVE locked folders in m_FolderLocks
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
index 0f2c9642fe..88f131bcd8 100644
--- a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
+++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
@@ -1,43 +1,64 @@
-
-
-
-
-
-
+ single_instance="true"
+ title="Active RLV Locks"
+ width="500">
+
+
+
+
+
+
+
+
+
+