diff options
Diffstat (limited to 'indra/newview/llfolderview.cpp')
-rw-r--r-- | indra/newview/llfolderview.cpp | 267 |
1 files changed, 176 insertions, 91 deletions
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index e90b6c1c3d..bad0d8cd8f 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -30,7 +30,7 @@ #include "llcallbacklist.h" #include "llinventorybridge.h" -#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. +#include "llclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryfilter.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" @@ -165,6 +165,33 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) { } ///---------------------------------------------------------------------------- +/// Class LLFolderViewScrollContainer +///---------------------------------------------------------------------------- + +// virtual +const LLRect LLFolderViewScrollContainer::getScrolledViewRect() const +{ + LLRect rect = LLRect::null; + if (mScrolledView) + { + LLFolderView* folder_view = dynamic_cast<LLFolderView*>(mScrolledView); + if (folder_view) + { + S32 height = folder_view->mRunningHeight; + + rect = mScrolledView->getRect(); + rect.setLeftTopAndSize(rect.mLeft, rect.mTop, rect.getWidth(), height); + } + } + + return rect; +} + +LLFolderViewScrollContainer::LLFolderViewScrollContainer(const LLScrollContainer::Params& p) +: LLScrollContainer(p) +{} + +///---------------------------------------------------------------------------- /// Class LLFolderView ///---------------------------------------------------------------------------- LLFolderView::Params::Params() @@ -172,6 +199,7 @@ LLFolderView::Params::Params() title("title"), use_label_suffix("use_label_suffix"), allow_multiselect("allow_multiselect", true), + show_empty_message("show_empty_message", true), show_load_status("show_load_status", true), use_ellipses("use_ellipses", false) { @@ -181,9 +209,11 @@ LLFolderView::Params::Params() // Default constructor LLFolderView::LLFolderView(const Params& p) : LLFolderViewFolder(p), + mRunningHeight(0), mScrollContainer( NULL ), mPopupMenuHandle(), mAllowMultiSelect(p.allow_multiselect), + mShowEmptyMessage(p.show_empty_message), mShowFolderHierarchy(FALSE), mSourceID(p.task_id), mRenameItem( NULL ), @@ -252,7 +282,7 @@ LLFolderView::LLFolderView(const Params& p) LLRect new_r = LLRect(rect.mLeft + ICON_PAD, rect.mTop - TEXT_PAD, rect.mRight, - rect.mTop - TEXT_PAD - llfloor(font->getLineHeight())); + rect.mTop - TEXT_PAD - font->getLineHeight()); text_p.rect(new_r); text_p.name(std::string(p.name)); text_p.font(font); @@ -298,7 +328,7 @@ LLFolderView::~LLFolderView( void ) mAutoOpenItems.removeAllNodes(); gIdleCallbacks.deleteFunction(idle, this); - LLView::deleteViewByHandle(mPopupMenuHandle); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); mAutoOpenItems.removeAllNodes(); clearSelection(); @@ -348,10 +378,6 @@ BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) { mFolders.insert(mFolders.begin(), folder); } - if (folder->numSelected()) - { - recursiveIncrementNumDescendantsSelected(folder->numSelected()); - } folder->setShowLoadStatus(mShowLoadStatus); folder->setOrigin(0, 0); folder->reshape(getRect().getWidth(), 0); @@ -369,16 +395,6 @@ void LLFolderView::closeAllFolders() arrangeAll(); } -void LLFolderView::openFolder(const std::string& foldername) -{ - LLFolderViewFolder* inv = findChild<LLFolderViewFolder>(foldername); - if (inv) - { - setSelection(inv, FALSE, FALSE); - inv->setOpen(TRUE); - } -} - void LLFolderView::openTopLevelFolders() { for (folders_t::iterator iter = mFolders.begin(); @@ -399,9 +415,19 @@ void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); -// This view grows and shinks to enclose all of its children items and folders. +// This view grows and shrinks to enclose all of its children items and folders. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) { + if (getListener()->getUUID().notNull()) + { + if (mNeedsSort) + { + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + mNeedsSort = false; + } + } + LLFastTimer t2(FTM_ARRANGE); filter_generation = mFilter->getMinRequiredGeneration(); @@ -415,7 +441,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen getRoot()->getFilter()->getShowFolderState(); S32 total_width = LEFT_PAD; - S32 running_height = mDebugFilters ? llceil(LLFontGL::getFontMonospace()->getLineHeight()) : 0; + S32 running_height = mDebugFilters ? LLFontGL::getFontMonospace()->getLineHeight() : 0; S32 target_height = running_height; S32 parent_item_height = getRect().getHeight(); @@ -430,8 +456,8 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen } else { - folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? - (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter + folderp->setVisible((show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? + (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation)))); } if (folderp->getVisible()) @@ -479,6 +505,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen target_height = running_height; } + mRunningHeight = running_height; LLRect scroll_rect = mScrollContainer->getContentWindowRect(); reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); @@ -524,16 +551,19 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) LLRect scroll_rect; if (mScrollContainer) { + LLView::reshape(width, height, called_from_parent); scroll_rect = mScrollContainer->getContentWindowRect(); } - width = llmax(mMinWidth, scroll_rect.getWidth()); + width = llmax(mMinWidth, scroll_rect.getWidth()); + height = llmax(mRunningHeight, scroll_rect.getHeight()); - // restrict width with scroll container's width - if (mUseEllipses) + // Restrict width within scroll container's width + if (mUseEllipses && mScrollContainer) + { width = scroll_rect.getWidth(); + } LLView::reshape(width, height, called_from_parent); - mReshapeSignal(mSelectedItems, FALSE); } @@ -690,28 +720,10 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) return rv; } -void LLFolderView::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray<LLFolderViewItem*>& items) -{ - // now store resulting selection - if (mAllowMultiSelect) - { - LLFolderViewItem *cur_selection = getCurSelectedItem(); - LLFolderViewFolder::extendSelection(selection, cur_selection, items); - for (S32 i = 0; i < items.count(); i++) - { - addToSelectionList(items[i]); - } - } - else - { - setSelection(selection, FALSE, FALSE); - } - - mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; -} - +static LLFastTimer::DeclareTimer FTM_SANITIZE_SELECTION("Sanitize Selection"); void LLFolderView::sanitizeSelection() { + LLFastTimer _(FTM_SANITIZE_SELECTION); // store off current item in case it is automatically deselected // and we want to preserve context LLFolderViewItem* original_selected_item = getCurSelectedItem(); @@ -785,7 +797,7 @@ void LLFolderView::sanitizeSelection() // if nothing selected after prior constraints... if (mSelectedItems.empty()) { - // ...select first available parent of original selection, or "My Inventory" otherwise + // ...select first available parent of original selection LLFolderViewItem* new_selection = NULL; if (original_selected_item) { @@ -926,9 +938,9 @@ void LLFolderView::draw() mStatusText.clear(); mStatusTextBox->setVisible( FALSE ); } - else + else if (mShowEmptyMessage) { - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { mStatusText = LLTrans::getString("Searching"); } @@ -959,8 +971,10 @@ void LLFolderView::draw() // We should call this method to also notify parent about required rect. // See EXT-7564, EXT-7047. arrangeFromRoot(); + LLUI::popMatrix(); + LLUI::pushMatrix(); + LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom); } - } // skip over LLFolderViewFolder::draw since we don't want the folder icon, label, @@ -1004,6 +1018,63 @@ void LLFolderView::removeSelectedItems( void ) LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLFolderView::onItemsRemovalConfirmation, this, _1, _2)); } +bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector<LLFolderViewItem*>& selectedItems) +{ + LLFolderViewItem* item_parent = dynamic_cast<LLFolderViewItem*>(item->getParent()); + + if (item_parent) + { + for(std::vector<LLFolderViewItem*>::const_iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + const LLFolderViewItem* const selected_item = (*it); + + LLFolderViewItem* parent = item_parent; + + while (parent) + { + if (selected_item == parent) + { + return true; + } + + parent = dynamic_cast<LLFolderViewItem*>(parent->getParent()); + } + } + } + + return false; +} + +// static +void LLFolderView::removeCutItems() +{ + // There's no item in "cut" mode on the clipboard -> exit + if (!LLClipboard::instance().isCutMode()) + return; + + // Get the list of clipboard item uuids and iterate through them + LLDynamicArray<LLUUID> objects; + LLClipboard::instance().pasteFromClipboard(objects); + for (LLDynamicArray<LLUUID>::const_iterator iter = objects.begin(); + iter != objects.end(); + ++iter) + { + const LLUUID& item_id = (*iter); + LLInventoryObject *obj = gInventory.getObject(item_id); + if (obj) + { + if (LLAssetType::AT_CATEGORY == obj->getType()) + { + remove_category(&gInventory, item_id); + } + else + { + remove_item(&gInventory, item_id); + } + } + } +} + void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -1025,7 +1096,7 @@ void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LL for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) { item = *item_it; - if(item->isRemovable()) + if (item && item->isRemovable()) { items.push_back(item); } @@ -1078,7 +1149,7 @@ void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LL if (!new_selection) { new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && new_selection->isSelected()) + while (new_selection && (new_selection->isSelected() || isDescendantOfASelectedItem(new_selection, items))) { new_selection = new_selection->getPreviousOpenNode(FALSE); } @@ -1189,7 +1260,9 @@ void LLFolderView::changeType(LLInventoryModel *model, LLFolderType::EType new_f void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { - if (mAutoOpenItems.check() == item || mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) + if ((mAutoOpenItems.check() == item) || + (mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) || + item->isOpen()) { return; } @@ -1281,7 +1354,7 @@ BOOL LLFolderView::canCopy() const void LLFolderView::copy() { // *NOTE: total hack to clear the inventory clipboard - LLInventoryClipboard::instance().reset(); + LLClipboard::instance().reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { @@ -1322,7 +1395,7 @@ BOOL LLFolderView::canCut() const void LLFolderView::cut() { // clear the inventory clipboard - LLInventoryClipboard::instance().reset(); + LLClipboard::instance().reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { @@ -1336,6 +1409,7 @@ void LLFolderView::cut() listener->cutToClipboard(); } } + LLFolderView::removeCutItems(); } mSearchString.clear(); } @@ -1690,7 +1764,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) } BOOL handled = FALSE; - if (gFocusMgr.childHasKeyboardFocus(getRoot())) + if (mParentPanel->hasFocus()) { // SL-51858: Key presses are not being passed to the Popup menu. // A proper fix is non-trivial so instead just close the menu. @@ -1903,20 +1977,25 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, std::string& tooltip_msg) { mDragAndDropThisFrame = TRUE; + // have children handle it first BOOL handled = LLView::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - // When there are no visible children drag and drop is handled + // when drop is not handled by child, it should be handled // by the folder which is the hierarchy root. - if (!handled && !hasVisibleChildren()) + if (!handled) { - if (mFolders.empty()) + if (getListener()->getUUID().notNull()) { - handled = handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } else { - handled = mFolders.front()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + if (!mFolders.empty()) + { + // dispatch to last folder as a hack to support "Contents" folder in object inventory + handled = mFolders.back()->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + } } } @@ -1931,7 +2010,7 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLFolderView::deleteAllChildren() { closeRenamer(); - LLView::deleteViewByHandle(mPopupMenuHandle); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); mPopupMenuHandle = LLHandle<LLView>(); mScrollContainer = NULL; mRenameItem = NULL; @@ -1944,19 +2023,13 @@ void LLFolderView::deleteAllChildren() void LLFolderView::scrollToShowSelection() { - // If items are filtered while background fetch is in progress - // scrollbar resets to the first filtered item. See EXT-3981. - // However we allow scrolling for folder views with mAutoSelectOverride - // (used in Places SP) as an exception because the selection in them - // is not reset during items filtering. See STORM-133. - if ( (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mAutoSelectOverride) - && mSelectedItems.size() ) + if ( mSelectedItems.size() ) { mNeedsScroll = TRUE; } } -// If the parent is scroll containter, scroll it to make the selection +// If the parent is scroll container, scroll it to make the selection // is maximally visible. void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) { @@ -1977,7 +2050,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = llround(getLabelFontForStyle(mLabelStyle)->getLineHeight()); + S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); @@ -2038,8 +2111,10 @@ void LLFolderView::removeItemID(const LLUUID& id) mItemMap.erase(id); } +LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) { + LLFastTimer _(FTM_GET_ITEM_BY_ID); if (id == getListener()->getUUID()) { return this; @@ -2089,10 +2164,10 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) removeSelectedItems(); return true; } - - if ("copy" == action) - { - LLInventoryClipboard::instance().reset(); + if (("copy" == action) || ("cut" == action)) + { + // Clear the clipboard before we start adding things on it + LLClipboard::instance().reset(); } static const std::string change_folder_string = "change_folder_type_"; @@ -2173,46 +2248,56 @@ void LLFolderView::doIdle() arrangeAll(); } + if (mFilter->isModified() && mFilter->isNotDefault()) + { + mNeedsAutoSelect = TRUE; + } mFilter->clearModified(); - BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter->getCurrentGeneration() && - mFilter->isNotDefault(); - mNeedsAutoSelect = filter_modified_and_active && - !(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture()); - // filter to determine visiblity before arranging + // filter to determine visibility before arranging filterFromRoot(); // automatically show matching items, and select first one if we had a selection - // do this every frame until user puts keyboard focus into the inventory window - // signaling the end of the automatic update - // only do this when mNeedsFilter is set, meaning filtered items have - // potentially changed if (mNeedsAutoSelect) { LLFastTimer t3(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); - if ((selected_itemp && !selected_itemp->getFiltered()) && !mAutoSelectOverride) + if (!mAutoSelectOverride && (!selected_itemp || !selected_itemp->potentiallyFiltered())) { - // select first filtered item - LLSelectFirstFilteredItem filter; - applyFunctorRecursively(filter); + // these are named variables to get around gcc not binding non-const references to rvalues + // and functor application is inherently non-const to allow for stateful functors + LLSelectFirstFilteredItem functor; + applyFunctorRecursively(functor); } // Open filtered folders for folder views with mAutoSelectOverride=TRUE. // Used by LLPlacesFolderView. if (mAutoSelectOverride && !mFilter->getFilterSubString().empty()) { - LLOpenFilteredFolders filter; - applyFunctorRecursively(filter); + // these are named variables to get around gcc not binding non-const references to rvalues + // and functor application is inherently non-const to allow for stateful functors + LLOpenFilteredFolders functor; + applyFunctorRecursively(functor); } scrollToShowSelection(); } + BOOL filter_finished = mCompletedFilterGeneration >= mFilter->getCurrentGeneration() + && !LLInventoryModelBackgroundFetch::instance().folderFetchActive(); + if (filter_finished + || gFocusMgr.childHasKeyboardFocus(inventory_panel) + || gFocusMgr.childHasMouseCapture(inventory_panel)) + { + // finishing the filter process, giving focus to the folder view, or dragging the scrollbar all stop the auto select process + mNeedsAutoSelect = FALSE; + } + + // during filtering process, try to pin selected item's location on screen // this will happen when searching your inventory and when new items arrive - if (filter_modified_and_active) + if (!filter_finished) { // calculate rectangle to pin item to at start of animated rearrange if (!mPinningSelectedItem && !mSelectedItems.empty()) @@ -2278,7 +2363,7 @@ void LLFolderView::doIdle() { scrollToShowItem(mSelectedItems.back(), constraint_rect); // continue scrolling until animated layout change is done - if (!filter_modified_and_active + if (filter_finished && (!needsArrange() || !is_visible)) { mNeedsScroll = FALSE; |