From 27046fcc14239d36604790c993a90394361ec873 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 21 Nov 2022 13:48:23 +0000 Subject: SL-18629 - moving createNewCategory to AIS3 --- indra/llmessage/message.cpp | 1 + indra/newview/llappearancemgr.cpp | 7 +++++-- indra/newview/llinventorymodel.cpp | 9 +++++---- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 19146c64f4..31acc65642 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -3402,6 +3402,7 @@ typedef std::map BuilderMap; void LLMessageSystem::newMessageFast(const char *name) { + //LL_DEBUGS("Messaging") << "creating new message: " << name << LL_ENDL; LLMessageConfig::Flavor message_flavor = LLMessageConfig::getMessageFlavor(name); LLMessageConfig::Flavor server_flavor = diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 909f32cd21..ab7adeeedc 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1701,6 +1701,7 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds { parent_id = gInventory.getRootFolderID(); } + // USES UDP PATH LLUUID subfolder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_NONE, src_cat->getName()); @@ -2725,7 +2726,8 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap { pid = gInventory.getRootFolderID(); } - + + // UDP PATH LLUUID new_cat_id = gInventory.createNewCategory( pid, LLFolderType::FT_NONE, @@ -3994,7 +3996,8 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo func); } else - { + { + // UDP PATH LLUUID folder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_OUTFIT, diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index fab7ae8f1a..36797a3f28 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -664,24 +664,25 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp // 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. +// +// On failure, returns a null UUID. +// FIXME: callers do not check for or handle a null results currently. LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& pname, inventory_func_type callback) { - LLUUID id; + LLUUID id; // Initially null. if (!isInventoryUsable()) { LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type " << preferred_type << LL_ENDL; - // FIXME failing but still returning an id? return id; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; - // FIXME failing but still returning an id? return id; } @@ -708,7 +709,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, std::string url; if ( viewer_region ) url = viewer_region->getCapability("CreateInventoryCategory"); - + if (!url.empty() && callback) { //Let's use the new capability. -- cgit v1.2.3 From f6208020f5b27b84aeb9ca258e8dbddce9c49bce Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 22 Nov 2022 15:46:08 +0000 Subject: SL-18629 - use AISAPI for some paths of new category creation --- indra/newview/llaisapi.cpp | 30 +++++++++++++++++++++++++++--- indra/newview/llaisapi.h | 3 ++- indra/newview/llappearancemgr.cpp | 1 + indra/newview/llinventorymodel.cpp | 35 +++++++++-------------------------- 4 files changed, 39 insertions(+), 30 deletions(-) (limited to 'indra') diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 005259bcb8..d2c59cfaba 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -100,7 +100,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c tid.generate(); std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + LL_DEBUGS("Inventory") << "url: " << url << " parentID " << parentId << " newInventory " << newInventory << LL_ENDL; // I may be suffering from golden hammer here, but the first part of this bind // is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that @@ -124,7 +124,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6); LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY)); + _1, postFn, url, parentId, newInventory, callback, CREATEINVENTORY)); EnqueueAISCommand("CreateInventory", proc); } @@ -478,6 +478,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; } + LL_DEBUGS("Inventory") << result << LL_ENDL; gInventory.onAISUpdateReceived("AISCommand", result); if (callback && !callback.empty()) @@ -487,9 +488,32 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) { id = result["category_id"]; + callback(id); } + if (type == CREATEINVENTORY) + { + if (result.has("_created_categories")) + { + LLSD& cats = result["_created_categories"]; + LLSD::array_const_iterator cat_iter; + for (cat_iter = cats.beginArray(); cat_iter != cats.endArray(); ++cat_iter) + { + LLUUID cat_id = *cat_iter; + callback(cat_id); + } + } + if (result.has("_created_items")) + { + LLSD& items = result["_created_items"]; + LLSD::array_const_iterator item_iter; + for (item_iter = items.beginArray(); item_iter != items.endArray(); ++item_iter) + { + LLUUID item_id = *item_iter; + callback(item_id); + } + } + } - callback(id); } } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 856f3fc180..6e9cc19baa 100644 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -61,7 +61,8 @@ private: PURGEDESCENDENTS, UPDATECATEGORY, UPDATEITEM, - COPYLIBRARYCATEGORY + COPYLIBRARYCATEGORY, + CREATEINVENTORY } COMMAND_TYPE; static const std::string INVENTORY_CAP_NAME; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index ab7adeeedc..4fc09c7739 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3989,6 +3989,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo // existence of AIS as an indicator the fix is present. Does // not actually use AIS to create the category. inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); + LLUUID folder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_OUTFIT, diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 36797a3f28..a7b3076e52 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -694,38 +694,20 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LL_WARNS(LOG_INV) << "Creating new system folder, type " << preferred_type << LL_ENDL; } - id.generate(); std::string name = pname; - if(!pname.empty()) - { - name.assign(pname); - } - else + if (pname.empty()) { name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); - - if (!url.empty() && callback) + if (callback) { - //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; - - LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; - LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", - boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["categories"] = LLSD::emptyArray(); + LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); + LLSD cat_sd = cat.asLLSD(); + new_inventory["categories"].append(cat_sd); + AISAPI::CreateInventory(parent_id, new_inventory, callback); return LLUUID::null; } @@ -740,6 +722,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, // assuming instant success. // Add the category to the internal representation + id.generate(); LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 -- cgit v1.2.3 From 819eec6f8c3abbf71ec3bdaaf4891068574fdc46 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 9 Jan 2023 21:14:16 +0000 Subject: SL-18924 - basic get/set functions for thumbnail UUID, removed obsolete binary pack/unpack functions for inventory --- indra/llinventory/llinventory.cpp | 148 ++++--------------------- indra/llinventory/llinventory.h | 6 +- indra/llinventory/tests/inventorymisc_test.cpp | 20 ---- 3 files changed, 22 insertions(+), 152 deletions(-) (limited to 'indra') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 81261f0767..b897198d10 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -40,9 +40,11 @@ ///---------------------------------------------------------------------------- /// Exported functions ///---------------------------------------------------------------------------- +// FIXME D567 - what's the point of these, especially if we don't even use them consistently? static const std::string INV_ITEM_ID_LABEL("item_id"); static const std::string INV_FOLDER_ID_LABEL("cat_id"); static const std::string INV_PARENT_ID_LABEL("parent_id"); +static const std::string INV_THUMBNAIL_ID_LABEL("thumbnail_id"); static const std::string INV_ASSET_TYPE_LABEL("type"); static const std::string INV_PREFERRED_TYPE_LABEL("preferred_type"); static const std::string INV_INVENTORY_TYPE_LABEL("inv_type"); @@ -99,6 +101,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other) mParentUUID = other->mParentUUID; mType = other->mType; mName = other->mName; + mThumbnailUUID = other->mThumbnailUUID; } const LLUUID& LLInventoryObject::getUUID() const @@ -111,6 +114,11 @@ const LLUUID& LLInventoryObject::getParentUUID() const return mParentUUID; } +const LLUUID& LLInventoryObject::getThumbnailUUID() const +{ + return mThumbnailUUID; +} + const std::string& LLInventoryObject::getName() const { return mName; @@ -160,6 +168,11 @@ void LLInventoryObject::setParent(const LLUUID& new_parent) mParentUUID = new_parent; } +void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid) +{ + mThumbnailUUID = thumbnail_uuid; +} + void LLInventoryObject::setType(LLAssetType::EType type) { mType = type; @@ -972,135 +985,6 @@ fail: } -// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML() -// because I can't find any non-test code references to it. 2009-05-04 JC - -S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const -{ - // Figure out which permissions to use. - LLPermissions perm; - if (perm_override) - { - // Use the permissions override. - perm = *perm_override; - } - else - { - // Use the current permissions. - perm = getPermissions(); - } - - // describe the inventory item - char* buffer = (char*) bin_bucket; - std::string creator_id_str; - - perm.getCreator().toString(creator_id_str); - std::string owner_id_str; - perm.getOwner().toString(owner_id_str); - std::string last_owner_id_str; - perm.getLastOwner().toString(last_owner_id_str); - std::string group_id_str; - perm.getGroup().toString(group_id_str); - std::string asset_id_str; - getAssetUUID().toString(asset_id_str); - S32 size = sprintf(buffer, /* Flawfinder: ignore */ - "%d|%d|%s|%s|%s|%s|%s|%x|%x|%x|%x|%x|%s|%s|%d|%d|%x", - getType(), - getInventoryType(), - getName().c_str(), - creator_id_str.c_str(), - owner_id_str.c_str(), - last_owner_id_str.c_str(), - group_id_str.c_str(), - perm.getMaskBase(), - perm.getMaskOwner(), - perm.getMaskGroup(), - perm.getMaskEveryone(), - perm.getMaskNextOwner(), - asset_id_str.c_str(), - getDescription().c_str(), - getSaleInfo().getSaleType(), - getSaleInfo().getSalePrice(), - getFlags()) + 1; - - return size; -} - -void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) -{ - // Early exit on an empty binary bucket. - if (bin_bucket_size <= 1) return; - - if (NULL == bin_bucket) - { - LL_ERRS() << "unpackBinaryBucket failed. bin_bucket is NULL." << LL_ENDL; - return; - } - - // Convert the bin_bucket into a string. - std::vector item_buffer(bin_bucket_size+1); - memcpy(&item_buffer[0], bin_bucket, bin_bucket_size); /* Flawfinder: ignore */ - item_buffer[bin_bucket_size] = '\0'; - std::string str(&item_buffer[0]); - - LL_DEBUGS() << "item buffer: " << str << LL_ENDL; - - // Tokenize the string. - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str, sep); - tokenizer::iterator iter = tokens.begin(); - - // Extract all values. - LLUUID item_id; - item_id.generate(); - setUUID(item_id); - - LLAssetType::EType type; - type = (LLAssetType::EType)(atoi((*(iter++)).c_str())); - setType( type ); - - LLInventoryType::EType inv_type; - inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str())); - setInventoryType( inv_type ); - - std::string name((*(iter++)).c_str()); - rename( name ); - - LLUUID creator_id((*(iter++)).c_str()); - LLUUID owner_id((*(iter++)).c_str()); - LLUUID last_owner_id((*(iter++)).c_str()); - LLUUID group_id((*(iter++)).c_str()); - PermissionMask mask_base = strtoul((*(iter++)).c_str(), NULL, 16); - PermissionMask mask_owner = strtoul((*(iter++)).c_str(), NULL, 16); - PermissionMask mask_group = strtoul((*(iter++)).c_str(), NULL, 16); - PermissionMask mask_every = strtoul((*(iter++)).c_str(), NULL, 16); - PermissionMask mask_next = strtoul((*(iter++)).c_str(), NULL, 16); - LLPermissions perm; - perm.init(creator_id, owner_id, last_owner_id, group_id); - perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next); - setPermissions(perm); - //LL_DEBUGS() << "perm: " << perm << LL_ENDL; - - LLUUID asset_id((*(iter++)).c_str()); - setAssetUUID(asset_id); - - std::string desc((*(iter++)).c_str()); - setDescription(desc); - - LLSaleInfo::EForSale sale_type; - sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str())); - S32 price = atoi((*(iter++)).c_str()); - LLSaleInfo sale_info(sale_type, price); - setSaleInfo(sale_info); - - U32 flags = strtoul((*(iter++)).c_str(), NULL, 16); - setFlags(flags); - - time_t now = time(NULL); - setCreationDate(now); -} - ///---------------------------------------------------------------------------- /// Class LLInventoryCategory ///---------------------------------------------------------------------------- @@ -1152,6 +1036,7 @@ LLSD LLInventoryCategory::asLLSD() const LLSD sd = LLSD(); sd["item_id"] = mUUID; sd["parent_id"] = mParentUUID; + sd["thumbnail_id"] = mThumbnailUUID; S8 type = static_cast(mPreferredType); sd["type"] = type; sd["name"] = mName; @@ -1184,6 +1069,11 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) { mParentUUID = sd[w]; } + w = INV_THUMBNAIL_ID_LABEL; + if (sd.has(w)) + { + mThumbnailUUID = sd[w]; + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 7d9f9704f1..dfe8b7659b 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -70,6 +70,7 @@ public: virtual const LLUUID& getUUID() const; // inventoryID that this item points to virtual const LLUUID& getLinkedUUID() const; // inventoryID that this item points to, else this item's inventoryID const LLUUID& getParentUUID() const; + virtual const LLUUID& getThumbnailUUID() const; virtual const std::string& getName() const; virtual LLAssetType::EType getType() const; LLAssetType::EType getActualType() const; // bypasses indirection for linked items @@ -84,6 +85,7 @@ public: void setUUID(const LLUUID& new_uuid); virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); + virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid); void setType(LLAssetType::EType type); virtual void setCreationDate(time_t creation_date_utc); // only stored for items @@ -108,6 +110,7 @@ public: protected: LLUUID mUUID; LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL. + LLUUID mThumbnailUUID; LLAssetType::EType mType; std::string mName; time_t mCreationDate; // seconds from 1/1/1970, UTC @@ -203,9 +206,6 @@ public: // Helper Functions //-------------------------------------------------------------------- public: - // Pack all information needed to reconstruct this item into the given binary bucket. - S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const; - void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size); LLSD asLLSD() const; void asLLSD( LLSD& sd ) const; bool fromLLSD(const LLSD& sd, bool is_new = true); diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index e8b063bffe..039fa938dd 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -400,27 +400,7 @@ namespace tut // Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML() // because I can't find any non-test code references to it. 2009-05-04 JC } - - template<> template<> - void inventory_object::test<10>() - { - LLPointer src1 = create_random_inventory_item(); - U8* bin_bucket = new U8[300]; - S32 bin_bucket_size = src1->packBinaryBucket(bin_bucket, NULL); - - LLPointer src2 = new LLInventoryItem(); - src2->unpackBinaryBucket(bin_bucket, bin_bucket_size); - ensure_equals("1.sale price::getSalePrice() failed price", src1->getSaleInfo().getSalePrice(), src2->getSaleInfo().getSalePrice()); - ensure_equals("2.sale type::getSaleType() failed type", src1->getSaleInfo().getSaleType(), src2->getSaleInfo().getSaleType()); - ensure_equals("3.type::getType() failed", src1->getType(), src2->getType()); - ensure_equals("4.inventory type::getInventoryType() failed type", src1->getInventoryType(), src2->getInventoryType()); - ensure_equals("5.name::getName() failed", src1->getName(), src2->getName()); - ensure_equals("6.description::getDescription() failed", src1->getDescription(), src2->getDescription()); - ensure_equals("7.flags::getFlags() failed", src1->getFlags(), src2->getFlags()); - - } - template<> template<> void inventory_object::test<11>() { -- cgit v1.2.3 From ce5ac93883b71b6abf8cffa35204541e257c6b02 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 24 Jan 2023 20:15:22 +0000 Subject: SL-18629 - various notes on work for D567 --- indra/newview/llappearancemgr.cpp | 7 ++++++- indra/newview/llfloateropenobject.cpp | 2 ++ indra/newview/llinventoryfunctions.cpp | 1 + indra/newview/llinventorymodel.cpp | 37 +++++++++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 4fc09c7739..d05c30d722 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -1702,6 +1702,7 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds parent_id = gInventory.getRootFolderID(); } // USES UDP PATH + // D567 needs to carry over thumbnail info LLUUID subfolder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_NONE, src_cat->getName()); @@ -2728,6 +2729,7 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap } // UDP PATH + // D567 needs to carry over thumbnail info if present LLUUID new_cat_id = gInventory.createNewCategory( pid, LLFolderType::FT_NONE, @@ -3983,6 +3985,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo // First, make a folder in the My Outfits directory. const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + // D567 replace with coros if (AISAPI::isAvailable()) { // cap-based category creation was buggy until recently. use @@ -3990,6 +3993,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo // not actually use AIS to create the category. inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); + // D567 copy thumbnail info from source folder LLUUID folder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_OUTFIT, @@ -3998,7 +4002,8 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo } else { - // UDP PATH + // UDP PATH, should remove + // D567 copy thumbnail info from source folder LLUUID folder_id = gInventory.createNewCategory( parent_id, LLFolderType::FT_OUTFIT, diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 2a1749bd42..cff42f72b7 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -166,6 +166,7 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace) } inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace); + // D567 copy thumbnail info LLUUID category_id = gInventory.createNewCategory(parent_category_id, LLFolderType::FT_NONE, name, @@ -173,6 +174,7 @@ void LLFloaterOpenObject::moveToInventory(bool wear, bool replace) //If we get a null category ID, we are using a capability in createNewCategory and we will //handle the following in the callbackCreateInventoryCategory routine. + // D567 review if ( category_id.notNull() ) { LLCatAndWear* data = new LLCatAndWear; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 27edc8148e..145cdf6476 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -403,6 +403,7 @@ void copy_inventory_category(LLInventoryModel* model, bool move_no_copy_items ) { // Create the initial folder + // D567 needs to handle new fields inventory_func_type func = boost::bind(©_inventory_category_content, _1, model, cat, root_copy_id, move_no_copy_items); gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func); } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a7b3076e52..b64dd431db 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -700,8 +700,13 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } +#ifdef USE_AIS_FOR_NC + // D567 currently this doesn't really work due to limitations in + // AIS3, also violates the common caller assumption that we can + // assign the id and return immediately. if (callback) { + // D567 note that we no longer assign the UUID in the viewer, so various workflows need to change. LLSD new_inventory = LLSD::emptyMap(); new_inventory["categories"] = LLSD::emptyArray(); LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID()); @@ -711,17 +716,47 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return LLUUID::null; } +#else + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty() && callback) + { + //Let's use the new capability. + + id.generate(); + 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; + + LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL; + LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", + boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); + + return LLUUID::null; + } +#endif + if (!gMessageSystem) { return LLUUID::null; } - // FIXME this UDP code path needs to be removed. Requires + // D567 FIXME this UDP code path needs to be removed. Requires // reworking many of the callers to use callbacks rather than // assuming instant success. // Add the category to the internal representation + LL_WARNS() << "D567 need to remove this usage" << LL_ENDL; + id.generate(); LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); -- cgit v1.2.3 From 1140ae3489a9e260a0abb808b4152f2d57384d67 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 29 Dec 2022 19:51:33 +0100 Subject: Add a texture inspector and show it when hovering over an inventory textory (or folder containing - among others - exactly one texture) and when hovering over notecard embedded textures --- indra/llui/llfolderview.cpp | 16 ++ indra/llui/llfolderview.h | 5 + indra/llui/llfolderviewitem.cpp | 12 +- indra/llui/lltooltip.cpp | 36 ++- indra/llui/lltooltip.h | 12 +- indra/newview/CMakeLists.txt | 2 + indra/newview/llinspecttexture.cpp | 301 +++++++++++++++++++++ indra/newview/llinspecttexture.h | 52 ++++ indra/newview/llinventorymodel.cpp | 25 ++ indra/newview/llinventorymodel.h | 1 + indra/newview/llinventorypanel.cpp | 23 ++ indra/newview/llinventorypanel.h | 1 + indra/newview/llviewerfloaterreg.cpp | 2 + indra/newview/llviewertexteditor.cpp | 11 + .../skins/default/xui/en/inspect_texture.xml | 63 +++++ 15 files changed, 548 insertions(+), 14 deletions(-) create mode 100644 indra/newview/llinspecttexture.cpp create mode 100644 indra/newview/llinspecttexture.h create mode 100644 indra/newview/skins/default/xui/en/inspect_texture.xml (limited to 'indra') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index ea2ca68e47..a6d4a2ae52 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1506,6 +1506,22 @@ BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask ) return LLView::handleHover( x, y, mask ); } +LLFolderViewItem* LLFolderView::getHoveredItem() const +{ + return dynamic_cast(mHoveredItem.get()); +} + +void LLFolderView::setHoveredItem(LLFolderViewItem* itemp) +{ + if (mHoveredItem.get() != itemp) + { + if (itemp) + mHoveredItem = itemp->getHandle(); + else + mHoveredItem.markDead(); + } +} + BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 6bb5e6c02e..bd38d93b33 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -144,6 +144,10 @@ public: // applies filters to control visibility of items virtual void filter( LLFolderViewFilter& filter); + void clearHoveredItem() { setHoveredItem(nullptr); } + LLFolderViewItem* getHoveredItem() const; + void setHoveredItem(LLFolderViewItem* itemp); + // Get the last selected item virtual LLFolderViewItem* getCurSelectedItem( void ); selected_items_t& getSelectedItems( void ); @@ -273,6 +277,7 @@ protected: protected: LLHandle mPopupMenuHandle; + LLHandle mHoveredItem; selected_items_t mSelectedItems; bool mKeyboardSelection, mAllowMultiSelect, diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index eba93beed9..d10130619a 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -624,11 +624,14 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) getWindow()->setCursor(UI_CURSOR_NOLOCKED); } + root->clearHoveredItem(); return TRUE; } else { - getRoot()->setShowSelectionContext(FALSE); + LLFolderView* pRoot = getRoot(); + pRoot->setHoveredItem(this); + pRoot->setShowSelectionContext(FALSE); getWindow()->setCursor(UI_CURSOR_ARROW); // let parent handle this then... return FALSE; @@ -683,6 +686,13 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) void LLFolderViewItem::onMouseLeave(S32 x, S32 y, MASK mask) { mIsMouseOverTitle = false; + + // NOTE: LLViewerWindow::updateUI() calls "enter" before "leave"; if the mouse moved to another item, we can't just outright clear it + LLFolderView* pRoot = getRoot(); + if (this == pRoot->getHoveredItem()) + { + pRoot->clearHoveredItem(); + } } BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 2f56a8b1d0..a6552d4ff1 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -163,6 +163,7 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p) : LLPanel(p), mHasClickCallback(p.click_callback.isProvided()), mPadding(p.padding), + mMaxWidth(p.max_width), mTextBox(NULL), mInfoButton(NULL), mPlayMediaButton(NULL), @@ -272,7 +273,7 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p) // do this *after* we've had our size set in LLPanel::initFromParams(); const S32 REALLY_LARGE_HEIGHT = 10000; - mTextBox->reshape(p.max_width, REALLY_LARGE_HEIGHT); + mTextBox->reshape(mMaxWidth, REALLY_LARGE_HEIGHT); if (p.styled_message.isProvided()) { @@ -288,16 +289,19 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p) mTextBox->setText(p.message()); } - S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth() + 1); + updateTextBox(); + snapToChildren(); +} + +void LLToolTip::updateTextBox() +{ + S32 text_width = llmin(mMaxWidth, mTextBox->getTextPixelWidth() + 1); S32 text_height = mTextBox->getTextPixelHeight(); mTextBox->reshape(text_width, text_height); - if (mInfoButton) - { - LLRect text_rect = mTextBox->getRect(); - LLRect icon_rect = mInfoButton->getRect(); - mTextBox->translate(0, icon_rect.getCenterY() - text_rect.getCenterY()); - } - +} + +void LLToolTip::snapToChildren() +{ // reshape tooltip panel to fit text box LLRect tooltip_rect = calcBoundingRect(); tooltip_rect.mTop += mPadding; @@ -305,7 +309,14 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p) tooltip_rect.mBottom = 0; tooltip_rect.mLeft = 0; - mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); + if (mInfoButton) + { + mTextBox->reshape(mTextBox->getRect().getWidth(), llmax(mTextBox->getRect().getHeight(), tooltip_rect.getHeight() - 2 * mPadding)); + + LLRect text_rect = mTextBox->getRect(); + LLRect icon_rect = mInfoButton->getRect(); + mInfoButton->translate(0, text_rect.getCenterY() - icon_rect.getCenterY()); + } setShape(tooltip_rect); } @@ -428,7 +439,10 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) } tooltip_params.rect = LLRect (0, 1, 1, 0); - mToolTip = LLUICtrlFactory::create (tooltip_params); + if (tooltip_params.create_callback.isProvided()) + mToolTip = tooltip_params.create_callback()(tooltip_params); + else + mToolTip = LLUICtrlFactory::create (tooltip_params); gToolTipView->addChild(mToolTip); diff --git a/indra/llui/lltooltip.h b/indra/llui/lltooltip.h index 0b1fbe5367..86943625ff 100644 --- a/indra/llui/lltooltip.h +++ b/indra/llui/lltooltip.h @@ -68,6 +68,7 @@ public: struct Params : public LLInitParam::Block { typedef boost::function click_callback_t; + typedef boost::function create_callback_t; Optional message; Multiple styled_message; @@ -84,6 +85,8 @@ public: Optional time_based_media, web_based_media, media_playing; + Optional create_callback; + Optional create_params; Optional click_callback, click_playmedia_callback, click_homepage_callback; @@ -103,11 +106,15 @@ public: bool hasClickCallback(); LLToolTip(const Params& p); - void initFromParams(const LLToolTip::Params& params); + virtual void initFromParams(const LLToolTip::Params& params); void getToolTipMessage(std::string & message); -private: +protected: + void updateTextBox(); + void snapToChildren(); + +protected: class LLTextBox* mTextBox; class LLButton* mInfoButton; class LLButton* mPlayMediaButton; @@ -117,6 +124,7 @@ private: LLFrameTimer mVisibleTimer; bool mHasClickCallback; S32 mPadding; // pixels + S32 mMaxWidth; }; // used for the inspector tooltips which need different background images etc. diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 9eee5338ec..b94a1415a2 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -374,6 +374,7 @@ set(viewer_SOURCE_FILES llinspectgroup.cpp llinspectobject.cpp llinspectremoteobject.cpp + llinspecttexture.cpp llinspecttoast.cpp llinventorybridge.cpp llinventoryfilter.cpp @@ -1014,6 +1015,7 @@ set(viewer_HEADER_FILES llinspectgroup.h llinspectobject.h llinspectremoteobject.h + llinspecttexture.h llinspecttoast.h llinventorybridge.h llinventoryfilter.h diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp new file mode 100644 index 0000000000..cd288e9603 --- /dev/null +++ b/indra/newview/llinspecttexture.cpp @@ -0,0 +1,301 @@ +/** + * @file llinspecttexture.cpp + * + * $LicenseInfo:firstyear=2009&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 "llfloaterreg.h" +#include "llinspect.h" +#include "llinspecttexture.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewertexturelist.h" + +// ============================================================================ +// LLInspectTexture class +// + +class LLInspectTexture : public LLInspect +{ + friend class LLFloaterReg; +public: + LLInspectTexture(const LLSD& sdKey); + ~LLInspectTexture(); + +public: + void onOpen(const LLSD& sdData) override; + BOOL postBuild() override; + +public: + const LLUUID& getAssetId() const { return mAssetId; } + const LLUUID& getItemId() const { return mItemId; } + +protected: + LLUUID mAssetId; + LLUUID mItemId; // Item UUID relative to gInventoryModel (or null if not displaying an inventory texture) + LLUUID mNotecardId; + LLTextureCtrl* mTextureCtrl = nullptr; + LLTextBox* mTextureName = nullptr; +}; + +LLInspectTexture::LLInspectTexture(const LLSD& sdKey) + : LLInspect(LLSD()) +{ +} + +LLInspectTexture::~LLInspectTexture() +{ +} + +void LLInspectTexture::onOpen(const LLSD& sdData) +{ + // Start fade animation + LLInspect::onOpen(sdData); + + bool fIsAsset = sdData.has("asset_id"); + bool fIsInventory = sdData.has("item_id"); + + // Skip if we're being asked to display the same thing + const LLUUID idAsset = (fIsAsset) ? sdData["asset_id"].asUUID() : LLUUID::null; + const LLUUID idItem = (fIsInventory) ? sdData["item_id"].asUUID() : LLUUID::null; + if ( (getVisible()) && ( ((fIsAsset) && (idAsset == mAssetId)) || ((fIsInventory) && (idItem == mItemId)) ) ) + { + return; + } + + // Position the inspector relative to the mouse cursor + // Similar to how tooltips are positioned [see LLToolTipMgr::createToolTip()] + if (sdData.has("pos")) + LLUI::instance().positionViewNearMouse(this, sdData["pos"]["x"].asInteger(), sdData["pos"]["y"].asInteger()); + else + LLUI::instance().positionViewNearMouse(this); + + std::string strName = sdData["name"].asString(); + if (fIsAsset) + { + mAssetId = idAsset; + mItemId = idItem; // Will be non-null in the case of a notecard + mNotecardId = sdData["notecard_id"].asUUID(); + } + else if (fIsInventory) + { + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + if ( (pItem) && (LLAssetType::AT_TEXTURE == pItem->getType()) ) + { + if (strName.empty()) + strName = pItem->getName(); + mAssetId = pItem->getAssetUUID(); + mItemId = idItem; + } + else + { + mAssetId.setNull(); + mItemId.setNull(); + } + mNotecardId = LLUUID::null; + } + + mTextureCtrl->setImageAssetID(mAssetId); + mTextureName->setText(strName); +} + +BOOL LLInspectTexture::postBuild() +{ + mTextureCtrl = getChild("texture_ctrl"); + mTextureName = getChild("texture_name"); + + return TRUE; +} + +// ============================================================================ +// Helper functions +// + +LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p) +{ + const LLSD& sdTooltip = p.create_params; + + LLInventoryType::EType eInvType = (sdTooltip.has("inv_type")) ? (LLInventoryType::EType)sdTooltip["inv_type"].asInteger() : LLInventoryType::IT_NONE; + switch (eInvType) + { + case LLInventoryType::IT_SNAPSHOT: + case LLInventoryType::IT_TEXTURE: + return LLUICtrlFactory::create(p); + case LLInventoryType::IT_CATEGORY: + { + if (sdTooltip.has("item_id")) + { + const LLUUID idCategory = sdTooltip["item_id"].asUUID(); + + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsOfAssetType f(LLAssetType::AT_TEXTURE); + gInventory.getDirectDescendentsOf(idCategory, cats, items, f); + + // Exactly one texture found => show the texture tooltip + if (1 == items.size()) + { + p.create_params.getValue()["asset_id"] = items.front()->getAssetUUID(); + return LLUICtrlFactory::create(p); + } + } + + // No or more than one texture found => show default tooltip + return LLUICtrlFactory::create(p); + } + default: + return LLUICtrlFactory::create(p); + } +} + +void LLInspectTextureUtil::registerFloater() +{ + LLFloaterReg::add("inspect_texture", "inspect_texture.xml", &LLFloaterReg::build); +} + +// ============================================================================ +// LLTexturePreviewView helper class +// + +class LLTexturePreviewView : public LLView +{ +public: + LLTexturePreviewView(const LLView::Params& p); + ~LLTexturePreviewView(); + +public: + void draw() override; + +public: + void setImageFromAssetId(const LLUUID& idAsset); + void setImageFromItemId(const LLUUID& idItem); + +protected: + LLPointer m_Image; + S32 mImageBoostLevel = LLGLTexture::BOOST_NONE; + std::string mLoadingText; +}; + + +LLTexturePreviewView::LLTexturePreviewView(const LLView::Params& p) + : LLView(p) +{ + mLoadingText = LLTrans::getString("texture_loading"); +} + +LLTexturePreviewView::~LLTexturePreviewView() +{ + if (m_Image) + { + m_Image->setBoostLevel(mImageBoostLevel); + m_Image = nullptr; + } +} + +void LLTexturePreviewView::draw() +{ + if (m_Image) + { + LLRect rctClient = getLocalRect(); + + gl_rect_2d(rctClient, LLColor4::black); + rctClient.stretch(-2); + if (4 == m_Image->getComponents()) + gl_rect_2d_checkerboard(rctClient); + gl_draw_scaled_image(rctClient.mLeft, rctClient.mBottom, rctClient.getWidth(), rctClient.getHeight(), m_Image); + + bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0); + if (isLoading) + LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, llfloor(rctClient.mLeft + 3), llfloor(rctClient.mTop - 25), LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); + m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight())); + } +} + +void LLTexturePreviewView::setImageFromAssetId(const LLUUID& idAsset) +{ + m_Image = LLViewerTextureManager::getFetchedTexture(idAsset, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + if (m_Image) + { + mImageBoostLevel = m_Image->getBoostLevel(); + m_Image->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + m_Image->forceToSaveRawImage(0); + if ( (!m_Image->isFullyLoaded()) && (!m_Image->hasFetcher()) ) + { + if (m_Image->isInFastCacheList()) + { + m_Image->loadFromFastCache(); + } + gTextureList.forceImmediateUpdate(m_Image); + } + } +} + +void LLTexturePreviewView::setImageFromItemId(const LLUUID& idItem) +{ + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + setImageFromAssetId( (pItem) ? pItem->getAssetUUID() : LLUUID::null ); +} + +// ============================================================================ +// LLTextureToolTip class +// + +LLTextureToolTip::LLTextureToolTip(const LLToolTip::Params& p) + : LLToolTip(p) + , mPreviewView(nullptr) + , mPreviewSize(256) +{ + mMaxWidth = llmax(mMaxWidth, mPreviewSize); +} + +LLTextureToolTip::~LLTextureToolTip() +{ +} + +void LLTextureToolTip::initFromParams(const LLToolTip::Params& p) +{ + LLToolTip::initFromParams(p); + + // Create and add the preview control + LLView::Params p_preview; + p_preview.name = "texture_preview"; + LLRect rctPreview; + rctPreview.setOriginAndSize(mPadding, mTextBox->getRect().mTop, mPreviewSize, mPreviewSize); + p_preview.rect = rctPreview; + mPreviewView = LLUICtrlFactory::create(p_preview); + addChild(mPreviewView); + + // Parse the control params + const LLSD& sdTextureParams = p.create_params; + if (sdTextureParams.has("asset_id")) + mPreviewView->setImageFromAssetId(sdTextureParams["asset_id"].asUUID()); + else if (sdTextureParams.has("item_id")) + mPreviewView->setImageFromItemId(sdTextureParams["item_id"].asUUID()); + + snapToChildren(); +} + +// ============================================================================ diff --git a/indra/newview/llinspecttexture.h b/indra/newview/llinspecttexture.h new file mode 100644 index 0000000000..192aafc3b4 --- /dev/null +++ b/indra/newview/llinspecttexture.h @@ -0,0 +1,52 @@ +/** + * @file llinspecttexture.h + * + * $LicenseInfo:firstyear=2009&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$ + */ + +#pragma once + +#include "lltooltip.h" + +class LLTexturePreviewView; + +namespace LLInspectTextureUtil +{ + LLToolTip* createInventoryToolTip(LLToolTip::Params p); + + // Register with LLFloaterReg + void registerFloater(); +} + +class LLTextureToolTip : public LLToolTip +{ +public: + LLTextureToolTip(const LLToolTip::Params& p); + ~LLTextureToolTip(); + +public: + void initFromParams(const LLToolTip::Params& p) override; + +protected: + LLTexturePreviewView* mPreviewView; + S32 mPreviewSize; +}; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 8b2a1a14f0..edd489f021 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -451,6 +451,31 @@ void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, items = get_ptr_in_map(mParentChildItemTree, cat_id); } +void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const +{ + if (cat_array_t* categoriesp = get_ptr_in_map(mParentChildCategoryTree, cat_id)) + { + for (LLViewerInventoryCategory* pFolder : *categoriesp) + { + if (f(pFolder, nullptr)) + { + categories.push_back(pFolder); + } + } + } + + if (item_array_t* itemsp = get_ptr_in_map(mParentChildItemTree, cat_id)) + { + for (LLViewerInventoryItem* pItem : *itemsp) + { + if (f(nullptr, pItem)) + { + items.push_back(pItem); + } + } + } +} + LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const { LLInventoryModel::cat_array_t* cat_array; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c4133ff9bb..b03181d646 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -256,6 +256,7 @@ public: void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t*& categories, item_array_t*& items) const; + void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t& categories, item_array_t& items, LLInventoryCollectFunctor& f) const; // Compute a hash of direct descendant names (for detecting child name changes) LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6b102c7500..dabe633b8c 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -40,6 +40,7 @@ #include "llfolderviewitem.h" #include "llfloaterimcontainer.h" #include "llimview.h" +#include "llinspecttexture.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" @@ -1278,6 +1279,28 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask) +{ + if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr) + { + if (const LLFolderViewModelItemInventory* vm_item_p = static_cast(hover_item_p->getViewModelItem())) + { + // Copy/pasted from LLView::handleToolTip() + F32 nTimeout = LLToolTipMgr::instance().toolTipVisible() + ? LLUI::getInstance()->mSettingGroups["config"]->getF32("ToolTipFastDelay") + : LLUI::getInstance()->mSettingGroups["config"]->getF32("ToolTipDelay"); + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(hover_item_p->getToolTip()) + .sticky_rect(hover_item_p->calcScreenRect()) + .delay_time(nTimeout) + .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) + .create_params(LLSD().with("inv_type", vm_item_p->getInventoryType()).with("item_id", vm_item_p->getUUID()))); + return TRUE; + } + } + return LLPanel::handleToolTip(x, y, mask); +} + BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 552c61b915..d5dc8cdba6 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -168,6 +168,7 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + BOOL handleToolTip(S32 x, S32 y, MASK mask) override; // LLUICtrl methods /*virtual*/ void onFocusLost(); /*virtual*/ void onFocusReceived(); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 59654350e4..77a7fd21a8 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -153,6 +153,7 @@ #include "llinspectgroup.h" #include "llinspectobject.h" #include "llinspectremoteobject.h" +#include "llinspecttexture.h" #include "llinspecttoast.h" #include "llmoveview.h" #include "llfloaterimnearbychat.h" @@ -281,6 +282,7 @@ void LLViewerFloaterReg::registerFloaters() LLInspectAvatarUtil::registerFloater(); LLInspectGroupUtil::registerFloater(); LLInspectObjectUtil::registerFloater(); + LLInspectTextureUtil::registerFloater(); LLInspectRemoteObjectUtil::registerFloater(); LLFloaterVoiceVolumeUtil::registerFloater(); LLNotificationsUI::registerFloater(); diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index e2de7ac825..299047d91b 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -36,6 +36,7 @@ #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" #include "llfocusmgr.h" +#include "llinspecttexture.h" #include "llinventorybridge.h" #include "llinventorydefines.h" #include "llinventorymodel.h" @@ -245,6 +246,16 @@ public: } virtual BOOL handleToolTip(S32 x, S32 y, MASK mask ) { + if (LLAssetType::AT_TEXTURE == mItem->getType()) + { + LLToolTipMgr::instance().show(LLToolTip::Params() + .message(mToolTip) + .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) + .create_params(LLSD().with("inv_type", mItem->getInventoryType()).with("asset_id", mItem->getAssetUUID()))); + + return TRUE; + } + if (!mToolTip.empty()) { LLToolTipMgr::instance().show(mToolTip); diff --git a/indra/newview/skins/default/xui/en/inspect_texture.xml b/indra/newview/skins/default/xui/en/inspect_texture.xml new file mode 100644 index 0000000000..30be90cfa0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/inspect_texture.xml @@ -0,0 +1,63 @@ + + + + + +