PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llinventorypanel.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1244 lines | 917 code | 194 blank | 133 comment | 159 complexity | 87378bb3e05079b6d3d7b886bcdb2829 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * @file llinventorypanel.cpp
  3. * @brief Implementation of the inventory panel and associated stuff.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llinventorypanel.h"
  28. #include <utility> // for std::pair<>
  29. #include "llagent.h"
  30. #include "llagentwearables.h"
  31. #include "llappearancemgr.h"
  32. #include "llavataractions.h"
  33. #include "llfloaterinventory.h"
  34. #include "llfloaterreg.h"
  35. #include "llfloatersidepanelcontainer.h"
  36. #include "llfolderview.h"
  37. #include "llimfloater.h"
  38. #include "llimview.h"
  39. #include "llinventorybridge.h"
  40. #include "llinventoryfunctions.h"
  41. #include "llinventorymodelbackgroundfetch.h"
  42. #include "llsidepanelinventory.h"
  43. #include "llviewerattachmenu.h"
  44. #include "llviewerfoldertype.h"
  45. #include "llvoavatarself.h"
  46. static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
  47. const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
  48. const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
  49. const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
  50. static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER;
  51. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  52. // Class LLInventoryPanelObserver
  53. //
  54. // Bridge to support knowing when the inventory has changed.
  55. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  56. class LLInventoryPanelObserver : public LLInventoryObserver
  57. {
  58. public:
  59. LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {}
  60. virtual ~LLInventoryPanelObserver() {}
  61. virtual void changed(U32 mask)
  62. {
  63. mIP->modelChanged(mask);
  64. }
  65. protected:
  66. LLInventoryPanel* mIP;
  67. };
  68. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  69. // Class LLInvPanelComplObserver
  70. //
  71. // Calls specified callback when all specified items become complete.
  72. //
  73. // Usage:
  74. // observer = new LLInvPanelComplObserver(boost::bind(onComplete));
  75. // inventory->addObserver(observer);
  76. // observer->reset(); // (optional)
  77. // observer->watchItem(incomplete_item1_id);
  78. // observer->watchItem(incomplete_item2_id);
  79. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  80. class LLInvPanelComplObserver : public LLInventoryCompletionObserver
  81. {
  82. public:
  83. typedef boost::function<void()> callback_t;
  84. LLInvPanelComplObserver(callback_t cb)
  85. : mCallback(cb)
  86. {
  87. }
  88. void reset();
  89. private:
  90. /*virtual*/ void done();
  91. /// Called when all the items are complete.
  92. callback_t mCallback;
  93. };
  94. void LLInvPanelComplObserver::reset()
  95. {
  96. mIncomplete.clear();
  97. mComplete.clear();
  98. }
  99. void LLInvPanelComplObserver::done()
  100. {
  101. mCallback();
  102. }
  103. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  104. // Class LLInventoryPanel
  105. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  106. LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
  107. LLPanel(p),
  108. mInventoryObserver(NULL),
  109. mCompletionObserver(NULL),
  110. mFolderRoot(NULL),
  111. mScroller(NULL),
  112. mSortOrderSetting(p.sort_order_setting),
  113. mInventory(p.inventory),
  114. mAcceptsDragAndDrop(p.accepts_drag_and_drop),
  115. mAllowMultiSelect(p.allow_multi_select),
  116. mShowItemLinkOverlays(p.show_item_link_overlays),
  117. mShowEmptyMessage(p.show_empty_message),
  118. mShowLoadStatus(p.show_load_status),
  119. mViewsInitialized(false),
  120. mInvFVBridgeBuilder(NULL)
  121. {
  122. mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
  123. // contex menu callbacks
  124. mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
  125. mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
  126. mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
  127. mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2));
  128. mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2));
  129. mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
  130. mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars));
  131. }
  132. void LLInventoryPanel::buildFolderView(const LLInventoryPanel::Params& params)
  133. {
  134. // Determine the root folder in case specified, and
  135. // build the views starting with that folder.
  136. std::string start_folder_name(params.start_folder());
  137. const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(start_folder_name);
  138. LLUUID root_id;
  139. if ("LIBRARY" == params.start_folder())
  140. {
  141. root_id = gInventory.getLibraryRootFolderID();
  142. }
  143. else
  144. {
  145. root_id = (preferred_type != LLFolderType::FT_NONE)
  146. ? gInventory.findCategoryUUIDForType(preferred_type, false, false)
  147. : LLUUID::null;
  148. }
  149. if ((root_id == LLUUID::null) && !start_folder_name.empty())
  150. {
  151. llwarns << "No category found that matches start_folder: " << start_folder_name << llendl;
  152. root_id = LLUUID::generateNewID();
  153. }
  154. LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY,
  155. LLAssetType::AT_CATEGORY,
  156. LLInventoryType::IT_CATEGORY,
  157. this,
  158. NULL,
  159. root_id);
  160. mFolderRoot = createFolderView(new_listener, params.use_label_suffix());
  161. }
  162. void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
  163. {
  164. LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD);
  165. mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
  166. buildFolderView(params);
  167. mCommitCallbackRegistrar.popScope();
  168. mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
  169. // Scroller
  170. {
  171. LLRect scroller_view_rect = getRect();
  172. scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
  173. LLScrollContainer::Params scroller_params(params.scroll());
  174. scroller_params.rect(scroller_view_rect);
  175. mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroller_params);
  176. addChild(mScroller);
  177. mScroller->addChild(mFolderRoot);
  178. mFolderRoot->setScrollContainer(mScroller);
  179. mFolderRoot->addChild(mFolderRoot->mStatusTextBox);
  180. }
  181. // Set up the callbacks from the inventory we're viewing, and then build everything.
  182. mInventoryObserver = new LLInventoryPanelObserver(this);
  183. mInventory->addObserver(mInventoryObserver);
  184. mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
  185. mInventory->addObserver(mCompletionObserver);
  186. // Build view of inventory if we need default full hierarchy and inventory ready,
  187. // otherwise wait for idle callback.
  188. if (mInventory->isInventoryUsable() && !mViewsInitialized)
  189. {
  190. initializeViews();
  191. }
  192. gIdleCallbacks.addFunction(onIdle, (void*)this);
  193. if (mSortOrderSetting != INHERIT_SORT_ORDER)
  194. {
  195. setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
  196. }
  197. else
  198. {
  199. setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
  200. }
  201. // hide inbox
  202. getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
  203. getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX));
  204. // set the filter for the empty folder if the debug setting is on
  205. if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
  206. {
  207. getFilter()->setFilterEmptySystemFolders();
  208. }
  209. // Initialize base class params.
  210. LLPanel::initFromParams(params);
  211. }
  212. LLInventoryPanel::~LLInventoryPanel()
  213. {
  214. if (mFolderRoot)
  215. {
  216. U32 sort_order = mFolderRoot->getSortOrder();
  217. if (mSortOrderSetting != INHERIT_SORT_ORDER)
  218. {
  219. gSavedSettings.setU32(mSortOrderSetting, sort_order);
  220. }
  221. }
  222. gIdleCallbacks.deleteFunction(onIdle, this);
  223. // LLView destructor will take care of the sub-views.
  224. mInventory->removeObserver(mInventoryObserver);
  225. mInventory->removeObserver(mCompletionObserver);
  226. delete mInventoryObserver;
  227. delete mCompletionObserver;
  228. mScroller = NULL;
  229. }
  230. void LLInventoryPanel::draw()
  231. {
  232. // Select the desired item (in case it wasn't loaded when the selection was requested)
  233. mFolderRoot->updateSelection();
  234. LLPanel::draw();
  235. }
  236. LLInventoryFilter* LLInventoryPanel::getFilter()
  237. {
  238. if (mFolderRoot)
  239. {
  240. return mFolderRoot->getFilter();
  241. }
  242. return NULL;
  243. }
  244. const LLInventoryFilter* LLInventoryPanel::getFilter() const
  245. {
  246. if (mFolderRoot)
  247. {
  248. return mFolderRoot->getFilter();
  249. }
  250. return NULL;
  251. }
  252. void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
  253. {
  254. if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT)
  255. getFilter()->setFilterObjectTypes(types);
  256. if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY)
  257. getFilter()->setFilterCategoryTypes(types);
  258. }
  259. U32 LLInventoryPanel::getFilterObjectTypes() const
  260. {
  261. return mFolderRoot->getFilterObjectTypes();
  262. }
  263. U32 LLInventoryPanel::getFilterPermMask() const
  264. {
  265. return mFolderRoot->getFilterPermissions();
  266. }
  267. void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
  268. {
  269. getFilter()->setFilterPermissions(filter_perm_mask);
  270. }
  271. void LLInventoryPanel::setFilterWearableTypes(U64 types)
  272. {
  273. getFilter()->setFilterWearableTypes(types);
  274. }
  275. void LLInventoryPanel::setFilterSubString(const std::string& string)
  276. {
  277. getFilter()->setFilterSubString(string);
  278. }
  279. const std::string LLInventoryPanel::getFilterSubString()
  280. {
  281. return mFolderRoot->getFilterSubString();
  282. }
  283. void LLInventoryPanel::setSortOrder(U32 order)
  284. {
  285. getFilter()->setSortOrder(order);
  286. if (getFilter()->isModified())
  287. {
  288. mFolderRoot->setSortOrder(order);
  289. // try to keep selection onscreen, even if it wasn't to start with
  290. mFolderRoot->scrollToShowSelection();
  291. }
  292. }
  293. U32 LLInventoryPanel::getSortOrder() const
  294. {
  295. return mFolderRoot->getSortOrder();
  296. }
  297. void LLInventoryPanel::requestSort()
  298. {
  299. mFolderRoot->requestSort();
  300. }
  301. void LLInventoryPanel::setSinceLogoff(BOOL sl)
  302. {
  303. getFilter()->setDateRangeLastLogoff(sl);
  304. }
  305. void LLInventoryPanel::setHoursAgo(U32 hours)
  306. {
  307. getFilter()->setHoursAgo(hours);
  308. }
  309. void LLInventoryPanel::setFilterLinks(U64 filter_links)
  310. {
  311. getFilter()->setFilterLinks(filter_links);
  312. }
  313. void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
  314. {
  315. getFilter()->setShowFolderState(show);
  316. }
  317. LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
  318. {
  319. return getFilter()->getShowFolderState();
  320. }
  321. void LLInventoryPanel::modelChanged(U32 mask)
  322. {
  323. static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh");
  324. LLFastTimer t2(FTM_REFRESH);
  325. bool handled = false;
  326. if (!mViewsInitialized) return;
  327. const LLInventoryModel* model = getModel();
  328. if (!model) return;
  329. const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs();
  330. if (changed_items.empty()) return;
  331. for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
  332. items_iter != changed_items.end();
  333. ++items_iter)
  334. {
  335. const LLUUID& item_id = (*items_iter);
  336. const LLInventoryObject* model_item = model->getObject(item_id);
  337. LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id);
  338. // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item
  339. // to folder is the fast way to get a folder without searching through folders tree.
  340. LLFolderViewFolder* view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
  341. //////////////////////////////
  342. // LABEL Operation
  343. // Empty out the display name for relabel.
  344. if (mask & LLInventoryObserver::LABEL)
  345. {
  346. handled = true;
  347. if (view_item)
  348. {
  349. // Request refresh on this item (also flags for filtering)
  350. LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getListener();
  351. if(bridge)
  352. { // Clear the display name first, so it gets properly re-built during refresh()
  353. bridge->clearDisplayName();
  354. view_item->refresh();
  355. }
  356. }
  357. }
  358. //////////////////////////////
  359. // REBUILD Operation
  360. // Destroy and regenerate the UI.
  361. if (mask & LLInventoryObserver::REBUILD)
  362. {
  363. handled = true;
  364. if (model_item && view_item)
  365. {
  366. view_item->destroyView();
  367. }
  368. view_item = buildNewViews(item_id);
  369. view_folder = dynamic_cast<LLFolderViewFolder *>(view_item);
  370. }
  371. //////////////////////////////
  372. // INTERNAL Operation
  373. // This could be anything. For now, just refresh the item.
  374. if (mask & LLInventoryObserver::INTERNAL)
  375. {
  376. if (view_item)
  377. {
  378. view_item->refresh();
  379. }
  380. }
  381. //////////////////////////////
  382. // SORT Operation
  383. // Sort the folder.
  384. if (mask & LLInventoryObserver::SORT)
  385. {
  386. if (view_folder)
  387. {
  388. view_folder->requestSort();
  389. }
  390. }
  391. // We don't typically care which of these masks the item is actually flagged with, since the masks
  392. // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into
  393. // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks
  394. // panel). What's relevant is that the item and UI are probably out of sync and thus need to be
  395. // resynchronized.
  396. if (mask & (LLInventoryObserver::STRUCTURE |
  397. LLInventoryObserver::ADD |
  398. LLInventoryObserver::REMOVE))
  399. {
  400. handled = true;
  401. //////////////////////////////
  402. // ADD Operation
  403. // Item exists in memory but a UI element hasn't been created for it.
  404. if (model_item && !view_item)
  405. {
  406. // Add the UI element for this item.
  407. buildNewViews(item_id);
  408. // Select any newly created object that has the auto rename at top of folder root set.
  409. if(mFolderRoot->getRoot()->needsAutoRename())
  410. {
  411. setSelection(item_id, FALSE);
  412. }
  413. }
  414. //////////////////////////////
  415. // STRUCTURE Operation
  416. // This item already exists in both memory and UI. It was probably reparented.
  417. else if (model_item && view_item)
  418. {
  419. // Don't process the item if it is the root
  420. if (view_item->getRoot() != view_item)
  421. {
  422. LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolderRoot->getItemByID(model_item->getParentUUID());
  423. // Item has been moved.
  424. if (view_item->getParentFolder() != new_parent)
  425. {
  426. if (new_parent != NULL)
  427. {
  428. // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
  429. view_item->getParentFolder()->extractItem(view_item);
  430. view_item->addToFolder(new_parent, mFolderRoot);
  431. }
  432. else
  433. {
  434. // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that
  435. // doesn't include trash). Just remove the item's UI.
  436. view_item->destroyView();
  437. }
  438. }
  439. }
  440. }
  441. //////////////////////////////
  442. // REMOVE Operation
  443. // This item has been removed from memory, but its associated UI element still exists.
  444. else if (!model_item && view_item)
  445. {
  446. // Remove the item's UI.
  447. view_item->destroyView();
  448. }
  449. }
  450. }
  451. }
  452. LLFolderView* LLInventoryPanel::getRootFolder()
  453. {
  454. return mFolderRoot;
  455. }
  456. // static
  457. void LLInventoryPanel::onIdle(void *userdata)
  458. {
  459. if (!gInventory.isInventoryUsable())
  460. return;
  461. LLInventoryPanel *self = (LLInventoryPanel*)userdata;
  462. // Inventory just initialized, do complete build
  463. if (!self->mViewsInitialized)
  464. {
  465. self->initializeViews();
  466. }
  467. if (self->mViewsInitialized)
  468. {
  469. gIdleCallbacks.deleteFunction(onIdle, (void*)self);
  470. }
  471. }
  472. const LLUUID& LLInventoryPanel::getRootFolderID() const
  473. {
  474. return mFolderRoot->getListener()->getUUID();
  475. }
  476. void LLInventoryPanel::initializeViews()
  477. {
  478. if (!gInventory.isInventoryUsable()) return;
  479. rebuildViewsFor(getRootFolderID());
  480. mViewsInitialized = true;
  481. openStartFolderOrMyInventory();
  482. // Special case for new user login
  483. if (gAgent.isFirstLogin())
  484. {
  485. // Auto open the user's library
  486. LLFolderViewFolder* lib_folder = mFolderRoot->getFolderByID(gInventory.getLibraryRootFolderID());
  487. if (lib_folder)
  488. {
  489. lib_folder->setOpen(TRUE);
  490. }
  491. // Auto close the user's my inventory folder
  492. LLFolderViewFolder* my_inv_folder = mFolderRoot->getFolderByID(gInventory.getRootFolderID());
  493. if (my_inv_folder)
  494. {
  495. my_inv_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
  496. }
  497. }
  498. }
  499. LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id)
  500. {
  501. // Destroy the old view for this ID so we can rebuild it.
  502. LLFolderViewItem* old_view = mFolderRoot->getItemByID(id);
  503. if (old_view)
  504. {
  505. old_view->destroyView();
  506. }
  507. return buildNewViews(id);
  508. }
  509. LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool useLabelSuffix)
  510. {
  511. LLRect folder_rect(0,
  512. 0,
  513. getRect().getWidth(),
  514. 0);
  515. LLFolderView::Params p;
  516. p.name = getName();
  517. p.title = getLabel();
  518. p.rect = folder_rect;
  519. p.parent_panel = this;
  520. p.tool_tip = p.name;
  521. p.listener = bridge;
  522. p.use_label_suffix = useLabelSuffix;
  523. p.allow_multiselect = mAllowMultiSelect;
  524. p.show_empty_message = mShowEmptyMessage;
  525. p.show_load_status = mShowLoadStatus;
  526. return LLUICtrlFactory::create<LLFolderView>(p);
  527. }
  528. LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge)
  529. {
  530. LLFolderViewFolder::Params params;
  531. params.name = bridge->getDisplayName();
  532. params.icon = bridge->getIcon();
  533. params.icon_open = bridge->getOpenIcon();
  534. if (mShowItemLinkOverlays) // if false, then links show up just like normal items
  535. {
  536. params.icon_overlay = LLUI::getUIImage("Inv_Link");
  537. }
  538. params.root = mFolderRoot;
  539. params.listener = bridge;
  540. params.tool_tip = params.name;
  541. return LLUICtrlFactory::create<LLFolderViewFolder>(params);
  542. }
  543. LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge)
  544. {
  545. LLFolderViewItem::Params params;
  546. params.name = bridge->getDisplayName();
  547. params.icon = bridge->getIcon();
  548. params.icon_open = bridge->getOpenIcon();
  549. if (mShowItemLinkOverlays) // if false, then links show up just like normal items
  550. {
  551. params.icon_overlay = LLUI::getUIImage("Inv_Link");
  552. }
  553. params.creation_date = bridge->getCreationDate();
  554. params.root = mFolderRoot;
  555. params.listener = bridge;
  556. params.rect = LLRect (0, 0, 0, 0);
  557. params.tool_tip = params.name;
  558. return LLUICtrlFactory::create<LLFolderViewItem>(params);
  559. }
  560. LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
  561. {
  562. LLInventoryObject const* objectp = gInventory.getObject(id);
  563. LLUUID root_id = mFolderRoot->getListener()->getUUID();
  564. LLFolderViewFolder* parent_folder = NULL;
  565. LLFolderViewItem* itemp = NULL;
  566. if (id == root_id)
  567. {
  568. parent_folder = mFolderRoot;
  569. }
  570. else if (objectp)
  571. {
  572. const LLUUID &parent_id = objectp->getParentUUID();
  573. parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id);
  574. if (parent_folder)
  575. {
  576. if (objectp->getType() <= LLAssetType::AT_NONE ||
  577. objectp->getType() >= LLAssetType::AT_COUNT)
  578. {
  579. llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : "
  580. << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
  581. << llendl;
  582. return NULL;
  583. }
  584. if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
  585. (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER))
  586. {
  587. LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(),
  588. objectp->getType(),
  589. LLInventoryType::IT_CATEGORY,
  590. this,
  591. mFolderRoot,
  592. objectp->getUUID());
  593. if (new_listener)
  594. {
  595. LLFolderViewFolder* folderp = createFolderViewFolder(new_listener);
  596. if (folderp)
  597. {
  598. folderp->setItemSortOrder(mFolderRoot->getSortOrder());
  599. }
  600. itemp = folderp;
  601. }
  602. }
  603. else
  604. {
  605. // Build new view for item.
  606. LLInventoryItem* item = (LLInventoryItem*)objectp;
  607. LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(),
  608. item->getActualType(),
  609. item->getInventoryType(),
  610. this,
  611. mFolderRoot,
  612. item->getUUID(),
  613. item->getFlags());
  614. if (new_listener)
  615. {
  616. itemp = createFolderViewItem(new_listener);
  617. }
  618. }
  619. if (itemp)
  620. {
  621. itemp->addToFolder(parent_folder, mFolderRoot);
  622. }
  623. }
  624. }
  625. // If this is a folder, add the children of the folder and recursively add any
  626. // child folders.
  627. if (id.isNull()
  628. || (objectp
  629. && objectp->getType() == LLAssetType::AT_CATEGORY))
  630. {
  631. LLViewerInventoryCategory::cat_array_t* categories;
  632. LLViewerInventoryItem::item_array_t* items;
  633. mInventory->lockDirectDescendentArrays(id, categories, items);
  634. if(categories)
  635. {
  636. for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin();
  637. cat_iter != categories->end();
  638. ++cat_iter)
  639. {
  640. const LLViewerInventoryCategory* cat = (*cat_iter);
  641. buildNewViews(cat->getUUID());
  642. }
  643. }
  644. if(items && parent_folder)
  645. {
  646. for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin();
  647. item_iter != items->end();
  648. ++item_iter)
  649. {
  650. const LLViewerInventoryItem* item = (*item_iter);
  651. buildNewViews(item->getUUID());
  652. }
  653. }
  654. mInventory->unlockDirectDescendentArrays(id);
  655. }
  656. return itemp;
  657. }
  658. // bit of a hack to make sure the inventory is open.
  659. void LLInventoryPanel::openStartFolderOrMyInventory()
  660. {
  661. // Find My Inventory folder and open it up by name
  662. for (LLView *child = mFolderRoot->getFirstChild(); child; child = mFolderRoot->findNextSibling(child))
  663. {
  664. LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child);
  665. if (fchild
  666. && fchild->getListener()
  667. && fchild->getListener()->getUUID() == gInventory.getRootFolderID())
  668. {
  669. fchild->setOpen(TRUE);
  670. break;
  671. }
  672. }
  673. }
  674. void LLInventoryPanel::onItemsCompletion()
  675. {
  676. if (mFolderRoot) mFolderRoot->updateMenu();
  677. }
  678. void LLInventoryPanel::openSelected()
  679. {
  680. LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem();
  681. if(!folder_item) return;
  682. LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener();
  683. if(!bridge) return;
  684. bridge->openItem();
  685. }
  686. void LLInventoryPanel::unSelectAll()
  687. {
  688. mFolderRoot->setSelection(NULL, FALSE, FALSE);
  689. }
  690. BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
  691. {
  692. BOOL handled = LLView::handleHover(x, y, mask);
  693. if(handled)
  694. {
  695. ECursorType cursor = getWindow()->getCursor();
  696. if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW)
  697. {
  698. // replace arrow cursor with arrow and hourglass cursor
  699. getWindow()->setCursor(UI_CURSOR_WORKING);
  700. }
  701. }
  702. else
  703. {
  704. getWindow()->setCursor(UI_CURSOR_ARROW);
  705. }
  706. return TRUE;
  707. }
  708. BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  709. EDragAndDropType cargo_type,
  710. void* cargo_data,
  711. EAcceptance* accept,
  712. std::string& tooltip_msg)
  713. {
  714. BOOL handled = FALSE;
  715. if (mAcceptsDragAndDrop)
  716. {
  717. handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
  718. // If folder view is empty the (x, y) point won't be in its rect
  719. // so the handler must be called explicitly.
  720. // but only if was not handled before. See EXT-6746.
  721. if (!handled && !mFolderRoot->hasVisibleChildren())
  722. {
  723. handled = mFolderRoot->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
  724. }
  725. if (handled)
  726. {
  727. mFolderRoot->setDragAndDropThisFrame();
  728. }
  729. }
  730. return handled;
  731. }
  732. void LLInventoryPanel::onFocusLost()
  733. {
  734. // inventory no longer handles cut/copy/paste/delete
  735. if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot)
  736. {
  737. LLEditMenuHandler::gEditMenuHandler = NULL;
  738. }
  739. LLPanel::onFocusLost();
  740. }
  741. void LLInventoryPanel::onFocusReceived()
  742. {
  743. // inventory now handles cut/copy/paste/delete
  744. LLEditMenuHandler::gEditMenuHandler = mFolderRoot;
  745. LLPanel::onFocusReceived();
  746. }
  747. bool LLInventoryPanel::addBadge(LLBadge * badge)
  748. {
  749. bool badge_added = false;
  750. if (acceptsBadge())
  751. {
  752. badge_added = badge->addToView(mFolderRoot);
  753. }
  754. return badge_added;
  755. }
  756. void LLInventoryPanel::openAllFolders()
  757. {
  758. mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
  759. mFolderRoot->arrangeAll();
  760. }
  761. void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus)
  762. {
  763. // Don't select objects in COF (e.g. to prevent refocus when items are worn).
  764. const LLInventoryObject *obj = gInventory.getObject(obj_id);
  765. if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())
  766. {
  767. return;
  768. }
  769. mFolderRoot->setSelectionByID(obj_id, take_keyboard_focus);
  770. }
  771. void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb)
  772. {
  773. if (mFolderRoot)
  774. {
  775. mFolderRoot->setSelectCallback(cb);
  776. }
  777. }
  778. void LLInventoryPanel::clearSelection()
  779. {
  780. mFolderRoot->clearSelection();
  781. }
  782. void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
  783. {
  784. // Schedule updating the folder view context menu when all selected items become complete (STORM-373).
  785. mCompletionObserver->reset();
  786. for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
  787. {
  788. LLUUID id = (*it)->getListener()->getUUID();
  789. LLViewerInventoryItem* inv_item = mInventory->getItem(id);
  790. if (inv_item && !inv_item->isFinished())
  791. {
  792. mCompletionObserver->watchItem(id);
  793. }
  794. }
  795. LLFolderView* fv = getRootFolder();
  796. if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
  797. {
  798. fv->setNeedsAutoRename(FALSE);
  799. if (items.size()) // new asset is visible and selected
  800. {
  801. fv->startRenamingSelectedItem();
  802. }
  803. }
  804. }
  805. void LLInventoryPanel::doToSelected(const LLSD& userdata)
  806. {
  807. mFolderRoot->doToSelected(&gInventory, userdata);
  808. }
  809. void LLInventoryPanel::doCreate(const LLSD& userdata)
  810. {
  811. menu_create_inventory_item(mFolderRoot, LLFolderBridge::sSelf.get(), userdata);
  812. }
  813. bool LLInventoryPanel::beginIMSession()
  814. {
  815. std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
  816. std::string name;
  817. static int session_num = 1;
  818. LLDynamicArray<LLUUID> members;
  819. EInstantMessage type = IM_SESSION_CONFERENCE_START;
  820. std::set<LLUUID>::const_iterator iter;
  821. for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
  822. {
  823. LLUUID item = *iter;
  824. LLFolderViewItem* folder_item = mFolderRoot->getItemByID(item);
  825. if(folder_item)
  826. {
  827. LLFolderViewEventListener* fve_listener = folder_item->getListener();
  828. if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
  829. {
  830. LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener();
  831. if(!bridge) return true;
  832. LLViewerInventoryCategory* cat = bridge->getCategory();
  833. if(!cat) return true;
  834. name = cat->getName();
  835. LLUniqueBuddyCollector is_buddy;
  836. LLInventoryModel::cat_array_t cat_array;
  837. LLInventoryModel::item_array_t item_array;
  838. gInventory.collectDescendentsIf(bridge->getUUID(),
  839. cat_array,
  840. item_array,
  841. LLInventoryModel::EXCLUDE_TRASH,
  842. is_buddy);
  843. S32 count = item_array.count();
  844. if(count > 0)
  845. {
  846. //*TODO by what to replace that?
  847. //LLFloaterReg::showInstance("communicate");
  848. // create the session
  849. LLAvatarTracker& at = LLAvatarTracker::instance();
  850. LLUUID id;
  851. for(S32 i = 0; i < count; ++i)
  852. {
  853. id = item_array.get(i)->getCreatorUUID();
  854. if(at.isBuddyOnline(id))
  855. {
  856. members.put(id);
  857. }
  858. }
  859. }
  860. }
  861. else
  862. {
  863. LLFolderViewItem* folder_item = mFolderRoot->getItemByID(item);
  864. if(!folder_item) return true;
  865. LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener();
  866. if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
  867. {
  868. LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID());
  869. if (inv_item)
  870. {
  871. LLAvatarTracker& at = LLAvatarTracker::instance();
  872. LLUUID id = inv_item->getCreatorUUID();
  873. if(at.isBuddyOnline(id))
  874. {
  875. members.put(id);
  876. }
  877. }
  878. } //if IT_CALLINGCARD
  879. } //if !IT_CATEGORY
  880. }
  881. } //for selected_items
  882. // the session_id is randomly generated UUID which will be replaced later
  883. // with a server side generated number
  884. if (name.empty())
  885. {
  886. name = llformat("Session %d", session_num++);
  887. }
  888. LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
  889. if (session_id != LLUUID::null)
  890. {
  891. LLIMFloater::show(session_id);
  892. }
  893. return true;
  894. }
  895. bool LLInventoryPanel::attachObject(const LLSD& userdata)
  896. {
  897. // Copy selected item UUIDs to a vector.
  898. std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
  899. uuid_vec_t items;
  900. for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin();
  901. set_iter != selected_items.end();
  902. ++set_iter)
  903. {
  904. items.push_back(*set_iter);
  905. }
  906. // Attach selected items.
  907. LLViewerAttachMenu::attachObjects(items, userdata.asString());
  908. gFocusMgr.setKeyboardFocus(NULL);
  909. return true;
  910. }
  911. BOOL LLInventoryPanel::getSinceLogoff()
  912. {
  913. return getFilter()->isSinceLogoff();
  914. }
  915. // DEBUG ONLY
  916. // static
  917. void LLInventoryPanel::dumpSelectionInformation(void* user_data)
  918. {
  919. LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
  920. iv->mFolderRoot->dumpSelectionInformation();
  921. }
  922. BOOL is_inventorysp_active()
  923. {
  924. LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
  925. if (!sidepanel_inventory || !sidepanel_inventory->isInVisibleChain()) return FALSE;
  926. return sidepanel_inventory->isMainInventoryPanelActive();
  927. }
  928. // static
  929. LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
  930. {
  931. S32 z_min = S32_MAX;
  932. LLInventoryPanel* res = NULL;
  933. LLFloater* active_inv_floaterp = NULL;
  934. LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
  935. if (!floater_inventory)
  936. {
  937. llwarns << "Could not find My Inventory floater" << llendl;
  938. return FALSE;
  939. }
  940. LLSidepanelInventory *inventory_panel = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
  941. // Iterate through the inventory floaters and return whichever is on top.
  942. LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
  943. for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
  944. {
  945. LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
  946. inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
  947. if (inventory_floater && inventory_panel && inventory_floater->getVisible())
  948. {
  949. S32 z_order = gFloaterView->getZOrder(inventory_floater);
  950. if (z_order < z_min)
  951. {
  952. res = inventory_panel->getActivePanel();
  953. z_min = z_order;
  954. active_inv_floaterp = inventory_floater;
  955. }
  956. }
  957. }
  958. if (res)
  959. {
  960. // Make sure the floater is not minimized (STORM-438).
  961. if (active_inv_floaterp && active_inv_floaterp->isMinimized())
  962. {
  963. active_inv_floaterp->setMinimized(FALSE);
  964. }
  965. }
  966. else if (auto_open)
  967. {
  968. floater_inventory->openFloater();
  969. res = inventory_panel->getActivePanel();
  970. }
  971. return res;
  972. }
  973. //static
  974. void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id)
  975. {
  976. LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
  977. if (active_panel)
  978. {
  979. LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL;
  980. LLViewerInventoryItem * item = gInventory.getItem(obj_id);
  981. LLViewerInventoryCategory * cat = gInventory.getCategory(obj_id);
  982. bool in_inbox = false;
  983. LLViewerInventoryCategory * parent_cat = NULL;
  984. if (item)
  985. {
  986. parent_cat = gInventory.getCategory(item->getParentUUID());
  987. }
  988. else if (cat)
  989. {
  990. parent_cat = gInventory.getCategory(cat->getParentUUID());
  991. }
  992. if (parent_cat)
  993. {
  994. in_inbox = (LLFolderType::FT_INBOX == parent_cat->getPreferredType());
  995. }
  996. if (in_inbox)
  997. {
  998. LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
  999. LLInventoryPanel * inventory_panel = NULL;
  1000. if (in_inbox)
  1001. {
  1002. sidepanel_inventory->openInbox();
  1003. inventory_panel = sidepanel_inventory->getInboxPanel();
  1004. }
  1005. if (inventory_panel)
  1006. {
  1007. inventory_panel->setSelection(obj_id, TAKE_FOCUS_YES);
  1008. }
  1009. }
  1010. else
  1011. {
  1012. active_panel->setSelection(obj_id, TAKE_FOCUS_YES);
  1013. }
  1014. }
  1015. }
  1016. void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
  1017. {
  1018. getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type));
  1019. }
  1020. BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const
  1021. {
  1022. return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type));
  1023. }
  1024. /************************************************************************/
  1025. /* Recent Inventory Panel related class */
  1026. /************************************************************************/
  1027. class LLInventoryRecentItemsPanel;
  1028. static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
  1029. static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER;
  1030. class LLInventoryRecentItemsPanel : public LLInventoryPanel
  1031. {
  1032. public:
  1033. struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params>
  1034. {};
  1035. void initFromParams(const Params& p)
  1036. {
  1037. LLInventoryPanel::initFromParams(p);
  1038. // turn on inbox for recent items
  1039. getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX));
  1040. }
  1041. protected:
  1042. LLInventoryRecentItemsPanel (const Params&);
  1043. friend class LLUICtrlFactory;
  1044. };
  1045. LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
  1046. : LLInventoryPanel(params)
  1047. {
  1048. // replace bridge builder to have necessary View bridges.
  1049. mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
  1050. }