Viewer#1301 Implement Inventory Favorites Tab
parent
bbadb8b390
commit
db3e5afbfb
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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<LLUUID> 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<LLUUID>::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<LLUUID>::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<LLFolderViewModelItemInventory*>(view_item->getViewModelItem());
|
||||
if (viewmodel_item)
|
||||
{
|
||||
removeItemID(viewmodel_item->getUUID());
|
||||
}
|
||||
view_item->destroyView();
|
||||
if (parent)
|
||||
{
|
||||
parent->getViewModelItem()->dirtyDescendantsFilter();
|
||||
LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(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<const LLViewerInventoryCategory*>(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 */
|
||||
/************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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<LLUUID> mBuildViewsQueue;
|
||||
std::deque<LLUUID> mBuildRootContent;
|
||||
std::deque<LLUUID> mBuildRootQueue;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue