// Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags) { // [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items] if (!gAgentWearables.areWearablesLoaded()) { LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); return; } if (!isAgentAvatarValid()) return; // Grab a list of all the items we'll be wearing/attaching LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; 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++) { LLViewerInventoryItem* pRlvItem = items.get(idxItem); LLViewerInventoryItem* pItem = (LLAssetType::AT_LINK == pRlvItem->getActualType()) ? pRlvItem->getLinkedItem() : pRlvItem; // If it's wearable it should be worn on detach // if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) ) // continue; // 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 switch (pItem->getType()) { case LLAssetType::AT_BODYPART: RLV_ASSERT(isWearAction(eAction)); // RlvWearableItemCollector shouldn't be supplying us with body parts on detach 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)) ) { // 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 { const LLViewerWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID()); if ( (pWearable) && (isForceRemovable(pWearable, false)) ) remWearable(pWearable); } break; case LLAssetType::AT_OBJECT: if (isWearAction(eAction)) { ERlvWearMask eWearMask = gRlvAttachmentLocks.canAttach(pRlvItem); if ( ((ACTION_WEAR_REPLACE == eCurAction) && (eWearMask & RLV_WEAR_REPLACE)) || ((ACTION_WEAR_ADD == eCurAction) && (eWearMask & RLV_WEAR_ADD)) ) { if (!isAddAttachment(pRlvItem)) { #ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS // We still need to check whether we're about to replace a currently worn composite item // (which we're not if we're just reattaching an attachment we're already wearing) LLViewerInventoryCategory* pCompositeFolder = NULL; if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && (pAttachPt->getItemID() != pItem->getUUID()) && (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) ) { // If we can't take off the composite folder this item would replace then don't allow it to get attached if (gRlvHandler.canTakeOffComposite(pCompositeFolder)) { forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT); addAttachment(pRlvItem); } } else #endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS { addAttachment(pRlvItem, eCurAction); } } } } else { const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID()); if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) ) remAttachment(pAttachObj); } break; #ifdef RLV_EXTENSION_FORCEWEAR_GESTURES case LLAssetType::AT_GESTURE: if (isWearAction(eAction)) { if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end()) m_addGestures.push_back(pRlvItem); } else { if (std::find_if(m_remGestures.begin(), m_remGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_remGestures.end()) m_remGestures.push_back(pRlvItem); } break; #endif // RLV_EXTENSION_FORCEWEAR_GESTURES default: break; } } }
bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const { // Always check against the clipboard // <FS:Ansariel> FIRE-6714: Don't move objects to trash during cut&paste // Don't hide cut items in inventory //const BOOL passed_clipboard = checkAgainstClipboard(folder_id); const BOOL passed_clipboard = TRUE; // </FS:Ansariel> FIRE-6714: Don't move objects to trash during cut&paste // we're showing all folders, overriding filter if (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS) { return passed_clipboard; } // when applying a filter, matching folders get their contents downloaded first if (isNotDefault() && !gInventory.isCategoryComplete(folder_id)) { LLInventoryModelBackgroundFetch::instance().start(folder_id); } // Marketplace folder filtering const U32 filterTypes = mFilterOps.mFilterTypes; const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE | FILTERTYPE_MARKETPLACE_UNASSOCIATED | FILTERTYPE_MARKETPLACE_LISTING_FOLDER | FILTERTYPE_NO_MARKETPLACE_ITEMS; if (filterTypes & marketplace_filter) { S32 depth = depth_nesting_in_marketplace(folder_id); if (filterTypes & FILTERTYPE_NO_MARKETPLACE_ITEMS) { if (depth >= 0) { return false; } } if (filterTypes & FILTERTYPE_MARKETPLACE_LISTING_FOLDER) { if (depth > 1) { return false; } } if (depth > 0) { LLUUID listing_uuid = nested_parent_id(folder_id, depth); if (filterTypes & FILTERTYPE_MARKETPLACE_ACTIVE) { if (!LLMarketplaceData::instance().getActivationState(listing_uuid)) { return false; } } else if (filterTypes & FILTERTYPE_MARKETPLACE_INACTIVE) { if (!LLMarketplaceData::instance().isListed(listing_uuid) || LLMarketplaceData::instance().getActivationState(listing_uuid)) { return false; } } else if (filterTypes & FILTERTYPE_MARKETPLACE_UNASSOCIATED) { if (LLMarketplaceData::instance().isListed(listing_uuid)) { return false; } } } } // show folder links LLViewerInventoryItem* item = gInventory.getItem(folder_id); if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) { return passed_clipboard; } if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) { // Can only filter categories for items in your inventory // (e.g. versus in-world object contents). const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); if (!cat) return folder_id.isNull(); LLFolderType::EType cat_type = cat->getPreferredType(); if (cat_type != LLFolderType::FT_NONE && (1LL << cat_type & mFilterOps.mFilterCategoryTypes) == U64(0)) return false; } return passed_clipboard; }