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/newview/llinventoryfunctions.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'indra/newview/llinventoryfunctions.cpp') 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; -- cgit v1.3 From a0c4d81080fbc4b5326e6b598e5df27e01631d48 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 27 Apr 2024 05:01:36 +0300 Subject: viewer#1300 'Star' favorites in inventory #2 --- indra/llui/llfolderviewitem.cpp | 58 ++++++++++++++++++++++++++++++++++ indra/llui/llfolderviewitem.h | 1 + indra/newview/llinventoryfunctions.cpp | 22 +++++++++++-- indra/newview/llinventoryobserver.h | 1 + indra/newview/llinventorypanel.cpp | 35 ++++++++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 84146e5829..be703a1e9a 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1783,6 +1783,64 @@ BOOL LLFolderViewFolder::isMovable() return TRUE; } +void LLFolderViewFolder::updateHasFavorites(bool new_childs_value) +{ + if (mHasFavorites != new_childs_value) + { + if (new_childs_value) + { + mHasFavorites = new_childs_value; + // propagate up to root + LLFolderViewFolder* parent = getParentFolder(); + while (parent && !parent->hasFavorites()) + { + parent->setHasFavorites(true); + parent = parent->getParentFolder(); + } + } + else + { + LLFolderViewFolder* parent = this; + while (parent) + { + bool has_favorites = false; + for (items_t::iterator iter = parent->mItems.begin(); + iter != parent->mItems.end();) + { + items_t::iterator iit = iter++; + if ((*iit)->isFavorite()) + { + has_favorites = true; + break; + } + } + + for (folders_t::iterator iter = parent->mFolders.begin(); + iter != parent->mFolders.end() && !has_favorites;) + { + folders_t::iterator fit = iter++; + if ((*fit)->isFavorite() || (*fit)->hasFavorites()) + { + has_favorites = true; + break; + } + } + + if (!has_favorites) + { + parent->mHasFavorites = false; + parent->setHasFavorites(false); + } + else + { + break; + } + parent = parent->getParentFolder(); + } + } + } +} + BOOL LLFolderViewFolder::isRemovable() { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index eba3cf4f83..5905516023 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -401,6 +401,7 @@ public: bool isFavorite() const { return mIsFavorite; } bool hasFavorites() const { return mHasFavorites; } void setHasFavorites(bool val) { mHasFavorites = val; } + void updateHasFavorites(bool new_childs_value); // destroys this folder, and all children virtual void destroyView(); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index b95d75a782..135dfa3519 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2344,6 +2344,21 @@ void ungroup_folder_items(const LLUUID& folder_id) gInventory.notifyObservers(); } +class LLUpdateFavorite : public LLInventoryCallback +{ +public: + LLUpdateFavorite(const LLUUID& inv_item_id) + : mInvItemID(inv_item_id) + {} + /* virtual */ void fire(const LLUUID& inv_item_id) override + { + gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, mInvItemID); + gInventory.notifyObservers(); + } +private: + LLUUID mInvItemID; +}; + void set_favorite(const LLUUID& obj_id, bool favorite) { LLInventoryObject* obj = gInventory.getObject(obj_id); @@ -2351,15 +2366,18 @@ void set_favorite(const LLUUID& obj_id, bool favorite) { LLSD updates; updates["favorite"] = LLSD().with("toggled", favorite); + + LLPointer cb = new LLUpdateFavorite(obj_id); + LLViewerInventoryCategory* view_folder = dynamic_cast(obj); if (view_folder) { - update_inventory_category(obj_id, updates, NULL); + update_inventory_category(obj_id, updates, cb); } LLViewerInventoryItem* view_item = dynamic_cast(obj); if (view_item) { - update_inventory_item(obj_id, updates, NULL); + update_inventory_item(obj_id, updates, cb); } } } diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index bec08d2cdf..6cd630bcd2 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -60,6 +60,7 @@ public: CREATE = 512, // With ADD, item has just been created. // unfortunately a particular message is still associated with some unique semantics. UPDATE_CREATE = 1024, // With ADD, item added via UpdateCreateInventoryItem + UPDATE_FAVORITE = 2048, // With ADD, item added via UpdateCreateInventoryItem ALL = 0xffffffff }; LLInventoryObserver(); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index ab04a8589a..4aace2f96e 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -620,6 +620,19 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve } } + if (mask & LLInventoryObserver::UPDATE_FAVORITE) + { + if (view_item) + { + // TODO:: move to idle + LLFolderViewFolder* parent = view_item->getParentFolder(); + if (parent) + { + parent->updateHasFavorites(view_item->isFavorite()); + } + } + } + // We don't typically care which of these masks the item is actually flagged with, since the masks // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks @@ -648,6 +661,16 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve setSelection(item_id, FALSE); } updateFolderLabel(model_item->getParentUUID()); + if (model_item->getIsFavorite()) + { + // TODO:: move to idle + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); + if (new_parent) + { + new_parent->updateHasFavorites(true); + } + } + } ////////////////////////////// @@ -694,6 +717,13 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve updateFolderLabel(viewmodel_folder->getUUID()); } old_parent->getViewModelItem()->dirtyDescendantsFilter(); + + if (view_item->isFavorite()) + { + // TODO:: move to idle + old_parent->updateHasFavorites(false); // favorite was removed + new_parent->updateHasFavorites(true); // favorite was added + } } } } @@ -715,6 +745,11 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve { updateFolderLabel(viewmodel_folder->getUUID()); } + if (view_item->isFavorite()) + { + // TODO:: move to idle + parent->updateHasFavorites(false); // favorite was removed + } } } } -- cgit v1.3 From db3e5afbfbbce73e8f8339e8b4f938f11023ca64 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 May 2024 23:10:51 +0300 Subject: Viewer#1301 Implement Inventory Favorites Tab --- indra/newview/llinventorybridge.cpp | 23 +++- indra/newview/llinventoryfunctions.cpp | 14 +++ indra/newview/llinventoryfunctions.h | 15 +++ indra/newview/llinventorypanel.cpp | 193 ++++++++++++++++++++++++++++++--- indra/newview/llinventorypanel.h | 5 +- indra/newview/llviewerinventory.cpp | 3 +- 6 files changed, 233 insertions(+), 20 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d7c7c7b552..20b2e1334e 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -838,6 +838,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { const LLInventoryObject *obj = getInventoryObject(); bool single_folder_root = (mRoot == NULL); + bool is_cof = isCOFFolder(); + bool is_inbox = isInboxFolder(); if (obj) { @@ -853,7 +855,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } bool is_agent_inventory = isAgentInventory(); - if (is_agent_inventory && !single_folder_root) + if (is_agent_inventory && !single_folder_root && !is_cof && !is_inbox) { items.push_back(std::string("New folder from selected")); items.push_back(std::string("Subfolder Separator")); @@ -889,6 +891,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (!isItemMovable() || !isItemRemovable()) { disabled_items.push_back(std::string("Cut")); + disabled_items.push_back(std::string("New folder from selected")); } } else @@ -898,7 +901,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, items.push_back(std::string("Find Links")); } - if (!isInboxFolder() && !single_folder_root) + if (!is_inbox && !single_folder_root) { items.push_back(std::string("Rename")); if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0)) @@ -938,6 +941,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (!isItemMovable() || !isItemRemovable()) { disabled_items.push_back(std::string("Cut")); + disabled_items.push_back(std::string("New folder from selected")); } if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder()) @@ -960,7 +964,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } // Don't allow items to be pasted directly into the COF or the inbox - if (!isCOFFolder() && !isInboxFolder()) + if (!is_cof && !is_inbox) { items.push_back(std::string("Paste")); } @@ -4445,6 +4449,15 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.push_back(std::string("Rename")); items.push_back(std::string("thumbnail")); + if (cat->getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else + { + items.push_back(std::string("Add to Favorites")); + } + addDeleteContextMenuOptions(items, disabled_items); // EXT-4030: disallow deletion of currently worn outfit const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); @@ -8029,6 +8042,7 @@ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) buildContextMenuOptions(flags, items, disabled_items); items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end()); hide_context_entries(menu, items, disabled_items); } @@ -8072,6 +8086,9 @@ void LLFavoritesFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items, items; buildContextMenuOptions(flags, items, disabled_items); + items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end()); + items.erase(std::remove(items.begin(), items.end(), std::string("New folder from selected")), items.end()); + hide_context_entries(menu, items, disabled_items); } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 135dfa3519..81be2c1f24 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2663,6 +2663,20 @@ bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryIt return FALSE; } +bool LLFavoritesCollector::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + if (item && item->getIsFavorite()) + { + return true; + } + if (cat && cat->getIsFavorite()) + { + return true; + } + return false; +} + bool LLBuddyCollector::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 14038967c6..44f85bfb3e 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -324,6 +324,21 @@ protected: LLUUID mGroupID; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFavoritesCollector +// +// Simple class that collects calling cards that are not null, and not +// the agent. Duplicates are possible. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFavoritesCollector : public LLInventoryCollectFunctor +{ +public: + LLFavoritesCollector() {} + virtual ~LLFavoritesCollector() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLBuddyCollector // diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 3892bfee03..4682f2085b 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -865,7 +865,23 @@ void LLInventoryPanel::idle(void* user_data) bool in_visible_chain = panel->isInVisibleChain(); - if (!panel->mBuildViewsQueue.empty()) + if (!panel->mBuildRootQueue.empty()) + { + const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms + F64 curent_time = LLTimer::getTotalSeconds(); + panel->mBuildViewsEndTime = curent_time + max_time; + + while (curent_time < panel->mBuildViewsEndTime + && !panel->mBuildRootQueue.empty()) + { + LLUUID item_id = panel->mBuildRootQueue.back(); + panel->mBuildRootQueue.pop_back(); + panel->findAndInitRootContent(item_id); + + curent_time = LLTimer::getTotalSeconds(); + } + } + else if (!panel->mBuildViewsQueue.empty()) { const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms F64 curent_time = LLTimer::getTotalSeconds(); @@ -949,7 +965,7 @@ void LLInventoryPanel::initializeViews(F64 max_time) // init everything initRootContent(); - if (mBuildViewsQueue.empty()) + if (mBuildViewsQueue.empty() && mBuildRootQueue.empty()) { mViewsInitialized = VIEWS_INITIALIZED; } @@ -2252,12 +2268,19 @@ public: getFilter().setFilterNoMarketplaceFolder(); } + void removeItemID(const LLUUID& id) override; + protected: LLInventoryFavoritesItemsPanel(const Params&); friend class LLUICtrlFactory; - void initRootContent(const LLUUID& id); + void findAndInitRootContent(const LLUUID& folder_id) override; void initRootContent() override; + + bool removeFavorite(const LLUUID& id, const LLInventoryObject* model_item); + void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override; + + std::set mRootContentIDs; }; LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& params) @@ -2267,8 +2290,27 @@ LLInventoryFavoritesItemsPanel::LLInventoryFavoritesItemsPanel(const Params& par mInvFVBridgeBuilder = &FAVORITES_BUILDER; } -void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) +void LLInventoryFavoritesItemsPanel::removeItemID(const LLUUID& id) +{ + std::set::iterator found = mRootContentIDs.find(id); + if (found != mRootContentIDs.end()) + { + mRootContentIDs.erase(found); + // check content for favorites + mBuildRootQueue.emplace_back(id); + } + + LLInventoryPanel::removeItemID(id); +} + +void LLInventoryFavoritesItemsPanel::findAndInitRootContent(const LLUUID& id) { + F64 curent_time = LLTimer::getTotalSeconds(); + if (mBuildViewsEndTime < curent_time) + { + mBuildRootQueue.emplace_back(id); + return; + } LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; mInventory->lockDirectDescendentArrays(id, categories, items); @@ -2285,14 +2327,18 @@ void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) } else if (cat->getIsFavorite()) { - const LLUUID& parent_id = cat->getParentUUID(); - LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); // Should be NULL + LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); + if (!folder_view_item) + { + const LLUUID& parent_id = cat->getParentUUID(); + mRootContentIDs.emplace(cat->getUUID()); - buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } } - else // Todo: timelimits + else { - initRootContent(cat->getUUID()); + findAndInitRootContent(cat->getUUID()); } } } @@ -2303,12 +2349,17 @@ void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) for (S32 i = 0; i < count; ++i) { LLViewerInventoryItem* item = items->at(i); - if (item->getIsFavorite() && typedViewsFilter(id, item)) + const LLUUID item_id = item->getUUID(); + if (item->getIsFavorite() && typedViewsFilter(item_id, item)) { - const LLUUID& parent_id = item->getParentUUID(); - LLFolderViewItem* folder_view_item = getItemByID(id); // Should be NULL + LLFolderViewItem* folder_view_item = getItemByID(id); + if (!folder_view_item) + { + const LLUUID& parent_id = item->getParentUUID(); + mRootContentIDs.emplace(item_id); - buildViewsTree(item->getUUID(), parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + buildViewsTree(item_id, parent_id, item, folder_view_item, mFolderRoot.get(), BUILD_TIMELIMIT); + } } } } @@ -2316,9 +2367,123 @@ void LLInventoryFavoritesItemsPanel::initRootContent(const LLUUID& id) void LLInventoryFavoritesItemsPanel::initRootContent() { - initRootContent(gInventory.getRootFolderID()); // My Inventory + findAndInitRootContent(gInventory.getRootFolderID()); // My Inventory +} + +bool LLInventoryFavoritesItemsPanel::removeFavorite(const LLUUID& id, const LLInventoryObject* model_item) +{ + std::set::iterator found = mRootContentIDs.find(id); + if (found == mRootContentIDs.end()) + { + return false; + } + + mRootContentIDs.erase(found); + + // This item is in root's content, remove item's UI. + LLFolderViewItem* view_item = getItemByID(id); + if (view_item) + { + LLFolderViewFolder* parent = view_item->getParentFolder(); + LLFolderViewModelItemInventory* viewmodel_item = static_cast(view_item->getViewModelItem()); + if (viewmodel_item) + { + removeItemID(viewmodel_item->getUUID()); + } + view_item->destroyView(); + if (parent) + { + parent->getViewModelItem()->dirtyDescendantsFilter(); + LLFolderViewModelItemInventory* viewmodel_folder = static_cast(parent->getViewModelItem()); + if (viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + } + if (view_item->isFavorite()) + { + parent->updateHasFavorites(false); // favorite was removed + } + } + } + + return true; } +void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, const LLInventoryObject* model_item) +{ + if (!model_item && !getItemByID(id)) + { + // remove operation, but item is not in panel already + return; + } + + bool handled = false; + + if (mask & (LLInventoryObserver::UPDATE_FAVORITE | + LLInventoryObserver::STRUCTURE | + LLInventoryObserver::ADD | + LLInventoryObserver::REMOVE)) + { + if (model_item && model_item->getIsFavorite()) + { + LLFolderViewItem* view_item = getItemByID(id); + if (!view_item) + { + const LLViewerInventoryCategory* cat = dynamic_cast(model_item); + if (cat) + { + // New favorite folder + if (cat->getPreferredType() != LLFolderType::FT_TRASH) + { + // If any descendants were in the list, remove them + LLFavoritesCollector is_favorite; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendentsIf(id, cat_array, item_array, FALSE, is_favorite); + for (LLInventoryModel::cat_array_t::const_iterator it = cat_array.begin(); it != cat_array.end(); ++it) + { + removeFavorite((*it)->getUUID(), *it); + } + for (LLInventoryModel::item_array_t::const_iterator it = item_array.begin(); it != item_array.end(); ++it) + { + removeFavorite((*it)->getUUID(), *it); + } + + LLFolderViewItem* folder_view_item = getItemByID(cat->getUUID()); + if (!folder_view_item) + { + const LLUUID& parent_id = cat->getParentUUID(); + mRootContentIDs.emplace(cat->getUUID()); + + buildViewsTree(cat->getUUID(), parent_id, cat, folder_view_item, mFolderRoot.get(), BUILD_ONE_FOLDER); + } + } + } + else + { + // New favorite item + if (model_item->getIsFavorite() && typedViewsFilter(id, model_item)) + { + const LLUUID& parent_id = model_item->getParentUUID(); + mRootContentIDs.emplace(id); + + buildViewsTree(id, parent_id, model_item, NULL, mFolderRoot.get(), BUILD_ONE_FOLDER); + } + } + handled = true; + } + } + else + { + handled = removeFavorite(id, model_item); + } + } + + if (!handled) + { + LLInventoryPanel::itemChanged(id, mask, model_item); + } +} /************************************************************************/ /* LLInventorySingleFolderPanel */ /************************************************************************/ diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index b6d21ea9a8..a03ec15777 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -251,7 +251,7 @@ public: bool reset_filter = false); static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id); void addItemID(const LLUUID& id, LLFolderViewItem* itemp); - void removeItemID(const LLUUID& id); + virtual void removeItemID(const LLUUID& id); LLFolderViewItem* getItemByID(const LLUUID& id); LLFolderViewFolder* getFolderByID(const LLUUID& id); void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); @@ -335,6 +335,7 @@ protected: // Builds the UI. Call this once the inventory is usable. void initializeViews(F64 max_time); virtual void initRootContent(); + virtual void findAndInitRootContent(const LLUUID& root_id) {}; // Specific inventory colors static bool sColorSetInitialized; @@ -395,7 +396,7 @@ protected: EViewsInitializationState mViewsInitialized; // Whether views have been generated F64 mBuildViewsEndTime; // Stop building views past this timestamp std::deque mBuildViewsQueue; - std::deque mBuildRootContent; + std::deque mBuildRootQueue; }; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b9a7c9448f..3a4ac96826 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1436,7 +1436,8 @@ void update_inventory_category( if(obj) { if (LLFolderType::lookupIsProtectedType(obj->getPreferredType()) - && (updates.size() != 1 || !updates.has("thumbnail"))) + && (updates.size() != 1 + || !(updates.has("thumbnail") || updates.has("favorite")))) { LLNotificationsUtil::add("CannotModifyProtectedCategories"); return; -- cgit v1.3 From 5c78396b64c985a7e58d045ff3f343bccc81c8d3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 May 2024 00:40:30 +0300 Subject: viewer#1424 Favorites in Appearance floater #1 --- indra/llui/llfolderviewitem.cpp | 2 +- indra/newview/llinventoryfunctions.cpp | 21 ++++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 23 +++++++++++ indra/newview/lloutfitgallery.cpp | 3 +- indra/newview/lloutfitslist.cpp | 46 ++++++++++++++++++++- indra/newview/lloutfitslist.h | 2 + .../textures/icons/Inv_Favorite_Star_Content.png | Bin 474 -> 620 bytes .../textures/icons/Inv_Favorite_Star_Full.png | Bin 582 -> 485 bytes .../default/xui/en/menu_gallery_inventory.xml | 16 +++++++ .../default/xui/en/menu_gallery_outfit_tab.xml | 20 +++++++++ .../skins/default/xui/en/menu_outfit_gear.xml | 30 +++++++++++--- .../skins/default/xui/en/menu_outfit_tab.xml | 14 +++++++ 13 files changed, 169 insertions(+), 9 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index b473b3b395..59be1444d9 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -785,7 +785,7 @@ void LLFolderViewItem::drawFavoriteIcon(const Params& default_params, const LLUI if (favorite_image) { const S32 PAD = 2; - const S32 image_size = 30; + const S32 image_size = 18; gl_draw_scaled_image( getRect().getWidth() - image_size - PAD, getRect().getHeight() - mItemHeight + PAD, diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 81be2c1f24..604adea125 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2382,6 +2382,27 @@ void set_favorite(const LLUUID& obj_id, bool favorite) } } +void toggle_favorite(const LLUUID& obj_id) +{ + LLInventoryObject* obj = gInventory.getObject(obj_id); + + LLSD updates; + updates["favorite"] = LLSD().with("toggled", !obj->getIsFavorite()); + + LLPointer cb = new LLUpdateFavorite(obj_id); + + LLViewerInventoryCategory* view_folder = dynamic_cast(obj); + if (view_folder) + { + update_inventory_category(obj_id, updates, cb); + } + LLViewerInventoryItem* view_item = dynamic_cast(obj); + if (view_item) + { + update_inventory_item(obj_id, updates, cb); + } +} + std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) { if (model) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 44f85bfb3e..fe05e30353 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -115,6 +115,7 @@ 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); +void toggle_favorite(const LLUUID& obj_id); 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 6e5d8802a4..de7ebd5ca8 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -547,6 +547,18 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("New Outfit")); } + if (!is_trash && !is_in_trash && gInventory.getRootFolderID() != selected_id) + { + if (obj->getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else + { + items.push_back(std::string("Add to Favorites")); + } + } + items.push_back(std::string("Subfolder Separator")); if (!is_system_folder && !isRootFolder()) { @@ -587,6 +599,17 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men if(is_agent_inventory) { items.push_back(std::string("Cut")); + if (!is_in_trash) + { + if (obj->getIsFavorite()) + { + items.push_back(std::string("Remove from Favorites")); + } + else + { + items.push_back(std::string("Add to Favorites")); + } + } if (!is_link || !is_cof || !get_is_item_worn(selected_id)) { items.push_back(std::string("Delete")); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index efffcefc4a..da2fbebc14 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1149,6 +1149,7 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu() registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id)); registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2)); registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id)); + registrar.add("Outfit.Favorite", boost::bind(&LLOutfitGalleryContextMenu::onFavorite, this, selected_id)); registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id)); enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2)); enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2)); @@ -1190,7 +1191,7 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility() mMenu->setItemVisible("expand", FALSE); mMenu->setItemVisible("collapse", FALSE); mMenu->setItemVisible("thumbnail", have_selection); - mMenu->setItemVisible("sort_folders_by_name", TRUE); + mMenu->setItemVisible("sort_order_by_image", TRUE); LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 1a6c5db535..c01e04f88d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -45,6 +45,7 @@ #include "lloutfitobserver.h" #include "lltoggleablemenu.h" #include "lltransutil.h" +#include "llviewercontrol.h" #include "llviewermenu.h" #include "llvoavatar.h" #include "llvoavatarself.h" @@ -1062,6 +1063,7 @@ LLContextMenu* LLOutfitContextMenu::createMenu() registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id)); + registrar.add("Outfit.Favorite", boost::bind(&LLOutfitContextMenu::onFavorite, this, selected_id)); registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id)); enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2)); @@ -1112,6 +1114,16 @@ bool LLOutfitContextMenu::onVisible(LLSD::String param) { return LLAppearanceMgr::instance().getCanRemoveOutfit(outfit_cat_id); } + else if ("favorites_add" == param) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id); + return cat && !cat->getIsFavorite(); + } + else if ("favorites_remove" == param) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(outfit_cat_id); + return cat && cat->getIsFavorite(); + } return true; } @@ -1136,6 +1148,14 @@ void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id) } } +void LLOutfitContextMenu::onFavorite(const LLUUID& outfit_cat_id) +{ + if (outfit_cat_id.notNull()) + { + toggle_favorite(outfit_cat_id); + } +} + void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id) { if (outfit_cat_id.notNull()) @@ -1173,7 +1193,8 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist) registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this)); registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this)); - registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this)); + registrar.add("Gear.Favorite", boost::bind(&LLOutfitListGearMenuBase::onFavorite, this)); + registrar.add("Gear.SortByImage", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this)); enable_registrar.add("Gear.OnEnable", boost::bind(&LLOutfitListGearMenuBase::onEnable, this, _2)); enable_registrar.add("Gear.OnVisible", boost::bind(&LLOutfitListGearMenuBase::onVisible, this, _2)); @@ -1296,6 +1317,10 @@ bool LLOutfitListGearMenuBase::onEnable(LLSD::String param) { return LLAppearanceMgr::instance().getCanReplaceCOF(mOutfitList->getSelectedOutfitUUID()); } + if ("sort_by_image" == param) + { + return !gSavedSettings.getBOOL("OutfitGallerySortByName"); + } return mOutfitList->isActionEnabled(param); } @@ -1307,6 +1332,16 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param) { return false; } + else if ("favorites_add" == param) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); + return cat && !cat->getIsFavorite(); + } + else if ("favorites_remove" == param) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(selected_outfit_id); + return cat && cat->getIsFavorite(); + } return true; } @@ -1318,6 +1353,12 @@ void LLOutfitListGearMenuBase::onThumbnail() LLFloaterReg::showInstance("change_item_thumbnail", data); } +void LLOutfitListGearMenuBase::onFavorite() +{ + const LLUUID& selected_outfit_id = getSelectedOutfitID(); + toggle_favorite(selected_outfit_id); +} + void LLOutfitListGearMenuBase::onChangeSortOrder() { @@ -1336,7 +1377,8 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility() mMenu->setItemVisible("expand", TRUE); mMenu->setItemVisible("collapse", TRUE); mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull()); - mMenu->setItemVisible("sort_folders_by_name", FALSE); + mMenu->setItemVisible("favorite", getSelectedOutfitID().notNull()); + mMenu->setItemVisible("sort_order_by_image", FALSE); LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index 89821f9333..86702cedfb 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -161,6 +161,7 @@ protected: static void renameOutfit(const LLUUID& outfit_cat_id); void onThumbnail(const LLUUID &outfit_cat_id); + void onFavorite(const LLUUID& outfit_cat_id); void onSave(const LLUUID &outfit_cat_id); private: @@ -180,6 +181,7 @@ public: protected: virtual void onUpdateItemsVisibility(); virtual void onThumbnail(); + virtual void onFavorite(); virtual void onChangeSortOrder(); const LLUUID& getSelectedOutfitID(); 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 index bf7ec1599a..b71b202234 100644 Binary files a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Content.png 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 index 916b57f3c5..7d55fb5cfe 100644 Binary files a/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png and b/indra/newview/skins/default/textures/icons/Inv_Favorite_Star_Full.png differ 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 929c626947..11c9988dd6 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -125,6 +125,22 @@ function="Inventory.DoToSelected" parameter="thumbnail" /> + + + + + + + + + + + + + + + + + + + + + + + name="sort_order_by_image"> + function="Gear.SortByImage" /> + function="Gear.OnEnable" + parameter="sort_by_image" /> + + + + + + 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/newview/llinventoryfunctions.cpp') 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 738cf84c340d8ade3ab462340d1444c4e70ef9f5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 May 2024 23:51:11 +0300 Subject: viewer#1424 Favorite support for items in outfits For now marking originals, pointless to marks links in COF, needs a revision due to inconsistency with inventory --- indra/newview/llinventoryfunctions.cpp | 13 +++++++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llpanelwearing.cpp | 10 ++++++++++ indra/newview/llwearableitemslist.cpp | 15 ++++++++++++++- .../skins/default/xui/en/menu_wearable_list_item.xml | 14 ++++++++++++++ indra/newview/skins/default/xui/en/menu_wearing_tab.xml | 14 ++++++++++++++ 6 files changed, 66 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 123d47b474..3e19bf885d 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2427,6 +2427,19 @@ void toggle_favorite(const LLUUID& obj_id) } } +void toggle_linked_favorite(const LLUUID& obj_id) +{ + LLViewerInventoryItem* item = gInventory.getItem(obj_id); + if (!item) + { + LL_WARNS() << "Invalid item" << LL_ENDL; + return; + } + + LLUUID linked_id = item->getLinkedUUID(); + toggle_favorite(linked_id); +} + std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) { if (model) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index fe05e30353..681d5e1611 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -116,6 +116,7 @@ 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); void toggle_favorite(const LLUUID& obj_id); +void toggle_linked_favorite(const LLUUID& obj_id); 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/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index b66c546f9b..aecdf13495 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -113,6 +113,7 @@ protected: boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); registrar.add("Wearing.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); + registrar.add("Wearing.Favorite", boost::bind(toggle_linked_favorite, mUUIDs.front())); LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); updateMenuItemsVisibility(menu); @@ -125,6 +126,8 @@ protected: bool bp_selected = false; // true if body parts selected bool clothes_selected = false; bool attachments_selected = false; + bool can_favorite = false; + bool can_unfavorite = false; // See what types of wearables are selected. for (uuid_vec_t::const_iterator it = mUUIDs.begin(); it != mUUIDs.end(); ++it) @@ -137,6 +140,9 @@ protected: continue; } + LLUUID linked_id = item->getLinkedUUID(); + LLViewerInventoryItem* linked_item = gInventory.getItem(linked_id); + LLAssetType::EType type = item->getType(); if (type == LLAssetType::AT_CLOTHING) { @@ -150,6 +156,8 @@ protected: { attachments_selected = true; } + can_favorite |= !linked_item->getIsFavorite(); + can_unfavorite |= linked_item->getIsFavorite(); } // Enable/disable some menu items depending on the selection. @@ -166,6 +174,8 @@ protected: menu->setItemVisible("detach", allow_detach); menu->setItemVisible("edit_outfit_separator", show_touch | show_edit | allow_take_off || allow_detach); menu->setItemVisible("show_original", mUUIDs.size() == 1); + menu->setItemVisible("favorites_add", can_favorite); + menu->setItemVisible("favorites_remove", can_unfavorite); } }; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 948fe55e0d..0576862dfb 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -936,6 +936,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() // Register handlers for attachments. registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); + registrar.add("Attachment.Favorite", boost::bind(toggle_linked_favorite, selected_id)); registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id)); registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id)); registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2)); @@ -967,6 +968,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu U32 n_links = 0; // number of links among the selected items U32 n_editable = 0; // number of editable items among the selected ones U32 n_touchable = 0; // number of touchable items among the selected ones + U32 n_favorites = 0; // number of favorite items among the selected ones bool can_be_worn = true; @@ -990,6 +992,11 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu const bool is_editable = get_is_item_editable(id); const bool is_touchable = enable_attachment_touch(id); const bool is_already_worn = gAgentWearables.selfHasWearable(wearable_type); + + LLUUID linked_id = item->getLinkedUUID(); + LLViewerInventoryItem* linked_item = gInventory.getItem(linked_id); + const bool is_favorite = linked_item->getIsFavorite(); + if (is_worn) { ++n_worn; @@ -1010,10 +1017,14 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu { ++n_already_worn; } + if (is_favorite) + { + ++n_favorites; + } if (can_be_worn) { - can_be_worn = get_can_item_be_worn(item->getLinkedUUID()); + can_be_worn = get_can_item_be_worn(linked_id); } } // for @@ -1035,6 +1046,8 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemEnabled(menu, "create_new", LLAppearanceMgr::instance().canAddWearables(ids)); setMenuItemVisible(menu, "show_original", !standalone); setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items); + setMenuItemVisible(menu, "favorites_add", n_favorites < n_items); + setMenuItemVisible(menu, "favorites_remove", n_favorites > 0); setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items); setMenuItemVisible(menu, "detach", mask == MASK_ATTACHMENT && n_worn == n_items); setMenuItemVisible(menu, "take_off_or_detach", mask == (MASK_ATTACHMENT|MASK_CLOTHING)); diff --git a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml index ee77ef23f0..63d37edf38 100644 --- a/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml +++ b/indra/newview/skins/default/xui/en/menu_wearable_list_item.xml @@ -79,6 +79,20 @@ + + + + + + + + + + + + -- cgit v1.3 From 25b19eb6b8b8482d5f6cff0cae8665a0f7518eb1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 17 May 2024 22:22:45 +0300 Subject: viewer#1424 Proper links support for favorites --- indra/newview/llinventorybridge.cpp | 4 +- indra/newview/llinventoryfilter.cpp | 13 ++-- indra/newview/llinventoryfunctions.cpp | 117 ++++++++++++++++++------------- indra/newview/llinventoryfunctions.h | 3 +- indra/newview/llinventorygallery.cpp | 5 +- indra/newview/llinventorygallerymenu.cpp | 6 +- indra/newview/llinventorypanel.cpp | 7 +- indra/newview/llpanelwearing.cpp | 2 +- indra/newview/llwearableitemslist.cpp | 2 +- 9 files changed, 94 insertions(+), 65 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e930af2d27..aa6d747622 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2283,11 +2283,11 @@ bool LLItemBridge::isFavorite() const LLInventoryModel* model = getInventoryModel(); if (model) { - item = (LLViewerInventoryItem*)model->getItem(mUUID); + item = model->getItem(mUUID); } if (item) { - return item->getIsFavorite(); + return get_is_favorite(item); } return false; } diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index cb54645ce5..52d03e302e 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -624,12 +624,15 @@ bool LLInventoryFilter::checkAgainstFilterFavorites(const LLUUID& object_id) con const LLInventoryObject* object = gInventory.getObject(object_id); if (!object) return true; - const bool is_favorite = object->getIsFavorite(); - if (is_favorite && (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES)) - return false; - if (!is_favorite && (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES)) - return false; + if (mFilterOps.mFilterFavorites != FILTER_INCLUDE_FAVORITES) + { + bool is_favorite = get_is_favorite(object); + if (is_favorite && (mFilterOps.mFilterFavorites == FILTER_EXCLUDE_FAVORITES)) + return false; + if (!is_favorite && (mFilterOps.mFilterFavorites == FILTER_ONLY_FAVORITES)) + return false; + } return true; } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 3e19bf885d..930e9e48ea 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2353,58 +2353,40 @@ public: /* virtual */ void fire(const LLUUID& inv_item_id) override { gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, mInvItemID); - gInventory.notifyObservers(); - } -private: - LLUUID mInvItemID; -}; -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 + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches matches(mInvItemID); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + items, + LLInventoryModel::INCLUDE_TRASH, + matches); - LLSD updates; - if (favorite) + std::set link_ids; + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); ++it) { - updates["favorite"] = LLSD().with("toggled", true); - } - else - { - updates["favorite"] = LLSD(); - } + LLPointer item = *it; - LLPointer cb = new LLUpdateFavorite(obj_id); - - LLViewerInventoryCategory* view_folder = dynamic_cast(obj); - if (view_folder) - { - update_inventory_category(obj_id, updates, cb); - } - LLViewerInventoryItem* view_item = dynamic_cast(obj); - if (view_item) - { - update_inventory_item(obj_id, updates, cb); + gInventory.addChangedMask(LLInventoryObserver::UPDATE_FAVORITE, item->getUUID()); } + + gInventory.notifyObservers(); } -} +private: + LLUUID mInvItemID; +}; -void toggle_favorite(const LLUUID& obj_id) +void favorite_send(LLInventoryObject* obj, const LLUUID& obj_id, bool favorite) { - LLInventoryObject* obj = gInventory.getObject(obj_id); - if (!obj) + LLSD val; + if (favorite) { - return; - } + val = true; + } // else leave undefined to remove unneeded metadata field LLSD updates; - if (!obj->getIsFavorite()) + if (favorite) { updates["favorite"] = LLSD().with("toggled", true); } @@ -2427,17 +2409,56 @@ void toggle_favorite(const LLUUID& obj_id) } } -void toggle_linked_favorite(const LLUUID& obj_id) +bool get_is_favorite(const LLInventoryObject* object) { - LLViewerInventoryItem* item = gInventory.getItem(obj_id); - if (!item) + if (object->getIsLinkType()) { - LL_WARNS() << "Invalid item" << LL_ENDL; - return; + LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID()); + return obj && obj->getIsFavorite(); + } + + return object->getIsFavorite(); +} + +bool get_is_favorite(const LLUUID& obj_id) +{ + LLInventoryObject* object = gInventory.getObject(obj_id); + if (object && object->getIsLinkType()) + { + LLInventoryObject* obj = gInventory.getObject(object->getLinkedUUID()); + return obj && obj->getIsFavorite(); + } + + return object->getIsFavorite(); +} + +void set_favorite(const LLUUID& obj_id, bool favorite) +{ + LLInventoryObject* obj = gInventory.getObject(obj_id); + + if (obj && obj->getIsLinkType()) + { + obj = gInventory.getObject(obj_id); + } + + if (obj && obj->getIsFavorite() != favorite) + { + favorite_send(obj, obj_id, favorite); + } +} + +void toggle_favorite(const LLUUID& obj_id) +{ + LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getIsLinkType()) + { + obj = gInventory.getObject(obj_id); } - LLUUID linked_id = item->getLinkedUUID(); - toggle_favorite(linked_id); + if (obj) + { + favorite_send(obj, obj_id, !obj->getIsFavorite()); + } } std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 681d5e1611..d90198d59b 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -114,9 +114,10 @@ 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); +bool get_is_favorite(const LLInventoryObject* object); +bool get_is_favorite(const LLUUID& obj_id); void set_favorite(const LLUUID& obj_id, bool favorite); void toggle_favorite(const LLUUID& obj_id); -void toggle_linked_favorite(const LLUUID& obj_id); 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/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 5991697ab7..d2f1257444 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -929,6 +929,7 @@ bool LLInventoryGallery::updateAddedItem(LLUUID item_id) } bool res = false; + bool is_favorite = get_is_favorite(obj); LLInventoryGalleryItem* item = buildGalleryItem( name, @@ -940,7 +941,7 @@ bool LLInventoryGallery::updateAddedItem(LLUUID item_id) obj->getCreationDate(), obj->getIsLinkType(), is_worn, - obj->getIsFavorite()); + is_favorite); mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item)); if (mGalleryCreated) { @@ -2154,7 +2155,7 @@ void LLInventoryGallery::refreshList(const LLUUID& category_id) return; } - updateChangedItemData(*items_iter, obj->getName(), obj->getIsFavorite()); + updateChangedItemData(*items_iter, obj->getName(), get_is_favorite(obj)); mNeedsArrange = true; } diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index de7ebd5ca8..00c8b191f5 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -549,7 +549,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men if (!is_trash && !is_in_trash && gInventory.getRootFolderID() != selected_id) { - if (obj->getIsFavorite()) + if (get_is_favorite(obj)) { items.push_back(std::string("Remove from Favorites")); } @@ -601,7 +601,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("Cut")); if (!is_in_trash) { - if (obj->getIsFavorite()) + if (get_is_favorite(obj)) { items.push_back(std::string("Remove from Favorites")); } @@ -745,7 +745,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("upload_def")); } - if (obj->getIsFavorite()) + if (get_is_favorite(obj)) { items.push_back(std::string("Remove from Favorites")); } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4682f2085b..8450c344a7 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -626,10 +626,11 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve { if (view_item) { + view_item->refresh(); LLFolderViewFolder* parent = view_item->getParentFolder(); if (parent) { - parent->updateHasFavorites(view_item->isFavorite()); + parent->updateHasFavorites(get_is_favorite(model_item)); } } } @@ -662,7 +663,8 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve setSelection(item_id, FALSE); } updateFolderLabel(model_item->getParentUUID()); - if (model_item->getIsFavorite()) + + if (get_is_favorite(model_item)) { LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); if (new_parent) @@ -2424,6 +2426,7 @@ void LLInventoryFavoritesItemsPanel::itemChanged(const LLUUID& id, U32 mask, con LLInventoryObserver::ADD | LLInventoryObserver::REMOVE)) { + // specifically exlude links and not get_is_favorite(model_item) if (model_item && model_item->getIsFavorite()) { LLFolderViewItem* view_item = getItemByID(id); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index aecdf13495..dbabe935f5 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -113,7 +113,7 @@ protected: boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); registrar.add("Wearing.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs)); - registrar.add("Wearing.Favorite", boost::bind(toggle_linked_favorite, mUUIDs.front())); + registrar.add("Wearing.Favorite", boost::bind(toggle_favorite, mUUIDs.front())); LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); updateMenuItemsVisibility(menu); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 8e44271efb..71b765ce71 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -936,7 +936,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() // Register handlers for attachments. registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids)); - registrar.add("Attachment.Favorite", boost::bind(toggle_linked_favorite, selected_id)); + registrar.add("Attachment.Favorite", boost::bind(toggle_favorite, selected_id)); registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id)); registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id)); registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2)); -- cgit v1.3 From 9f00bb19b189753d9f801e080a87c821dcdcc8af Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 31 May 2024 12:21:36 +0300 Subject: viewer#1600 Fixed being unable to delete links to worn objects --- indra/newview/llinventoryfunctions.cpp | 4 ++-- indra/newview/llinventorygallery.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 016b0880eb..be9a20b924 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -3185,7 +3185,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root for (LLInventoryModel::item_array_t::value_type& item : items) { - if (get_is_item_worn(item)) + if (!item->getIsLinkType() && get_is_item_worn(item)) { has_worn = true; LLWearableType::EType type = item->getWearableType(); @@ -3205,7 +3205,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root } } LLViewerInventoryItem* item = gInventory.getItem(obj_id); - if (item && get_is_item_worn(item)) + if (item && !item->getIsLinkType() && get_is_item_worn(item)) { has_worn = true; LLWearableType::EType type = item->getWearableType(); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 329c0d751a..708e6be73e 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -1988,7 +1988,7 @@ void LLInventoryGallery::deleteSelection() for (LLInventoryModel::item_array_t::value_type& item : items) { - if (get_is_item_worn(item)) + if (!item->getIsLinkType() && get_is_item_worn(item)) { has_worn = true; LLWearableType::EType type = item->getWearableType(); @@ -2009,7 +2009,7 @@ void LLInventoryGallery::deleteSelection() } LLViewerInventoryItem* item = gInventory.getItem(id); - if (item && get_is_item_worn(item)) + if (item && !item->getIsLinkType() && get_is_item_worn(item)) { has_worn = true; LLWearableType::EType type = item->getWearableType(); -- cgit v1.3 From db3f7eafa05636a3079037109d3d21514b25a8bb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 4 Jun 2024 02:08:12 +0300 Subject: viewer#1588 Upload directly to Specified Inventory Folder --- indra/newview/llfloaterbvhpreview.cpp | 7 +- indra/newview/llfloaterbvhpreview.h | 2 +- indra/newview/llfloaterimagepreview.cpp | 4 +- indra/newview/llfloaterimagepreview.h | 2 +- indra/newview/llfloatermodelpreview.cpp | 8 +- indra/newview/llfloatermodelpreview.h | 7 +- indra/newview/llfloaternamedesc.cpp | 32 +++-- indra/newview/llfloaternamedesc.h | 9 +- indra/newview/llinventorybridge.cpp | 3 + indra/newview/llinventoryfunctions.cpp | 51 ++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 19 +-- indra/newview/llinventorypanel.cpp | 22 +--- indra/newview/llmaterialeditor.cpp | 29 +++-- indra/newview/llmaterialeditor.h | 14 ++- indra/newview/llmeshrepository.cpp | 19 ++- indra/newview/llmeshrepository.h | 9 +- indra/newview/llsnapshotlivepreview.cpp | 2 +- indra/newview/llviewerassetupload.cpp | 26 +++-- indra/newview/llviewerassetupload.h | 5 + indra/newview/llviewermenufile.cpp | 44 ++++--- indra/newview/llviewermenufile.h | 10 ++ .../default/xui/en/menu_gallery_inventory.xml | 130 +++++++++++++++++++++ .../skins/default/xui/en/menu_inventory.xml | 103 +++++++++++++--- 24 files changed, 429 insertions(+), 129 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 1fb0a72d3e..5c80d9cdc9 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -118,8 +118,8 @@ std::string STATUS[] = //----------------------------------------------------------------------------- // LLFloaterBvhPreview() //----------------------------------------------------------------------------- -LLFloaterBvhPreview::LLFloaterBvhPreview(const std::string& filename) : - LLFloaterNameDesc(filename) +LLFloaterBvhPreview::LLFloaterBvhPreview(const LLSD& args) : + LLFloaterNameDesc(args) { mLastMouseX = 0; mLastMouseY = 0; @@ -1013,7 +1013,8 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost)); + expected_upload_cost, + floaterp->mDestinationFolderId)); upload_new_resource(assetUploadInfo); } diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h index 9de74c39cd..4dd28389a5 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -70,7 +70,7 @@ protected: class LLFloaterBvhPreview : public LLFloaterNameDesc { public: - LLFloaterBvhPreview(const std::string& filename); + LLFloaterBvhPreview(const LLSD& args); virtual ~LLFloaterBvhPreview(); BOOL postBuild(); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 7851c5403b..9fa3dd0c47 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -71,8 +71,8 @@ const S32 PREVIEW_TEXTURE_HEIGHT = 320; //----------------------------------------------------------------------------- // LLFloaterImagePreview() //----------------------------------------------------------------------------- -LLFloaterImagePreview::LLFloaterImagePreview(const std::string& filename) : - LLFloaterNameDesc(filename), +LLFloaterImagePreview::LLFloaterImagePreview(const LLSD& args) : + LLFloaterNameDesc(args), mAvatarPreview(NULL), mSculptedPreview(NULL), diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index 9e764e4972..47228d7676 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -110,7 +110,7 @@ protected: class LLFloaterImagePreview : public LLFloaterNameDesc { public: - LLFloaterImagePreview(const std::string& filename); + LLFloaterImagePreview(const LLSD& args); virtual ~LLFloaterImagePreview(); virtual BOOL postBuild(); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 66f89d88d3..ab5766f260 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -349,14 +349,14 @@ void LLFloaterModelPreview::initModelPreview() } //static -bool LLFloaterModelPreview::showModelPreview() +void LLFloaterModelPreview::showModelPreview(const LLUUID& dest_folder) { LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model"); if (fmp && !fmp->isModelLoading()) { + fmp->setUploadDestination(dest_folder); fmp->loadHighLodModel(); } - return true; } void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) @@ -505,7 +505,7 @@ void LLFloaterModelPreview::onClickCalculateBtn() gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, - mUploadModelUrl, false, + mUploadModelUrl, mDestinationFolderId, false, getWholeModelFeeObserverHandle()); toggleCalculateButton(false); @@ -1655,7 +1655,7 @@ void LLFloaterModelPreview::onUpload(void* user_data) gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, - mp->mUploadModelUrl, + mp->mUploadModelUrl, mp->mDestinationFolderId, true, LLHandle(), mp->getWholeModelUploadObserverHandle()); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 20e645532b..018014ba04 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -73,7 +73,8 @@ public: /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void initModelPreview(); - static bool showModelPreview(); + void setUploadDestination(const LLUUID& dest_folder) { mDestinationFolderId = dest_folder; } + static void showModelPreview(const LLUUID& dest_folder = LLUUID::null); BOOL handleMouseDown(S32 x, S32 y, MASK mask); BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -164,9 +165,6 @@ protected: static void onPhysicsBrowse(LLUICtrl* ctrl, void* userdata); static void onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata); - static void onPhysicsOptimize(LLUICtrl* ctrl, void* userdata); - static void onPhysicsDecomposeBack(LLUICtrl* ctrl, void* userdata); - static void onPhysicsSimplifyBack(LLUICtrl* ctrl, void* userdata); void draw(); @@ -225,6 +223,7 @@ private: void createSmoothComboBox(LLComboBox* combo_box, float min, float max); + LLUUID mDestinationFolderId; LLButton* mUploadBtn; LLButton* mCalculateBtn; LLViewerTextEditor* mUploadLogText; diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index b47deb838b..ffb21f34c9 100644 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -62,11 +62,20 @@ const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; //----------------------------------------------------------------------------- // LLFloaterNameDesc() //----------------------------------------------------------------------------- -LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& filename ) - : LLFloater(filename), - mIsAudio(FALSE) +LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& args) + : LLFloater(args) + , mIsAudio(FALSE) + , mIsText(FALSE) { - mFilenameAndPath = filename.asString(); + if (args.isString()) + { + mFilenameAndPath = args.asString(); + } + else + { + mFilenameAndPath = args["filename"].asString(); + mDestinationFolderId = args["dest"].asUUID(); + } mFilename = gDirUtilp->getBaseFileName(mFilenameAndPath, false); } @@ -203,7 +212,8 @@ void LLFloaterNameDesc::onBtnOK( ) LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost)); + expected_upload_cost, + mDestinationFolderId)); upload_new_resource(uploadInfo, callback, nruserdata); } @@ -230,8 +240,8 @@ void LLFloaterNameDesc::onBtnCancel() // LLFloaterSoundPreview() //----------------------------------------------------------------------------- -LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& filename ) - : LLFloaterNameDesc(filename) +LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& args ) + : LLFloaterNameDesc(args) { mIsAudio = TRUE; } @@ -251,8 +261,8 @@ BOOL LLFloaterSoundPreview::postBuild() // LLFloaterAnimPreview() //----------------------------------------------------------------------------- -LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& filename ) - : LLFloaterNameDesc(filename) +LLFloaterAnimPreview::LLFloaterAnimPreview(const LLSD& args ) + : LLFloaterNameDesc(args) { } @@ -270,8 +280,8 @@ BOOL LLFloaterAnimPreview::postBuild() // LLFloaterScriptPreview() //----------------------------------------------------------------------------- -LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& filename ) - : LLFloaterNameDesc(filename) +LLFloaterScriptPreview::LLFloaterScriptPreview(const LLSD& args ) + : LLFloaterNameDesc(args) { mIsText = TRUE; } diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h index 148da6912a..f2dc8cfaa7 100644 --- a/indra/newview/llfloaternamedesc.h +++ b/indra/newview/llfloaternamedesc.h @@ -39,7 +39,7 @@ class LLRadioGroup; class LLFloaterNameDesc : public LLFloater { public: - LLFloaterNameDesc(const LLSD& filename); + LLFloaterNameDesc(const LLSD& args); virtual ~LLFloaterNameDesc(); virtual BOOL postBuild(); @@ -58,26 +58,27 @@ protected: std::string mFilenameAndPath; std::string mFilename; + LLUUID mDestinationFolderId; }; class LLFloaterSoundPreview : public LLFloaterNameDesc { public: - LLFloaterSoundPreview(const LLSD& filename ); + LLFloaterSoundPreview(const LLSD& args ); virtual BOOL postBuild(); }; class LLFloaterAnimPreview : public LLFloaterNameDesc { public: - LLFloaterAnimPreview(const LLSD& filename ); + LLFloaterAnimPreview(const LLSD& args ); virtual BOOL postBuild(); }; class LLFloaterScriptPreview : public LLFloaterNameDesc { public: - LLFloaterScriptPreview(const LLSD& filename ); + LLFloaterScriptPreview(const LLSD& args ); virtual BOOL postBuild(); }; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index fbb4ac8801..b4a3054d07 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4263,6 +4263,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items } disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("upload_options")); disabled_items.push_back(std::string("upload_def")); disabled_items.push_back(std::string("create_new")); } @@ -4286,6 +4287,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) { disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("upload_options")); disabled_items.push_back(std::string("upload_def")); disabled_items.push_back(std::string("create_new")); } @@ -4351,6 +4353,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items } if (!isMarketplaceListingsFolder()) { + items.push_back(std::string("upload_options")); items.push_back(std::string("upload_def")); items.push_back(std::string("create_new")); items.push_back(std::string("New Script")); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index be9a20b924..909dea050e 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -51,6 +51,7 @@ #include "lldirpicker.h" #include "lldonotdisturbnotificationstorage.h" #include "llfloatermarketplacelistings.h" +#include "llfloatermodelpreview.h" #include "llfloatersidepanelcontainer.h" #include "llfocusmgr.h" #include "llfolderview.h" @@ -62,6 +63,7 @@ #include "llinventorymodel.h" #include "llinventorypanel.h" #include "lllineeditor.h" +#include "llmaterialeditor.h" #include "llmarketplacenotifications.h" #include "llmarketplacefunctions.h" #include "llmenugl.h" @@ -86,6 +88,7 @@ #include "llviewermessage.h" #include "llviewerfoldertype.h" #include "llviewerobjectlist.h" +#include "llviewermenufile.h" #include "llviewerregion.h" #include "llviewerwindow.h" #include "llvoavatarself.h" @@ -3548,6 +3551,54 @@ void LLInventoryAction::removeItemFromDND(LLFolderView* root) } } +void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::string& action) +{ + if (action == "def_model") + { + gSavedPerAccountSettings.setString("ModelUploadFolder", dest_id.asString()); + } + else if (action == "def_texture") + { + gSavedPerAccountSettings.setString("TextureUploadFolder", dest_id.asString()); + } + else if (action == "def_sound") + { + gSavedPerAccountSettings.setString("SoundUploadFolder", dest_id.asString()); + } + else if (action == "def_animation") + { + gSavedPerAccountSettings.setString("AnimationUploadFolder", dest_id.asString()); + } + else if (action == "def_pbr_material") + { + gSavedPerAccountSettings.setString("PBRUploadFolder", dest_id.asString()); + } + else if (action == "upload_texture") + { + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_IMAGE, false); + } + else if (action == "upload_sound") + { + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_WAV, false); + } + else if (action == "upload_animation") + { + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, dest_id), LLFilePicker::FFLOAD_ANIM, false); + } + else if (action == "upload_model") + { + LLFloaterModelPreview::showModelPreview(dest_id); + } + else if (action == "upload_pbr_material") + { + LLMaterialEditor::importMaterial(dest_id); + } + else if (action == "upload_bulk") + { + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, dest_id), LLFilePicker::FFLOAD_ALL, true); + } +} + void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 5cb996ad54..f8403f890c 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -583,6 +583,7 @@ struct LLInventoryAction static void callback_copySelected(const LLSD& notification, const LLSD& response, class LLInventoryModel* model, class LLFolderView* root, const std::string& action); static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); static void removeItemFromDND(LLFolderView* root); + static void fileUploadLocation(const LLUUID& dest_id, const std::string& action); static void saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 4b47346473..77bdb4d1f5 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -344,22 +344,7 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata) { const std::string param = userdata.asString(); - if (param == "model") - { - gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString()); - } - else if (param == "texture") - { - gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString()); - } - else if (param == "sound") - { - gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString()); - } - else if (param == "animation") - { - gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString()); - } + LLInventoryAction::fileUploadLocation(mUUIDs.front(), param); } bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata) @@ -525,6 +510,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men { items.push_back(std::string("New Folder")); } + items.push_back(std::string("upload_options")); items.push_back(std::string("upload_def")); } @@ -714,6 +700,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("upload_options")); disabled_items.push_back(std::string("upload_def")); } } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 4ac43ea6b2..f1471e81c7 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1727,26 +1727,8 @@ bool LLInventoryPanel::beginIMSession() void LLInventoryPanel::fileUploadLocation(const LLSD& userdata) { const std::string param = userdata.asString(); - if (param == "model") - { - gSavedPerAccountSettings.setString("ModelUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString()); - } - else if (param == "texture") - { - gSavedPerAccountSettings.setString("TextureUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString()); - } - else if (param == "sound") - { - gSavedPerAccountSettings.setString("SoundUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString()); - } - else if (param == "animation") - { - gSavedPerAccountSettings.setString("AnimationUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString()); - } - else if (param == "pbr_material") - { - gSavedPerAccountSettings.setString("PBRUploadFolder", LLFolderBridge::sSelf.get()->getUUID().asString()); - } + const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID(); + LLInventoryAction::fileUploadLocation(dest, param); } void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index b7811dfb43..f3b2339893 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1398,7 +1398,7 @@ bool LLMaterialEditor::saveIfNeeded() } std::string res_desc = buildMaterialDescription(); - createInventoryItem(buffer, mMaterialName, res_desc, local_permissions); + createInventoryItem(buffer, mMaterialName, res_desc, local_permissions, mUploadFolder); // We do not update floater with uploaded asset yet, so just close it. closeFloater(); @@ -1568,12 +1568,12 @@ private: std::string mNewName; }; -void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions) +void LLMaterialEditor::createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder) { // gen a new uuid for this asset LLTransactionID tid; tid.generate(); // timestamp-based randomization + uniquification - LLUUID parent = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL); + LLUUID parent = upload_folder.isNull() ? gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) : upload_folder; const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? LLPointer cb = new LLObjectsMaterialItemCallback(permissions, buffer, name); @@ -1887,7 +1887,11 @@ static void pack_textures( } } -void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model_in, S32 index) +void LLMaterialEditor::uploadMaterialFromModel( + const std::string& filename, + tinygltf::Model& model_in, + S32 index, + const LLUUID& dest) { if (index < 0 || !LLMaterialEditor::capabilitiesAvailable()) { @@ -1910,12 +1914,13 @@ void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tiny // This uses 'filename' to make sure multiple bulk uploads work // instead of fighting for a single instance. LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor", LLSD().with("filename", filename).with("index", LLSD::Integer(index))); + me->mUploadFolder = dest; me->loadMaterial(model_in, filename, index, false); me->saveIfNeeded(); } -void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index) +void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index, const LLUUID& dest_folder) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; @@ -1961,6 +1966,7 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 ind } LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); + me->mUploadFolder = dest_folder; if (index >= 0) { @@ -2411,17 +2417,15 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati return; } - createInventoryItem(str.str(), new_name, std::string(), permissions); + createInventoryItem(str.str(), new_name, std::string(), permissions, LLUUID::null); } -const void upload_bulk(const std::vector& filenames, LLFilePicker::ELoadFilter type); - void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename, S32 index, bool open_floater) { if (index == model_in.materials.size()) { // bulk upload all the things - upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL); + upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL, mUploadFolder); return; } @@ -2828,10 +2832,10 @@ void LLMaterialEditor::setFromGltfMetaData(const std::string& filename, const ti } } -void LLMaterialEditor::importMaterial() +void LLMaterialEditor::importMaterial(const LLUUID dest_folder) { LLFilePickerReplyThread::startPicker( - [](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) + [dest_folder](const std::vector& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter) { if (LLAppViewer::instance()->quitRequested()) { @@ -2839,7 +2843,7 @@ void LLMaterialEditor::importMaterial() } if (filenames.size() > 0) { - LLMaterialEditor::loadMaterialFromFile(filenames[0], -1); + LLMaterialEditor::loadMaterialFromFile(filenames[0], -1, dest_folder); } }, LLFilePicker::FFLOAD_MATERIAL, @@ -3521,6 +3525,7 @@ void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, con LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), expected_upload_cost, + mUploadFolder, false, cb, failed_upload)); diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index dda65476af..68b957a489 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -94,7 +94,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener void setFromGltfMetaData(const std::string& filename, const tinygltf::Model& model, S32 index); // open a file dialog and select a gltf/glb file for import - static void importMaterial(); + static void importMaterial(const LLUUID dest_folder = LLUUID::null); // for live preview, apply current material to currently selected object void applyToSelection(); @@ -105,8 +105,11 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener void loadAsset() override; // @index if -1 and file contains more than one material, // will promt to select specific one - static void uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model, S32 index); - static void loadMaterialFromFile(const std::string& filename, S32 index = -1); + static void uploadMaterialFromModel(const std::string& filename, + tinygltf::Model& model, + S32 index, + const LLUUID& dest_folder_id = LLUUID::null); + static void loadMaterialFromFile(const std::string& filename, S32 index = -1, const LLUUID& dest_folder = LLUUID::null); void onSelectionChanged(); // live overrides selection changes @@ -134,8 +137,6 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener void onClickSave(); - void getGLTFModel(tinygltf::Model& model); - std::string getEncodedAsset(); bool decodeAsset(const std::vector& buffer); @@ -239,7 +240,7 @@ private: static void saveObjectsMaterialAs(const LLGLTFMaterial *render_material, const LLLocalGLTFMaterial *local_material, const LLPermissions& permissions, const LLUUID& object_id /* = LLUUID::null */, const LLUUID& item /* = LLUUID::null */); static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id); - static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions); + static void createInventoryItem(const std::string &buffer, const std::string &name, const std::string &desc, const LLPermissions& permissions, const LLUUID& upload_folder); void setFromGLTFMaterial(LLGLTFMaterial* mat); bool setFromSelection(); @@ -249,6 +250,7 @@ private: friend class LLMaterialFilePicker; LLUUID mAssetID; + LLUUID mUploadFolder; LLTextureCtrl* mBaseColorTextureCtrl; LLTextureCtrl* mMetallicTextureCtrl; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f6441f8404..66cad13739 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2094,7 +2094,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, - const std::string & upload_url, bool do_upload, + const std::string & upload_url, LLUUID destination_folder_id, bool do_upload, LLHandle fee_observer, LLHandle upload_observer) : LLThread("mesh upload"), @@ -2102,6 +2102,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mDiscarded(false), mDoUpload(do_upload), mWholeModelUploadURL(upload_url), + mDestinationFolderId(destination_folder_id), mFeeObserverHandle(fee_observer), mUploadObserverHandle(upload_observer) { @@ -2224,8 +2225,16 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) LLSD result; LLSD res; - result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT); - result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE); + if (mDestinationFolderId.isNull()) + { + result["folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT); + result["texture_folder_id"] = gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE); + } + else + { + result["folder_id"] = mDestinationFolderId; + result["texture_folder_id"] = mDestinationFolderId; + } result["asset_type"] = "mesh"; result["inventory_type"] = "object"; result["description"] = "(No Description)"; @@ -4338,12 +4347,12 @@ bool LLMeshRepoThread::hasHeader(const LLUUID& mesh_id) void LLMeshRepository::uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, - std::string upload_url, bool do_upload, + std::string upload_url, const LLUUID& destination_folder_id, bool do_upload, LLHandle fee_observer, LLHandle upload_observer) { LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, lock_scale_if_joint_position, - upload_url, do_upload, fee_observer, upload_observer); + upload_url, destination_folder_id, do_upload, fee_observer, upload_observer); mUploadWaitList.push_back(thread); } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index b31d726004..e77a4a6af7 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -501,10 +501,13 @@ public: LLHost mHost; std::string mWholeModelFeeCapability; std::string mWholeModelUploadURL; + LLUUID mDestinationFolderId; LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, - const std::string & upload_url, bool do_upload = true, + const std::string & upload_url, + const LLUUID destination_folder_id = LLUUID::null, + bool do_upload = true, LLHandle fee_observer = (LLHandle()), LLHandle upload_observer = (LLHandle())); ~LLMeshUploadThread(); @@ -663,7 +666,9 @@ public: void uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position, - std::string upload_url, bool do_upload = true, + std::string upload_url, + const LLUUID& destination_folder_id = LLUUID::null, + bool do_upload = true, LLHandle fee_observer= (LLHandle()), LLHandle upload_observer = (LLHandle())); diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index ef0f58ff7a..1310826d06 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -1028,7 +1028,7 @@ void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) tid, LLAssetType::AT_TEXTURE, res_name, res_desc, 0, folder_type, inv_type, PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost, !outfit_snapshot)); + expected_upload_cost, LLUUID::null, !outfit_snapshot)); upload_new_resource(assetUploadInfo); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 078db565f5..daf635cc57 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -62,7 +62,8 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId, LLAssetType::EType assetType, std::string name, std::string description, S32 compressionInfo, LLFolderType::EType destinationType, LLInventoryType::EType inventoryType, U32 nextOWnerPerms, - U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) : + U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId, bool showInventory) : mTransactionId(transactId), mAssetType(assetType), mName(name), @@ -75,7 +76,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId, mEveryonePerms(everyonePerms), mExpectedUploadCost(expectedCost), mShowInventory(showInventory), - mFolderId(LLUUID::null), + mFolderId(destFolderId), mItemId(LLUUID::null), mAssetId(LLAssetID::null) { } @@ -84,7 +85,8 @@ LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId, LLResourceUploadInfo::LLResourceUploadInfo(std::string name, std::string description, S32 compressionInfo, LLFolderType::EType destinationType, LLInventoryType::EType inventoryType, - U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost, bool showInventory) : + U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId, bool showInventory) : mName(name), mDescription(description), mCompressionInfo(compressionInfo), @@ -97,7 +99,7 @@ LLResourceUploadInfo::LLResourceUploadInfo(std::string name, mShowInventory(showInventory), mTransactionId(), mAssetType(LLAssetType::AT_NONE), - mFolderId(LLUUID::null), + mFolderId(destFolderId), mItemId(LLUUID::null), mAssetId(LLAssetID::null) { @@ -299,9 +301,12 @@ void LLResourceUploadInfo::assignDefaults() mDescription = "(No Description)"; } - mFolderId = gInventory.findUserDefinedCategoryUUIDForType( - (mDestinationFolderType == LLFolderType::FT_NONE) ? - (LLFolderType::EType)mAssetType : mDestinationFolderType); + if (mFolderId.isNull()) + { + mFolderId = gInventory.findUserDefinedCategoryUUIDForType( + (mDestinationFolderType == LLFolderType::FT_NONE) ? + (LLFolderType::EType)mAssetType : mDestinationFolderType); + } } std::string LLResourceUploadInfo::getDisplayName() const @@ -358,10 +363,12 @@ LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo( U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId, bool show_inventory) : LLResourceUploadInfo(name, description, compressionInfo, destinationType, inventoryType, - nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory), + nextOWnerPerms, groupPerms, everyonePerms, expectedCost, + destFolderId, show_inventory), mFileName(fileName) { } @@ -566,12 +573,13 @@ LLNewBufferedResourceUploadInfo::LLNewBufferedResourceUploadInfo( U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId, bool show_inventory, uploadFinish_f finish, uploadFailure_f failure) : LLResourceUploadInfo(name, description, compressionInfo, destinationType, inventoryType, - nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory) + nextOWnerPerms, groupPerms, everyonePerms, expectedCost, destFolderId, show_inventory) , mBuffer(buffer) , mFinishFn(finish) , mFailureFn(failure) diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h index 5a07fbf802..dbe2c7e7ea 100644 --- a/indra/newview/llviewerassetupload.h +++ b/indra/newview/llviewerassetupload.h @@ -54,6 +54,7 @@ public: U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID &destFolderId = LLUUID::null, bool showInventory = true); virtual ~LLResourceUploadInfo() @@ -104,6 +105,7 @@ protected: U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId = LLUUID::null, bool showInventory = true); LLResourceUploadInfo( @@ -155,6 +157,7 @@ public: U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID &destFolderId = LLUUID::null, bool show_inventory = true); virtual LLSD prepareUpload(); @@ -191,6 +194,7 @@ public: U32 groupPerms, U32 everyonePerms, S32 expectedCost, + const LLUUID& destFolderId, // use null for default bool show_inventory, uploadFinish_f finish, uploadFailure_f failure); @@ -217,6 +221,7 @@ public: typedef std::function taskUploadFinish_f; typedef std::function uploadFailed_f; + // destFolderId is the folder to put the new item in, leave null for default LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed); LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer image, invnUploadFinish_f finish); LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 2fd75498d2..c312cadafe 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -478,13 +478,19 @@ const bool check_file_extension(const std::string& filename, LLFilePicker::ELoad return true; } -const void upload_single_file(const std::vector& filenames, LLFilePicker::ELoadFilter type) +void upload_single_file( + const std::vector& filenames, + LLFilePicker::ELoadFilter type, + const LLUUID& dest) { std::string filename = filenames[0]; if (!check_file_extension(filename, type)) return; if (!filename.empty()) { + LLSD args; + args["filename"] = filename; + args["dest"] = dest; if (type == LLFilePicker::FFLOAD_WAV) { // pre-qualify wavs to make sure the format is acceptable @@ -499,12 +505,12 @@ const void upload_single_file(const std::vector& filenames, LLFileP } else { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); + LLFloaterReg::showInstance("upload_sound", args); } } if (type == LLFilePicker::FFLOAD_IMAGE) { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); + LLFloaterReg::showInstance("upload_image", args); } if (type == LLFilePicker::FFLOAD_ANIM) { @@ -512,18 +518,22 @@ const void upload_single_file(const std::vector& filenames, LLFileP LLStringUtil::toLower(filename_lc); if (filename_lc.rfind(".anim") != std::string::npos) { - LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); + LLFloaterReg::showInstance("upload_anim_anim", args); } else { - LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); + LLFloaterReg::showInstance("upload_anim_bvh", args); } } } return; } -void do_bulk_upload(std::vector filenames, const LLSD& notification, const LLSD& response) +void do_bulk_upload( + std::vector filenames, + const LLSD& notification, + const LLSD& response, + const LLUUID& dest) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option != 0) @@ -558,7 +568,8 @@ void do_bulk_upload(std::vector filenames, const LLSD& notification LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - expected_upload_cost)); + expected_upload_cost, + dest)); upload_new_resource(uploadInfo); } @@ -576,7 +587,7 @@ void do_bulk_upload(std::vector filenames, const LLSD& notification // Todo: // 1. Decouple bulk upload from material editor // 2. Take into account possiblity of identical textures - LLMaterialEditor::uploadMaterialFromModel(filename, model, i); + LLMaterialEditor::uploadMaterialFromModel(filename, model, i, dest); } } } @@ -657,7 +668,10 @@ bool get_bulk_upload_expected_cost(const std::vector& filenames, S3 return file_count > 0; } -const void upload_bulk(const std::vector& filenames, LLFilePicker::ELoadFilter type) +void upload_bulk( + const std::vector& filenames, + LLFilePicker::ELoadFilter type, + const LLUUID& dest) { // TODO: // Check user balance for entire cost @@ -688,7 +702,7 @@ const void upload_bulk(const std::vector& filenames, LLFilePicker:: LLSD args; args["COST"] = expected_upload_cost; args["COUNT"] = expected_upload_count; - LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2)); + LLNotificationsUtil::add("BulkUploadCostConfirmation", args, LLSD(), boost::bind(do_bulk_upload, filtered_filenames, _1, _2, dest)); if (filtered_filenames.size() > expected_upload_count) { @@ -721,7 +735,7 @@ class LLFileUploadImage : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_IMAGE, false); return true; } }; @@ -752,7 +766,7 @@ class LLFileUploadSound : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_WAV, false); return true; } }; @@ -765,7 +779,7 @@ class LLFileUploadAnim : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_ANIM, false); return true; } }; @@ -778,7 +792,7 @@ class LLFileUploadBulk : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2, LLUUID::null), LLFilePicker::FFLOAD_ALL, true); return true; } }; @@ -1066,7 +1080,7 @@ LLUUID upload_new_resource( name, desc, compression_info, destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms, - expected_upload_cost, show_inventory)); + expected_upload_cost, LLUUID::null, show_inventory)); upload_new_resource(uploadInfo, callback, userdata); return LLUUID::null; diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 1acb701d50..f58b7b42c1 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -72,6 +72,16 @@ void assign_defaults_and_show_upload_message( const std::string& display_name, std::string& description); +void upload_single_file( + const std::vector& filenames, + LLFilePicker::ELoadFilter type, + const LLUUID& dest); + +void upload_bulk( + const std::vector& filenames, + LLFilePicker::ELoadFilter type, + const LLUUID& dest); + //consider moving all file pickers below to more suitable place class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) 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..ef9e26d8be 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -486,6 +486,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parameter="def_texture" /> - + - + - + - + Date: Wed, 26 Jun 2024 14:48:02 +0300 Subject: viewer#1005 Review fixes --- indra/newview/llappearancemgr.cpp | 4 ++-- indra/newview/llappearancemgr.h | 2 +- indra/newview/llfloaterinventorysettings.cpp | 9 +++++++-- indra/newview/llinventoryfunctions.cpp | 8 ++++---- indra/newview/llinventoryfunctions.h | 3 --- .../skins/default/xui/en/menu_gallery_inventory.xml | 16 ---------------- 6 files changed, 14 insertions(+), 28 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 5971799ca5..fe567f8d1a 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2042,7 +2042,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) } // Moved from LLWearableList::ContextMenu for wider utility. -bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismarch) const +bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch) const { // TODO: investigate wearables may not be loaded at this point EXT-8231 @@ -2072,7 +2072,7 @@ bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids, bool warn_on_t } else { - if (warn_on_type_mismarch) + if (warn_on_type_mismatch) { LL_WARNS() << "Unexpected wearable type" << LL_ENDL; } diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index c2affc766f..51ac6522fa 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -102,7 +102,7 @@ public: bool getCanReplaceCOF(const LLUUID& outfit_cat_id); // Can we add all referenced items to the avatar? - bool canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismarch = true) const; + bool canAddWearables(const uuid_vec_t& item_ids, bool warn_on_type_mismatch = true) const; // Copy all items in a category. void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, diff --git a/indra/newview/llfloaterinventorysettings.cpp b/indra/newview/llfloaterinventorysettings.cpp index 612953b6df..62f76207a3 100644 --- a/indra/newview/llfloaterinventorysettings.cpp +++ b/indra/newview/llfloaterinventorysettings.cpp @@ -29,6 +29,7 @@ #include "llfloaterinventorysettings.h" #include "llcolorswatch.h" +#include "llviewercontrol.h" LLFloaterInventorySettings::LLFloaterInventorySettings(const LLSD& key) : LLFloater(key) @@ -43,13 +44,17 @@ LLFloaterInventorySettings::~LLFloaterInventorySettings() BOOL LLFloaterInventorySettings::postBuild() { getChild("favorites_color")->setCommitCallback(boost::bind(&LLFloaterInventorySettings::updateColorSwatch, this)); + + bool enable_color = gSavedSettings.getBOOL("InventoryFavoritesColorText"); + getChild("favorites_swatch")->setEnabled(enable_color); + return TRUE; } void LLFloaterInventorySettings::updateColorSwatch() { - bool val = getChild("favorites_color")->getEnabled(); - getChild("favorites_color")->setEnabled(val); + bool val = getChild("favorites_color")->getValue(); + getChild("favorites_swatch")->setEnabled(val); } void LLFloaterInventorySettings::applyUIColor(LLUICtrl* ctrl, const LLSD& param) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 4fbd8856b9..28d79b7665 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2514,12 +2514,12 @@ void set_favorite(const LLUUID& obj_id, bool favorite) if (obj && obj->getIsLinkType()) { - obj = gInventory.getObject(obj_id); + obj = gInventory.getObject(obj->getLinkedUUID()); } if (obj && obj->getIsFavorite() != favorite) { - favorite_send(obj, obj_id, favorite); + favorite_send(obj, obj->getUUID(), favorite); } } @@ -2528,12 +2528,12 @@ void toggle_favorite(const LLUUID& obj_id) LLInventoryObject* obj = gInventory.getObject(obj_id); if (obj && obj->getIsLinkType()) { - obj = gInventory.getObject(obj_id); + obj = gInventory.getObject(obj->getLinkedUUID()); } if (obj) { - favorite_send(obj, obj_id, !obj->getIsFavorite()); + favorite_send(obj, obj->getUUID(), !obj->getIsFavorite()); } } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 2df9a11290..0eabf696ae 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -331,9 +331,6 @@ protected: //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFavoritesCollector -// -// Simple class that collects calling cards that are not null, and not -// the agent. Duplicates are possible. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLFavoritesCollector : public LLInventoryCollectFunctor { 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 11c9988dd6..929c626947 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -125,22 +125,6 @@ function="Inventory.DoToSelected" parameter="thumbnail" /> - - - - - - Date: Wed, 3 Jul 2024 13:00:32 +0300 Subject: viewer#1300 Small 'favorites' improvement --- indra/newview/llinventoryfunctions.cpp | 32 ++++++++++++++++++++++++++------ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llpanelwearing.cpp | 2 +- indra/newview/llwearableitemslist.cpp | 2 +- 4 files changed, 29 insertions(+), 8 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index ca27ea8b3f..eac5661847 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2458,12 +2458,6 @@ private: void favorite_send(LLInventoryObject* obj, const LLUUID& obj_id, bool favorite) { - LLSD val; - if (favorite) - { - val = true; - } // else leave undefined to remove unneeded metadata field - LLSD updates; if (favorite) { @@ -2517,6 +2511,13 @@ void set_favorite(const LLUUID& obj_id, bool favorite) if (obj && obj->getIsLinkType()) { + if (!favorite && obj->getIsFavorite()) + { + // Links currently aren't supposed to be favorites, + // instead should show state of the original + LL_INFOS("Inventory") << "Recovering proper 'favorites' state of a link " << obj_id << LL_ENDL; + favorite_send(obj, obj_id, false); + } obj = gInventory.getObject(obj->getLinkedUUID()); } @@ -2540,6 +2541,25 @@ void toggle_favorite(const LLUUID& obj_id) } } +void toggle_favorites(const uuid_vec_t& ids) +{ + if (ids.size() == 0) + { + return; + } + if (ids.size() == 1) + { + toggle_favorite(ids[0]); + return; + } + + bool new_val = !get_is_favorite(ids.front()); + for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + set_favorite(*it, new_val); + } +} + std::string get_searchable_description(LLInventoryModel* model, const LLUUID& item_id) { if (model) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index fdb6fc77d7..f2fa7b3fe5 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -120,6 +120,7 @@ bool get_is_favorite(const LLInventoryObject* object); bool get_is_favorite(const LLUUID& obj_id); void set_favorite(const LLUUID& obj_id, bool favorite); void toggle_favorite(const LLUUID& obj_id); +void toggle_favorites(const uuid_vec_t& ids); 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/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index be8321e7bc..79b40e392a 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -113,7 +113,7 @@ protected: boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); registrar.add("Wearing.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op)); - registrar.add("Wearing.Favorite", boost::bind(toggle_favorite, mUUIDs.front())); + registrar.add("Wearing.Favorite", boost::bind(toggle_favorites, mUUIDs)); LLContextMenu* menu = createFromFile("menu_wearing_tab.xml"); updateMenuItemsVisibility(menu); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 3ddd0c30ea..982e397748 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -936,7 +936,7 @@ LLContextMenu* LLWearableItemsList::ContextMenu::createMenu() // Register handlers for attachments. registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), ids, no_op)); - registrar.add("Attachment.Favorite", boost::bind(toggle_favorite, selected_id)); + registrar.add("Attachment.Favorite", boost::bind(toggle_favorites, ids)); registrar.add("Attachment.Touch", boost::bind(handle_attachment_touch, selected_id)); registrar.add("Attachment.Profile", boost::bind(show_item_profile, selected_id)); registrar.add("Object.Attach", boost::bind(LLViewerAttachMenu::attachObjects, ids, _2)); -- cgit v1.3 From b95b20a1be56ff7baa3ad20e8d0571ec9f07ab12 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 8 Apr 2025 20:28:50 +0300 Subject: #3757 Allow subfolders in "My Outfits" --- indra/newview/llappearancelistener.cpp | 2 +- indra/newview/llinventorybridge.cpp | 45 +++++++++++++++++++-- indra/newview/llinventorybridge.h | 1 + indra/newview/llinventoryfunctions.cpp | 5 +++ indra/newview/llinventoryfunctions.h | 18 +++++++++ indra/newview/llinventorygallery.cpp | 13 ++++++ indra/newview/llinventorygallerymenu.cpp | 1 + indra/newview/lloutfitslist.cpp | 47 +++++++++++++++++++++- .../skins/default/xui/en/menu_inventory.xml | 8 ++++ 9 files changed, 134 insertions(+), 6 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp index a6d6e76e02..dc7bbc3236 100644 --- a/indra/newview/llappearancelistener.cpp +++ b/indra/newview/llappearancelistener.cpp @@ -122,7 +122,7 @@ void LLAppearanceListener::getOutfitsList(LLSD const &data) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - LLIsType is_category(LLAssetType::AT_CATEGORY); + LLIsFolderType is_category(LLFolderType::FT_OUTFIT); gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); response["outfits"] = llsd::toMap(cat_array, diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ce91f9a1f3..8d31c4dde7 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2916,6 +2916,10 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // create a new folder and populate it with links to original objects dropToMyOutfits(inv_cat, cb); } + else if (getCategory() && getCategory()->getParentUUID() == my_outifts_id) + { + dropToMyOutfitsSubfolder(inv_cat, mUUID, cb); + } // if target is current outfit folder we use link else if (move_is_into_current_outfit && (inv_cat->getPreferredType() == LLFolderType::FT_NONE || @@ -4016,7 +4020,14 @@ void LLFolderBridge::perform_pasteFromClipboard() U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear)) { - dropToMyOutfits(cat, cb); + if (mUUID == my_outifts_id) + { + dropToMyOutfits(cat, cb); + } + else if (getCategory() && getCategory()->getParentUUID() == mUUID) + { + dropToMyOutfitsSubfolder(cat, mUUID, cb); + } } else { @@ -4256,6 +4267,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (outfits_id == mUUID) { + items.push_back(std::string("New Outfit Folder")); items.push_back(std::string("New Outfit")); } @@ -5331,13 +5343,36 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointergetUUID(), _1, cb, mInventoryPanel); - gInventory.createNewCategory(dest_id, + getInventoryModel()->createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } +void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLPointer cb) +{ + LLViewerInventoryCategory* cat = getInventoryModel()->getCategory(dest_id); + const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); + if (cat && cat->getParentUUID() == outfits_id) + { + getInventoryModel()->createNewCategory(dest_id, + LLFolderType::FT_OUTFIT, + inv_cat->getName(), + func, + inv_cat->getThumbnailUUID()); + } + else + { + getInventoryModel()->createNewCategory(outfits_id, + LLFolderType::FT_OUTFIT, + inv_cat->getName(), + func, + inv_cat->getThumbnailUUID()); + } +} + void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, LLUUID cat_dest_id, LLPointer cb, @@ -5441,6 +5476,10 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const bool move_is_into_favorites = (mUUID == favorites_id); const bool move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const bool move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const bool move_is_into_my_outfits_subfolder = move_is_into_my_outfits + && getCategory() + && getCategory()->getParentUUID() == my_outifts_id + && getCategory()->getPreferredType() != LLFolderType::FT_OUTFIT; const bool move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); const bool move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const bool move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id); @@ -5511,7 +5550,7 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit)) { - accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); + accept = !move_is_into_my_outfits_subfolder && can_move_to_outfit(inv_item, move_is_into_current_outfit); } else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks)) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3e7f74384b..b7bdef9b21 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -369,6 +369,7 @@ protected: void dropToFavorites(LLInventoryItem* inv_item, LLPointer cb = NULL); void dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer cb = NULL); void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer cb = NULL); + void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLPointer cb = NULL); //-------------------------------------------------------------------- // Messy hacks for handling folder options diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 1ccefa3212..b4299972d9 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2621,6 +2621,11 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryIte return false; } +bool LLIsFolderType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + return cat && cat->getPreferredType() == mType; +} + bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 13a64f21dc..b379d625a9 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -234,6 +234,24 @@ protected: // the type is the type passed in during construction. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLIsFolderType : public LLInventoryCollectFunctor +{ +public: + LLIsFolderType(LLFolderType::EType type) : mType(type) {} + virtual ~LLIsFolderType() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + LLFolderType::EType mType; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsType +// +// Implementation of a LLInventoryCollectFunctor which returns true if +// the type is the type passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + class LLIsType : public LLInventoryCollectFunctor { public: diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index c4f93cee98..6188b812d5 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -64,6 +64,7 @@ const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value imm bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link); bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm); void dropToMyOutfits(LLInventoryCategory* inv_cat); +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id); class LLGalleryPanel: public LLPanel { @@ -3898,6 +3899,10 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, // create a new folder and populate it with links to original objects dropToMyOutfits(inv_cat); } + else if (dest_cat && dest_cat->getParentUUID() == my_outifts_id) + { + dropToMyOutfitsSubfolder(inv_cat, dest_id); + } // if target is current outfit folder we use link else if (move_is_into_current_outfit && (inv_cat->getPreferredType() == LLFolderType::FT_NONE || @@ -4041,3 +4046,11 @@ void dropToMyOutfits(LLInventoryCategory* inv_cat) inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1); gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } + +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id) +{ + // Note: creation will take time, so passing folder id to callback is slightly unreliable, + // but so is collecting and passing descendants' ids + inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1); + gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); +} diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index dbf4821ca1..25b339d51e 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -771,6 +771,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men if(is_outfits && !isRootFolder()) { + items.push_back(std::string("New Outfit Folder")); items.push_back(std::string("New Outfit")); } diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 6e666b8a4b..cfbfe8f8e0 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -819,6 +819,49 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id) refreshList(category_id); } +class LLIsOutfitListFolder : public LLInventoryCollectFunctor +{ +public: + LLIsOutfitListFolder() + { + mOutfitsId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + } + virtual ~LLIsOutfitListFolder() {} + + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + if (cat) + { + if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return true; + } + if (cat->getPreferredType() == LLFolderType::FT_NONE + && cat->getParentUUID() == mOutfitsId) + { + LLViewerInventoryCategory* inv_cat = dynamic_cast(cat); + if (inv_cat && inv_cat->getDescendentCount() > 3) + { + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + if (items->size() > 3) // eyes, skin, hair and shape are required + { + // For now assume this to be an old style outfit, not a subfolder + // but ideally no such 'outfits' should be left in My Outfits + // Todo: stop counting FT_NONE as outfits, + // convert obvious outfits into FT_OUTFIT + return true; + } + } + } + } + return false; + } +protected: + LLUUID mOutfitsId; +}; + void LLOutfitListBase::refreshList(const LLUUID& category_id) { bool wasNull = mRefreshListState.CategoryUUID.isNull(); @@ -828,13 +871,13 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) LLInventoryModel::item_array_t item_array; // Collect all sub-categories of a given category. - LLIsType is_category(LLAssetType::AT_CATEGORY); + LLIsOutfitListFolder is_outfit; gInventory.collectDescendentsIf( category_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_category); + is_outfit); // Memorize item names for each UUID std::map names; diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index e57e3b0750..d8c7de0e55 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -151,6 +151,14 @@ function="Inventory.DoCreate" parameter="category" /> + + + Date: Wed, 9 Apr 2025 21:35:40 +0300 Subject: #3757 Menu for subfodlers in outfits p2 --- indra/newview/llinventorybridge.cpp | 90 +++++++++----------------- indra/newview/llinventoryfunctions.cpp | 30 +++++++++ indra/newview/llinventoryfunctions.h | 11 ++++ indra/newview/llinventorygallery.cpp | 65 +++++++------------ indra/newview/llinventorygallerymenu.cpp | 16 ++++- indra/newview/skins/default/xui/en/strings.xml | 1 + 6 files changed, 109 insertions(+), 104 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index fd9d08a26d..2c1c6d22a6 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -104,45 +104,6 @@ static bool check_item(const LLUUID& item_id, LLInventoryFilter* filter); // Helper functions - - -namespace { - enum EMyOutfitsSubfolderType - { - MY_OUTFITS_NO, - MY_OUTFITS_SUBFOLDER, - MY_OUTFITS_OUTFIT, - }; - - EMyOutfitsSubfolderType myoutfit_object_subfolder_type(LLInventoryModel* model, const LLUUID& obj_id, - const LLUUID& cat_id) - { - if (obj_id == cat_id) return MY_OUTFITS_NO; - - const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); - while (test_cat) - { - if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) - { - return MY_OUTFITS_OUTFIT; - } - - const LLUUID& parent_id = test_cat->getParentUUID(); - if (parent_id.isNull()) - { - return MY_OUTFITS_NO; - } - if (parent_id == cat_id) - { - return MY_OUTFITS_SUBFOLDER; - } - test_cat = model->getCategory(parent_id); - } - - return MY_OUTFITS_NO; - } -} - bool isAddAction(const std::string& action) { return ("wear" == action || "attach" == action || "activate" == action); @@ -2735,7 +2696,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); if (is_movable && move_is_into_outfit) { - if (mUUID == my_outifts_id) + if ((inv_cat->getPreferredType() != LLFolderType::FT_NONE) && (inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT)) + { + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + is_movable = false; + } + else if (mUUID == my_outifts_id) { if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings) { @@ -2752,13 +2718,28 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = false; } } - else if(getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE) + else if (!getCategory()) { - is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } else { - is_movable = false; + LLFolderType::EType type = getCategory()->getPreferredType(); + if (type == LLFolderType::FT_OUTFIT && inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); + } + else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + } + else + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } } } if (is_movable && move_is_into_current_outfit && is_link) @@ -2964,6 +2945,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else { + // or link it? dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); } } @@ -5435,25 +5417,13 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer cb) { - LLViewerInventoryCategory* cat = getInventoryModel()->getCategory(dest_id); const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); - if (cat && cat->getParentUUID() == outfits_id) - { - getInventoryModel()->createNewCategory(dest_id, - preferred_type, - inv_cat->getName(), - func, - inv_cat->getThumbnailUUID()); - } - else - { - getInventoryModel()->createNewCategory(outfits_id, - preferred_type, - inv_cat->getName(), - func, - inv_cat->getThumbnailUUID()); - } + getInventoryModel()->createNewCategory(dest_id, + preferred_type, + inv_cat->getName(), + func, + inv_cat->getThumbnailUUID()); } void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id, diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index b4299972d9..dc69e0c92e 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2493,6 +2493,36 @@ bool can_share_item(const LLUUID& item_id) return can_share; } + +EMyOutfitsSubfolderType myoutfit_object_subfolder_type( + LLInventoryModel* model, + const LLUUID& obj_id, + const LLUUID& my_outfits_id) +{ + if (obj_id == my_outfits_id) return MY_OUTFITS_NO; + + const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); + while (test_cat) + { + if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return MY_OUTFITS_OUTFIT; + } + + const LLUUID& parent_id = test_cat->getParentUUID(); + if (parent_id.isNull()) + { + return MY_OUTFITS_NO; + } + if (parent_id == my_outfits_id) + { + return MY_OUTFITS_SUBFOLDER; + } + test_cat = model->getCategory(parent_id); + } + + return MY_OUTFITS_NO; +} ///---------------------------------------------------------------------------- /// LLMarketplaceValidator implementations ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index b379d625a9..eb3503c5b0 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -121,6 +121,17 @@ std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& i std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id); bool can_share_item(const LLUUID& item_id); +enum EMyOutfitsSubfolderType +{ + MY_OUTFITS_NO, + MY_OUTFITS_SUBFOLDER, + MY_OUTFITS_OUTFIT, +}; +EMyOutfitsSubfolderType myoutfit_object_subfolder_type( + LLInventoryModel* model, + const LLUUID& obj_id, + const LLUUID& my_outfits_id); + /** Miscellaneous global functions ** ** *******************************************************************************/ diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 15bc578c64..d640e04915 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -61,43 +61,6 @@ const S32 GALLERY_ITEMS_PER_ROW_MIN = 2; const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value immediately -namespace { - enum EMyOutfitsSubfolderType - { - MY_OUTFITS_NO, - MY_OUTFITS_SUBFOLDER, - MY_OUTFITS_OUTFIT, - }; - - EMyOutfitsSubfolderType myoutfit_object_subfolder_type(LLInventoryModel* model, const LLUUID& obj_id, - const LLUUID& cat_id) - { - if (obj_id == cat_id) return MY_OUTFITS_NO; - - const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); - while (test_cat) - { - if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) - { - return MY_OUTFITS_OUTFIT; - } - - const LLUUID& parent_id = test_cat->getParentUUID(); - if (parent_id.isNull()) - { - return MY_OUTFITS_NO; - } - if (parent_id == cat_id) - { - return MY_OUTFITS_SUBFOLDER; - } - test_cat = model->getCategory(parent_id); - } - - return MY_OUTFITS_NO; - } -} - // Helper dnd functions bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link); bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm); @@ -3784,7 +3747,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); if (is_movable && move_is_into_outfit) { - if (dest_id == my_outifts_id) + if ((inv_cat->getPreferredType() != LLFolderType::FT_NONE) && (inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT)) + { + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + is_movable = false; + } + else if (dest_id == my_outifts_id) { if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings) { @@ -3801,13 +3769,28 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, is_movable = false; } } - else if (dest_cat && dest_cat->getPreferredType() == LLFolderType::FT_NONE) + else if (!dest_cat) { - is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } else { - is_movable = false; + LLFolderType::EType type = dest_cat->getPreferredType(); + if (type == LLFolderType::FT_OUTFIT && inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); + } + else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + } + else + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } } } if (is_movable && move_is_into_current_outfit && is_link) diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 3ef5071c97..68af0cb581 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -771,14 +771,24 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("upload_def")); } - if(is_outfits && !isRootFolder()) + if(is_outfits) { + EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(&gInventory, selected_id, my_outfits); + if (res == MY_OUTFITS_OUTFIT) + { + items.push_back(std::string("New Outfit")); + } items.push_back(std::string("New Outfit Folder")); - items.push_back(std::string("New Outfit")); + items.push_back(std::string("Delete")); + items.push_back(std::string("Rename")); + if (!get_is_category_and_children_removable(&gInventory, selected_id, false)) + { + disabled_items.push_back(std::string("Delete")); + } } items.push_back(std::string("Subfolder Separator")); - if (!is_system_folder && !isRootFolder()) + if (!is_system_folder && !isRootFolder() && !is_outfits) { if(has_children && (folder_type != LLFolderType::FT_OUTFIT) && !is_in_outfits) { diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index d909a95b83..7361ad5245 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -258,6 +258,7 @@ If you feel this is an error, please contact support@secondlife.com All items in a stock folder must have the same type and permission You can only put items or outfits from your personal inventory into "My outfits" One or more items can't be used inside "My outfits" + Can not move an outfit into another outfit You can't move a folder into its child You can't move a folder into itself -- cgit v1.3 From 7dce74fcfb9ca9e6c152eaf33392ff79412ff555 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 10 Apr 2025 22:39:04 +0300 Subject: #3757 Move for subfodlers --- indra/newview/llinventorybridge.cpp | 93 +++++++++++++++++++++++++++----- indra/newview/llinventoryfunctions.cpp | 6 ++- indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallery.cpp | 85 ++++++++++++++++++++++++----- indra/newview/llinventorygallerymenu.cpp | 2 +- 5 files changed, 158 insertions(+), 29 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 2c1c6d22a6..5bd17d4d5b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2725,12 +2725,23 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else { - LLFolderType::EType type = getCategory()->getPreferredType(); - if (type == LLFolderType::FT_OUTFIT && inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_OUTFIT) { is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); } + else if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_SUBFOLDER) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } + else if (dest_res == MY_OUTFITS_SUBFOLDER && inv_res == MY_OUTFITS_SUBOUTFIT) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) { is_movable = true; @@ -2931,22 +2942,76 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (mUUID == my_outifts_id) { - // Category can't contains objects, - // create a new folder and populate it with links to original objects - dropToMyOutfits(inv_cat, cb); - } - else if (move_is_into_my_outfits) - { - EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); - if (res == MY_OUTFITS_SUBFOLDER) + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) { - // turn it into outfit - dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + false); + if (cb) cb->fire(inv_cat->getUUID()); } else { - // or link it? - dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); + // Moving from inventory + // create a new folder and populate it with links to original objects + dropToMyOutfits(inv_cat, cb); + } + } + else if (move_is_into_my_outfits) + { + EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + switch (inv_res) + { + case MY_OUTFITS_NO: + // Moning from outside outfits into outfits + if (dest_res == MY_OUTFITS_SUBFOLDER) + { + // turn it into outfit + dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); + } + else + { + // or link it? + dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); + } + break; + case MY_OUTFITS_SUBFOLDER: + case MY_OUTFITS_OUTFIT: + // only permit moving subfodlers and outfits into other subfolders + if (dest_res == MY_OUTFITS_SUBFOLDER) + { + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + false); + if (cb) cb->fire(inv_cat->getUUID()); + } + else + { + assert(false); // mot permitted, shouldn't have accepted + } + break; + case MY_OUTFITS_SUBOUTFIT: + if (dest_res == MY_OUTFITS_SUBOUTFIT || dest_res == MY_OUTFITS_OUTFIT) + { + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + false); + if (cb) cb->fire(inv_cat->getUUID()); + } + else + { + assert(false); // mot permitted, shouldn't have accepted + } + break; + default: + break; } } // if target is current outfit folder we use link diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index dc69e0c92e..7fff88fba7 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2502,11 +2502,15 @@ EMyOutfitsSubfolderType myoutfit_object_subfolder_type( if (obj_id == my_outfits_id) return MY_OUTFITS_NO; const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); + if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + return MY_OUTFITS_OUTFIT; + } while (test_cat) { if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) { - return MY_OUTFITS_OUTFIT; + return MY_OUTFITS_SUBOUTFIT; } const LLUUID& parent_id = test_cat->getParentUUID(); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index eb3503c5b0..0ab045f2a0 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -126,6 +126,7 @@ enum EMyOutfitsSubfolderType MY_OUTFITS_NO, MY_OUTFITS_SUBFOLDER, MY_OUTFITS_OUTFIT, + MY_OUTFITS_SUBOUTFIT, }; EMyOutfitsSubfolderType myoutfit_object_subfolder_type( LLInventoryModel* model, diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index d640e04915..713d87787e 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -3776,12 +3776,23 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, } else { - LLFolderType::EType type = dest_cat->getPreferredType(); - if (type == LLFolderType::FT_OUTFIT && inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT) + EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_OUTFIT) { is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); } + else if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_SUBFOLDER) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } + else if (dest_res == MY_OUTFITS_SUBFOLDER && inv_res == MY_OUTFITS_SUBOUTFIT) + { + is_movable = false; + tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); + } else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) { is_movable = true; @@ -3916,21 +3927,69 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, if (dest_id == my_outifts_id) { - // Category can contains objects, - // create a new folder and populate it with links to original objects - dropToMyOutfits(inv_cat); - } - else if (move_is_into_my_outfits) - { - EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); - if (res == MY_OUTFITS_SUBFOLDER) + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) { - // turn it into outfit - dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); + gInventory.changeCategoryParent( + (LLViewerInventoryCategory*)inv_cat, + dest_id, + move_is_into_trash); } else { - dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE); + // Category can contains objects, + // create a new folder and populate it with links to original objects + dropToMyOutfits(inv_cat); + } + } + else if (move_is_into_my_outfits) + { + EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); + EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); + switch (inv_res) + { + case MY_OUTFITS_NO: + // Moning from outside outfits into outfits + if (dest_res == MY_OUTFITS_SUBFOLDER) + { + // turn it into outfit + dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); + } + else + { + dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE); + } + break; + case MY_OUTFITS_SUBFOLDER: + case MY_OUTFITS_OUTFIT: + // only permit moving subfodlers and outfits into other subfolders + if (dest_res == MY_OUTFITS_SUBFOLDER) + { + gInventory.changeCategoryParent( + (LLViewerInventoryCategory*)inv_cat, + dest_id, + move_is_into_trash); + } + else + { + assert(false); // mot permitted, shouldn't have accepted + } + break; + case MY_OUTFITS_SUBOUTFIT: + if (dest_res == MY_OUTFITS_SUBOUTFIT || dest_res == MY_OUTFITS_OUTFIT) + { + gInventory.changeCategoryParent( + (LLViewerInventoryCategory*)inv_cat, + dest_id, + move_is_into_trash); + } + else + { + assert(false); // mot permitted, shouldn't have accepted + } + break; + default: + break; } } // if target is current outfit folder we use link diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 68af0cb581..7acd3b90a2 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -774,7 +774,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men if(is_outfits) { EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(&gInventory, selected_id, my_outfits); - if (res == MY_OUTFITS_OUTFIT) + if (res != MY_OUTFITS_OUTFIT && res != MY_OUTFITS_SUBOUTFIT) { items.push_back(std::string("New Outfit")); } -- cgit v1.3 From 3142429fd4b3977e36d7ab7b0605470936b32b09 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 15 Apr 2025 22:37:19 +0300 Subject: #3910 Sometimes can't favorite a folder due to version mismatch. Should use LLInventoryModel::changeItemParent --- indra/llui/llfolderviewitem.cpp | 2 +- indra/newview/llinventoryfunctions.cpp | 24 ++++++------------------ 2 files changed, 7 insertions(+), 19 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 879dd270ce..d624d950da 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1908,7 +1908,7 @@ void LLFolderViewFolder::onIdleUpdateFavorites(void* data) } else { - LL_WARNS() << "FAVORITE_ADDED for a folder without favorites" << LL_ENDL; + // already up to date self->mFavoritesDirtyFlags = 0; gIdleCallbacks.deleteFunction(&LLFolderViewFolder::onIdleUpdateFavorites, self); } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 22ee036a6d..a2626daa2e 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2150,21 +2150,10 @@ void validate_marketplacelistings( void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) { - LLInventoryItem* inv_item = gInventory.getItem(item_id); + LLViewerInventoryItem* inv_item = gInventory.getItem(item_id); if (inv_item) { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(inv_item); - new_item->setParent(new_parent_id); - new_item->updateParentOnServer(false); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); + gInventory.changeItemParent(inv_item, new_parent_id, false); } } @@ -2172,17 +2161,17 @@ void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected { for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it) { - LLInventoryItem* inv_item = gInventory.getItem(*it); + LLViewerInventoryItem* inv_item = gInventory.getItem(*it); if (inv_item) { - change_item_parent(*it, new_cat_uuid); + gInventory.changeItemParent(inv_item, new_cat_uuid, false); } else { - LLInventoryCategory* inv_cat = gInventory.getCategory(*it); + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); if (inv_cat && !LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) { - gInventory.changeCategoryParent((LLViewerInventoryCategory*)inv_cat, new_cat_uuid, false); + gInventory.changeCategoryParent(inv_cat, new_cat_uuid, false); } } } @@ -3577,7 +3566,6 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root } else if ("new_folder_from_selected" == action) { - LLInventoryObject* first_item = gInventory.getObject(*ids.begin()); if (!first_item) { -- cgit v1.3 From 37134720bce619a754ff097aff764d9a44bb0893 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 May 2025 22:29:08 +0300 Subject: #3757 Smarter subfolders dragndrop --- indra/newview/llinventorybridge.cpp | 38 ++++++++++++++++++++++++------- indra/newview/llinventoryfunctions.cpp | 41 +++++++++++++++++++++++++++++++++- indra/newview/llinventoryfunctions.h | 3 ++- indra/newview/llinventorygallery.cpp | 19 ++++++++++++---- 4 files changed, 87 insertions(+), 14 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 4018a89c5a..bff7138282 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2664,6 +2664,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // bool is_movable = true; + bool create_outfit = false; if (is_movable && (marketplacelistings_id == cat_id)) { @@ -2708,7 +2709,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory"); is_movable = false; } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -2742,7 +2748,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -2943,7 +2954,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (mUUID == my_outifts_id) { EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); - if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit) { LLInvFVBridge::changeCategoryParent( model, @@ -2967,7 +2978,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, { case MY_OUTFITS_NO: // Moning from outside outfits into outfits - if (dest_res == MY_OUTFITS_SUBFOLDER) + if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); @@ -4094,7 +4105,6 @@ void LLFolderBridge::perform_pasteFromClipboard() LLInventoryObject *obj = model->getObject(item_id); if (obj) { - if (move_is_into_lost_and_found) { if (LLAssetType::AT_CATEGORY == obj->getType()) @@ -4111,9 +4121,9 @@ void LLFolderBridge::perform_pasteFromClipboard() } else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType()) { - LLInventoryCategory* cat = model->getCategory(item_id); + LLViewerInventoryCategory* cat = model->getCategory(item_id); U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); - if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear)) + if (cat && can_move_to_my_outfits_as_outfit(model, cat, max_items_to_wear)) { if (mUUID == my_outifts_id) { @@ -4133,6 +4143,18 @@ void LLFolderBridge::perform_pasteFromClipboard() } } } + else if (cat && can_move_to_my_outfits_as_subfolder(model, cat)) + { + if (LLClipboard::instance().isCutMode()) + { + changeCategoryParent(model, cat, parent_id, false); + if (cb) cb->fire(item_id); + } + else + { + copy_inventory_category(model, cat, parent_id); + } + } else { LLNotificationsUtil::add("MyOutfitsPasteFailed"); @@ -4181,7 +4203,7 @@ void LLFolderBridge::perform_pasteFromClipboard() // move_inventory_item() is not enough, as we have to update inventory locally too if (LLAssetType::AT_CATEGORY == obj->getType()) { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); + LLViewerInventoryCategory* vicat = model->getCategory(item_id); llassert(vicat); if (vicat) { diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7fff88fba7..9967318e92 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2314,7 +2314,7 @@ bool can_move_to_landmarks(LLInventoryItem* inv_item) } // Returns true if folder's content can be moved to Current Outfit or any outfit folder. -bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit) +bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit) { LLInventoryModel::cat_array_t *cats; LLInventoryModel::item_array_t *items; @@ -2353,6 +2353,45 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca return true; } +bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + if (items->size() > 0) + { + // subfolders don't allow items + return false; + } + + constexpr size_t MAX_CONTENT = 255; + if (cats->size() > MAX_CONTENT) + { + // don't allow massive folders + return false; + } + + for (LLPointer& cat : *cats) + { + // outfits are valid to move, check non-outfit folders + if (cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + if (depth == 3) + { + // don't allow massive folders + return false; + } + if (!can_move_to_my_outfits_as_subfolder(model, cat, depth + 1)) + { + return false; + } + } + } + + return true; +} + std::string get_localized_folder_name(LLUUID cat_uuid) { std::string localized_root_name; diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 0ab045f2a0..f56413bf5d 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -112,7 +112,8 @@ std::string get_category_path(LLUUID cat_id); bool can_move_to_outfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit); bool can_move_to_landmarks(LLInventoryItem* inv_item); -bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit); +bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit); +bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth = 0); 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); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index eb47af85fd..3222dff1b2 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -3714,6 +3714,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, // bool is_movable = true; + bool create_outfit = false; if (is_movable && (marketplacelistings_id == cat_id)) { @@ -3759,7 +3760,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory"); is_movable = false; } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -3793,7 +3799,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -3928,7 +3939,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, if (dest_id == my_outifts_id) { EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); - if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit) { gInventory.changeCategoryParent( (LLViewerInventoryCategory*)inv_cat, @@ -3950,7 +3961,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, { case MY_OUTFITS_NO: // Moning from outside outfits into outfits - if (dest_res == MY_OUTFITS_SUBFOLDER) + if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); -- cgit v1.3 From e466414be4621906cb4c9cfc5f4a7216ba3670aa Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 12 May 2025 22:07:49 +0300 Subject: #4055 Fix subfolder dragging --- indra/newview/llinventorybridge.cpp | 32 ++++++++++++++++++-------------- indra/newview/llinventorybridge.h | 2 +- indra/newview/llinventoryfunctions.cpp | 25 +++++++++++++++++++++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallery.cpp | 13 ++++++++----- 5 files changed, 53 insertions(+), 20 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index bff7138282..e48fe69853 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2981,12 +2981,16 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit - dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); + dropToMyOutfitsSubfolder(inv_cat, mUUID, cb); } else { - // or link it? - dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + move_is_into_trash); + if (cb) cb->fire(inv_cat->getUUID()); } break; case MY_OUTFITS_SUBFOLDER: @@ -4123,11 +4127,13 @@ void LLFolderBridge::perform_pasteFromClipboard() { LLViewerInventoryCategory* cat = model->getCategory(item_id); U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); + bool handled = false; if (cat && can_move_to_my_outfits_as_outfit(model, cat, max_items_to_wear)) { if (mUUID == my_outifts_id) { dropToMyOutfits(cat, cb); + handled = true; } else if (move_is_into_my_outfits) { @@ -4135,27 +4141,26 @@ void LLFolderBridge::perform_pasteFromClipboard() if (res == MY_OUTFITS_SUBFOLDER) { // turn it into outfit - dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_OUTFIT, cb); - } - else - { - dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_NONE, cb); + dropToMyOutfitsSubfolder(cat, mUUID, cb); + handled = true; } } } - else if (cat && can_move_to_my_outfits_as_subfolder(model, cat)) + if (!handled && cat && can_move_to_my_outfits_as_subfolder(model, cat)) { if (LLClipboard::instance().isCutMode()) { changeCategoryParent(model, cat, parent_id, false); - if (cb) cb->fire(item_id); } else { copy_inventory_category(model, cat, parent_id); } + if (cb) cb->fire(item_id); + handled = true; } - else + + if (!handled) { LLNotificationsUtil::add("MyOutfitsPasteFailed"); } @@ -5500,12 +5505,11 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointergetThumbnailUUID()); } -void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type, LLPointer cb) +void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLPointer cb) { - const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); getInventoryModel()->createNewCategory(dest_id, - preferred_type, + LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a101c7368a..b7bdef9b21 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -369,7 +369,7 @@ protected: void dropToFavorites(LLInventoryItem* inv_item, LLPointer cb = NULL); void dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer cb = NULL); void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer cb = NULL); - void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLFolderType::EType preferred_type, LLPointer cb = NULL); + void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLPointer cb = NULL); //-------------------------------------------------------------------- // Messy hacks for handling folder options diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 9967318e92..3286eca265 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -460,6 +460,25 @@ void copy_inventory_category(LLInventoryModel* model, gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); } +void copy_inventory_category(LLInventoryModel* model, + LLViewerInventoryCategory* cat, + const LLUUID& parent_id, + const LLUUID& root_copy_id, + bool move_no_copy_items, + LLPointer callback) +{ + // Create the initial folder + inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID& new_id) + { + copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items); + if (callback) + { + callback.get()->fire(new_id); + } + }; + gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); +} + void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) { // Decrement the count in root_id since that one item won't be copied over @@ -2365,6 +2384,12 @@ bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCat return false; } + if (inv_cat->getPreferredType() != LLFolderType::FT_NONE) + { + // only normal folders can become subfodlers + return false; + } + constexpr size_t MAX_CONTENT = 255; if (cats->size() > MAX_CONTENT) { diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index f56413bf5d..b23f82a189 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -78,6 +78,7 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false); void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, inventory_func_type callback); +void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id, bool move_no_copy_items, LLPointer callback); void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 3222dff1b2..43d4edb069 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -65,7 +65,7 @@ const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value imm bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link); bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm); void dropToMyOutfits(LLInventoryCategory* inv_cat); -void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type); +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id); class LLGalleryPanel: public LLPanel { @@ -3964,11 +3964,14 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit - dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); + dropToMyOutfitsSubfolder(inv_cat, dest_id); } else { - dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE); + gInventory.changeCategoryParent( + (LLViewerInventoryCategory*)inv_cat, + dest_id, + move_is_into_trash); } break; case MY_OUTFITS_SUBFOLDER: @@ -4147,10 +4150,10 @@ void dropToMyOutfits(LLInventoryCategory* inv_cat) gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } -void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id, LLFolderType::EType preferred_type) +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id) { // Note: creation will take time, so passing folder id to callback is slightly unreliable, // but so is collecting and passing descendants' ids inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1); - gInventory.createNewCategory(dest_id, preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); + gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); } -- cgit v1.3 From b5db42e26b64952bdc485bd8a0e0731856f03ae9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 15 May 2025 23:08:52 +0300 Subject: #4088 Fix Outfit folders changing to normal folders when parent copied and pasted --- indra/newview/llinventoryfunctions.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 3286eca265..1077ce74ae 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -438,7 +438,13 @@ void copy_inventory_category(LLInventoryModel* model, { copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items); }; - gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); + LLFolderType::EType type = LLFolderType::FT_NONE; + if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) + { + // at the moment only permitting copy of outfits and normal folders + type = LLFolderType::FT_OUTFIT; + } + gInventory.createNewCategory(parent_id, type, cat->getName(), func, cat->getThumbnailUUID()); } void copy_inventory_category(LLInventoryModel* model, -- cgit v1.3 From 2df00437d1525a7c09c4178a755eec923a077558 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 23 May 2025 20:00:10 +0300 Subject: #4149 Empty Outfit folders cannot be moved --- indra/newview/llinventoryfunctions.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 1077ce74ae..d2ed7168c5 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2350,9 +2350,9 @@ bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCatego return false; } - if (items->size() == 0) + if (items->size() == 0 && inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - // Nothing to move(create) + // Nothing to create an outfit folder from return false; } -- cgit v1.3 From 4bc20a8e536fddf5e48e5d963a39e3dae0fb733f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 26 Jun 2025 23:31:21 +0300 Subject: #4184 clearAndDeparentModels crash To resolve dual ownership switched children to LLPointer --- indra/llui/llfolderviewmodel.h | 67 ++++++++++++++-------------- indra/newview/llconversationmodel.cpp | 20 ++++----- indra/newview/llfloaterchatmentionpicker.cpp | 2 +- indra/newview/llfloaterimcontainer.cpp | 6 +-- indra/newview/llfloaterimsessiontab.cpp | 45 +------------------ indra/newview/llinventoryfunctions.cpp | 10 +++-- 6 files changed, 54 insertions(+), 96 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index ba9d0b8de3..2865b789b9 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -224,6 +224,7 @@ public: virtual S32 getSortVersion() = 0; virtual void setSortVersion(S32 version) = 0; virtual void setParent(LLFolderViewModelItem* parent) = 0; + virtual const LLFolderViewModelItem* getParent() = 0; virtual bool hasParent() = 0; protected: @@ -254,14 +255,14 @@ public: mChildren.clear(); } - void requestSort() { mSortVersion = -1; } - S32 getSortVersion() { return mSortVersion; } - void setSortVersion(S32 version) { mSortVersion = version;} + void requestSort() override { mSortVersion = -1; } + S32 getSortVersion() override { return mSortVersion; } + void setSortVersion(S32 version) override { mSortVersion = version;} - S32 getLastFilterGeneration() const { return mLastFilterGeneration; } + S32 getLastFilterGeneration() const override { return mLastFilterGeneration; } S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; } - S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; } - void dirtyFilter() + S32 getMarkedDirtyGeneration() const override { return mMarkedDirtyGeneration; } + void dirtyFilter() override { if(mMarkedDirtyGeneration < 0) { @@ -276,7 +277,7 @@ public: mParent->dirtyFilter(); } } - void dirtyDescendantsFilter() + void dirtyDescendantsFilter() override { mMostFilteredDescendantGeneration = -1; if (mParent) @@ -284,13 +285,13 @@ public: mParent->dirtyDescendantsFilter(); } } - bool hasFilterStringMatch(); - std::string::size_type getFilterStringOffset(); - std::string::size_type getFilterStringSize(); + bool hasFilterStringMatch() override; + std::string::size_type getFilterStringOffset() override; + std::string::size_type getFilterStringSize() override; - typedef std::list child_list_t; + typedef std::list > child_list_t; - virtual void addChild(LLFolderViewModelItem* child) + virtual void addChild(LLFolderViewModelItem* child) override { mChildren.push_back(child); child->setParent(this); @@ -298,15 +299,15 @@ public: requestSort(); } - virtual void removeChild(LLFolderViewModelItem* child) + virtual void removeChild(LLFolderViewModelItem* child) override final { - mChildren.remove(child); child->setParent(NULL); + mChildren.remove(child); dirtyDescendantsFilter(); dirtyFilter(); } - virtual void clearChildren() + virtual void clearChildren() override { // We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); }); @@ -319,7 +320,7 @@ public: child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); } child_list_t::size_type getChildrenCount() const { return mChildren.size(); } - void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) + void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) override { mPassedFilter = passed; mLastFilterGeneration = filter_generation; @@ -328,20 +329,20 @@ public: mMarkedDirtyGeneration = -1; } - void setPassedFolderFilter(bool passed, S32 filter_generation) + void setPassedFolderFilter(bool passed, S32 filter_generation) override { mPassedFolderFilter = passed; mLastFolderFilterGeneration = filter_generation; } - virtual bool potentiallyVisible() + virtual bool potentiallyVisible() override { return passedFilter() // we've passed the filter || (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet || descendantsPassedFilter(); } - virtual bool passedFilter(S32 filter_generation = -1) + virtual bool passedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -352,7 +353,7 @@ public: return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation)); } - virtual bool descendantsPassedFilter(S32 filter_generation = -1) + virtual bool descendantsPassedFilter(S32 filter_generation = -1) override { if (filter_generation < 0) { @@ -361,10 +362,10 @@ public: return mMostFilteredDescendantGeneration >= filter_generation; } - protected: - virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } - virtual bool hasParent() { return mParent != NULL; } + virtual void setParent(LLFolderViewModelItem* parent) override final { mParent = parent; } + virtual const LLFolderViewModelItem* getParent() override { return mParent; }; + virtual bool hasParent() override { return mParent != NULL; } S32 mSortVersion; bool mPassedFilter; @@ -381,7 +382,7 @@ protected: LLFolderViewModelItem* mParent; LLFolderViewModelInterface& mRootViewModel; - void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} + void setFolderViewItem(LLFolderViewItem* folder_view_item) override { mFolderViewItem = folder_view_item;} LLFolderViewItem* mFolderViewItem; }; @@ -395,15 +396,15 @@ public: mFolderView(NULL) {} - virtual void requestSortAll() + virtual void requestSortAll() override { // sort everything mTargetSortVersion++; } - virtual std::string getStatusText(bool is_empty_folder = false); - virtual void filter(); + virtual std::string getStatusText(bool is_empty_folder = false) override; + virtual void filter() override; - void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;} + void setFolderView(LLFolderView* folder_view) override { mFolderView = folder_view;} protected: bool needsSort(class LLFolderViewModelItem* item); @@ -433,14 +434,14 @@ public: virtual const SortType& getSorter() const { return *mSorter; } virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); } - virtual FilterType& getFilter() { return *mFilter; } - virtual const FilterType& getFilter() const { return *mFilter; } + virtual FilterType& getFilter() override { return *mFilter; } + virtual const FilterType& getFilter() const override { return *mFilter; } virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); } // By default, we assume the content is available. If a network fetch mechanism is implemented for the model, // this method needs to be overloaded and return the relevant fetch status. - virtual bool contentsReady() { return true; } - virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; } + virtual bool contentsReady() override { return true; } + virtual bool isFolderComplete(LLFolderViewFolder* folder) override { return true; } struct ViewModelCompare { @@ -461,7 +462,7 @@ public: const SortType& mSorter; }; - void sort(LLFolderViewFolder* folder) + void sort(LLFolderViewFolder* folder) override { if (needsSort(folder->getViewModelItem())) { diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 5004055666..bb1daf4ec1 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -300,7 +300,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic for (auto itemp : mChildren) { - LLConversationItem* current_participant = dynamic_cast(itemp); + LLConversationItem* current_participant = dynamic_cast(itemp.get()); // Add the avatar uuid to the list (except if it's the own agent uuid) if (current_participant->getUUID() != gAgentID) { @@ -329,6 +329,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic void LLConversationItemSession::removeParticipant(LLConversationItemParticipant* participant) { + LLPointer holder(participant); removeChild(participant); mNeedsRefresh = true; updateName(participant); @@ -360,15 +361,10 @@ void LLConversationItemSession::clearAndDeparentModels() for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();) { LLFolderViewModelItem* child = *it; - if (child->getNumRefs() == 0) + // Note that model might still be assigned to some view/widget + // and have a different parent + if (child->getParent() == this) { - // LLConversationItemParticipant can be created but not assigned to any view, - // it was waiting for an "add_participant" event to be processed - delete child; - } - else - { - // Model is still assigned to some view/widget child->setParent(NULL); } it = mChildren.erase(it); @@ -383,7 +379,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const child_list_t::iterator iter; for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { - participant = dynamic_cast(*iter); + participant = dynamic_cast((*iter).get()); if (participant && participant->hasSameValue(participant_id)) { break; @@ -493,7 +489,7 @@ const bool LLConversationItemSession::getTime(F64& time) const child_list_t::const_iterator iter; for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { - participant = dynamic_cast(*iter); + participant = dynamic_cast((*iter).get()); F64 participant_time; if (participant && participant->getTime(participant_time)) { @@ -517,7 +513,7 @@ void LLConversationItemSession::dumpDebugData(bool dump_children) { for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); iter++) { - LLConversationItemParticipant* participant = dynamic_cast(*iter); + LLConversationItemParticipant* participant = dynamic_cast((*iter).get()); if (participant) { participant->dumpDebugData(); diff --git a/indra/newview/llfloaterchatmentionpicker.cpp b/indra/newview/llfloaterchatmentionpicker.cpp index 1cfed122a9..a3eb286375 100644 --- a/indra/newview/llfloaterchatmentionpicker.cpp +++ b/indra/newview/llfloaterchatmentionpicker.cpp @@ -88,7 +88,7 @@ uuid_vec_t LLFloaterChatMentionPicker::getParticipantIds() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast((*current_participant_model).get()); if (participant_model) { avatar_ids.push_back(participant_model->getUUID()); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 72d4d30dcf..4312c058a1 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -460,7 +460,7 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast((*current_participant_model).get()); if (participant_model) { // Get the avatar name for this participant id from the cache and update the model @@ -511,7 +511,7 @@ void LLFloaterIMContainer::idleUpdate() bool can_ban = haveAbilityToBan(); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast((*current_participant_model).get()); if (participant_model) { participant_model->setModeratorOptionsVisible(is_moderator); @@ -1874,7 +1874,7 @@ LLConversationItem* LLFloaterIMContainer::addConversationListItem(const LLUUID& LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast((*current_participant_model).get()); LLConversationViewParticipant* participant_view = createConversationViewParticipant(participant_model); participant_view->addToFolder(widget); current_participant_model++; diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 7c3d2b511b..e03422780a 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -107,26 +107,6 @@ LLFloaterIMSessionTab::~LLFloaterIMSessionTab() delete mRefreshTimer; LLIMMgr::instance().removeSessionObserver(this); mEmojiCloseConn.disconnect(); - - LLFloaterIMContainer* im_container = LLFloaterIMContainer::findInstance(); - if (im_container) - { - LLParticipantList* session = dynamic_cast(im_container->getSessionModel(mSessionID)); - if (session) - { - for (const conversations_widgets_map::value_type& widget_pair : mConversationsWidgets) - { - LLFolderViewItem* widget = widget_pair.second; - LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); - if (item_vmi && item_vmi->getNumRefs() == 1) - { - // This is the last pointer, remove participant from session - // before participant gets deleted on destroyView. - session->removeChild(item_vmi); - } - } - } - } } // static @@ -730,7 +710,7 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant() LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { - LLConversationItem* participant_model = dynamic_cast(*current_participant_model); + LLConversationItem* participant_model = dynamic_cast((*current_participant_model).get()); if (participant_model) { addConversationViewParticipant(participant_model); @@ -774,27 +754,6 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); if (widget) { - LLFolderViewModelItem* item_vmi = widget->getViewModelItem(); - if (item_vmi && item_vmi->getNumRefs() == 1) - { - // This is the last pointer, remove participant from session - // before participant gets deleted on destroyView. - // - // Floater (widget) and participant's view can simultaneously - // co-own the model, in which case view is responsible for - // the deletion and floater is free to clear and recreate - // the list, yet there are cases where only widget owns - // the pointer so it should do the cleanup. - // See "add_participant". - // - // Todo: If it keeps causing issues turn participants - // into LLPointers in the session - LLParticipantList* session = getParticipantList(); - if (session) - { - session->removeChild(item_vmi); - } - } widget->destroyView(); } mConversationsWidgets.erase(participant_id); @@ -860,7 +819,7 @@ void LLFloaterIMSessionTab::refreshConversation() LLIMSpeakerMgr *speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); while (current_participant_model != end_participant_model) { - LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); + LLConversationItemParticipant* participant_model = dynamic_cast((*current_participant_model).get()); if (speaker_mgr && participant_model) { LLSpeaker *participant_speaker = speaker_mgr->findSpeaker(participant_model->getUUID()); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index b577e302a8..0365b06edb 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -3998,15 +3998,17 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) for (; set_iter != selected_items.end(); ++set_iter) { viewModel = dynamic_cast((*set_iter)->getViewModelItem()); - if (!viewModel || !viewModel->getInventoryObject()) continue; - if (gInventory.isObjectDescendentOf(viewModel->getInventoryObject()->getParentUUID(), marketplacelistings_id)) + if (!viewModel) continue; + LLInventoryObject* inv_obj = viewModel->getInventoryObject(); + if (!inv_obj) continue; + if (gInventory.isObjectDescendentOf(inv_obj->getParentUUID(), marketplacelistings_id)) { - const LLUUID &parent_id = viewModel->getInventoryObject()->getParentUUID(); + const LLUUID &parent_id = inv_obj->getParentUUID(); if (parent_id != marketplacelistings_id) { sMarketplaceFolders.push_back(parent_id); } - const LLUUID &curr_id = viewModel->getInventoryObject()->getUUID(); + const LLUUID &curr_id = inv_obj->getUUID(); if (curr_id != marketplacelistings_id) { sMarketplaceFolders.push_back(curr_id); -- cgit v1.3 From cf3352e6f24630948c38db52b749a103e4d08d77 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Fri, 12 Sep 2025 15:54:21 +0300 Subject: #3957 Add indication to a folder's context menu that it is the default upload location --- indra/newview/llinventoryfunctions.cpp | 25 ++++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 7 ++ indra/newview/llinventorygallerymenu.h | 1 + indra/newview/llinventorypanel.cpp | 8 ++ indra/newview/llinventorypanel.h | 1 + .../default/xui/en/menu_gallery_inventory.xml | 98 ++++++++-------------- .../skins/default/xui/en/menu_inventory.xml | 45 ++++++---- 8 files changed, 107 insertions(+), 79 deletions(-) (limited to 'indra/newview/llinventoryfunctions.cpp') diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index d1fd82a7f1..e6b33453d5 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -3890,6 +3890,31 @@ void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::str } } +bool LLInventoryAction::isFileUploadLocation(const LLUUID& dest_id, const std::string& action) +{ + if (action == "def_model") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT) == dest_id; + } + else if (action == "def_texture") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE) == dest_id; + } + else if (action == "def_sound") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_SOUND) == dest_id; + } + else if (action == "def_animation") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_ANIMATION) == dest_id; + } + else if (action == "def_pbr_material") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) == dest_id; + } + return false; +} + void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index ae7bb8770d..77a2a18877 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -653,6 +653,7 @@ struct LLInventoryAction static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); static void removeItemFromDND(LLFolderView* root); static void fileUploadLocation(const LLUUID& dest_id, const std::string& action); + static bool isFileUploadLocation(const LLUUID& dest_id, const std::string& action); static void saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 7212c4dedb..e129a1296a 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -110,6 +110,7 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery))); enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2)); + enable_registrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryGalleryContextMenu::isUploadLocationSelected, this, _2)); enable_registrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl*, const LLSD&) { @@ -489,6 +490,12 @@ void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata) LLInventoryAction::fileUploadLocation(mUUIDs.front(), param); } +bool LLInventoryGalleryContextMenu::isUploadLocationSelected(const LLSD& userdata) +{ + const std::string param = userdata.asString(); + return LLInventoryAction::isFileUploadLocation(mUUIDs.front(), param); +} + bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata) { if (mUUIDs.size() != 1) diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h index 7c3545432b..e90c7a19d2 100644 --- a/indra/newview/llinventorygallerymenu.h +++ b/indra/newview/llinventorygallerymenu.h @@ -47,6 +47,7 @@ protected: void updateMenuItemsVisibility(LLContextMenu* menu); void fileUploadLocation(const LLSD& userdata); + bool isUploadLocationSelected(const LLSD& userdata); bool canSetUploadLocation(const LLSD& userdata); static void onRename(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 590cbbec4e..a935ede186 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -187,6 +187,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this)); mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2)); + mEnableCallbackRegistrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryPanel::isUploadLocationSelected, this, _2)); mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID())); } @@ -1832,6 +1833,13 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata) LLInventoryAction::fileUploadLocation(dest, param); } +bool LLInventoryPanel::isUploadLocationSelected(const LLSD& userdata) +{ + const std::string param = userdata.asString(); + const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID(); + return LLInventoryAction::isFileUploadLocation(dest, param); +} + void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id) { LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 473283352f..50333709fc 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -225,6 +225,7 @@ public: void doCreate(const LLSD& userdata); bool beginIMSession(); void fileUploadLocation(const LLSD& userdata); + bool isUploadLocationSelected(const LLSD& userdata); void openSingleViewInventory(LLUUID folder_id = LLUUID()); void purgeSelectedItems(); bool attachObject(const LLSD& userdata); 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 d8090070bd..3cfe2e0e6f 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -686,51 +686,6 @@ function="Inventory.DoToSelected" parameter="remove_from_favorites" /> - - - - - - - - - - - - - - - - - - - - - - - + + - - - - + + - - - - + + - - - - + + - - + + - - - - + + - - - + + - - - + + - - - + + - - + +