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"> + + + + + + + +