From 2e564abcd682c348de3a2d3a50ef58df545c143b Mon Sep 17 00:00:00 2001 From: Leslie Linden Date: Thu, 15 Dec 2011 14:26:42 -0800 Subject: EXP-1730 FIX EXP-1731 FIX EXP-1735 FIX EXP-1736 FIX EXP-1737 FIX EXP-1738 FIX EXP-1739 FIX * Users can no longer drag and drop items to the outbox from in world, notecards or the library. * Drag and drop now blocks the creation of hierarchies that are too deep, too many folders or contain too many items. * Settings now exist to specify drag and drop limitations to the outbox, named: InventoryOutboxMaxFolderDepth (4) InventoryOutboxMaxFolderCount (20) InventoryOutboxMaxItemCount (200) --- indra/newview/llinventorymodel.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index dc25689fa3..2fb9c53857 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -217,6 +217,38 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons return NULL; } +// +// Search up the parent chain until we get to the specified parent, then return the first child category under it +// +const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const +{ + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; +} + // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { -- cgit v1.2.3 From bd3a652eabf09a5843a6a0b8a9f60c4b402ecce5 Mon Sep 17 00:00:00 2001 From: Aura Linden Date: Fri, 6 Jan 2012 07:46:53 -0500 Subject: Add capability-based create folder routine for more reliable inventory, with fix for copy and wear --- indra/newview/llinventorymodel.cpp | 87 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index dc25689fa3..568ec4c5e2 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -377,14 +377,67 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe return rv; } +class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder +{ +public: + LLCreateInventoryCategoryResponder(LLInventoryModel* model, + void (*callback)(const LLSD&, void*), + void* user_data) : + mModel(model), + mCallback(callback), + mData(user_data) + { + } + + virtual void error(U32 status, const std::string& reason) + { + LL_WARNS("InvAPI") << "CreateInventoryCategory failed. status = " << status << ", reasion = \"" << reason << "\"" << LL_ENDL; + } + + virtual void result(const LLSD& content) + { + //Server has created folder. + + LLUUID category_id = content["folder_id"].asUUID(); + + + // Add the category to the internal representation + LLPointer cat = + new LLViewerInventoryCategory( category_id, + content["parent_id"].asUUID(), + (LLFolderType::EType)content["type"].asInteger(), + content["name"].asString(), + gAgent.getID() ); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setDescendentCount(0); + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + mModel->accountForUpdate(update); + mModel->updateCategory(cat); + + if (mCallback && mData) + { + mCallback(content, mData); + } + + } + +private: + void (*mCallback)(const LLSD&, void*); + void* mData; + LLInventoryModel* mModel; +}; + // Convenience function to create a new category. You could call // updateCategory() with a newly generated UUID category, but this // version will take care of details like what the name should be // based on preferred type. Returns the UUID of the new category. LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, - const std::string& pname) + const std::string& pname, + void (*callback)(const LLSD&, void*), //Default to NULL + void* user_data) //Default to NULL { + LLUUID id; if(!isInventoryUsable()) { @@ -408,6 +461,35 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } + + if ( callback && user_data ) //callback required for acked message. + { + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty()) + { + //Let's use the new capability. + + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; + + // viewer_region->getCapAPI().post(request); + LLHTTPClient::post( + url, + body, + new LLCreateInventoryCategoryResponder(this, callback, user_data) ); + return LLUUID::null; + } + } // Add the category to the internal representation LLPointer cat = @@ -1087,7 +1169,6 @@ void LLInventoryModel::notifyObservers() iter != mObservers.end(); ) { LLInventoryObserver* observer = *iter; - observer->changed(mModifyMask); // safe way to increment since changed may delete entries! (@!##%@!@&*!) @@ -2574,7 +2655,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) << titem->getParentUUID() << llendl; U32 callback_id; msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); - if(titem->getUUID().notNull()) + if(titem->getUUID().notNull() ) // && callback_id.notNull() ) { items.push_back(titem); cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); -- cgit v1.2.3 From 7b866448dbeeeb04b074df493369927afcf9971a Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 12 Mar 2012 13:59:25 -0700 Subject: EXP-1922 : Skip the clipboard elements when purging the trash when in cut mode --- indra/newview/llinventorymodel.cpp | 114 ++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 41 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a71b699fdd..06e780508b 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -30,6 +30,7 @@ #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llclipboard.h" #include "llinventorypanel.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -1110,50 +1111,81 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) return; } LLPointer cat = getCategory(id); - if(cat.notNull()) - { - // do the cache accounting - llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << llendl; - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLCategoryUpdate up(id, -descendents); - accountForUpdate(up); + if (cat.notNull()) + { + if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) + { + // Something on the clipboard is in "cut mode" and needs to be preserved + llinfos << "Merov debug : purging through iteration" << llendl; + cat_array_t* categories; + item_array_t* items; + // Get the list of direct descendants in tha categoy passed as argument + getDirectDescendentsOf(id, categories, items); + std::vector list_uuids; + // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) + // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists + for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + // Iterate through the list and only purge the UUIDs that are not on the clipboard + for (std::vector::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + if (!LLClipboard::instance().isOnClipboard(*it)) + { + purgeObject(*it); + } + } } + else + { + // Fast purge + // do the cache accounting + llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() + << llendl; + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLCategoryUpdate up(id, -descendents); + accountForUpdate(up); + } - // we know that descendent count is 0, aide since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // send it upstream + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("PurgeInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", id); + gAgent.sendReliableMessage(); - // send it upstream - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("PurgeInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", id); - gAgent.sendReliableMessage(); - - // unceremoniously remove anything we have locally stored. - cat_array_t categories; - item_array_t items; - collectDescendents(id, - categories, - items, - INCLUDE_TRASH); - S32 count = items.count(); - S32 i; - for(i = 0; i < count; ++i) - { - deleteObject(items.get(i)->getUUID()); - } - count = categories.count(); - for(i = 0; i < count; ++i) - { - deleteObject(categories.get(i)->getUUID()); + // unceremoniously remove anything we have locally stored. + cat_array_t categories; + item_array_t items; + collectDescendents(id, + categories, + items, + INCLUDE_TRASH); + S32 count = items.count(); + for(S32 i = 0; i < count; ++i) + { + deleteObject(items.get(i)->getUUID()); + } + count = categories.count(); + for(S32 i = 0; i < count; ++i) + { + deleteObject(categories.get(i)->getUUID()); + } } } } -- cgit v1.2.3 From 82700548058527001657758888cf79df099064b3 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 13 Mar 2012 21:08:10 -0700 Subject: EXP-1915 : Rewrote the fetching mechanism for folders making it truly recursive. --- indra/newview/llinventorymodel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 06e780508b..0eba8bd0f1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1116,7 +1116,8 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) if (LLClipboard::instance().hasContents() && LLClipboard::instance().isCutMode()) { // Something on the clipboard is in "cut mode" and needs to be preserved - llinfos << "Merov debug : purging through iteration" << llendl; + llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() + << " iterate and purge non hidden items" << llendl; cat_array_t* categories; item_array_t* items; // Get the list of direct descendants in tha categoy passed as argument -- cgit v1.2.3 From fdd018783a0cc06a467443ca7c9ea0876a87ef49 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 27 Mar 2012 18:40:17 -0400 Subject: CHOP-854: move change_(item|category)_parent() into LLInventoryModel. It's not really clear why they're in llinventoryfunctions.{h,cpp} instead of LLInventoryModel, and in fact LLInventoryModel::removeItem() already contains code essentially cloned from change_item_parent() -- or perhaps vice-versa. This changeset addresses only migrating the functions, and fixing up existing references, to simplify code review. --- indra/newview/llinventorymodel.cpp | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a71b699fdd..6cc0d6768e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1017,6 +1017,58 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) } } +// Migrated from llinventoryfunctions +void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp) +{ + 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); + accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } +} + +// Migrated from llinventoryfunctions +void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp) +{ + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + 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); + accountForUpdate(update); + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); +} + // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id) { -- cgit v1.2.3 From b8561da34d5d733670b6b1eabf483871ec6c18b0 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 27 Mar 2012 19:06:33 -0400 Subject: CHOP-854: Make LLInventoryModel::removeItem() call changeItemParent(). The body of removeItem() was already nearly identical to the body of changeItemParent(); this eliminates the redundancy. Improve logging for changeItemParent(). --- indra/newview/llinventorymodel.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 6cc0d6768e..de52f3a18d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1022,8 +1022,16 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, const LLUUID& new_parent_id, BOOL restamp) { - if (item->getParentUUID() != new_parent_id) + if (item->getParentUUID() == new_parent_id) { + LL_DEBUGS("Inventory") << "'" << item->getName() << "' (" << item->getUUID() + << ") is already in folder " << new_parent_id << LL_ENDL; + } + else + { + LL_INFOS("Inventory") << "Moving '" << item->getName() << "' (" << item->getUUID() + << ") from " << item->getParentUUID() << " to folder " + << new_parent_id << LL_ENDL; LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); update.push_back(old_folder); @@ -2983,21 +2991,15 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT void LLInventoryModel::removeItem(const LLUUID& item_id) { LLViewerInventoryItem* item = getItem(item_id); - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if (item && item->getParentUUID() != new_parent) + if (! item) { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent); - new_item->updateParentOnServer(TRUE); - updateItem(new_item); - notifyObservers(); + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); } } -- cgit v1.2.3 From b7e0e44e3246299b639f787e3ab9b8e59cdc05c3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 27 Mar 2012 22:39:31 -0400 Subject: CHOP-854: Use new LLInventoryModel::removeObject() to discard offer. Introduce new LLInventoryModel::removeCategory() method comparable to removeItem(), but for folder objects (using changeCategoryParent() rather than changeItemParent()). Introduce removeObject() method that calls one of the above, depending on runtime object type. --- indra/newview/llinventorymodel.cpp | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index de52f3a18d..1ede6bc1c9 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -46,6 +46,7 @@ #include "llviewerregion.h" #include "llcallbacklist.h" #include "llvoavatarself.h" +#include //#define DIFF_INVENTORY_FILES #ifdef DIFF_INVENTORY_FILES @@ -3003,6 +3004,44 @@ void LLInventoryModel::removeItem(const LLUUID& item_id) } } +void LLInventoryModel::removeCategory(const LLUUID& category_id) +{ + LLViewerInventoryCategory* cat = getCategory(category_id); + if (! cat) + { + LL_WARNS("Inventory") << "couldn't find inventory folder " << category_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeCategoryParent(cat, new_parent, TRUE); + } +} + +void LLInventoryModel::removeObject(const LLUUID& object_id) +{ + LLInventoryObject* obj = getObject(object_id); + if (dynamic_cast(obj)) + { + removeItem(object_id); + } + else if (dynamic_cast(obj)) + { + removeCategory(object_id); + } + else if (obj) + { + LL_WARNS("Inventory") << "object ID " << object_id + << " is an object of unrecognized class " + << typeid(*obj).name() << LL_ENDL; + } + else + { + LL_WARNS("Inventory") << "object ID " << object_id << " not found" << LL_ENDL; + } +} + const LLUUID &LLInventoryModel::getRootFolderID() const { return mRootFolderID; -- cgit v1.2.3 From ee87fd975faf403707908cd3c7d37f8431df46ac Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 14 Apr 2012 22:23:24 -0400 Subject: DRTVWR-136: Remove redundant remove_(item|category)() functions. Incoming changes from two different project repos left viewer-development with LLInventoryModel::removeItem() and removeCategory() plus free functions remove_item() and remove_category() in llinventoryfunctions.cpp. remove_category() was actually the better implementation; migrated its body into LLInventoryModel::removeCategory(). Clearly the previous state of affairs -- with LLInventoryModel::removeItem() plus a remove_category() free function in a very different source file -- fooled two different developers into overlooking the other of the pair. Unfortunately we each added different "missing" functions, leaving us with a complete set of four. Fix existing references to remove_item() and remove_category() free functions. --- indra/newview/llinventorymodel.cpp | 43 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'indra/newview/llinventorymodel.cpp') diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 1ea4cb63f6..85ecb133d0 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -47,6 +47,7 @@ #include "llviewerregion.h" #include "llcallbacklist.h" #include "llvoavatarself.h" +#include "llgesturemgr.h" #include //#define DIFF_INVENTORY_FILES @@ -3032,23 +3033,47 @@ void LLInventoryModel::removeItem(const LLUUID& item_id) else { const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; - changeItemParent(item, new_parent, TRUE); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } } } void LLInventoryModel::removeCategory(const LLUUID& category_id) { - LLViewerInventoryCategory* cat = getCategory(category_id); - if (! cat) + if (! get_is_category_removable(this, category_id)) { - LL_WARNS("Inventory") << "couldn't find inventory folder " << category_id << LL_ENDL; + return; } - else + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) { - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; - changeCategoryParent(cat, new_parent, TRUE); + 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 = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } } } -- cgit v1.2.3