#4000 Cherry pick inventory LEAP functions from develop branch

master
Maxim Nikolenko 2025-05-20 20:40:04 +03:00 committed by GitHub
parent 3de223aecf
commit 2cbff073ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 451 additions and 1 deletions

View File

@ -29,6 +29,7 @@
#include "llassettype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsd.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
@ -246,3 +247,19 @@ bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
}
return false;
}
LLSD LLAssetType::getTypeNames()
{
LLSD type_names;
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
for (S32 type = AT_TEXTURE; type < AT_COUNT; ++type)
{
const AssetEntry *entry = dict->lookup((LLAssetType::EType) type);
// skip llassettype_bad_lookup
if (entry)
{
type_names.append(entry->mTypeName);
}
}
return type_names;
}

View File

@ -165,6 +165,8 @@ public:
static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download
static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer
static LLSD getTypeNames();
static const std::string BADLOOKUP;
protected:

View File

@ -553,6 +553,44 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter
} // namespace llsd
/*****************************************************************************
* LLSDParam<std::vector<T>>
*****************************************************************************/
// Given an LLSD array, return a const std::vector<T>&, where T is a type
// supported by LLSDParam. Bonus: if the LLSD value is actually a scalar,
// return a single-element vector containing the converted value.
template <typename T>
class LLSDParam<std::vector<T>>: public LLSDParamBase
{
public:
LLSDParam(const LLSD& array)
{
// treat undefined "array" as empty vector
if (array.isDefined())
{
// what if it's a scalar?
if (! array.isArray())
{
v.push_back(LLSDParam<T>(array));
}
else // really is an array
{
// reserve space for the array entries
v.reserve(array.size());
for (const auto& item : llsd::inArray(array))
{
v.push_back(LLSDParam<T>(item));
}
}
}
}
operator const std::vector<T>&() const { return v; }
private:
std::vector<T> v;
};
// Specialization for generating a hash value from an LLSD block.
namespace boost
{

View File

@ -29,6 +29,7 @@
#include "llfoldertype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsd.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
@ -220,3 +221,21 @@ const std::string &LLFolderType::badLookup()
static const std::string sBadLookup = "llfoldertype_bad_lookup";
return sBadLookup;
}
LLSD LLFolderType::getTypeNames()
{
LLSD type_names;
for (S32 type = FT_TEXTURE; type < FT_COUNT; ++type)
{
if (lookupIsEnsembleType((LLFolderType::EType)type))
continue;
const FolderEntry* entry = LLFolderDictionary::getInstance()->lookup((LLFolderType::EType)type);
// skip llfoldertype_bad_lookup
if (entry)
{
type_names.append(entry->mName);
}
}
return type_names;
}

View File

@ -115,6 +115,8 @@ public:
static const std::string& badLookup(); // error string when a lookup fails
static LLSD getTypeNames();
protected:
LLFolderType() {}
~LLFolderType() {}

View File

