llfolderview.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:62k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfolderview.cpp
  3.  * @brief Implementation of the folder view collection of classes.
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llfolderview.h"
  34. #include "llcallbacklist.h"
  35. #include "llinventorybridge.h"
  36. #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone.
  37. #include "llinventoryfilter.h"
  38. #include "llinventoryfunctions.h"
  39. #include "llinventorypanel.h"
  40. #include "llfoldertype.h"
  41. #include "llfloaterinventory.h"// hacked in for the bonus context menu items.
  42. #include "llkeyboard.h"
  43. #include "lllineeditor.h"
  44. #include "llmenugl.h"
  45. #include "llpanel.h"
  46. #include "llpreview.h"
  47. #include "llscrollcontainer.h" // hack to allow scrolling
  48. #include "lltooldraganddrop.h"
  49. #include "lltrans.h"
  50. #include "llui.h"
  51. #include "llviewertexture.h"
  52. #include "llviewertexturelist.h"
  53. #include "llviewerjointattachment.h"
  54. #include "llviewermenu.h"
  55. #include "lluictrlfactory.h"
  56. #include "llviewercontrol.h"
  57. #include "llviewerfoldertype.h"
  58. #include "llviewerwindow.h"
  59. #include "llvoavatar.h"
  60. #include "llfloaterproperties.h"
  61. // Linden library includes
  62. #include "lldbstrings.h"
  63. #include "llfocusmgr.h"
  64. #include "llfontgl.h"
  65. #include "llgl.h" 
  66. #include "llrender.h"
  67. #include "llinventory.h"
  68. // Third-party library includes
  69. #include <algorithm>
  70. ///----------------------------------------------------------------------------
  71. /// Local function declarations, constants, enums, and typedefs
  72. ///----------------------------------------------------------------------------
  73. const S32 RENAME_WIDTH_PAD = 4;
  74. const S32 RENAME_HEIGHT_PAD = 1;
  75. const S32 AUTO_OPEN_STACK_DEPTH = 16;
  76. const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH
  77. + LLFolderViewItem::ICON_PAD 
  78. + LLFolderViewItem::ARROW_SIZE 
  79. + LLFolderViewItem::TEXT_PAD 
  80. + /*first few characters*/ 40;
  81. const S32 MINIMUM_RENAMER_WIDTH = 80;
  82. enum {
  83. SIGNAL_NO_KEYBOARD_FOCUS = 1,
  84. SIGNAL_KEYBOARD_FOCUS = 2
  85. };
  86. F32 LLFolderView::sAutoOpenTime = 1.f;
  87. void delete_selected_item(void* user_data);
  88. void copy_selected_item(void* user_data);
  89. void open_selected_items(void* user_data);
  90. void properties_selected_items(void* user_data);
  91. void paste_items(void* user_data);
  92. void renamer_focus_lost( LLFocusableElement* handler, void* user_data );
  93. //---------------------------------------------------------------------------
  94. // Tells all folders in a folderview to sort their items
  95. // (and only their items, not folders) by a certain function.
  96. class LLSetItemSortFunction : public LLFolderViewFunctor
  97. {
  98. public:
  99. LLSetItemSortFunction(U32 ordering)
  100. : mSortOrder(ordering) {}
  101. virtual ~LLSetItemSortFunction() {}
  102. virtual void doFolder(LLFolderViewFolder* folder);
  103. virtual void doItem(LLFolderViewItem* item);
  104. U32 mSortOrder;
  105. };
  106. // Set the sort order.
  107. void LLSetItemSortFunction::doFolder(LLFolderViewFolder* folder)
  108. {
  109. folder->setItemSortOrder(mSortOrder);
  110. }
  111. // Do nothing.
  112. void LLSetItemSortFunction::doItem(LLFolderViewItem* item)
  113. {
  114. return;
  115. }
  116. //---------------------------------------------------------------------------
  117. // Tells all folders in a folderview to close themselves
  118. // For efficiency, calls setOpenArrangeRecursively().
  119. // The calling function must then call:
  120. // LLFolderView* root = getRoot();
  121. // if( root )
  122. // {
  123. // root->arrange( NULL, NULL );
  124. // root->scrollToShowSelection();
  125. // }
  126. // to patch things up.
  127. class LLCloseAllFoldersFunctor : public LLFolderViewFunctor
  128. {
  129. public:
  130. LLCloseAllFoldersFunctor(BOOL close) { mOpen = !close; }
  131. virtual ~LLCloseAllFoldersFunctor() {}
  132. virtual void doFolder(LLFolderViewFolder* folder);
  133. virtual void doItem(LLFolderViewItem* item);
  134. BOOL mOpen;
  135. };
  136. // Set the sort order.
  137. void LLCloseAllFoldersFunctor::doFolder(LLFolderViewFolder* folder)
  138. {
  139. folder->setOpenArrangeRecursively(mOpen);
  140. }
  141. // Do nothing.
  142. void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item)
  143. { }
  144. ///----------------------------------------------------------------------------
  145. /// Class LLFolderView
  146. ///----------------------------------------------------------------------------
  147. // Default constructor
  148. LLFolderView::LLFolderView(const Params& p)
  149. : LLFolderViewFolder(p),
  150. mScrollContainer( NULL ),
  151. mPopupMenuHandle(),
  152. mAllowMultiSelect(TRUE),
  153. mShowFolderHierarchy(FALSE),
  154. mSourceID(p.task_id),
  155. mRenameItem( NULL ),
  156. mNeedsScroll( FALSE ),
  157. mPinningSelectedItem(FALSE),
  158. mNeedsAutoSelect( FALSE ),
  159. mAutoSelectOverride(FALSE),
  160. mNeedsAutoRename(FALSE),
  161. mDebugFilters(FALSE),
  162. mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME), // This gets overridden by a pref immediately
  163. mFilter( new LLInventoryFilter(p.name) ),
  164. mShowSelectionContext(FALSE),
  165. mShowSingleSelection(FALSE),
  166. mArrangeGeneration(0),
  167. mSignalSelectCallback(0),
  168. mMinWidth(0),
  169. mDragAndDropThisFrame(FALSE),
  170. mCallbackRegistrar(NULL),
  171. mParentPanel(p.parent_panel),
  172. mUseEllipses(false),
  173. mDraggingOverItem(NULL),
  174. mStatusTextBox(NULL)
  175. {
  176. LLRect rect = p.rect;
  177. LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom);
  178. setRect( rect );
  179. reshape(rect.getWidth(), rect.getHeight());
  180. mIsOpen = TRUE; // this view is always open.
  181. mAutoOpenItems.setDepth(AUTO_OPEN_STACK_DEPTH);
  182. mAutoOpenCandidate = NULL;
  183. mAutoOpenTimer.stop();
  184. mKeyboardSelection = FALSE;
  185. const LLFolderViewItem::Params& item_params =
  186. LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
  187. S32 indentation = item_params.folder_indentation();
  188. mIndentation = -indentation; // children start at indentation 0
  189. gIdleCallbacks.addFunction(idle, this);
  190. //clear label
  191. // go ahead and render root folder as usual
  192. // just make sure the label ("Inventory Folder") never shows up
  193. mLabel = LLStringUtil::null;
  194. //mRenamer->setWriteableBgColor(LLColor4::white);
  195. // Escape is handled by reverting the rename, not commiting it (default behavior)
  196. LLLineEditor::Params params;
  197. params.name("ren");
  198. params.rect(rect);
  199. params.font(getLabelFontForStyle(LLFontGL::NORMAL));
  200. params.max_length_bytes(DB_INV_ITEM_NAME_STR_LEN);
  201. params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2));
  202. params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe);
  203. params.commit_on_focus_lost(true);
  204. params.visible(false);
  205. mRenamer = LLUICtrlFactory::create<LLLineEditor> (params);
  206. addChild(mRenamer);
  207. // Textbox
  208. LLTextBox::Params text_p;
  209. LLFontGL* font = getLabelFontForStyle(mLabelStyle);
  210. LLRect new_r = LLRect(rect.mLeft + ICON_PAD,
  211.       rect.mTop - TEXT_PAD,
  212.       rect.mRight,
  213.       rect.mTop - TEXT_PAD - llfloor(font->getLineHeight()));
  214. text_p.rect(new_r);
  215. text_p.name(std::string(p.name));
  216. text_p.font(font);
  217. text_p.visible(false);
  218. text_p.allow_html(true);
  219. mStatusTextBox = LLUICtrlFactory::create<LLTextBox> (text_p);
  220. mStatusTextBox->setFollowsLeft();
  221. mStatusTextBox->setFollowsTop();
  222. //addChild(mStatusTextBox);
  223. // make the popup menu available
  224. LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  225. if (!menu)
  226. {
  227. menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
  228. }
  229. menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor"));
  230. mPopupMenuHandle = menu->getHandle();
  231. }
  232. // Destroys the object
  233. LLFolderView::~LLFolderView( void )
  234. {
  235. // The release focus call can potentially call the
  236. // scrollcontainer, which can potentially be called with a partly
  237. // destroyed scollcontainer. Just null it out here, and no worries
  238. // about calling into the invalid scroll container.
  239. // Same with the renamer.
  240. mScrollContainer = NULL;
  241. mRenameItem = NULL;
  242. mRenamer = NULL;
  243. mStatusTextBox = NULL;
  244. if( gEditMenuHandler == this )
  245. {
  246. gEditMenuHandler = NULL;
  247. }
  248. mAutoOpenItems.removeAllNodes();
  249. gIdleCallbacks.deleteFunction(idle, this);
  250. LLView::deleteViewByHandle(mPopupMenuHandle);
  251. if(mRenamer == gFocusMgr.getTopCtrl())
  252. {
  253. gFocusMgr.setTopCtrl(NULL);
  254. }
  255. mAutoOpenItems.removeAllNodes();
  256. clearSelection();
  257. mItems.clear();
  258. mFolders.clear();
  259. mItemMap.clear();
  260. delete mFilter;
  261. mFilter = NULL;
  262. }
  263. BOOL LLFolderView::canFocusChildren() const
  264. {
  265. return FALSE;
  266. }
  267. void LLFolderView::checkTreeResortForModelChanged()
  268. {
  269. if (mSortOrder & LLInventoryFilter::SO_DATE && !(mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME))
  270. {
  271. // This is the case where something got added or removed.  If we are date sorting
  272. // everything including folders, then we need to rebuild the whole tree.
  273. // Just set to something not SO_DATE to force the folder most resent date resort.
  274. mSortOrder = mSortOrder & ~LLInventoryFilter::SO_DATE;
  275. setSortOrder(mSortOrder | LLInventoryFilter::SO_DATE);
  276. }
  277. }
  278. static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory");
  279. void LLFolderView::setSortOrder(U32 order)
  280. {
  281. if (order != mSortOrder)
  282. {
  283. LLFastTimer t(FTM_SORT);
  284. mSortOrder = order;
  285. for (folders_t::iterator iter = mFolders.begin();
  286.  iter != mFolders.end();)
  287. {
  288. folders_t::iterator fit = iter++;
  289. (*fit)->sortBy(order);
  290. }
  291. arrangeAll();
  292. }
  293. }
  294. U32 LLFolderView::getSortOrder() const
  295. {
  296. return mSortOrder;
  297. }
  298. BOOL LLFolderView::addFolder( LLFolderViewFolder* folder)
  299. {
  300. // enforce sort order of My Inventory followed by Library
  301. if (folder->getListener()->getUUID() == gInventory.getLibraryRootFolderID())
  302. {
  303. mFolders.push_back(folder);
  304. }
  305. else
  306. {
  307. mFolders.insert(mFolders.begin(), folder);
  308. }
  309. folder->setShowLoadStatus(true);
  310. folder->setOrigin(0, 0);
  311. folder->reshape(getRect().getWidth(), 0);
  312. folder->setVisible(FALSE);
  313. addChild( folder );
  314. folder->dirtyFilter();
  315. folder->requestArrange();
  316. return TRUE;
  317. }
  318. void LLFolderView::closeAllFolders()
  319. {
  320. // Close all the folders
  321. setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
  322. arrangeAll();
  323. }
  324. void LLFolderView::openFolder(const std::string& foldername)
  325. {
  326. LLFolderViewFolder* inv = findChild<LLFolderViewFolder>(foldername);
  327. if (inv)
  328. {
  329. setSelection(inv, FALSE, FALSE);
  330. inv->setOpen(TRUE);
  331. }
  332. }
  333. void LLFolderView::openTopLevelFolders()
  334. {
  335. for (folders_t::iterator iter = mFolders.begin();
  336.  iter != mFolders.end();)
  337. {
  338. folders_t::iterator fit = iter++;
  339. (*fit)->setOpen(TRUE);
  340. }
  341. }
  342. void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse)
  343. {
  344. // call base class to do proper recursion
  345. LLFolderViewFolder::setOpenArrangeRecursively(openitem, recurse);
  346. // make sure root folder is always open
  347. mIsOpen = TRUE;
  348. }
  349. static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
  350. // This view grows and shinks to enclose all of its children items and folders.
  351. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation )
  352. {
  353. LLFastTimer t2(FTM_ARRANGE);
  354. filter_generation = mFilter->getMinRequiredGeneration();
  355. mMinWidth = 0;
  356. mHasVisibleChildren = hasFilteredDescendants(filter_generation);
  357. // arrange always finishes, so optimistically set the arrange generation to the most current
  358. mLastArrangeGeneration = getRoot()->getArrangeGeneration();
  359. LLInventoryFilter::EFolderShow show_folder_state =
  360. getRoot()->getFilter()->getShowFolderState();
  361. S32 total_width = LEFT_PAD;
  362. S32 running_height = mDebugFilters ? llceil(LLFontGL::getFontMonospace()->getLineHeight()) : 0;
  363. S32 target_height = running_height;
  364. S32 parent_item_height = getRect().getHeight();
  365. for (folders_t::iterator iter = mFolders.begin();
  366.  iter != mFolders.end();)
  367. {
  368. folders_t::iterator fit = iter++;
  369. LLFolderViewFolder* folderp = (*fit);
  370. if (getDebugFilters())
  371. {
  372. folderp->setVisible(TRUE);
  373. }
  374. else
  375. {
  376. folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders?
  377. (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter
  378. }
  379. // Need to call arrange regardless of visibility, since children's visibility
  380. // might need to be changed too (e.g. even though a folder is invisible, its
  381. // children also need to be set invisible for state-tracking purposes, e.g.
  382. // llfolderviewitem::filter).
  383. // if (folderp->getVisible())
  384. {
  385. S32 child_height = 0;
  386. S32 child_width = 0;
  387. S32 child_top = parent_item_height - running_height;
  388. target_height += folderp->arrange( &child_width, &child_height, filter_generation );
  389. mMinWidth = llmax(mMinWidth, child_width);
  390. total_width = llmax( total_width, child_width );
  391. running_height += child_height;
  392. folderp->setOrigin( ICON_PAD, child_top - (*fit)->getRect().getHeight() );
  393. }
  394. }
  395. for (items_t::iterator iter = mItems.begin();
  396.  iter != mItems.end();)
  397. {
  398. items_t::iterator iit = iter++;
  399. LLFolderViewItem* itemp = (*iit);
  400. itemp->setVisible(itemp->getFiltered(filter_generation));
  401. if (itemp->getVisible())
  402. {
  403. S32 child_width = 0;
  404. S32 child_height = 0;
  405. S32 child_top = parent_item_height - running_height;
  406. target_height += itemp->arrange( &child_width, &child_height, filter_generation );
  407. itemp->reshape(itemp->getRect().getWidth(), child_height);
  408. mMinWidth = llmax(mMinWidth, child_width);
  409. total_width = llmax( total_width, child_width );
  410. running_height += child_height;
  411. itemp->setOrigin( ICON_PAD, child_top - itemp->getRect().getHeight() );
  412. }
  413. }
  414. LLRect scroll_rect = mScrollContainer->getContentWindowRect();
  415. reshape( llmax(scroll_rect.getWidth(), total_width), running_height );
  416. LLRect new_scroll_rect = mScrollContainer->getContentWindowRect();
  417. if (new_scroll_rect.getWidth() != scroll_rect.getWidth())
  418. {
  419. reshape( llmax(scroll_rect.getWidth(), total_width), running_height );
  420. }
  421. // move item renamer text field to item's new position
  422. updateRenamerPosition();
  423. mTargetHeight = (F32)target_height;
  424. return llround(mTargetHeight);
  425. }
  426. const std::string LLFolderView::getFilterSubString(BOOL trim)
  427. {
  428. return mFilter->getFilterSubString(trim);
  429. }
  430. static LLFastTimer::DeclareTimer FTM_FILTER("Filter Inventory");
  431. void LLFolderView::filter( LLInventoryFilter& filter )
  432. {
  433. LLFastTimer t2(FTM_FILTER);
  434. filter.setFilterCount(llclamp(gSavedSettings.getS32("FilterItemsPerFrame"), 1, 5000));
  435. if (getCompletedFilterGeneration() < filter.getCurrentGeneration())
  436. {
  437. mPassedFilter = FALSE;
  438. mMinWidth = 0;
  439. LLFolderViewFolder::filter(filter);
  440. }
  441. else
  442. {
  443. mPassedFilter = TRUE;
  444. }
  445. }
  446. void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)
  447. {
  448. LLRect scroll_rect;
  449. if (mScrollContainer)
  450. {
  451. scroll_rect = mScrollContainer->getContentWindowRect();
  452. }
  453. width = llmax(mMinWidth, scroll_rect.getWidth());
  454. // restrict width with scroll container's width
  455. if (mUseEllipses)
  456. width = scroll_rect.getWidth();
  457. LLView::reshape(width, height, called_from_parent);
  458. mReshapeSignal(mSelectedItems, FALSE);
  459. }
  460. void LLFolderView::addToSelectionList(LLFolderViewItem* item)
  461. {
  462. if (item->isSelected())
  463. {
  464. removeFromSelectionList(item);
  465. }
  466. if (mSelectedItems.size())
  467. {
  468. mSelectedItems.back()->setIsCurSelection(FALSE);
  469. }
  470. item->setIsCurSelection(TRUE);
  471. mSelectedItems.push_back(item);
  472. }
  473. void LLFolderView::removeFromSelectionList(LLFolderViewItem* item)
  474. {
  475. if (mSelectedItems.size())
  476. {
  477. mSelectedItems.back()->setIsCurSelection(FALSE);
  478. }
  479. selected_items_t::iterator item_iter;
  480. for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end();)
  481. {
  482. if (*item_iter == item)
  483. {
  484. item_iter = mSelectedItems.erase(item_iter);
  485. }
  486. else
  487. {
  488. ++item_iter;
  489. }
  490. }
  491. if (mSelectedItems.size())
  492. {
  493. mSelectedItems.back()->setIsCurSelection(TRUE);
  494. }
  495. }
  496. LLFolderViewItem* LLFolderView::getCurSelectedItem( void )
  497. {
  498. if(mSelectedItems.size())
  499. {
  500. LLFolderViewItem* itemp = mSelectedItems.back();
  501. llassert(itemp->getIsCurSelection());
  502. return itemp;
  503. }
  504. return NULL;
  505. }
  506. // Record the selected item and pass it down the hierachy.
  507. BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem,
  508. BOOL take_keyboard_focus)
  509. {
  510. mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS;
  511. if( selection == this )
  512. {
  513. return FALSE;
  514. }
  515. if( selection && take_keyboard_focus)
  516. {
  517. mParentPanel->setFocus(TRUE);
  518. }
  519. // clear selection down here because change of keyboard focus can potentially
  520. // affect selection
  521. clearSelection();
  522. if(selection)
  523. {
  524. addToSelectionList(selection);
  525. }
  526. BOOL rv = LLFolderViewFolder::setSelection(selection, openitem, take_keyboard_focus);
  527. if(openitem && selection)
  528. {
  529. selection->getParentFolder()->requestArrange();
  530. }
  531. llassert(mSelectedItems.size() <= 1);
  532. return rv;
  533. }
  534. void LLFolderView::setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus)
  535. {
  536. LLFolderViewItem* itemp = getItemByID(obj_id);
  537. if(itemp && itemp->getListener())
  538. {
  539. itemp->arrangeAndSet(TRUE, take_keyboard_focus);
  540. mSelectThisID.setNull();
  541. return;
  542. }
  543. else
  544. {
  545. // save the desired item to be selected later (if/when ready)
  546. mSelectThisID = obj_id;
  547. }
  548. }
  549. void LLFolderView::updateSelection()
  550. {
  551. if (mSelectThisID.notNull())
  552. {
  553. setSelectionByID(mSelectThisID, false);
  554. }
  555. }
  556. BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
  557. {
  558. BOOL rv = FALSE;
  559. // can't select root folder
  560. if(!selection || selection == this)
  561. {
  562. return FALSE;
  563. }
  564. if (!mAllowMultiSelect)
  565. {
  566. clearSelection();
  567. }
  568. selected_items_t::iterator item_iter;
  569. for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter)
  570. {
  571. if (*item_iter == selection)
  572. {
  573. break;
  574. }
  575. }
  576. BOOL on_list = (item_iter != mSelectedItems.end());
  577. if(selected && !on_list)
  578. {
  579. addToSelectionList(selection);
  580. }
  581. if(!selected && on_list)
  582. {
  583. removeFromSelectionList(selection);
  584. }
  585. rv = LLFolderViewFolder::changeSelection(selection, selected);
  586. mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS;
  587. return rv;
  588. }
  589. S32 LLFolderView::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray<LLFolderViewItem*>& items)
  590. {
  591. S32 rv = 0;
  592. // now store resulting selection
  593. if (mAllowMultiSelect)
  594. {
  595. LLFolderViewItem *cur_selection = getCurSelectedItem();
  596. rv = LLFolderViewFolder::extendSelection(selection, cur_selection, items);
  597. for (S32 i = 0; i < items.count(); i++)
  598. {
  599. addToSelectionList(items[i]);
  600. rv++;
  601. }
  602. }
  603. else
  604. {
  605. setSelection(selection, FALSE, FALSE);
  606. rv++;
  607. }
  608. mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS;
  609. return rv;
  610. }
  611. void LLFolderView::sanitizeSelection()
  612. {
  613. // store off current item in case it is automatically deselected
  614. // and we want to preserve context
  615. LLFolderViewItem* original_selected_item = getCurSelectedItem();
  616. // Cache "Show all folders" filter setting
  617. BOOL show_all_folders = (getRoot()->getFilter()->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS);
  618. std::vector<LLFolderViewItem*> items_to_remove;
  619. selected_items_t::iterator item_iter;
  620. for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter)
  621. {
  622. LLFolderViewItem* item = *item_iter;
  623. // ensure that each ancestor is open and potentially passes filtering
  624. BOOL visible = item->potentiallyVisible(); // initialize from filter state for this item
  625. // modify with parent open and filters states
  626. LLFolderViewFolder* parent_folder = item->getParentFolder();
  627. if ( parent_folder )
  628. {
  629. if ( show_all_folders )
  630. { // "Show all folders" is on, so this folder is visible
  631. visible = TRUE;
  632. }
  633. else
  634. { // Move up through parent folders and see what's visible
  635. while(parent_folder)
  636. {
  637. visible = visible && parent_folder->isOpen() && parent_folder->potentiallyVisible();
  638. parent_folder = parent_folder->getParentFolder();
  639. }
  640. }
  641. }
  642. //  deselect item if any ancestor is closed or didn't pass filter requirements.
  643. if (!visible)
  644. {
  645. items_to_remove.push_back(item);
  646. }
  647. // disallow nested selections (i.e. folder items plus one or more ancestors)
  648. // could check cached mum selections count and only iterate if there are any
  649. // but that may be a premature optimization.
  650. selected_items_t::iterator other_item_iter;
  651. for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter)
  652. {
  653. LLFolderViewItem* other_item = *other_item_iter;
  654. for( parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder())
  655. {
  656. if (parent_folder == item)
  657. {
  658. // this is a descendent of the current folder, remove from list
  659. items_to_remove.push_back(other_item);
  660. break;
  661. }
  662. }
  663. }
  664. // Don't allow invisible items (such as root folders) to be selected.
  665. if (item->getHidden())
  666. {
  667. items_to_remove.push_back(item);
  668. }
  669. }
  670. std::vector<LLFolderViewItem*>::iterator item_it;
  671. for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it )
  672. {
  673. changeSelection(*item_it, FALSE); // toggle selection (also removes from list)
  674. }
  675. // if nothing selected after prior constraints...
  676. if (mSelectedItems.empty())
  677. {
  678. // ...select first available parent of original selection, or "My Inventory" otherwise
  679. LLFolderViewItem* new_selection = NULL;
  680. if (original_selected_item)
  681. {
  682. for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder();
  683. parent_folder;
  684. parent_folder = parent_folder->getParentFolder())
  685. {
  686. if (parent_folder->potentiallyVisible() && !parent_folder->getHidden())
  687. {
  688. // give initial selection to first ancestor folder that potentially passes the filter
  689. if (!new_selection)
  690. {
  691. new_selection = parent_folder;
  692. }
  693. // if any ancestor folder of original item is closed, move the selection up 
  694. // to the highest closed
  695. if (!parent_folder->isOpen())
  696. {
  697. new_selection = parent_folder;
  698. }
  699. }
  700. }
  701. }
  702. else
  703. {
  704. // nothing selected to start with, so pick "My Inventory" as best guess
  705. new_selection = getItemByID(gInventory.getRootFolderID());
  706. // ... except if it's hidden from the UI.
  707. if (new_selection && new_selection->getHidden())
  708. {
  709. new_selection = NULL;
  710. }
  711. }
  712. if (new_selection)
  713. {
  714. setSelection(new_selection, FALSE, FALSE);
  715. }
  716. }
  717. }
  718. void LLFolderView::clearSelection()
  719. {
  720. if (mSelectedItems.size() > 0)
  721. {
  722. recursiveDeselect(FALSE);
  723. mSelectedItems.clear();
  724. }
  725. mSelectThisID.setNull();
  726. }
  727. BOOL LLFolderView::getSelectionList(std::set<LLUUID> &selection) const
  728. {
  729. for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); 
  730.  item_it != mSelectedItems.end(); 
  731.  ++item_it)
  732. {
  733. selection.insert((*item_it)->getListener()->getUUID());
  734. }
  735. return (selection.size() != 0);
  736. }
  737. BOOL LLFolderView::startDrag(LLToolDragAndDrop::ESource source)
  738. {
  739. std::vector<EDragAndDropType> types;
  740. std::vector<LLUUID> cargo_ids;
  741. selected_items_t::iterator item_it;
  742. BOOL can_drag = TRUE;
  743. if (!mSelectedItems.empty())
  744. {
  745. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  746. {
  747. EDragAndDropType type = DAD_NONE;
  748. LLUUID id = LLUUID::null;
  749. can_drag = can_drag && (*item_it)->getListener()->startDrag(&type, &id);
  750. types.push_back(type);
  751. cargo_ids.push_back(id);
  752. }
  753. LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, source, mSourceID); 
  754. }
  755. return can_drag;
  756. }
  757. void LLFolderView::commitRename( const LLSD& data )
  758. {
  759. finishRenamingItem();
  760. }
  761. void LLFolderView::draw()
  762. {
  763. static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", LLColor4::white);
  764. if (mDebugFilters)
  765. {
  766. std::string current_filter_string = llformat("Current Filter: %d, Least Filter: %d, Auto-accept Filter: %d",
  767. mFilter->getCurrentGeneration(), mFilter->getMinRequiredGeneration(), mFilter->getMustPassGeneration());
  768. LLFontGL::getFontMonospace()->renderUTF8(current_filter_string, 0, 2, 
  769. getRect().getHeight() - LLFontGL::getFontMonospace()->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), 
  770. LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
  771. }
  772. //LLFontGL* font = getLabelFontForStyle(mLabelStyle);
  773. // if cursor has moved off of me during drag and drop
  774. // close all auto opened folders
  775. if (!mDragAndDropThisFrame)
  776. {
  777. closeAutoOpenedFolders();
  778. }
  779. // while dragging, update selection rendering to reflect single/multi drag status
  780. if (LLToolDragAndDrop::getInstance()->hasMouseCapture())
  781. {
  782. EAcceptance last_accept = LLToolDragAndDrop::getInstance()->getLastAccept();
  783. if (last_accept == ACCEPT_YES_SINGLE || last_accept == ACCEPT_YES_COPY_SINGLE)
  784. {
  785. setShowSingleSelection(TRUE);
  786. }
  787. else
  788. {
  789. setShowSingleSelection(FALSE);
  790. }
  791. }
  792. else
  793. {
  794. setShowSingleSelection(FALSE);
  795. }
  796. if (mSearchTimer.getElapsedTimeF32() > gSavedSettings.getF32("TypeAheadTimeout") || !mSearchString.size())
  797. {
  798. mSearchString.clear();
  799. }
  800. if (hasVisibleChildren()
  801. || mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS)
  802. {
  803. mStatusText.clear();
  804. mStatusTextBox->setVisible( FALSE );
  805. }
  806. else
  807. {
  808. if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration())
  809. {
  810. mStatusText = LLTrans::getString("Searching");
  811. //font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL,  LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
  812. }
  813. else
  814. {
  815. mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage());
  816. //font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL,  LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
  817. }
  818. mStatusTextBox->setValue(mStatusText);
  819. mStatusTextBox->setVisible( TRUE );
  820. }
  821. LLFolderViewFolder::draw();
  822. mDragAndDropThisFrame = FALSE;
  823. }
  824. void LLFolderView::finishRenamingItem( void )
  825. {
  826. if(!mRenamer)
  827. {
  828. return;
  829. }
  830. if( mRenameItem )
  831. {
  832. mRenameItem->rename( mRenamer->getText() );
  833. }
  834. gFocusMgr.setTopCtrl( NULL );
  835. if( mRenameItem )
  836. {
  837. setSelectionFromRoot( mRenameItem, TRUE );
  838. mRenameItem = NULL;
  839. }
  840. // List is re-sorted alphabeticly, so scroll to make sure the selected item is visible.
  841. scrollToShowSelection();
  842. }
  843. void LLFolderView::closeRenamer( void )
  844. {
  845. // will commit current name (which could be same as original name)
  846. mRenamer->setFocus( FALSE );
  847. mRenamer->setVisible( FALSE );
  848. gFocusMgr.setTopCtrl( NULL );
  849. if( mRenameItem )
  850. {
  851. setSelectionFromRoot( mRenameItem, TRUE );
  852. mRenameItem = NULL;
  853. }
  854. }
  855. void LLFolderView::removeSelectedItems( void )
  856. {
  857. if(getVisible() && getEnabled())
  858. {
  859. // just in case we're removing the renaming item.
  860. mRenameItem = NULL;
  861. // create a temporary structure which we will use to remove
  862. // items, since the removal will futz with internal data
  863. // structures.
  864. std::vector<LLFolderViewItem*> items;
  865. S32 count = mSelectedItems.size();
  866. if(count == 0) return;
  867. LLFolderViewItem* item = NULL;
  868. selected_items_t::iterator item_it;
  869. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  870. {
  871. item = *item_it;
  872. if(item->isRemovable())
  873. {
  874. items.push_back(item);
  875. }
  876. else
  877. {
  878. llinfos << "Cannot delete " << item->getName() << llendl;
  879. return;
  880. }
  881. }
  882. // iterate through the new container.
  883. count = items.size();
  884. LLUUID new_selection_id;
  885. if(count == 1)
  886. {
  887. LLFolderViewItem* item_to_delete = items[0];
  888. LLFolderViewFolder* parent = item_to_delete->getParentFolder();
  889. LLFolderViewItem* new_selection = item_to_delete->getNextOpenNode(FALSE);
  890. if (!new_selection)
  891. {
  892. new_selection = item_to_delete->getPreviousOpenNode(FALSE);
  893. }
  894. if(parent)
  895. {
  896. if (parent->removeItem(item_to_delete))
  897. {
  898. // change selection on successful delete
  899. if (new_selection)
  900. {
  901. setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
  902. }
  903. else
  904. {
  905. setSelectionFromRoot(NULL, mParentPanel->hasFocus());
  906. }
  907. }
  908. }
  909. arrangeAll();
  910. }
  911. else if (count > 1)
  912. {
  913. LLDynamicArray<LLFolderViewEventListener*> listeners;
  914. LLFolderViewEventListener* listener;
  915. LLFolderViewItem* last_item = items[count - 1];
  916. LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE);
  917. while(new_selection && new_selection->isSelected())
  918. {
  919. new_selection = new_selection->getNextOpenNode(FALSE);
  920. }
  921. if (!new_selection)
  922. {
  923. new_selection = last_item->getPreviousOpenNode(FALSE);
  924. while (new_selection && new_selection->isSelected())
  925. {
  926. new_selection = new_selection->getPreviousOpenNode(FALSE);
  927. }
  928. }
  929. if (new_selection)
  930. {
  931. setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
  932. }
  933. else
  934. {
  935. setSelectionFromRoot(NULL, mParentPanel->hasFocus());
  936. }
  937. for(S32 i = 0; i < count; ++i)
  938. {
  939. listener = items[i]->getListener();
  940. if(listener && (listeners.find(listener) == LLDynamicArray<LLFolderViewEventListener*>::FAIL))
  941. {
  942. listeners.put(listener);
  943. }
  944. }
  945. listener = listeners.get(0);
  946. if(listener)
  947. {
  948. listener->removeBatch(listeners);
  949. }
  950. }
  951. arrangeAll();
  952. scrollToShowSelection();
  953. }
  954. }
  955. // open the selected item.
  956. void LLFolderView::openSelectedItems( void )
  957. {
  958. if(getVisible() && getEnabled())
  959. {
  960. if (mSelectedItems.size() == 1)
  961. {
  962. mSelectedItems.front()->openItem();
  963. }
  964. else
  965. {
  966. LLMultiPreview* multi_previewp = new LLMultiPreview();
  967. LLMultiProperties* multi_propertiesp = new LLMultiProperties();
  968. selected_items_t::iterator item_it;
  969. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  970. {
  971. // IT_{OBJECT,ATTACHMENT} creates LLProperties
  972. // floaters; others create LLPreviews.  Put
  973. // each one in the right type of container.
  974. LLFolderViewEventListener* listener = (*item_it)->getListener();
  975. bool is_prop = listener && (listener->getInventoryType() == LLInventoryType::IT_OBJECT || listener->getInventoryType() == LLInventoryType::IT_ATTACHMENT);
  976. if (is_prop)
  977. LLFloater::setFloaterHost(multi_propertiesp);
  978. else
  979. LLFloater::setFloaterHost(multi_previewp);
  980. (*item_it)->openItem();
  981. }
  982. LLFloater::setFloaterHost(NULL);
  983. // *NOTE: LLMulti* will safely auto-delete when open'd
  984. // without any children.
  985. multi_previewp->openFloater(LLSD());
  986. multi_propertiesp->openFloater(LLSD());
  987. }
  988. }
  989. }
  990. void LLFolderView::propertiesSelectedItems( void )
  991. {
  992. if(getVisible() && getEnabled())
  993. {
  994. if (mSelectedItems.size() == 1)
  995. {
  996. LLFolderViewItem* folder_item = mSelectedItems.front();
  997. if(!folder_item) return;
  998. folder_item->getListener()->showProperties();
  999. }
  1000. else
  1001. {
  1002. LLMultiProperties* multi_propertiesp = new LLMultiProperties();
  1003. LLFloater::setFloaterHost(multi_propertiesp);
  1004. selected_items_t::iterator item_it;
  1005. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  1006. {
  1007. (*item_it)->getListener()->showProperties();
  1008. }
  1009. LLFloater::setFloaterHost(NULL);
  1010. multi_propertiesp->openFloater(LLSD());
  1011. }
  1012. }
  1013. }
  1014. void LLFolderView::changeType(LLInventoryModel *model, LLFolderType::EType new_folder_type)
  1015. {
  1016. LLFolderBridge *folder_bridge = LLFolderBridge::sSelf;
  1017. if (!folder_bridge) return;
  1018. LLViewerInventoryCategory *cat = folder_bridge->getCategory();
  1019. if (!cat) return;
  1020. cat->changeType(new_folder_type);
  1021. }
  1022. void LLFolderView::autoOpenItem( LLFolderViewFolder* item )
  1023. {
  1024. if (mAutoOpenItems.check() == item || mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH)
  1025. {
  1026. return;
  1027. }
  1028. // close auto-opened folders
  1029. LLFolderViewFolder* close_item = mAutoOpenItems.check();
  1030. while (close_item && close_item != item->getParentFolder())
  1031. {
  1032. mAutoOpenItems.pop();
  1033. close_item->setOpenArrangeRecursively(FALSE);
  1034. close_item = mAutoOpenItems.check();
  1035. }
  1036. item->requestArrange();
  1037. mAutoOpenItems.push(item);
  1038. item->setOpen(TRUE);
  1039. LLRect content_rect = mScrollContainer->getContentWindowRect();
  1040. LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0);
  1041. scrollToShowItem(item, constraint_rect);
  1042. }
  1043. void LLFolderView::closeAutoOpenedFolders()
  1044. {
  1045. while (mAutoOpenItems.check())
  1046. {
  1047. LLFolderViewFolder* close_item = mAutoOpenItems.pop();
  1048. close_item->setOpen(FALSE);
  1049. }
  1050. if (mAutoOpenCandidate)
  1051. {
  1052. mAutoOpenCandidate->setAutoOpenCountdown(0.f);
  1053. }
  1054. mAutoOpenCandidate = NULL;
  1055. mAutoOpenTimer.stop();
  1056. }
  1057. BOOL LLFolderView::autoOpenTest(LLFolderViewFolder* folder)
  1058. {
  1059. if (folder && mAutoOpenCandidate == folder)
  1060. {
  1061. if (mAutoOpenTimer.getStarted())
  1062. {
  1063. if (!mAutoOpenCandidate->isOpen())
  1064. {
  1065. mAutoOpenCandidate->setAutoOpenCountdown(clamp_rescale(mAutoOpenTimer.getElapsedTimeF32(), 0.f, sAutoOpenTime, 0.f, 1.f));
  1066. }
  1067. if (mAutoOpenTimer.getElapsedTimeF32() > sAutoOpenTime)
  1068. {
  1069. autoOpenItem(folder);
  1070. mAutoOpenTimer.stop();
  1071. return TRUE;
  1072. }
  1073. }
  1074. return FALSE;
  1075. }
  1076. // otherwise new candidate, restart timer
  1077. if (mAutoOpenCandidate)
  1078. {
  1079. mAutoOpenCandidate->setAutoOpenCountdown(0.f);
  1080. }
  1081. mAutoOpenCandidate = folder;
  1082. mAutoOpenTimer.start();
  1083. return FALSE;
  1084. }
  1085. BOOL LLFolderView::canCopy() const
  1086. {
  1087. if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0)))
  1088. {
  1089. return FALSE;
  1090. }
  1091. for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it)
  1092. {
  1093. const LLFolderViewItem* item = *selected_it;
  1094. if (!item->getListener()->isItemCopyable())
  1095. {
  1096. return FALSE;
  1097. }
  1098. }
  1099. return TRUE;
  1100. }
  1101. // copy selected item
  1102. void LLFolderView::copy()
  1103. {
  1104. // *NOTE: total hack to clear the inventory clipboard
  1105. LLInventoryClipboard::instance().reset();
  1106. S32 count = mSelectedItems.size();
  1107. if(getVisible() && getEnabled() && (count > 0))
  1108. {
  1109. LLFolderViewEventListener* listener = NULL;
  1110. selected_items_t::iterator item_it;
  1111. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  1112. {
  1113. listener = (*item_it)->getListener();
  1114. if(listener)
  1115. {
  1116. listener->copyToClipboard();
  1117. }
  1118. }
  1119. }
  1120. mSearchString.clear();
  1121. }
  1122. BOOL LLFolderView::canCut() const
  1123. {
  1124. if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0)))
  1125. {
  1126. return FALSE;
  1127. }
  1128. for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it)
  1129. {
  1130. const LLFolderViewItem* item = *selected_it;
  1131. const LLFolderViewEventListener* listener = item->getListener();
  1132. if (!listener || !listener->isItemRemovable())
  1133. {
  1134. return FALSE;
  1135. }
  1136. }
  1137. return TRUE;
  1138. }
  1139. void LLFolderView::cut()
  1140. {
  1141. // clear the inventory clipboard
  1142. LLInventoryClipboard::instance().reset();
  1143. S32 count = mSelectedItems.size();
  1144. if(getVisible() && getEnabled() && (count > 0))
  1145. {
  1146. LLFolderViewEventListener* listener = NULL;
  1147. selected_items_t::iterator item_it;
  1148. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  1149. {
  1150. listener = (*item_it)->getListener();
  1151. if(listener)
  1152. {
  1153. listener->cutToClipboard();
  1154. }
  1155. }
  1156. }
  1157. mSearchString.clear();
  1158. }
  1159. BOOL LLFolderView::canPaste() const
  1160. {
  1161. if (mSelectedItems.empty())
  1162. {
  1163. return FALSE;
  1164. }
  1165. if(getVisible() && getEnabled())
  1166. {
  1167. for (selected_items_t::const_iterator item_it = mSelectedItems.begin();
  1168.  item_it != mSelectedItems.end(); ++item_it)
  1169. {
  1170. // *TODO: only check folders and parent folders of items
  1171. const LLFolderViewItem* item = (*item_it);
  1172. const LLFolderViewEventListener* listener = item->getListener();
  1173. if(!listener || !listener->isClipboardPasteable())
  1174. {
  1175. const LLFolderViewFolder* folderp = item->getParentFolder();
  1176. listener = folderp->getListener();
  1177. if (!listener || !listener->isClipboardPasteable())
  1178. {
  1179. return FALSE;
  1180. }
  1181. }
  1182. }
  1183. return TRUE;
  1184. }
  1185. return FALSE;
  1186. }
  1187. // paste selected item
  1188. void LLFolderView::paste()
  1189. {
  1190. if(getVisible() && getEnabled())
  1191. {
  1192. // find set of unique folders to paste into
  1193. std::set<LLFolderViewItem*> folder_set;
  1194. selected_items_t::iterator selected_it;
  1195. for (selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it)
  1196. {
  1197. LLFolderViewItem* item = *selected_it;
  1198. LLFolderViewEventListener* listener = item->getListener();
  1199. if (listener->getInventoryType() != LLInventoryType::IT_CATEGORY)
  1200. {
  1201. item = item->getParentFolder();
  1202. }
  1203. folder_set.insert(item);
  1204. }
  1205. std::set<LLFolderViewItem*>::iterator set_iter;
  1206. for(set_iter = folder_set.begin(); set_iter != folder_set.end(); ++set_iter)
  1207. {
  1208. LLFolderViewEventListener* listener = (*set_iter)->getListener();
  1209. if(listener && listener->isClipboardPasteable())
  1210. {
  1211. listener->pasteFromClipboard();
  1212. }
  1213. }
  1214. }
  1215. mSearchString.clear();
  1216. }
  1217. // public rename functionality - can only start the process
  1218. void LLFolderView::startRenamingSelectedItem( void )
  1219. {
  1220. // make sure selection is visible
  1221. scrollToShowSelection();
  1222. S32 count = mSelectedItems.size();
  1223. LLFolderViewItem* item = NULL;
  1224. if(count > 0)
  1225. {
  1226. item = mSelectedItems.front();
  1227. }
  1228. if(getVisible() && getEnabled() && (count == 1) && item && item->getListener() &&
  1229.    item->getListener()->isItemRenameable())
  1230. {
  1231. mRenameItem = item;
  1232. updateRenamerPosition();
  1233. mRenamer->setText(item->getName());
  1234. mRenamer->selectAll();
  1235. mRenamer->setVisible( TRUE );
  1236. // set focus will fail unless item is visible
  1237. mRenamer->setFocus( TRUE );
  1238. mRenamer->setTopLostCallback(boost::bind(onRenamerLost, _1));
  1239. mRenamer->setFocusLostCallback(boost::bind(onRenamerLost, _1));
  1240. gFocusMgr.setTopCtrl( mRenamer );
  1241. }
  1242. }
  1243. BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
  1244. {
  1245. BOOL handled = FALSE;
  1246. // SL-51858: Key presses are not being passed to the Popup menu.
  1247. // A proper fix is non-trivial so instead just close the menu.
  1248. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
  1249. if (menu && menu->isOpen())
  1250. {
  1251. LLMenuGL::sMenuContainer->hideMenus();
  1252. }
  1253. LLView *item = NULL;
  1254. if (getChildCount() > 0)
  1255. {
  1256. item = *(getChildList()->begin());
  1257. }
  1258. switch( key )
  1259. {
  1260. case KEY_F2:
  1261. mSearchString.clear();
  1262. startRenamingSelectedItem();
  1263. handled = TRUE;
  1264. break;
  1265. case KEY_RETURN:
  1266. if (mask == MASK_NONE)
  1267. {
  1268. if( mRenameItem && mRenamer->getVisible() )
  1269. {
  1270. finishRenamingItem();
  1271. mSearchString.clear();
  1272. handled = TRUE;
  1273. }
  1274. else
  1275. {
  1276. LLFolderView::openSelectedItems();
  1277. handled = TRUE;
  1278. }
  1279. }
  1280. break;
  1281. case KEY_ESCAPE:
  1282. if( mRenameItem && mRenamer->getVisible() )
  1283. {
  1284. closeRenamer();
  1285. handled = TRUE;
  1286. }
  1287. mSearchString.clear();
  1288. break;
  1289. case KEY_PAGE_UP:
  1290. mSearchString.clear();
  1291. mScrollContainer->pageUp(30);
  1292. handled = TRUE;
  1293. break;
  1294. case KEY_PAGE_DOWN:
  1295. mSearchString.clear();
  1296. mScrollContainer->pageDown(30);
  1297. handled = TRUE;
  1298. break;
  1299. case KEY_HOME:
  1300. mSearchString.clear();
  1301. mScrollContainer->goToTop();
  1302. handled = TRUE;
  1303. break;
  1304. case KEY_END:
  1305. mSearchString.clear();
  1306. mScrollContainer->goToBottom();
  1307. break;
  1308. case KEY_DOWN:
  1309. if((mSelectedItems.size() > 0) && mScrollContainer)
  1310. {
  1311. LLFolderViewItem* last_selected = getCurSelectedItem();
  1312. if (!mKeyboardSelection)
  1313. {
  1314. setSelection(last_selected, FALSE, TRUE);
  1315. mKeyboardSelection = TRUE;
  1316. }
  1317. LLFolderViewItem* next = NULL;
  1318. if (mask & MASK_SHIFT)
  1319. {
  1320. // don't shift select down to children of folders (they are implicitly selected through parent)
  1321. next = last_selected->getNextOpenNode(FALSE);
  1322. if (next)
  1323. {
  1324. if (next->isSelected())
  1325. {
  1326. // shrink selection
  1327. changeSelectionFromRoot(last_selected, FALSE);
  1328. }
  1329. else if (last_selected->getParentFolder() == next->getParentFolder())
  1330. {
  1331. // grow selection
  1332. changeSelectionFromRoot(next, TRUE);
  1333. }
  1334. }
  1335. }
  1336. else
  1337. {
  1338. next = last_selected->getNextOpenNode();
  1339. if( next )
  1340. {
  1341. if (next == last_selected)
  1342. {
  1343. //special case for LLAccordionCtrl
  1344. if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed
  1345. {
  1346. clearSelection();
  1347. return TRUE;
  1348. }
  1349. return FALSE;
  1350. }
  1351. setSelection( next, FALSE, TRUE );
  1352. }
  1353. else
  1354. {
  1355. //special case for LLAccordionCtrl
  1356. if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed
  1357. {
  1358. clearSelection();
  1359. return TRUE;
  1360. }
  1361. return FALSE;
  1362. }
  1363. }
  1364. scrollToShowSelection();
  1365. mSearchString.clear();
  1366. handled = TRUE;
  1367. }
  1368. break;
  1369. case KEY_UP:
  1370. if((mSelectedItems.size() > 0) && mScrollContainer)
  1371. {
  1372. LLFolderViewItem* last_selected = mSelectedItems.back();
  1373. if (!mKeyboardSelection)
  1374. {
  1375. setSelection(last_selected, FALSE, TRUE);
  1376. mKeyboardSelection = TRUE;
  1377. }
  1378. LLFolderViewItem* prev = NULL;
  1379. if (mask & MASK_SHIFT)
  1380. {
  1381. // don't shift select down to children of folders (they are implicitly selected through parent)
  1382. prev = last_selected->getPreviousOpenNode(FALSE);
  1383. if (prev)
  1384. {
  1385. if (prev->isSelected())
  1386. {
  1387. // shrink selection
  1388. changeSelectionFromRoot(last_selected, FALSE);
  1389. }
  1390. else if (last_selected->getParentFolder() == prev->getParentFolder())
  1391. {
  1392. // grow selection
  1393. changeSelectionFromRoot(prev, TRUE);
  1394. }
  1395. }
  1396. }
  1397. else
  1398. {
  1399. prev = last_selected->getPreviousOpenNode();
  1400. if( prev )
  1401. {
  1402. if (prev == this)
  1403. {
  1404. // If case we are in accordion tab notify parent to go to the previous accordion
  1405. if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed
  1406. {
  1407. clearSelection();
  1408. return TRUE;
  1409. }
  1410. return FALSE;
  1411. }
  1412. setSelection( prev, FALSE, TRUE );
  1413. }
  1414. }
  1415. scrollToShowSelection();
  1416. mSearchString.clear();
  1417. handled = TRUE;
  1418. }
  1419. break;
  1420. case KEY_RIGHT:
  1421. if(mSelectedItems.size())
  1422. {
  1423. LLFolderViewItem* last_selected = getCurSelectedItem();
  1424. last_selected->setOpen( TRUE );
  1425. mSearchString.clear();
  1426. handled = TRUE;
  1427. }
  1428. break;
  1429. case KEY_LEFT:
  1430. if(mSelectedItems.size())
  1431. {
  1432. LLFolderViewItem* last_selected = getCurSelectedItem();
  1433. LLFolderViewItem* parent_folder = last_selected->getParentFolder();
  1434. if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder())
  1435. {
  1436. // Don't change selectin to hidden folder. See EXT-5328.
  1437. if (!parent_folder->getHidden())
  1438. {
  1439. setSelection(parent_folder, FALSE, TRUE);
  1440. }
  1441. }
  1442. else
  1443. {
  1444. last_selected->setOpen( FALSE );
  1445. }
  1446. mSearchString.clear();
  1447. scrollToShowSelection();
  1448. handled = TRUE;
  1449. }
  1450. break;
  1451. }
  1452. if (!handled && mParentPanel->hasFocus())
  1453. {
  1454. if (key == KEY_BACKSPACE)
  1455. {
  1456. mSearchTimer.reset();
  1457. if (mSearchString.size())
  1458. {
  1459. mSearchString.erase(mSearchString.size() - 1, 1);
  1460. }
  1461. search(getCurSelectedItem(), mSearchString, FALSE);
  1462. handled = TRUE;
  1463. }
  1464. }
  1465. return handled;
  1466. }
  1467. BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char)
  1468. {
  1469. if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL
  1470. {
  1471. return FALSE;
  1472. }
  1473. if (uni_char > 0x7f)
  1474. {
  1475. llwarns << "LLFolderView::handleUnicodeCharHere - Don't handle non-ascii yet, aborting" << llendl;
  1476. return FALSE;
  1477. }
  1478. BOOL handled = FALSE;
  1479. if (gFocusMgr.childHasKeyboardFocus(getRoot()))
  1480. {
  1481. // SL-51858: Key presses are not being passed to the Popup menu.
  1482. // A proper fix is non-trivial so instead just close the menu.
  1483. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
  1484. if (menu && menu->isOpen())
  1485. {
  1486. LLMenuGL::sMenuContainer->hideMenus();
  1487. }
  1488. //do text search
  1489. if (mSearchTimer.getElapsedTimeF32() > gSavedSettings.getF32("TypeAheadTimeout"))
  1490. {
  1491. mSearchString.clear();
  1492. }
  1493. mSearchTimer.reset();
  1494. if (mSearchString.size() < 128)
  1495. {
  1496. mSearchString += uni_char;
  1497. }
  1498. search(getCurSelectedItem(), mSearchString, FALSE);
  1499. handled = TRUE;
  1500. }
  1501. return handled;
  1502. }
  1503. BOOL LLFolderView::canDoDelete() const
  1504. {
  1505. if (mSelectedItems.size() == 0) return FALSE;
  1506. for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  1507. {
  1508. if (!(*item_it)->getListener()->isItemRemovable())
  1509. {
  1510. return FALSE;
  1511. }
  1512. }
  1513. return TRUE;
  1514. }
  1515. void LLFolderView::doDelete()
  1516. {
  1517. if(mSelectedItems.size() > 0)
  1518. {
  1519. removeSelectedItems();
  1520. }
  1521. }
  1522. BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask )
  1523. {
  1524. mKeyboardSelection = FALSE;
  1525. mSearchString.clear();
  1526. mParentPanel->setFocus(TRUE);
  1527. return LLView::handleMouseDown( x, y, mask );
  1528. }
  1529. BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward)
  1530. {
  1531. // get first selected item
  1532. LLFolderViewItem* search_item = first_item;
  1533. // make sure search string is upper case
  1534. std::string upper_case_string = search_string;
  1535. LLStringUtil::toUpper(upper_case_string);
  1536. // if nothing selected, select first item in folder
  1537. if (!search_item)
  1538. {
  1539. // start from first item
  1540. search_item = getNextFromChild(NULL);
  1541. }
  1542. // search over all open nodes for first substring match (with wrapping)
  1543. BOOL found = FALSE;
  1544. LLFolderViewItem* original_search_item = search_item;
  1545. do
  1546. {
  1547. // wrap at end
  1548. if (!search_item)
  1549. {
  1550. if (backward)
  1551. {
  1552. search_item = getPreviousFromChild(NULL);
  1553. }
  1554. else
  1555. {
  1556. search_item = getNextFromChild(NULL);
  1557. }
  1558. if (!search_item || search_item == original_search_item)
  1559. {
  1560. break;
  1561. }
  1562. }
  1563. const std::string current_item_label(search_item->getSearchableLabel());
  1564. S32 search_string_length = llmin(upper_case_string.size(), current_item_label.size());
  1565. if (!current_item_label.compare(0, search_string_length, upper_case_string))
  1566. {
  1567. found = TRUE;
  1568. break;
  1569. }
  1570. if (backward)
  1571. {
  1572. search_item = search_item->getPreviousOpenNode();
  1573. }
  1574. else
  1575. {
  1576. search_item = search_item->getNextOpenNode();
  1577. }
  1578. } while(search_item != original_search_item);
  1579. if (found)
  1580. {
  1581. setSelection(search_item, FALSE, TRUE);
  1582. scrollToShowSelection();
  1583. }
  1584. return found;
  1585. }
  1586. BOOL LLFolderView::handleDoubleClick( S32 x, S32 y, MASK mask )
  1587. {
  1588. // skip LLFolderViewFolder::handleDoubleClick()
  1589. return LLView::handleDoubleClick( x, y, mask );
  1590. }
  1591. BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
  1592. {
  1593. // all user operations move keyboard focus to inventory
  1594. // this way, we know when to stop auto-updating a search
  1595. mParentPanel->setFocus(TRUE);
  1596. BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;
  1597. S32 count = mSelectedItems.size();
  1598. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
  1599. if(handled && (count > 0) && menu)
  1600. {
  1601. if (mCallbackRegistrar)
  1602. mCallbackRegistrar->pushScope();
  1603. //menu->empty();
  1604. const LLView::child_list_t *list = menu->getChildList();
  1605. LLView::child_list_t::const_iterator menu_itor;
  1606. for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor)
  1607. {
  1608. (*menu_itor)->setVisible(TRUE);
  1609. (*menu_itor)->setEnabled(TRUE);
  1610. }
  1611. // Successively filter out invalid options
  1612. selected_items_t::iterator item_itor;
  1613. U32 flags = FIRST_SELECTED_ITEM;
  1614. for (item_itor = mSelectedItems.begin(); item_itor != mSelectedItems.end(); ++item_itor)
  1615. {
  1616. (*item_itor)->buildContextMenu(*menu, flags);
  1617. flags = 0x0;
  1618. }
  1619. menu->updateParent(LLMenuGL::sMenuContainer);
  1620. LLMenuGL::showPopup(this, menu, x, y);
  1621. if (mCallbackRegistrar)
  1622. mCallbackRegistrar->popScope();
  1623. }
  1624. else
  1625. {
  1626. if(menu && menu->getVisible())
  1627. {
  1628. menu->setVisible(FALSE);
  1629. }
  1630. setSelection(NULL, FALSE, TRUE);
  1631. }
  1632. return handled;
  1633. }
  1634. BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask )
  1635. {
  1636. return LLView::handleHover( x, y, mask );
  1637. }
  1638. BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  1639.  EDragAndDropType cargo_type,
  1640.  void* cargo_data, 
  1641.  EAcceptance* accept,
  1642.  std::string& tooltip_msg)
  1643. {
  1644. mDragAndDropThisFrame = TRUE;
  1645. BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data,
  1646.  accept, tooltip_msg);
  1647. // When there are no visible children drag and drop is handled
  1648. // by the folder which is the hierarchy root.
  1649. if (!handled && !hasVisibleChildren())
  1650. {
  1651. handled = mFolders.front()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg);
  1652. }
  1653. if (handled)
  1654. {
  1655. lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderView" << llendl;
  1656. }
  1657. return handled;
  1658. }
  1659. void LLFolderView::deleteAllChildren()
  1660. {
  1661. if(mRenamer == gFocusMgr.getTopCtrl())
  1662. {
  1663. gFocusMgr.setTopCtrl(NULL);
  1664. }
  1665. LLView::deleteViewByHandle(mPopupMenuHandle);
  1666. mPopupMenuHandle = LLHandle<LLView>();
  1667. mRenamer = NULL;
  1668. mRenameItem = NULL;
  1669. clearSelection();
  1670. LLView::deleteAllChildren();
  1671. }
  1672. void LLFolderView::scrollToShowSelection()
  1673. {
  1674. if (mSelectedItems.size())
  1675. {
  1676. mNeedsScroll = TRUE;
  1677. }
  1678. }
  1679. // If the parent is scroll containter, scroll it to make the selection
  1680. // is maximally visible.
  1681. void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect)
  1682. {
  1683. if (!mScrollContainer) return;
  1684. // don't scroll to items when mouse is being used to scroll/drag and drop
  1685. if (gFocusMgr.childHasMouseCapture(mScrollContainer))
  1686. {
  1687. mNeedsScroll = FALSE;
  1688. return;
  1689. }
  1690. // if item exists and is in visible portion of parent folder...
  1691. if(item)
  1692. {
  1693. LLRect local_rect = item->getLocalRect();
  1694. LLRect item_scrolled_rect; // item position relative to display area of scroller
  1695. LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect();
  1696. S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); 
  1697. S32 label_height = llround(getLabelFontForStyle(mLabelStyle)->getLineHeight()); 
  1698. // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder
  1699. S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); 
  1700. // get portion of item that we want to see...
  1701. LLRect item_local_rect = LLRect(item->getIndentation(), 
  1702. local_rect.getHeight(), 
  1703. llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()), 
  1704. llmax(0, local_rect.getHeight() - max_height_to_show));
  1705. LLRect item_doc_rect;
  1706. item->localRectToOtherView(item_local_rect, &item_doc_rect, this); 
  1707. mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect );
  1708. }
  1709. }
  1710. LLRect LLFolderView::getVisibleRect()
  1711. {
  1712. S32 visible_height = mScrollContainer->getRect().getHeight();
  1713. S32 visible_width = mScrollContainer->getRect().getWidth();
  1714. LLRect visible_rect;
  1715. visible_rect.setLeftTopAndSize(-getRect().mLeft, visible_height - getRect().mBottom, visible_width, visible_height);
  1716. return visible_rect;
  1717. }
  1718. BOOL LLFolderView::getShowSelectionContext()
  1719. {
  1720. if (mShowSelectionContext)
  1721. {
  1722. return TRUE;
  1723. }
  1724. LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
  1725. if (menu && menu->getVisible())
  1726. {
  1727. return TRUE;
  1728. }
  1729. return FALSE;
  1730. }
  1731. void LLFolderView::setShowSingleSelection(BOOL show)
  1732. {
  1733. if (show != mShowSingleSelection)
  1734. {
  1735. mMultiSelectionFadeTimer.reset();
  1736. mShowSingleSelection = show;
  1737. }
  1738. }
  1739. void LLFolderView::addItemID(const LLUUID& id, LLFolderViewItem* itemp)
  1740. {
  1741. mItemMap[id] = itemp;
  1742. }
  1743. void LLFolderView::removeItemID(const LLUUID& id)
  1744. {
  1745. mItemMap.erase(id);
  1746. }
  1747. LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id)
  1748. {
  1749. if (id.isNull())
  1750. {
  1751. return this;
  1752. }
  1753. std::map<LLUUID, LLFolderViewItem*>::iterator map_it;
  1754. map_it = mItemMap.find(id);
  1755. if (map_it != mItemMap.end())
  1756. {
  1757. return map_it->second;
  1758. }
  1759. return NULL;
  1760. }
  1761. LLFolderViewFolder* LLFolderView::getFolderByID(const LLUUID& id)
  1762. {
  1763. if (id.isNull())
  1764. {
  1765. return this;
  1766. }
  1767. for (folders_t::iterator iter = mFolders.begin();
  1768.  iter != mFolders.end();
  1769.  ++iter)
  1770. {
  1771. LLFolderViewFolder *folder = (*iter);
  1772. if (folder->getListener()->getUUID() == id)
  1773. {
  1774. return folder;
  1775. }
  1776. }
  1777. return NULL;
  1778. }
  1779. bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata)
  1780. {
  1781. std::string action = userdata.asString();
  1782. if ("rename" == action)
  1783. {
  1784. startRenamingSelectedItem();
  1785. return true;
  1786. }
  1787. if ("delete" == action)
  1788. {
  1789. removeSelectedItems();
  1790. return true;
  1791. }
  1792. if ("copy" == action)
  1793. {
  1794. LLInventoryClipboard::instance().reset();
  1795. }
  1796. static const std::string change_folder_string = "change_folder_type_";
  1797. if (action.length() > change_folder_string.length() && 
  1798. (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0))
  1799. {
  1800. LLFolderType::EType new_folder_type = LLViewerFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length()));
  1801. changeType(model, new_folder_type);
  1802. return true;
  1803. }
  1804. std::set<LLUUID> selected_items;
  1805. getSelectionList(selected_items);
  1806. LLMultiPreview* multi_previewp = NULL;
  1807. LLMultiProperties* multi_propertiesp = NULL;
  1808. if (("task_open" == action  || "open" == action) && selected_items.size() > 1)
  1809. {
  1810. multi_previewp = new LLMultiPreview();
  1811. gFloaterView->addChild(multi_previewp);
  1812. LLFloater::setFloaterHost(multi_previewp);
  1813. }
  1814. else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1)
  1815. {
  1816. multi_propertiesp = new LLMultiProperties();
  1817. gFloaterView->addChild(multi_propertiesp);
  1818. LLFloater::setFloaterHost(multi_propertiesp);
  1819. }
  1820. std::set<LLUUID>::iterator set_iter;
  1821. for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter)
  1822. {
  1823. LLFolderViewItem* folder_item = getItemByID(*set_iter);
  1824. if(!folder_item) continue;
  1825. LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener();
  1826. if(!bridge) continue;
  1827. bridge->performAction(this, model, action);
  1828. }
  1829. LLFloater::setFloaterHost(NULL);
  1830. if (multi_previewp)
  1831. {
  1832. multi_previewp->openFloater(LLSD());
  1833. }
  1834. else if (multi_propertiesp)
  1835. {
  1836. multi_propertiesp->openFloater(LLSD());
  1837. }
  1838. return true;
  1839. }
  1840. static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select");
  1841. static LLFastTimer::DeclareTimer FTM_INVENTORY("Inventory");
  1842. // Main idle routine
  1843. void LLFolderView::doIdle()
  1844. {
  1845. // If this is associated with the user's inventory, don't do anything
  1846. // until that inventory is loaded up.
  1847. const LLInventoryPanel *inventory_panel = dynamic_cast<LLInventoryPanel*>(mParentPanel);
  1848. if (inventory_panel && !inventory_panel->getIsViewsInitialized())
  1849. {
  1850. return;
  1851. }
  1852. LLFastTimer t2(FTM_INVENTORY);
  1853. BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters");
  1854. if (debug_filters != getDebugFilters())
  1855. {
  1856. mDebugFilters = debug_filters;
  1857. arrangeAll();
  1858. }
  1859. mFilter->clearModified();
  1860. BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter->getCurrentGeneration() && 
  1861. mFilter->isNotDefault();
  1862. mNeedsAutoSelect = filter_modified_and_active &&
  1863. !(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture());
  1864. // filter to determine visiblity before arranging
  1865. filterFromRoot();
  1866. // automatically show matching items, and select first one
  1867. // do this every frame until user puts keyboard focus into the inventory window
  1868. // signaling the end of the automatic update
  1869. // only do this when mNeedsFilter is set, meaning filtered items have
  1870. // potentially changed
  1871. if (mNeedsAutoSelect)
  1872. {
  1873. LLFastTimer t3(FTM_AUTO_SELECT);
  1874. // select new item only if a filtered item not currently selected
  1875. LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back();
  1876. if ((!selected_itemp || !selected_itemp->getFiltered()) && !mAutoSelectOverride)
  1877. {
  1878. // select first filtered item
  1879. LLSelectFirstFilteredItem filter;
  1880. applyFunctorRecursively(filter);
  1881. }
  1882. scrollToShowSelection();
  1883. }
  1884. // during filtering process, try to pin selected item's location on screen
  1885. // this will happen when searching your inventory and when new items arrive
  1886. if (filter_modified_and_active)
  1887. {
  1888. // calculate rectangle to pin item to at start of animated rearrange
  1889. if (!mPinningSelectedItem && !mSelectedItems.empty())
  1890. {
  1891. // lets pin it!
  1892. mPinningSelectedItem = TRUE;
  1893. LLRect visible_content_rect = mScrollContainer->getVisibleContentRect();
  1894. LLFolderViewItem* selected_item = mSelectedItems.back();
  1895. LLRect item_rect;
  1896. selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this);
  1897. // if item is visible in scrolled region
  1898. if (visible_content_rect.overlaps(item_rect))
  1899. {
  1900. // then attempt to keep it in same place on screen
  1901. mScrollConstraintRect = item_rect;
  1902. mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom);
  1903. }
  1904. else
  1905. {
  1906. // otherwise we just want it onscreen somewhere
  1907. LLRect content_rect = mScrollContainer->getContentWindowRect();
  1908. mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight());
  1909. }
  1910. }
  1911. }
  1912. else
  1913. {
  1914. // stop pinning selected item after folders stop rearranging
  1915. if (!needsArrange())
  1916. {
  1917. mPinningSelectedItem = FALSE;
  1918. }
  1919. }
  1920. LLRect constraint_rect;
  1921. if (mPinningSelectedItem)
  1922. {
  1923. // use last known constraint rect for pinned item
  1924. constraint_rect = mScrollConstraintRect;
  1925. }
  1926. else
  1927. {
  1928. // during normal use (page up/page down, etc), just try to fit item on screen
  1929. LLRect content_rect = mScrollContainer->getContentWindowRect();
  1930. constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight());
  1931. }
  1932. BOOL is_visible = isInVisibleChain();
  1933. if ( is_visible )
  1934. {
  1935. sanitizeSelection();
  1936. if( needsArrange() )
  1937. {
  1938. arrangeFromRoot();
  1939. }
  1940. }
  1941. if (mSelectedItems.size() && mNeedsScroll)
  1942. {
  1943. scrollToShowItem(mSelectedItems.back(), constraint_rect);
  1944. // continue scrolling until animated layout change is done
  1945. if (!filter_modified_and_active 
  1946. && (!needsArrange() || !is_visible))
  1947. {
  1948. mNeedsScroll = FALSE;
  1949. }
  1950. }
  1951. if (mSignalSelectCallback)
  1952. {
  1953. //RN: we use keyboard focus as a proxy for user-explicit actions
  1954. BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS);
  1955. mSelectSignal(mSelectedItems, take_keyboard_focus);
  1956. }
  1957. mSignalSelectCallback = FALSE;
  1958. }
  1959. //static
  1960. void LLFolderView::idle(void* user_data)
  1961. {
  1962. LLFolderView* self = (LLFolderView*)user_data;
  1963. if ( self )
  1964. { // Do the real idle 
  1965. self->doIdle();
  1966. }
  1967. }
  1968. void LLFolderView::dumpSelectionInformation()
  1969. {
  1970. llinfos << "LLFolderView::dumpSelectionInformation()" << llendl;
  1971. llinfos << "****************************************" << llendl;
  1972. selected_items_t::iterator item_it;
  1973. for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
  1974. {
  1975. llinfos << "  " << (*item_it)->getName() << llendl;
  1976. }
  1977. llinfos << "****************************************" << llendl;
  1978. }
  1979. void LLFolderView::updateRenamerPosition()
  1980. {
  1981. if(mRenameItem)
  1982. {
  1983. // See also LLFolderViewItem::draw()
  1984. S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mRenameItem->getIndentation();
  1985. S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD;
  1986. mRenameItem->localPointToScreen( x, y, &x, &y );
  1987. screenPointToLocal( x, y, &x, &y );
  1988. mRenamer->setOrigin( x, y );
  1989. LLRect scroller_rect(0, 0, gViewerWindow->getWindowWidthScaled(), 0);
  1990. if (mScrollContainer)
  1991. {
  1992. scroller_rect = mScrollContainer->getContentWindowRect();
  1993. }
  1994. S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH);
  1995. S32 height = mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD;
  1996. mRenamer->reshape( width, height, TRUE );
  1997. }
  1998. }
  1999. bool LLFolderView::selectFirstItem()
  2000. {
  2001. for (folders_t::iterator iter = mFolders.begin();
  2002.  iter != mFolders.end();)
  2003. {
  2004. LLFolderViewFolder* folder = (*iter );
  2005. if (folder->getVisible())
  2006. {
  2007. LLFolderViewItem* itemp = folder->getNextFromChild(0,true);
  2008. if(itemp)
  2009. setSelection(itemp,FALSE,TRUE);
  2010. return true;
  2011. }
  2012. }
  2013. for(items_t::iterator iit = mItems.begin();
  2014. iit != mItems.end(); ++iit)
  2015. {
  2016. LLFolderViewItem* itemp = (*iit);
  2017. if (itemp->getVisible())
  2018. {
  2019. setSelection(itemp,FALSE,TRUE);
  2020. return true;
  2021. }
  2022. }
  2023. return false;
  2024. }
  2025. bool LLFolderView::selectLastItem()
  2026. {
  2027. for(items_t::reverse_iterator iit = mItems.rbegin();
  2028. iit != mItems.rend(); ++iit)
  2029. {
  2030. LLFolderViewItem* itemp = (*iit);
  2031. if (itemp->getVisible())
  2032. {
  2033. setSelection(itemp,FALSE,TRUE);
  2034. return true;
  2035. }
  2036. }
  2037. for (folders_t::reverse_iterator iter = mFolders.rbegin();
  2038.  iter != mFolders.rend();)
  2039. {
  2040. LLFolderViewFolder* folder = (*iter);
  2041. if (folder->getVisible())
  2042. {
  2043. LLFolderViewItem* itemp = folder->getPreviousFromChild(0,true);
  2044. if(itemp)
  2045. setSelection(itemp,FALSE,TRUE);
  2046. return true;
  2047. }
  2048. }
  2049. return false;
  2050. }
  2051. S32 LLFolderView::notify(const LLSD& info) 
  2052. {
  2053. if(info.has("action"))
  2054. {
  2055. std::string str_action = info["action"];
  2056. if(str_action == "select_first")
  2057. {
  2058. setFocus(true);
  2059. selectFirstItem();
  2060. return 1;
  2061. }
  2062. else if(str_action == "select_last")
  2063. {
  2064. setFocus(true);
  2065. selectLastItem();
  2066. return 1;
  2067. }
  2068. }
  2069. return 0;
  2070. }
  2071. ///----------------------------------------------------------------------------
  2072. /// Local function definitions
  2073. ///----------------------------------------------------------------------------
  2074. //static 
  2075. void LLFolderView::onRenamerLost( LLFocusableElement* renamer)
  2076. {
  2077. LLUICtrl* uictrl = dynamic_cast<LLUICtrl*>(renamer);
  2078. if (uictrl)
  2079. {
  2080. uictrl->setVisible(FALSE);
  2081. }
  2082. }
  2083. LLInventoryFilter* LLFolderView::getFilter()
  2084. {
  2085. return mFilter;
  2086. }
  2087. void LLFolderView::setFilterPermMask( PermissionMask filter_perm_mask )
  2088. {
  2089. mFilter->setFilterPermissions(filter_perm_mask);
  2090. }
  2091. U32 LLFolderView::getFilterObjectTypes() const
  2092. {
  2093. return mFilter->getFilterObjectTypes();
  2094. }
  2095. PermissionMask LLFolderView::getFilterPermissions() const
  2096. {
  2097. return mFilter->getFilterPermissions();
  2098. }
  2099. BOOL LLFolderView::isFilterModified()
  2100. {
  2101. return mFilter->isNotDefault();
  2102. }
  2103. BOOL LLFolderView::getAllowMultiSelect()
  2104. {
  2105. return mAllowMultiSelect;
  2106. }
  2107. void delete_selected_item(void* user_data)
  2108. {
  2109. if(user_data)
  2110. {
  2111. LLFolderView* fv = reinterpret_cast<LLFolderView*>(user_data);
  2112. fv->removeSelectedItems();
  2113. }
  2114. }
  2115. void copy_selected_item(void* user_data)
  2116. {
  2117. if(user_data)
  2118. {
  2119. LLFolderView* fv = reinterpret_cast<LLFolderView*>(user_data);
  2120. fv->copy();
  2121. }
  2122. }
  2123. void paste_items(void* user_data)
  2124. {
  2125. if(user_data)
  2126. {
  2127. LLFolderView* fv = reinterpret_cast<LLFolderView*>(user_data);
  2128. fv->paste();
  2129. }
  2130. }
  2131. void open_selected_items(void* user_data)
  2132. {
  2133. if(user_data)
  2134. {
  2135. LLFolderView* fv = reinterpret_cast<LLFolderView*>(user_data);
  2136. fv->openSelectedItems();
  2137. }
  2138. }
  2139. void properties_selected_items(void* user_data)
  2140. {
  2141. if(user_data)
  2142. {
  2143. LLFolderView* fv = reinterpret_cast<LLFolderView*>(user_data);
  2144. fv->propertiesSelectedItems();
  2145. }
  2146. }