summaryrefslogtreecommitdiff
path: root/indra/newview/llinventorypanel.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llinventorypanel.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/newview/llinventorypanel.cpp')
-rw-r--r--indra/newview/llinventorypanel.cpp5178
1 files changed, 2589 insertions, 2589 deletions
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 462b4929a2..d2c9dffc44 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1,2589 +1,2589 @@
-/*
- * @file llinventorypanel.cpp
- * @brief Implementation of the inventory panel and associated stuff.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llinventorypanel.h"
-
-#include <utility> // for std::pair<>
-
-#include "llagent.h"
-#include "llagentwearables.h"
-#include "llappearancemgr.h"
-#include "llavataractions.h"
-#include "llclipboard.h"
-#include "llfloaterreg.h"
-#include "llfloatersidepanelcontainer.h"
-#include "llfolderview.h"
-#include "llfolderviewitem.h"
-#include "llfloaterimcontainer.h"
-#include "llimview.h"
-#include "llinspecttexture.h"
-#include "llinventorybridge.h"
-#include "llinventoryfunctions.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llnotificationsutil.h"
-#include "llpanelmaininventory.h"
-#include "llpreview.h"
-#include "llsidepanelinventory.h"
-#include "llstartup.h"
-#include "lltrans.h"
-#include "llviewerassettype.h"
-#include "llviewerattachmenu.h"
-#include "llviewerfoldertype.h"
-#include "llvoavatarself.h"
-
-class LLInventoryRecentItemsPanel;
-class LLAssetFilteredInventoryPanel;
-
-static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
-static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
-static LLDefaultChildRegistry::Register<LLAssetFilteredInventoryPanel> t_asset_filtered_inv_panel("asset_filtered_inv_panel");
-
-const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
-const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
-const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
-static const LLInventoryFolderViewModelBuilder INVENTORY_BRIDGE_BUILDER;
-
-// statics
-bool LLInventoryPanel::sColorSetInitialized = false;
-LLUIColor LLInventoryPanel::sDefaultColor;
-LLUIColor LLInventoryPanel::sDefaultHighlightColor;
-LLUIColor LLInventoryPanel::sLibraryColor;
-LLUIColor LLInventoryPanel::sLinkColor;
-
-const LLColor4U DEFAULT_WHITE(255, 255, 255);
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInventoryPanelObserver
-//
-// Bridge to support knowing when the inventory has changed.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLInventoryPanelObserver : public LLInventoryObserver
-{
-public:
- LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {}
- virtual ~LLInventoryPanelObserver() {}
- virtual void changed(U32 mask)
- {
- mIP->modelChanged(mask);
- }
-protected:
- LLInventoryPanel* mIP;
-};
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInvPanelComplObserver
-//
-// Calls specified callback when all specified items become complete.
-//
-// Usage:
-// observer = new LLInvPanelComplObserver(boost::bind(onComplete));
-// inventory->addObserver(observer);
-// observer->reset(); // (optional)
-// observer->watchItem(incomplete_item1_id);
-// observer->watchItem(incomplete_item2_id);
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-class LLInvPanelComplObserver : public LLInventoryCompletionObserver
-{
-public:
- typedef boost::function<void()> callback_t;
-
- LLInvPanelComplObserver(callback_t cb)
- : mCallback(cb)
- {
- }
-
- void reset();
-
-private:
- /*virtual*/ void done();
-
- /// Called when all the items are complete.
- callback_t mCallback;
-};
-
-void LLInvPanelComplObserver::reset()
-{
- mIncomplete.clear();
- mComplete.clear();
-}
-
-void LLInvPanelComplObserver::done()
-{
- mCallback();
-}
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLInventoryPanel
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
- LLPanel(p),
- mInventoryObserver(NULL),
- mCompletionObserver(NULL),
- mScroller(NULL),
- mSortOrderSetting(p.sort_order_setting),
- mInventory(p.inventory), //inventory("", &gInventory)
- mAcceptsDragAndDrop(p.accepts_drag_and_drop),
- mAllowMultiSelect(p.allow_multi_select),
- mAllowDrag(p.allow_drag),
- mShowItemLinkOverlays(p.show_item_link_overlays),
- mShowEmptyMessage(p.show_empty_message),
- mSuppressFolderMenu(p.suppress_folder_menu),
- mSuppressOpenItemAction(false),
- mBuildViewsOnInit(p.preinitialize_views),
- mViewsInitialized(VIEWS_UNINITIALIZED),
- mInvFVBridgeBuilder(NULL),
- mInventoryViewModel(p.name),
- mGroupedItemBridge(new LLFolderViewGroupedItemBridge),
- mFocusSelection(false),
- mBuildChildrenViews(true),
- mRootInited(false)
-{
- mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
-
- if (!sColorSetInitialized)
- {
- sDefaultColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
- sDefaultHighlightColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
- sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
- sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
- sColorSetInitialized = true;
- }
-
- // context menu callbacks
- mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
- mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
- mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
- mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2));
- mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2));
- 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));
- mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
-}
-
-LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
-{
- LLFolderView::Params p(mParams.folder_view);
- p.name = getName();
- p.title = getLabel();
- p.rect = LLRect(0, 0, getRect().getWidth(), 0);
- p.parent_panel = this;
- p.tool_tip = p.name;
- p.listener = mInvFVBridgeBuilder->createBridge( LLAssetType::AT_CATEGORY,
- LLAssetType::AT_CATEGORY,
- LLInventoryType::IT_CATEGORY,
- this,
- &mInventoryViewModel,
- NULL,
- root_id);
- p.view_model = &mInventoryViewModel;
- p.grouped_item_model = mGroupedItemBridge;
- p.use_label_suffix = mParams.use_label_suffix;
- p.allow_multiselect = mAllowMultiSelect;
- p.allow_drag = mAllowDrag;
- p.show_empty_message = mShowEmptyMessage;
- p.suppress_folder_menu = mSuppressFolderMenu;
- p.show_item_link_overlays = mShowItemLinkOverlays;
- p.root = NULL;
- p.allow_drop = mParams.allow_drop_on_root;
- p.options_menu = "menu_inventory.xml";
-
- LLFolderView* fv = LLUICtrlFactory::create<LLFolderView>(p);
- fv->setCallbackRegistrar(&mCommitCallbackRegistrar);
- fv->setEnableRegistrar(&mEnableCallbackRegistrar);
-
- return fv;
-}
-
-void LLInventoryPanel::clearFolderRoot()
-{
- gIdleCallbacks.deleteFunction(idle, this);
- gIdleCallbacks.deleteFunction(onIdle, this);
-
- if (mInventoryObserver)
- {
- mInventory->removeObserver(mInventoryObserver);
- delete mInventoryObserver;
- mInventoryObserver = NULL;
- }
- if (mCompletionObserver)
- {
- mInventory->removeObserver(mCompletionObserver);
- delete mCompletionObserver;
- mCompletionObserver = NULL;
- }
-
- if (mScroller)
- {
- removeChild(mScroller);
- delete mScroller;
- mScroller = NULL;
- }
-}
-
-void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
-{
- // save off copy of params
- mParams = params;
-
- initFolderRoot();
-
- // Initialize base class params.
- LLPanel::initFromParams(mParams);
-}
-
-LLInventoryPanel::~LLInventoryPanel()
-{
- U32 sort_order = getFolderViewModel()->getSorter().getSortOrder();
- if (mSortOrderSetting != INHERIT_SORT_ORDER)
- {
- gSavedSettings.setU32(mSortOrderSetting, sort_order);
- }
-
- clearFolderRoot();
-}
-
-void LLInventoryPanel::initFolderRoot()
-{
- // Clear up the root view
- // Note: This needs to be done *before* we build the new folder view
- LLUUID root_id = getRootFolderID();
- if (mFolderRoot.get())
- {
- removeItemID(root_id);
- mFolderRoot.get()->destroyView();
- }
-
- mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
- {
- // Determine the root folder in case specified, and
- // build the views starting with that folder.
- LLFolderView* folder_view = createFolderRoot(root_id);
- mFolderRoot = folder_view->getHandle();
- mRootInited = true;
-
- addItemID(root_id, mFolderRoot.get());
- }
- mCommitCallbackRegistrar.popScope();
- mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
- mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
-
- // Scroller
- LLRect scroller_view_rect = getRect();
- scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
- LLScrollContainer::Params scroller_params(mParams.scroll());
- scroller_params.rect(scroller_view_rect);
- mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
- addChild(mScroller);
- mScroller->addChild(mFolderRoot.get());
- mFolderRoot.get()->setScrollContainer(mScroller);
- mFolderRoot.get()->setFollowsAll();
- mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
-
- if (mSelectionCallback)
- {
- mFolderRoot.get()->setSelectCallback(mSelectionCallback);
- }
-
- // Set up the callbacks from the inventory we're viewing, and then build everything.
- mInventoryObserver = new LLInventoryPanelObserver(this);
- mInventory->addObserver(mInventoryObserver);
-
- mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
- mInventory->addObserver(mCompletionObserver);
-
- if (mBuildViewsOnInit)
- {
- initializeViewBuilding();
- }
-
- if (mSortOrderSetting != INHERIT_SORT_ORDER)
- {
- setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
- }
- else
- {
- setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
- }
-
- // hide inbox
- if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
- {
- getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
- }
- // hide marketplace listing box, unless we are a marketplace panel
- if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
- {
- getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
- }
-
- // set the filter for the empty folder if the debug setting is on
- if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
- {
- getFilter().setFilterEmptySystemFolders();
- }
-
- // keep track of the clipboard state so that we avoid filtering too much
- mClipboardState = LLClipboard::instance().getGeneration();
-}
-
-void LLInventoryPanel::initializeViewBuilding()
-{
- if (mViewsInitialized == VIEWS_UNINITIALIZED)
- {
- LL_DEBUGS("Inventory") << "Setting views for " << getName() << " to initialize" << LL_ENDL;
- // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
- // Initializing views takes a while so always do it onIdle if viewer already loaded.
- if (mInventory->isInventoryUsable()
- && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
- {
- // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
- const F64 max_time = 20.f;
- initializeViews(max_time);
- }
- else
- {
- mViewsInitialized = VIEWS_INITIALIZING;
- gIdleCallbacks.addFunction(onIdle, (void*)this);
- }
- }
-}
-
-/*virtual*/
-void LLInventoryPanel::onVisibilityChange(bool new_visibility)
-{
- if (new_visibility && mViewsInitialized == VIEWS_UNINITIALIZED)
- {
- // first call can be from tab initialization
- if (gFloaterView->getParentFloater(this) != NULL)
- {
- initializeViewBuilding();
- }
- }
- LLPanel::onVisibilityChange(new_visibility);
-}
-
-void LLInventoryPanel::draw()
-{
- // Select the desired item (in case it wasn't loaded when the selection was requested)
- updateSelection();
-
- LLPanel::draw();
-}
-
-const LLInventoryFilter& LLInventoryPanel::getFilter() const
-{
- return getFolderViewModel()->getFilter();
-}
-
-LLInventoryFilter& LLInventoryPanel::getFilter()
-{
- return getFolderViewModel()->getFilter();
-}
-
-void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
-{
- if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT)
- {
- getFilter().setFilterObjectTypes(types);
- }
- if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY)
- getFilter().setFilterCategoryTypes(types);
-}
-
-void LLInventoryPanel::setFilterWorn()
-{
- getFilter().setFilterWorn();
-}
-
-U32 LLInventoryPanel::getFilterObjectTypes() const
-{
- return getFilter().getFilterObjectTypes();
-}
-
-U32 LLInventoryPanel::getFilterPermMask() const
-{
- return getFilter().getFilterPermissions();
-}
-
-
-void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
-{
- getFilter().setFilterPermissions(filter_perm_mask);
-}
-
-void LLInventoryPanel::setFilterWearableTypes(U64 types)
-{
- getFilter().setFilterWearableTypes(types);
-}
-
-void LLInventoryPanel::setFilterSettingsTypes(U64 filter)
-{
- getFilter().setFilterSettingsTypes(filter);
-}
-
-void LLInventoryPanel::setFilterSubString(const std::string& string)
-{
- getFilter().setFilterSubString(string);
-}
-
-const std::string LLInventoryPanel::getFilterSubString()
-{
- return getFilter().getFilterSubString();
-}
-
-void LLInventoryPanel::setSortOrder(U32 order)
-{
- LLInventorySort sorter(order);
- if (order != getFolderViewModel()->getSorter().getSortOrder())
- {
- getFolderViewModel()->setSorter(sorter);
- mFolderRoot.get()->arrangeAll();
- // try to keep selection onscreen, even if it wasn't to start with
- mFolderRoot.get()->scrollToShowSelection();
- }
-}
-
-U32 LLInventoryPanel::getSortOrder() const
-{
- return getFolderViewModel()->getSorter().getSortOrder();
-}
-
-void LLInventoryPanel::setSinceLogoff(bool sl)
-{
- getFilter().setDateRangeLastLogoff(sl);
-}
-
-void LLInventoryPanel::setHoursAgo(U32 hours)
-{
- getFilter().setHoursAgo(hours);
-}
-
-void LLInventoryPanel::setDateSearchDirection(U32 direction)
-{
- getFilter().setDateSearchDirection(direction);
-}
-
-void LLInventoryPanel::setFilterLinks(U64 filter_links)
-{
- getFilter().setFilterLinks(filter_links);
-}
-
-void LLInventoryPanel::setSearchType(LLInventoryFilter::ESearchType type)
-{
- getFilter().setSearchType(type);
-}
-
-LLInventoryFilter::ESearchType LLInventoryPanel::getSearchType()
-{
- return getFilter().getSearchType();
-}
-
-void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
-{
- getFilter().setShowFolderState(show);
-}
-
-LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
-{
- return getFilter().getShowFolderState();
-}
-
-void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item)
-{
- LLFolderViewItem* view_item = getItemByID(item_id);
- LLFolderViewModelItemInventory* viewmodel_item =
- static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL);
-
- // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item
- // to folder is the fast way to get a folder without searching through folders tree.
- LLFolderViewFolder* view_folder = NULL;
-
- // Check requires as this item might have already been deleted
- // as a child of its deleted parent.
- if (model_item && view_item)
- {
- view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
- }
-
- // if folder is not fully initialized (likely due to delayed load on idle)
- // and we are not rebuilding, try updating children
- if (view_folder
- && !view_folder->areChildrenInited()
- && ( (mask & LLInventoryObserver::REBUILD) == 0))
- {
- LLInventoryObject const* objectp = mInventory->getObject(item_id);
- if (objectp)
- {
- view_item = buildNewViews(item_id, objectp, view_item, BUILD_ONE_FOLDER);
- }
- }
-
- //////////////////////////////
- // LABEL Operation
- // Empty out the display name for relabel.
- if (mask & LLInventoryObserver::LABEL)
- {
- if (view_item)
- {
- // Request refresh on this item (also flags for filtering)
- LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getViewModelItem();
- if(bridge)
- {
- // Clear the display name first, so it gets properly re-built during refresh()
- bridge->clearDisplayName();
-
- view_item->refresh();
- }
- LLFolderViewFolder* parent = view_item->getParentFolder();
- if(parent)
- {
- parent->getViewModelItem()->dirtyDescendantsFilter();
- }
- }
- }
-
- //////////////////////////////
- // REBUILD Operation
- // Destroy and regenerate the UI.
- if (mask & LLInventoryObserver::REBUILD)
- {
- if (model_item && view_item && viewmodel_item)
- {
- const LLUUID& idp = viewmodel_item->getUUID();
- view_item->destroyView();
- removeItemID(idp);
- }
-
- LLInventoryObject const* objectp = mInventory->getObject(item_id);
- if (objectp)
- {
- // providing NULL directly avoids unnessesary getItemByID calls
- view_item = buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);
- }
- else
- {
- view_item = NULL;
- }
-
- viewmodel_item =
- static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL);
- view_folder = dynamic_cast<LLFolderViewFolder *>(view_item);
- }
-
- //////////////////////////////
- // INTERNAL Operation
- // This could be anything. For now, just refresh the item.
- if (mask & LLInventoryObserver::INTERNAL)
- {
- if (view_item)
- {
- view_item->refresh();
- }
- }
-
- //////////////////////////////
- // SORT Operation
- // Sort the folder.
- if (mask & LLInventoryObserver::SORT)
- {
- if (view_folder)
- {
- view_folder->getViewModelItem()->requestSort();
- }
- }
-
- // 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
- // panel). What's relevant is that the item and UI are probably out of sync and thus need to be
- // resynchronized.
- if (mask & (LLInventoryObserver::STRUCTURE |
- LLInventoryObserver::ADD |
- LLInventoryObserver::REMOVE))
- {
- //////////////////////////////
- // ADD Operation
- // Item exists in memory but a UI element hasn't been created for it.
- if (model_item && !view_item)
- {
- // Add the UI element for this item.
- LLInventoryObject const* objectp = mInventory->getObject(item_id);
- if (objectp)
- {
- // providing NULL directly avoids unnessesary getItemByID calls
- buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);
- }
-
- // Select any newly created object that has the auto rename at top of folder root set.
- if(mFolderRoot.get()->getRoot()->needsAutoRename())
- {
- setSelection(item_id, false);
- }
- updateFolderLabel(model_item->getParentUUID());
- }
-
- //////////////////////////////
- // STRUCTURE Operation
- // This item already exists in both memory and UI. It was probably reparented.
- else if (model_item && view_item)
- {
- LLFolderViewFolder* old_parent = view_item->getParentFolder();
- // Don't process the item if it is the root
- if (old_parent)
- {
- LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent->getViewModelItem());
- LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID());
- // Item has been moved.
- if (old_parent != new_parent)
- {
- if (new_parent != NULL)
- {
- // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
- view_item->addToFolder(new_parent);
- addItemID(viewmodel_item->getUUID(), view_item);
- if (mInventory)
- {
- const LLUUID trash_id = mInventory->findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (trash_id != model_item->getParentUUID() && (mask & LLInventoryObserver::INTERNAL) && new_parent->isOpen())
- {
- setSelection(item_id, false);
- }
- }
- updateFolderLabel(model_item->getParentUUID());
- }
- else
- {
- // Remove the item ID before destroying the view because the view-model-item gets
- // destroyed when the view is destroyed
- removeItemID(viewmodel_item->getUUID());
-
- // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that
- // doesn't include trash). Just remove the item's UI.
- view_item->destroyView();
- }
- if(viewmodel_folder)
- {
- updateFolderLabel(viewmodel_folder->getUUID());
- }
- old_parent->getViewModelItem()->dirtyDescendantsFilter();
- }
- }
- }
-
- //////////////////////////////
- // REMOVE Operation
- // This item has been removed from memory, but its associated UI element still exists.
- else if (!model_item && view_item && viewmodel_item)
- {
- // Remove the item's UI.
- LLFolderViewFolder* parent = view_item->getParentFolder();
- 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());
- }
- }
- }
- }
-}
-
-// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)
-void LLInventoryPanel::modelChanged(U32 mask)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- if (mViewsInitialized != VIEWS_INITIALIZED) return;
-
- const LLInventoryModel* model = getModel();
- if (!model) return;
-
- const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs();
- if (changed_items.empty()) return;
-
- for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
- items_iter != changed_items.end();
- ++items_iter)
- {
- const LLUUID& item_id = (*items_iter);
- const LLInventoryObject* model_item = model->getObject(item_id);
- itemChanged(item_id, mask, model_item);
- }
-}
-
-LLUUID LLInventoryPanel::getRootFolderID()
-{
- LLUUID root_id;
- if (mFolderRoot.get() && mFolderRoot.get()->getViewModelItem())
- {
- root_id = static_cast<LLFolderViewModelItemInventory*>(mFolderRoot.get()->getViewModelItem())->getUUID();
- }
- else
- {
- if (mParams.start_folder.id.isChosen())
- {
- root_id = mParams.start_folder.id;
- }
- else
- {
- const LLFolderType::EType preferred_type = mParams.start_folder.type.isChosen()
- ? mParams.start_folder.type
- : LLViewerFolderType::lookupTypeFromNewCategoryName(mParams.start_folder.name);
-
- if ("LIBRARY" == mParams.start_folder.name())
- {
- root_id = gInventory.getLibraryRootFolderID();
- }
- else if (preferred_type != LLFolderType::FT_NONE)
- {
- LLStringExplicit label(mParams.start_folder.name());
- setLabel(label);
-
- root_id = gInventory.findCategoryUUIDForType(preferred_type);
- if (root_id.isNull())
- {
- LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL;
- root_id.generateNewID();
- }
- }
- }
- }
- return root_id;
-}
-
-// static
-void LLInventoryPanel::onIdle(void *userdata)
-{
- if (!gInventory.isInventoryUsable())
- return;
-
- LLInventoryPanel *self = (LLInventoryPanel*)userdata;
- if (self->mViewsInitialized <= VIEWS_INITIALIZING)
- {
- const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders
- self->initializeViews(max_time); // Shedules LLInventoryPanel::idle()
- }
- if (self->mViewsInitialized >= VIEWS_BUILDING)
- {
- gIdleCallbacks.deleteFunction(onIdle, (void*)self);
- }
-}
-
-struct DirtyFilterFunctor : public LLFolderViewFunctor
-{
- /*virtual*/ void doFolder(LLFolderViewFolder* folder)
- {
- folder->getViewModelItem()->dirtyFilter();
- }
- /*virtual*/ void doItem(LLFolderViewItem* item)
- {
- item->getViewModelItem()->dirtyFilter();
- }
-};
-
-void LLInventoryPanel::idle(void* user_data)
-{
- LLInventoryPanel* panel = (LLInventoryPanel*)user_data;
- // Nudge the filter if the clipboard state changed
- if (panel->mClipboardState != LLClipboard::instance().getGeneration())
- {
- panel->mClipboardState = LLClipboard::instance().getGeneration();
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- LLFolderViewFolder* trash_folder = panel->getFolderByID(trash_id);
- if (trash_folder)
- {
- DirtyFilterFunctor dirtyFilterFunctor;
- trash_folder->applyFunctorToChildren(dirtyFilterFunctor);
- }
-
- }
-
- bool in_visible_chain = panel->isInVisibleChain();
-
- if (!panel->mBuildViewsQueue.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;
-
- // things added last are closer to root thus of higher priority
- std::deque<LLUUID> priority_list;
- priority_list.swap(panel->mBuildViewsQueue);
-
- while (curent_time < panel->mBuildViewsEndTime
- && !priority_list.empty())
- {
- LLUUID item_id = priority_list.back();
- priority_list.pop_back();
-
- LLInventoryObject const* objectp = panel->mInventory->getObject(item_id);
- if (objectp && panel->typedViewsFilter(item_id, objectp))
- {
- LLFolderViewItem* folder_view_item = panel->getItemByID(item_id);
- if (!folder_view_item || !folder_view_item->areChildrenInited())
- {
- const LLUUID &parent_id = objectp->getParentUUID();
- LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id);
- panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT);
- }
- }
- curent_time = LLTimer::getTotalSeconds();
- }
- while (!priority_list.empty())
- {
- // items in priority_list are of higher priority
- panel->mBuildViewsQueue.push_back(priority_list.front());
- priority_list.pop_front();
- }
- if (panel->mBuildViewsQueue.empty())
- {
- panel->mViewsInitialized = VIEWS_INITIALIZED;
- }
- }
-
- // Take into account the fact that the root folder might be invalidated
- if (panel->mFolderRoot.get())
- {
- panel->mFolderRoot.get()->update();
- // while dragging, update selection rendering to reflect single/multi drag status
- if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
- {
- EAcceptance last_accept = LLToolDragAndDrop::getInstance()->getLastAccept();
- if (last_accept == ACCEPT_YES_SINGLE || last_accept == ACCEPT_YES_COPY_SINGLE)
- {
- panel->mFolderRoot.get()->setShowSingleSelection(true);
- }
- else
- {
- panel->mFolderRoot.get()->setShowSingleSelection(false);
- }
- }
- else
- {
- panel->mFolderRoot.get()->setShowSingleSelection(false);
- }
- }
- else
- {
- LL_WARNS() << "Inventory : Deleted folder root detected on panel" << LL_ENDL;
- panel->clearFolderRoot();
- }
-}
-
-
-void LLInventoryPanel::initializeViews(F64 max_time)
-{
- if (!gInventory.isInventoryUsable()) return;
- if (!mRootInited) return;
-
- mViewsInitialized = VIEWS_BUILDING;
-
- F64 curent_time = LLTimer::getTotalSeconds();
- mBuildViewsEndTime = curent_time + max_time;
-
- // init everything
- LLUUID root_id = getRootFolderID();
- if (root_id.notNull())
- {
- buildNewViews(getRootFolderID());
- }
- else
- {
- // Default case: always add "My Inventory" root first, "Library" root second
- // If we run out of time, this still should create root folders
- buildNewViews(gInventory.getRootFolderID()); // My Inventory
- buildNewViews(gInventory.getLibraryRootFolderID()); // Library
- }
-
- if (mBuildViewsQueue.empty())
- {
- mViewsInitialized = VIEWS_INITIALIZED;
- }
-
- gIdleCallbacks.addFunction(idle, this);
-
- if(mParams.open_first_folder)
- {
- openStartFolderOrMyInventory();
- }
-
- // Special case for new user login
- if (gAgent.isFirstLogin())
- {
- // Auto open the user's library
- LLFolderViewFolder* lib_folder = getFolderByID(gInventory.getLibraryRootFolderID());
- if (lib_folder)
- {
- lib_folder->setOpen(true);
- }
-
- // Auto close the user's my inventory folder
- LLFolderViewFolder* my_inv_folder = getFolderByID(gInventory.getRootFolderID());
- if (my_inv_folder)
- {
- my_inv_folder->setOpenArrangeRecursively(false, LLFolderViewFolder::RECURSE_DOWN);
- }
- }
-}
-
-
-LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop)
-{
- LLFolderViewFolder::Params params(mParams.folder);
-
- params.name = bridge->getDisplayName();
- params.root = mFolderRoot.get();
- params.listener = bridge;
- params.tool_tip = params.name;
- params.allow_drop = allow_drop;
-
- params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
- params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
-
- return LLUICtrlFactory::create<LLFolderViewFolder>(params);
-}
-
-LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge)
-{
- LLFolderViewItem::Params params(mParams.item);
-
- params.name = bridge->getDisplayName();
- params.creation_date = bridge->getCreationDate();
- params.root = mFolderRoot.get();
- params.listener = bridge;
- params.rect = LLRect (0, 0, 0, 0);
- params.tool_tip = params.name;
-
- params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
- params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
-
- return LLUICtrlFactory::create<LLFolderViewItem>(params);
-}
-
-LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
-{
- LLInventoryObject const* objectp = mInventory->getObject(id);
- return buildNewViews(id, objectp);
-}
-
-LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp)
-{
- if (!objectp)
- {
- return NULL;
- }
- if (!typedViewsFilter(id, objectp))
- {
- // if certain types are not allowed permanently, no reason to create views
- return NULL;
- }
-
- const LLUUID &parent_id = objectp->getParentUUID();
- LLFolderViewItem* folder_view_item = getItemByID(id);
- LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id);
-
- return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT);
-}
-
-LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id,
- LLInventoryObject const* objectp,
- LLFolderViewItem *folder_view_item,
- const EBuildModes &mode)
-{
- if (!objectp)
- {
- return NULL;
- }
- if (!typedViewsFilter(id, objectp))
- {
- // if certain types are not allowed permanently, no reason to create views
- return NULL;
- }
-
- const LLUUID &parent_id = objectp->getParentUUID();
- LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id);
-
- return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, mode);
-}
-
-LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
- const LLUUID& parent_id,
- LLInventoryObject const* objectp,
- LLFolderViewItem *folder_view_item,
- LLFolderViewFolder *parent_folder,
- const EBuildModes &mode,
- S32 depth)
-{
- depth++;
-
- // Force the creation of an extra root level folder item if required by the inventory panel (default is "false")
- bool allow_drop = true;
- bool create_root = false;
- if (mParams.show_root_folder)
- {
- LLUUID root_id = getRootFolderID();
- if (root_id == id)
- {
- // We insert an extra level that's seen by the UI but has no influence on the model
- parent_folder = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
- folder_view_item = NULL;
- allow_drop = mParams.allow_drop_on_root;
- create_root = true;
- }
- }
-
- if (!folder_view_item && parent_folder)
- {
- if (objectp->getType() <= LLAssetType::AT_NONE)
- {
- LL_WARNS() << "LLInventoryPanel::buildViewsTree called with invalid objectp->mType : "
- << ((S32)objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
- << LL_ENDL;
- return NULL;
- }
-
- if (objectp->getType() >= LLAssetType::AT_COUNT)
- {
- // Example: Happens when we add assets of new, not yet supported type to library
- LL_DEBUGS("Inventory") << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
- << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
- << LL_ENDL;
-
- LLInventoryItem* item = (LLInventoryItem*)objectp;
- if (item)
- {
- LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_UNKNOWN,
- LLAssetType::AT_UNKNOWN,
- LLInventoryType::IT_UNKNOWN,
- this,
- &mInventoryViewModel,
- mFolderRoot.get(),
- item->getUUID(),
- item->getFlags());
-
- if (new_listener)
- {
- folder_view_item = createFolderViewItem(new_listener);
- }
- }
- }
-
- if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
- (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER))
- {
- LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY,
- (mParams.use_marketplace_folders ? LLAssetType::AT_MARKETPLACE_FOLDER : LLAssetType::AT_CATEGORY),
- LLInventoryType::IT_CATEGORY,
- this,
- &mInventoryViewModel,
- mFolderRoot.get(),
- objectp->getUUID());
- if (new_listener)
- {
- folder_view_item = createFolderViewFolder(new_listener,allow_drop);
- }
- }
- else
- {
- // Build new view for item.
- LLInventoryItem* item = (LLInventoryItem*)objectp;
- LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(),
- item->getActualType(),
- item->getInventoryType(),
- this,
- &mInventoryViewModel,
- mFolderRoot.get(),
- item->getUUID(),
- item->getFlags());
-
- if (new_listener)
- {
- folder_view_item = createFolderViewItem(new_listener);
- }
- }
-
- if (folder_view_item)
- {
- llassert(parent_folder != NULL);
- folder_view_item->addToFolder(parent_folder);
- addItemID(id, folder_view_item);
- // In the case of the root folder been shown, open that folder by default once the widget is created
- if (create_root)
- {
- folder_view_item->setOpen(true);
- }
- }
- }
-
- bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY
- && (mBuildChildrenViews || depth == 0);
-
- if (create_children)
- {
- switch (mode)
- {
- case BUILD_TIMELIMIT:
- {
- F64 curent_time = LLTimer::getTotalSeconds();
- // If function is out of time, we want to shedule it into mBuildViewsQueue
- // If we have time, no matter how little, create views for all children
- //
- // This creates children in 'bulk' to make sure folder has either
- // 'empty and incomplete' or 'complete' states with nothing in between.
- // Folders are marked as mIsFolderComplete == false by default,
- // later arrange() will update mIsFolderComplete by child count
- if (mBuildViewsEndTime < curent_time)
- {
- create_children = false;
- // run it again for the sake of creating children
- if (mBuildChildrenViews || depth == 0)
- {
- mBuildViewsQueue.push_back(id);
- }
- }
- else
- {
- create_children = true;
- folder_view_item->setChildrenInited(mBuildChildrenViews);
- }
- break;
- }
- case BUILD_NO_CHILDREN:
- {
- create_children = false;
- // run it to create children, current caller is only interested in current view
- if (mBuildChildrenViews || depth == 0)
- {
- mBuildViewsQueue.push_back(id);
- }
- break;
- }
- case BUILD_ONE_FOLDER:
- {
- // This view loads chindren, following ones don't
- // Note: Might be better idea to do 'depth' instead,
- // It also will help to prioritize root folder's content
- create_children = true;
- folder_view_item->setChildrenInited(true);
- break;
- }
- case BUILD_NO_LIMIT:
- default:
- {
- // keep working till everything exists
- create_children = true;
- folder_view_item->setChildrenInited(true);
- }
- }
- }
-
- // If this is a folder, add the children of the folder and recursively add any
- // child folders.
- if (create_children)
- {
- LLViewerInventoryCategory::cat_array_t* categories;
- LLViewerInventoryItem::item_array_t* items;
- mInventory->lockDirectDescendentArrays(id, categories, items);
-
- // Make sure panel won't lock in a loop over existing items if
- // folder is enormous and at least some work gets done
- const S32 MIN_ITEMS_PER_CALL = 500;
- const S32 starting_item_count = mItemMap.size();
-
- LLFolderViewFolder *parentp = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
- bool done = true;
-
- if(categories)
- {
- bool has_folders = parentp->getFoldersCount() > 0;
- for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin();
- cat_iter != categories->end();
- ++cat_iter)
- {
- const LLViewerInventoryCategory* cat = (*cat_iter);
- if (typedViewsFilter(cat->getUUID(), cat))
- {
- if (has_folders)
- {
- // This can be optimized: we don't need to call getItemByID()
- // each time, especially since content is growing, we can just
- // iter over copy of mItemMap in some way
- LLFolderViewItem* view_itemp = getItemByID(cat->getUUID());
- buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
- }
- else
- {
- buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
- }
- }
-
- if (!mBuildChildrenViews
- && mode == BUILD_TIMELIMIT
- && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
- {
- // Single folder view, check if we still have time
- //
- // Todo: make sure this causes no dupplciates, breaks nothing,
- // especially filters and arrange
- F64 curent_time = LLTimer::getTotalSeconds();
- if (mBuildViewsEndTime < curent_time)
- {
- mBuildViewsQueue.push_back(id);
- done = false;
- break;
- }
- }
- }
- }
-
- if(items)
- {
- for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin();
- item_iter != items->end();
- ++item_iter)
- {
- // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime
- const LLViewerInventoryItem* item = (*item_iter);
- if (typedViewsFilter(item->getUUID(), item))
- {
- // This can be optimized: we don't need to call getItemByID()
- // each time, especially since content is growing, we can just
- // iter over copy of mItemMap in some way
- LLFolderViewItem* view_itemp = getItemByID(item->getUUID());
- buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode, depth);
- }
-
- if (!mBuildChildrenViews
- && mode == BUILD_TIMELIMIT
- && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
- {
- // Single folder view, check if we still have time
- //
- // Todo: make sure this causes no dupplciates, breaks nothing,
- // especially filters and arrange
- F64 curent_time = LLTimer::getTotalSeconds();
- if (mBuildViewsEndTime < curent_time)
- {
- mBuildViewsQueue.push_back(id);
- done = false;
- break;
- }
- }
- }
- }
-
- if (!mBuildChildrenViews && done)
- {
- // flat list is done initializing folder
- folder_view_item->setChildrenInited(true);
- }
- mInventory->unlockDirectDescendentArrays(id);
- }
-
- return folder_view_item;
-}
-
-// bit of a hack to make sure the inventory is open.
-void LLInventoryPanel::openStartFolderOrMyInventory()
-{
- // Find My Inventory folder and open it up by name
- for (LLView *child = mFolderRoot.get()->getFirstChild(); child; child = mFolderRoot.get()->findNextSibling(child))
- {
- LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child);
- if (fchild
- && fchild->getViewModelItem()
- && fchild->getViewModelItem()->getName() == "My Inventory")
- {
- fchild->setOpen(true);
- break;
- }
- }
-}
-
-void LLInventoryPanel::onItemsCompletion()
-{
- if (mFolderRoot.get()) mFolderRoot.get()->updateMenu();
-}
-
-void LLInventoryPanel::openSelected()
-{
- LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
- if(!folder_item) return;
- LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
- if(!bridge) return;
- bridge->openItem();
-}
-
-void LLInventoryPanel::unSelectAll()
-{
- mFolderRoot.get()->setSelection(NULL, false, false);
-}
-
-
-bool LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
-{
- bool handled = LLView::handleHover(x, y, mask);
- if(handled)
- {
- // getCursor gets current cursor, setCursor sets next cursor
- // check that children didn't set own 'next' cursor
- ECursorType cursor = getWindow()->getNextCursor();
- if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW)
- {
- // replace arrow cursor with arrow and hourglass cursor
- getWindow()->setCursor(UI_CURSOR_WORKING);
- }
- }
- else
- {
- getWindow()->setCursor(UI_CURSOR_ARROW);
- }
- return true;
-}
-
-bool LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask)
-{
- if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr)
- {
- if (const LLFolderViewModelItemInventory* vm_item_p = static_cast<const LLFolderViewModelItemInventory*>(hover_item_p->getViewModelItem()))
- {
- LLSD params;
- params["inv_type"] = vm_item_p->getInventoryType();
- params["thumbnail_id"] = vm_item_p->getThumbnailUUID();
- params["item_id"] = vm_item_p->getUUID();
-
- // tooltip should only show over folder, but screen
- // rect includes items under folder as well
- LLRect actionable_rect = hover_item_p->calcScreenRect();
- if (hover_item_p->isOpen() && hover_item_p->hasVisibleChildren())
- {
- actionable_rect.mBottom = actionable_rect.mTop - hover_item_p->getItemHeight();
- }
-
- LLToolTipMgr::instance().show(LLToolTip::Params()
- .message(hover_item_p->getToolTip())
- .sticky_rect(actionable_rect)
- .delay_time(LLView::getTooltipTimeout())
- .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
- .create_params(params));
- return true;
- }
- }
- return LLPanel::handleToolTip(x, y, mask);
-}
-
-bool LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- bool handled = false;
-
- if (mAcceptsDragAndDrop)
- {
- handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
-
- // If folder view is empty the (x, y) point won't be in its rect
- // so the handler must be called explicitly.
- // but only if was not handled before. See EXT-6746.
- if (!handled && mParams.allow_drop_on_root && !mFolderRoot.get()->hasVisibleChildren())
- {
- handled = mFolderRoot.get()->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
-
- if (handled)
- {
- mFolderRoot.get()->setDragAndDropThisFrame();
- }
- }
-
- return handled;
-}
-
-void LLInventoryPanel::onFocusLost()
-{
- // inventory no longer handles cut/copy/paste/delete
- if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot.get())
- {
- LLEditMenuHandler::gEditMenuHandler = NULL;
- }
-
- LLPanel::onFocusLost();
-}
-
-void LLInventoryPanel::onFocusReceived()
-{
- // inventory now handles cut/copy/paste/delete
- LLEditMenuHandler::gEditMenuHandler = mFolderRoot.get();
-
- LLPanel::onFocusReceived();
-}
-
-void LLInventoryPanel::onFolderOpening(const LLUUID &id)
-{
- LLFolderViewItem* folder = getItemByID(id);
- if (folder && !folder->areChildrenInited())
- {
- // Last item in list will be processed first.
- // This might result in dupplicates in list, but it
- // isn't critical, views won't be created twice
- mBuildViewsQueue.push_back(id);
- }
-}
-
-bool LLInventoryPanel::addBadge(LLBadge * badge)
-{
- bool badge_added = false;
-
- if (acceptsBadge())
- {
- badge_added = badge->addToView(mFolderRoot.get());
- }
-
- return badge_added;
-}
-
-void LLInventoryPanel::openAllFolders()
-{
- mFolderRoot.get()->setOpenArrangeRecursively(true, LLFolderViewFolder::RECURSE_DOWN);
- mFolderRoot.get()->arrangeAll();
-}
-
-void LLInventoryPanel::setSelection(const LLUUID& obj_id, bool take_keyboard_focus)
-{
- // Don't select objects in COF (e.g. to prevent refocus when items are worn).
- const LLInventoryObject *obj = mInventory->getObject(obj_id);
- if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())
- {
- return;
- }
- setSelectionByID(obj_id, take_keyboard_focus);
-}
-
-void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, bool user_action)>& cb)
-{
- if (mFolderRoot.get())
- {
- mFolderRoot.get()->setSelectCallback(cb);
- }
- mSelectionCallback = cb;
-}
-
-void LLInventoryPanel::clearSelection()
-{
- mSelectThisID.setNull();
- mFocusSelection = false;
-}
-
-LLInventoryPanel::selected_items_t LLInventoryPanel::getSelectedItems() const
-{
- return mFolderRoot.get()->getSelectionList();
-}
-
-void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, bool user_action)
-{
- // Schedule updating the folder view context menu when all selected items become complete (STORM-373).
- mCompletionObserver->reset();
- for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
- {
- LLFolderViewModelItemInventory* view_model = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem());
- if (view_model)
- {
- LLUUID id = view_model->getUUID();
- if (!(*it)->areChildrenInited())
- {
- const F64 max_time = 0.0001f;
- mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time;
- buildNewViews(id);
- }
- LLViewerInventoryItem* inv_item = mInventory->getItem(id);
-
- if (inv_item && !inv_item->isFinished())
- {
- mCompletionObserver->watchItem(id);
- }
- }
- }
-
- LLFolderView* fv = mFolderRoot.get();
- if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
- {
- fv->setNeedsAutoRename(false);
- if (items.size()) // new asset is visible and selected
- {
- fv->startRenamingSelectedItem();
- }
- else
- {
- LL_DEBUGS("Inventory") << "Failed to start renemr, no items selected" << LL_ENDL;
- }
- }
-
- std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
- LLFolderViewItem* prev_folder_item = getItemByID(mPreviousSelectedFolder);
-
- if (selected_items.size() == 1)
- {
- std::set<LLFolderViewItem*>::const_iterator iter = selected_items.begin();
- LLFolderViewItem* folder_item = (*iter);
- if(folder_item && (folder_item != prev_folder_item))
- {
- LLFolderViewModelItemInventory* fve_listener = static_cast<LLFolderViewModelItemInventory*>(folder_item->getViewModelItem());
- if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
- {
- if (fve_listener->getInventoryObject() && fve_listener->getInventoryObject()->getIsLinkType())
- {
- return;
- }
-
- if(prev_folder_item)
- {
- LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
- if(prev_bridge)
- {
- prev_bridge->clearDisplayName();
- prev_bridge->setShowDescendantsCount(false);
- prev_folder_item->refresh();
- }
- }
-
- LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
- if(bridge)
- {
- bridge->clearDisplayName();
- bridge->setShowDescendantsCount(true);
- folder_item->refresh();
- mPreviousSelectedFolder = bridge->getUUID();
- }
- }
- }
- }
- else
- {
- if(prev_folder_item)
- {
- LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
- if(prev_bridge)
- {
- prev_bridge->clearDisplayName();
- prev_bridge->setShowDescendantsCount(false);
- prev_folder_item->refresh();
- }
- }
- mPreviousSelectedFolder = LLUUID();
- }
-
-}
-
-void LLInventoryPanel::updateFolderLabel(const LLUUID& folder_id)
-{
- if(folder_id != mPreviousSelectedFolder) return;
-
- LLFolderViewItem* folder_item = getItemByID(mPreviousSelectedFolder);
- if(folder_item)
- {
- LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
- if(bridge)
- {
- bridge->clearDisplayName();
- bridge->setShowDescendantsCount(true);
- folder_item->refresh();
- }
- }
-}
-
-void LLInventoryPanel::doCreate(const LLSD& userdata)
-{
- reset_inventory_filter();
- menu_create_inventory_item(this, LLFolderBridge::sSelf.get(), userdata);
-}
-
-bool LLInventoryPanel::beginIMSession()
-{
- std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
-
- std::string name;
-
- std::vector<LLUUID> members;
- EInstantMessage type = IM_SESSION_CONFERENCE_START;
-
- std::set<LLFolderViewItem*>::const_iterator iter;
- for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
- {
-
- LLFolderViewItem* folder_item = (*iter);
-
- if(folder_item)
- {
- LLFolderViewModelItemInventory* fve_listener = static_cast<LLFolderViewModelItemInventory*>(folder_item->getViewModelItem());
- if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
- {
-
- LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
- if(!bridge) return true;
- LLViewerInventoryCategory* cat = bridge->getCategory();
- if(!cat) return true;
- name = cat->getName();
- LLUniqueBuddyCollector is_buddy;
- LLInventoryModel::cat_array_t cat_array;
- LLInventoryModel::item_array_t item_array;
- gInventory.collectDescendentsIf(bridge->getUUID(),
- cat_array,
- item_array,
- LLInventoryModel::EXCLUDE_TRASH,
- is_buddy);
- S32 count = item_array.size();
- if(count > 0)
- {
- //*TODO by what to replace that?
- //LLFloaterReg::showInstance("communicate");
-
- // create the session
- LLAvatarTracker& at = LLAvatarTracker::instance();
- LLUUID id;
- for(S32 i = 0; i < count; ++i)
- {
- id = item_array.at(i)->getCreatorUUID();
- if(at.isBuddyOnline(id))
- {
- members.push_back(id);
- }
- }
- }
- }
- else
- {
- LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getViewModelItem();
-
- if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
- {
- LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID());
-
- if (inv_item)
- {
- LLAvatarTracker& at = LLAvatarTracker::instance();
- LLUUID id = inv_item->getCreatorUUID();
-
- if(at.isBuddyOnline(id))
- {
- members.push_back(id);
- }
- }
- } //if IT_CALLINGCARD
- } //if !IT_CATEGORY
- }
- } //for selected_items
-
- // the session_id is randomly generated UUID which will be replaced later
- // with a server side generated number
-
- if (name.empty())
- {
- name = LLTrans::getString("conference-title");
- }
-
- LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
- if (session_id != LLUUID::null)
- {
- LLFloaterIMContainer::getInstance()->showConversation(session_id);
- }
-
- return true;
-}
-
-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());
- }
-}
-
-void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
-{
- LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);
-}
-
-void LLInventoryPanel::purgeSelectedItems()
-{
- if (!mFolderRoot.get()) return;
-
- const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList();
- if (inventory_selected.empty()) return;
- LLSD args;
- S32 count = inventory_selected.size();
- std::vector<LLUUID> selected_items;
- for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end();
- it != end_it;
- ++it)
- {
- LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID();
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH);
- count += items.size() + cats.size();
- selected_items.push_back(item_id);
- }
- args["COUNT"] = count;
- LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(callbackPurgeSelectedItems, _1, _2, selected_items));
-}
-
-// static
-void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0)
- {
- if (inventory_selected.empty()) return;
-
- for (auto it : inventory_selected)
- {
- remove_inventory_object(it, NULL);
- }
- }
-}
-
-bool LLInventoryPanel::attachObject(const LLSD& userdata)
-{
- // Copy selected item UUIDs to a vector.
- std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
- uuid_vec_t items;
- for (std::set<LLFolderViewItem*>::const_iterator set_iter = selected_items.begin();
- set_iter != selected_items.end();
- ++set_iter)
- {
- items.push_back(static_cast<LLFolderViewModelItemInventory*>((*set_iter)->getViewModelItem())->getUUID());
- }
-
- // Attach selected items.
- LLViewerAttachMenu::attachObjects(items, userdata.asString());
-
- gFocusMgr.setKeyboardFocus(NULL);
-
- return true;
-}
-
-bool LLInventoryPanel::getSinceLogoff()
-{
- return getFilter().isSinceLogoff();
-}
-
-// DEBUG ONLY
-// static
-void LLInventoryPanel::dumpSelectionInformation(void* user_data)
-{
- LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
- iv->mFolderRoot.get()->dumpSelectionInformation();
-}
-
-bool is_inventorysp_active()
-{
- LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
- if (!sidepanel_inventory || !sidepanel_inventory->isInVisibleChain()) return false;
- return sidepanel_inventory->isMainInventoryPanelActive();
-}
-
-// static
-LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(bool auto_open)
-{
- S32 z_min = S32_MAX;
- LLInventoryPanel* res = NULL;
- LLFloater* active_inv_floaterp = NULL;
-
- LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
- if (!floater_inventory)
- {
- LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
- return nullptr;
- }
-
- LLSidepanelInventory *inventory_panel = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
-
- // Iterate through the inventory floaters and return whichever is on top.
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
- {
- LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
- inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
-
- if (inventory_floater && inventory_panel && inventory_floater->getVisible())
- {
- S32 z_order = gFloaterView->getZOrder(inventory_floater);
- if (z_order < z_min)
- {
- res = inventory_panel->getActivePanel();
- z_min = z_order;
- active_inv_floaterp = inventory_floater;
- }
- }
- }
-
- if (res)
- {
- // Make sure the floater is not minimized (STORM-438).
- if (active_inv_floaterp && active_inv_floaterp->isMinimized())
- {
- active_inv_floaterp->setMinimized(false);
- }
- }
- else if (auto_open)
- {
- floater_inventory->openFloater();
-
- res = inventory_panel->getActivePanel();
- }
-
- return res;
-}
-
-//static
-void LLInventoryPanel::openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id,
- bool use_main_panel, bool take_keyboard_focus, bool reset_filter)
-{
- LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
- sidepanel_inventory->showInventoryPanel();
-
- LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
- bool in_inbox = gInventory.isObjectDescendentOf(obj_id, cat_id);
- if (!in_inbox && use_main_panel)
- {
- sidepanel_inventory->selectAllItemsPanel();
- }
-
- if (!auto_open)
- {
- LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
- if (inventory_floater && inventory_floater->getVisible())
- {
- LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
- LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
- if (main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
- {
- LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
- main_panel->setGallerySelection(obj_id);
- return;
- }
- }
- }
-
- if (use_main_panel)
- {
- LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
- if (main_inventory && main_inventory->isSingleFolderMode())
- {
- const LLInventoryObject *obj = gInventory.getObject(obj_id);
- if (obj)
- {
- LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
- main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
- main_inventory->setGallerySelection(obj_id);
- return;
- }
- }
- }
-
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
- if (active_panel)
- {
- LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL;
-
- if (reset_filter)
- {
- reset_inventory_filter();
- }
-
- if (in_inbox)
- {
- sidepanel_inventory->openInbox();
- LLInventoryPanel* inventory_panel = sidepanel_inventory->getInboxPanel();
- if (inventory_panel)
- {
- inventory_panel->setSelection(obj_id, take_keyboard_focus);
- }
- }
- else if (auto_open)
- {
- LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
- if (floater_inventory)
- {
- floater_inventory->setFocus(true);
- }
- active_panel->setSelection(obj_id, take_keyboard_focus);
- }
- else
- {
- // Created items are going to receive proper focus from callbacks
- active_panel->setSelection(obj_id, take_keyboard_focus);
- }
- }
-}
-
-void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
-{
- LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
- for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
- {
- LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
- LLSidepanelInventory* sidepanel_inventory = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
-
- LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
- if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
- {
- main_inventory->initSingleFolderRoot(folder_id);
- main_inventory->toggleViewMode();
- main_inventory->setSingleFolderViewRoot(folder_id, false);
- }
- }
-}
-
-void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
-{
- getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
-}
-
-bool LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const
-{
- return !(getFilter().getFilterCategoryTypes() & (1ULL << folder_type));
-}
-
-void LLInventoryPanel::addItemID( const LLUUID& id, LLFolderViewItem* itemp )
-{
- mItemMap[id] = itemp;
-}
-
-void LLInventoryPanel::removeItemID(const LLUUID& id)
-{
- LLInventoryModel::cat_array_t categories;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(id, categories, items, true);
-
- mItemMap.erase(id);
-
- for (LLInventoryModel::cat_array_t::iterator it = categories.begin(), end_it = categories.end();
- it != end_it;
- ++it)
- {
- mItemMap.erase((*it)->getUUID());
-}
-
- for (LLInventoryModel::item_array_t::iterator it = items.begin(), end_it = items.end();
- it != end_it;
- ++it)
- {
- mItemMap.erase((*it)->getUUID());
- }
-}
-
-LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
-{
- LL_PROFILE_ZONE_SCOPED;
-
- std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
- map_it = mItemMap.find(id);
- if (map_it != mItemMap.end())
- {
- return map_it->second;
- }
-
- return NULL;
-}
-
-LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id)
-{
- LLFolderViewItem* item = getItemByID(id);
- return dynamic_cast<LLFolderViewFolder*>(item);
-}
-
-
-void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, bool take_keyboard_focus )
-{
- LLFolderViewItem* itemp = getItemByID(obj_id);
-
- if (itemp && !itemp->areChildrenInited())
- {
- LLInventoryObject const* objectp = mInventory->getObject(obj_id);
- if (objectp)
- {
- buildNewViews(obj_id, objectp, itemp, BUILD_ONE_FOLDER);
- }
- }
-
- if(itemp && itemp->getViewModelItem())
- {
- itemp->arrangeAndSet(true, take_keyboard_focus);
- mSelectThisID.setNull();
- mFocusSelection = false;
- return;
- }
- else
- {
- // save the desired item to be selected later (if/when ready)
- mFocusSelection = take_keyboard_focus;
- mSelectThisID = obj_id;
- }
-}
-
-void LLInventoryPanel::updateSelection()
-{
- if (mSelectThisID.notNull())
- {
- setSelectionByID(mSelectThisID, mFocusSelection);
- }
-}
-
-void LLInventoryPanel::doToSelected(const LLSD& userdata)
-{
- if (("purge" == userdata.asString()))
- {
- purgeSelectedItems();
- return;
- }
- LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), userdata.asString());
-
- return;
-}
-
-bool LLInventoryPanel::handleKeyHere( KEY key, MASK mask )
-{
- bool handled = false;
- switch (key)
- {
- case KEY_RETURN:
- // Open selected items if enter key hit on the inventory panel
- if (mask == MASK_NONE)
- {
- if (mSuppressOpenItemAction)
- {
- LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
- if(folder_item)
- {
- LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
- if(bridge && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
- {
- return handled;
- }
- }
- }
- LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open");
- handled = true;
- }
- break;
- case KEY_DELETE:
-#if LL_DARWIN
- case KEY_BACKSPACE:
-#endif
- // Delete selected items if delete or backspace key hit on the inventory panel
- // Note: on Mac laptop keyboards, backspace and delete are one and the same
- if (isSelectionRemovable() && (mask == MASK_NONE))
- {
- LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "delete");
- handled = true;
- }
- break;
- }
- return handled;
-}
-
-bool LLInventoryPanel::isSelectionRemovable()
-{
- bool can_delete = false;
- if (mFolderRoot.get())
- {
- std::set<LLFolderViewItem*> selection_set = mFolderRoot.get()->getSelectionList();
- if (!selection_set.empty())
- {
- can_delete = true;
- for (std::set<LLFolderViewItem*>::iterator iter = selection_set.begin();
- iter != selection_set.end();
- ++iter)
- {
- LLFolderViewItem *item = *iter;
- const LLFolderViewModelItemInventory *listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
- if (!listener)
- {
- can_delete = false;
- }
- else
- {
- can_delete &= listener->isItemRemovable() && !listener->isItemInTrash();
- }
- }
- }
- }
- return can_delete;
-}
-
-/************************************************************************/
-/* Recent Inventory Panel related class */
-/************************************************************************/
-static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER;
-class LLInventoryRecentItemsPanel : public LLInventoryPanel
-{
-public:
- struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
- {};
-
- void initFromParams(const Params& p)
- {
- LLInventoryPanel::initFromParams(p);
- // turn on inbox for recent items
- getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX));
- // turn off marketplace for recent items
- getFilter().setFilterNoMarketplaceFolder();
- }
-
-protected:
- LLInventoryRecentItemsPanel (const Params&);
- friend class LLUICtrlFactory;
-};
-
-LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
-: LLInventoryPanel(params)
-{
- // replace bridge builder to have necessary View bridges.
- mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
-}
-
-static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
-
-LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
- : LLInventoryPanel(params)
-{
- mBuildChildrenViews = false;
- getFilter().setSingleFolderMode(true);
- getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
- getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
-
- mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2));
- mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2));
- mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this));
-}
-
-LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
-{
-}
-
-void LLInventorySingleFolderPanel::initFromParams(const Params& p)
-{
- mFolderID = gInventory.getRootFolderID();
-
- mParams = p;
- LLPanel::initFromParams(mParams);
-}
-
-void LLInventorySingleFolderPanel::onFocusReceived()
-{
- // Tab support, when tabbing into this view, select first item
- // (ideally needs to account for scroll)
- bool select_first = mSelectThisID.isNull() && mFolderRoot.get() && mFolderRoot.get()->getSelectedCount() == 0;
-
- if (select_first)
- {
- LLFolderViewFolder::folders_t::const_iterator folders_it = mFolderRoot.get()->getFoldersBegin();
- LLFolderViewFolder::folders_t::const_iterator folders_end = mFolderRoot.get()->getFoldersEnd();
-
- for (; folders_it != folders_end; ++folders_it)
- {
- const LLFolderViewFolder* folder_view = *folders_it;
- if (folder_view->getVisible())
- {
- const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(folder_view->getViewModelItem());
- setSelectionByID(modelp->getUUID(), true);
- // quick and dirty fix: don't scroll on switching focus
- // todo: better 'tab' support, one that would work for LLInventoryPanel
- mFolderRoot.get()->stopAutoScollining();
- select_first = false;
- break;
- }
- }
- }
-
- if (select_first)
- {
- LLFolderViewFolder::items_t::const_iterator items_it = mFolderRoot.get()->getItemsBegin();
- LLFolderViewFolder::items_t::const_iterator items_end = mFolderRoot.get()->getItemsEnd();
-
- for (; items_it != items_end; ++items_it)
- {
- const LLFolderViewItem* item_view = *items_it;
- if (item_view->getVisible())
- {
- const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(item_view->getViewModelItem());
- setSelectionByID(modelp->getUUID(), true);
- mFolderRoot.get()->stopAutoScollining();
- break;
- }
- }
- }
- LLInventoryPanel::onFocusReceived();
-}
-
-void LLInventorySingleFolderPanel::initFolderRoot(const LLUUID& start_folder_id)
-{
- if(mRootInited) return;
-
- mRootInited = true;
- if(start_folder_id.notNull())
- {
- mFolderID = start_folder_id;
- }
-
- mParams.open_first_folder = false;
- mParams.start_folder.id = mFolderID;
-
- LLInventoryPanel::initFolderRoot();
- mFolderRoot.get()->setSingleFolderMode(true);
-}
-
-void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
-{
- if (mFolderID != new_id)
- {
- if(mFolderID.notNull())
- {
- mBackwardFolders.push_back(mFolderID);
- }
- mFolderID = new_id;
- updateSingleFolderRoot();
- }
-}
-
-void LLInventorySingleFolderPanel::onForwardFolder()
-{
- if(isForwardAvailable())
- {
- mBackwardFolders.push_back(mFolderID);
- mFolderID = mForwardFolders.back();
- mForwardFolders.pop_back();
- updateSingleFolderRoot();
- }
-}
-
-void LLInventorySingleFolderPanel::onBackwardFolder()
-{
- if(isBackwardAvailable())
- {
- mForwardFolders.push_back(mFolderID);
- mFolderID = mBackwardFolders.back();
- mBackwardFolders.pop_back();
- updateSingleFolderRoot();
- }
-}
-
-void LLInventorySingleFolderPanel::clearNavigationHistory()
-{
- mForwardFolders.clear();
- mBackwardFolders.clear();
-}
-
-bool LLInventorySingleFolderPanel::isBackwardAvailable()
-{
- return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
-}
-
-bool LLInventorySingleFolderPanel::isForwardAvailable()
-{
- return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
-}
-
-boost::signals2::connection LLInventorySingleFolderPanel::setRootChangedCallback(root_changed_callback_t cb)
-{
- return mRootChangedSignal.connect(cb);
-}
-
-void LLInventorySingleFolderPanel::updateSingleFolderRoot()
-{
- if (mFolderID != getRootFolderID())
- {
- mRootChangedSignal();
-
- LLUUID root_id = mFolderID;
- if (mFolderRoot.get())
- {
- mItemMap.clear();
- mFolderRoot.get()->destroyRoot();
- }
-
- mCommitCallbackRegistrar.pushScope();
- {
- LLFolderView* folder_view = createFolderRoot(root_id);
- folder_view->setChildrenInited(false);
- mFolderRoot = folder_view->getHandle();
- mFolderRoot.get()->setSingleFolderMode(true);
- addItemID(root_id, mFolderRoot.get());
-
- LLRect scroller_view_rect = getRect();
- scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
- LLScrollContainer::Params scroller_params(mParams.scroll());
- scroller_params.rect(scroller_view_rect);
-
- if (mScroller)
- {
- removeChild(mScroller);
- delete mScroller;
- mScroller = NULL;
- }
- mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
- addChild(mScroller);
- mScroller->addChild(mFolderRoot.get());
- mFolderRoot.get()->setScrollContainer(mScroller);
- mFolderRoot.get()->setFollowsAll();
- mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
-
- if (!mSelectionCallback.empty())
- {
- mFolderRoot.get()->setSelectCallback(mSelectionCallback);
- }
- }
- mCommitCallbackRegistrar.popScope();
- mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
-
- buildNewViews(mFolderID);
-
- LLFloater* root_floater = gFloaterView->getParentFloater(this);
- if(root_floater)
- {
- root_floater->setFocus(true);
- }
- }
-}
-
-bool LLInventorySingleFolderPanel::hasVisibleItems()
-{
- return mFolderRoot.get()->hasVisibleChildren();
-}
-
-void LLInventorySingleFolderPanel::doCreate(const LLSD& userdata)
-{
- std::string type_name = userdata.asString();
- LLUUID dest_id = LLFolderBridge::sSelf.get()->getUUID();
- if (("category" == type_name) || ("outfit" == type_name))
- {
- changeFolderRoot(dest_id);
- }
- reset_inventory_filter();
- menu_create_inventory_item(this, dest_id, userdata);
-}
-
-void LLInventorySingleFolderPanel::doToSelected(const LLSD& userdata)
-{
- if (("open_in_current_window" == userdata.asString()))
- {
- changeFolderRoot(LLFolderBridge::sSelf.get()->getUUID());
- return;
- }
- LLInventoryPanel::doToSelected(userdata);
-}
-
-void LLInventorySingleFolderPanel::doShare()
-{
- LLAvatarActions::shareWithAvatars(this);
-}
-/************************************************************************/
-/* Asset Pre-Filtered Inventory Panel related class */
-/************************************************************************/
-
-LLAssetFilteredInventoryPanel::LLAssetFilteredInventoryPanel(const Params& p)
- : LLInventoryPanel(p)
-{
-}
-
-
-void LLAssetFilteredInventoryPanel::initFromParams(const Params& p)
-{
- // Init asset types
- std::string types = p.filter_asset_types.getValue();
-
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|");
- tokenizer tokens(types, sep);
- tokenizer::iterator token_iter = tokens.begin();
-
- memset(mAssetTypes, 0, LLAssetType::AT_COUNT * sizeof(bool));
- while (token_iter != tokens.end())
- {
- const std::string& token_str = *token_iter;
- LLAssetType::EType asset_type = LLAssetType::lookup(token_str);
- if (asset_type > LLAssetType::AT_NONE && asset_type < LLAssetType::AT_COUNT)
- {
- mAssetTypes[asset_type] = true;
- }
- ++token_iter;
- }
-
- // Init drag types
- memset(mDragTypes, 0, EDragAndDropType::DAD_COUNT * sizeof(bool));
- for (S32 i = 0; i < LLAssetType::AT_COUNT; i++)
- {
- if (mAssetTypes[i])
- {
- EDragAndDropType drag_type = LLViewerAssetType::lookupDragAndDropType((LLAssetType::EType)i);
- if (drag_type != DAD_NONE)
- {
- mDragTypes[drag_type] = true;
- }
- }
- }
- // Always show AT_CATEGORY, but it shouldn't get into mDragTypes
- mAssetTypes[LLAssetType::AT_CATEGORY] = true;
-
- // Init the panel
- LLInventoryPanel::initFromParams(p);
- U64 filter_cats = getFilter().getFilterCategoryTypes();
- filter_cats &= ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS);
- getFilter().setFilterCategoryTypes(filter_cats);
- getFilter().setFilterNoMarketplaceFolder();
-}
-
-bool LLAssetFilteredInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
- EDragAndDropType cargo_type,
- void* cargo_data,
- EAcceptance* accept,
- std::string& tooltip_msg)
-{
- bool result = false;
-
- if (mAcceptsDragAndDrop)
- {
- // Don't allow DAD_CATEGORY here since it can contain other items besides required assets
- // We should see everything we drop!
- if (mDragTypes[cargo_type])
- {
- result = LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
- }
- }
-
- return result;
-}
-
-/*virtual*/
-bool LLAssetFilteredInventoryPanel::typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp)
-{
- if (!objectp)
- {
- return false;
- }
- LLAssetType::EType asset_type = objectp->getType();
-
- if (asset_type < 0 || asset_type >= LLAssetType::AT_COUNT)
- {
- return false;
- }
-
- if (!mAssetTypes[asset_type])
- {
- return false;
- }
-
- return true;
-}
-
-void LLAssetFilteredInventoryPanel::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;
- }
-
- if (model_item)
- {
- LLAssetType::EType asset_type = model_item->getType();
-
- if (asset_type < 0
- || asset_type >= LLAssetType::AT_COUNT
- || !mAssetTypes[asset_type])
- {
- return;
- }
- }
-
- LLInventoryPanel::itemChanged(id, mask, model_item);
-}
-
-namespace LLInitParam
-{
- void TypeValues<LLFolderType::EType>::declareValues()
- {
- declare(LLFolderType::lookup(LLFolderType::FT_TEXTURE) , LLFolderType::FT_TEXTURE);
- declare(LLFolderType::lookup(LLFolderType::FT_SOUND) , LLFolderType::FT_SOUND);
- declare(LLFolderType::lookup(LLFolderType::FT_CALLINGCARD) , LLFolderType::FT_CALLINGCARD);
- declare(LLFolderType::lookup(LLFolderType::FT_LANDMARK) , LLFolderType::FT_LANDMARK);
- declare(LLFolderType::lookup(LLFolderType::FT_CLOTHING) , LLFolderType::FT_CLOTHING);
- declare(LLFolderType::lookup(LLFolderType::FT_OBJECT) , LLFolderType::FT_OBJECT);
- declare(LLFolderType::lookup(LLFolderType::FT_NOTECARD) , LLFolderType::FT_NOTECARD);
- declare(LLFolderType::lookup(LLFolderType::FT_ROOT_INVENTORY) , LLFolderType::FT_ROOT_INVENTORY);
- declare(LLFolderType::lookup(LLFolderType::FT_LSL_TEXT) , LLFolderType::FT_LSL_TEXT);
- declare(LLFolderType::lookup(LLFolderType::FT_BODYPART) , LLFolderType::FT_BODYPART);
- declare(LLFolderType::lookup(LLFolderType::FT_TRASH) , LLFolderType::FT_TRASH);
- declare(LLFolderType::lookup(LLFolderType::FT_SNAPSHOT_CATEGORY), LLFolderType::FT_SNAPSHOT_CATEGORY);
- declare(LLFolderType::lookup(LLFolderType::FT_LOST_AND_FOUND) , LLFolderType::FT_LOST_AND_FOUND);
- declare(LLFolderType::lookup(LLFolderType::FT_ANIMATION) , LLFolderType::FT_ANIMATION);
- declare(LLFolderType::lookup(LLFolderType::FT_GESTURE) , LLFolderType::FT_GESTURE);
- declare(LLFolderType::lookup(LLFolderType::FT_FAVORITE) , LLFolderType::FT_FAVORITE);
- declare(LLFolderType::lookup(LLFolderType::FT_ENSEMBLE_START) , LLFolderType::FT_ENSEMBLE_START);
- declare(LLFolderType::lookup(LLFolderType::FT_ENSEMBLE_END) , LLFolderType::FT_ENSEMBLE_END);
- declare(LLFolderType::lookup(LLFolderType::FT_CURRENT_OUTFIT) , LLFolderType::FT_CURRENT_OUTFIT);
- declare(LLFolderType::lookup(LLFolderType::FT_OUTFIT) , LLFolderType::FT_OUTFIT);
- declare(LLFolderType::lookup(LLFolderType::FT_MY_OUTFITS) , LLFolderType::FT_MY_OUTFITS);
- declare(LLFolderType::lookup(LLFolderType::FT_MESH ) , LLFolderType::FT_MESH );
- declare(LLFolderType::lookup(LLFolderType::FT_INBOX) , LLFolderType::FT_INBOX);
- declare(LLFolderType::lookup(LLFolderType::FT_OUTBOX) , LLFolderType::FT_OUTBOX);
- declare(LLFolderType::lookup(LLFolderType::FT_BASIC_ROOT) , LLFolderType::FT_BASIC_ROOT);
- declare(LLFolderType::lookup(LLFolderType::FT_SETTINGS) , LLFolderType::FT_SETTINGS);
- declare(LLFolderType::lookup(LLFolderType::FT_MATERIAL) , LLFolderType::FT_MATERIAL);
- declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_LISTINGS) , LLFolderType::FT_MARKETPLACE_LISTINGS);
- declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_STOCK), LLFolderType::FT_MARKETPLACE_STOCK);
- declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_VERSION), LLFolderType::FT_MARKETPLACE_VERSION);
- }
-}
+/*
+ * @file llinventorypanel.cpp
+ * @brief Implementation of the inventory panel and associated stuff.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llinventorypanel.h"
+
+#include <utility> // for std::pair<>
+
+#include "llagent.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llavataractions.h"
+#include "llclipboard.h"
+#include "llfloaterreg.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llfolderview.h"
+#include "llfolderviewitem.h"
+#include "llfloaterimcontainer.h"
+#include "llimview.h"
+#include "llinspecttexture.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llnotificationsutil.h"
+#include "llpanelmaininventory.h"
+#include "llpreview.h"
+#include "llsidepanelinventory.h"
+#include "llstartup.h"
+#include "lltrans.h"
+#include "llviewerassettype.h"
+#include "llviewerattachmenu.h"
+#include "llviewerfoldertype.h"
+#include "llvoavatarself.h"
+
+class LLInventoryRecentItemsPanel;
+class LLAssetFilteredInventoryPanel;
+
+static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
+static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
+static LLDefaultChildRegistry::Register<LLAssetFilteredInventoryPanel> t_asset_filtered_inv_panel("asset_filtered_inv_panel");
+
+const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
+const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
+const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
+static const LLInventoryFolderViewModelBuilder INVENTORY_BRIDGE_BUILDER;
+
+// statics
+bool LLInventoryPanel::sColorSetInitialized = false;
+LLUIColor LLInventoryPanel::sDefaultColor;
+LLUIColor LLInventoryPanel::sDefaultHighlightColor;
+LLUIColor LLInventoryPanel::sLibraryColor;
+LLUIColor LLInventoryPanel::sLinkColor;
+
+const LLColor4U DEFAULT_WHITE(255, 255, 255);
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryPanelObserver
+//
+// Bridge to support knowing when the inventory has changed.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInventoryPanelObserver : public LLInventoryObserver
+{
+public:
+ LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {}
+ virtual ~LLInventoryPanelObserver() {}
+ virtual void changed(U32 mask)
+ {
+ mIP->modelChanged(mask);
+ }
+protected:
+ LLInventoryPanel* mIP;
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInvPanelComplObserver
+//
+// Calls specified callback when all specified items become complete.
+//
+// Usage:
+// observer = new LLInvPanelComplObserver(boost::bind(onComplete));
+// inventory->addObserver(observer);
+// observer->reset(); // (optional)
+// observer->watchItem(incomplete_item1_id);
+// observer->watchItem(incomplete_item2_id);
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInvPanelComplObserver : public LLInventoryCompletionObserver
+{
+public:
+ typedef boost::function<void()> callback_t;
+
+ LLInvPanelComplObserver(callback_t cb)
+ : mCallback(cb)
+ {
+ }
+
+ void reset();
+
+private:
+ /*virtual*/ void done();
+
+ /// Called when all the items are complete.
+ callback_t mCallback;
+};
+
+void LLInvPanelComplObserver::reset()
+{
+ mIncomplete.clear();
+ mComplete.clear();
+}
+
+void LLInvPanelComplObserver::done()
+{
+ mCallback();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryPanel
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
+ LLPanel(p),
+ mInventoryObserver(NULL),
+ mCompletionObserver(NULL),
+ mScroller(NULL),
+ mSortOrderSetting(p.sort_order_setting),
+ mInventory(p.inventory), //inventory("", &gInventory)
+ mAcceptsDragAndDrop(p.accepts_drag_and_drop),
+ mAllowMultiSelect(p.allow_multi_select),
+ mAllowDrag(p.allow_drag),
+ mShowItemLinkOverlays(p.show_item_link_overlays),
+ mShowEmptyMessage(p.show_empty_message),
+ mSuppressFolderMenu(p.suppress_folder_menu),
+ mSuppressOpenItemAction(false),
+ mBuildViewsOnInit(p.preinitialize_views),
+ mViewsInitialized(VIEWS_UNINITIALIZED),
+ mInvFVBridgeBuilder(NULL),
+ mInventoryViewModel(p.name),
+ mGroupedItemBridge(new LLFolderViewGroupedItemBridge),
+ mFocusSelection(false),
+ mBuildChildrenViews(true),
+ mRootInited(false)
+{
+ mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
+
+ if (!sColorSetInitialized)
+ {
+ sDefaultColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
+ sDefaultHighlightColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
+ sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
+ sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
+ sColorSetInitialized = true;
+ }
+
+ // context menu callbacks
+ mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
+ mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
+ mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
+ mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2));
+ mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2));
+ 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));
+ mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
+}
+
+LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )
+{
+ LLFolderView::Params p(mParams.folder_view);
+ p.name = getName();
+ p.title = getLabel();
+ p.rect = LLRect(0, 0, getRect().getWidth(), 0);
+ p.parent_panel = this;
+ p.tool_tip = p.name;
+ p.listener = mInvFVBridgeBuilder->createBridge( LLAssetType::AT_CATEGORY,
+ LLAssetType::AT_CATEGORY,
+ LLInventoryType::IT_CATEGORY,
+ this,
+ &mInventoryViewModel,
+ NULL,
+ root_id);
+ p.view_model = &mInventoryViewModel;
+ p.grouped_item_model = mGroupedItemBridge;
+ p.use_label_suffix = mParams.use_label_suffix;
+ p.allow_multiselect = mAllowMultiSelect;
+ p.allow_drag = mAllowDrag;
+ p.show_empty_message = mShowEmptyMessage;
+ p.suppress_folder_menu = mSuppressFolderMenu;
+ p.show_item_link_overlays = mShowItemLinkOverlays;
+ p.root = NULL;
+ p.allow_drop = mParams.allow_drop_on_root;
+ p.options_menu = "menu_inventory.xml";
+
+ LLFolderView* fv = LLUICtrlFactory::create<LLFolderView>(p);
+ fv->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ fv->setEnableRegistrar(&mEnableCallbackRegistrar);
+
+ return fv;
+}
+
+void LLInventoryPanel::clearFolderRoot()
+{
+ gIdleCallbacks.deleteFunction(idle, this);
+ gIdleCallbacks.deleteFunction(onIdle, this);
+
+ if (mInventoryObserver)
+ {
+ mInventory->removeObserver(mInventoryObserver);
+ delete mInventoryObserver;
+ mInventoryObserver = NULL;
+ }
+ if (mCompletionObserver)
+ {
+ mInventory->removeObserver(mCompletionObserver);
+ delete mCompletionObserver;
+ mCompletionObserver = NULL;
+ }
+
+ if (mScroller)
+ {
+ removeChild(mScroller);
+ delete mScroller;
+ mScroller = NULL;
+ }
+}
+
+void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
+{
+ // save off copy of params
+ mParams = params;
+
+ initFolderRoot();
+
+ // Initialize base class params.
+ LLPanel::initFromParams(mParams);
+}
+
+LLInventoryPanel::~LLInventoryPanel()
+{
+ U32 sort_order = getFolderViewModel()->getSorter().getSortOrder();
+ if (mSortOrderSetting != INHERIT_SORT_ORDER)
+ {
+ gSavedSettings.setU32(mSortOrderSetting, sort_order);
+ }
+
+ clearFolderRoot();
+}
+
+void LLInventoryPanel::initFolderRoot()
+{
+ // Clear up the root view
+ // Note: This needs to be done *before* we build the new folder view
+ LLUUID root_id = getRootFolderID();
+ if (mFolderRoot.get())
+ {
+ removeItemID(root_id);
+ mFolderRoot.get()->destroyView();
+ }
+
+ mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
+ {
+ // Determine the root folder in case specified, and
+ // build the views starting with that folder.
+ LLFolderView* folder_view = createFolderRoot(root_id);
+ mFolderRoot = folder_view->getHandle();
+ mRootInited = true;
+
+ addItemID(root_id, mFolderRoot.get());
+ }
+ mCommitCallbackRegistrar.popScope();
+ mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);
+
+ // Scroller
+ LLRect scroller_view_rect = getRect();
+ scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ LLScrollContainer::Params scroller_params(mParams.scroll());
+ scroller_params.rect(scroller_view_rect);
+ mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+ addChild(mScroller);
+ mScroller->addChild(mFolderRoot.get());
+ mFolderRoot.get()->setScrollContainer(mScroller);
+ mFolderRoot.get()->setFollowsAll();
+ mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
+
+ if (mSelectionCallback)
+ {
+ mFolderRoot.get()->setSelectCallback(mSelectionCallback);
+ }
+
+ // Set up the callbacks from the inventory we're viewing, and then build everything.
+ mInventoryObserver = new LLInventoryPanelObserver(this);
+ mInventory->addObserver(mInventoryObserver);
+
+ mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
+ mInventory->addObserver(mCompletionObserver);
+
+ if (mBuildViewsOnInit)
+ {
+ initializeViewBuilding();
+ }
+
+ if (mSortOrderSetting != INHERIT_SORT_ORDER)
+ {
+ setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
+ }
+ else
+ {
+ setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
+ }
+
+ // hide inbox
+ if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible"))
+ {
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
+ }
+ // hide marketplace listing box, unless we are a marketplace panel
+ if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mParams.use_marketplace_folders)
+ {
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS));
+ }
+
+ // set the filter for the empty folder if the debug setting is on
+ if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
+ {
+ getFilter().setFilterEmptySystemFolders();
+ }
+
+ // keep track of the clipboard state so that we avoid filtering too much
+ mClipboardState = LLClipboard::instance().getGeneration();
+}
+
+void LLInventoryPanel::initializeViewBuilding()
+{
+ if (mViewsInitialized == VIEWS_UNINITIALIZED)
+ {
+ LL_DEBUGS("Inventory") << "Setting views for " << getName() << " to initialize" << LL_ENDL;
+ // Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
+ // Initializing views takes a while so always do it onIdle if viewer already loaded.
+ if (mInventory->isInventoryUsable()
+ && LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
+ {
+ // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
+ const F64 max_time = 20.f;
+ initializeViews(max_time);
+ }
+ else
+ {
+ mViewsInitialized = VIEWS_INITIALIZING;
+ gIdleCallbacks.addFunction(onIdle, (void*)this);
+ }
+ }
+}
+
+/*virtual*/
+void LLInventoryPanel::onVisibilityChange(bool new_visibility)
+{
+ if (new_visibility && mViewsInitialized == VIEWS_UNINITIALIZED)
+ {
+ // first call can be from tab initialization
+ if (gFloaterView->getParentFloater(this) != NULL)
+ {
+ initializeViewBuilding();
+ }
+ }
+ LLPanel::onVisibilityChange(new_visibility);
+}
+
+void LLInventoryPanel::draw()
+{
+ // Select the desired item (in case it wasn't loaded when the selection was requested)
+ updateSelection();
+
+ LLPanel::draw();
+}
+
+const LLInventoryFilter& LLInventoryPanel::getFilter() const
+{
+ return getFolderViewModel()->getFilter();
+}
+
+LLInventoryFilter& LLInventoryPanel::getFilter()
+{
+ return getFolderViewModel()->getFilter();
+}
+
+void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
+{
+ if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT)
+ {
+ getFilter().setFilterObjectTypes(types);
+ }
+ if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY)
+ getFilter().setFilterCategoryTypes(types);
+}
+
+void LLInventoryPanel::setFilterWorn()
+{
+ getFilter().setFilterWorn();
+}
+
+U32 LLInventoryPanel::getFilterObjectTypes() const
+{
+ return getFilter().getFilterObjectTypes();
+}
+
+U32 LLInventoryPanel::getFilterPermMask() const
+{
+ return getFilter().getFilterPermissions();
+}
+
+
+void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
+{
+ getFilter().setFilterPermissions(filter_perm_mask);
+}
+
+void LLInventoryPanel::setFilterWearableTypes(U64 types)
+{
+ getFilter().setFilterWearableTypes(types);
+}
+
+void LLInventoryPanel::setFilterSettingsTypes(U64 filter)
+{
+ getFilter().setFilterSettingsTypes(filter);
+}
+
+void LLInventoryPanel::setFilterSubString(const std::string& string)
+{
+ getFilter().setFilterSubString(string);
+}
+
+const std::string LLInventoryPanel::getFilterSubString()
+{
+ return getFilter().getFilterSubString();
+}
+
+void LLInventoryPanel::setSortOrder(U32 order)
+{
+ LLInventorySort sorter(order);
+ if (order != getFolderViewModel()->getSorter().getSortOrder())
+ {
+ getFolderViewModel()->setSorter(sorter);
+ mFolderRoot.get()->arrangeAll();
+ // try to keep selection onscreen, even if it wasn't to start with
+ mFolderRoot.get()->scrollToShowSelection();
+ }
+}
+
+U32 LLInventoryPanel::getSortOrder() const
+{
+ return getFolderViewModel()->getSorter().getSortOrder();
+}
+
+void LLInventoryPanel::setSinceLogoff(bool sl)
+{
+ getFilter().setDateRangeLastLogoff(sl);
+}
+
+void LLInventoryPanel::setHoursAgo(U32 hours)
+{
+ getFilter().setHoursAgo(hours);
+}
+
+void LLInventoryPanel::setDateSearchDirection(U32 direction)
+{
+ getFilter().setDateSearchDirection(direction);
+}
+
+void LLInventoryPanel::setFilterLinks(U64 filter_links)
+{
+ getFilter().setFilterLinks(filter_links);
+}
+
+void LLInventoryPanel::setSearchType(LLInventoryFilter::ESearchType type)
+{
+ getFilter().setSearchType(type);
+}
+
+LLInventoryFilter::ESearchType LLInventoryPanel::getSearchType()
+{
+ return getFilter().getSearchType();
+}
+
+void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
+{
+ getFilter().setShowFolderState(show);
+}
+
+LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
+{
+ return getFilter().getShowFolderState();
+}
+
+void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item)
+{
+ LLFolderViewItem* view_item = getItemByID(item_id);
+ LLFolderViewModelItemInventory* viewmodel_item =
+ static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL);
+
+ // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item
+ // to folder is the fast way to get a folder without searching through folders tree.
+ LLFolderViewFolder* view_folder = NULL;
+
+ // Check requires as this item might have already been deleted
+ // as a child of its deleted parent.
+ if (model_item && view_item)
+ {
+ view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
+ }
+
+ // if folder is not fully initialized (likely due to delayed load on idle)
+ // and we are not rebuilding, try updating children
+ if (view_folder
+ && !view_folder->areChildrenInited()
+ && ( (mask & LLInventoryObserver::REBUILD) == 0))
+ {
+ LLInventoryObject const* objectp = mInventory->getObject(item_id);
+ if (objectp)
+ {
+ view_item = buildNewViews(item_id, objectp, view_item, BUILD_ONE_FOLDER);
+ }
+ }
+
+ //////////////////////////////
+ // LABEL Operation
+ // Empty out the display name for relabel.
+ if (mask & LLInventoryObserver::LABEL)
+ {
+ if (view_item)
+ {
+ // Request refresh on this item (also flags for filtering)
+ LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getViewModelItem();
+ if(bridge)
+ {
+ // Clear the display name first, so it gets properly re-built during refresh()
+ bridge->clearDisplayName();
+
+ view_item->refresh();
+ }
+ LLFolderViewFolder* parent = view_item->getParentFolder();
+ if(parent)
+ {
+ parent->getViewModelItem()->dirtyDescendantsFilter();
+ }
+ }
+ }
+
+ //////////////////////////////
+ // REBUILD Operation
+ // Destroy and regenerate the UI.
+ if (mask & LLInventoryObserver::REBUILD)
+ {
+ if (model_item && view_item && viewmodel_item)
+ {
+ const LLUUID& idp = viewmodel_item->getUUID();
+ view_item->destroyView();
+ removeItemID(idp);
+ }
+
+ LLInventoryObject const* objectp = mInventory->getObject(item_id);
+ if (objectp)
+ {
+ // providing NULL directly avoids unnessesary getItemByID calls
+ view_item = buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);
+ }
+ else
+ {
+ view_item = NULL;
+ }
+
+ viewmodel_item =
+ static_cast<LLFolderViewModelItemInventory*>(view_item ? view_item->getViewModelItem() : NULL);
+ view_folder = dynamic_cast<LLFolderViewFolder *>(view_item);
+ }
+
+ //////////////////////////////
+ // INTERNAL Operation
+ // This could be anything. For now, just refresh the item.
+ if (mask & LLInventoryObserver::INTERNAL)
+ {
+ if (view_item)
+ {
+ view_item->refresh();
+ }
+ }
+
+ //////////////////////////////
+ // SORT Operation
+ // Sort the folder.
+ if (mask & LLInventoryObserver::SORT)
+ {
+ if (view_folder)
+ {
+ view_folder->getViewModelItem()->requestSort();
+ }
+ }
+
+ // 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
+ // panel). What's relevant is that the item and UI are probably out of sync and thus need to be
+ // resynchronized.
+ if (mask & (LLInventoryObserver::STRUCTURE |
+ LLInventoryObserver::ADD |
+ LLInventoryObserver::REMOVE))
+ {
+ //////////////////////////////
+ // ADD Operation
+ // Item exists in memory but a UI element hasn't been created for it.
+ if (model_item && !view_item)
+ {
+ // Add the UI element for this item.
+ LLInventoryObject const* objectp = mInventory->getObject(item_id);
+ if (objectp)
+ {
+ // providing NULL directly avoids unnessesary getItemByID calls
+ buildNewViews(item_id, objectp, NULL, BUILD_ONE_FOLDER);
+ }
+
+ // Select any newly created object that has the auto rename at top of folder root set.
+ if(mFolderRoot.get()->getRoot()->needsAutoRename())
+ {
+ setSelection(item_id, false);
+ }
+ updateFolderLabel(model_item->getParentUUID());
+ }
+
+ //////////////////////////////
+ // STRUCTURE Operation
+ // This item already exists in both memory and UI. It was probably reparented.
+ else if (model_item && view_item)
+ {
+ LLFolderViewFolder* old_parent = view_item->getParentFolder();
+ // Don't process the item if it is the root
+ if (old_parent)
+ {
+ LLFolderViewModelItemInventory* viewmodel_folder = static_cast<LLFolderViewModelItemInventory*>(old_parent->getViewModelItem());
+ LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID());
+ // Item has been moved.
+ if (old_parent != new_parent)
+ {
+ if (new_parent != NULL)
+ {
+ // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
+ view_item->addToFolder(new_parent);
+ addItemID(viewmodel_item->getUUID(), view_item);
+ if (mInventory)
+ {
+ const LLUUID trash_id = mInventory->findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if (trash_id != model_item->getParentUUID() && (mask & LLInventoryObserver::INTERNAL) && new_parent->isOpen())
+ {
+ setSelection(item_id, false);
+ }
+ }
+ updateFolderLabel(model_item->getParentUUID());
+ }
+ else
+ {
+ // Remove the item ID before destroying the view because the view-model-item gets
+ // destroyed when the view is destroyed
+ removeItemID(viewmodel_item->getUUID());
+
+ // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that
+ // doesn't include trash). Just remove the item's UI.
+ view_item->destroyView();
+ }
+ if(viewmodel_folder)
+ {
+ updateFolderLabel(viewmodel_folder->getUUID());
+ }
+ old_parent->getViewModelItem()->dirtyDescendantsFilter();
+ }
+ }
+ }
+
+ //////////////////////////////
+ // REMOVE Operation
+ // This item has been removed from memory, but its associated UI element still exists.
+ else if (!model_item && view_item && viewmodel_item)
+ {
+ // Remove the item's UI.
+ LLFolderViewFolder* parent = view_item->getParentFolder();
+ 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());
+ }
+ }
+ }
+ }
+}
+
+// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849)
+void LLInventoryPanel::modelChanged(U32 mask)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ if (mViewsInitialized != VIEWS_INITIALIZED) return;
+
+ const LLInventoryModel* model = getModel();
+ if (!model) return;
+
+ const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs();
+ if (changed_items.empty()) return;
+
+ for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
+ items_iter != changed_items.end();
+ ++items_iter)
+ {
+ const LLUUID& item_id = (*items_iter);
+ const LLInventoryObject* model_item = model->getObject(item_id);
+ itemChanged(item_id, mask, model_item);
+ }
+}
+
+LLUUID LLInventoryPanel::getRootFolderID()
+{
+ LLUUID root_id;
+ if (mFolderRoot.get() && mFolderRoot.get()->getViewModelItem())
+ {
+ root_id = static_cast<LLFolderViewModelItemInventory*>(mFolderRoot.get()->getViewModelItem())->getUUID();
+ }
+ else
+ {
+ if (mParams.start_folder.id.isChosen())
+ {
+ root_id = mParams.start_folder.id;
+ }
+ else
+ {
+ const LLFolderType::EType preferred_type = mParams.start_folder.type.isChosen()
+ ? mParams.start_folder.type
+ : LLViewerFolderType::lookupTypeFromNewCategoryName(mParams.start_folder.name);
+
+ if ("LIBRARY" == mParams.start_folder.name())
+ {
+ root_id = gInventory.getLibraryRootFolderID();
+ }
+ else if (preferred_type != LLFolderType::FT_NONE)
+ {
+ LLStringExplicit label(mParams.start_folder.name());
+ setLabel(label);
+
+ root_id = gInventory.findCategoryUUIDForType(preferred_type);
+ if (root_id.isNull())
+ {
+ LL_WARNS() << "Could not find folder of type " << preferred_type << LL_ENDL;
+ root_id.generateNewID();
+ }
+ }
+ }
+ }
+ return root_id;
+}
+
+// static
+void LLInventoryPanel::onIdle(void *userdata)
+{
+ if (!gInventory.isInventoryUsable())
+ return;
+
+ LLInventoryPanel *self = (LLInventoryPanel*)userdata;
+ if (self->mViewsInitialized <= VIEWS_INITIALIZING)
+ {
+ const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders
+ self->initializeViews(max_time); // Shedules LLInventoryPanel::idle()
+ }
+ if (self->mViewsInitialized >= VIEWS_BUILDING)
+ {
+ gIdleCallbacks.deleteFunction(onIdle, (void*)self);
+ }
+}
+
+struct DirtyFilterFunctor : public LLFolderViewFunctor
+{
+ /*virtual*/ void doFolder(LLFolderViewFolder* folder)
+ {
+ folder->getViewModelItem()->dirtyFilter();
+ }
+ /*virtual*/ void doItem(LLFolderViewItem* item)
+ {
+ item->getViewModelItem()->dirtyFilter();
+ }
+};
+
+void LLInventoryPanel::idle(void* user_data)
+{
+ LLInventoryPanel* panel = (LLInventoryPanel*)user_data;
+ // Nudge the filter if the clipboard state changed
+ if (panel->mClipboardState != LLClipboard::instance().getGeneration())
+ {
+ panel->mClipboardState = LLClipboard::instance().getGeneration();
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLFolderViewFolder* trash_folder = panel->getFolderByID(trash_id);
+ if (trash_folder)
+ {
+ DirtyFilterFunctor dirtyFilterFunctor;
+ trash_folder->applyFunctorToChildren(dirtyFilterFunctor);
+ }
+
+ }
+
+ bool in_visible_chain = panel->isInVisibleChain();
+
+ if (!panel->mBuildViewsQueue.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;
+
+ // things added last are closer to root thus of higher priority
+ std::deque<LLUUID> priority_list;
+ priority_list.swap(panel->mBuildViewsQueue);
+
+ while (curent_time < panel->mBuildViewsEndTime
+ && !priority_list.empty())
+ {
+ LLUUID item_id = priority_list.back();
+ priority_list.pop_back();
+
+ LLInventoryObject const* objectp = panel->mInventory->getObject(item_id);
+ if (objectp && panel->typedViewsFilter(item_id, objectp))
+ {
+ LLFolderViewItem* folder_view_item = panel->getItemByID(item_id);
+ if (!folder_view_item || !folder_view_item->areChildrenInited())
+ {
+ const LLUUID &parent_id = objectp->getParentUUID();
+ LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id);
+ panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT);
+ }
+ }
+ curent_time = LLTimer::getTotalSeconds();
+ }
+ while (!priority_list.empty())
+ {
+ // items in priority_list are of higher priority
+ panel->mBuildViewsQueue.push_back(priority_list.front());
+ priority_list.pop_front();
+ }
+ if (panel->mBuildViewsQueue.empty())
+ {
+ panel->mViewsInitialized = VIEWS_INITIALIZED;
+ }
+ }
+
+ // Take into account the fact that the root folder might be invalidated
+ if (panel->mFolderRoot.get())
+ {
+ panel->mFolderRoot.get()->update();
+ // while dragging, update selection rendering to reflect single/multi drag status
+ if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
+ {
+ EAcceptance last_accept = LLToolDragAndDrop::getInstance()->getLastAccept();
+ if (last_accept == ACCEPT_YES_SINGLE || last_accept == ACCEPT_YES_COPY_SINGLE)
+ {
+ panel->mFolderRoot.get()->setShowSingleSelection(true);
+ }
+ else
+ {
+ panel->mFolderRoot.get()->setShowSingleSelection(false);
+ }
+ }
+ else
+ {
+ panel->mFolderRoot.get()->setShowSingleSelection(false);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "Inventory : Deleted folder root detected on panel" << LL_ENDL;
+ panel->clearFolderRoot();
+ }
+}
+
+
+void LLInventoryPanel::initializeViews(F64 max_time)
+{
+ if (!gInventory.isInventoryUsable()) return;
+ if (!mRootInited) return;
+
+ mViewsInitialized = VIEWS_BUILDING;
+
+ F64 curent_time = LLTimer::getTotalSeconds();
+ mBuildViewsEndTime = curent_time + max_time;
+
+ // init everything
+ LLUUID root_id = getRootFolderID();
+ if (root_id.notNull())
+ {
+ buildNewViews(getRootFolderID());
+ }
+ else
+ {
+ // Default case: always add "My Inventory" root first, "Library" root second
+ // If we run out of time, this still should create root folders
+ buildNewViews(gInventory.getRootFolderID()); // My Inventory
+ buildNewViews(gInventory.getLibraryRootFolderID()); // Library
+ }
+
+ if (mBuildViewsQueue.empty())
+ {
+ mViewsInitialized = VIEWS_INITIALIZED;
+ }
+
+ gIdleCallbacks.addFunction(idle, this);
+
+ if(mParams.open_first_folder)
+ {
+ openStartFolderOrMyInventory();
+ }
+
+ // Special case for new user login
+ if (gAgent.isFirstLogin())
+ {
+ // Auto open the user's library
+ LLFolderViewFolder* lib_folder = getFolderByID(gInventory.getLibraryRootFolderID());
+ if (lib_folder)
+ {
+ lib_folder->setOpen(true);
+ }
+
+ // Auto close the user's my inventory folder
+ LLFolderViewFolder* my_inv_folder = getFolderByID(gInventory.getRootFolderID());
+ if (my_inv_folder)
+ {
+ my_inv_folder->setOpenArrangeRecursively(false, LLFolderViewFolder::RECURSE_DOWN);
+ }
+ }
+}
+
+
+LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge, bool allow_drop)
+{
+ LLFolderViewFolder::Params params(mParams.folder);
+
+ params.name = bridge->getDisplayName();
+ params.root = mFolderRoot.get();
+ params.listener = bridge;
+ params.tool_tip = params.name;
+ params.allow_drop = allow_drop;
+
+ params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+ params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
+
+ return LLUICtrlFactory::create<LLFolderViewFolder>(params);
+}
+
+LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge)
+{
+ LLFolderViewItem::Params params(mParams.item);
+
+ params.name = bridge->getDisplayName();
+ params.creation_date = bridge->getCreationDate();
+ params.root = mFolderRoot.get();
+ params.listener = bridge;
+ params.rect = LLRect (0, 0, 0, 0);
+ params.tool_tip = params.name;
+
+ params.font_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultColor);
+ params.font_highlight_color = (bridge->isLibraryItem() ? sLibraryColor : sDefaultHighlightColor);
+
+ return LLUICtrlFactory::create<LLFolderViewItem>(params);
+}
+
+LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
+{
+ LLInventoryObject const* objectp = mInventory->getObject(id);
+ return buildNewViews(id, objectp);
+}
+
+LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryObject const* objectp)
+{
+ if (!objectp)
+ {
+ return NULL;
+ }
+ if (!typedViewsFilter(id, objectp))
+ {
+ // if certain types are not allowed permanently, no reason to create views
+ return NULL;
+ }
+
+ const LLUUID &parent_id = objectp->getParentUUID();
+ LLFolderViewItem* folder_view_item = getItemByID(id);
+ LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id);
+
+ return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, BUILD_TIMELIMIT);
+}
+
+LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id,
+ LLInventoryObject const* objectp,
+ LLFolderViewItem *folder_view_item,
+ const EBuildModes &mode)
+{
+ if (!objectp)
+ {
+ return NULL;
+ }
+ if (!typedViewsFilter(id, objectp))
+ {
+ // if certain types are not allowed permanently, no reason to create views
+ return NULL;
+ }
+
+ const LLUUID &parent_id = objectp->getParentUUID();
+ LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)getItemByID(parent_id);
+
+ return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder, mode);
+}
+
+LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
+ const LLUUID& parent_id,
+ LLInventoryObject const* objectp,
+ LLFolderViewItem *folder_view_item,
+ LLFolderViewFolder *parent_folder,
+ const EBuildModes &mode,
+ S32 depth)
+{
+ depth++;
+
+ // Force the creation of an extra root level folder item if required by the inventory panel (default is "false")
+ bool allow_drop = true;
+ bool create_root = false;
+ if (mParams.show_root_folder)
+ {
+ LLUUID root_id = getRootFolderID();
+ if (root_id == id)
+ {
+ // We insert an extra level that's seen by the UI but has no influence on the model
+ parent_folder = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
+ folder_view_item = NULL;
+ allow_drop = mParams.allow_drop_on_root;
+ create_root = true;
+ }
+ }
+
+ if (!folder_view_item && parent_folder)
+ {
+ if (objectp->getType() <= LLAssetType::AT_NONE)
+ {
+ LL_WARNS() << "LLInventoryPanel::buildViewsTree called with invalid objectp->mType : "
+ << ((S32)objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
+ << LL_ENDL;
+ return NULL;
+ }
+
+ if (objectp->getType() >= LLAssetType::AT_COUNT)
+ {
+ // Example: Happens when we add assets of new, not yet supported type to library
+ LL_DEBUGS("Inventory") << "LLInventoryPanel::buildViewsTree called with unknown objectp->mType : "
+ << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
+ << LL_ENDL;
+
+ LLInventoryItem* item = (LLInventoryItem*)objectp;
+ if (item)
+ {
+ LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_UNKNOWN,
+ LLAssetType::AT_UNKNOWN,
+ LLInventoryType::IT_UNKNOWN,
+ this,
+ &mInventoryViewModel,
+ mFolderRoot.get(),
+ item->getUUID(),
+ item->getFlags());
+
+ if (new_listener)
+ {
+ folder_view_item = createFolderViewItem(new_listener);
+ }
+ }
+ }
+
+ if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
+ (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER))
+ {
+ LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY,
+ (mParams.use_marketplace_folders ? LLAssetType::AT_MARKETPLACE_FOLDER : LLAssetType::AT_CATEGORY),
+ LLInventoryType::IT_CATEGORY,
+ this,
+ &mInventoryViewModel,
+ mFolderRoot.get(),
+ objectp->getUUID());
+ if (new_listener)
+ {
+ folder_view_item = createFolderViewFolder(new_listener,allow_drop);
+ }
+ }
+ else
+ {
+ // Build new view for item.
+ LLInventoryItem* item = (LLInventoryItem*)objectp;
+ LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(),
+ item->getActualType(),
+ item->getInventoryType(),
+ this,
+ &mInventoryViewModel,
+ mFolderRoot.get(),
+ item->getUUID(),
+ item->getFlags());
+
+ if (new_listener)
+ {
+ folder_view_item = createFolderViewItem(new_listener);
+ }
+ }
+
+ if (folder_view_item)
+ {
+ llassert(parent_folder != NULL);
+ folder_view_item->addToFolder(parent_folder);
+ addItemID(id, folder_view_item);
+ // In the case of the root folder been shown, open that folder by default once the widget is created
+ if (create_root)
+ {
+ folder_view_item->setOpen(true);
+ }
+ }
+ }
+
+ bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY
+ && (mBuildChildrenViews || depth == 0);
+
+ if (create_children)
+ {
+ switch (mode)
+ {
+ case BUILD_TIMELIMIT:
+ {
+ F64 curent_time = LLTimer::getTotalSeconds();
+ // If function is out of time, we want to shedule it into mBuildViewsQueue
+ // If we have time, no matter how little, create views for all children
+ //
+ // This creates children in 'bulk' to make sure folder has either
+ // 'empty and incomplete' or 'complete' states with nothing in between.
+ // Folders are marked as mIsFolderComplete == false by default,
+ // later arrange() will update mIsFolderComplete by child count
+ if (mBuildViewsEndTime < curent_time)
+ {
+ create_children = false;
+ // run it again for the sake of creating children
+ if (mBuildChildrenViews || depth == 0)
+ {
+ mBuildViewsQueue.push_back(id);
+ }
+ }
+ else
+ {
+ create_children = true;
+ folder_view_item->setChildrenInited(mBuildChildrenViews);
+ }
+ break;
+ }
+ case BUILD_NO_CHILDREN:
+ {
+ create_children = false;
+ // run it to create children, current caller is only interested in current view
+ if (mBuildChildrenViews || depth == 0)
+ {
+ mBuildViewsQueue.push_back(id);
+ }
+ break;
+ }
+ case BUILD_ONE_FOLDER:
+ {
+ // This view loads chindren, following ones don't
+ // Note: Might be better idea to do 'depth' instead,
+ // It also will help to prioritize root folder's content
+ create_children = true;
+ folder_view_item->setChildrenInited(true);
+ break;
+ }
+ case BUILD_NO_LIMIT:
+ default:
+ {
+ // keep working till everything exists
+ create_children = true;
+ folder_view_item->setChildrenInited(true);
+ }
+ }
+ }
+
+ // If this is a folder, add the children of the folder and recursively add any
+ // child folders.
+ if (create_children)
+ {
+ LLViewerInventoryCategory::cat_array_t* categories;
+ LLViewerInventoryItem::item_array_t* items;
+ mInventory->lockDirectDescendentArrays(id, categories, items);
+
+ // Make sure panel won't lock in a loop over existing items if
+ // folder is enormous and at least some work gets done
+ const S32 MIN_ITEMS_PER_CALL = 500;
+ const S32 starting_item_count = mItemMap.size();
+
+ LLFolderViewFolder *parentp = dynamic_cast<LLFolderViewFolder*>(folder_view_item);
+ bool done = true;
+
+ if(categories)
+ {
+ bool has_folders = parentp->getFoldersCount() > 0;
+ for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin();
+ cat_iter != categories->end();
+ ++cat_iter)
+ {
+ const LLViewerInventoryCategory* cat = (*cat_iter);
+ if (typedViewsFilter(cat->getUUID(), cat))
+ {
+ if (has_folders)
+ {
+ // This can be optimized: we don't need to call getItemByID()
+ // each time, especially since content is growing, we can just
+ // iter over copy of mItemMap in some way
+ LLFolderViewItem* view_itemp = getItemByID(cat->getUUID());
+ buildViewsTree(cat->getUUID(), id, cat, view_itemp, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
+ }
+ else
+ {
+ buildViewsTree(cat->getUUID(), id, cat, NULL, parentp, (mode == BUILD_ONE_FOLDER ? BUILD_NO_CHILDREN : mode), depth);
+ }
+ }
+
+ if (!mBuildChildrenViews
+ && mode == BUILD_TIMELIMIT
+ && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
+ {
+ // Single folder view, check if we still have time
+ //
+ // Todo: make sure this causes no dupplciates, breaks nothing,
+ // especially filters and arrange
+ F64 curent_time = LLTimer::getTotalSeconds();
+ if (mBuildViewsEndTime < curent_time)
+ {
+ mBuildViewsQueue.push_back(id);
+ done = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if(items)
+ {
+ for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin();
+ item_iter != items->end();
+ ++item_iter)
+ {
+ // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime
+ const LLViewerInventoryItem* item = (*item_iter);
+ if (typedViewsFilter(item->getUUID(), item))
+ {
+ // This can be optimized: we don't need to call getItemByID()
+ // each time, especially since content is growing, we can just
+ // iter over copy of mItemMap in some way
+ LLFolderViewItem* view_itemp = getItemByID(item->getUUID());
+ buildViewsTree(item->getUUID(), id, item, view_itemp, parentp, mode, depth);
+ }
+
+ if (!mBuildChildrenViews
+ && mode == BUILD_TIMELIMIT
+ && MIN_ITEMS_PER_CALL + starting_item_count < mItemMap.size())
+ {
+ // Single folder view, check if we still have time
+ //
+ // Todo: make sure this causes no dupplciates, breaks nothing,
+ // especially filters and arrange
+ F64 curent_time = LLTimer::getTotalSeconds();
+ if (mBuildViewsEndTime < curent_time)
+ {
+ mBuildViewsQueue.push_back(id);
+ done = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!mBuildChildrenViews && done)
+ {
+ // flat list is done initializing folder
+ folder_view_item->setChildrenInited(true);
+ }
+ mInventory->unlockDirectDescendentArrays(id);
+ }
+
+ return folder_view_item;
+}
+
+// bit of a hack to make sure the inventory is open.
+void LLInventoryPanel::openStartFolderOrMyInventory()
+{
+ // Find My Inventory folder and open it up by name
+ for (LLView *child = mFolderRoot.get()->getFirstChild(); child; child = mFolderRoot.get()->findNextSibling(child))
+ {
+ LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child);
+ if (fchild
+ && fchild->getViewModelItem()
+ && fchild->getViewModelItem()->getName() == "My Inventory")
+ {
+ fchild->setOpen(true);
+ break;
+ }
+ }
+}
+
+void LLInventoryPanel::onItemsCompletion()
+{
+ if (mFolderRoot.get()) mFolderRoot.get()->updateMenu();
+}
+
+void LLInventoryPanel::openSelected()
+{
+ LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
+ if(!folder_item) return;
+ LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+ if(!bridge) return;
+ bridge->openItem();
+}
+
+void LLInventoryPanel::unSelectAll()
+{
+ mFolderRoot.get()->setSelection(NULL, false, false);
+}
+
+
+bool LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
+{
+ bool handled = LLView::handleHover(x, y, mask);
+ if(handled)
+ {
+ // getCursor gets current cursor, setCursor sets next cursor
+ // check that children didn't set own 'next' cursor
+ ECursorType cursor = getWindow()->getNextCursor();
+ if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW)
+ {
+ // replace arrow cursor with arrow and hourglass cursor
+ getWindow()->setCursor(UI_CURSOR_WORKING);
+ }
+ }
+ else
+ {
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+ }
+ return true;
+}
+
+bool LLInventoryPanel::handleToolTip(S32 x, S32 y, MASK mask)
+{
+ if (const LLFolderViewItem* hover_item_p = (!mFolderRoot.isDead()) ? mFolderRoot.get()->getHoveredItem() : nullptr)
+ {
+ if (const LLFolderViewModelItemInventory* vm_item_p = static_cast<const LLFolderViewModelItemInventory*>(hover_item_p->getViewModelItem()))
+ {
+ LLSD params;
+ params["inv_type"] = vm_item_p->getInventoryType();
+ params["thumbnail_id"] = vm_item_p->getThumbnailUUID();
+ params["item_id"] = vm_item_p->getUUID();
+
+ // tooltip should only show over folder, but screen
+ // rect includes items under folder as well
+ LLRect actionable_rect = hover_item_p->calcScreenRect();
+ if (hover_item_p->isOpen() && hover_item_p->hasVisibleChildren())
+ {
+ actionable_rect.mBottom = actionable_rect.mTop - hover_item_p->getItemHeight();
+ }
+
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(hover_item_p->getToolTip())
+ .sticky_rect(actionable_rect)
+ .delay_time(LLView::getTooltipTimeout())
+ .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1))
+ .create_params(params));
+ return true;
+ }
+ }
+ return LLPanel::handleToolTip(x, y, mask);
+}
+
+bool LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ bool handled = false;
+
+ if (mAcceptsDragAndDrop)
+ {
+ handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+
+ // If folder view is empty the (x, y) point won't be in its rect
+ // so the handler must be called explicitly.
+ // but only if was not handled before. See EXT-6746.
+ if (!handled && mParams.allow_drop_on_root && !mFolderRoot.get()->hasVisibleChildren())
+ {
+ handled = mFolderRoot.get()->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+ }
+
+ if (handled)
+ {
+ mFolderRoot.get()->setDragAndDropThisFrame();
+ }
+ }
+
+ return handled;
+}
+
+void LLInventoryPanel::onFocusLost()
+{
+ // inventory no longer handles cut/copy/paste/delete
+ if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot.get())
+ {
+ LLEditMenuHandler::gEditMenuHandler = NULL;
+ }
+
+ LLPanel::onFocusLost();
+}
+
+void LLInventoryPanel::onFocusReceived()
+{
+ // inventory now handles cut/copy/paste/delete
+ LLEditMenuHandler::gEditMenuHandler = mFolderRoot.get();
+
+ LLPanel::onFocusReceived();
+}
+
+void LLInventoryPanel::onFolderOpening(const LLUUID &id)
+{
+ LLFolderViewItem* folder = getItemByID(id);
+ if (folder && !folder->areChildrenInited())
+ {
+ // Last item in list will be processed first.
+ // This might result in dupplicates in list, but it
+ // isn't critical, views won't be created twice
+ mBuildViewsQueue.push_back(id);
+ }
+}
+
+bool LLInventoryPanel::addBadge(LLBadge * badge)
+{
+ bool badge_added = false;
+
+ if (acceptsBadge())
+ {
+ badge_added = badge->addToView(mFolderRoot.get());
+ }
+
+ return badge_added;
+}
+
+void LLInventoryPanel::openAllFolders()
+{
+ mFolderRoot.get()->setOpenArrangeRecursively(true, LLFolderViewFolder::RECURSE_DOWN);
+ mFolderRoot.get()->arrangeAll();
+}
+
+void LLInventoryPanel::setSelection(const LLUUID& obj_id, bool take_keyboard_focus)
+{
+ // Don't select objects in COF (e.g. to prevent refocus when items are worn).
+ const LLInventoryObject *obj = mInventory->getObject(obj_id);
+ if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())
+ {
+ return;
+ }
+ setSelectionByID(obj_id, take_keyboard_focus);
+}
+
+void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, bool user_action)>& cb)
+{
+ if (mFolderRoot.get())
+ {
+ mFolderRoot.get()->setSelectCallback(cb);
+ }
+ mSelectionCallback = cb;
+}
+
+void LLInventoryPanel::clearSelection()
+{
+ mSelectThisID.setNull();
+ mFocusSelection = false;
+}
+
+LLInventoryPanel::selected_items_t LLInventoryPanel::getSelectedItems() const
+{
+ return mFolderRoot.get()->getSelectionList();
+}
+
+void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, bool user_action)
+{
+ // Schedule updating the folder view context menu when all selected items become complete (STORM-373).
+ mCompletionObserver->reset();
+ for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
+ {
+ LLFolderViewModelItemInventory* view_model = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem());
+ if (view_model)
+ {
+ LLUUID id = view_model->getUUID();
+ if (!(*it)->areChildrenInited())
+ {
+ const F64 max_time = 0.0001f;
+ mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time;
+ buildNewViews(id);
+ }
+ LLViewerInventoryItem* inv_item = mInventory->getItem(id);
+
+ if (inv_item && !inv_item->isFinished())
+ {
+ mCompletionObserver->watchItem(id);
+ }
+ }
+ }
+
+ LLFolderView* fv = mFolderRoot.get();
+ if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
+ {
+ fv->setNeedsAutoRename(false);
+ if (items.size()) // new asset is visible and selected
+ {
+ fv->startRenamingSelectedItem();
+ }
+ else
+ {
+ LL_DEBUGS("Inventory") << "Failed to start renemr, no items selected" << LL_ENDL;
+ }
+ }
+
+ std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
+ LLFolderViewItem* prev_folder_item = getItemByID(mPreviousSelectedFolder);
+
+ if (selected_items.size() == 1)
+ {
+ std::set<LLFolderViewItem*>::const_iterator iter = selected_items.begin();
+ LLFolderViewItem* folder_item = (*iter);
+ if(folder_item && (folder_item != prev_folder_item))
+ {
+ LLFolderViewModelItemInventory* fve_listener = static_cast<LLFolderViewModelItemInventory*>(folder_item->getViewModelItem());
+ if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
+ {
+ if (fve_listener->getInventoryObject() && fve_listener->getInventoryObject()->getIsLinkType())
+ {
+ return;
+ }
+
+ if(prev_folder_item)
+ {
+ LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
+ if(prev_bridge)
+ {
+ prev_bridge->clearDisplayName();
+ prev_bridge->setShowDescendantsCount(false);
+ prev_folder_item->refresh();
+ }
+ }
+
+ LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
+ if(bridge)
+ {
+ bridge->clearDisplayName();
+ bridge->setShowDescendantsCount(true);
+ folder_item->refresh();
+ mPreviousSelectedFolder = bridge->getUUID();
+ }
+ }
+ }
+ }
+ else
+ {
+ if(prev_folder_item)
+ {
+ LLFolderBridge* prev_bridge = (LLFolderBridge*)prev_folder_item->getViewModelItem();
+ if(prev_bridge)
+ {
+ prev_bridge->clearDisplayName();
+ prev_bridge->setShowDescendantsCount(false);
+ prev_folder_item->refresh();
+ }
+ }
+ mPreviousSelectedFolder = LLUUID();
+ }
+
+}
+
+void LLInventoryPanel::updateFolderLabel(const LLUUID& folder_id)
+{
+ if(folder_id != mPreviousSelectedFolder) return;
+
+ LLFolderViewItem* folder_item = getItemByID(mPreviousSelectedFolder);
+ if(folder_item)
+ {
+ LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
+ if(bridge)
+ {
+ bridge->clearDisplayName();
+ bridge->setShowDescendantsCount(true);
+ folder_item->refresh();
+ }
+ }
+}
+
+void LLInventoryPanel::doCreate(const LLSD& userdata)
+{
+ reset_inventory_filter();
+ menu_create_inventory_item(this, LLFolderBridge::sSelf.get(), userdata);
+}
+
+bool LLInventoryPanel::beginIMSession()
+{
+ std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
+
+ std::string name;
+
+ std::vector<LLUUID> members;
+ EInstantMessage type = IM_SESSION_CONFERENCE_START;
+
+ std::set<LLFolderViewItem*>::const_iterator iter;
+ for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
+ {
+
+ LLFolderViewItem* folder_item = (*iter);
+
+ if(folder_item)
+ {
+ LLFolderViewModelItemInventory* fve_listener = static_cast<LLFolderViewModelItemInventory*>(folder_item->getViewModelItem());
+ if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
+ {
+
+ LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getViewModelItem();
+ if(!bridge) return true;
+ LLViewerInventoryCategory* cat = bridge->getCategory();
+ if(!cat) return true;
+ name = cat->getName();
+ LLUniqueBuddyCollector is_buddy;
+ LLInventoryModel::cat_array_t cat_array;
+ LLInventoryModel::item_array_t item_array;
+ gInventory.collectDescendentsIf(bridge->getUUID(),
+ cat_array,
+ item_array,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_buddy);
+ S32 count = item_array.size();
+ if(count > 0)
+ {
+ //*TODO by what to replace that?
+ //LLFloaterReg::showInstance("communicate");
+
+ // create the session
+ LLAvatarTracker& at = LLAvatarTracker::instance();
+ LLUUID id;
+ for(S32 i = 0; i < count; ++i)
+ {
+ id = item_array.at(i)->getCreatorUUID();
+ if(at.isBuddyOnline(id))
+ {
+ members.push_back(id);
+ }
+ }
+ }
+ }
+ else
+ {
+ LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getViewModelItem();
+
+ if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
+ {
+ LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID());
+
+ if (inv_item)
+ {
+ LLAvatarTracker& at = LLAvatarTracker::instance();
+ LLUUID id = inv_item->getCreatorUUID();
+
+ if(at.isBuddyOnline(id))
+ {
+ members.push_back(id);
+ }
+ }
+ } //if IT_CALLINGCARD
+ } //if !IT_CATEGORY
+ }
+ } //for selected_items
+
+ // the session_id is randomly generated UUID which will be replaced later
+ // with a server side generated number
+
+ if (name.empty())
+ {
+ name = LLTrans::getString("conference-title");
+ }
+
+ LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
+ if (session_id != LLUUID::null)
+ {
+ LLFloaterIMContainer::getInstance()->showConversation(session_id);
+ }
+
+ return true;
+}
+
+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());
+ }
+}
+
+void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
+{
+ LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);
+}
+
+void LLInventoryPanel::purgeSelectedItems()
+{
+ if (!mFolderRoot.get()) return;
+
+ const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList();
+ if (inventory_selected.empty()) return;
+ LLSD args;
+ S32 count = inventory_selected.size();
+ std::vector<LLUUID> selected_items;
+ for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end();
+ it != end_it;
+ ++it)
+ {
+ LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID();
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH);
+ count += items.size() + cats.size();
+ selected_items.push_back(item_id);
+ }
+ args["COUNT"] = count;
+ LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(callbackPurgeSelectedItems, _1, _2, selected_items));
+}
+
+// static
+void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ if (inventory_selected.empty()) return;
+
+ for (auto it : inventory_selected)
+ {
+ remove_inventory_object(it, NULL);
+ }
+ }
+}
+
+bool LLInventoryPanel::attachObject(const LLSD& userdata)
+{
+ // Copy selected item UUIDs to a vector.
+ std::set<LLFolderViewItem*> selected_items = mFolderRoot.get()->getSelectionList();
+ uuid_vec_t items;
+ for (std::set<LLFolderViewItem*>::const_iterator set_iter = selected_items.begin();
+ set_iter != selected_items.end();
+ ++set_iter)
+ {
+ items.push_back(static_cast<LLFolderViewModelItemInventory*>((*set_iter)->getViewModelItem())->getUUID());
+ }
+
+ // Attach selected items.
+ LLViewerAttachMenu::attachObjects(items, userdata.asString());
+
+ gFocusMgr.setKeyboardFocus(NULL);
+
+ return true;
+}
+
+bool LLInventoryPanel::getSinceLogoff()
+{
+ return getFilter().isSinceLogoff();
+}
+
+// DEBUG ONLY
+// static
+void LLInventoryPanel::dumpSelectionInformation(void* user_data)
+{
+ LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
+ iv->mFolderRoot.get()->dumpSelectionInformation();
+}
+
+bool is_inventorysp_active()
+{
+ LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+ if (!sidepanel_inventory || !sidepanel_inventory->isInVisibleChain()) return false;
+ return sidepanel_inventory->isMainInventoryPanelActive();
+}
+
+// static
+LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(bool auto_open)
+{
+ S32 z_min = S32_MAX;
+ LLInventoryPanel* res = NULL;
+ LLFloater* active_inv_floaterp = NULL;
+
+ LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+ if (!floater_inventory)
+ {
+ LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL;
+ return nullptr;
+ }
+
+ LLSidepanelInventory *inventory_panel = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+
+ // Iterate through the inventory floaters and return whichever is on top.
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
+ inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+
+ if (inventory_floater && inventory_panel && inventory_floater->getVisible())
+ {
+ S32 z_order = gFloaterView->getZOrder(inventory_floater);
+ if (z_order < z_min)
+ {
+ res = inventory_panel->getActivePanel();
+ z_min = z_order;
+ active_inv_floaterp = inventory_floater;
+ }
+ }
+ }
+
+ if (res)
+ {
+ // Make sure the floater is not minimized (STORM-438).
+ if (active_inv_floaterp && active_inv_floaterp->isMinimized())
+ {
+ active_inv_floaterp->setMinimized(false);
+ }
+ }
+ else if (auto_open)
+ {
+ floater_inventory->openFloater();
+
+ res = inventory_panel->getActivePanel();
+ }
+
+ return res;
+}
+
+//static
+void LLInventoryPanel::openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id,
+ bool use_main_panel, bool take_keyboard_focus, bool reset_filter)
+{
+ LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
+ sidepanel_inventory->showInventoryPanel();
+
+ LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
+ bool in_inbox = gInventory.isObjectDescendentOf(obj_id, cat_id);
+ if (!in_inbox && use_main_panel)
+ {
+ sidepanel_inventory->selectAllItemsPanel();
+ }
+
+ if (!auto_open)
+ {
+ LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
+ if (inventory_floater && inventory_floater->getVisible())
+ {
+ LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+ LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
+ if (main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
+ {
+ LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
+ main_panel->setGallerySelection(obj_id);
+ return;
+ }
+ }
+ }
+
+ if (use_main_panel)
+ {
+ LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+ if (main_inventory && main_inventory->isSingleFolderMode())
+ {
+ const LLInventoryObject *obj = gInventory.getObject(obj_id);
+ if (obj)
+ {
+ LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
+ main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
+ main_inventory->setGallerySelection(obj_id);
+ return;
+ }
+ }
+ }
+
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
+ if (active_panel)
+ {
+ LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL;
+
+ if (reset_filter)
+ {
+ reset_inventory_filter();
+ }
+
+ if (in_inbox)
+ {
+ sidepanel_inventory->openInbox();
+ LLInventoryPanel* inventory_panel = sidepanel_inventory->getInboxPanel();
+ if (inventory_panel)
+ {
+ inventory_panel->setSelection(obj_id, take_keyboard_focus);
+ }
+ }
+ else if (auto_open)
+ {
+ LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
+ if (floater_inventory)
+ {
+ floater_inventory->setFocus(true);
+ }
+ active_panel->setSelection(obj_id, take_keyboard_focus);
+ }
+ else
+ {
+ // Created items are going to receive proper focus from callbacks
+ active_panel->setSelection(obj_id, take_keyboard_focus);
+ }
+ }
+}
+
+void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
+{
+ LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
+ for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
+ {
+ LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
+ LLSidepanelInventory* sidepanel_inventory = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
+
+ LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
+ if (main_inventory && panel->hasAncestor(main_inventory) && !main_inventory->isSingleFolderMode())
+ {
+ main_inventory->initSingleFolderRoot(folder_id);
+ main_inventory->toggleViewMode();
+ main_inventory->setSingleFolderViewRoot(folder_id, false);
+ }
+ }
+}
+
+void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
+{
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type));
+}
+
+bool LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const
+{
+ return !(getFilter().getFilterCategoryTypes() & (1ULL << folder_type));
+}
+
+void LLInventoryPanel::addItemID( const LLUUID& id, LLFolderViewItem* itemp )
+{
+ mItemMap[id] = itemp;
+}
+
+void LLInventoryPanel::removeItemID(const LLUUID& id)
+{
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(id, categories, items, true);
+
+ mItemMap.erase(id);
+
+ for (LLInventoryModel::cat_array_t::iterator it = categories.begin(), end_it = categories.end();
+ it != end_it;
+ ++it)
+ {
+ mItemMap.erase((*it)->getUUID());
+}
+
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(), end_it = items.end();
+ it != end_it;
+ ++it)
+ {
+ mItemMap.erase((*it)->getUUID());
+ }
+}
+
+LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
+ map_it = mItemMap.find(id);
+ if (map_it != mItemMap.end())
+ {
+ return map_it->second;
+ }
+
+ return NULL;
+}
+
+LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id)
+{
+ LLFolderViewItem* item = getItemByID(id);
+ return dynamic_cast<LLFolderViewFolder*>(item);
+}
+
+
+void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, bool take_keyboard_focus )
+{
+ LLFolderViewItem* itemp = getItemByID(obj_id);
+
+ if (itemp && !itemp->areChildrenInited())
+ {
+ LLInventoryObject const* objectp = mInventory->getObject(obj_id);
+ if (objectp)
+ {
+ buildNewViews(obj_id, objectp, itemp, BUILD_ONE_FOLDER);
+ }
+ }
+
+ if(itemp && itemp->getViewModelItem())
+ {
+ itemp->arrangeAndSet(true, take_keyboard_focus);
+ mSelectThisID.setNull();
+ mFocusSelection = false;
+ return;
+ }
+ else
+ {
+ // save the desired item to be selected later (if/when ready)
+ mFocusSelection = take_keyboard_focus;
+ mSelectThisID = obj_id;
+ }
+}
+
+void LLInventoryPanel::updateSelection()
+{
+ if (mSelectThisID.notNull())
+ {
+ setSelectionByID(mSelectThisID, mFocusSelection);
+ }
+}
+
+void LLInventoryPanel::doToSelected(const LLSD& userdata)
+{
+ if (("purge" == userdata.asString()))
+ {
+ purgeSelectedItems();
+ return;
+ }
+ LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), userdata.asString());
+
+ return;
+}
+
+bool LLInventoryPanel::handleKeyHere( KEY key, MASK mask )
+{
+ bool handled = false;
+ switch (key)
+ {
+ case KEY_RETURN:
+ // Open selected items if enter key hit on the inventory panel
+ if (mask == MASK_NONE)
+ {
+ if (mSuppressOpenItemAction)
+ {
+ LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem();
+ if(folder_item)
+ {
+ LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem();
+ if(bridge && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY))
+ {
+ return handled;
+ }
+ }
+ }
+ LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open");
+ handled = true;
+ }
+ break;
+ case KEY_DELETE:
+#if LL_DARWIN
+ case KEY_BACKSPACE:
+#endif
+ // Delete selected items if delete or backspace key hit on the inventory panel
+ // Note: on Mac laptop keyboards, backspace and delete are one and the same
+ if (isSelectionRemovable() && (mask == MASK_NONE))
+ {
+ LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "delete");
+ handled = true;
+ }
+ break;
+ }
+ return handled;
+}
+
+bool LLInventoryPanel::isSelectionRemovable()
+{
+ bool can_delete = false;
+ if (mFolderRoot.get())
+ {
+ std::set<LLFolderViewItem*> selection_set = mFolderRoot.get()->getSelectionList();
+ if (!selection_set.empty())
+ {
+ can_delete = true;
+ for (std::set<LLFolderViewItem*>::iterator iter = selection_set.begin();
+ iter != selection_set.end();
+ ++iter)
+ {
+ LLFolderViewItem *item = *iter;
+ const LLFolderViewModelItemInventory *listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
+ if (!listener)
+ {
+ can_delete = false;
+ }
+ else
+ {
+ can_delete &= listener->isItemRemovable() && !listener->isItemInTrash();
+ }
+ }
+ }
+ }
+ return can_delete;
+}
+
+/************************************************************************/
+/* Recent Inventory Panel related class */
+/************************************************************************/
+static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER;
+class LLInventoryRecentItemsPanel : public LLInventoryPanel
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
+ {};
+
+ void initFromParams(const Params& p)
+ {
+ LLInventoryPanel::initFromParams(p);
+ // turn on inbox for recent items
+ getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX));
+ // turn off marketplace for recent items
+ getFilter().setFilterNoMarketplaceFolder();
+ }
+
+protected:
+ LLInventoryRecentItemsPanel (const Params&);
+ friend class LLUICtrlFactory;
+};
+
+LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
+: LLInventoryPanel(params)
+{
+ // replace bridge builder to have necessary View bridges.
+ mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
+}
+
+static LLDefaultChildRegistry::Register<LLInventorySingleFolderPanel> t_single_folder_inventory_panel("single_folder_inventory_panel");
+
+LLInventorySingleFolderPanel::LLInventorySingleFolderPanel(const Params& params)
+ : LLInventoryPanel(params)
+{
+ mBuildChildrenViews = false;
+ getFilter().setSingleFolderMode(true);
+ getFilter().setEmptyLookupMessage("InventorySingleFolderNoMatches");
+ getFilter().setDefaultEmptyLookupMessage("InventorySingleFolderEmpty");
+
+ mCommitCallbackRegistrar.replace("Inventory.DoToSelected", boost::bind(&LLInventorySingleFolderPanel::doToSelected, this, _2));
+ mCommitCallbackRegistrar.replace("Inventory.DoCreate", boost::bind(&LLInventorySingleFolderPanel::doCreate, this, _2));
+ mCommitCallbackRegistrar.replace("Inventory.Share", boost::bind(&LLInventorySingleFolderPanel::doShare, this));
+}
+
+LLInventorySingleFolderPanel::~LLInventorySingleFolderPanel()
+{
+}
+
+void LLInventorySingleFolderPanel::initFromParams(const Params& p)
+{
+ mFolderID = gInventory.getRootFolderID();
+
+ mParams = p;
+ LLPanel::initFromParams(mParams);
+}
+
+void LLInventorySingleFolderPanel::onFocusReceived()
+{
+ // Tab support, when tabbing into this view, select first item
+ // (ideally needs to account for scroll)
+ bool select_first = mSelectThisID.isNull() && mFolderRoot.get() && mFolderRoot.get()->getSelectedCount() == 0;
+
+ if (select_first)
+ {
+ LLFolderViewFolder::folders_t::const_iterator folders_it = mFolderRoot.get()->getFoldersBegin();
+ LLFolderViewFolder::folders_t::const_iterator folders_end = mFolderRoot.get()->getFoldersEnd();
+
+ for (; folders_it != folders_end; ++folders_it)
+ {
+ const LLFolderViewFolder* folder_view = *folders_it;
+ if (folder_view->getVisible())
+ {
+ const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(folder_view->getViewModelItem());
+ setSelectionByID(modelp->getUUID(), true);
+ // quick and dirty fix: don't scroll on switching focus
+ // todo: better 'tab' support, one that would work for LLInventoryPanel
+ mFolderRoot.get()->stopAutoScollining();
+ select_first = false;
+ break;
+ }
+ }
+ }
+
+ if (select_first)
+ {
+ LLFolderViewFolder::items_t::const_iterator items_it = mFolderRoot.get()->getItemsBegin();
+ LLFolderViewFolder::items_t::const_iterator items_end = mFolderRoot.get()->getItemsEnd();
+
+ for (; items_it != items_end; ++items_it)
+ {
+ const LLFolderViewItem* item_view = *items_it;
+ if (item_view->getVisible())
+ {
+ const LLFolderViewModelItemInventory* modelp = static_cast<const LLFolderViewModelItemInventory*>(item_view->getViewModelItem());
+ setSelectionByID(modelp->getUUID(), true);
+ mFolderRoot.get()->stopAutoScollining();
+ break;
+ }
+ }
+ }
+ LLInventoryPanel::onFocusReceived();
+}
+
+void LLInventorySingleFolderPanel::initFolderRoot(const LLUUID& start_folder_id)
+{
+ if(mRootInited) return;
+
+ mRootInited = true;
+ if(start_folder_id.notNull())
+ {
+ mFolderID = start_folder_id;
+ }
+
+ mParams.open_first_folder = false;
+ mParams.start_folder.id = mFolderID;
+
+ LLInventoryPanel::initFolderRoot();
+ mFolderRoot.get()->setSingleFolderMode(true);
+}
+
+void LLInventorySingleFolderPanel::changeFolderRoot(const LLUUID& new_id)
+{
+ if (mFolderID != new_id)
+ {
+ if(mFolderID.notNull())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ }
+ mFolderID = new_id;
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::onForwardFolder()
+{
+ if(isForwardAvailable())
+ {
+ mBackwardFolders.push_back(mFolderID);
+ mFolderID = mForwardFolders.back();
+ mForwardFolders.pop_back();
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::onBackwardFolder()
+{
+ if(isBackwardAvailable())
+ {
+ mForwardFolders.push_back(mFolderID);
+ mFolderID = mBackwardFolders.back();
+ mBackwardFolders.pop_back();
+ updateSingleFolderRoot();
+ }
+}
+
+void LLInventorySingleFolderPanel::clearNavigationHistory()
+{
+ mForwardFolders.clear();
+ mBackwardFolders.clear();
+}
+
+bool LLInventorySingleFolderPanel::isBackwardAvailable()
+{
+ return (!mBackwardFolders.empty() && (mFolderID != mBackwardFolders.back()));
+}
+
+bool LLInventorySingleFolderPanel::isForwardAvailable()
+{
+ return (!mForwardFolders.empty() && (mFolderID != mForwardFolders.back()));
+}
+
+boost::signals2::connection LLInventorySingleFolderPanel::setRootChangedCallback(root_changed_callback_t cb)
+{
+ return mRootChangedSignal.connect(cb);
+}
+
+void LLInventorySingleFolderPanel::updateSingleFolderRoot()
+{
+ if (mFolderID != getRootFolderID())
+ {
+ mRootChangedSignal();
+
+ LLUUID root_id = mFolderID;
+ if (mFolderRoot.get())
+ {
+ mItemMap.clear();
+ mFolderRoot.get()->destroyRoot();
+ }
+
+ mCommitCallbackRegistrar.pushScope();
+ {
+ LLFolderView* folder_view = createFolderRoot(root_id);
+ folder_view->setChildrenInited(false);
+ mFolderRoot = folder_view->getHandle();
+ mFolderRoot.get()->setSingleFolderMode(true);
+ addItemID(root_id, mFolderRoot.get());
+
+ LLRect scroller_view_rect = getRect();
+ scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ LLScrollContainer::Params scroller_params(mParams.scroll());
+ scroller_params.rect(scroller_view_rect);
+
+ if (mScroller)
+ {
+ removeChild(mScroller);
+ delete mScroller;
+ mScroller = NULL;
+ }
+ mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+ addChild(mScroller);
+ mScroller->addChild(mFolderRoot.get());
+ mFolderRoot.get()->setScrollContainer(mScroller);
+ mFolderRoot.get()->setFollowsAll();
+ mFolderRoot.get()->addChild(mFolderRoot.get()->mStatusTextBox);
+
+ if (!mSelectionCallback.empty())
+ {
+ mFolderRoot.get()->setSelectCallback(mSelectionCallback);
+ }
+ }
+ mCommitCallbackRegistrar.popScope();
+ mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar);
+
+ buildNewViews(mFolderID);
+
+ LLFloater* root_floater = gFloaterView->getParentFloater(this);
+ if(root_floater)
+ {
+ root_floater->setFocus(true);
+ }
+ }
+}
+
+bool LLInventorySingleFolderPanel::hasVisibleItems()
+{
+ return mFolderRoot.get()->hasVisibleChildren();
+}
+
+void LLInventorySingleFolderPanel::doCreate(const LLSD& userdata)
+{
+ std::string type_name = userdata.asString();
+ LLUUID dest_id = LLFolderBridge::sSelf.get()->getUUID();
+ if (("category" == type_name) || ("outfit" == type_name))
+ {
+ changeFolderRoot(dest_id);
+ }
+ reset_inventory_filter();
+ menu_create_inventory_item(this, dest_id, userdata);
+}
+
+void LLInventorySingleFolderPanel::doToSelected(const LLSD& userdata)
+{
+ if (("open_in_current_window" == userdata.asString()))
+ {
+ changeFolderRoot(LLFolderBridge::sSelf.get()->getUUID());
+ return;
+ }
+ LLInventoryPanel::doToSelected(userdata);
+}
+
+void LLInventorySingleFolderPanel::doShare()
+{
+ LLAvatarActions::shareWithAvatars(this);
+}
+/************************************************************************/
+/* Asset Pre-Filtered Inventory Panel related class */
+/************************************************************************/
+
+LLAssetFilteredInventoryPanel::LLAssetFilteredInventoryPanel(const Params& p)
+ : LLInventoryPanel(p)
+{
+}
+
+
+void LLAssetFilteredInventoryPanel::initFromParams(const Params& p)
+{
+ // Init asset types
+ std::string types = p.filter_asset_types.getValue();
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|");
+ tokenizer tokens(types, sep);
+ tokenizer::iterator token_iter = tokens.begin();
+
+ memset(mAssetTypes, 0, LLAssetType::AT_COUNT * sizeof(bool));
+ while (token_iter != tokens.end())
+ {
+ const std::string& token_str = *token_iter;
+ LLAssetType::EType asset_type = LLAssetType::lookup(token_str);
+ if (asset_type > LLAssetType::AT_NONE && asset_type < LLAssetType::AT_COUNT)
+ {
+ mAssetTypes[asset_type] = true;
+ }
+ ++token_iter;
+ }
+
+ // Init drag types
+ memset(mDragTypes, 0, EDragAndDropType::DAD_COUNT * sizeof(bool));
+ for (S32 i = 0; i < LLAssetType::AT_COUNT; i++)
+ {
+ if (mAssetTypes[i])
+ {
+ EDragAndDropType drag_type = LLViewerAssetType::lookupDragAndDropType((LLAssetType::EType)i);
+ if (drag_type != DAD_NONE)
+ {
+ mDragTypes[drag_type] = true;
+ }
+ }
+ }
+ // Always show AT_CATEGORY, but it shouldn't get into mDragTypes
+ mAssetTypes[LLAssetType::AT_CATEGORY] = true;
+
+ // Init the panel
+ LLInventoryPanel::initFromParams(p);
+ U64 filter_cats = getFilter().getFilterCategoryTypes();
+ filter_cats &= ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS);
+ getFilter().setFilterCategoryTypes(filter_cats);
+ getFilter().setFilterNoMarketplaceFolder();
+}
+
+bool LLAssetFilteredInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, bool drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ EAcceptance* accept,
+ std::string& tooltip_msg)
+{
+ bool result = false;
+
+ if (mAcceptsDragAndDrop)
+ {
+ // Don't allow DAD_CATEGORY here since it can contain other items besides required assets
+ // We should see everything we drop!
+ if (mDragTypes[cargo_type])
+ {
+ result = LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+ }
+ }
+
+ return result;
+}
+
+/*virtual*/
+bool LLAssetFilteredInventoryPanel::typedViewsFilter(const LLUUID& id, LLInventoryObject const* objectp)
+{
+ if (!objectp)
+ {
+ return false;
+ }
+ LLAssetType::EType asset_type = objectp->getType();
+
+ if (asset_type < 0 || asset_type >= LLAssetType::AT_COUNT)
+ {
+ return false;
+ }
+
+ if (!mAssetTypes[asset_type])
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void LLAssetFilteredInventoryPanel::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;
+ }
+
+ if (model_item)
+ {
+ LLAssetType::EType asset_type = model_item->getType();
+
+ if (asset_type < 0
+ || asset_type >= LLAssetType::AT_COUNT
+ || !mAssetTypes[asset_type])
+ {
+ return;
+ }
+ }
+
+ LLInventoryPanel::itemChanged(id, mask, model_item);
+}
+
+namespace LLInitParam
+{
+ void TypeValues<LLFolderType::EType>::declareValues()
+ {
+ declare(LLFolderType::lookup(LLFolderType::FT_TEXTURE) , LLFolderType::FT_TEXTURE);
+ declare(LLFolderType::lookup(LLFolderType::FT_SOUND) , LLFolderType::FT_SOUND);
+ declare(LLFolderType::lookup(LLFolderType::FT_CALLINGCARD) , LLFolderType::FT_CALLINGCARD);
+ declare(LLFolderType::lookup(LLFolderType::FT_LANDMARK) , LLFolderType::FT_LANDMARK);
+ declare(LLFolderType::lookup(LLFolderType::FT_CLOTHING) , LLFolderType::FT_CLOTHING);
+ declare(LLFolderType::lookup(LLFolderType::FT_OBJECT) , LLFolderType::FT_OBJECT);
+ declare(LLFolderType::lookup(LLFolderType::FT_NOTECARD) , LLFolderType::FT_NOTECARD);
+ declare(LLFolderType::lookup(LLFolderType::FT_ROOT_INVENTORY) , LLFolderType::FT_ROOT_INVENTORY);
+ declare(LLFolderType::lookup(LLFolderType::FT_LSL_TEXT) , LLFolderType::FT_LSL_TEXT);
+ declare(LLFolderType::lookup(LLFolderType::FT_BODYPART) , LLFolderType::FT_BODYPART);
+ declare(LLFolderType::lookup(LLFolderType::FT_TRASH) , LLFolderType::FT_TRASH);
+ declare(LLFolderType::lookup(LLFolderType::FT_SNAPSHOT_CATEGORY), LLFolderType::FT_SNAPSHOT_CATEGORY);
+ declare(LLFolderType::lookup(LLFolderType::FT_LOST_AND_FOUND) , LLFolderType::FT_LOST_AND_FOUND);
+ declare(LLFolderType::lookup(LLFolderType::FT_ANIMATION) , LLFolderType::FT_ANIMATION);
+ declare(LLFolderType::lookup(LLFolderType::FT_GESTURE) , LLFolderType::FT_GESTURE);
+ declare(LLFolderType::lookup(LLFolderType::FT_FAVORITE) , LLFolderType::FT_FAVORITE);
+ declare(LLFolderType::lookup(LLFolderType::FT_ENSEMBLE_START) , LLFolderType::FT_ENSEMBLE_START);
+ declare(LLFolderType::lookup(LLFolderType::FT_ENSEMBLE_END) , LLFolderType::FT_ENSEMBLE_END);
+ declare(LLFolderType::lookup(LLFolderType::FT_CURRENT_OUTFIT) , LLFolderType::FT_CURRENT_OUTFIT);
+ declare(LLFolderType::lookup(LLFolderType::FT_OUTFIT) , LLFolderType::FT_OUTFIT);
+ declare(LLFolderType::lookup(LLFolderType::FT_MY_OUTFITS) , LLFolderType::FT_MY_OUTFITS);
+ declare(LLFolderType::lookup(LLFolderType::FT_MESH ) , LLFolderType::FT_MESH );
+ declare(LLFolderType::lookup(LLFolderType::FT_INBOX) , LLFolderType::FT_INBOX);
+ declare(LLFolderType::lookup(LLFolderType::FT_OUTBOX) , LLFolderType::FT_OUTBOX);
+ declare(LLFolderType::lookup(LLFolderType::FT_BASIC_ROOT) , LLFolderType::FT_BASIC_ROOT);
+ declare(LLFolderType::lookup(LLFolderType::FT_SETTINGS) , LLFolderType::FT_SETTINGS);
+ declare(LLFolderType::lookup(LLFolderType::FT_MATERIAL) , LLFolderType::FT_MATERIAL);
+ declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_LISTINGS) , LLFolderType::FT_MARKETPLACE_LISTINGS);
+ declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_STOCK), LLFolderType::FT_MARKETPLACE_STOCK);
+ declare(LLFolderType::lookup(LLFolderType::FT_MARKETPLACE_VERSION), LLFolderType::FT_MARKETPLACE_VERSION);
+ }
+}