@ -362,6 +362,7 @@ set(viewer_SOURCE_FILES
llinventorygallerymenu.cpp
llinventoryicon.cpp
llinventoryitemslist.cpp
llinventorylistener.cpp
llinventorylistitem.cpp
llinventorymodel.cpp
llinventorymodelbackgroundfetch.cpp
@ -1033,6 +1034,7 @@ set(viewer_HEADER_FILES
llinventorygallerymenu.h
llinventoryicon.h
llinventoryitemslist.h
llinventorylistener.h
llinventorylistitem.h
llinventorymodel.h
llinventorymodelbackgroundfetch.h

View File

@ -192,7 +192,9 @@ class LLInventoryCollectFunctor
{
public:
virtual ~LLInventoryCollectFunctor(){};
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) = 0;
virtual bool exceedsLimit() { return false; }
static bool itemTransferCommonlyAllowed(const LLInventoryItem* item);
};

View File

@ -0,0 +1,309 @@
/**
* @file llinventorylistener.cpp
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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 "llinventorylistener.h"
#include "llappearancemgr.h"
#include "llinventoryfunctions.h"
#include "lltransutil.h"
#include "llwearableitemslist.h"
#include "stringize.h"
LLInventoryListener::LLInventoryListener()
: LLEventAPI("LLInventory",
"API for interactions with viewer Inventory items")
{
add("getItemsInfo",
"Return information about items or folders defined in [\"item_ids\"]:\n"
"reply will contain [\"items\"] and [\"categories\"] result set keys",
&LLInventoryListener::getItemsInfo,
llsd::map("item_ids", LLSD(), "reply", LLSD()));
add("getFolderTypeNames",
"Return the table of folder type names, contained in [\"names\"]\n",
&LLInventoryListener::getFolderTypeNames,
llsd::map("reply", LLSD()));
add("getAssetTypeNames",
"Return the table of asset type names, contained in [\"names\"]\n",
&LLInventoryListener::getAssetTypeNames,
llsd::map("reply", LLSD()));
add("getBasicFolderID",
"Return the UUID of the folder by specified folder type name, for example:\n"
"\"Textures\", \"My outfits\", \"Sounds\" and other basic folders which have associated type",
&LLInventoryListener::getBasicFolderID,
llsd::map("ft_name", LLSD(), "reply", LLSD()));
add("getDirectDescendants",
"Return result set keys [\"categories\"] and [\"items\"] for the direct\n"
"descendants of the [\"folder_id\"]",
&LLInventoryListener::getDirectDescendants,
llsd::map("folder_id", LLSD(), "reply", LLSD()));
add("collectDescendantsIf",
"Return result set keys [\"categories\"] and [\"items\"] for the descendants\n"
"of the [\"folder_id\"], if it passes specified filters:\n"
"[\"name\"] is a substring of object's name,\n"
"[\"desc\"] is a substring of object's description,\n"
"asset [\"type\"] corresponds to the string name of the object's asset type\n"
"[\"limit\"] sets item count limit in result set (default unlimited)\n"
"[\"filter_links\"]: EXCLUDE_LINKS - don't show links, ONLY_LINKS - only show links, INCLUDE_LINKS - show links too (default)",
&LLInventoryListener::collectDescendantsIf,
llsd::map("folder_id", LLSD(), "reply", LLSD()));
}
void add_cat_info(LLEventAPI::Response& response, LLViewerInventoryCategory* cat)
{
response["categories"].insert(cat->getUUID().asString(),
llsd::map("id", cat->getUUID(),
"name", cat->getName(),
"parent_id", cat->getParentUUID(),
"type", LLFolderType::lookup(cat->getPreferredType())));
};
void add_item_info(LLEventAPI::Response& response, LLViewerInventoryItem* item)
{
response["items"].insert(item->getUUID().asString(),
llsd::map("id", item->getUUID(),
"name", item->getName(),
"parent_id", item->getParentUUID(),
"desc", item->getDescription(),
"inv_type", LLInventoryType::lookup(item->getInventoryType()),
"asset_type", LLAssetType::lookup(item->getType()),
"creation_date", LLSD::Integer(item->getCreationDate()),
"asset_id", item->getAssetUUID(),
"is_link", item->getIsLinkType(),
"linked_id", item->getLinkedUUID()));
}
void add_objects_info(LLEventAPI::Response& response, LLInventoryModel::cat_array_t cat_array, LLInventoryModel::item_array_t item_array)
{
for (auto& p : item_array)
{
add_item_info(response, p);
}
for (auto& p : cat_array)
{
add_cat_info(response, p);
}
}
void LLInventoryListener::getItemsInfo(LLSD const &data)
{
Response response(LLSD(), data);
uuid_vec_t ids = LLSDParam<uuid_vec_t>(data["item_ids"]);
for (auto &it : ids)
{
LLViewerInventoryItem* item = gInventory.getItem(it);
if (item)
{
add_item_info(response, item);
}
else
{
LLViewerInventoryCategory *cat = gInventory.getCategory(it);
if (cat)
{
add_cat_info(response, cat);
}
}
}
}
void LLInventoryListener::getFolderTypeNames(LLSD const &data)
{
Response response(llsd::map("names", LLFolderType::getTypeNames()), data);
}
void LLInventoryListener::getAssetTypeNames(LLSD const &data)
{
Response response(llsd::map("names", LLAssetType::getTypeNames()), data);
}
void LLInventoryListener::getBasicFolderID(LLSD const &data)
{
Response response(llsd::map("id", gInventory.findCategoryUUIDForType(LLFolderType::lookup(data["ft_name"].asString()))), data);
}
void LLInventoryListener::getDirectDescendants(LLSD const &data)
{
Response response(LLSD(), data);
LLUUID folder_id(data["folder_id"].asUUID());
LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
if (!cat)
{
return response.error(stringize("Folder ", std::quoted(data["folder_id"].asString()), " was not found"));
}
LLInventoryModel::cat_array_t* cats;
LLInventoryModel::item_array_t* items;
gInventory.getDirectDescendentsOf(folder_id, cats, items);
add_objects_info(response, *cats, *items);
}
struct LLFilteredCollector : public LLInventoryCollectFunctor
{
enum EFilterLink
{
INCLUDE_LINKS, // show links too
EXCLUDE_LINKS, // don't show links
ONLY_LINKS // only show links
};
LLFilteredCollector(LLSD const &data);
virtual ~LLFilteredCollector() {}
virtual bool operator()(LLInventoryCategory *cat, LLInventoryItem *item) override;
virtual bool exceedsLimit() override
{
// mItemLimit == 0 means unlimited
return (mItemLimit && mItemLimit <= mItemCount);
}
protected:
bool checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item);
bool checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item);
bool checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item);
LLAssetType::EType mType;
std::string mName;
std::string mDesc;
EFilterLink mLinkFilter;
S32 mItemLimit;
S32 mItemCount;
};
void LLInventoryListener::collectDescendantsIf(LLSD const &data)
{
Response response(LLSD(), data);
LLUUID folder_id(data["folder_id"].asUUID());
LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id);
if (!cat)
{
return response.error(stringize("Folder ", std::quoted(data["folder_id"].asString()), " was not found"));
}
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
LLFilteredCollector collector = LLFilteredCollector(data);
gInventory.collectDescendentsIf(folder_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector);
add_objects_info(response, cat_array, item_array);
}
LLFilteredCollector::LLFilteredCollector(LLSD const &data) :
mType(LLAssetType::EType::AT_UNKNOWN),
mLinkFilter(INCLUDE_LINKS),
mItemLimit(0),
mItemCount(0)
{
mName = data["name"].asString();
mDesc = data["desc"].asString();
if (data.has("type"))
{
mType = LLAssetType::lookup(data["type"]);
}
if (data.has("filter_links"))
{
if (data["filter_links"] == "EXCLUDE_LINKS")
{
mLinkFilter = EXCLUDE_LINKS;
}
else if (data["filter_links"] == "ONLY_LINKS")
{
mLinkFilter = ONLY_LINKS;
}
}
if (data["limit"].isInteger())
{
mItemLimit = std::max(data["limit"].asInteger(), 1);
}
}
bool LLFilteredCollector::operator()(LLInventoryCategory *cat, LLInventoryItem *item)
{
bool passed = checkagainstType(cat, item);
passed = passed && checkagainstNameDesc(cat, item);
passed = passed && checkagainstLinks(cat, item);
if (passed)
{
++mItemCount;
}
return passed;
}
bool LLFilteredCollector::checkagainstNameDesc(LLInventoryCategory *cat, LLInventoryItem *item)
{
std::string name, desc;
bool passed(true);
if (cat)
{
if (!mDesc.empty()) return false;
name = cat->getName();
}
if (item)
{
name = item->getName();
passed = (mDesc.empty() || (item->getDescription().find(mDesc) != std::string::npos));
}
return passed && (mName.empty() || name.find(mName) != std::string::npos);
}
bool LLFilteredCollector::checkagainstType(LLInventoryCategory *cat, LLInventoryItem *item)
{
if (mType == LLAssetType::AT_UNKNOWN)
{
return true;
}
if (cat && (mType == LLAssetType::AT_CATEGORY))
{
return true;
}
if (item && item->getType() == mType)
{
return true;
}
return false;
}
bool LLFilteredCollector::checkagainstLinks(LLInventoryCategory *cat, LLInventoryItem *item)
{
bool is_link = cat ? cat->getIsLinkType() : item->getIsLinkType();
if (is_link && (mLinkFilter == EXCLUDE_LINKS))
return false;
if (!is_link && (mLinkFilter == ONLY_LINKS))
return false;
return true;
}

View File

@ -0,0 +1,48 @@
/**
* @file llinventorylistener.h
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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_LLINVENTORYLISTENER_H
#define LL_LLINVENTORYLISTENER_H
#include "lleventapi.h"
#include "llinventoryfunctions.h"
class LLInventoryListener : public LLEventAPI
{
public:
LLInventoryListener();
private:
void getItemsInfo(LLSD const &data);
void getFolderTypeNames(LLSD const &data);
void getAssetTypeNames(LLSD const &data);
void getBasicFolderID(LLSD const &data);
void getDirectDescendants(LLSD const &data);
void collectDescendantsIf(LLSD const &data);
};
#endif // LL_LLINVENTORYLISTENER_H

View File

@ -1282,6 +1282,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
{
for (auto& cat : *cat_array)
{
if (add.exceedsLimit())
{
break;
}
if(add(cat,NULL))
{
cats.push_back(cat);
@ -1297,6 +1301,10 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
{
for (auto& item : *item_array)
{
if (add.exceedsLimit())
{
break;
}
if(add(NULL, item))
{
items.push_back(item);

View File

@ -71,6 +71,9 @@
#include "llclipboard.h"
#include "llhttpretrypolicy.h"
#include "llsettingsvo.h"
#include "llinventorylistener.h"
LLInventoryListener sInventoryListener;
// do-nothing ops for use in callbacks.
void no_op_inventory_func(const LLUUID&) {}