diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 8391f3d2f..88c64bde1 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -214,17 +214,16 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_ bool LLAssetType::lookupCanLink(EType asset_type) { //Check that enabling all these other types as linkable doesn't break things. - /*const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); const AssetEntry *entry = dict->lookup(asset_type); if (entry) { return entry->mCanLink; } return false; - */ - return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY || - asset_type == AT_BODYPART || asset_type == AT_GESTURE); + /*return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY || + asset_type == AT_BODYPART || asset_type == AT_GESTURE);*/ } // static diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7c927fd12..577b646ff 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -266,6 +266,7 @@ set(viewer_SOURCE_FILES llframestats.cpp llframestatview.cpp llgesturemgr.cpp + llgiveinventory.cpp llgivemoney.cpp llglsandbox.cpp llgroupmgr.cpp @@ -446,6 +447,7 @@ set(viewer_SOURCE_FILES llviewercamera.cpp llviewercontrol.cpp llviewerdisplay.cpp + llviewerfoldertype.cpp llviewergenericmessage.cpp llviewergesture.cpp #llviewerimage.cpp @@ -735,10 +737,12 @@ set(viewer_HEADER_FILES llfloaterwindlight.h llfloaterworldmap.h llfolderview.h + llfoldervieweventlistener.h llfollowcam.h llframestats.h llframestatview.h llgesturemgr.h + llgiveinventory.h llgivemoney.h llgroupmgr.h llgroupnotify.h @@ -923,6 +927,7 @@ set(viewer_HEADER_FILES llviewercamera.h llviewercontrol.h llviewerdisplay.h + llviewerfoldertype.h llviewergenericmessage.h llviewergesture.h #llviewerimage.h diff --git a/indra/newview/cofmgr.cpp b/indra/newview/cofmgr.cpp index bac05e2ff..3820517ae 100644 --- a/indra/newview/cofmgr.cpp +++ b/indra/newview/cofmgr.cpp @@ -264,7 +264,7 @@ void LLCOFMgr::addCOFItemLink(const LLInventoryItem* pItem, LLPointergetLinkedUUID(), getCOF(), pItem->getName(), strDescr, LLAssetType::AT_LINK, cb); } -bool LLCOFMgr::isLinkInCOF(const LLUUID& idItem) +bool LLCOFMgr::isLinkInCOF(const LLUUID& idItem) const { LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; LLLinkedItemIDMatches f(gInventory.getLinkedItemID(idItem)); @@ -287,6 +287,34 @@ void LLCOFMgr::removeCOFItemLinks(const LLUUID& idItem) } } +BOOL LLCOFMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const +{ + if (!isLinkInCOF(obj_id)) return FALSE; + + // If a non-link somehow ended up in COF, allow deletion. + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && !obj->getIsLinkType()) + { + return FALSE; + } + + // For now, don't allow direct deletion from the COF. Instead, force users + // to choose "Detach" or "Take Off". + return TRUE; + /* + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (!obj) return FALSE; + + // Can't delete bodyparts, since this would be equivalent to removing the item. + if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; + + // Can't delete the folder link, since this is saved for bookkeeping. + if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; + + return FALSE; + */ +} + // ============================================================================ // Attachment functions // diff --git a/indra/newview/cofmgr.h b/indra/newview/cofmgr.h index 10d819001..50d812c68 100644 --- a/indra/newview/cofmgr.h +++ b/indra/newview/cofmgr.h @@ -31,7 +31,8 @@ public: static const LLUUID getCOF() { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); } static void getDescendentsOfAssetType(const LLUUID& idCat, LLInventoryModel::item_array_t& items, LLAssetType::EType typeAsset, bool fFollowFolderLinks); - bool isLinkInCOF(const LLUUID& idItem); + bool isLinkInCOF(const LLUUID& idItem) const; + BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; protected: void addCOFItemLink(const LLUUID& idItem, LLPointer cb = NULL); void addCOFItemLink(const LLInventoryItem* pItem, LLPointer cb = NULL); diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index e35aa57b1..7b41bf74b 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -38,8 +38,10 @@ #include "llagent.h" #include "llbutton.h" #include "llfocusmgr.h" +#include "llfoldervieweventlistener.h" #include "llinventoryview.h" #include "llinventorymodel.h" +#include "llinventoryfunctions.h" #include "lllineeditor.h" #include "llscrolllistctrl.h" #include "lltextbox.h" diff --git a/indra/newview/llfloaterlandmark.cpp b/indra/newview/llfloaterlandmark.cpp index f9b81bbe5..b6dd5bd2a 100644 --- a/indra/newview/llfloaterlandmark.cpp +++ b/indra/newview/llfloaterlandmark.cpp @@ -39,6 +39,7 @@ #include "llcheckboxctrl.h" #include "llviewerparcelmgr.h" #include "llfolderview.h" +#include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventoryfunctions.h" #include "llinventoryview.h" diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 16a4f1379..16b26bb26 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -45,8 +45,10 @@ #include "llinventory.h" #include "llcallbacklist.h" +#include "llfoldervieweventlistener.h" #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryview.h"// hacked in for the bonus context menu items. +#include "llinventoryfunctions.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 9e4f9e24b..7eda4f691 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -70,65 +70,9 @@ class LLMenuGL; class LLFolderViewItem; class LLFolderView; class LLInventoryModel; +class LLFolderViewFunctor; class LLScrollableContainerView; - -class LLFolderViewEventListener -{ -public: - virtual ~LLFolderViewEventListener( void ) {} - virtual const std::string& getName() const = 0; - virtual const std::string& getDisplayName() const = 0; - virtual const LLUUID& getUUID() const = 0; - virtual time_t getCreationDate() const = 0; // UTC seconds - virtual PermissionMask getPermissionMask() const = 0; - virtual LLUIImagePtr getIcon() const = 0; - virtual LLFontGL::StyleFlags getLabelStyle() const = 0; - virtual std::string getLabelSuffix() const = 0; - virtual void openItem( void ) = 0; - virtual void previewItem( void ) = 0; - virtual void selectItem(void) = 0; - virtual void showProperties(void) = 0; - virtual BOOL isItemRenameable() const = 0; - virtual BOOL renameItem(const std::string& new_name) = 0; - virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder - virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed - virtual BOOL removeItem() = 0; - virtual void removeBatch(LLDynamicArray& batch) = 0; - virtual void move( LLFolderViewEventListener* parent_listener ) = 0; - virtual BOOL isItemCopyable() const = 0; - virtual BOOL copyToClipboard() const = 0; - virtual BOOL cutToClipboard() const = 0; - virtual BOOL isClipboardPasteable() const = 0; - virtual void pasteFromClipboard() = 0; - virtual void pasteLinkFromClipboard() = 0; - virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; - virtual BOOL isUpToDate() const = 0; - virtual BOOL hasChildren() const = 0; - virtual LLInventoryType::EType getInventoryType() const = 0; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) {} - - // This method should be called when a drag begins. returns TRUE - // if the drag can begin, otherwise FALSE. - virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0; - - // This method will be called to determine if a drop can be - // performed, and will set drop to TRUE if a drop is - // requested. Returns TRUE if a drop is possible/happened, - // otherwise FALSE. - virtual BOOL dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) = 0; - - // This method is called when the object being referenced by the - // bridge is actually dropped. This allows for cleanup of the old - // view, reference counting, etc. -// virtual void dropped() = 0; - - // this method accesses the parent and arranges and sets it as - // specified. - void arrangeAndSet(LLFolderViewItem* focus, BOOL set_selection, - BOOL take_keyboard_focus = TRUE); -}; +class LLFolderViewEventListener; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -157,13 +101,6 @@ public: class LLFolderViewItem; class LLFolderViewFolder; -class LLFolderViewFunctor -{ -public: - virtual ~LLFolderViewFunctor() {} - virtual void doFolder(LLFolderViewFolder* folder) = 0; - virtual void doItem(LLFolderViewItem* item) = 0; -}; class LLInventoryFilter { diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h new file mode 100644 index 000000000..deefa298b --- /dev/null +++ b/indra/newview/llfoldervieweventlistener.h @@ -0,0 +1,108 @@ +/** + * @file llfoldervieweventlistener.h + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#ifndef LLFOLDERVIEWEVENTLISTENER_H +#define LLFOLDERVIEWEVENTLISTENER_H + +#include "lldarray.h" // *TODO: convert to std::vector +#include "llfoldertype.h" +#include "llfontgl.h" // just for StyleFlags enum +#include "llinventorytype.h" +#include "llpermissionsflags.h" +#include "llpointer.h" +#include "llwearabletype.h" + + +class LLFolderViewItem; +class LLFolderView; +class LLFontGL; +class LLInventoryModel; +class LLMenuGL; +class LLScrollContainer; +class LLUIImage; +class LLUUID; + +// This is an abstract base class that users of the folderview classes +// would use to catch the useful events emitted from the folder +// views. +class LLFolderViewEventListener +{ +public: + virtual ~LLFolderViewEventListener( void ) {} + virtual const std::string& getName() const = 0; + virtual const std::string& getDisplayName() const = 0; + virtual const LLUUID& getUUID() const = 0; + virtual time_t getCreationDate() const = 0; // UTC seconds + virtual PermissionMask getPermissionMask() const = 0; + virtual LLPointer getIcon() const = 0; + virtual LLFontGL::StyleFlags getLabelStyle() const = 0; + virtual std::string getLabelSuffix() const = 0; + virtual void openItem( void ) = 0; + virtual void previewItem( void ) = 0; + virtual void selectItem(void) = 0; + virtual void showProperties(void) = 0; + virtual BOOL isItemRenameable() const = 0; + virtual BOOL renameItem(const std::string& new_name) = 0; + virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder + virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed + virtual BOOL removeItem() = 0; + virtual void removeBatch(LLDynamicArray& batch) = 0; + virtual void move( LLFolderViewEventListener* parent_listener ) = 0; + virtual BOOL isItemCopyable() const = 0; + virtual BOOL copyToClipboard() const = 0; + virtual BOOL cutToClipboard() const = 0; + virtual BOOL isClipboardPasteable() const = 0; + virtual void pasteFromClipboard() = 0; + virtual void pasteLinkFromClipboard() = 0; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; + virtual BOOL isUpToDate() const = 0; + virtual BOOL hasChildren() const = 0; + virtual LLInventoryType::EType getInventoryType() const = 0; + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) {} + + // This method should be called when a drag begins. returns TRUE + // if the drag can begin, otherwise FALSE. + virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0; + + // This method will be called to determine if a drop can be + // performed, and will set drop to TRUE if a drop is + // requested. Returns TRUE if a drop is possible/happened, + // otherwise FALSE. + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) = 0; + + // This method is called when the object being referenced by the + // bridge is actually dropped. This allows for cleanup of the old + // view, reference counting, etc. +// virtual void dropped() = 0; + + // this method accesses the parent and arranges and sets it as + // specified. + void arrangeAndSet(LLFolderViewItem* focus, BOOL set_selection, + BOOL take_keyboard_focus = TRUE); +}; + + +#endif diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp new file mode 100644 index 000000000..8e61b9298 --- /dev/null +++ b/indra/newview/llgiveinventory.cpp @@ -0,0 +1,541 @@ +/** + * @file llgiveinventory.cpp + * @brief LLGiveInventory class implementation + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llgiveinventory.h" + +// library includes +#include "llnotificationsutil.h" +#include "lltrans.h" + +// newview includes +#include "llagent.h" +#include "llagentdata.h" +#include "llagentui.h" +#include "llagentwearables.h" +#include "llfloatertools.h" // for gFloaterTool +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llimview.h" +#include "llinventory.h" +#include "llinventoryfunctions.h" +#include "llmutelist.h" +#include "llviewerobjectlist.h" +#include "llvoavatarself.h" + +// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES +// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a +// bit from there to give some pad. +const S32 MAX_ITEMS = 42; + +class LLGiveable : public LLInventoryCollectFunctor +{ +public: + LLGiveable() : mCountLosing(0) {} + virtual ~LLGiveable() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + + S32 countNoCopy() const { return mCountLosing; } +protected: + S32 mCountLosing; +}; + +bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + // All categories can be given. + if (cat) + return true; + + bool allowed = false; + if(item) + { + allowed = itemTransferCommonlyAllowed(item); + if(allowed && + !item->getPermissions().allowOperationBy(PERM_TRANSFER, + gAgent.getID())) + { + allowed = FALSE; + } + if(allowed && + !item->getPermissions().allowCopyBy(gAgent.getID())) + { + ++mCountLosing; + } + } + return allowed; +} + +class LLUncopyableItems : public LLInventoryCollectFunctor +{ +public: + LLUncopyableItems() {} + virtual ~LLUncopyableItems() {} + virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +}; + +bool LLUncopyableItems::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + bool uncopyable = false; + if(item) + { + if (itemTransferCommonlyAllowed(item) && + !item->getPermissions().allowCopyBy(gAgent.getID())) + { + uncopyable = true; + } + } + return uncopyable; +} + +// static +bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item) +{ + if (!item) return false; + + if (!isAgentAvatarValid()) return false; + + if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID)) + { + return false; + } + + + bool acceptable = true; + switch(item->getType()) + { + case LLAssetType::AT_CALLINGCARD: + acceptable = false; + break; + case LLAssetType::AT_OBJECT: + // + /*if(my_avatar->isWearingAttachment(item->getUUID())) + { + acceptable = false; + }*/ + // + break; + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_CLOTHING: + { + // + /*bool copyable = false; + if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = true; + + if(!copyable && gAgentWearables.isWearingItem(item->getUUID())) + { + acceptable = false; + }*/ + // + } + + break; + default: + break; + } + return acceptable; +} + +// Static +bool LLGiveInventory::isInventoryGroupGiveAcceptable(const LLInventoryItem* item) +{ + if(!item) return false; + + if (!isAgentAvatarValid()) return false; + + // These permissions are double checked in the simulator in + // LLGroupNoticeInventoryItemFetch::result(). + if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID)) + { + return false; + } + if (!item->getPermissions().allowCopyBy(gAgent.getID())) + { + return false; + } + + + bool acceptable = true; + + switch(item->getType()) + { + case LLAssetType::AT_CALLINGCARD: + acceptable = false; + break; + // + /*case LLAssetType::AT_OBJECT: + if(gAgentAvatarp->isWearingAttachment(item->getUUID())) + { + acceptable = false; + }* + break;*/ + // + default: + break; + } + return acceptable; +} + +// static +bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, + const LLInventoryItem* item, + const LLUUID& im_session_id/* = LLUUID::null*/) + +{ + bool res = true; + llinfos << "LLGiveInventory::giveInventory()" << llendl; + if(!isInventoryGiveAcceptable(item)) + { + return false; + } + if (item->getPermissions().allowCopyBy(gAgentID)) + { + // just give it away. + LLGiveInventory::commitGiveInventoryItem(to_agent, item, im_session_id); + } + else + { + // ask if the agent is sure. + LLSD payload; + payload["agent_id"] = to_agent; + payload["item_id"] = item->getUUID(); + LLNotificationsUtil::add("CannotCopyWarning", LLSD(), payload, + &LLGiveInventory::handleCopyProtectedItem); + res = false; + } + + return res; +} + +void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, + const LLInventoryCategory* cat, + const LLUUID& im_session_id) + +{ + if (!cat) return; + llinfos << "LLGiveInventory::giveInventoryCategory() - " + << cat->getUUID() << llendl; + + if (!isAgentAvatarValid()) return; + + // Test out how many items are being given. + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLGiveable giveable; + gInventory.collectDescendentsIf(cat->getUUID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + giveable); + S32 count = cats.count(); + bool complete = true; + for(S32 i = 0; i < count; ++i) + { + if(!gInventory.isCategoryComplete(cats.get(i)->getUUID())) + { + complete = false; + break; + } + } + if(!complete) + { + LLNotificationsUtil::add("IncompleteInventory"); + return; + } + count = items.count() + cats.count(); + if(count > MAX_ITEMS) + { + LLNotificationsUtil::add("TooManyItems"); + return; + } + else if(count == 0) + { + LLNotificationsUtil::add("NoItems"); + return; + } + else + { + if(0 == giveable.countNoCopy()) + { + LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id); + } + else + { + LLSD args; + args["COUNT"] = llformat("%d",giveable.countNoCopy()); + LLSD payload; + payload["agent_id"] = to_agent; + payload["folder_id"] = cat->getUUID(); + LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLGiveInventory::handleCopyProtectedCategory); + } + } +} + +////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS +////////////////////////////////////////////////////////////////////////// + +//static +void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id) +{ + // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. + if (im_session_id.notNull()) + { + LLSD args; + gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); + } +} + +// static +bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLInventoryItem* item = NULL; + switch(option) + { + case 0: // "Yes" + item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + if(item) + { + LLGiveInventory::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), + item); + // delete it for now - it will be deleted on the server + // quickly enough. + gInventory.deleteObject(notification["payload"]["item_id"].asUUID()); + gInventory.notifyObservers(); + } + else + { + LLNotificationsUtil::add("CannotGiveItem"); + } + break; + + default: // no, cancel, whatever, who cares, not yes. + LLNotificationsUtil::add("TransactionCancelled"); + break; + } + return false; +} + +// static +void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent, + const LLInventoryItem* item, + const LLUUID& im_session_id) +{ + if (!item) return; + std::string name; + LLAgentUI::buildFullname(name); + LLUUID transaction_id; + transaction_id.generate(); + const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES; + U8 bucket[BUCKET_SIZE]; + bucket[0] = (U8)item->getType(); + memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES); /* Flawfinder: ignore */ + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + to_agent, + name, + item->getName(), + IM_ONLINE, + IM_INVENTORY_OFFERED, + transaction_id, + 0, + LLUUID::null, + gAgent.getPositionAgent(), + NO_TIMESTAMP, + bucket, + BUCKET_SIZE); + gAgent.sendReliableMessage(); + // + if (gSavedSettings.getBOOL("BroadcastViewerEffects")) + { + // + // VEFFECT: giveInventory + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); + effectp->setSourceObject(gAgentAvatarp); + effectp->setTargetObject(gObjectList.findObject(to_agent)); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + // + } + // + gFloaterTools->dirty(); + + LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); + + logInventoryOffer(to_agent, im_session_id); +} + +// static +bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLInventoryCategory* cat = NULL; + switch(option) + { + case 0: // "Yes" + cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID()); + if(cat) + { + LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), + cat); + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLUncopyableItems remove; + gInventory.collectDescendentsIf(cat->getUUID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + remove); + S32 count = items.count(); + for(S32 i = 0; i < count; ++i) + { + gInventory.deleteObject(items.get(i)->getUUID()); + } + gInventory.notifyObservers(); + } + else + { + LLNotificationsUtil::add("CannotGiveCategory"); + } + break; + + default: // no, cancel, whatever, who cares, not yes. + LLNotificationsUtil::add("TransactionCancelled"); + break; + } + return false; +} + +// static +void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, + const LLInventoryCategory* cat, + const LLUUID& im_session_id) + +{ +if(!cat) return; + llinfos << "LLGiveInventory::commitGiveInventoryCategory() - " + << cat->getUUID() << llendl; + + // Test out how many items are being given. + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLGiveable giveable; + gInventory.collectDescendentsIf(cat->getUUID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + giveable); + + // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < + // MTUBYTES or 18 * count < 1200 => count < 1200/18 => + // 66. I've cut it down a bit from there to give some pad. + S32 count = items.count() + cats.count(); + if(count > MAX_ITEMS) + { + LLNotificationsUtil::add("TooManyItems"); + return; + } + else if(count == 0) + { + LLNotificationsUtil::add("NoItems"); + return; + } + else + { + std::string name; + LLAgentUI::buildFullname(name); + LLUUID transaction_id; + transaction_id.generate(); + S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1); + U8* bucket = new U8[bucket_size]; + U8* pos = bucket; + U8 type = (U8)cat->getType(); + memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ + pos += sizeof(U8); + memcpy(pos, &(cat->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ + pos += UUID_BYTES; + S32 i; + count = cats.count(); + for(i = 0; i < count; ++i) + { + memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ + pos += sizeof(U8); + memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ + pos += UUID_BYTES; + } + count = items.count(); + for(i = 0; i < count; ++i) + { + type = (U8)items.get(i)->getType(); + memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ + pos += sizeof(U8); + memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ + pos += UUID_BYTES; + } + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + to_agent, + name, + cat->getName(), + IM_ONLINE, + IM_INVENTORY_OFFERED, + transaction_id, + 0, + LLUUID::null, + gAgent.getPositionAgent(), + NO_TIMESTAMP, + bucket, + bucket_size); + gAgent.sendReliableMessage(); + delete[] bucket; + // + if (gSavedSettings.getBOOL("BroadcastViewerEffects")) + { + // + // VEFFECT: giveInventoryCategory + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); + effectp->setSourceObject(gAgentAvatarp); + effectp->setTargetObject(gObjectList.findObject(to_agent)); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + // + } + // + gFloaterTools->dirty(); + + LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); + + logInventoryOffer(to_agent, im_session_id); + } +} +// EOF diff --git a/indra/newview/llgiveinventory.h b/indra/newview/llgiveinventory.h new file mode 100644 index 000000000..19dab82a5 --- /dev/null +++ b/indra/newview/llgiveinventory.h @@ -0,0 +1,93 @@ +/** + * @file llgiveinventory.cpp + * @brief LLGiveInventory class declaration + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLGIVEINVENTORY_H +#define LL_LLGIVEINVENTORY_H + +class LLInventoryItem; +class LLInventoryCategory; + +/** + * Class represented give inventory related actions. + * + * It has only static methods and is not intended to be instantiated for now. + */ +class LLGiveInventory +{ +public: + /** + * Checks if inventory item you are attempting to transfer to a resident can be given. + * + * @return true if you can give, otherwise false. + */ + static bool isInventoryGiveAcceptable(const LLInventoryItem* item); + + /** + * Checks if inventory item you are attempting to transfer to a group can be given. + * + * @return true if you can give, otherwise false. + */ + static bool isInventoryGroupGiveAcceptable(const LLInventoryItem* item); + + /** + * Gives passed inventory item to specified avatar in specified session. + */ + static bool doGiveInventoryItem(const LLUUID& to_agent, + const LLInventoryItem* item, + const LLUUID& im_session_id = LLUUID::null); + + /** + * Gives passed inventory category to specified avatar in specified session. + */ + static void doGiveInventoryCategory(const LLUUID& to_agent, + const LLInventoryCategory* item, + const LLUUID &session_id = LLUUID::null); + // give inventory item functionality + static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response); + +private: + // this class is not intended to be instantiated. + LLGiveInventory(); + + /** + * logs "Inventory item offered" to IM + */ + static void logInventoryOffer(const LLUUID& to_agent, + const LLUUID &im_session_id = LLUUID::null); + + static void commitGiveInventoryItem(const LLUUID& to_agent, + const LLInventoryItem* item, + const LLUUID &im_session_id = LLUUID::null); + + // give inventory category functionality + static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response); + static void commitGiveInventoryCategory(const LLUUID& to_agent, + const LLInventoryCategory* cat, + const LLUUID &im_session_id = LLUUID::null); + +}; + +#endif // LL_LLGIVEINVENTORY_H diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 304d8d5b3..14cad7cc6 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -43,6 +43,7 @@ #include "llagent.h" #include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons +#include "llfoldervieweventlistener.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "llspinctrl.h" @@ -410,7 +411,7 @@ class LLDoCreate : public inventory_panel_listener_t LLInventoryModel* model = mPtr->getModel(); if(!model) return false; std::string type = userdata.asString(); - do_create(model, mPtr, type, LLFolderBridge::sSelf); + do_create(model, mPtr, type, LLFolderBridge::sSelf.get()); return true; } }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 37172bd71..08ee59a0c 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -52,6 +52,7 @@ #include "llspinctrl.h" #include "lltextbox.h" #include "llui.h" +#include "llviewerfoldertype.h" #include "llviewercontrol.h" #include "llfirstuse.h" @@ -64,6 +65,7 @@ #include "llfocusmgr.h" #include "llfolderview.h" #include "llgesturemgr.h" +#include "llgiveinventory.h" #include "lliconctrl.h" #include "llinventorymodel.h" #include "llinventoryclipboard.h" @@ -251,21 +253,7 @@ time_t LLInvFVBridge::getCreationDate() const // Can be destroyed (or moved to trash) BOOL LLInvFVBridge::isItemRemovable() { - LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return FALSE; - } - const LLInventoryObject *obj = model->getItem(mUUID); - if (obj && obj->getIsLinkType()) - { - return TRUE; - } - if(model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return TRUE; - } - return FALSE; + return get_is_item_removable(getInventoryModel(), mUUID); } // Can be moved to another folder @@ -645,6 +633,10 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } else { + if (LLAssetType::lookupCanLink(obj->getType())) + { + items.push_back(std::string("Find Links")); + } items.push_back(std::string("Rename")); if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) { @@ -654,13 +646,21 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (show_asset_id) { items.push_back(std::string("Copy Asset UUID")); - if ((!( isItemPermissive() || gAgent.isGodlike())) - || (flags & FIRST_SELECTED_ITEM) == 0) + + bool is_asset_knowable = false; + + LLViewerInventoryItem* inv_item = gInventory.getItem(mUUID); + if (inv_item) + { + is_asset_knowable = LLAssetType::lookupIsAssetIDKnowable(inv_item->getType()); + } + if ( !is_asset_knowable // disable menu item for Inventory items with unknown asset. EXT-5308 + || (! ( isItemPermissive() || gAgent.isGodlike() ) ) + || (flags & FIRST_SELECTED_ITEM) == 0) { disabled_items.push_back(std::string("Copy Asset UUID")); } } - items.push_back(std::string("Copy Separator")); items.push_back(std::string("Copy")); @@ -898,27 +898,7 @@ void LLInvFVBridge::changeItemParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - // - bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); - // - if(item->getParentUUID() != new_parent_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - // - if(send_parent_update) - // - new_item->updateParentOnServer(restamp); - model->updateItem(new_item); - model->notifyObservers(); - } + change_item_parent(model, item, new_parent_id, restamp); } // static @@ -927,21 +907,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - if(cat->getParentUUID() != new_parent_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); - } + change_category_parent(model, cat, new_parent_id, restamp); } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, @@ -1540,11 +1506,7 @@ BOOL LLItemBridge::isItemPermissive() const LLViewerInventoryItem* item = getItem(); if(item) { - U32 mask = item->getPermissions().getMaskBase(); - if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - { - return TRUE; - } + return item->getIsFullPerm(); } return FALSE; } @@ -1553,7 +1515,7 @@ BOOL LLItemBridge::isItemPermissive() const // | LLFolderBridge | // +=================================================+ -LLFolderBridge* LLFolderBridge::sSelf=NULL; +LLHandle LLFolderBridge::sSelf; // Can be moved to another folder BOOL LLFolderBridge::isItemMovable() @@ -1922,29 +1884,6 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, return accept; } -class LLFindWearables : public LLInventoryCollectFunctor -{ -public: - LLFindWearables() {} - virtual ~LLFindWearables() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; - -bool LLFindWearables::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CLOTHING) - || (item->getType() == LLAssetType::AT_BODYPART)) - { - return TRUE; - } - } - return FALSE; -} - //Used by LLFolderBridge as callback for directory recursion. class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver { @@ -2210,13 +2149,7 @@ void LLFolderBridge::openItem() BOOL LLFolderBridge::isItemRenameable() const { - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && ((cat->getPreferredType() == LLFolderType::FT_NONE) || (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) - && (cat->getOwnerID() == gAgent.getID())) - { - return TRUE; - } - return FALSE; + return get_is_category_renameable(getInventoryModel(), mUUID); } void LLFolderBridge::restoreItem() @@ -2247,82 +2180,34 @@ LLFolderType::EType LLFolderBridge::getPreferredType() const // Icons for folders are based on the preferred type LLUIImagePtr LLFolderBridge::getIcon() const { - const char* control = NULL; LLFolderType::EType preferred_type = LLFolderType::FT_NONE; LLViewerInventoryCategory* cat = getCategory(); if(cat) { preferred_type = cat->getPreferredType(); } - switch(preferred_type) - { - case LLFolderType::FT_TEXTURE: - control = "inv_folder_texture.tga"; - break; - case LLFolderType::FT_SOUND: - control = "inv_folder_sound.tga"; - break; - case LLFolderType::FT_CALLINGCARD: - control = "inv_folder_callingcard.tga"; - break; - case LLFolderType::FT_LANDMARK: - control = "inv_folder_landmark.tga"; - break; - //case LLFolderType::FT_SCRIPT: - case LLFolderType::FT_LSL_TEXT: - control = "inv_folder_script.tga"; - break; - case LLFolderType::FT_OBJECT: - control = "inv_folder_object.tga"; - break; - case LLFolderType::FT_NOTECARD: - control = "inv_folder_notecard.tga"; - break; - //case LLFolderType::FT_CATEGORY: - // control = "inv_folder_plain_closed.tga"; - // break; - case LLFolderType::FT_CLOTHING: - control = "inv_folder_clothing.tga"; - break; - case LLFolderType::FT_BODYPART: - control = "inv_folder_bodypart.tga"; - break; - case LLFolderType::FT_TRASH: - control = "inv_folder_trash.tga"; - break; - case LLFolderType::FT_SNAPSHOT_CATEGORY: - control = "inv_folder_snapshot.tga"; - break; - case LLFolderType::FT_LOST_AND_FOUND: - control = "inv_folder_lostandfound.tga"; - break; - case LLFolderType::FT_ANIMATION: - control = "inv_folder_animation.tga"; - break; - case LLFolderType::FT_GESTURE: - control = "inv_folder_gesture.tga"; - break; - default: - control = "inv_folder_plain_closed.tga"; - break; - } - return LLUI::getUIImage(control); + return getIcon(preferred_type); +} + +// static +LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) +{ + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE)); + /*case LLAssetType::AT_MESH: + control = "inv_folder_mesh.tga"; + break;*/ +} + +LLUIImagePtr LLFolderBridge::getOpenIcon() const +{ + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(getPreferredType(), TRUE)); + } BOOL LLFolderBridge::renameItem(const std::string& new_name) { - if(!isItemRenameable()) return FALSE; - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat && (cat->getName() != new_name)) - { - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); - model->notifyObservers(); - } + rename_category(getInventoryModel(), mUUID, new_name); + // return FALSE because we either notified observers (& therefore // rebuilt) or we didn't update. return FALSE; @@ -2475,14 +2360,15 @@ void LLFolderBridge::pasteLinkFromClipboard() void LLFolderBridge::staticFolderOptionsMenu() { - if (!sSelf) return; - sSelf->folderOptionsMenu(); + LLFolderBridge* selfp = sSelf.get(); + if (selfp) + { + selfp->folderOptionsMenu(); + } } void LLFolderBridge::folderOptionsMenu() { - menuentry_vec_t disabled_items; - // *TODO: Translate LLInventoryModel* model = getInventoryModel(); @@ -2511,7 +2397,12 @@ void LLFolderBridge::folderOptionsMenu() mItems.push_back(std::string("IM All Contacts In Folder")); } } - + + if (!isItemRemovable()) + { + mDisabledItems.push_back(std::string("Delete")); + } + // wearables related functionality for folders. //is_wearable LLFindWearables is_wearable; @@ -2539,7 +2430,11 @@ void LLFolderBridge::folderOptionsMenu() } mItems.push_back(std::string("Take Off Items")); } - hide_context_entries(*mMenu, mItems, disabled_items); + LLMenuGL* menup = dynamic_cast(mMenu.get()); + if (menup) + { + hide_context_entries(*menup, mItems, mDisabledItems); + } } BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) @@ -2576,11 +2471,14 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // [/RLVa:KB] if (lost_and_found_id == mUUID) - { + { // This is the lost+found folder. mItems.push_back(std::string("Empty Lost And Found")); - } - + } + + // clear out old menu and folder pointers + mMenu.markDead(); + sSelf.markDead(); if (cof_id == mUUID) { mItems.push_back(std::string("Take Off Items")); @@ -2649,16 +2547,17 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mWearables=TRUE; } - mMenu = &menu; - sSelf = this; - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); - LLInventoryFetchDescendentsObserver::folder_ref_t folders; + uuid_vec_t folders; LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); if (category) { - folders.push_back(category->getUUID()); + folders.push_back(category->getUUID()); } + + mMenu = menu.getHandle(); + sSelf = getHandle(); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); fetch->fetchDescendents(folders); inc_busy_count(); if(fetch->isEverythingComplete()) @@ -3570,7 +3469,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, rv = TRUE; if(drop) { - LLToolDragAndDrop::giveInventory(item->getCreatorUUID(), + LLGiveInventory::doGiveInventoryItem(item->getCreatorUUID(), (LLInventoryItem*)cargo_data); } } @@ -3591,7 +3490,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, rv = TRUE; if(drop) { - LLToolDragAndDrop::giveInventoryCategory( + LLGiveInventory::doGiveInventoryCategory( item->getCreatorUUID(), inv_cat); } @@ -4342,11 +4241,10 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) model->updateItem(new_item); model->notifyObservers(); - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) + if (isAgentAvatarValid()) { - LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() ); - if( obj ) + LLViewerObject* obj = gAgentAvatarp->getWornAttachment( item->getUUID() ); + if(obj) { LLSelectMgr::getInstance()->deselectAll(); LLSelectMgr::getInstance()->addAsIndividual( obj, SELECT_ALL_TES, FALSE ); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 8806c466a..0279c850f 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -35,7 +35,7 @@ #include "llcallingcard.h" #include "llfloaterproperties.h" -#include "llfolderview.h" +#include "llfoldervieweventlistener.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" //#include "llinventoryview.h" @@ -302,7 +302,11 @@ public: virtual LLFolderType::EType getPreferredType() const; virtual LLUIImagePtr getIcon() const; + virtual LLUIImagePtr getOpenIcon() const; + static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); + virtual BOOL renameItem(const std::string& new_name); + virtual BOOL removeItem(); virtual void pasteFromClipboard(); virtual void pasteLinkFromClipboard(); @@ -322,6 +326,7 @@ public: static void createWearable(LLUUID parent_folder_id, LLWearableType::EType type); LLViewerInventoryCategory* getCategory() const; + LLHandle getHandle() { mHandle.bind(this); return mHandle; } protected: // menu callbacks @@ -350,15 +355,17 @@ protected: void modifyOutfit(BOOL append, BOOL replace = FALSE); menuentry_vec_t getMenuItems() { return mItems; } // returns a copy of current menu items public: - static LLFolderBridge* sSelf; + static LLHandle sSelf; static void staticFolderOptionsMenu(); void folderOptionsMenu(); + private: BOOL mCallingCards; BOOL mWearables; - LLMenuGL* mMenu; + LLHandle mMenu; menuentry_vec_t mItems; menuentry_vec_t mDisabledItems; + LLRootHandle mHandle; }; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 5cd8e7a41..dafa4434b 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -106,7 +106,10 @@ void change_item_parent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - if (item->getParentUUID() != new_parent_id) + // + bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); + // + if(item->getParentUUID() != new_parent_id) { LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); @@ -117,6 +120,9 @@ void change_item_parent(LLInventoryModel* model, LLPointer new_item = new LLViewerInventoryItem(item); new_item->setParent(new_parent_id); + // + if(send_parent_update) + // new_item->updateParentOnServer(restamp); model->updateItem(new_item); model->notifyObservers(); @@ -153,6 +159,59 @@ void change_category_parent(LLInventoryModel* model, model->notifyObservers(); } +/*void remove_category(LLInventoryModel* model, const LLUUID& cat_id) +{ + if (!model || !get_is_category_removable(model, cat_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (cat) + { + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + change_category_parent(model, cat, trash_id, TRUE); + } +}*/ + +void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) +{ + LLViewerInventoryCategory* cat; + + if (!model || + !get_is_category_renameable(model, cat_id) || + (cat = model->getCategory(cat_id)) == NULL || + cat->getName() == new_name) + { + return; + } + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->rename(new_name); + new_cat->updateServer(FALSE); + model->updateCategory(new_cat); + + model->notifyObservers(); +} + class LLInventoryCollectAllItems : public LLInventoryCollectFunctor { public: @@ -308,6 +367,101 @@ BOOL get_can_item_be_worn(const LLUUID& id) return FALSE; } +BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id) +{ + if (!model) + { + return FALSE; + } + + // Can't delete an item that's in the library. + if(!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } + + // Disable delete from COF folder; have users explicitly choose "detach/take off", + // unless the item is not worn but in the COF (i.e. is bugged). + if (LLCOFMgr::instance().getIsProtectedCOFItem(id)) + { + if (get_is_item_worn(id)) + { + return FALSE; + } + } + + const LLInventoryObject *obj = model->getItem(id); + if (obj && obj->getIsLinkType()) + { + return TRUE; + } + if (get_is_item_worn(id)) + { + return FALSE; + } + return TRUE; +} + +/*BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id) +{ + // NOTE: This function doesn't check the folder's children. + // See LLFolderBridge::isItemRemovable for a function that does + // consider the children. + + if (!model) + { + return FALSE; + } + + if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + return FALSE; + } + + if (!isAgentAvatarValid()) return FALSE; + + const LLInventoryCategory* category = model->getCategory(id); + if (!category) + { + return FALSE; + } + + const LLFolderType::EType folder_type = category->getPreferredType(); + + if (LLFolderType::lookupIsProtectedType(folder_type)) + { + return FALSE; + } + + // Can't delete the outfit that is currently being worn. + if (folder_type == LLFolderType::FT_OUTFIT) + { + const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); + if (base_outfit_link && (category == base_outfit_link->getLinkedCategory())) + { + return FALSE; + } + } + + return TRUE; +}*/ + +BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) +{ + if (!model) + { + return FALSE; + } + + LLViewerInventoryCategory* cat = model->getCategory(id); + + if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) && + cat->getOwnerID() == gAgent.getID()) + { + return TRUE; + } + return FALSE; +} ///---------------------------------------------------------------------------- @@ -458,6 +612,21 @@ bool LLNameCategoryCollector::operator()( } return false; } + +bool LLFindWearables::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART)) + { + return TRUE; + } + } + return FALSE; +} + ///---------------------------------------------------------------------------- /// LLAssetIDMatches ///---------------------------------------------------------------------------- @@ -474,4 +643,112 @@ bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem return (item && (item->getIsLinkType()) && (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. -} \ No newline at end of file +} + +void LLSaveFolderState::setApply(BOOL apply) +{ + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } +} + +void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) +{ + if(mApply) + { + // we're applying the open state + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + folder->setOpen(TRUE); + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + mOpenFolders.insert(bridge->getUUID()); + } + } +} + +void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + // if this folder didn't pass the filter, and none of its descendants did + else if (!folder->getFiltered() && !folder->hasFilteredDescendants()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } +} + +void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + item->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && !mItemSelected) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + if (folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + folder->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) +{ + if (item->getParentFolder() && item->isSelected()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getParentFolder() && folder->isSelected()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 7cd944cad..b2e2be357 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -47,6 +47,11 @@ BOOL get_is_item_worn(const LLUUID& id); // Could this item be worn (correct type + not already being worn) BOOL get_can_item_be_worn(const LLUUID& id); +BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id); + +BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id); + +BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id); void change_item_parent(LLInventoryModel* model, LLViewerInventoryItem* item, @@ -57,6 +62,10 @@ void change_category_parent(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& new_parent_id, BOOL restamp); + +void remove_category(LLInventoryModel* model, const LLUUID& cat_id); +void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); + // Generates a string containing the path to the item specified by item_id. void append_path(const LLUUID& id, std::string& path); @@ -252,6 +261,42 @@ public: protected: std::string mName; }; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindWearables +// +// Collects wearables based on item type. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindWearables : public LLInventoryCollectFunctor +{ +public: + LLFindWearables() {} + virtual ~LLFindWearables() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + +/** Inventory Collector Functions + ** ** + *******************************************************************************/ +class LLFolderViewItem; +class LLFolderViewFolder; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFolderViewFunctor +// +// Simple abstract base class for applying a functor to folders and +// items in a folder view hierarchy. This is suboptimal for algorithms +// that only work folders or only work on items, but I'll worry about +// that later when it's determined to be too slow. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFolderViewFunctor +{ +public: + virtual ~LLFolderViewFunctor() {} + virtual void doFolder(LLFolderViewFolder* folder) = 0; + virtual void doItem(LLFolderViewItem* item) = 0; +}; + class LLInventoryState { public: @@ -260,6 +305,49 @@ public: static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction }; +class LLSelectFirstFilteredItem : public LLFolderViewFunctor +{ +public: + LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} + virtual ~LLSelectFirstFilteredItem() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + BOOL wasItemSelected() { return mItemSelected; } +protected: + BOOL mItemSelected; +}; + +class LLOpenFilteredFolders : public LLFolderViewFunctor +{ +public: + LLOpenFilteredFolders() {} + virtual ~LLOpenFilteredFolders() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +class LLSaveFolderState : public LLFolderViewFunctor +{ +public: + LLSaveFolderState() : mApply(FALSE) {} + virtual ~LLSaveFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + void setApply(BOOL apply); + void clearOpenFolders() { mOpenFolders.clear(); } +protected: + std::set mOpenFolders; + BOOL mApply; +}; + +class LLOpenFoldersWithSelection : public LLFolderViewFunctor +{ +public: + LLOpenFoldersWithSelection() {} + virtual ~LLOpenFoldersWithSelection() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; #endif // LL_LLINVENTORYFUNCTIONS_H diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 09678c6c7..5745b5704 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -50,6 +50,7 @@ #include "llviewerinventory.h" #include "llviewermessage.h" #include "llfoldertype.h" +#include "llviewerfoldertype.h" #include "llviewerwindow.h" #include "llviewerregion.h" #include "llappviewer.h" @@ -77,6 +78,8 @@ #include "process.h" #endif +const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; +const S32 MAX_FETCH_RETRIES = 10; BOOL LLInventoryModel::sBackgroundFetchActive = FALSE; BOOL LLInventoryModel::sAllFoldersFetched = FALSE; BOOL LLInventoryModel::sFullFetchStarted = FALSE; @@ -90,6 +93,7 @@ S16 LLInventoryModel::sBulkFetchCount = 0; // RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue static std::deque sFetchQueue; + // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewers with link items support, former caches are incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; @@ -99,67 +103,8 @@ const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; ///---------------------------------------------------------------------------- //BOOL decompress_file(const char* src_filename, const char* dst_filename); -const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; -const S32 MAX_FETCH_RETRIES = 10; -const char CACHE_FORMAT_STRING[] = "%s.inv"; -const char* NEW_CATEGORY_NAME = "New Folder"; -const char* NEW_CATEGORY_NAMES[LLFolderType::FT_COUNT] = -{ - "Textures", // FT_TEXTURE = 0, - "Sounds", // FT_SOUND = 1, - "Calling Cards", // FT_CALLINGCARD = 2, - "Landmarks", // FT_LANDMARK = 3, - "Scripts", // AT_SCRIPT (deprecated?) - "Clothing", // FT_CLOTHING = 5, - "Objects", // FT_OBJECT = 6, - "Notecards", // FT_NOTECARD = 7, - "New Folder", // FT_ROOT_INVENTORY = 8, - "Inventory", // AT_ROOT_CATEGORY - "Scripts", // FT_LSL_TEXT = 10, - "Scripts", // AT_LSL_BYTECODE - "Uncompressed Images", // AT_TEXTURE_TGA - "Body Parts", // FT_BODYPART = 13, - "Trash", // FT_TRASH = 14, - "Photo Album", // FT_SNAPSHOT_CATEGORY = 15, - "Lost And Found", // FT_LOST_AND_FOUND = 16, - "Uncompressed Sounds", // AT_SOUND_WAV - "Uncompressed Images", // AT_IMAGE_TGA - "Uncompressed Images", // AT_IMAGE_JPEG - "Animations", // FT_ANIMATION = 20, - "Gestures", // FT_GESTURE = 21, - "New Folder", // AT_SIMSTATE - "Favorites", // FT_FAVORITE = 23, - "New Folder", - "New Folder", - "New Ensemble", // FT_ENSEMBLE_START = 26, - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", - "New Ensemble", // FT_ENSEMBLE_END = 45, - "Current Outfit", // FT_CURRENT_OUTFIT = 46, - "New Outfit", // FT_OUTFIT = 47, - "My Outfits", // FT_MY_OUTFITS = 48, - "Mesh", // FT_MESH = 49, - "Inbox", // FT_INBOX = 50, - "Outbox", // FT_OUTBOX = 51, - "Basic Root" // FT_BASIC_ROOT = 52 -}; +const char CACHE_FORMAT_STRING[] = "%s.inv"; struct InventoryIDPtrLess { @@ -600,10 +545,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(pname); } - else if(preferred_type < (LLFolderType::EType)0 || preferred_type >= LLFolderType::FT_COUNT) - name.assign(NEW_CATEGORY_NAME); else - name.assign(NEW_CATEGORY_NAMES[preferred_type]); + { + name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); + } if ( callback && user_data ) //callback required for acked message. { @@ -996,10 +941,10 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) } } - /*else if (new_item->getType() == LLAssetType::AT_GESTURE) + else if (new_item->getType() == LLAssetType::AT_GESTURE) { mask |= LLInventoryObserver::GESTURE; - }*/ + } addChangedMask(mask, new_item->getUUID()); return mask; } diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index 0d3bdb930..e07beabd4 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -55,6 +55,7 @@ public: REMOVE = 8, // something deleted STRUCTURE = 16, // structural change, eg, item or folder moved CALLING_CARD = 32, // online, grant status, cancel, etc change + GESTURE = 64, ALL = 0xffffffff }; virtual ~LLInventoryObserver() {}; diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index ba667e658..bbfc1c515 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -413,49 +413,6 @@ void LLInventoryViewFinder::selectNoTypes(void* user_data) ///---------------------------------------------------------------------------- /// LLInventoryView ///---------------------------------------------------------------------------- -void LLSaveFolderState::setApply(BOOL apply) -{ - mApply = apply; - // before generating new list of open folders, clear the old one - if(!apply) - { - clearOpenFolders(); - } -} - -void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) -{ - if(mApply) - { - // we're applying the open state - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; - LLUUID id(bridge->getUUID()); - if(mOpenFolders.find(id) != mOpenFolders.end()) - { - folder->setOpen(TRUE); - } - else - { - // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected()) - { - folder->setOpen(FALSE); - } - } - } - else - { - // we're recording state at this point - if(folder->isOpen()) - { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; - mOpenFolders.insert(bridge->getUUID()); - } - } -} - // Default constructor LLInventoryView::LLInventoryView(const std::string& name, const std::string& rect, @@ -667,71 +624,6 @@ void LLInventoryView::draw() LLFloater::draw(); } -void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) -{ - if (item->getFiltered()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } -} - -void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) -{ - if (folder->getFiltered() && folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - // if this folder didn't pass the filter, and none of its descendants did - else if (!folder->getFiltered() && !folder->hasFilteredDescendants()) - { - folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); - } -} - -void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) -{ - if (item->getFiltered() && !mItemSelected) - { - item->getRoot()->setSelection(item, FALSE, FALSE); - if (item->getParentFolder()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - item->getRoot()->scrollToShowSelection(); - mItemSelected = TRUE; - } -} - -void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) -{ - if (folder->getFiltered() && !mItemSelected) - { - folder->getRoot()->setSelection(folder, FALSE, FALSE); - if (folder->getParentFolder()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - folder->getRoot()->scrollToShowSelection(); - mItemSelected = TRUE; - } -} - -void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) -{ - if (item->getParentFolder() && item->isSelected()) - { - item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } -} - -void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) -{ - if (folder->getParentFolder() && folder->isSelected()) - { - folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } -} - void LLInventoryView::startSearch() { // this forces focus to line editor portion of search editor diff --git a/indra/newview/llinventoryview.h b/indra/newview/llinventoryview.h index 724e3d1c1..24fd127c0 100644 --- a/indra/newview/llinventoryview.h +++ b/indra/newview/llinventoryview.h @@ -318,50 +318,6 @@ protected: static LLDynamicArray sActiveViews; }; -class LLSelectFirstFilteredItem : public LLFolderViewFunctor -{ -public: - LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} - virtual ~LLSelectFirstFilteredItem() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); - BOOL wasItemSelected() { return mItemSelected; } -protected: - BOOL mItemSelected; -}; - -class LLOpenFilteredFolders : public LLFolderViewFunctor -{ -public: - LLOpenFilteredFolders() {} - virtual ~LLOpenFilteredFolders() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - -class LLSaveFolderState : public LLFolderViewFunctor -{ -public: - LLSaveFolderState() : mApply(FALSE) {} - virtual ~LLSaveFolderState() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item) {} - void setApply(BOOL apply); - void clearOpenFolders() { mOpenFolders.clear(); } -protected: - std::set mOpenFolders; - BOOL mApply; -}; - -class LLOpenFoldersWithSelection : public LLFolderViewFunctor -{ -public: - LLOpenFoldersWithSelection() {} - virtual ~LLOpenFoldersWithSelection() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - ///---------------------------------------------------------------------------- /// Function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 36bd9b809..bde9aa848 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -36,10 +36,12 @@ #include "llview.h" +#include "llavatarnamecache.h" #include "llinventory.h" #include "llviewerinventory.h" -#include "llinventorymodel.h" #include "llinventorydefines.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" #include "llinventoryicon.h" #include "llagent.h" #include "lltooldraganddrop.h" @@ -49,7 +51,6 @@ #include "llbutton.h" #include "lliconctrl.h" #include "llcheckboxctrl.h" -#include "llnotificationsutil.h" #include "llscrolllistctrl.h" #include "lltextbox.h" @@ -57,6 +58,8 @@ #include "llviewerwindow.h" #include "llviewercontrol.h" #include "llviewermessage.h" +#include "llnotificationsutil.h" +#include "llgiveinventory.h" const S32 NOTICE_DATE_STRING_SIZE = 30; @@ -140,7 +143,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) - && LLToolDragAndDrop::isInventoryGroupGiveAcceptable(inv_item)) + && LLGiveInventory::isInventoryGroupGiveAcceptable(inv_item)) { // *TODO: get multiple object transfers working *accept = ACCEPT_YES_COPY_SINGLE; diff --git a/indra/newview/llpanelinventory.cpp b/indra/newview/llpanelinventory.cpp index 89eff24d2..c4dd9e00a 100644 --- a/indra/newview/llpanelinventory.cpp +++ b/indra/newview/llpanelinventory.cpp @@ -49,6 +49,7 @@ #include "lldarray.h" #include "llfontgl.h" #include "llassetstorage.h" +#include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventorybridge.h" #include "llinventorydefines.h" diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 75aca382d..d09dbdb4c 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -44,6 +44,7 @@ #include "lldraghandle.h" #include "llfocusmgr.h" #include "llfolderview.h" +#include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventoryfunctions.h" #include "llinventoryview.h" diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index f6f658f3f..42ffd4a6b 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -48,8 +48,10 @@ #include "llfloatertools.h" #include "llfocusmgr.h" #include "llgesturemgr.h" -#include "llhudeffecttrail.h" +#include "llgiveinventory.h" #include "llhudmanager.h" +#include "llhudeffecttrail.h" +#include "llimview.h" #include "llinventorybridge.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" @@ -68,18 +70,15 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvolume.h" #include "llworld.h" #include "object_flags.h" -#include "llimview.h" // #include "llappviewer.h" // System Folders #include "llparcel.h" // always rez #include "llviewerparcelmgr.h" // always rez // -#include "object_flags.h" -#include "llimview.h" // [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) #include "rlvhandler.h" @@ -145,18 +144,18 @@ bool LLDroppableItem::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { bool allowed = false; - if(item) + if (item) { allowed = itemTransferCommonlyAllowed(item); - if(allowed + if (allowed && mIsTransfer && !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) { allowed = false; } - if(allowed && !item->getPermissions().allowCopyBy(gAgent.getID())) + if (allowed && !item->getPermissions().allowCopyBy(gAgent.getID())) { ++mCountLosing; } @@ -164,29 +163,6 @@ bool LLDroppableItem::operator()(LLInventoryCategory* cat, return allowed; } -class LLUncopyableItems : public LLInventoryCollectFunctor -{ -public: - LLUncopyableItems() {} - virtual ~LLUncopyableItems() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); -}; - -bool LLUncopyableItems::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - bool uncopyable = false; - if(item) - { - if (itemTransferCommonlyAllowed(item) && - !item->getPermissions().allowCopyBy(gAgent.getID())) - { - uncopyable = true; - } - } - return uncopyable; -} - class LLDropCopyableItems : public LLInventoryCollectFunctor { public: @@ -214,43 +190,6 @@ bool LLDropCopyableItems::operator()( return allowed; } -class LLGiveable : public LLInventoryCollectFunctor -{ -public: - LLGiveable() : mCountLosing(0) {} - virtual ~LLGiveable() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); - - S32 countNoCopy() const { return mCountLosing; } -protected: - S32 mCountLosing; -}; - -bool LLGiveable::operator()(LLInventoryCategory* cat, LLInventoryItem* item) -{ - // All categories can be given. - if (cat) - return true; - - bool allowed = false; - if(item) - { - allowed = itemTransferCommonlyAllowed(item); - if(allowed && - !item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID())) - { - allowed = FALSE; - } - if(allowed && - !item->getPermissions().allowCopyBy(gAgent.getID())) - { - ++mCountLosing; - } - } - return allowed; -} - class LLCategoryFireAndForget : public LLInventoryFetchComboObserver { public: @@ -558,8 +497,8 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLNoPreferredTypeOrItem is_not_preferred; - LLInventoryFetchComboObserver::folder_ref_t folder_ids; - LLInventoryFetchComboObserver::item_ref_t item_ids; + uuid_vec_t folder_ids; + uuid_vec_t item_ids; if(is_not_preferred(cat, NULL)) { folder_ids.push_back(cargo_id); @@ -649,9 +588,9 @@ void LLToolDragAndDrop::beginMultiDrag( } if(!cat_ids.empty()) { - LLInventoryFetchComboObserver::folder_ref_t folder_ids; - LLInventoryFetchComboObserver::item_ref_t item_ids; - std::back_insert_iterator copier(folder_ids); + uuid_vec_t folder_ids; + uuid_vec_t item_ids; + std::back_insert_iterator copier(folder_ids); std::copy(cat_ids.begin(), cat_ids.end(), copier); LLCategoryFireAndForget fetcher; fetcher.fetch(folder_ids, item_ids); @@ -1561,447 +1500,6 @@ struct LLGiveInventoryInfo {} }; -void LLToolDragAndDrop::giveInventory(const LLUUID& to_agent, - LLInventoryItem* item, - const LLUUID& im_session_id) - -{ - llinfos << "LLToolDragAndDrop::giveInventory()" << llendl; - if(!isInventoryGiveAcceptable(item)) - { - return; - } - if(item->getPermissions().allowCopyBy(gAgent.getID())) - { - // just give it away. - LLToolDragAndDrop::commitGiveInventoryItem(to_agent, item, im_session_id); - } - else - { - // ask if the agent is sure. - LLSD payload; - payload["agent_id"] = to_agent; - payload["item_id"] = item->getUUID(); - LLNotificationsUtil::add("CannotCopyWarning", LLSD(), payload, - &LLToolDragAndDrop::handleCopyProtectedItem); - } -} -// static -bool LLToolDragAndDrop::handleCopyProtectedItem(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLInventoryItem* item = NULL; - switch(option) - { - case 0: // "Yes" - item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - if(item) - { - LLToolDragAndDrop::commitGiveInventoryItem(notification["payload"]["agent_id"].asUUID(), - item); - // delete it for now - it will be deleted on the server - // quickly enough. - gInventory.deleteObject(notification["payload"]["item_id"].asUUID()); - gInventory.notifyObservers(); - } - else - { - LLNotificationsUtil::add("CannotGiveItem"); - } - break; - - default: // no, cancel, whatever, who cares, not yes. - LLNotificationsUtil::add("TransactionCancelled"); - break; - } - return false; -} - -// static -void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent, - LLInventoryItem* item, - const LLUUID& im_session_id) -{ - if(!item) return; - std::string name; - gAgent.buildFullname(name); - LLUUID transaction_id; - transaction_id.generate(); - const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES; - U8 bucket[BUCKET_SIZE]; - bucket[0] = (U8)item->getType(); - memcpy(&bucket[1], &(item->getUUID().mData), UUID_BYTES); /* Flawfinder: ignore */ - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - to_agent, - name, - item->getName(), - IM_ONLINE, - IM_INVENTORY_OFFERED, - transaction_id, - 0, - LLUUID::null, - gAgent.getPositionAgent(), - NO_TIMESTAMP, - bucket, - BUCKET_SIZE); - gAgent.sendReliableMessage(); - // - if (gSavedSettings.getBOOL("BroadcastViewerEffects")) - { - // - // VEFFECT: giveInventory - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); - effectp->setSourceObject(gAgentAvatarp); - effectp->setTargetObject(gObjectList.findObject(to_agent)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - // - } - // - gFloaterTools->dirty(); - - LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); - - // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. - if (im_session_id != LLUUID::null) - { - LLSD args; - gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); - } - -} - -void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, - LLInventoryCategory* cat, - const LLUUID& im_session_id) - -{ - if(!cat) return; - llinfos << "LLToolDragAndDrop::giveInventoryCategory() - " - << cat->getUUID() << llendl; - - LLVOAvatar* my_avatar = gAgentAvatarp; - if( !my_avatar ) - { - return; - } - - // Test out how many items are being given. - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLGiveable giveable; - gInventory.collectDescendentsIf(cat->getUUID(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - giveable); - S32 count = cats.count(); - bool complete = true; - for(S32 i = 0; i < count; ++i) - { - if(!gInventory.isCategoryComplete(cats.get(i)->getUUID())) - { - complete = false; - break; - } - } - if(!complete) - { - LLNotificationsUtil::add("IncompleteInventory"); - return; - } - count = items.count() + cats.count(); - if(count > MAX_ITEMS) - { - LLNotificationsUtil::add("TooManyItems"); - return; - } - else if(count == 0) - { - LLNotificationsUtil::add("NoItems"); - return; - } - else - { - if(0 == giveable.countNoCopy()) - { - LLToolDragAndDrop::commitGiveInventoryCategory(to_agent, cat, im_session_id); - } - else - { - LLGiveInventoryInfo* info = NULL; - info = new LLGiveInventoryInfo(to_agent, cat->getUUID(), im_session_id); - LLSD args; - args["COUNT"] = llformat("%d",giveable.countNoCopy()); - LLSD payload; - payload["agent_id"] = to_agent; - payload["folder_id"] = cat->getUUID(); - LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLToolDragAndDrop::handleCopyProtectedCategory); - } - } -} - - -// static -bool LLToolDragAndDrop::handleCopyProtectedCategory(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLInventoryCategory* cat = NULL; - switch(option) - { - case 0: // "Yes" - cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID()); - if(cat) - { - LLToolDragAndDrop::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), - cat); - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLUncopyableItems remove; - gInventory.collectDescendentsIf(cat->getUUID(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - remove); - S32 count = items.count(); - for(S32 i = 0; i < count; ++i) - { - gInventory.deleteObject(items.get(i)->getUUID()); - } - gInventory.notifyObservers(); - } - else - { - LLNotificationsUtil::add("CannotGiveCategory"); - } - break; - - default: // no, cancel, whatever, who cares, not yes. - LLNotificationsUtil::add("TransactionCancelled"); - break; - } - return false; -} - -// static -void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, - LLInventoryCategory* cat, - const LLUUID& im_session_id) - -{ - if(!cat) return; - llinfos << "LLToolDragAndDrop::commitGiveInventoryCategory() - " - << cat->getUUID() << llendl; - - // Test out how many items are being given. - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLGiveable giveable; - gInventory.collectDescendentsIf(cat->getUUID(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - giveable); - - // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < - // MTUBYTES or 18 * count < 1200 => count < 1200/18 => - // 66. I've cut it down a bit from there to give some pad. - S32 count = items.count() + cats.count(); - if(count > MAX_ITEMS) - { - LLNotificationsUtil::add("TooManyItems"); - return; - } - else if(count == 0) - { - LLNotificationsUtil::add("NoItems"); - return; - } - else - { - std::string name; - gAgent.buildFullname(name); - LLUUID transaction_id; - transaction_id.generate(); - S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1); - U8* bucket = new U8[bucket_size]; - U8* pos = bucket; - U8 type = (U8)cat->getType(); - memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ - pos += sizeof(U8); - memcpy(pos, &(cat->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ - pos += UUID_BYTES; - S32 i; - count = cats.count(); - for(i = 0; i < count; ++i) - { - memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ - pos += sizeof(U8); - memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ - pos += UUID_BYTES; - } - count = items.count(); - for(i = 0; i < count; ++i) - { - type = (U8)items.get(i)->getType(); - memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ - pos += sizeof(U8); - memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ - pos += UUID_BYTES; - } - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - to_agent, - name, - cat->getName(), - IM_ONLINE, - IM_INVENTORY_OFFERED, - transaction_id, - 0, - LLUUID::null, - gAgent.getPositionAgent(), - NO_TIMESTAMP, - bucket, - bucket_size); - gAgent.sendReliableMessage(); - delete[] bucket; - // - if (gSavedSettings.getBOOL("BroadcastViewerEffects")) - { - // - // VEFFECT: giveInventoryCategory - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); - effectp->setSourceObject(gAgentAvatarp); - effectp->setTargetObject(gObjectList.findObject(to_agent)); - effectp->setDuration(LL_HUD_DUR_SHORT); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - // - } - // - gFloaterTools->dirty(); - - LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); - - // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. - if (im_session_id != LLUUID::null) - { - LLSD args; - gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); - } - } -} - -// static -BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item) -{ - if(!item) - { - return FALSE; - } - if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - return FALSE; - } - BOOL copyable = FALSE; - if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE; - - // - /*LLVOAvatar* my_avatar = gAgentAvatarp; - if(!my_avatar) - { - return FALSE; - }*/ - // - - // - //BOOL acceptable = FALSE; - BOOL acceptable = TRUE; - // Might also look at what's down below - // - switch(item->getType()) - { - case LLAssetType::AT_CALLINGCARD: - acceptable = FALSE; - break; - case LLAssetType::AT_OBJECT: - // - /*if(my_avatar->isWearingAttachment(item->getUUID())) - { - acceptable = FALSE; - }*/ - // - break; - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_CLOTHING: - // - /*if(!copyable && gAgentWearables.isWearingItem(item->getUUID())) - { - acceptable = FALSE; - }*/ - // - break; - default: - break; - } - return acceptable; -} - -// Static -BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item) -{ - if(!item) - { - return FALSE; - } - - // These permissions are double checked in the simulator in - // LLGroupNoticeInventoryItemFetch::result(). - if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - return FALSE; - } - if(!item->getPermissions().allowCopyBy(gAgent.getID())) - { - return FALSE; - } - - LLVOAvatar* my_avatar = gAgentAvatarp; - if(!my_avatar) - { - return FALSE; - } - - BOOL acceptable = TRUE; - // - /* - // - switch(item->getType()) - { - case LLAssetType::AT_CALLINGCARD: - acceptable = FALSE; - break; - case LLAssetType::AT_OBJECT: - if(my_avatar->isWearingAttachment(item->getUUID())) - { - acceptable = FALSE; - } - break; - default: - break; - } - // - */ - // - return acceptable; -} - // accessor that looks at permissions, copyability, and names of // inventory items to determine if a drop would be ok. EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item) @@ -2117,13 +1615,13 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) - && LLToolDragAndDrop::isInventoryGiveAcceptable(inv_item)) + && LLGiveInventory::isInventoryGiveAcceptable(inv_item)) { // *TODO: get multiple object transfers working *accept = ACCEPT_YES_COPY_SINGLE; if(drop) { - LLToolDragAndDrop::giveInventory(dest_agent, inv_item, session_id); + LLGiveInventory::doGiveInventoryItem(dest_agent, inv_item, session_id); } } else @@ -2145,7 +1643,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ *accept = ACCEPT_YES_COPY_SINGLE; if(drop) { - LLToolDragAndDrop::giveInventoryCategory(dest_agent, inv_cat, session_id); + LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id); } } else @@ -2868,7 +2366,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( { if(drop) { - giveInventory(obj->getID(), item ); + LLGiveInventory::doGiveInventoryItem(obj->getID(), item ); } // *TODO: deal with all the issues surrounding multi-object // inventory transfers. @@ -2888,13 +2386,13 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory( LLViewerInventoryCategory* cat; locateInventory(item, cat); if(!item || !item->isComplete()) return ACCEPT_NO; - if(!isInventoryGiveAcceptable(item)) + if(!LLGiveInventory::isInventoryGiveAcceptable(item)) { return ACCEPT_NO; } if(drop && obj) { - giveInventory(obj->getID(), item); + LLGiveInventory::doGiveInventoryItem(obj->getID(), item); } // *TODO: deal with all the issues surrounding multi-object // inventory transfers. @@ -2911,7 +2409,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory( LLViewerInventoryCategory* cat; locateInventory(item, cat); if(!cat) return ACCEPT_NO; - giveInventoryCategory(obj->getID(), cat); + LLGiveInventory::doGiveInventoryCategory(obj->getID(), cat); } // *TODO: deal with all the issues surrounding multi-object // inventory transfers. diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index f9e5bec14..b03f7f98d 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -208,27 +208,10 @@ protected: LLToolDragAndDrop::ESource source, const LLUUID& src_id); - - // give inventory item functionality - static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response); - static void commitGiveInventoryItem(const LLUUID& to_agent, - LLInventoryItem* item, - const LLUUID &im_session_id = LLUUID::null); - - // give inventory category functionality - static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response); - static void commitGiveInventoryCategory(const LLUUID& to_agent, - LLInventoryCategory* cat, - const LLUUID &im_session_id = LLUUID::null); - public: // helper functions static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); } - // This simple helper function assumes you are attempting to - // transfer item. returns true if you can give, otherwise false. - static BOOL isInventoryGiveAcceptable(LLInventoryItem* item); - static BOOL isInventoryGroupGiveAcceptable(LLInventoryItem* item); BOOL dadUpdateInventory(LLViewerObject* obj, BOOL drop); BOOL dadUpdateInventoryCategory(LLViewerObject* obj, BOOL drop); @@ -255,13 +238,6 @@ public: ESource source, const LLUUID& src_id); - static void giveInventory(const LLUUID& to_agent, - LLInventoryItem* item, - const LLUUID &session_id = LLUUID::null); - static void giveInventoryCategory(const LLUUID& to_agent, - LLInventoryCategory* item, - const LLUUID &session_id = LLUUID::null); - static bool handleGiveDragAndDrop(LLUUID agent, LLUUID session, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp new file mode 100644 index 000000000..85dbcc562 --- /dev/null +++ b/indra/newview/llviewerfoldertype.cpp @@ -0,0 +1,303 @@ +/** + * @file llfoldertype.cpp + * @brief Implementation of LLViewerFolderType functionality. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerfoldertype.h" +#include "lldictionary.h" +#include "llmemory.h" +#include "llvisualparam.h" + +static const std::string empty_string; + +struct ViewerFolderEntry : public LLDictionaryEntry +{ + // Constructor for non-ensembles + ViewerFolderEntry(const std::string &new_category_name, // default name when creating a new category of this type + const std::string &icon_name_open, // name of the folder icon + const std::string &icon_name_closed, + BOOL is_quiet, // folder doesn't need a UI update when changed + const std::string &dictionary_name = empty_string // no reverse lookup needed on non-ensembles, so in most cases just leave this blank + ) + : + LLDictionaryEntry(dictionary_name), + mNewCategoryName(new_category_name), + mIconNameOpen(icon_name_open), + mIconNameClosed(icon_name_closed), + mIsQuiet(is_quiet) + { + mAllowedNames.clear(); + } + + // Constructor for ensembles + ViewerFolderEntry(const std::string &xui_name, // name of the xui menu item + const std::string &new_category_name, // default name when creating a new category of this type + const std::string &icon_name, // name of the folder icon + const std::string allowed_names // allowed item typenames for this folder type + ) + : + LLDictionaryEntry(xui_name), + /* Just use default icons until we actually support ensembles + mIconNameOpen(icon_name), + mIconNameClosed(icon_name), + */ + mIconNameOpen("Inv_FolderOpen"), mIconNameClosed("Inv_FolderClosed"), + mNewCategoryName(new_category_name), + mIsQuiet(FALSE) + { + const std::string delims (","); + LLStringUtilBase::getTokens(allowed_names, mAllowedNames, delims); + } + + bool getIsAllowedName(const std::string &name) const + { + if (mAllowedNames.empty()) + return false; + for (name_vec_t::const_iterator iter = mAllowedNames.begin(); + iter != mAllowedNames.end(); + iter++) + { + if (name == (*iter)) + return true; + } + return false; + } + const std::string mIconNameOpen; + const std::string mIconNameClosed; + const std::string mNewCategoryName; + typedef std::vector name_vec_t; + name_vec_t mAllowedNames; + BOOL mIsQuiet; +}; + +class LLViewerFolderDictionary : public LLSingleton, + public LLDictionary +{ +public: + LLViewerFolderDictionary(); +protected: + bool initEnsemblesFromFile(); // Reads in ensemble information from foldertypes.xml +}; + +LLViewerFolderDictionary::LLViewerFolderDictionary() +{ + // NEW CATEGORY NAME FOLDER OPEN FOLDER CLOSED QUIET? + // |-------------------------|-----------------------|----------------------|-----------| + addEntry(LLFolderType::FT_TEXTURE, new ViewerFolderEntry("Textures", "inv_folder_texture.tga", "inv_folder_texture.tga", FALSE)); + addEntry(LLFolderType::FT_SOUND, new ViewerFolderEntry("Sounds", "inv_folder_sound.tga", "inv_folder_sound.tga", FALSE)); + addEntry(LLFolderType::FT_CALLINGCARD, new ViewerFolderEntry("Calling Cards", "inv_folder_callingcard.tga", "inv_folder_callingcard.tga", FALSE)); + addEntry(LLFolderType::FT_LANDMARK, new ViewerFolderEntry("Landmarks", "inv_folder_landmark.tga", "inv_folder_landmark.tga", FALSE)); + addEntry(LLFolderType::FT_CLOTHING, new ViewerFolderEntry("Clothing", "inv_folder_clothing.tga", "inv_folder_clothing.tga", FALSE)); + addEntry(LLFolderType::FT_OBJECT, new ViewerFolderEntry("Objects", "inv_folder_object.tga", "inv_folder_object.tga", FALSE)); + addEntry(LLFolderType::FT_NOTECARD, new ViewerFolderEntry("Notecards", "inv_folder_notecard.tga", "inv_folder_notecard.tga", FALSE)); + addEntry(LLFolderType::FT_ROOT_INVENTORY, new ViewerFolderEntry("My Inventory", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry(LLFolderType::FT_LSL_TEXT, new ViewerFolderEntry("Scripts", "inv_folder_script.tga", "inv_folder_script.tga", FALSE)); + addEntry(LLFolderType::FT_BODYPART, new ViewerFolderEntry("Body Parts", "inv_folder_bodypart.tga", "inv_folder_bodypart.tga", FALSE)); + addEntry(LLFolderType::FT_TRASH, new ViewerFolderEntry("Trash", "inv_folder_trash.tga", "inv_folder_trash.tga", TRUE)); + addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new ViewerFolderEntry("Photo Album", "inv_folder_snapshot.tga", "inv_folder_snapshot.tga", FALSE)); + addEntry(LLFolderType::FT_LOST_AND_FOUND, new ViewerFolderEntry("Lost And Found", "inv_folder_lostandfound.tga", "inv_folder_lostandfound.tga", TRUE)); + addEntry(LLFolderType::FT_ANIMATION, new ViewerFolderEntry("Animations", "inv_folder_animation.tga", "inv_folder_animation.tga", FALSE)); + addEntry(LLFolderType::FT_GESTURE, new ViewerFolderEntry("Gestures", "inv_folder_gesture.tga", "inv_folder_gesture.tga", FALSE)); + addEntry(LLFolderType::FT_FAVORITE, new ViewerFolderEntry("Favorites", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + + addEntry(LLFolderType::FT_CURRENT_OUTFIT, new ViewerFolderEntry("Current Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); + addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); + addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", TRUE)); + addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + + addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + + addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + + addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE, "default")); + +#if SUPPORT_ENSEMBLES + initEnsemblesFromFile(); +#else + for (U32 type = (U32)LLFolderType::FT_ENSEMBLE_START; type <= (U32)LLFolderType::FT_ENSEMBLE_END; ++type) + { + addEntry((LLFolderType::EType)type, new ViewerFolderEntry("New Folder", "inv_folder_plain_closed.tga", "inv_folder_plain_closed.tga", FALSE)); + } +#endif +} + +bool LLViewerFolderDictionary::initEnsemblesFromFile() +{ + std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"foldertypes.xml"); + LLXmlTree folder_def; + if (!folder_def.parseFile(xml_filename)) + { + llerrs << "Failed to parse folders file " << xml_filename << llendl; + return false; + } + + LLXmlTreeNode* rootp = folder_def.getRoot(); + for (LLXmlTreeNode* ensemble = rootp->getFirstChild(); + ensemble; + ensemble = rootp->getNextChild()) + { + if (!ensemble->hasName("ensemble")) + { + llwarns << "Invalid ensemble definition node " << ensemble->getName() << llendl; + continue; + } + + S32 ensemble_type; + static LLStdStringHandle ensemble_num_string = LLXmlTree::addAttributeString("foldertype_num"); + if (!ensemble->getFastAttributeS32(ensemble_num_string, ensemble_type)) + { + llwarns << "No ensemble type defined" << llendl; + continue; + } + + + if (ensemble_type < S32(LLFolderType::FT_ENSEMBLE_START) || ensemble_type > S32(LLFolderType::FT_ENSEMBLE_END)) + { + llwarns << "Exceeded maximum ensemble index" << LLFolderType::FT_ENSEMBLE_END << llendl; + break; + } + + std::string xui_name; + static LLStdStringHandle xui_name_string = LLXmlTree::addAttributeString("xui_name"); + if (!ensemble->getFastAttributeString(xui_name_string, xui_name)) + { + llwarns << "No xui name defined" << llendl; + continue; + } + + std::string icon_name; + static LLStdStringHandle icon_name_string = LLXmlTree::addAttributeString("icon_name"); + if (!ensemble->getFastAttributeString(icon_name_string, icon_name)) + { + llwarns << "No ensemble icon name defined" << llendl; + continue; + } + + std::string allowed_names; + static LLStdStringHandle allowed_names_string = LLXmlTree::addAttributeString("allowed"); + if (!ensemble->getFastAttributeString(allowed_names_string, allowed_names)) + { + } + + // Add the entry and increment the asset number. + const static std::string new_ensemble_name = "New Ensemble"; + addEntry(LLFolderType::EType(ensemble_type), new ViewerFolderEntry(xui_name, new_ensemble_name, icon_name, allowed_names)); + } + + return true; +} + + +const std::string &LLViewerFolderType::lookupXUIName(LLFolderType::EType folder_type) +{ + const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type); + if (entry) + { + return entry->mName; + } + return badLookup(); +} + +LLFolderType::EType LLViewerFolderType::lookupTypeFromXUIName(const std::string &name) +{ + return LLViewerFolderDictionary::getInstance()->lookup(name); +} + +const std::string &LLViewerFolderType::lookupIconName(LLFolderType::EType folder_type, BOOL is_open) +{ + const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type); + if (entry) + { + if (is_open) + return entry->mIconNameOpen; + else + return entry->mIconNameClosed; + } + + // Error condition. Return something so that we don't show a grey box in inventory view. + const ViewerFolderEntry *default_entry = LLViewerFolderDictionary::getInstance()->lookup(LLFolderType::FT_NONE); + if (default_entry) + { + return default_entry->mIconNameClosed; + } + + // Should not get here unless there's something corrupted with the FT_NONE entry. + return badLookup(); +} + +BOOL LLViewerFolderType::lookupIsQuietType(LLFolderType::EType folder_type) +{ + const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type); + if (entry) + { + return entry->mIsQuiet; + } + return FALSE; +} + + +const std::string &LLViewerFolderType::lookupNewCategoryName(LLFolderType::EType folder_type) +{ + const ViewerFolderEntry *entry = LLViewerFolderDictionary::getInstance()->lookup(folder_type); + if (entry) + { + return entry->mNewCategoryName; + } + return badLookup(); +} + +LLFolderType::EType LLViewerFolderType::lookupTypeFromNewCategoryName(const std::string& name) +{ + for (LLViewerFolderDictionary::const_iterator iter = LLViewerFolderDictionary::getInstance()->begin(); + iter != LLViewerFolderDictionary::getInstance()->end(); + iter++) + { + const ViewerFolderEntry *entry = iter->second; + if (entry->mNewCategoryName == name) + { + return iter->first; + } + } + return FT_NONE; +} + + +U64 LLViewerFolderType::lookupValidFolderTypes(const std::string& item_name) +{ + U64 matching_folders = 0; + for (LLViewerFolderDictionary::const_iterator iter = LLViewerFolderDictionary::getInstance()->begin(); + iter != LLViewerFolderDictionary::getInstance()->end(); + iter++) + { + const ViewerFolderEntry *entry = iter->second; + if (entry->getIsAllowedName(item_name)) + { + matching_folders |= 1LL << iter->first; + } + } + return matching_folders; +} diff --git a/indra/newview/llviewerfoldertype.h b/indra/newview/llviewerfoldertype.h new file mode 100644 index 000000000..f5938de61 --- /dev/null +++ b/indra/newview/llviewerfoldertype.h @@ -0,0 +1,53 @@ +/** + * @file llviewerfoldertype.h + * @brief Declaration of LLAssetType. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERFOLDERTYPE_H +#define LL_LLVIEWERFOLDERTYPE_H + +#include +#include "llfoldertype.h" + +// This class is similar to llfoldertype, but contains methods +// only used by the viewer. This also handles ensembles. +class LLViewerFolderType : public LLFolderType +{ +public: + static const std::string& lookupXUIName(EType folder_type); // name used by the UI + static LLFolderType::EType lookupTypeFromXUIName(const std::string& name); + + static const std::string& lookupIconName(EType folder_type, BOOL is_open = FALSE); // folder icon name + static BOOL lookupIsQuietType(EType folder_type); // folder doesn't require UI update when changes have occured + static const std::string& lookupNewCategoryName(EType folder_type); // default name when creating new category + static LLFolderType::EType lookupTypeFromNewCategoryName(const std::string& name); // default name when creating new category + + static U64 lookupValidFolderTypes(const std::string& item_name); // which folders allow an item of this type? + +protected: + LLViewerFolderType() {} + ~LLViewerFolderType() {} +}; + +#endif // LL_LLVIEWERFOLDERTYPE_H diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index de0c3f575..1d07ebae5 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -167,6 +167,8 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" +#include "llgiveinventory.h" + #include #if LL_WINDOWS // For Windows specific error handler @@ -1972,7 +1974,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) position, false); } - LLToolDragAndDrop::giveInventory(from_id, item); + LLGiveInventory::doGiveInventoryItem(from_id, item); } } } diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp index da62f0e73..bd7771c46 100644 --- a/indra/newview/rlvinventory.cpp +++ b/indra/newview/rlvinventory.cpp @@ -18,6 +18,7 @@ #include "llagent.h" #include "llcallbacklist.h" #include "llstartup.h" +#include "llviewerfoldertype.h" #include "llviewerobject.h" #include "llvoavatar.h" @@ -29,9 +30,6 @@ #include "boost/algorithm/string.hpp" -// Only defined in llinventorymodel.cpp -extern const char* NEW_CATEGORY_NAME; - // ============================================================================ // Static variable initialization // @@ -394,6 +392,7 @@ void RlvRenameOnWearObserver::doneIdle() continue; } + static const std::string &new_category_name = LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE); for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++) { LLViewerInventoryItem* pItem = items.get(idxItem); @@ -428,7 +427,7 @@ void RlvRenameOnWearObserver::doneIdle() std::string strFolderName = ".(" + strAttachPt + ")"; // Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object - if ( (NEW_CATEGORY_NAME == pFolder->getName()) && + if ( (new_category_name == pFolder->getName()) && (pFolder->getParentUUID() != pRlvRoot->getUUID()) && (1 == RlvInventory::getDirectDescendentsCount(pFolder, LLAssetType::AT_OBJECT)) ) {