From a220acb45496dfbfb154fa9e16943102eda922fc Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 22 Apr 2024 23:45:44 +0300 Subject: viewer#1300 Inventory favorites basic framework --- indra/llinventory/llinventory.cpp | 77 +++++++++++++++++++++++++++++++++++++-- indra/llinventory/llinventory.h | 3 ++ 2 files changed, 77 insertions(+), 3 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 6334a35fd0..cef469e11e 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -46,6 +46,7 @@ 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_LABEL("thumbnail"); +static const std::string INV_FAVORITE_LABEL("favorite"); 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"); @@ -82,14 +83,16 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid, mParentUUID(parent_uuid), mType(type), mName(name), - mCreationDate(0) + mCreationDate(0), + mFavorite(false) { correctInventoryName(mName); } LLInventoryObject::LLInventoryObject() : mType(LLAssetType::AT_NONE), - mCreationDate(0) + mCreationDate(0), + mFavorite(false) { } @@ -104,6 +107,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other) mType = other->mType; mName = other->mName; mThumbnailUUID = other->mThumbnailUUID; + mFavorite = other->mFavorite; } const LLUUID& LLInventoryObject::getUUID() const @@ -121,6 +125,11 @@ const LLUUID& LLInventoryObject::getThumbnailUUID() const return mThumbnailUUID; } +bool LLInventoryObject::getIsFavorite() const +{ + return mFavorite; +} + const std::string& LLInventoryObject::getName() const { return mName; @@ -175,6 +184,11 @@ void LLInventoryObject::setThumbnailUUID(const LLUUID& thumbnail_uuid) mThumbnailUUID = thumbnail_uuid; } +void LLInventoryObject::setFavorite(bool favorite) +{ + mFavorite = favorite; +} + void LLInventoryObject::setType(LLAssetType::EType type) { mType = type; @@ -247,6 +261,14 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else if(0 == strcmp("name", keyword)) { @@ -735,6 +757,14 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else if(0 == strcmp("inv_type", keyword)) { @@ -895,6 +925,11 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } + U32 mask = mPermissions.getMaskBase(); if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) || (mAssetUUID.isNull())) @@ -974,7 +1009,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) 1 */ continue; - } + } if (i->first == INV_THUMBNAIL_ID_LABEL) { @@ -982,6 +1017,12 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) continue; } + if (i->first == INV_FAVORITE_LABEL) + { + mFavorite = i->second.asBoolean(); + continue; + } + if (i->first == INV_PERMISSIONS_LABEL) { mPermissions = ll_permissions_from_sd(i->second); @@ -1177,6 +1218,11 @@ LLSD LLInventoryCategory::asLLSD() const sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } + return sd; } @@ -1192,6 +1238,10 @@ LLSD LLInventoryCategory::asAISCreateCatLLSD() const { sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + sd[INV_FAVORITE_LABEL] = mFavorite; + } return sd; } @@ -1240,6 +1290,11 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) mThumbnailUUID = sd[w]; } } + w = INV_FAVORITE_LABEL; + if (sd.has(w)) + { + mFavorite = sd[w].asBoolean(); + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { @@ -1362,6 +1417,14 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) + { + setFavorite(metadata["favorite"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -1409,6 +1472,10 @@ LLSD LLInventoryCategory::exportLLSD() const { cat_data[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) + { + cat_data[INV_FAVORITE_LABEL] = mFavorite; + } return cat_data; } @@ -1440,6 +1507,10 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); } setThumbnailUUID(thumbnail_uuid); + } + if (cat_data.has(INV_FAVORITE_LABEL)) + { + setFavorite(cat_data[INV_FAVORITE_LABEL].asBoolean()); } if (cat_data.has(INV_NAME_LABEL)) { diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 6d4535af27..27a05c1345 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -71,6 +71,7 @@ public: 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 bool getIsFavorite() const; virtual const std::string& getName() const; virtual LLAssetType::EType getType() const; LLAssetType::EType getActualType() const; // bypasses indirection for linked items @@ -86,6 +87,7 @@ public: virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); virtual void setThumbnailUUID(const LLUUID& thumbnail_uuid); + virtual void setFavorite(bool favorite); void setType(LLAssetType::EType type); virtual void setCreationDate(time_t creation_date_utc); // only stored for items @@ -111,6 +113,7 @@ protected: LLUUID mUUID; LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL. LLUUID mThumbnailUUID; + bool mFavorite; LLAssetType::EType mType; std::string mName; time_t mCreationDate; // seconds from 1/1/1970, UTC -- cgit v1.3 From 384d694aba523218490ec48c22d97b63acbffd6f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 23 Apr 2024 23:28:58 +0300 Subject: viewer#1300 Inventory favorites context menu --- indra/llinventory/llinventory.cpp | 68 ++++++++++++++++++---- indra/newview/llinventorybridge.cpp | 14 ++++- indra/newview/llinventoryfunctions.cpp | 34 +++++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 23 ++++++++ .../default/xui/en/menu_gallery_inventory.xml | 16 +++++ .../skins/default/xui/en/menu_inventory.xml | 18 +++++- 7 files changed, 162 insertions(+), 12 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index cef469e11e..2f701f12a0 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -60,6 +60,7 @@ static const std::string INV_LINKED_ID_LABEL("linked_id"); static const std::string INV_SALE_INFO_LABEL("sale_info"); static const std::string INV_FLAGS_LABEL("flags"); static const std::string INV_CREATION_DATE_LABEL("created_at"); +static const std::string INV_TOGGLED_LABEL("toggled"); // key used by agent-inventory-service static const std::string INV_ASSET_TYPE_LABEL_WS("type_default"); @@ -261,9 +262,18 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -757,9 +767,18 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -927,7 +946,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } U32 mask = mPermissions.getMaskBase(); @@ -972,6 +991,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // TODO - figure out if this should be moved into the noclobber fields above mThumbnailUUID.setNull(); + mFavorite = false; // iterate as map to avoid making unnecessary temp copies of everything LLSD::map_const_iterator i, end; @@ -1019,7 +1039,12 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_FAVORITE_LABEL) { - mFavorite = i->second.asBoolean(); + const LLSD& favorite_map = i->second; + const std::string w = INV_TOGGLED_LABEL; + if (favorite_map.has(w)) + { + mFavorite = favorite_map[w].asBoolean(); + } continue; } @@ -1220,7 +1245,7 @@ LLSD LLInventoryCategory::asLLSD() const if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return sd; @@ -1234,13 +1259,15 @@ LLSD LLInventoryCategory::asAISCreateCatLLSD() const S8 type = static_cast(mPreferredType); sd[INV_ASSET_TYPE_LABEL_WS] = type; sd[INV_NAME_LABEL] = mName; + if (mThumbnailUUID.notNull()) { sd[INV_THUMBNAIL_LABEL] = LLSD().with(INV_ASSET_ID_LABEL, mThumbnailUUID); } + if (mFavorite) { - sd[INV_FAVORITE_LABEL] = mFavorite; + sd[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return sd; @@ -1290,10 +1317,16 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd) mThumbnailUUID = sd[w]; } } + mFavorite = false; w = INV_FAVORITE_LABEL; if (sd.has(w)) { - mFavorite = sd[w].asBoolean(); + const LLSD& favorite_map = sd[w]; + w = INV_TOGGLED_LABEL; + if (favorite_map.has(w)) + { + mFavorite = favorite_map[w].asBoolean(); + } } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) @@ -1417,9 +1450,18 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) { setThumbnailUUID(LLUUID::null); } + if (metadata.has("favorite")) { - setFavorite(metadata["favorite"].asBoolean()); + const LLSD& favorite = metadata["favorite"]; + if (favorite.has("toggled")) + { + setFavorite(favorite["toggled"].asBoolean()); + } + else + { + setFavorite(false); + } } else { @@ -1474,7 +1516,7 @@ LLSD LLInventoryCategory::exportLLSD() const } if (mFavorite) { - cat_data[INV_FAVORITE_LABEL] = mFavorite; + cat_data[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } return cat_data; @@ -1510,7 +1552,13 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) } if (cat_data.has(INV_FAVORITE_LABEL)) { - setFavorite(cat_data[INV_FAVORITE_LABEL].asBoolean()); + bool favorite = false; + const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; + if (favorite_data.has(INV_TOGGLED_LABEL)) + { + favorite = favorite_data[INV_ASSET_ID_LABEL].asBoolean(); + } + setFavorite(favorite); } if (cat_data.has(INV_NAME_LABEL)) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 93567e6155..17f7f33891 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -852,7 +852,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Copy")); } - if (isAgentInventory() && !single_folder_root) + bool is_agent_inventory = isAgentInventory(); + if (is_agent_inventory && !single_folder_root) { items.push_back(std::string("New folder from selected")); items.push_back(std::string("Subfolder Separator")); @@ -865,6 +866,17 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } + if (getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (is_agent_inventory + && gInventory.getRootFolderID() != mUUID + && !gInventory.isObjectDescendentOf(mUUID, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) + { + items.push_back(std::string("Add to Favorites")); + } + if (obj->getIsLinkType()) { items.push_back(std::string("Find Original")); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index ea0566f5c4..b95d75a782 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2344,6 +2344,26 @@ void ungroup_folder_items(const LLUUID& folder_id) gInventory.notifyObservers(); } +void set_favorite(const LLUUID& obj_id, bool favorite) +{ + LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj->getIsFavorite() != favorite) + { + LLSD updates; + updates["favorite"] = LLSD().with("toggled", favorite); + LLViewerInventoryCategory* view_folder = dynamic_cast(obj); + if (view_folder) + { + update_inventory_category(obj_id, updates, NULL); + } + LLViewerInventoryItem* view_item = dynamic_cast(obj); + if (view_item) + { + update_inventory_item(obj_id, updates, NULL); + } + } +} + std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) { if (model) @@ -3322,6 +3342,20 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root ungroup_folder_items(*ids.begin()); } } + else if ("add_to_favorites" == action) + { + for (const LLUUID& id : ids) + { + set_favorite(id, true); + } + } + else if ("remove_from_favorites" == action) + { + for (const LLUUID& id : ids) + { + set_favorite(id, false); + } + } else { std::set::iterator set_iter; diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 5a833eab8c..14038967c6 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -114,6 +114,7 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca std::string get_localized_folder_name(LLUUID cat_uuid); void new_folder_window(const LLUUID& folder_id); void ungroup_folder_items(const LLUUID& folder_id); +void set_favorite(const LLUUID& obj_id, bool favorite); std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id); std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& item_id); std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..6e5d8802a4 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -186,6 +186,20 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) { ungroup_folder_items(mUUIDs.front()); } + else if ("add_to_favorites" == action) + { + for (const LLUUID& id : mUUIDs) + { + set_favorite(id, true); + } + } + else if ("remove_from_favorites" == action) + { + for (const LLUUID& id : mUUIDs) + { + set_favorite(id, false); + } + } else if ("take_off" == action || "detach" == action) { for (LLUUID& selected_id : mUUIDs) @@ -707,6 +721,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("New Folder")); disabled_items.push_back(std::string("upload_def")); } + + if (obj->getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else if (is_agent_inventory) + { + items.push_back(std::string("Add to Favorites")); + } } hide_context_entries(*menu, items, disabled_items); diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index c11f1c88cb..929c626947 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -442,6 +442,22 @@ function="Inventory.DoToSelected" parameter="ungroup_folder_items" /> + + + + + + - + + + + + + + Date: Thu, 2 May 2024 03:05:41 +0300 Subject: Viewer#1301 Implement Inventory Favorites Tab WIP#2 --- indra/llinventory/llinventory.cpp | 26 +++++- indra/newview/llinventorypanel.cpp | 93 ++++++++++++++++++--- indra/newview/llinventorypanel.h | 4 +- indra/newview/llpanelmaininventory.cpp | 2 - .../textures/icons/Inv_Favorite_Star_Content.png | Bin 0 -> 474 bytes .../textures/icons/Inv_Favorite_Star_Full.png | Bin 0 -> 582 bytes indra/newview/skins/default/textures/textures.xml | 2 + .../skins/default/xui/en/floater_preview_trash.xml | 4 +- .../default/xui/en/widgets/folder_view_item.xml | 4 +- .../xui/en/widgets/inbox_folder_view_folder.xml | 4 +- 10 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png create mode 100644 indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 2f701f12a0..0545c6262c 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -874,12 +874,20 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\tparent_id\t" << uuid_str << "\n"; mPermissions.exportLegacyStream(output_stream); - if (mThumbnailUUID.notNull()) + bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; + if (needs_metadata) { // Max length is 255 chars, will have to export differently if it gets more data // Ex: use newline and toNotation (uses {}) for unlimited size LLSD metadata; - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + if (mThumbnailUUID.notNull()) + { + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + } + if (mFavorite) + { + metadata["favorite"] = LLSD().with("toggled", mFavorite); + } output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); @@ -1488,11 +1496,21 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n"; output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n"; output_stream << "\t\tname\t" << mName.c_str() << "|\n"; - if (mThumbnailUUID.notNull()) + + bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; + if (needs_metadata) { // Only up to 255 chars LLSD metadata; - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + if (mThumbnailUUID.notNull()) + { + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); + } + if (mFavorite) + { + metadata["favorite"] = LLSD().with("toggled", mFavorite); + } + output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); output_stream << "|\n"; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index bdf9e87e60..f22ac6f775 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -947,18 +947,7 @@ void LLInventoryPanel::initializeViews(F64 max_time) mBuildViewsEndTime = curent_time + max_time; // init everything - LLUUID root_id = getRootFolderID(); - if (root_id.notNull()) - { - buildNewViews(getRootFolderID()); - } - else - { - // Default case: always add "My Inventory" root first, "Library" root second - // If we run out of time, this still should create root folders - buildNewViews(gInventory.getRootFolderID()); // My Inventory - buildNewViews(gInventory.getLibraryRootFolderID()); // Library - } + initRootContent(); if (mBuildViewsQueue.empty()) { @@ -991,6 +980,22 @@ void LLInventoryPanel::initializeViews(F64 max_time) } } +void LLInventoryPanel::initRootContent() +{ + LLUUID root_id = getRootFolderID(); + if (root_id.notNull()) + { + buildNewViews(getRootFolderID()); + } + else + { + // Default case: always add "My Inventory" root first, "Library" root second + // If we run out of time, this still should create root folders + buildNewViews(gInventory.getRootFolderID()); // My Inventory + buildNewViews(gInventory.getLibraryRootFolderID()); // Library + } +} + LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop) { @@ -1248,6 +1253,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; + //collectInventoryDescendants(id, categories, items); mInventory->lockDirectDescendentArrays(id, categories, items); // Make sure panel won't lock in a loop over existing items if @@ -1348,6 +1354,14 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, return folder_view_item; } + +/*void LLInventoryPanel::collectInventoryDescendants(const LLUUID& id, + LLViewerInventoryCategory::cat_array_t*& categories, + LLViewerInventoryItem::item_array_t*& items); +{ + mInventory->lockDirectDescendentArrays(id, categories, items); +}*/ + // bit of a hack to make sure the inventory is open. void LLInventoryPanel::openStartFolderOrMyInventory() { @@ -2250,6 +2264,9 @@ public: protected: LLInventoryFavoritesItemsPanel(const Params&); friend class LLUICtrlFactory; + + void initRootContent(const LLUUID& id); + void initRootContent() override; }; LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& params) @@ -2259,6 +2276,58 @@ LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& par mInvFVBridgeBuilder = &FAVORITES_BUILDER; } +void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) +{ + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + mInventory->lockDirectDescendentArrays(id, categories, items); + + if (categories) + { + S32 count = categories->size(); + for (S32 i = 0; i < count; ++i) + { + LLViewerInventoryCategory* cat = categories->at(i); + if (cat->getPreferredType() == LLFolderType::FT_TRASH) + { + continue; + } + else if (cat->getIsFavorite()) + { + const LLUUID& parent_id = cat->getParentUUID(); + LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); // Should be NULL + + buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } + else // Todo: timelimits + { + initRootContent(cat->getUUID()); + } + } + } + + if (items) + { + S32 count = items->size(); + for (S32 i = 0; i < count; ++i) + { + LLViewerInventoryItem* item = items->at(i); + if (item->getIsFavorite() && typedViewsFilter(id, item)) + { + const LLUUID& parent_id = item->getParentUUID(); + LLFolderViewItem* folder_view_item = getItemByID(id); // Should be NULL + + buildViewsTree(item->getUUID(), parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } + } + } +} + +void LLInventoryFavoritesItemsPanel::initRootContent() +{ + initRootContent(gInventory.getRootFolderID()); // My Inventory +} + /************************************************************************/ /* LLInventorySingleFolderPanel */ /************************************************************************/ diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 97300596f9..b6d21ea9a8 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -334,6 +334,7 @@ public: protected: // Builds the UI. Call this once the inventory is usable. void initializeViews(F64 max_time); + virtual void initRootContent(); // Specific inventory colors static bool sColorSetInitialized; @@ -371,7 +372,7 @@ protected: virtual LLFolderViewItem* createFolderViewItem(LLInvFVBridge * bridge); boost::function& items, BOOL user_action)> mSelectionCallback; -private: +protected: // buildViewsTree does not include some checks and is meant // for recursive use, use buildNewViews() for first call LLFolderViewItem* buildViewsTree(const LLUUID& id, @@ -394,6 +395,7 @@ private: EViewsInitializationState mViewsInitialized; // Whether views have been generated F64 mBuildViewsEndTime; // Stop building views past this timestamp std::deque mBuildViewsQueue; + std::deque mBuildRootContent; }; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index b1bfd52bc6..c41fedec20 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -199,9 +199,7 @@ BOOL LLPanelMainInventory::postBuild() if (favorites_panel) { favorites_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); - favorites_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); LLInventoryFilter& favorites_filter = favorites_panel->getFilter(); - favorites_filter.setFilterFavorites(LLInventoryFilter::FILTER_ONLY_FAVORITES); favorites_filter.setEmptyLookupMessage("InventoryNoMatchingFavorites"); favorites_filter.markDefault(); favorites_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, favorites_panel, _1, _2)); diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png new file mode 100644 index 0000000000..bf7ec1599a Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png differ diff --git a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png new file mode 100644 index 0000000000..916b57f3c5 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index c733d3feaf..7f3b9a8cee 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -304,6 +304,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/xui/en/floater_preview_trash.xml b/indra/newview/skins/default/xui/en/floater_preview_trash.xml index f62e04baf2..ebb5cd9251 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_trash.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_trash.xml @@ -29,8 +29,8 @@ bevel_style="none" scroll.reserve_scroll_corner="false"> Date: Thu, 2 May 2024 21:08:41 +0300 Subject: Viewer#1301 Small cleanup notecards do not need to store 'favorite' flag --- indra/llinventory/llinventory.cpp | 26 ++++---------------------- indra/newview/llinventorypanel.cpp | 9 --------- 2 files changed, 4 insertions(+), 31 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 0545c6262c..2f701f12a0 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -874,20 +874,12 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\tparent_id\t" << uuid_str << "\n"; mPermissions.exportLegacyStream(output_stream); - bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; - if (needs_metadata) + if (mThumbnailUUID.notNull()) { // Max length is 255 chars, will have to export differently if it gets more data // Ex: use newline and toNotation (uses {}) for unlimited size LLSD metadata; - if (mThumbnailUUID.notNull()) - { - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - } - if (mFavorite) - { - metadata["favorite"] = LLSD().with("toggled", mFavorite); - } + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); @@ -1496,21 +1488,11 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n"; output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n"; output_stream << "\t\tname\t" << mName.c_str() << "|\n"; - - bool needs_metadata = mThumbnailUUID.notNull() || mFavorite; - if (needs_metadata) + if (mThumbnailUUID.notNull()) { // Only up to 255 chars LLSD metadata; - if (mThumbnailUUID.notNull()) - { - metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - } - if (mFavorite) - { - metadata["favorite"] = LLSD().with("toggled", mFavorite); - } - + metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); output_stream << "\t\tmetadata\t"; LLSDSerialize::toXML(metadata, output_stream); output_stream << "|\n"; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index f22ac6f775..3892bfee03 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1253,7 +1253,6 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; - //collectInventoryDescendants(id, categories, items); mInventory->lockDirectDescendentArrays(id, categories, items); // Make sure panel won't lock in a loop over existing items if @@ -1354,14 +1353,6 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id, return folder_view_item; } - -/*void LLInventoryPanel::collectInventoryDescendants(const LLUUID& id, - LLViewerInventoryCategory::cat_array_t*& categories, - LLViewerInventoryItem::item_array_t*& items); -{ - mInventory->lockDirectDescendentArrays(id, categories, items); -}*/ - // bit of a hack to make sure the inventory is open. void LLInventoryPanel::openStartFolderOrMyInventory() { -- cgit v1.3 From a420e84f4822d19388241f99a916dacc4d1eab61 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 May 2024 23:22:26 +0300 Subject: viewer#1424 Favorites in Appearance floater #2 --- indra/llinventory/llinventory.cpp | 2 +- indra/llui/llaccordionctrltab.h | 2 +- indra/newview/llinventoryfunctions.cpp | 28 ++++++++++++++-- indra/newview/llinventoryobserver.cpp | 29 ++++++++++++++--- indra/newview/llinventoryobserver.h | 18 +++++++++-- indra/newview/lloutfitslist.cpp | 37 +++++++++++++++++++++- indra/newview/lloutfitslist.h | 9 ++++++ .../default/xui/en/menu_gallery_outfit_tab.xml | 32 +++++++++---------- .../skins/default/xui/en/menu_outfit_gear.xml | 12 +++---- .../skins/default/xui/en/menu_outfit_tab.xml | 6 ++++ 10 files changed, 142 insertions(+), 33 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 2f701f12a0..9b73cbbd74 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1556,7 +1556,7 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; if (favorite_data.has(INV_TOGGLED_LABEL)) { - favorite = favorite_data[INV_ASSET_ID_LABEL].asBoolean(); + favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean(); } setFavorite(favorite); } diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 496c34c38b..c2ddd6f7d1 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -140,7 +140,7 @@ public: S32 notify(const LLSD& info); bool notifyChildren(const LLSD& info); - void draw(); + virtual void draw(); void storeOpenCloseState(); void restoreOpenCloseState(); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 604adea125..123d47b474 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2364,8 +2364,21 @@ void set_favorite(const LLUUID& obj_id, bool favorite) LLInventoryObject* obj = gInventory.getObject(obj_id); if (obj->getIsFavorite() != favorite) { + LLSD val; + if (favorite) + { + val = true; + } // else leave undefined to remove unneeded metadata field + LLSD updates; - updates["favorite"] = LLSD().with("toggled", favorite); + if (favorite) + { + updates["favorite"] = LLSD().with("toggled", true); + } + else + { + updates["favorite"] = LLSD(); + } LLPointer cb = new LLUpdateFavorite(obj_id); @@ -2385,9 +2398,20 @@ void set_favorite(const LLUUID& obj_id, bool favorite) void toggle_favorite(const LLUUID& obj_id) { LLInventoryObject* obj = gInventory.getObject(obj_id); + if (!obj) + { + return; + } LLSD updates; - updates["favorite"] = LLSD().with("toggled", !obj->getIsFavorite()); + if (!obj->getIsFavorite()) + { + updates["favorite"] = LLSD().with("toggled", true); + } + else + { + updates["favorite"] = LLSD(); + } LLPointer cb = new LLUpdateFavorite(obj_id); diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 15cd7957a2..4676d8a411 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -749,6 +749,13 @@ void LLInventoryCategoriesObserver::changed(U32 mask) cat_changed = true; } + bool is_favorite = category->getIsFavorite(); + if (cat_data.mIsFavorite != is_favorite) + { + cat_data.mIsFavorite = is_favorite; + cat_changed = true; + } + // If anything has changed above, fire the callback. if (cat_changed) cat_data.mCallback(); @@ -766,6 +773,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t S32 version = LLViewerInventoryCategory::VERSION_UNKNOWN; S32 current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN; bool can_be_added = true; + bool favorite = false; LLUUID thumbnail_id; LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); @@ -779,6 +787,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t // to a category have been made. version = category->getVersion(); thumbnail_id = category->getThumbnailUUID(); + favorite = category->getIsFavorite(); LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; @@ -804,11 +813,11 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t if(init_name_hash) { digest_t item_name_hash = gInventory.hashDirectDescendentNames(cat_id); - mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents,item_name_hash))); + mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents,item_name_hash))); } else { - mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, cb, version, current_num_known_descendents))); + mCategoryMap.insert(category_map_value_t(cat_id,LLCategoryData(cat_id, thumbnail_id, favorite, cb, version, current_num_known_descendents))); } } @@ -821,25 +830,37 @@ void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id) } LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( - const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents) + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents) : mCatID(cat_id) , mCallback(cb) , mVersion(version) , mDescendentsCount(num_descendents) , mThumbnailId(thumbnail_id) + , mIsFavorite(is_favorite) , mIsNameHashInitialized(false) { } LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( - const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash) + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, S32 version, + S32 num_descendents, + const digest_t& name_hash) : mCatID(cat_id) , mCallback(cb) , mVersion(version) , mDescendentsCount(num_descendents) , mThumbnailId(thumbnail_id) + , mIsFavorite(is_favorite) , mIsNameHashInitialized(true) , mItemNameHash(name_hash) { diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index 6cd630bcd2..7b7d8b06d9 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -277,12 +277,26 @@ protected: typedef LLUUID digest_t; // To clarify the actual usage of this "UUID" struct LLCategoryData { - LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents); - LLCategoryData(const LLUUID& cat_id, const LLUUID& thumbnail_id, callback_t cb, S32 version, S32 num_descendents, const digest_t& name_hash); + LLCategoryData( + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents); + LLCategoryData( + const LLUUID& cat_id, + const LLUUID& thumbnail_id, + bool is_favorite, + callback_t cb, + S32 version, + S32 num_descendents, + const digest_t& name_hash); callback_t mCallback; S32 mVersion; S32 mDescendentsCount; digest_t mItemNameHash; + bool mIsFavorite; bool mIsNameHashInitialized; LLUUID mCatID; LLUUID mThumbnailId; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index c01e04f88d..ef38edfe3d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -81,6 +81,9 @@ const outfit_accordion_tab_params& get_accordion_tab_params() { initialized = true; + LLOutfitAccordionCtrlTab::sFavoriteIcon = LLUI::getUIImage("Inv_Favorite_Star_Full"); + LLOutfitAccordionCtrlTab::sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255)); + LLXMLNodePtr xmlNode; if (LLUICtrlFactory::getLayeredXMLNode("outfit_accordion_tab.xml", xmlNode)) { @@ -155,6 +158,7 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) tab->setName(name); tab->setTitle(name); + tab->setFavorite(cat->getIsFavorite()); // *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated. tab->setDisplayChildren(false); @@ -426,11 +430,12 @@ void LLOutfitsList::updateChangedCategoryName(LLViewerInventoryCategory *cat, st if (outfits_iter != mOutfitsMap.end()) { // Update tab name with the new category name. - LLAccordionCtrlTab* tab = outfits_iter->second; + LLOutfitAccordionCtrlTab* tab = (LLOutfitAccordionCtrlTab*) outfits_iter->second; if (tab) { tab->setName(name); tab->setTitle(name); + tab->setFavorite(cat->getIsFavorite()); } } } @@ -1382,6 +1387,16 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility() LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } + +LLUIImage* LLOutfitAccordionCtrlTab::sFavoriteIcon; +LLUIColor LLOutfitAccordionCtrlTab::sFgColor; + +void LLOutfitAccordionCtrlTab::draw() +{ + LLAccordionCtrlTab::draw(); + drawFavoriteIcon(); +} + BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) { if (y >= getLocalRect().getHeight() - getHeaderHeight()) @@ -1402,4 +1417,24 @@ BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) return LLAccordionCtrlTab::handleToolTip(x, y, mask); } + +void LLOutfitAccordionCtrlTab::drawFavoriteIcon() +{ + if (!mIsFavorite) + { + return; + } + static LLUICachedControl draw_star("InventoryFavoritesUseStar", true); + if (!draw_star) + { + return; + } + + const S32 PAD = 2; + const S32 image_size = 18; + + gl_draw_scaled_image( + getRect().getWidth() - image_size - PAD, getRect().getHeight() - image_size - PAD, + image_size, image_size, sFavoriteIcon->getImage(), sFgColor); +} // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 86702cedfb..8975ac09d1 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -221,8 +221,14 @@ public: Params() : cat_id("cat_id") {} }; + virtual void draw(); virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + void setFavorite(bool is_favorite) { mIsFavorite = is_favorite; } + + static LLUIImage* sFavoriteIcon; + static LLUIColor sFgColor; + protected: LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p) : LLAccordionCtrlTab(p), @@ -230,7 +236,10 @@ public: {} friend class LLUICtrlFactory; + void drawFavoriteIcon(); + LLUUID mFolderID; + bool mIsFavorite = false; }; /** * @class LLOutfitsList diff --git a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml index 77de521154..fb68193006 100755 --- a/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_outfit_tab.xml @@ -50,24 +50,24 @@ function="Outfit.Thumbnail" /> + label="Add to favorites" + layout="topleft" + name="favorites_add"> - + function="Outfit.OnVisible" + parameter="favorites_add" /> + - - - + + + - + @@ -63,9 +63,9 @@ label="Remove from favorite outfits" layout="topleft" name="favorites_remove"> - + diff --git a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml index 070efe9d78..0d45e7c95c 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_tab.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_tab.xml @@ -53,6 +53,9 @@ label="Add to favorites" layout="topleft" name="favorites_add"> + @@ -60,6 +63,9 @@ label="Remove from favorites" layout="topleft" name="favorites_remove"> + -- cgit v1.3 From f73e0d09aabd17f778ce802353dea5c5aae007be Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 30 Apr 2025 23:45:22 +0300 Subject: #3905 Crashes in LLInventoryModel::saveToFile I don't expect it to fix the problem. Just making things more explicit in places of most frequent crashes. --- indra/llinventory/llinventory.cpp | 24 ++++++++++++------------ indra/llinventory/llinventory.h | 3 ++- indra/llinventory/llpermissions.cpp | 16 ++++++++++------ indra/llinventory/llpermissions.h | 1 + indra/llinventory/llsaleinfo.cpp | 9 +++++++-- indra/llinventory/llsaleinfo.h | 1 + indra/llinventory/tests/inventorymisc_test.cpp | 8 ++++++-- indra/newview/llinventorymodel.cpp | 8 ++++++-- indra/newview/llviewerinventory.cpp | 6 ++---- indra/newview/llviewerinventory.h | 4 ++-- 10 files changed, 49 insertions(+), 31 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 5bf8020a68..fe60800700 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -928,7 +928,7 @@ bool LLInventoryItem::exportLegacyStream(std::ostream& output_stream, bool inclu LLSD LLInventoryItem::asLLSD() const { - LLSD sd = LLSD(); + LLSD sd; asLLSD(sd); return sd; } @@ -937,7 +937,7 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const { sd[INV_ITEM_ID_LABEL] = mUUID; sd[INV_PARENT_ID_LABEL] = mParentUUID; - sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions); + ll_fill_sd_from_permissions(sd[INV_PERMISSIONS_LABEL], mPermissions); if (mThumbnailUUID.notNull()) { @@ -963,19 +963,22 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const cipher.encrypt(shadow_id.mData, UUID_BYTES); sd[INV_SHADOW_ID_LABEL] = shadow_id; } - sd[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); - sd[INV_INVENTORY_TYPE_LABEL] = mInventoryType; + sd[INV_ASSET_TYPE_LABEL] = std::string(LLAssetType::lookup(mType)); const std::string inv_type_str = LLInventoryType::lookup(mInventoryType); if(!inv_type_str.empty()) { sd[INV_INVENTORY_TYPE_LABEL] = inv_type_str; } + else + { + sd[INV_INVENTORY_TYPE_LABEL] = (LLSD::Integer)mInventoryType; + } //sd[INV_FLAGS_LABEL] = (S32)mFlags; sd[INV_FLAGS_LABEL] = ll_sd_from_U32(mFlags); - sd[INV_SALE_INFO_LABEL] = mSaleInfo.asLLSD(); + mSaleInfo.asLLSD(sd[INV_SALE_INFO_LABEL]); sd[INV_NAME_LABEL] = mName; sd[INV_DESC_LABEL] = mDescription; - sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate; + sd[INV_CREATION_DATE_LABEL] = (LLSD::Integer)mCreationDate; } bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) @@ -1501,12 +1504,11 @@ bool LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, bool) return true; } -LLSD LLInventoryCategory::exportLLSD() const +void LLInventoryCategory::exportLLSD(LLSD& cat_data) const { - LLSD cat_data; cat_data[INV_FOLDER_ID_LABEL] = mUUID; cat_data[INV_PARENT_ID_LABEL] = mParentUUID; - cat_data[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(mType); + cat_data[INV_ASSET_TYPE_LABEL] = std::string(LLAssetType::lookup(mType)); cat_data[INV_PREFERRED_TYPE_LABEL] = LLFolderType::lookup(mPreferredType); cat_data[INV_NAME_LABEL] = mName; @@ -1518,8 +1520,6 @@ LLSD LLInventoryCategory::exportLLSD() const { cat_data[INV_FAVORITE_LABEL] = LLSD().with(INV_TOGGLED_LABEL, mFavorite); } - - return cat_data; } bool LLInventoryCategory::importLLSD(const LLSD& cat_data) @@ -1570,7 +1570,7 @@ bool LLInventoryCategory::importLLSD(const LLSD& cat_data) return true; } ///---------------------------------------------------------------------------- -/// Local function definitions +/// Local function definitions for testing purposes ///---------------------------------------------------------------------------- LLSD ll_create_sd_from_inventory_item(LLPointer item) diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 2044b0102c..17670d2ea1 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -273,7 +273,7 @@ public: virtual bool importLegacyStream(std::istream& input_stream); virtual bool exportLegacyStream(std::ostream& output_stream, bool include_asset_key = true) const; - LLSD exportLLSD() const; + virtual void exportLLSD(LLSD& sd) const; bool importLLSD(const LLSD& cat_data); //-------------------------------------------------------------------- // Member Variables @@ -288,6 +288,7 @@ protected: // // These functions convert between structured data and an inventory // item, appropriate for serialization. +// Not up to date (no favorites, nor thumbnails), for testing purposes //----------------------------------------------------------------------------- LLSD ll_create_sd_from_inventory_item(LLPointer item); LLSD ll_create_sd_from_inventory_category(LLPointer cat); diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index c8963881df..d800ca02c9 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -1012,17 +1012,21 @@ static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); LLSD ll_create_sd_from_permissions(const LLPermissions& perm) { LLSD rv; + ll_fill_sd_from_permissions(rv, perm); + return rv; +} +void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm) +{ rv[PERM_CREATOR_ID_LABEL] = perm.getCreator(); rv[PERM_OWNER_ID_LABEL] = perm.getOwner(); rv[PERM_LAST_OWNER_ID_LABEL] = perm.getLastOwner(); rv[PERM_GROUP_ID_LABEL] = perm.getGroup(); rv[PERM_IS_OWNER_GROUP_LABEL] = perm.isGroupOwned(); - rv[PERM_BASE_MASK_LABEL] = (S32)perm.getMaskBase(); - rv[PERM_OWNER_MASK_LABEL] = (S32)perm.getMaskOwner(); - rv[PERM_GROUP_MASK_LABEL] = (S32)perm.getMaskGroup(); - rv[PERM_EVERYONE_MASK_LABEL] = (S32)perm.getMaskEveryone(); - rv[PERM_NEXT_OWNER_MASK_LABEL] = (S32)perm.getMaskNextOwner(); - return rv; + rv[PERM_BASE_MASK_LABEL] = (LLSD::Integer)perm.getMaskBase(); + rv[PERM_OWNER_MASK_LABEL] = (LLSD::Integer)perm.getMaskOwner(); + rv[PERM_GROUP_MASK_LABEL] = (LLSD::Integer)perm.getMaskGroup(); + rv[PERM_EVERYONE_MASK_LABEL] = (LLSD::Integer)perm.getMaskEveryone(); + rv[PERM_NEXT_OWNER_MASK_LABEL] = (LLSD::Integer)perm.getMaskNextOwner(); } LLPermissions ll_permissions_from_sd(const LLSD& sd_perm) diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index a68abcfa34..f3e10af25c 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -435,6 +435,7 @@ protected: // like 'creator_id', 'owner_id', etc, with the value copied from the // permission object. LLSD ll_create_sd_from_permissions(const LLPermissions& perm); +void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm); LLPermissions ll_permissions_from_sd(const LLSD& sd_perm); #endif diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index 35bbc1dbb1..b4d64bb4fb 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -90,15 +90,20 @@ bool LLSaleInfo::exportLegacyStream(std::ostream& output_stream) const LLSD LLSaleInfo::asLLSD() const { LLSD sd; + asLLSD(sd); + return sd; +} + +void LLSaleInfo::asLLSD(LLSD& sd) const +{ const char* type = lookup(mSaleType); if (!type) { LL_WARNS_ONCE() << "Unknown sale type: " << mSaleType << LL_ENDL; type = lookup(LLSaleInfo::FS_NOT); } - sd["sale_type"] = type; + sd["sale_type"] = std::string(type); sd["sale_price"] = mSalePrice; - return sd; } bool LLSaleInfo::fromLLSD(const LLSD& sd, bool& has_perm_mask, U32& perm_mask) diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h index 44eb841641..7186e8ab49 100644 --- a/indra/llinventory/llsaleinfo.h +++ b/indra/llinventory/llsaleinfo.h @@ -86,6 +86,7 @@ public: bool exportLegacyStream(std::ostream& output_stream) const; LLSD asLLSD() const; + void asLLSD(LLSD &sd) const; operator LLSD() const { return asLLSD(); } bool fromLLSD(const LLSD& sd, bool& has_perm_mask, U32& perm_mask); bool importLegacyStream(std::istream& input_stream, bool& has_perm_mask, U32& perm_mask); diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index 9779cb8fbc..ee01f0e428 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -329,7 +329,9 @@ namespace tut } LLPointer src1 = create_random_inventory_item(); - fileXML << LLSDOStreamer(src1->asLLSD()) << std::endl; + LLSD sd; + src1->asLLSD(sd); + fileXML << LLSDOStreamer(sd) << std::endl; fileXML.close(); @@ -458,7 +460,9 @@ namespace tut } LLPointer src1 = create_random_inventory_cat(); - fileXML << LLSDOStreamer(src1->exportLLSD()) << std::endl; + LLSD sd; + src1->exportLLSD(sd); + fileXML << LLSDOStreamer(sd) << std::endl; fileXML.close(); llifstream file(filename.c_str()); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 0b2615c706..c7cc8f3032 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3500,7 +3500,9 @@ bool LLInventoryModel::saveToFile(const std::string& filename, { if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { - fileXML << LLSDOStreamer(cat->exportLLSD()) << std::endl; + LLSD sd = LLSD::emptyMap(); + cat->exportLLSD(sd); + fileXML << LLSDOStreamer(sd) << std::endl; cat_count++; } @@ -3514,7 +3516,9 @@ bool LLInventoryModel::saveToFile(const std::string& filename, auto it_count = items.size(); for (auto& item : items) { - fileXML << LLSDOStreamer(item->asLLSD()) << std::endl; + LLSD sd = LLSD::emptyMap(); + item->asLLSD(sd); + fileXML << LLSDOStreamer(sd) << std::endl; if (fileXML.fail()) { diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 36ec6f0d78..8caa0144c3 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -751,13 +751,11 @@ S32 LLViewerInventoryCategory::getViewerDescendentCount() const return descendents_actual; } -LLSD LLViewerInventoryCategory::exportLLSD() const +void LLViewerInventoryCategory::exportLLSD(LLSD & cat_data) const { - LLSD cat_data = LLInventoryCategory::exportLLSD(); + LLInventoryCategory::exportLLSD(cat_data); cat_data[INV_OWNER_ID] = mOwnerID; cat_data[INV_VERSION] = mVersion; - - return cat_data; } bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data) diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 18daa368d9..5cd31353f8 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -232,8 +232,8 @@ public: // How many descendents do we currently have information for in the InventoryModel? S32 getViewerDescendentCount() const; - LLSD exportLLSD() const; - bool importLLSD(const LLSD& cat_data); + virtual void exportLLSD(LLSD &sd) const; + virtual bool importLLSD(const LLSD& cat_data); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); -- cgit v1.3 From 3de223aecf53ee6f69de8fba29aaa6593484d7e8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 1 May 2025 13:10:30 +0300 Subject: #1300 Test coverage for inventory metadata For now it's random, needs more consistent coverage --- indra/llinventory/tests/inventorymisc_test.cpp | 46 +++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index ee01f0e428..e41500b4c5 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -39,6 +39,34 @@ #pragma warning(disable: 4702) #endif +void set_random_inventory_metadata(LLInventoryObject* obj) +{ + S32 extra = rand() % 4; + switch (extra) + { + case 0: + { + LLUUID thumbnail_id; + thumbnail_id.generate(); + obj->setThumbnailUUID(thumbnail_id); + break; + } + case 1: + obj->setFavorite(true); + break; + case 2: + { + LLUUID thumbnail_id; + thumbnail_id.generate(); + obj->setThumbnailUUID(thumbnail_id); + obj->setFavorite(true); + break; + } + default: + break; + } +} + LLPointer create_random_inventory_item() { LLUUID item_id; @@ -75,6 +103,7 @@ LLPointer create_random_inventory_item() sale_info, flags, creation); + set_random_inventory_metadata(item); return item; } @@ -90,6 +119,7 @@ LLPointer create_random_inventory_cat() parent_id, LLFolderType::FT_NONE, std::string("Sample category")); + set_random_inventory_metadata(cat); return cat; } @@ -290,6 +320,7 @@ namespace tut src->setCreationDate(new_creation); // test a save/load cycle to LLSD and back again + // Note: ll_create_sd_from_inventory_item does not support metadata LLSD sd = ll_create_sd_from_inventory_item(src); LLPointer dst = new LLInventoryItem; bool successful_parse = dst->fromLLSD(sd); @@ -366,13 +397,13 @@ namespace tut ensure_equals("8.name::getName() failed", src1->getName(), src2->getName()); ensure_equals("9.description::getDescription() failed", src1->getDescription(), src2->getDescription()); ensure_equals("10.creation::getCreationDate() failed", src1->getCreationDate(), src2->getCreationDate()); - + ensure_equals("13.thumbnails::getThumbnailUUID() failed", src1->getThumbnailUUID(), src2->getThumbnailUUID()); + ensure_equals("14.favorites::getIsFavorite() failed", src1->getIsFavorite(), src2->getIsFavorite()); } template<> template<> void inventory_object::test<8>() { - LLPointer src1 = create_random_inventory_item(); std::ostringstream ostream; @@ -392,8 +423,8 @@ namespace tut ensure_equals("8.name::getName() failed", src1->getName(), src2->getName()); ensure_equals("9.description::getDescription() failed", src1->getDescription(), src2->getDescription()); ensure_equals("10.creation::getCreationDate() failed", src1->getCreationDate(), src2->getCreationDate()); - - + ensure_equals("11.thumbnails::getThumbnailUUID() failed", src1->getThumbnailUUID(), src2->getThumbnailUUID()); + ensure_equals("12.favorites::getIsFavorite() failed", false, src2->getIsFavorite()); // not supposed to carry over } template<> template<> @@ -423,6 +454,8 @@ namespace tut ensure_equals("10.name::getName() failed", src1->getName(), src2->getName()); ensure_equals("11.description::getDescription() failed", src1->getDescription(), src2->getDescription()); ensure_equals("12.creation::getCreationDate() failed", src1->getCreationDate(), src2->getCreationDate()); + ensure_equals("13.thumbnails::getThumbnailUUID() failed", src1->getThumbnailUUID(), src2->getThumbnailUUID()); + ensure_equals("14.favorites::getIsFavorite() failed", src1->getIsFavorite(), src2->getIsFavorite()); } //******class LLInventoryCategory*******// @@ -492,6 +525,8 @@ namespace tut ensure_equals("3.type::getType() failed", src1->getType(), src2->getType()); ensure_equals("4.preferred type::getPreferredType() failed", src1->getPreferredType(), src2->getPreferredType()); ensure_equals("5.name::getName() failed", src1->getName(), src2->getName()); + ensure_equals("6.thumbnails::getThumbnailUUID() failed", src1->getThumbnailUUID(), src2->getThumbnailUUID()); + ensure_equals("7.favorites::getIsFavorite() failed", src1->getIsFavorite(), src2->getIsFavorite()); } template<> template<> @@ -511,6 +546,7 @@ namespace tut ensure_equals("3.type::getType() failed", src1->getType(), src2->getType()); ensure_equals("4.preferred type::getPreferredType() failed", src1->getPreferredType(), src2->getPreferredType()); ensure_equals("5.name::getName() failed", src1->getName(), src2->getName()); - + ensure_equals("13.thumbnails::getThumbnailUUID() failed", src1->getThumbnailUUID(), src2->getThumbnailUUID()); + ensure_equals("14.favorites::getIsFavorite() failed", false, src2->getIsFavorite()); // currently not supposed to carry over } } -- cgit v1.3 From 2cbff073edad0bb31d2a025b888a9fb2e90fe2cf Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 20 May 2025 20:40:04 +0300 Subject: #4000 Cherry pick inventory LEAP functions from develop branch --- indra/llcommon/llassettype.cpp | 17 ++ indra/llcommon/llassettype.h | 2 + indra/llcommon/llsdutil.h | 38 +++++ indra/llinventory/llfoldertype.cpp | 19 +++ indra/llinventory/llfoldertype.h | 2 + indra/newview/CMakeLists.txt | 2 + indra/newview/llinventoryfunctions.h | 4 +- indra/newview/llinventorylistener.cpp | 309 ++++++++++++++++++++++++++++++++++ indra/newview/llinventorylistener.h | 48 ++++++ indra/newview/llinventorymodel.cpp | 8 + indra/newview/llviewerinventory.cpp | 3 + 11 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 indra/newview/llinventorylistener.cpp create mode 100644 indra/newview/llinventorylistener.h (limited to 'indra/llinventory') diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index c09cf7abd2..9672a3262b 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -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; +} diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 547c3f4329..17177d81c3 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -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: diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 38bbe19ddd..4d65059fe6 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -553,6 +553,44 @@ LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter } // namespace llsd +/***************************************************************************** +* LLSDParam> +*****************************************************************************/ +// Given an LLSD array, return a const std::vector&, 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 +class LLSDParam>: 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(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(item)); + } + } + } + } + + operator const std::vector&() const { return v; } + +private: + std::vector v; +}; + // Specialization for generating a hash value from an LLSD block. namespace boost { diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 7e1be17ecc..670405e9b5 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -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; +} diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 46a1b92a96..dd12693f66 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -115,6 +115,8 @@ public: static const std::string& badLookup(); // error string when a lookup fails + static LLSD getTypeNames(); + protected: LLFolderType() {} ~LLFolderType() {} diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 98a1d7f0fd..9290bc0ffa 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -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 diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index a668cc31d8..b40fc051a0 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -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); }; diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp new file mode 100644 index 0000000000..028483e134 --- /dev/null +++ b/indra/newview/llinventorylistener.cpp @@ -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(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; +} diff --git a/indra/newview/llinventorylistener.h b/indra/newview/llinventorylistener.h new file mode 100644 index 0000000000..d50397730c --- /dev/null +++ b/indra/newview/llinventorylistener.h @@ -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 + diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c7cc8f3032..110957dfa7 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -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); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 8caa0144c3..5f61aeaf13 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -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&) {} -- cgit v1.3 From 3b8b408b9031f295a936eb5e3342fbb7eb671c7c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 25 Jul 2025 19:06:06 +0300 Subject: #3969 Make inventory creation from cache faster Still has a lot of space for improvements, but should be 2.5 times faster --- indra/llinventory/llinventory.cpp | 60 +++++---- indra/llinventory/llinventory.h | 3 +- indra/llinventory/llpermissions.cpp | 104 ++++++++++----- indra/llinventory/llpermissions.h | 2 + indra/llinventory/tests/inventorymisc_test.cpp | 2 +- indra/newview/llinventorymodel.cpp | 172 +++++++++++++------------ indra/newview/llviewerinventory.cpp | 19 ++- indra/newview/llviewerinventory.h | 2 +- 8 files changed, 220 insertions(+), 144 deletions(-) (limited to 'indra/llinventory') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index fe60800700..3defad8f3b 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -995,6 +995,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) // TODO - figure out if this should be moved into the noclobber fields above mThumbnailUUID.setNull(); mFavorite = false; + mPermissions.init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); // iterate as map to avoid making unnecessary temp copies of everything LLSD::map_const_iterator i, end; @@ -1053,7 +1054,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) if (i->first == INV_PERMISSIONS_LABEL) { - mPermissions = ll_permissions_from_sd(i->second); + mPermissions.importLLSD(i->second); continue; } @@ -1522,53 +1523,68 @@ void LLInventoryCategory::exportLLSD(LLSD& cat_data) const } } -bool LLInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLInventoryCategory::importLLSDMap(const LLSD& cat_data) { - if (cat_data.has(INV_FOLDER_ID_LABEL)) + LLSD::map_const_iterator i, end; + end = cat_data.endMap(); + for ( i = cat_data.beginMap(); i != end; ++i) + { + importLLSD(i->first, i->second); + } + return true; +} + +bool LLInventoryCategory::importLLSD(const std::string& label, const LLSD& value) +{ + if (label == INV_FOLDER_ID_LABEL) { - setUUID(cat_data[INV_FOLDER_ID_LABEL].asUUID()); + setUUID(value.asUUID()); + return true; } - if (cat_data.has(INV_PARENT_ID_LABEL)) + else if (label == INV_PARENT_ID_LABEL) { - setParent(cat_data[INV_PARENT_ID_LABEL].asUUID()); + setParent(value.asUUID()); + return true; } - if (cat_data.has(INV_ASSET_TYPE_LABEL)) + else if (label == INV_ASSET_TYPE_LABEL) { - setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE_LABEL].asString())); + setType(LLAssetType::lookup(value.asString())); + return true; } - if (cat_data.has(INV_PREFERRED_TYPE_LABEL)) + else if (label == INV_PREFERRED_TYPE_LABEL) { - setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString())); + setPreferredType(LLFolderType::lookup(value.asString())); + return true; } - if (cat_data.has(INV_THUMBNAIL_LABEL)) + else if (label == INV_THUMBNAIL_LABEL) { LLUUID thumbnail_uuid; - const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL]; - if (thumbnail_data.has(INV_ASSET_ID_LABEL)) + if (value.has(INV_ASSET_ID_LABEL)) { - thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID(); + thumbnail_uuid = value[INV_ASSET_ID_LABEL].asUUID(); } setThumbnailUUID(thumbnail_uuid); + return true; } - if (cat_data.has(INV_FAVORITE_LABEL)) + if (label == INV_FAVORITE_LABEL) { bool favorite = false; - const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL]; - if (favorite_data.has(INV_TOGGLED_LABEL)) + if (value.has(INV_TOGGLED_LABEL)) { - favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean(); + favorite = value[INV_TOGGLED_LABEL].asBoolean(); } setFavorite(favorite); } - if (cat_data.has(INV_NAME_LABEL)) + else if (label == INV_NAME_LABEL) { - mName = cat_data[INV_NAME_LABEL].asString(); + mName = value.asString(); LLStringUtil::replaceNonstandardASCII(mName, ' '); LLStringUtil::replaceChar(mName, '|', ' '); + return true; } - - return true; + return false; } + ///---------------------------------------------------------------------------- /// Local function definitions for testing purposes ///---------------------------------------------------------------------------- diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 17670d2ea1..181c46226c 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -274,7 +274,8 @@ public: virtual bool exportLegacyStream(std::ostream& output_stream, bool include_asset_key = true) const; virtual void exportLLSD(LLSD& sd) const; - bool importLLSD(const LLSD& cat_data); + bool importLLSDMap(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); //-------------------------------------------------------------------- // Member Variables //-------------------------------------------------------------------- diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index d800ca02c9..ebf7445c65 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -704,6 +704,79 @@ bool LLPermissions::exportLegacyStream(std::ostream& output_stream) const return true; } +static const std::string PERM_CREATOR_ID_LABEL("creator_id"); +static const std::string PERM_OWNER_ID_LABEL("owner_id"); +static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); +static const std::string PERM_GROUP_ID_LABEL("group_id"); +static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); +static const std::string PERM_BASE_MASK_LABEL("base_mask"); +static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); +static const std::string PERM_GROUP_MASK_LABEL("group_mask"); +static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); +static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); + +void LLPermissions::importLLSD(const LLSD& sd_perm) +{ + LLSD::map_const_iterator i, end; + end = sd_perm.endMap(); + for (i = sd_perm.beginMap(); i != end; ++i) + { + const std::string& label = i->first; + if (label == PERM_CREATOR_ID_LABEL) + { + mCreator = i->second.asUUID(); + continue; + } + if (label == PERM_OWNER_ID_LABEL) + { + mOwner = i->second.asUUID(); + continue; + } + if (label == PERM_LAST_OWNER_ID_LABEL) + { + mLastOwner = i->second.asUUID(); + continue; + } + if (label == PERM_GROUP_ID_LABEL) + { + mGroup = i->second.asUUID(); + continue; + } + if (label == PERM_BASE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskBase = mask; + continue; + } + if (label == PERM_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskOwner = mask; + continue; + } + if (label == PERM_EVERYONE_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskEveryone = mask; + continue; + } + if (label == PERM_GROUP_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskGroup = mask; + continue; + } + if (label == PERM_NEXT_OWNER_MASK_LABEL) + { + PermissionMask mask = i->second.asInteger(); + mMaskNextOwner = mask; + continue; + } + } + + fix(); +} + bool LLPermissions::operator==(const LLPermissions &rhs) const { return @@ -998,16 +1071,6 @@ std::string mask_to_string(U32 mask) ///---------------------------------------------------------------------------- /// exported functions ///---------------------------------------------------------------------------- -static const std::string PERM_CREATOR_ID_LABEL("creator_id"); -static const std::string PERM_OWNER_ID_LABEL("owner_id"); -static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id"); -static const std::string PERM_GROUP_ID_LABEL("group_id"); -static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group"); -static const std::string PERM_BASE_MASK_LABEL("base_mask"); -static const std::string PERM_OWNER_MASK_LABEL("owner_mask"); -static const std::string PERM_GROUP_MASK_LABEL("group_mask"); -static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask"); -static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask"); LLSD ll_create_sd_from_permissions(const LLPermissions& perm) { @@ -1032,25 +1095,6 @@ void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm) LLPermissions ll_permissions_from_sd(const LLSD& sd_perm) { LLPermissions rv; - rv.init( - sd_perm[PERM_CREATOR_ID_LABEL].asUUID(), - sd_perm[PERM_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(), - sd_perm[PERM_GROUP_ID_LABEL].asUUID()); - - // We do a cast to U32 here since LLSD does not attempt to - // represent unsigned ints. - PermissionMask mask; - mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger()); - rv.setMaskBase(mask); - mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger()); - rv.setMaskOwner(mask); - mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger()); - rv.setMaskEveryone(mask); - mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger()); - rv.setMaskGroup(mask); - mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger()); - rv.setMaskNext(mask); - rv.fix(); + rv.importLLSD(sd_perm); return rv; } diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index f3e10af25c..82cdc03727 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -299,6 +299,8 @@ public: bool importLegacyStream(std::istream& input_stream); bool exportLegacyStream(std::ostream& output_stream) const; + void importLLSD(const LLSD& sd_perm); + bool operator==(const LLPermissions &rhs) const; bool operator!=(const LLPermissions &rhs) const; diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index e41500b4c5..f11a4c3bf7 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -518,7 +518,7 @@ namespace tut file.close(); LLPointer src2 = new LLInventoryCategory(); - src2->importLLSD(s_item); + src2->importLLSDMap(s_item); ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID()); ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID()); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 117f2d1adb..2dfc3b014f 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -78,7 +78,7 @@ // Increment this if the inventory contents change in a non-backwards-compatible way. // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect. -const S32 LLInventoryModel::sCurrentInvCacheVersion = 4; +const S32 LLInventoryModel::sCurrentInvCacheVersion = 5; bool LLInventoryModel::sFirstTimeInViewer2 = true; S32 LLInventoryModel::sPendingSystemFolders = 0; @@ -3384,7 +3384,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL; - llifstream file(filename.c_str()); + llifstream file(filename.c_str(), std::ifstream::in | std::ifstream::binary); if (!file.is_open()) { @@ -3393,80 +3393,92 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, } is_cache_obsolete = true; // Obsolete until proven current - - //U64 lines_count = 0U; - std::string line; - LLPointer parser = new LLSDNotationParser(); - while (std::getline(file, line)) + U32 value_nbo = 0; + file.read((char*)&value_nbo, sizeof(U32)); + if (file.fail()) + { + LL_WARNS(LOG_INV) << "Failed to read cache version. Unable to load inventory from: " << filename << LL_ENDL; + } + else { - LLSD s_item; - std::istringstream iss(line); - if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + S32 version = (S32)ntohl(value_nbo); + if (version == sCurrentInvCacheVersion) { - LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL; - break; + // Cache is up to date + is_cache_obsolete = false; } - - if (s_item.has("inv_cache_version")) + else { - S32 version = s_item["inv_cache_version"].asInteger(); - if (version == sCurrentInvCacheVersion) - { - // Cache is up to date - is_cache_obsolete = false; - continue; - } - else - { - LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL; - break; - } + LL_WARNS(LOG_INV) << "Inventory cache is out of date" << LL_ENDL; } - else if (s_item.has("cat_id")) + } + + LLSD inventory; + if (!is_cache_obsolete) + { + LLPointer parser = new LLSDBinaryParser(); + + if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE) { - if (is_cache_obsolete) - break; + is_cache_obsolete = true; + LL_WARNS(LOG_INV) << "Parsing inventory cache failed" << LL_ENDL; + } + } - LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); - if(inv_cat->importLLSD(s_item)) + if (!is_cache_obsolete) + { + const LLSD& llsd_cats = inventory["categories"]; + if (llsd_cats.isArray()) + { + LLSD::array_const_iterator iter = llsd_cats.beginArray(); + LLSD::array_const_iterator end = llsd_cats.endArray(); + for (; iter != end; ++iter) { - categories.push_back(inv_cat); + LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); + if (inv_cat->importLLSDMap(*iter)) + { + categories.push_back(inv_cat); + } } } - else if (s_item.has("item_id")) - { - if (is_cache_obsolete) - break; - LLPointer inv_item = new LLViewerInventoryItem; - if( inv_item->fromLLSD(s_item) ) + const LLSD& llsd_items = inventory["items"]; + if (llsd_items.isArray()) + { + LLSD::array_const_iterator iter = llsd_items.beginArray(); + LLSD::array_const_iterator end = llsd_items.endArray(); + for (; iter != end; ++iter) { - if(inv_item->getUUID().isNull()) - { - LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " - << inv_item->getName() << LL_ENDL; - } - else + LLPointer inv_item = new LLViewerInventoryItem; + if (inv_item->fromLLSD(*iter)) { - if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + if (inv_item->getUUID().isNull()) { - cats_to_update.insert(inv_item->getParentUUID()); + LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; } else { - items.push_back(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } + + // TODO(brad) - figure out how to reenable this without breaking everything else + // static constexpr U64 BATCH_SIZE = 512U; + // if ((++lines_count % BATCH_SIZE) == 0) + // { + // // SL-19968 - make sure message system code gets a chance to run every so often + // pump_idle_startup_network(); + // } } } - -// TODO(brad) - figure out how to reenable this without breaking everything else -// static constexpr U64 BATCH_SIZE = 512U; -// if ((++lines_count % BATCH_SIZE) == 0) -// { -// // SL-19968 - make sure message system code gets a chance to run every so often -// pump_idle_startup_network(); -// } } file.close(); @@ -3489,58 +3501,54 @@ bool LLInventoryModel::saveToFile(const std::string& filename, try { - llofstream fileXML(filename.c_str()); - if (!fileXML.is_open()) + llofstream fileSD(filename.c_str(), std::ios_base::out | std::ios_base::binary); + if (!fileSD.is_open()) { LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL; return false; } - - LLSD cache_ver; - cache_ver["inv_cache_version"] = sCurrentInvCacheVersion; - - if (fileXML.fail()) + U32 value_nbo = htonl(sCurrentInvCacheVersion); + fileSD.write((const char*)(&value_nbo), sizeof(U32)); + if (fileSD.fail()) { - LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL; + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; return false; } - fileXML << LLSDOStreamer(cache_ver) << std::endl; + LLSD inventory; + inventory["categories"] = LLSD::emptyArray(); + LLSD& cat_array = inventory["categories"]; S32 cat_count = 0; for (auto& cat : categories) { if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; cat->exportLLSD(sd); - fileXML << LLSDOStreamer(sd) << std::endl; + cat_array.append(sd); cat_count++; } - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } } + inventory["items"] = LLSD::emptyArray(); + LLSD& item_array = inventory["items"]; auto it_count = items.size(); for (auto& item : items) { - LLSD sd = LLSD::emptyMap(); + LLSD sd; item->asLLSD(sd); - fileXML << LLSDOStreamer(sd) << std::endl; - - if (fileXML.fail()) - { - LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL; - return false; - } + item_array.append(sd); + } + fileSD << LLSDOStreamer(inventory) << std::endl; + if (fileSD.fail()) + { + LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL; + return false; } - fileXML.flush(); + fileSD.flush(); - fileXML.close(); + fileSD.close(); LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL; } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 5f61aeaf13..6155058f14 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -761,18 +761,23 @@ void LLViewerInventoryCategory::exportLLSD(LLSD & cat_data) const cat_data[INV_VERSION] = mVersion; } -bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data) +bool LLViewerInventoryCategory::importLLSD(const std::string& label, const LLSD& value) { - LLInventoryCategory::importLLSD(cat_data); - if (cat_data.has(INV_OWNER_ID)) + if (LLInventoryCategory::importLLSD(label, value)) { - mOwnerID = cat_data[INV_OWNER_ID].asUUID(); + return true; } - if (cat_data.has(INV_VERSION)) + else if (label == INV_OWNER_ID) { - setVersion(cat_data[INV_VERSION].asInteger()); + mOwnerID = value.asUUID(); + return true; } - return true; + else if (label == INV_VERSION) + { + setVersion(value.asInteger()); + return true; + } + return false; } bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 5cd31353f8..0dfbf0cced 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -233,7 +233,7 @@ public: S32 getViewerDescendentCount() const; virtual void exportLLSD(LLSD &sd) const; - virtual bool importLLSD(const LLSD& cat_data); + virtual bool importLLSD(const std::string& label, const LLSD& value); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); -- cgit v1.3