From 1494a1058f41c5aa00a8ed08fe71123f63e92e81 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 3 Jul 2012 23:55:39 -0700 Subject: CHUI-101 WIP Make LLFolderview general purpose move llfolderview* into LLUI! --- indra/llui/llfolderview.cpp | 2078 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2078 insertions(+) create mode 100644 indra/llui/llfolderview.cpp (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp new file mode 100644 index 0000000000..0d3bc44ae4 --- /dev/null +++ b/indra/llui/llfolderview.cpp @@ -0,0 +1,2078 @@ +/** + * @file llfolderview.cpp + * @brief Implementation of the folder view collection of classes. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfolderview.h" +#include "llfolderviewmodel.h" +#include "llclipboard.h" // *TODO: remove this once hack below gone. +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llpanel.h" +#include "llscrollcontainer.h" // hack to allow scrolling +#include "lltextbox.h" +#include "lltrans.h" +#include "llui.h" +#include "lluictrlfactory.h" + +// Linden library includes +#include "lldbstrings.h" +#include "llfocusmgr.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llrender.h" + +// Third-party library includes +#include + +///---------------------------------------------------------------------------- +/// Local function declarations, constants, enums, and typedefs +///---------------------------------------------------------------------------- + +const S32 RENAME_WIDTH_PAD = 4; +const S32 RENAME_HEIGHT_PAD = 1; +const S32 AUTO_OPEN_STACK_DEPTH = 16; +const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH + + LLFolderViewItem::ICON_PAD + + LLFolderViewItem::ARROW_SIZE + + LLFolderViewItem::TEXT_PAD + + /*first few characters*/ 40; +const S32 MINIMUM_RENAMER_WIDTH = 80; + +// *TODO: move in params in xml if necessary. Requires modification of LLFolderView & LLInventoryPanel Params. +const S32 STATUS_TEXT_HPAD = 6; +const S32 STATUS_TEXT_VPAD = 8; + +enum { + SIGNAL_NO_KEYBOARD_FOCUS = 1, + SIGNAL_KEYBOARD_FOCUS = 2 +}; + +F32 LLFolderView::sAutoOpenTime = 1.f; + +//--------------------------------------------------------------------------- + +// Tells all folders in a folderview to close themselves +// For efficiency, calls setOpenArrangeRecursively(). +// The calling function must then call: +// LLFolderView* root = getRoot(); +// if( root ) +// { +// root->arrange( NULL, NULL ); +// root->scrollToShowSelection(); +// } +// to patch things up. +class LLCloseAllFoldersFunctor : public LLFolderViewFunctor +{ +public: + LLCloseAllFoldersFunctor(BOOL close) { mOpen = !close; } + virtual ~LLCloseAllFoldersFunctor() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + + BOOL mOpen; +}; + + +void LLCloseAllFoldersFunctor::doFolder(LLFolderViewFolder* folder) +{ + folder->setOpenArrangeRecursively(mOpen); +} + +// Do nothing. +void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) +{ } + +///---------------------------------------------------------------------------- +/// Class LLFolderViewScrollContainer +///---------------------------------------------------------------------------- + +// virtual +const LLRect LLFolderViewScrollContainer::getScrolledViewRect() const +{ + LLRect rect = LLRect::null; + if (mScrolledView) + { + LLFolderView* folder_view = dynamic_cast(mScrolledView); + if (folder_view) + { + S32 height = folder_view->getRect().getHeight(); + + 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() +: title("title"), + use_label_suffix("use_label_suffix"), + allow_multiselect("allow_multiselect", true), + show_empty_message("show_empty_message", true), + use_ellipses("use_ellipses", false) +{ + folder_indentation = -4; +} + + +// Default constructor +LLFolderView::LLFolderView(const Params& p) +: LLFolderViewFolder(p), + mScrollContainer( NULL ), + mPopupMenuHandle(), + mAllowMultiSelect(p.allow_multiselect), + mShowEmptyMessage(p.show_empty_message), + mShowFolderHierarchy(FALSE), + mRenameItem( NULL ), + mNeedsScroll( FALSE ), + mUseLabelSuffix(p.use_label_suffix), + mPinningSelectedItem(FALSE), + mNeedsAutoSelect( FALSE ), + mAutoSelectOverride(FALSE), + mNeedsAutoRename(FALSE), + mShowSelectionContext(FALSE), + mShowSingleSelection(FALSE), + mArrangeGeneration(0), + mSignalSelectCallback(0), + mMinWidth(0), + mDragAndDropThisFrame(FALSE), + mCallbackRegistrar(NULL), + mParentPanel(p.parent_panel), + mUseEllipses(p.use_ellipses), + mDraggingOverItem(NULL), + mStatusTextBox(NULL), + mShowItemLinkOverlays(p.show_item_link_overlays), + mViewModel(p.view_model) +{ + mViewModel->setFolderView(this); + mRoot = this; + + LLRect rect = p.rect; + LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); + setRect( rect ); + reshape(rect.getWidth(), rect.getHeight()); + mAutoOpenItems.setDepth(AUTO_OPEN_STACK_DEPTH); + mAutoOpenCandidate = NULL; + mAutoOpenTimer.stop(); + mKeyboardSelection = FALSE; + mIndentation = p.folder_indentation; + + //clear label + // go ahead and render root folder as usual + // just make sure the label ("Inventory Folder") never shows up + mLabel = LLStringUtil::null; + + // Escape is handled by reverting the rename, not commiting it (default behavior) + LLLineEditor::Params params; + params.name("ren"); + params.rect(rect); + params.font(getLabelFontForStyle(LLFontGL::NORMAL)); + params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN); + params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); + params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe); + params.commit_on_focus_lost(true); + params.visible(false); + mRenamer = LLUICtrlFactory::create (params); + addChild(mRenamer); + + // Textbox + LLTextBox::Params text_p; + LLFontGL* font = getLabelFontForStyle(mLabelStyle); + LLRect new_r = LLRect(rect.mLeft + ICON_PAD, + rect.mTop - TEXT_PAD, + rect.mRight, + rect.mTop - TEXT_PAD - font->getLineHeight()); + text_p.rect(new_r); + text_p.name(std::string(p.name)); + text_p.font(font); + text_p.visible(false); + text_p.parse_urls(true); + text_p.wrap(true); // allow multiline text. See EXT-7564, EXT-7047 + // set text padding the same as in People panel. EXT-7047, EXT-4837 + text_p.h_pad(STATUS_TEXT_HPAD); + text_p.v_pad(STATUS_TEXT_VPAD); + mStatusTextBox = LLUICtrlFactory::create (text_p); + mStatusTextBox->setFollowsLeft(); + mStatusTextBox->setFollowsTop(); + //addChild(mStatusTextBox); + + + // make the popup menu available + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + if (!menu) + { + menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); + } + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); + mPopupMenuHandle = menu->getHandle(); + + mViewModelItem->openItem(); +} + +// Destroys the object +LLFolderView::~LLFolderView( void ) +{ + closeRenamer(); + + // The release focus call can potentially call the + // scrollcontainer, which can potentially be called with a partly + // destroyed scollcontainer. Just null it out here, and no worries + // about calling into the invalid scroll container. + // Same with the renamer. + mScrollContainer = NULL; + mRenameItem = NULL; + mRenamer = NULL; + mStatusTextBox = NULL; + + mAutoOpenItems.removeAllNodes(); + + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + + mAutoOpenItems.removeAllNodes(); + clearSelection(); + mItems.clear(); + mFolders.clear(); + + delete mViewModel; + mViewModel = NULL; +} + +BOOL LLFolderView::canFocusChildren() const +{ + return FALSE; +} + +BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) +{ + LLFolderViewFolder::addFolder(folder); + + // TODO RN: enforce sort order of My Inventory followed by Library + //mFolders.remove(folder); + //if (((LLFolderViewModelItemInventory*)folder->getViewModelItem())->getUUID() == gInventory.getLibraryRootFolderID()) + //{ + // mFolders.push_back(folder); + //} + //else + //{ + // mFolders.insert(mFolders.begin(), folder); + //} + + return TRUE; +} + +void LLFolderView::closeAllFolders() +{ + // Close all the folders + setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + arrangeAll(); +} + +void LLFolderView::openTopLevelFolders() +{ + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setOpen(TRUE); + } +} + +// This view grows and shrinks to enclose all of its children items and folders. +// *width should be 0 +// conform show folder state works +S32 LLFolderView::arrange( S32* unused_width, S32* unused_height ) +{ + mMinWidth = 0; + S32 target_height; + + LLFolderViewFolder::arrange(&mMinWidth, &target_height); + + LLRect scroll_rect = mScrollContainer->getContentWindowRect(); + reshape( llmax(scroll_rect.getWidth(), mMinWidth), llround(mCurHeight) ); + + LLRect new_scroll_rect = mScrollContainer->getContentWindowRect(); + if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) + { + reshape( llmax(scroll_rect.getWidth(), mMinWidth), llround(mCurHeight) ); + } + + // move item renamer text field to item's new position + updateRenamerPosition(); + + return llround(mTargetHeight); +} + +static LLFastTimer::DeclareTimer FTM_FILTER("Filter Folder View"); + +void LLFolderView::filter( LLFolderViewFilter& filter ) +{ + LLFastTimer t2(FTM_FILTER); + filter.setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000)); + + getViewModelItem()->filter(filter); +} + +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()); + height = llmax(llround(mCurHeight), scroll_rect.getHeight()); + + // Restrict width within scroll container's width + if (mUseEllipses && mScrollContainer) + { + width = scroll_rect.getWidth(); + } + + LLView::reshape(width, height, called_from_parent); + mReshapeSignal(mSelectedItems, FALSE); +} + +void LLFolderView::addToSelectionList(LLFolderViewItem* item) +{ + if (item->isSelected()) + { + removeFromSelectionList(item); + } + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(FALSE); + } + item->setIsCurSelection(TRUE); + mSelectedItems.push_back(item); +} + +void LLFolderView::removeFromSelectionList(LLFolderViewItem* item) +{ + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(FALSE); + } + + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end();) + { + if (*item_iter == item) + { + item_iter = mSelectedItems.erase(item_iter); + } + else + { + ++item_iter; + } + } + if (mSelectedItems.size()) + { + mSelectedItems.back()->setIsCurSelection(TRUE); + } +} + +LLFolderViewItem* LLFolderView::getCurSelectedItem( void ) +{ + if(mSelectedItems.size()) + { + LLFolderViewItem* itemp = mSelectedItems.back(); + llassert(itemp->getIsCurSelection()); + return itemp; + } + return NULL; +} + + +// Record the selected item and pass it down the hierachy. +BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus) +{ + mSignalSelectCallback = take_keyboard_focus ? SIGNAL_KEYBOARD_FOCUS : SIGNAL_NO_KEYBOARD_FOCUS; + + if( selection == this ) + { + return FALSE; + } + + if( selection && take_keyboard_focus) + { + mParentPanel->setFocus(TRUE); + } + + // clear selection down here because change of keyboard focus can potentially + // affect selection + clearSelection(); + + if(selection) + { + addToSelectionList(selection); + } + + BOOL rv = LLFolderViewFolder::setSelection(selection, openitem, take_keyboard_focus); + if(openitem && selection) + { + selection->getParentFolder()->requestArrange(); + } + + llassert(mSelectedItems.size() <= 1); + + return rv; +} + +BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) +{ + BOOL rv = FALSE; + + // can't select root folder + if(!selection || selection == this) + { + return FALSE; + } + + if (!mAllowMultiSelect) + { + clearSelection(); + } + + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + if (*item_iter == selection) + { + break; + } + } + + BOOL on_list = (item_iter != mSelectedItems.end()); + + if(selected && !on_list) + { + addToSelectionList(selection); + } + if(!selected && on_list) + { + removeFromSelectionList(selection); + } + + rv = LLFolderViewFolder::changeSelection(selection, selected); + + mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS; + + return rv; +} + +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(); + + std::vector items_to_remove; + selected_items_t::iterator item_iter; + for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) + { + LLFolderViewItem* item = *item_iter; + + // ensure that each ancestor is open and potentially passes filtering + BOOL visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item + // modify with parent open and filters states + LLFolderViewFolder* parent_folder = item->getParentFolder(); + // Move up through parent folders and see what's visible + while(parent_folder) + { + visible = visible && parent_folder->isOpen() && parent_folder->getViewModelItem()->potentiallyVisible(); + parent_folder = parent_folder->getParentFolder(); + } + + // deselect item if any ancestor is closed or didn't pass filter requirements. + if (!visible) + { + items_to_remove.push_back(item); + } + + // disallow nested selections (i.e. folder items plus one or more ancestors) + // could check cached mum selections count and only iterate if there are any + // but that may be a premature optimization. + selected_items_t::iterator other_item_iter; + for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter) + { + LLFolderViewItem* other_item = *other_item_iter; + for( parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder()) + { + if (parent_folder == item) + { + // this is a descendent of the current folder, remove from list + items_to_remove.push_back(other_item); + break; + } + } + } + + // Don't allow invisible items (such as root folders) to be selected. + if (item == getRoot()) + { + items_to_remove.push_back(item); + } + } + + std::vector::iterator item_it; + for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it ) + { + changeSelection(*item_it, FALSE); // toggle selection (also removes from list) + } + + // if nothing selected after prior constraints... + if (mSelectedItems.empty()) + { + // ...select first available parent of original selection + LLFolderViewItem* new_selection = NULL; + if (original_selected_item) + { + for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder(); + parent_folder; + parent_folder = parent_folder->getParentFolder()) + { + if (parent_folder->getViewModelItem()->potentiallyVisible()) + { + // give initial selection to first ancestor folder that potentially passes the filter + if (!new_selection) + { + new_selection = parent_folder; + } + + // if any ancestor folder of original item is closed, move the selection up + // to the highest closed + if (!parent_folder->isOpen()) + { + new_selection = parent_folder; + } + } + } + } + else + { + new_selection = NULL; + } + + if (new_selection) + { + setSelection(new_selection, FALSE, FALSE); + } + } +} + +void LLFolderView::clearSelection() +{ + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); + item_it != mSelectedItems.end(); + ++item_it) + { + (*item_it)->setUnselected(); + } + + mSelectedItems.clear(); +} + +std::set LLFolderView::getSelectionList() const +{ + std::set selection; + std::copy(mSelectedItems.begin(), mSelectedItems.end(), std::inserter(selection, selection.begin())); + return selection; +} + +bool LLFolderView::startDrag() +{ + std::vector selected_items; + selected_items_t::iterator item_it; + + if (!mSelectedItems.empty()) + { + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + selected_items.push_back((*item_it)->getViewModelItem()); + } + + return getFolderViewModel()->startDrag(selected_items); + } + return false; +} + +void LLFolderView::commitRename( const LLSD& data ) +{ + finishRenamingItem(); +} + +void LLFolderView::draw() +{ + //LLFontGL* font = getLabelFontForStyle(mLabelStyle); + + // if cursor has moved off of me during drag and drop + // close all auto opened folders + if (!mDragAndDropThisFrame) + { + closeAutoOpenedFolders(); + } + + if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout") || !mSearchString.size()) + { + mSearchString.clear(); + } + + if (hasVisibleChildren()) + { + mStatusTextBox->setVisible( FALSE ); + } + else if (mShowEmptyMessage) + { + mStatusTextBox->setValue(getFolderViewModel()->getStatusText()); + mStatusTextBox->setVisible( TRUE ); + + // firstly reshape message textbox with current size. This is necessary to + // LLTextBox::getTextPixelHeight works properly + const LLRect local_rect = getLocalRect(); + mStatusTextBox->setShape(local_rect); + + // get preferable text height... + S32 pixel_height = mStatusTextBox->getTextPixelHeight(); + bool height_changed = local_rect.getHeight() != pixel_height; + if (height_changed) + { + // ... if it does not match current height, lets rearrange current view. + // This will indirectly call ::arrange and reshape of the status textbox. + // We should call this method to also notify parent about required rect. + // See EXT-7564, EXT-7047. + S32 height = 0; + S32 width = 0; + S32 total_height = arrange( &width, &height ); + notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); + + 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, + // and arrow for the root folder + LLView::draw(); + + mDragAndDropThisFrame = FALSE; +} + +void LLFolderView::finishRenamingItem( void ) +{ + if(!mRenamer) + { + return; + } + if( mRenameItem ) + { + mRenameItem->rename( mRenamer->getText() ); + } + + closeRenamer(); + + // List is re-sorted alphabetically, so scroll to make sure the selected item is visible. + scrollToShowSelection(); +} + +void LLFolderView::closeRenamer( void ) +{ + if (mRenamer && mRenamer->getVisible()) + { + // Triggers onRenamerLost() that actually closes the renamer. + LLUI::removePopup(mRenamer); + } +} + +bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector& selectedItems) +{ + LLFolderViewItem* item_parent = dynamic_cast(item->getParent()); + + if (item_parent) + { + for(std::vector::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(parent->getParent()); + } + } + } + + return false; +} + +void LLFolderView::removeSelectedItems() +{ + if(getVisible() && getEnabled()) + { + // just in case we're removing the renaming item. + mRenameItem = NULL; + + // create a temporary structure which we will use to remove + // items, since the removal will futz with internal data + // structures. + std::vector items; + S32 count = mSelectedItems.size(); + if(count == 0) return; + LLFolderViewItem* item = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + item = *item_it; + if (item && item->isRemovable()) + { + items.push_back(item); + } + else + { + llinfos << "Cannot delete " << item->getName() << llendl; + return; + } + } + + // iterate through the new container. + count = items.size(); + LLUUID new_selection_id; + if(count == 1) + { + LLFolderViewItem* item_to_delete = items[0]; + LLFolderViewFolder* parent = item_to_delete->getParentFolder(); + LLFolderViewItem* new_selection = item_to_delete->getNextOpenNode(FALSE); + if (!new_selection) + { + new_selection = item_to_delete->getPreviousOpenNode(FALSE); + } + if(parent) + { + if (item_to_delete->remove()) + { + // change selection on successful delete + if (new_selection) + { + getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); + } + else + { + getRoot()->setSelection(NULL, mParentPanel->hasFocus()); + } + } + } + arrangeAll(); + } + else if (count > 1) + { + LLDynamicArray listeners; + LLFolderViewModelItem* listener; + LLFolderViewItem* last_item = items[count - 1]; + LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); + while(new_selection && new_selection->isSelected()) + { + new_selection = new_selection->getNextOpenNode(FALSE); + } + if (!new_selection) + { + new_selection = last_item->getPreviousOpenNode(FALSE); + while (new_selection && (new_selection->isSelected() || isDescendantOfASelectedItem(new_selection, items))) + { + new_selection = new_selection->getPreviousOpenNode(FALSE); + } + } + if (new_selection) + { + getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); + } + else + { + getRoot()->setSelection(NULL, mParentPanel->hasFocus()); + } + + for(S32 i = 0; i < count; ++i) + { + listener = items[i]->getViewModelItem(); + if(listener && (listeners.find(listener) == LLDynamicArray::FAIL)) + { + listeners.put(listener); + } + } + listener = static_cast(listeners.get(0)); + if(listener) + { + listener->removeBatch(listeners); + } + } + arrangeAll(); + scrollToShowSelection(); + } +} + +// TODO RN: abstract +// open the selected item. +void LLFolderView::openSelectedItems( void ) +{ + //TODO RN: get working again + //if(getVisible() && getEnabled()) + //{ + // if (mSelectedItems.size() == 1) + // { + // mSelectedItems.front()->openItem(); + // } + // else + // { + // LLMultiPreview* multi_previewp = new LLMultiPreview(); + // LLMultiProperties* multi_propertiesp = new LLMultiProperties(); + + // selected_items_t::iterator item_it; + // for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + // { + // // IT_{OBJECT,ATTACHMENT} creates LLProperties + // // floaters; others create LLPreviews. Put + // // each one in the right type of container. + // LLFolderViewModelItemInventory* listener = static_cast((*item_it)->getViewModelItem()); + // bool is_prop = listener && (listener->getInventoryType() == LLInventoryType::IT_OBJECT || listener->getInventoryType() == LLInventoryType::IT_ATTACHMENT); + // if (is_prop) + // LLFloater::setFloaterHost(multi_propertiesp); + // else + // LLFloater::setFloaterHost(multi_previewp); + // listener->openItem(); + // } + + // LLFloater::setFloaterHost(NULL); + // // *NOTE: LLMulti* will safely auto-delete when open'd + // // without any children. + // multi_previewp->openFloater(LLSD()); + // multi_propertiesp->openFloater(LLSD()); + // } + //} +} + +void LLFolderView::propertiesSelectedItems( void ) +{ + //TODO RN: get working again + //if(getVisible() && getEnabled()) + //{ + // if (mSelectedItems.size() == 1) + // { + // LLFolderViewItem* folder_item = mSelectedItems.front(); + // if(!folder_item) return; + // folder_item->getViewModelItem()->showProperties(); + // } + // else + // { + // LLMultiProperties* multi_propertiesp = new LLMultiProperties(); + + // LLFloater::setFloaterHost(multi_propertiesp); + + // selected_items_t::iterator item_it; + // for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + // { + // (*item_it)->getViewModelItem()->showProperties(); + // } + + // LLFloater::setFloaterHost(NULL); + // multi_propertiesp->openFloater(LLSD()); + // } + //} +} + + +void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) +{ + if ((mAutoOpenItems.check() == item) || + (mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) || + item->isOpen()) + { + return; + } + + // close auto-opened folders + LLFolderViewFolder* close_item = mAutoOpenItems.check(); + while (close_item && close_item != item->getParentFolder()) + { + mAutoOpenItems.pop(); + close_item->setOpenArrangeRecursively(FALSE); + close_item = mAutoOpenItems.check(); + } + + item->requestArrange(); + + mAutoOpenItems.push(item); + + item->setOpen(TRUE); + LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); + scrollToShowItem(item, constraint_rect); +} + +void LLFolderView::closeAutoOpenedFolders() +{ + while (mAutoOpenItems.check()) + { + LLFolderViewFolder* close_item = mAutoOpenItems.pop(); + close_item->setOpen(FALSE); + } + + if (mAutoOpenCandidate) + { + mAutoOpenCandidate->setAutoOpenCountdown(0.f); + } + mAutoOpenCandidate = NULL; + mAutoOpenTimer.stop(); +} + +BOOL LLFolderView::autoOpenTest(LLFolderViewFolder* folder) +{ + if (folder && mAutoOpenCandidate == folder) + { + if (mAutoOpenTimer.getStarted()) + { + if (!mAutoOpenCandidate->isOpen()) + { + mAutoOpenCandidate->setAutoOpenCountdown(clamp_rescale(mAutoOpenTimer.getElapsedTimeF32(), 0.f, sAutoOpenTime, 0.f, 1.f)); + } + if (mAutoOpenTimer.getElapsedTimeF32() > sAutoOpenTime) + { + autoOpenItem(folder); + mAutoOpenTimer.stop(); + return TRUE; + } + } + return FALSE; + } + + // otherwise new candidate, restart timer + if (mAutoOpenCandidate) + { + mAutoOpenCandidate->setAutoOpenCountdown(0.f); + } + mAutoOpenCandidate = folder; + mAutoOpenTimer.start(); + return FALSE; +} + +BOOL LLFolderView::canCopy() const +{ + if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) + { + return FALSE; + } + + for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + const LLFolderViewItem* item = *selected_it; + if (!item->getViewModelItem()->isItemCopyable()) + { + return FALSE; + } + } + return TRUE; +} + +// copy selected item +void LLFolderView::copy() +{ + // *NOTE: total hack to clear the inventory clipboard + LLClipboard::instance().reset(); + S32 count = mSelectedItems.size(); + if(getVisible() && getEnabled() && (count > 0)) + { + LLFolderViewModelItem* listener = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + listener = (*item_it)->getViewModelItem(); + if(listener) + { + listener->copyToClipboard(); + } + } + } + mSearchString.clear(); +} + +BOOL LLFolderView::canCut() const +{ + if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0))) + { + return FALSE; + } + + for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + const LLFolderViewItem* item = *selected_it; + const LLFolderViewModelItem* listener = item->getViewModelItem(); + + if (!listener || !listener->isItemRemovable()) + { + return FALSE; + } + } + return TRUE; +} + +void LLFolderView::cut() +{ + // clear the inventory clipboard + LLClipboard::instance().reset(); + S32 count = mSelectedItems.size(); + if(getVisible() && getEnabled() && (count > 0)) + { + LLFolderViewModelItem* listener = NULL; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + listener = (*item_it)->getViewModelItem(); + if(listener) + { + listener->cutToClipboard(); + listener->removeItem(); + } + } + } + mSearchString.clear(); +} + +BOOL LLFolderView::canPaste() const +{ + if (mSelectedItems.empty()) + { + return FALSE; + } + + if(getVisible() && getEnabled()) + { + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); + item_it != mSelectedItems.end(); ++item_it) + { + // *TODO: only check folders and parent folders of items + const LLFolderViewItem* item = (*item_it); + const LLFolderViewModelItem* listener = item->getViewModelItem(); + if(!listener || !listener->isClipboardPasteable()) + { + const LLFolderViewFolder* folderp = item->getParentFolder(); + listener = folderp->getViewModelItem(); + if (!listener || !listener->isClipboardPasteable()) + { + return FALSE; + } + } + } + return TRUE; + } + return FALSE; +} + +// paste selected item +void LLFolderView::paste() +{ + if(getVisible() && getEnabled()) + { + // find set of unique folders to paste into + std::set folder_set; + + selected_items_t::iterator selected_it; + for (selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it) + { + LLFolderViewItem* item = *selected_it; + LLFolderViewFolder* folder = dynamic_cast(item); + if (folder == NULL) + { + item = item->getParentFolder(); + } + folder_set.insert(folder); + } + + std::set::iterator set_iter; + for(set_iter = folder_set.begin(); set_iter != folder_set.end(); ++set_iter) + { + LLFolderViewModelItem* listener = (*set_iter)->getViewModelItem(); + if(listener && listener->isClipboardPasteable()) + { + listener->pasteFromClipboard(); + } + } + } + mSearchString.clear(); +} + +// public rename functionality - can only start the process +void LLFolderView::startRenamingSelectedItem( void ) +{ + // make sure selection is visible + scrollToShowSelection(); + + S32 count = mSelectedItems.size(); + LLFolderViewItem* item = NULL; + if(count > 0) + { + item = mSelectedItems.front(); + } + if(getVisible() && getEnabled() && (count == 1) && item && item->getViewModelItem() && + item->getViewModelItem()->isItemRenameable()) + { + mRenameItem = item; + + updateRenamerPosition(); + + + mRenamer->setText(item->getName()); + mRenamer->selectAll(); + mRenamer->setVisible( TRUE ); + // set focus will fail unless item is visible + mRenamer->setFocus( TRUE ); + mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this)); + LLUI::addPopup(mRenamer); + } +} + +BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) +{ + BOOL handled = FALSE; + + // SL-51858: Key presses are not being passed to the Popup menu. + // A proper fix is non-trivial so instead just close the menu. + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + + LLView *item = NULL; + if (getChildCount() > 0) + { + item = *(getChildList()->begin()); + } + + switch( key ) + { + case KEY_F2: + mSearchString.clear(); + startRenamingSelectedItem(); + handled = TRUE; + break; + + case KEY_RETURN: + if (mask == MASK_NONE) + { + if( mRenameItem && mRenamer->getVisible() ) + { + finishRenamingItem(); + mSearchString.clear(); + handled = TRUE; + } + else + { + LLFolderView::openSelectedItems(); + handled = TRUE; + } + } + break; + + case KEY_ESCAPE: + if( mRenameItem && mRenamer->getVisible() ) + { + closeRenamer(); + handled = TRUE; + } + mSearchString.clear(); + break; + + case KEY_PAGE_UP: + mSearchString.clear(); + mScrollContainer->pageUp(30); + handled = TRUE; + break; + + case KEY_PAGE_DOWN: + mSearchString.clear(); + mScrollContainer->pageDown(30); + handled = TRUE; + break; + + case KEY_HOME: + mSearchString.clear(); + mScrollContainer->goToTop(); + handled = TRUE; + break; + + case KEY_END: + mSearchString.clear(); + mScrollContainer->goToBottom(); + break; + + case KEY_DOWN: + if((mSelectedItems.size() > 0) && mScrollContainer) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); + + if (!mKeyboardSelection) + { + setSelection(last_selected, FALSE, TRUE); + mKeyboardSelection = TRUE; + } + + LLFolderViewItem* next = NULL; + if (mask & MASK_SHIFT) + { + // don't shift select down to children of folders (they are implicitly selected through parent) + next = last_selected->getNextOpenNode(FALSE); + if (next) + { + if (next->isSelected()) + { + // shrink selection + getRoot()->changeSelection(last_selected, FALSE); + } + else if (last_selected->getParentFolder() == next->getParentFolder()) + { + // grow selection + getRoot()->changeSelection(next, TRUE); + } + } + } + else + { + next = last_selected->getNextOpenNode(); + if( next ) + { + if (next == last_selected) + { + //special case for LLAccordionCtrl + if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + return FALSE; + } + setSelection( next, FALSE, TRUE ); + } + else + { + //special case for LLAccordionCtrl + if(notifyParent(LLSD().with("action","select_next")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + return FALSE; + } + } + scrollToShowSelection(); + mSearchString.clear(); + handled = TRUE; + } + break; + + case KEY_UP: + if((mSelectedItems.size() > 0) && mScrollContainer) + { + LLFolderViewItem* last_selected = mSelectedItems.back(); + + if (!mKeyboardSelection) + { + setSelection(last_selected, FALSE, TRUE); + mKeyboardSelection = TRUE; + } + + LLFolderViewItem* prev = NULL; + if (mask & MASK_SHIFT) + { + // don't shift select down to children of folders (they are implicitly selected through parent) + prev = last_selected->getPreviousOpenNode(FALSE); + if (prev) + { + if (prev->isSelected()) + { + // shrink selection + getRoot()->changeSelection(last_selected, FALSE); + } + else if (last_selected->getParentFolder() == prev->getParentFolder()) + { + // grow selection + getRoot()->changeSelection(prev, TRUE); + } + } + } + else + { + prev = last_selected->getPreviousOpenNode(); + if( prev ) + { + if (prev == this) + { + // If case we are in accordion tab notify parent to go to the previous accordion + if(notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + { + clearSelection(); + return TRUE; + } + + return FALSE; + } + setSelection( prev, FALSE, TRUE ); + } + } + scrollToShowSelection(); + mSearchString.clear(); + + handled = TRUE; + } + break; + + case KEY_RIGHT: + if(mSelectedItems.size()) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); + last_selected->setOpen( TRUE ); + mSearchString.clear(); + handled = TRUE; + } + break; + + case KEY_LEFT: + if(mSelectedItems.size()) + { + LLFolderViewItem* last_selected = getCurSelectedItem(); + LLFolderViewItem* parent_folder = last_selected->getParentFolder(); + if (!last_selected->isOpen() && parent_folder && parent_folder->getParentFolder()) + { + setSelection(parent_folder, FALSE, TRUE); + } + else + { + last_selected->setOpen( FALSE ); + } + mSearchString.clear(); + scrollToShowSelection(); + handled = TRUE; + } + break; + } + + if (!handled && mParentPanel->hasFocus()) + { + if (key == KEY_BACKSPACE) + { + mSearchTimer.reset(); + if (mSearchString.size()) + { + mSearchString.erase(mSearchString.size() - 1, 1); + } + search(getCurSelectedItem(), mSearchString, FALSE); + handled = TRUE; + } + } + + return handled; +} + + +BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) +{ + if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL + { + return FALSE; + } + + if (uni_char > 0x7f) + { + llwarns << "LLFolderView::handleUnicodeCharHere - Don't handle non-ascii yet, aborting" << llendl; + return FALSE; + } + + BOOL handled = FALSE; + 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. + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->isOpen()) + { + LLMenuGL::sMenuContainer->hideMenus(); + } + + //do text search + if (mSearchTimer.getElapsedTimeF32() > LLUI::sSettingGroups["config"]->getF32("TypeAheadTimeout")) + { + mSearchString.clear(); + } + mSearchTimer.reset(); + if (mSearchString.size() < 128) + { + mSearchString += uni_char; + } + search(getCurSelectedItem(), mSearchString, FALSE); + + handled = TRUE; + } + + return handled; +} + + +BOOL LLFolderView::canDoDelete() const +{ + if (mSelectedItems.size() == 0) return FALSE; + + for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + if (!(*item_it)->getViewModelItem()->isItemRemovable()) + { + return FALSE; + } + } + return TRUE; +} + +void LLFolderView::doDelete() +{ + if(mSelectedItems.size() > 0) + { + removeSelectedItems(); + } +} + + +BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + mKeyboardSelection = FALSE; + mSearchString.clear(); + + mParentPanel->setFocus(TRUE); + + LLEditMenuHandler::gEditMenuHandler = this; + + return LLView::handleMouseDown( x, y, mask ); +} + +BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward) +{ + // get first selected item + LLFolderViewItem* search_item = first_item; + + // make sure search string is upper case + std::string upper_case_string = search_string; + LLStringUtil::toUpper(upper_case_string); + + // if nothing selected, select first item in folder + if (!search_item) + { + // start from first item + search_item = getNextFromChild(NULL); + } + + // search over all open nodes for first substring match (with wrapping) + BOOL found = FALSE; + LLFolderViewItem* original_search_item = search_item; + do + { + // wrap at end + if (!search_item) + { + if (backward) + { + search_item = getPreviousFromChild(NULL); + } + else + { + search_item = getNextFromChild(NULL); + } + if (!search_item || search_item == original_search_item) + { + break; + } + } + + const std::string current_item_label(search_item->getViewModelItem()->getSearchableName()); + S32 search_string_length = llmin(upper_case_string.size(), current_item_label.size()); + if (!current_item_label.compare(0, search_string_length, upper_case_string)) + { + found = TRUE; + break; + } + if (backward) + { + search_item = search_item->getPreviousOpenNode(); + } + else + { + search_item = search_item->getNextOpenNode(); + } + + } while(search_item != original_search_item); + + + if (found) + { + setSelection(search_item, FALSE, TRUE); + scrollToShowSelection(); + } + + return found; +} + +BOOL LLFolderView::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + // skip LLFolderViewFolder::handleDoubleClick() + return LLView::handleDoubleClick( x, y, mask ); +} + +BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) +{ + // all user operations move keyboard focus to inventory + // this way, we know when to stop auto-updating a search + mParentPanel->setFocus(TRUE); + + BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; + S32 count = mSelectedItems.size(); + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if ( handled + && ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible + && menu ) + { + if (mCallbackRegistrar) + mCallbackRegistrar->pushScope(); + + updateMenuOptions(menu); + + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + if (mCallbackRegistrar) + mCallbackRegistrar->popScope(); + } + else + { + if (menu && menu->getVisible()) + { + menu->setVisible(FALSE); + } + setSelection(NULL, FALSE, TRUE); + } + return handled; +} + +// Add "--no options--" if the menu is completely blank. +BOOL LLFolderView::addNoOptions(LLMenuGL* menu) const +{ + const std::string nooptions_str = "--no options--"; + LLView *nooptions_item = NULL; + + const LLView::child_list_t *list = menu->getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + if (menu_item->getVisible()) + { + return FALSE; + } + std::string name = menu_item->getName(); + if (menu_item->getName() == nooptions_str) + { + nooptions_item = menu_item; + } + } + if (nooptions_item) + { + nooptions_item->setVisible(TRUE); + nooptions_item->setEnabled(FALSE); + return TRUE; + } + return FALSE; +} + +BOOL LLFolderView::handleHover( S32 x, S32 y, MASK mask ) +{ + return LLView::handleHover( x, y, mask ); +} + +BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + 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 drop is not handled by child, it should be handled + // by the folder which is the hierarchy root. + if (!handled) + { + handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + return handled; +} + +void LLFolderView::deleteAllChildren() +{ + closeRenamer(); + if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + mPopupMenuHandle = LLHandle(); + mScrollContainer = NULL; + mRenameItem = NULL; + mRenamer = NULL; + mStatusTextBox = NULL; + + clearSelection(); + LLView::deleteAllChildren(); +} + +void LLFolderView::scrollToShowSelection() +{ + if ( mSelectedItems.size() ) + { + mNeedsScroll = TRUE; + } +} + +// If the parent is scroll container, scroll it to make the selection +// is maximally visible. +void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) +{ + if (!mScrollContainer) return; + + // don't scroll to items when mouse is being used to scroll/drag and drop + if (gFocusMgr.childHasMouseCapture(mScrollContainer)) + { + mNeedsScroll = FALSE; + return; + } + + // if item exists and is in visible portion of parent folder... + if(item) + { + LLRect local_rect = item->getLocalRect(); + LLRect item_scrolled_rect; // item position relative to display area of scroller + LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); + + S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); + 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(); + + // get portion of item that we want to see... + LLRect item_local_rect = LLRect(item->getIndentation(), + local_rect.getHeight(), + llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()), + llmax(0, local_rect.getHeight() - max_height_to_show)); + + LLRect item_doc_rect; + + item->localRectToOtherView(item_local_rect, &item_doc_rect, this); + + mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect ); + + } +} + +LLRect LLFolderView::getVisibleRect() +{ + S32 visible_height = mScrollContainer->getRect().getHeight(); + S32 visible_width = mScrollContainer->getRect().getWidth(); + LLRect visible_rect; + visible_rect.setLeftTopAndSize(-getRect().mLeft, visible_height - getRect().mBottom, visible_width, visible_height); + return visible_rect; +} + +BOOL LLFolderView::getShowSelectionContext() +{ + if (mShowSelectionContext) + { + return TRUE; + } + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + return TRUE; + } + return FALSE; +} + +void LLFolderView::setShowSingleSelection(BOOL show) +{ + if (show != mShowSingleSelection) + { + mMultiSelectionFadeTimer.reset(); + mShowSingleSelection = show; + } +} + +static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select"); +static LLFastTimer::DeclareTimer FTM_INVENTORY("Inventory"); + +// Main idle routine +void LLFolderView::update() +{ + // If this is associated with the user's inventory, don't do anything + // until that inventory is loaded up. + LLFastTimer t2(FTM_INVENTORY); + + if (getFolderViewModel()->getFilter()->isModified() && getFolderViewModel()->getFilter()->isNotDefault()) + { + mNeedsAutoSelect = TRUE; + } + getFolderViewModel()->getFilter()->clearModified(); + + // filter to determine visibility before arranging + filter(*(getFolderViewModel()->getFilter())); + + // automatically show matching items, and select first one if we had a selection + 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 (!mAutoSelectOverride && (!selected_itemp || !selected_itemp->getViewModelItem()->potentiallyVisible())) + { + // 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 (getFolderViewModel()->getFilter()->showAllResults()) + { + // 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 = getViewModelItem()->passedFilter() + && mViewModel->contentsReady(); + if (filter_finished + || gFocusMgr.childHasKeyboardFocus(getParent()) // assume we are inside a scroll container + || gFocusMgr.childHasMouseCapture(getParent())) + { + // 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_finished) + { + // calculate rectangle to pin item to at start of animated rearrange + if (!mPinningSelectedItem && !mSelectedItems.empty()) + { + // lets pin it! + mPinningSelectedItem = TRUE; + + LLRect visible_content_rect = mScrollContainer->getVisibleContentRect(); + LLFolderViewItem* selected_item = mSelectedItems.back(); + + LLRect item_rect; + selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); + // if item is visible in scrolled region + if (visible_content_rect.overlaps(item_rect)) + { + // then attempt to keep it in same place on screen + mScrollConstraintRect = item_rect; + mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); + } + else + { + // otherwise we just want it onscreen somewhere + LLRect content_rect = mScrollContainer->getContentWindowRect(); + mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + } + } + else + { + // stop pinning selected item after folders stop rearranging + if (!needsArrange()) + { + mPinningSelectedItem = FALSE; + } + } + + LLRect constraint_rect; + if (mPinningSelectedItem) + { + // use last known constraint rect for pinned item + constraint_rect = mScrollConstraintRect; + } + else + { + // during normal use (page up/page down, etc), just try to fit item on screen + LLRect content_rect = mScrollContainer->getContentWindowRect(); + constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + + BOOL is_visible = isInVisibleChain(); + + if ( is_visible ) + { + sanitizeSelection(); + if( needsArrange() ) + { + S32 height = 0; + S32 width = 0; + S32 total_height = arrange( &width, &height ); + notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); + } + } + + if (mSelectedItems.size() && mNeedsScroll) + { + scrollToShowItem(mSelectedItems.back(), constraint_rect); + // continue scrolling until animated layout change is done + if (filter_finished + && (!needsArrange() || !is_visible)) + { + mNeedsScroll = FALSE; + } + } + + if (mSignalSelectCallback) + { + //RN: we use keyboard focus as a proxy for user-explicit actions + BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS); + mSelectSignal(mSelectedItems, take_keyboard_focus); + } + mSignalSelectCallback = FALSE; +} + +void LLFolderView::dumpSelectionInformation() +{ + llinfos << "LLFolderView::dumpSelectionInformation()" << llendl; + llinfos << "****************************************" << llendl; + selected_items_t::iterator item_it; + for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + { + llinfos << " " << (*item_it)->getName() << llendl; + } + llinfos << "****************************************" << llendl; +} + +void LLFolderView::updateRenamerPosition() +{ + if(mRenameItem) + { + // See also LLFolderViewItem::draw() + S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mRenameItem->getIndentation(); + S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenameItem->localPointToScreen( x, y, &x, &y ); + screenPointToLocal( x, y, &x, &y ); + mRenamer->setOrigin( x, y ); + + LLRect scroller_rect(0, 0, LLUI::getWindowSize().mV[VX], 0); + if (mScrollContainer) + { + scroller_rect = mScrollContainer->getContentWindowRect(); + } + + S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); + S32 height = mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; + mRenamer->reshape( width, height, TRUE ); + } +} + +// Update visibility and availability (i.e. enabled/disabled) of context menu items. +void LLFolderView::updateMenuOptions(LLMenuGL* menu) +{ + const LLView::child_list_t *list = menu->getChildList(); + + LLView::child_list_t::const_iterator menu_itor; + for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor) + { + (*menu_itor)->setVisible(FALSE); + (*menu_itor)->pushVisible(TRUE); + (*menu_itor)->setEnabled(TRUE); + } + + // Successively filter out invalid options + + U32 flags = FIRST_SELECTED_ITEM; + for (selected_items_t::iterator item_itor = mSelectedItems.begin(); + item_itor != mSelectedItems.end(); + ++item_itor) + { + LLFolderViewItem* selected_item = (*item_itor); + selected_item->buildContextMenu(*menu, flags); + flags = 0x0; + } + + addNoOptions(menu); +} + +// Refresh the context menu (that is already shown). +void LLFolderView::updateMenu() +{ + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + if (menu && menu->getVisible()) + { + updateMenuOptions(menu); + menu->needsArrange(); // update menu height if needed + } +} + +bool LLFolderView::selectFirstItem() +{ + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();++iter) + { + LLFolderViewFolder* folder = (*iter ); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getNextFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + + } + for(items_t::iterator iit = mItems.begin(); + iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; +} +bool LLFolderView::selectLastItem() +{ + for(items_t::reverse_iterator iit = mItems.rbegin(); + iit != mItems.rend(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (itemp->getVisible()) + { + setSelection(itemp,FALSE,TRUE); + return true; + } + } + for (folders_t::reverse_iterator iter = mFolders.rbegin(); + iter != mFolders.rend();++iter) + { + LLFolderViewFolder* folder = (*iter); + if (folder->getVisible()) + { + LLFolderViewItem* itemp = folder->getPreviousFromChild(0,true); + if(itemp) + setSelection(itemp,FALSE,TRUE); + return true; + } + } + return false; +} + + +S32 LLFolderView::notify(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + scrollToShowSelection(); + return 1; + + } + else if(str_action == "select_last") + { + setFocus(true); + selectLastItem(); + scrollToShowSelection(); + return 1; + } + } + return 0; +} + + +///---------------------------------------------------------------------------- +/// Local function definitions +///---------------------------------------------------------------------------- + +void LLFolderView::onRenamerLost() +{ + if (mRenamer && mRenamer->getVisible()) + { + mRenamer->setVisible(FALSE); + + // will commit current name (which could be same as original name) + mRenamer->setFocus(FALSE); + } + + if( mRenameItem ) + { + setSelection( mRenameItem, TRUE ); + mRenameItem = NULL; + } +} + +S32 LLFolderView::getItemHeight() +{ + if(!hasVisibleChildren()) + { + //We need to display status textbox, let's reserve some place for it + return llmax(0, mStatusTextBox->getTextPixelHeight()); + } + return 0; +} -- cgit v1.3 From d3edb1c466f42e2c46c77e43b26d700c6298b8d6 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Wed, 4 Jul 2012 00:30:00 -0700 Subject: CHUI-101 WIP Make LLFolderview general purpose partial fix for crash on startup --- indra/llui/llfolderview.cpp | 4 ++-- indra/llui/llfolderviewitem.h | 2 +- indra/newview/llimfloatercontainer.cpp | 17 ++++++++++++++--- indra/newview/llimfloatercontainer.h | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 0d3bc44ae4..990b79a30b 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1798,8 +1798,8 @@ void LLFolderView::update() BOOL filter_finished = getViewModelItem()->passedFilter() && mViewModel->contentsReady(); if (filter_finished - || gFocusMgr.childHasKeyboardFocus(getParent()) // assume we are inside a scroll container - || gFocusMgr.childHasMouseCapture(getParent())) + || gFocusMgr.childHasKeyboardFocus(mParentPanel) + || gFocusMgr.childHasMouseCapture(mParentPanel)) { // finishing the filter process, giving focus to the folder view, or dragging the scrollbar all stop the auto select process mNeedsAutoSelect = FALSE; diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 9cb885066a..50d3e0580e 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -53,7 +53,7 @@ public: { Optional folder_arrow_image, selection_image; - Optional root; + Mandatory root; Mandatory listener; Optional folder_indentation, // pixels diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 261b5f33a2..2b943df48f 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -47,8 +47,9 @@ // LLIMFloaterContainer // LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) -: LLMultiFloater(seed) - ,mExpandCollapseBtn(NULL) +: LLMultiFloater(seed), + mExpandCollapseBtn(NULL), + mFolders(NULL) { // Firstly add our self to IMSession observers, so we catch session events LLIMMgr::getInstance()->addSessionObserver(this); @@ -90,6 +91,16 @@ BOOL LLIMFloaterContainer::postBuild() mConversationsListPanel = getChild("conversations_list_panel"); + LLFolderView::Params p; + //TODO RN: define view model for conversations + //p.view_model = ?; + p.parent_panel = mConversationsListPanel; + p.rect = mConversationsListPanel->getLocalRect(); + p.follows.flags = FOLLOWS_ALL; + + mFolders = LLUICtrlFactory::create(p); + mConversationsListPanel->addChild(mFolders); + mExpandCollapseBtn = getChild("expand_collapse_btn"); mExpandCollapseBtn->setClickedCallback(boost::bind(&LLIMFloaterContainer::onExpandCollapseButtonClicked, this)); @@ -512,7 +523,7 @@ LLFolderViewItem* LLIMFloaterContainer::createConversationItemWidget(LLConversat //params.icon = bridge->getIcon(); //params.icon_open = bridge->getOpenIcon(); //params.creation_date = bridge->getCreationDate(); - //params.root = mFolderRoot; + params.root = mFolders; params.listener = item; params.rect = LLRect (0, 0, 0, 0); params.tool_tip = params.name; diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index f68cf07d8c..890a115a04 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -194,6 +194,7 @@ private: LLPanel* mConversationsListPanel; // This is the widget we add items to (i.e. clickable title for each conversation) conversations_items_map mConversationsItems; conversations_widgets_map mConversationsWidgets; + LLFolderView* mFolders; }; #endif // LL_LLIMFLOATERCONTAINER_H -- cgit v1.3 From ec15ff6350c0997421cf2884e40aa9feaa070d4d Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 5 Jul 2012 16:42:20 -0700 Subject: CHUI-98 : WIP, use the refactored folder view for conversation view list --- indra/llui/llfolderview.cpp | 36 ++++++++++----- indra/newview/llimfloatercontainer.cpp | 23 +++++++++- indra/newview/llimfloatercontainer.h | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 14 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 990b79a30b..92e3b7a8e9 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -320,10 +320,10 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height ) LLFolderViewFolder::arrange(&mMinWidth, &target_height); - LLRect scroll_rect = mScrollContainer->getContentWindowRect(); + LLRect scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); reshape( llmax(scroll_rect.getWidth(), mMinWidth), llround(mCurHeight) ); - LLRect new_scroll_rect = mScrollContainer->getContentWindowRect(); + LLRect new_scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) { reshape( llmax(scroll_rect.getWidth(), mMinWidth), llround(mCurHeight) ); @@ -945,7 +945,7 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) mAutoOpenItems.push(item); item->setOpen(TRUE); - LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); scrollToShowItem(item, constraint_rect); } @@ -1225,25 +1225,37 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) case KEY_PAGE_UP: mSearchString.clear(); - mScrollContainer->pageUp(30); + if (mScrollContainer) + { + mScrollContainer->pageUp(30); + } handled = TRUE; break; case KEY_PAGE_DOWN: mSearchString.clear(); - mScrollContainer->pageDown(30); + if (mScrollContainer) + { + mScrollContainer->pageDown(30); + } handled = TRUE; break; case KEY_HOME: mSearchString.clear(); - mScrollContainer->goToTop(); + if (mScrollContainer) + { + mScrollContainer->goToTop(); + } handled = TRUE; break; case KEY_END: mSearchString.clear(); - mScrollContainer->goToBottom(); + if (mScrollContainer) + { + mScrollContainer->goToBottom(); + } break; case KEY_DOWN: @@ -1719,8 +1731,8 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr LLRect LLFolderView::getVisibleRect() { - S32 visible_height = mScrollContainer->getRect().getHeight(); - S32 visible_width = mScrollContainer->getRect().getWidth(); + S32 visible_height = (mScrollContainer ? mScrollContainer->getRect().getHeight() : 0); + S32 visible_width = (mScrollContainer ? mScrollContainer->getRect().getWidth() : 0); LLRect visible_rect; visible_rect.setLeftTopAndSize(-getRect().mLeft, visible_height - getRect().mBottom, visible_width, visible_height); return visible_rect; @@ -1816,7 +1828,7 @@ void LLFolderView::update() // lets pin it! mPinningSelectedItem = TRUE; - LLRect visible_content_rect = mScrollContainer->getVisibleContentRect(); + LLRect visible_content_rect = (mScrollContainer ? mScrollContainer->getVisibleContentRect() : LLRect()); LLFolderViewItem* selected_item = mSelectedItems.back(); LLRect item_rect; @@ -1831,7 +1843,7 @@ void LLFolderView::update() else { // otherwise we just want it onscreen somewhere - LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); } } @@ -1854,7 +1866,7 @@ void LLFolderView::update() else { // during normal use (page up/page down, etc), just try to fit item on screen - LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect()); constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); } diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 2b943df48f..be38eddbaf 100644 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -91,12 +91,14 @@ BOOL LLIMFloaterContainer::postBuild() mConversationsListPanel = getChild("conversations_list_panel"); + mRoot = new LLConversationItem(); LLFolderView::Params p; - //TODO RN: define view model for conversations - //p.view_model = ?; + // CHUI-98 : View Model for conversations + p.view_model = &mConversationViewModel; p.parent_panel = mConversationsListPanel; p.rect = mConversationsListPanel->getLocalRect(); p.follows.flags = FOLLOWS_ALL; + p.listener = mRoot; mFolders = LLUICtrlFactory::create(p); mConversationsListPanel->addChild(mFolders); @@ -544,6 +546,15 @@ LLConversationItem::LLConversationItem(std::string name, const LLUUID& uuid, LLF mName = "Nearby Chat"; } +LLConversationItem::LLConversationItem() : + mName(""), + mUUID(), + mFloater(NULL), + mContainer(NULL) +{ +} + + // Virtual action callbacks void LLConversationItem::selectItem(void) { @@ -589,4 +600,12 @@ void LLConversationItem::showProperties(void) { } +bool LLConversationSort::operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const +{ + // We compare only by name for the moment + // *TODO : Implement the sorting by date + S32 compare = LLStringUtil::compareDict(a->getDisplayName(), b->getDisplayName()); + return (compare < 0); +} + // EOF diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index 890a115a04..f146e65897 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -57,6 +57,7 @@ class LLConversationItem : public LLFolderViewModelItemCommon { public: LLConversationItem(std::string name, const LLUUID& uuid, LLFloater* floaterp, LLIMFloaterContainer* containerp); + LLConversationItem(); virtual ~LLConversationItem() {} // Stub those things we won't really be using in this conversation context @@ -120,6 +121,86 @@ private: LLFloater* mFloater; LLIMFloaterContainer* mContainer; }; + +// We don't want to ever filter conversations but we need to declare that class to create a conversation view model. +// We just stubb everything for the moment. +class LLConversationFilter : public LLFolderViewFilter +{ +public: + + enum ESortOrderType + { + SO_NAME = 0, // Sort inventory by name + SO_DATE = 0x1, // Sort inventory by date + }; + + LLConversationFilter() { mEmpty = ""; } + ~LLConversationFilter() {} + + bool check(const LLFolderViewModelItem* item) { return true; } + bool checkFolder(const LLFolderViewModelItem* folder) const { return true; } + void setEmptyLookupMessage(const std::string& message) { } + std::string getEmptyLookupMessage() const { return mEmpty; } + bool showAllResults() const { return true; } + + bool isActive() const { return false; } + bool isModified() const { return false; } + void clearModified() { } + const std::string& getName() const { return mEmpty; } + const std::string& getFilterText() { return mEmpty; } + void setModified(EFilterModified behavior = FILTER_RESTART) { } + + void setFilterCount(S32 count) { } + S32 getFilterCount() const { return 0; } + void decrementFilterCount() { } + + bool isDefault() const { return true; } + bool isNotDefault() const { return false; } + void markDefault() { } + void resetDefault() { } + + S32 getCurrentGeneration() const { return 0; } + S32 getFirstSuccessGeneration() const { return 0; } + S32 getFirstRequiredGeneration() const { return 0; } +private: + std::string mEmpty; +}; + +class LLConversationSort +{ +public: + LLConversationSort(U32 order = 0) + : mSortOrder(order), + mByDate(false), + mByName(false) + { + mByDate = (order & LLConversationFilter::SO_DATE); + mByName = (order & LLConversationFilter::SO_NAME); + } + + bool isByDate() const { return mByDate; } + U32 getSortOrder() const { return mSortOrder; } + + bool operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const; +private: + U32 mSortOrder; + bool mByDate; + bool mByName; +}; + +class LLConversationViewModel +: public LLFolderViewModel +{ +public: + typedef LLFolderViewModel base_t; + + void sort(LLFolderViewFolder* folder) { } // *TODO : implement conversation sort + bool contentsReady() { return true; } // *TODO : we need to check that participants names are available somewhat + bool startDrag(std::vector& items) { return false; } // We do not allow drag of conversation items + +private: +}; + // CHUI-137 : End class LLIMFloaterContainer @@ -189,6 +270,8 @@ public: void addConversationListItem(std::string name, const LLUUID& uuid, LLFloater* floaterp); LLFloater* findConversationItem(LLUUID& uuid); private: + LLConversationViewModel mConversationViewModel; + LLConversationItem* mRoot; LLFolderViewItem* createConversationItemWidget(LLConversationItem* item); // Conversation list data LLPanel* mConversationsListPanel; // This is the widget we add items to (i.e. clickable title for each conversation) -- cgit v1.3 From c9e11635488720626601b7b4a7926f09031a6908 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Sat, 7 Jul 2012 01:10:30 +0300 Subject: Another Linux build fix. --- indra/llui/llfolderview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 92e3b7a8e9..8ade17b763 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1927,7 +1927,7 @@ void LLFolderView::updateRenamerPosition() screenPointToLocal( x, y, &x, &y ); mRenamer->setOrigin( x, y ); - LLRect scroller_rect(0, 0, LLUI::getWindowSize().mV[VX], 0); + LLRect scroller_rect(0, 0, (S32)LLUI::getWindowSize().mV[VX], 0); if (mScrollContainer) { scroller_rect = mScrollContainer->getContentWindowRect(); -- cgit v1.3 From decd8a435d8fb15bab52eec9e447b176e33eb5cf Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Tue, 24 Jul 2012 14:42:28 -0700 Subject: CHUI-211: Problem was due to a non-heap variable being deleted and then referenced later (which was found by ProductEngine). Also the crash occurred at a specifc location llpangelobjectinventory::reset() during a static_cast, so now using a dynamic_cast as a safeguard. --- indra/llui/llfolderview.cpp | 3 ++- indra/newview/llpanelobjectinventory.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 8ade17b763..10729a3eae 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -266,7 +266,8 @@ LLFolderView::~LLFolderView( void ) mItems.clear(); mFolders.clear(); - delete mViewModel; + //product engine bugfix, prevent deletion of non-heap data + //delete mViewModel; mViewModel = NULL; } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index ca20051a51..937d3bb8c5 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1565,7 +1565,12 @@ void LLPanelObjectInventory::reset() mFolders = LLUICtrlFactory::create(p); // this ensures that we never say "searching..." or "no items found" //TODO RN: make this happen by manipulating filter object directly - static_cast(mFolders->getFolderViewModel()->getFilter())->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); + LLInventoryFilter* inventoryFilter = dynamic_cast(mFolders->getFolderViewModel()->getFilter()); + if(inventoryFilter) + { + inventoryFilter->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); + } + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); if (hasFocus()) -- cgit v1.3 From 891a09561d4dff23836c8618d481a6cd2dd001de Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 24 Jul 2012 20:29:20 -0700 Subject: CHUI-206 FIX Viewer crash when selecting to cut inventory item, then selecting to cut another inventory item Seems to work now, without filtering de-optimization --- indra/llui/llfolderview.cpp | 2 +- indra/newview/llfolderviewmodelinventory.cpp | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 8ade17b763..943e690948 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1123,7 +1123,7 @@ void LLFolderView::paste() LLFolderViewFolder* folder = dynamic_cast(item); if (folder == NULL) { - item = item->getParentFolder(); + folder = item->getParentFolder(); } folder_set.insert(folder); } diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index d23b4af8cb..faf5b3e7ac 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -163,11 +163,6 @@ bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* ite { // failed to pass an earlier filter that was a subset of the current one // go ahead and flag this item as done - item->filter(filter); - if (item->passedFilter()) - { - llerrs << "Invalid shortcut in inventory filtering!" << llendl; - } item->setPassedFilter(false, false, filter_generation); } else -- cgit v1.3 From f6dfd6bf0f3ea0e9b5f56a939867353c393539d6 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Wed, 25 Jul 2012 18:20:54 -0700 Subject: CHUI-222 FIX Selecting None in inventory filters does not update until inventory selected --- indra/llui/llfolderview.cpp | 2 - indra/llui/llfolderviewitem.cpp | 11 +++-- indra/llui/llfolderviewmodel.h | 4 +- indra/newview/llfolderviewmodelinventory.cpp | 74 +++++++++++++--------------- indra/newview/llfolderviewmodelinventory.h | 4 +- indra/newview/llimfloatercontainer.h | 2 +- indra/newview/llpanelobjectinventory.cpp | 2 +- 7 files changed, 49 insertions(+), 50 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 10729a3eae..147af04f30 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -266,8 +266,6 @@ LLFolderView::~LLFolderView( void ) mItems.clear(); mFolders.clear(); - //product engine bugfix, prevent deletion of non-heap data - //delete mViewModel; mViewModel = NULL; } diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 741fc9c324..a356d587f9 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1543,11 +1543,14 @@ BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) void LLFolderViewFolder::requestArrange() { - mLastArrangeGeneration = -1; - // flag all items up to root - if (mParentFolder) + //if ( mLastArrangeGeneration != -1) { - mParentFolder->requestArrange(); + mLastArrangeGeneration = -1; + // flag all items up to root + if (mParentFolder) + { + mParentFolder->requestArrange(); + } } } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 268ae8eea8..acdec53602 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -152,7 +152,7 @@ public: virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet? - virtual bool filter( LLFolderViewFilter& filter) = 0; + virtual void filter( LLFolderViewFilter& filter) = 0; virtual bool passedFilter(S32 filter_generation = -1) = 0; virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0; virtual void setPassedFilter(bool passed, bool passed_folder, S32 filter_generation) = 0; @@ -192,6 +192,7 @@ public: : mSortVersion(-1), mPassedFilter(true), mPassedFolderFilter(true), + mPrevPassedAllFilters(false), mFolderViewItem(NULL), mLastFilterGeneration(-1), mMostFilteredDescendantGeneration(-1), @@ -232,6 +233,7 @@ protected: S32 mSortVersion; bool mPassedFilter; bool mPassedFolderFilter; + bool mPrevPassedAllFilters; S32 mLastFilterGeneration; S32 mMostFilteredDescendantGeneration; diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index e8135496d5..13ca73917b 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -133,8 +133,9 @@ bool LLFolderViewModelItemInventory::passedFilter(S32 filter_generation) filter_generation = mRootViewModel.getFilter()->getFirstSuccessGeneration(); return mPassedFolderFilter - && mLastFilterGeneration >= filter_generation - && (mPassedFilter || descendantsPassedFilter(filter_generation)); + && (descendantsPassedFilter(filter_generation) + || (mLastFilterGeneration >= filter_generation + && mPassedFilter)); } bool LLFolderViewModelItemInventory::descendantsPassedFilter(S32 filter_generation) @@ -148,30 +149,29 @@ void LLFolderViewModelItemInventory::setPassedFilter(bool passed, bool passed_fo mPassedFilter = passed; mPassedFolderFilter = passed_folder; mLastFilterGeneration = filter_generation; + + bool passed_filter_before = mPrevPassedAllFilters; + mPrevPassedAllFilters = passedFilter(filter_generation); + + if (passed_filter_before != mPrevPassedAllFilters) + { + //TODO RN: ensure this still happens, but without dependency on folderview + LLFolderViewFolder* parent_folder = mFolderViewItem->getParentFolder(); + if (parent_folder) + { + parent_folder->requestArrange(); + } + } } -bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter ) +void LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter ) { - bool passed_filter_before = item->passedFilter(); S32 filter_generation = filter.getCurrentGeneration(); - S32 must_pass_generation = filter.getFirstRequiredGeneration(); if (item->getLastFilterGeneration() < filter_generation) { // recursive application of the filter for child items item->filter( filter ); - - if (item->getLastFilterGeneration() >= must_pass_generation - && !item->passedFilter(must_pass_generation)) - { - // failed to pass an earlier filter that was a subset of the current one - // go ahead and flag this item as done - if (item->passedFilter()) - { - llerrs << "Invalid shortcut in inventory filtering!" << llendl; - } - item->setPassedFilter(false, false, filter_generation); - } } // track latest generation to pass any child items, for each folder up to root @@ -184,39 +184,36 @@ bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* ite view_model->mMostFilteredDescendantGeneration = filter_generation; view_model = static_cast(view_model->mParent); } - - return !passed_filter_before; - } - else // !item->passedfilter() - { - return passed_filter_before; } } -bool LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter) +void LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter) { - bool changed = false; + const S32 filter_generation = filter.getCurrentGeneration(); + const S32 must_pass_generation = filter.getFirstRequiredGeneration(); + + if (getLastFilterGeneration() >= must_pass_generation + && !passedFilter(must_pass_generation)) + { + // failed to pass an earlier filter that was a subset of the current one + // go ahead and flag this item as done + setPassedFilter(false, false, filter_generation); + return; + } if(!mChildren.empty() - && (getLastFilterGeneration() < filter.getFirstRequiredGeneration() // haven't checked descendants against minimum required generation to pass - || descendantsPassedFilter(filter.getFirstRequiredGeneration()))) // or at least one descendant has passed the minimum requirement + && (getLastFilterGeneration() < must_pass_generation // haven't checked descendants against minimum required generation to pass + || descendantsPassedFilter(must_pass_generation))) // or at least one descendant has passed the minimum requirement { // now query children - for (child_list_t::iterator iter = mChildren.begin(); - iter != mChildren.end() && filter.getFilterCount() > 0; + for (child_list_t::iterator iter = mChildren.begin(), end_iter = mChildren.end(); + iter != end_iter && filter.getFilterCount() > 0; ++iter) { - changed |= filterChildItem((*iter), filter); + filterChildItem((*iter), filter); } } - if (changed) - { - //TODO RN: ensure this still happens, but without dependency on folderview - LLFolderViewFolder* folder = static_cast(mFolderViewItem); - folder->requestArrange(); - } - // if we didn't use all filter iterations // that means we filtered all of our descendants // so filter ourselves now @@ -229,11 +226,10 @@ bool LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter) ? filter.checkFolder(this) : true; - setPassedFilter(passed_filter, passed_filter_folder, filter.getCurrentGeneration()); + setPassedFilter(passed_filter, passed_filter_folder, filter_generation); //TODO RN: create interface for string highlighting //mStringMatchOffset = filter.getStringMatchOffset(this); } - return changed; } LLFolderViewModelInventory* LLInventoryPanel::getFolderViewModel() diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index eb2a4bfdec..ab67c93897 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -59,8 +59,8 @@ public: virtual bool passedFilter(S32 filter_generation = -1); virtual bool descendantsPassedFilter(S32 filter_generation = -1); virtual void setPassedFilter(bool filtered, bool filtered_folder, S32 filter_generation); - virtual bool filter( LLFolderViewFilter& filter); - virtual bool filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter); + virtual void filter( LLFolderViewFilter& filter); + virtual void filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter); virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0; virtual LLToolDragAndDrop::ESource getDragSource() const = 0; diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index a25ea0ab46..7005ab7b6a 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -89,7 +89,7 @@ public: virtual bool hasChildren() const { return FALSE; } virtual bool potentiallyVisible() { return true; } - virtual bool filter( LLFolderViewFilter& filter) { return true; } + virtual void filter( LLFolderViewFilter& filter) { } virtual bool descendantsPassedFilter(S32 filter_generation = -1) { return true; } virtual void setPassedFilter(bool passed, bool passed_folder, S32 filter_generation) { } virtual bool passedFilter(S32 filter_generation = -1) { return true; } diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 9bd716e900..4719191231 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1616,7 +1616,7 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, iter != inventory->end(); ) { LLInventoryObject* item = *iter++; - LLFloaterProperties* floater = LLFloaterReg::findTypedInstance("properites", item->getUUID()); + LLFloaterProperties* floater = LLFloaterReg::findTypedInstance("properties", item->getUUID()); if(floater) { floater->refresh(); -- cgit v1.3 From a204059d2e69fb33cb1a3c8d2fbed35d3967297c Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Wed, 1 Aug 2012 01:14:27 -0700 Subject: CHUI-267 FIX Full inventory listing not always shown for test account changed LLFolderViewModelInterface::getFilter() to return a reference, since it is never NULL removed sort order from filter, which was causing unneeded filtering --- indra/llui/llfolderview.cpp | 12 ++-- indra/llui/llfolderview.h | 2 +- indra/llui/llfolderviewitem.cpp | 68 +++++++----------- indra/llui/llfolderviewitem.h | 20 +++--- indra/llui/llfolderviewmodel.cpp | 8 +-- indra/llui/llfolderviewmodel.h | 82 ++++++++++++++++------ indra/newview/llfloateroutbox.cpp | 2 +- indra/newview/llfolderviewmodelinventory.cpp | 40 ++++------- indra/newview/llfolderviewmodelinventory.h | 36 ++++++---- indra/newview/llinventorybridge.cpp | 2 +- indra/newview/llinventoryfilter.cpp | 17 ----- indra/newview/llinventoryfilter.h | 25 +++---- indra/newview/llinventorypanel.cpp | 53 +++++++------- indra/newview/llinventorypanel.h | 10 ++- indra/newview/llpanellandmarks.cpp | 24 ++----- indra/newview/llpanelmaininventory.cpp | 76 ++++++++++---------- indra/newview/llpanelmarketplaceinbox.cpp | 4 +- indra/newview/llpanelmarketplaceinboxinventory.cpp | 6 +- indra/newview/llpanelmarketplaceinboxinventory.h | 2 +- indra/newview/llpanelobjectinventory.cpp | 7 +- indra/newview/lltexturectrl.cpp | 10 +-- 21 files changed, 239 insertions(+), 267 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index e09026fc33..d714d4623d 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -274,7 +274,7 @@ BOOL LLFolderView::canFocusChildren() const return FALSE; } -BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) +void LLFolderView::addFolder( LLFolderViewFolder* folder) { LLFolderViewFolder::addFolder(folder); @@ -288,8 +288,6 @@ BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) //{ // mFolders.insert(mFolders.begin(), folder); //} - - return TRUE; } void LLFolderView::closeAllFolders() @@ -1769,14 +1767,14 @@ void LLFolderView::update() // until that inventory is loaded up. LLFastTimer t2(FTM_INVENTORY); - if (getFolderViewModel()->getFilter()->isModified() && getFolderViewModel()->getFilter()->isNotDefault()) + if (getFolderViewModel()->getFilter().isModified() && getFolderViewModel()->getFilter().isNotDefault()) { mNeedsAutoSelect = TRUE; } - getFolderViewModel()->getFilter()->clearModified(); + getFolderViewModel()->getFilter().clearModified(); // filter to determine visibility before arranging - filter(*(getFolderViewModel()->getFilter())); + filter(getFolderViewModel()->getFilter()); // automatically show matching items, and select first one if we had a selection if (mNeedsAutoSelect) @@ -1794,7 +1792,7 @@ void LLFolderView::update() // Open filtered folders for folder views with mAutoSelectOverride=TRUE. // Used by LLPlacesFolderView. - if (getFolderViewModel()->getFilter()->showAllResults()) + if (getFolderViewModel()->getFilter().showAllResults()) { // 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 diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 5ebd8f73ac..05beff9bd8 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -121,7 +121,7 @@ public: void closeAllFolders(); void openTopLevelFolders(); - virtual BOOL addFolder( LLFolderViewFolder* folder); + virtual void addFolder( LLFolderViewFolder* folder); // Find width and height of this object and its children. Also // makes sure that this view and its children are the right size. diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 0f486d06c9..167c8123a1 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -221,11 +221,11 @@ void LLFolderViewItem::refresh() mIconOpen = vmi.getIconOpen(); mIconOverlay = vmi.getIconOverlay(); - if (mRoot->useLabelSuffix()) - { + if (mRoot->useLabelSuffix()) + { mLabelStyle = vmi.getLabelStyle(); mLabelSuffix = vmi.getLabelSuffix(); -} + } //TODO RN: make sure this logic still fires //std::string searchable_label(mLabel); @@ -255,7 +255,7 @@ void LLFolderViewItem::arrangeAndSet(BOOL set_selection, LLFolderView* root = getRoot(); if (getParentFolder()) { - getParentFolder()->requestArrange(); + getParentFolder()->requestArrange(); } if(set_selection) { @@ -275,9 +275,9 @@ std::set LLFolderViewItem::getSelectionList() const } // addToFolder() returns TRUE if it succeeds. FALSE otherwise -BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder) +void LLFolderViewItem::addToFolder(LLFolderViewFolder* folder) { - return folder->addItem(this); + folder->addItem(this); } @@ -418,12 +418,12 @@ void LLFolderViewItem::rename(const std::string& new_name) { getViewModelItem()->renameItem(new_name); - if(mParentFolder) - { - mParentFolder->requestSort(); - } - } + //if(mParentFolder) + //{ + // mParentFolder->requestSort(); + //} } +} const std::string& LLFolderViewItem::getName( void ) const { @@ -839,9 +839,9 @@ LLFolderViewFolder::~LLFolderViewFolder( void ) } // addToFolder() returns TRUE if it succeeds. FALSE otherwise -BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder) +void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder) { - return folder->addFolder(this); + folder->addFolder(this); } static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); @@ -1008,11 +1008,6 @@ BOOL LLFolderViewFolder::needsArrange() return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); } -void LLFolderViewFolder::requestSort() -{ - getViewModelItem()->requestSort(); -} - //TODO RN: get height resetting working //void LLFolderViewFolder::setPassedFilter(BOOL passed, BOOL passed_folder, S32 filter_generation) //{ @@ -1417,7 +1412,6 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) } //item has been removed, need to update filter getViewModelItem()->removeChild(item->getViewModelItem()); - getViewModelItem()->dirtyFilter(); //because an item is going away regardless of filter status, force rearrange requestArrange(); removeChild(item); @@ -1483,7 +1477,7 @@ BOOL LLFolderViewFolder::isRemovable() } // this is an internal method used for adding items to folders. -BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) +void LLFolderViewFolder::addItem(LLFolderViewItem* item) { if (item->getParentFolder()) { @@ -1496,7 +1490,6 @@ BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); item->setVisible(FALSE); - addChild(item); // TODO RN - port creation date management to new code location #if 0 @@ -1504,10 +1497,7 @@ BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) setCreationDate(llmax(mCreationDate, item->getCreationDate())); #endif - // Handle sorting - requestArrange(); - requestSort(); - + addChild(item); getViewModelItem()->addChild(item->getViewModelItem()); // TODO RN - port creation date management to new code location #if 0 @@ -1533,14 +1523,10 @@ BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) // parentp = parentp->getParentFolder(); //} - - item->getViewModelItem()->dirtyFilter(); - - return TRUE; } // this is an internal method used for adding items to folders. -BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) +void LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) { if (folder->mParentFolder) { @@ -1551,30 +1537,26 @@ BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) folder->setOrigin(0, 0); folder->reshape(getRect().getWidth(), 0); folder->setVisible(FALSE); - addChild( folder ); // rearrange all descendants too, as our indentation level might have changed - folder->requestArrange(); - requestSort(); + //folder->requestArrange(); + //requestSort(); + addChild( folder ); getViewModelItem()->addChild(folder->getViewModelItem()); - //After addChild since addChild assigns parent to bubble up to when calling dirtyFilter - folder->getViewModelItem()->dirtyFilter(); - - return TRUE; } void LLFolderViewFolder::requestArrange() { //if ( mLastArrangeGeneration != -1) { - mLastArrangeGeneration = -1; - // flag all items up to root - if (mParentFolder) - { - mParentFolder->requestArrange(); - } + mLastArrangeGeneration = -1; + // flag all items up to root + if (mParentFolder) + { + mParentFolder->requestArrange(); } } +} void LLFolderViewFolder::toggleOpen() { diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index df007dd15d..baa12b38f3 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -116,8 +116,8 @@ protected: // this is an internal method used for adding items to folders. A // no-op at this level, but reimplemented in derived classes. - virtual BOOL addItem(LLFolderViewItem*) { return FALSE; } - virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } + virtual void addItem(LLFolderViewItem*) { } + virtual void addFolder(LLFolderViewFolder*) { } static LLFontGL* getLabelFontForStyle(U8 style); @@ -131,7 +131,7 @@ public: virtual ~LLFolderViewItem( void ); // addToFolder() returns TRUE if it succeeds. FALSE otherwise - virtual BOOL addToFolder(LLFolderViewFolder* folder); + virtual void addToFolder(LLFolderViewFolder* folder); // Finds width and height of this object and it's children. Also // makes sure that this view and it's children are the right size. @@ -297,7 +297,7 @@ public: LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); // addToFolder() returns TRUE if it succeeds. FALSE otherwise - virtual BOOL addToFolder(LLFolderViewFolder* folder); + virtual void addToFolder(LLFolderViewFolder* folder); // Finds width and height of this object and it's children. Also // makes sure that this view and it's children are the right size. @@ -356,8 +356,6 @@ public: // Called when a child is refreshed. virtual void requestArrange(); - virtual void requestSort(); - // internal method which doesn't update the entire view. This // method was written because the list iterators destroy the state // of other iterations, thus, we can't arrange while iterating @@ -381,8 +379,6 @@ public: void applyFunctorToChildren(LLFolderViewFunctor& functor); virtual void openItem( void ); - virtual BOOL addItem(LLFolderViewItem* item); - virtual BOOL addFolder( LLFolderViewFolder* folder); // LLView functionality virtual BOOL handleHover(S32 x, S32 y, MASK mask); @@ -412,6 +408,14 @@ public: LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse); void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector& items); +protected: + friend void LLFolderViewItem::addToFolder(LLFolderViewFolder*); + // internal functions for tracking folders and items separately + // use addToFolder() virtual method to ensure folders are always added to mFolders + // and not mItems + void addItem(LLFolderViewItem* item); + void addFolder( LLFolderViewFolder* folder); + public: //WARNING: do not call directly...use the appropriate LLFolderViewModel-derived class instead template void sortFolders(const SORT_FUNC& func) { mFolders.sort(func); } diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index dc6e4d754b..6aa4a63edc 100644 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -36,18 +36,18 @@ bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item) std::string LLFolderViewModelCommon::getStatusText() { - if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter()->getCurrentGeneration()) + if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration()) { return LLTrans::getString("Searching"); } else { - return getFilter()->getEmptyLookupMessage(); + return getFilter().getEmptyLookupMessage(); } } void LLFolderViewModelCommon::filter() { - getFilter()->setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000)); - mFolderView->getViewModelItem()->filter(*getFilter()); + getFilter().setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000)); + mFolderView->getViewModelItem()->filter(getFilter()); } diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index acdec53602..81de15923a 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -107,6 +107,24 @@ public: virtual S32 getFirstRequiredGeneration() const = 0; }; +class LLFolderViewModelInterface +{ +public: + virtual ~LLFolderViewModelInterface() {} + virtual void requestSortAll() = 0; + + virtual void sort(class LLFolderViewFolder*) = 0; + virtual void filter() = 0; + + virtual bool contentsReady() = 0; + virtual void setFolderView(LLFolderView* folder_view) = 0; + virtual LLFolderViewFilter& getFilter() = 0; + virtual const LLFolderViewFilter& getFilter() const = 0; + virtual std::string getStatusText() = 0; + + virtual bool startDrag(std::vector& items) = 0; +}; + // This is am abstract base class that users of the folderview classes // would use to bridge the folder view with the underlying data class LLFolderViewModelItem @@ -188,15 +206,15 @@ protected: class LLFolderViewModelItemCommon : public LLFolderViewModelItem { public: - LLFolderViewModelItemCommon() + LLFolderViewModelItemCommon(LLFolderViewModelInterface& root_view_model) : mSortVersion(-1), mPassedFilter(true), mPassedFolderFilter(true), - mPrevPassedAllFilters(false), mFolderViewItem(NULL), mLastFilterGeneration(-1), mMostFilteredDescendantGeneration(-1), - mParent(NULL) + mParent(NULL), + mRootViewModel(root_view_model) { std::for_each(mChildren.begin(), mChildren.end(), DeletePointer()); } @@ -220,20 +238,55 @@ public: { mChildren.push_back(child); child->setParent(this); + dirtyFilter(); + requestSort(); } virtual void removeChild(LLFolderViewModelItem* child) { mChildren.remove(child); child->setParent(NULL); + dirtyFilter(); + } + + void setPassedFilter(bool passed, bool passed_folder, S32 filter_generation) + { + mPassedFilter = passed; + mPassedFolderFilter = passed_folder; + mLastFilterGeneration = filter_generation; + } + + virtual bool potentiallyVisible() + { + return passedFilter() // we've passed the filter + || getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration() // or we don't know yet + || descendantsPassedFilter(); } + virtual bool passedFilter(S32 filter_generation = -1) + { + if (filter_generation < 0) + filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); + + bool passed_folder_filter = mPassedFolderFilter && mLastFilterGeneration >= filter_generation; + bool passed_filter = mPassedFilter && mLastFilterGeneration >= filter_generation; + return passed_folder_filter + && (descendantsPassedFilter(filter_generation) + || passed_filter); + } + + virtual bool descendantsPassedFilter(S32 filter_generation = -1) + { + if (filter_generation < 0) filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration(); + return mMostFilteredDescendantGeneration >= filter_generation; + } + + protected: virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; } S32 mSortVersion; bool mPassedFilter; bool mPassedFolderFilter; - bool mPrevPassedAllFilters; S32 mLastFilterGeneration; S32 mMostFilteredDescendantGeneration; @@ -242,28 +295,13 @@ protected: typedef std::list child_list_t; child_list_t mChildren; LLFolderViewModelItem* mParent; + LLFolderViewModelInterface& mRootViewModel; void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;} LLFolderViewItem* mFolderViewItem; }; -class LLFolderViewModelInterface -{ -public: - virtual ~LLFolderViewModelInterface() {} - virtual void requestSortAll() = 0; - - virtual void sort(class LLFolderViewFolder*) = 0; - virtual void filter() = 0; - - virtual bool contentsReady() = 0; - virtual void setFolderView(LLFolderView* folder_view) = 0; - virtual LLFolderViewFilter* getFilter() = 0; - virtual const LLFolderViewFilter* getFilter() const = 0; - virtual std::string getStatusText() = 0; - virtual bool startDrag(std::vector& items) = 0; -}; class LLFolderViewModelCommon : public LLFolderViewModelInterface { @@ -307,8 +345,8 @@ public: virtual const SortType& getSorter() const { return mSorter; } virtual void setSorter(const SortType& sorter) { mSorter = sorter; requestSortAll(); } - virtual FilterType* getFilter() { return &mFilter; } - virtual const FilterType* getFilter() const { return &mFilter; } + virtual FilterType& getFilter() { return mFilter; } + virtual const FilterType& getFilter() const { return mFilter; } virtual void setFilter(const FilterType& filter) { mFilter = filter; } // TODO RN: remove this and put all filtering logic in view model diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp index e4ed97892e..18ed36d0f3 100644 --- a/indra/newview/llfloateroutbox.cpp +++ b/indra/newview/llfloateroutbox.cpp @@ -251,7 +251,7 @@ void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId) // Set the sort order newest to oldest mOutboxInventoryPanel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME); - mOutboxInventoryPanel->getFilter()->markDefault(); + mOutboxInventoryPanel->getFilter().markDefault(); fetchOutboxContents(); diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 13ca73917b..21218850a6 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -109,7 +109,12 @@ bool LLFolderViewModelInventory::contentsReady() void LLFolderViewModelItemInventory::requestSort() { LLFolderViewModelItemCommon::requestSort(); - if (mRootViewModel.getSorter().isByDate()) + LLFolderViewFolder* folderp = dynamic_cast(mFolderViewItem); + if (folderp) + { + folderp->requestArrange(); + } + if (static_cast(mRootViewModel).getSorter().isByDate()) { // sort by date potentially affects parent folders which use a date // derived from newest item in them @@ -120,35 +125,9 @@ void LLFolderViewModelItemInventory::requestSort() } } -bool LLFolderViewModelItemInventory::potentiallyVisible() -{ - return passedFilter() // we've passed the filter - || getLastFilterGeneration() < mRootViewModel.getFilter()->getFirstSuccessGeneration() // or we don't know yet - || descendantsPassedFilter(); -} - -bool LLFolderViewModelItemInventory::passedFilter(S32 filter_generation) -{ - if (filter_generation < 0) - filter_generation = mRootViewModel.getFilter()->getFirstSuccessGeneration(); - - return mPassedFolderFilter - && (descendantsPassedFilter(filter_generation) - || (mLastFilterGeneration >= filter_generation - && mPassedFilter)); -} - -bool LLFolderViewModelItemInventory::descendantsPassedFilter(S32 filter_generation) -{ - if (filter_generation < 0) filter_generation = mRootViewModel.getFilter()->getFirstSuccessGeneration(); - return mMostFilteredDescendantGeneration >= filter_generation; -} - void LLFolderViewModelItemInventory::setPassedFilter(bool passed, bool passed_folder, S32 filter_generation) { - mPassedFilter = passed; - mPassedFolderFilter = passed_folder; - mLastFilterGeneration = filter_generation; + LLFolderViewModelItemCommon::setPassedFilter(passed, passed_folder, filter_generation); bool passed_filter_before = mPrevPassedAllFilters; mPrevPassedAllFilters = passedFilter(filter_generation); @@ -324,3 +303,8 @@ bool LLInventorySort::operator()(const LLFolderViewModelItemInventory* const& a, } } +LLFolderViewModelItemInventory::LLFolderViewModelItemInventory( class LLFolderViewModelInventory& root_view_model ) + : LLFolderViewModelItemCommon(root_view_model), + mPrevPassedAllFilters(false) +{ +} diff --git a/indra/newview/llfolderviewmodelinventory.h b/indra/newview/llfolderviewmodelinventory.h index ab67c93897..5b0ad5e46e 100644 --- a/indra/newview/llfolderviewmodelinventory.h +++ b/indra/newview/llfolderviewmodelinventory.h @@ -37,9 +37,7 @@ class LLFolderViewModelItemInventory : public LLFolderViewModelItemCommon { public: - LLFolderViewModelItemInventory(class LLFolderViewModelInventory& root_view_model) - : mRootViewModel(root_view_model) - {} + LLFolderViewModelItemInventory(class LLFolderViewModelInventory& root_view_model); virtual const LLUUID& getUUID() const = 0; virtual time_t getCreationDate() const = 0; // UTC seconds virtual void setCreationDate(time_t creation_date_utc) = 0; @@ -55,9 +53,6 @@ public: virtual EInventorySortGroup getSortGroup() const = 0; virtual LLInventoryObject* getInventoryObject() const = 0; virtual void requestSort(); - virtual bool potentiallyVisible(); - virtual bool passedFilter(S32 filter_generation = -1); - virtual bool descendantsPassedFilter(S32 filter_generation = -1); virtual void setPassedFilter(bool filtered, bool filtered_folder, S32 filter_generation); virtual void filter( LLFolderViewFilter& filter); virtual void filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter); @@ -66,25 +61,36 @@ public: virtual LLToolDragAndDrop::ESource getDragSource() const = 0; protected: - class LLFolderViewModelInventory& mRootViewModel; + bool mPrevPassedAllFilters; }; class LLInventorySort { public: - LLInventorySort(U32 order = 0) - : mSortOrder(order), - mByDate(false), - mSystemToTop(false), - mFoldersByName(false) + struct Params : public LLInitParam::Block { - mByDate = (order & LLInventoryFilter::SO_DATE); - mSystemToTop = (order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); - mFoldersByName = (order & LLInventoryFilter::SO_FOLDERS_BY_NAME); + Optional order; + + Params() + : order("order", 0) + {} + }; + + LLInventorySort(S32 order = 0) + { + fromParams(Params().order(order)); } bool isByDate() const { return mByDate; } U32 getSortOrder() const { return mSortOrder; } + void toParams(Params& p) { p.order(mSortOrder);} + void fromParams(Params& p) + { + mSortOrder = p.order; + mByDate = (mSortOrder & LLInventoryFilter::SO_DATE); + mSystemToTop = (mSortOrder & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); + mFoldersByName = (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME); + } bool operator()(const LLFolderViewModelItemInventory* const& a, const LLFolderViewModelItemInventory* const& b) const; private: diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 14616ca7ab..43c4ce1278 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -900,7 +900,7 @@ LLInventoryModel* LLInvFVBridge::getInventoryModel() const LLInventoryFilter* LLInvFVBridge::getInventoryFilter() const { LLInventoryPanel* panel = mInventoryPanel.get(); - return panel ? panel->getFilter() : NULL; + return panel ? &(panel->getFilter()) : NULL; } BOOL LLInvFVBridge::isItemInTrash() const diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index b4be927b09..7993dd04c5 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -69,7 +69,6 @@ LLInventoryFilter::LLInventoryFilter(const Params& p) mFilterModified(FILTER_NONE), mEmptyLookupMessage("InventoryNoMatchingItems"), mFilterOps(p.filter_ops), - mOrder(p.sort_order), mFilterSubString(p.substring), mCurrentGeneration(0), mFirstRequiredGeneration(0), @@ -703,15 +702,6 @@ void LLInventoryFilter::setShowFolderState(EFolderShow state) } } -void LLInventoryFilter::setSortOrder(U32 order) -{ - if (mOrder != order) - { - mOrder = order; - setModified(); - } -} - void LLInventoryFilter::markDefault() { mDefaultFilterOps = mFilterOps; @@ -944,7 +934,6 @@ LLInventoryFilter& LLInventoryFilter::operator=( const LLInventoryFilter& othe setShowFolderState(other.getShowFolderState()); setFilterPermissions(other.getFilterPermissions()); setFilterSubString(other.getFilterSubString()); - setSortOrder(other.getSortOrder()); setDateRangeLastLogoff(other.isSinceLogoff()); return *this; } @@ -961,7 +950,6 @@ void LLInventoryFilter::toParams(Params& params) const params.filter_ops.show_folder_state = getShowFolderState(); params.filter_ops.permissions = getFilterPermissions(); params.substring = getFilterSubString(); - params.sort_order = getSortOrder(); params.since_logoff = isSinceLogoff(); } @@ -980,7 +968,6 @@ void LLInventoryFilter::fromParams(const Params& params) setShowFolderState(params.filter_ops.show_folder_state); setFilterPermissions(params.filter_ops.permissions); setFilterSubString(params.substring); - setSortOrder(params.sort_order); setDateRangeLastLogoff(params.since_logoff); } @@ -1030,10 +1017,6 @@ LLInventoryFilter::EFolderShow LLInventoryFilter::getShowFolderState() const { return mFilterOps.mShowFolderState; } -U32 LLInventoryFilter::getSortOrder() const -{ - return mOrder; -} void LLInventoryFilter::setFilterCount(S32 count) { diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index af245a9c3b..b560730873 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -74,8 +74,8 @@ public: { struct DateRange : public LLInitParam::Block { - Optional min_date; - Optional max_date; + Optional min_date, + max_date; DateRange() : min_date("min_date", time_min()), @@ -115,18 +115,18 @@ public: FilterOps(const Params& = Params()); U32 mFilterTypes; - - U64 mFilterObjectTypes; // For _OBJECT - U64 mFilterWearableTypes; - U64 mFilterCategoryTypes; // For _CATEGORY + U64 mFilterObjectTypes, // For _OBJECT + mFilterWearableTypes, + mFilterLinks, + mFilterCategoryTypes; // For _CATEGORY LLUUID mFilterUUID; // for UUID - time_t mMinDate; - time_t mMaxDate; + time_t mMinDate, + mMaxDate; U32 mHoursAgo; + EFolderShow mShowFolderState; PermissionMask mPermissions; - U64 mFilterLinks; }; struct Params : public LLInitParam::Block @@ -134,14 +134,12 @@ public: Optional name; Optional filter_ops; Optional substring; - Optional sort_order; Optional since_logoff; Params() : name("name"), filter_ops(""), substring("substring"), - sort_order("sort_order"), since_logoff("since_logoff") {} }; @@ -203,9 +201,6 @@ public: void setShowFolderState( EFolderShow state); EFolderShow getShowFolderState() const; - void setSortOrder(U32 order); - U32 getSortOrder() const; - void setEmptyLookupMessage(const std::string& message); std::string getEmptyLookupMessage() const; @@ -261,8 +256,6 @@ private: bool checkAgainstFilterLinks(const class LLFolderViewModelItemInventory* listener) const; bool checkAgainstClipboard(const LLUUID& object_id) const; - U32 mOrder; - FilterOps mFilterOps; FilterOps mDefaultFilterOps; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index e9b128e836..1b3391f7ee 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -239,13 +239,13 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params) } // hide inbox - getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); - getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); // set the filter for the empty folder if the debug setting is on if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders")) { - getFilter()->setFilterEmptySystemFolders(); + getFilter().setFilterEmptySystemFolders(); } // keep track of the clipboard state so that we avoid filtering too much @@ -285,18 +285,18 @@ void LLInventoryPanel::draw() if (mClipboardState != LLClipboard::instance().getGeneration()) { mClipboardState = LLClipboard::instance().getGeneration(); - getFilter()->setModified(LLClipboard::instance().isCutMode() ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); + getFilter().setModified(LLClipboard::instance().isCutMode() ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); } LLPanel::draw(); } -const LLInventoryFilter* LLInventoryPanel::getFilter() const +const LLInventoryFilter& LLInventoryPanel::getFilter() const { return getFolderViewModel()->getFilter(); } -LLInventoryFilter* LLInventoryPanel::getFilter() +LLInventoryFilter& LLInventoryPanel::getFilter() { return getFolderViewModel()->getFilter(); } @@ -304,50 +304,49 @@ LLInventoryFilter* LLInventoryPanel::getFilter() void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type) { if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT) - getFilter()->setFilterObjectTypes(types); + getFilter().setFilterObjectTypes(types); if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY) - getFilter()->setFilterCategoryTypes(types); + getFilter().setFilterCategoryTypes(types); } U32 LLInventoryPanel::getFilterObjectTypes() const { - return getFilter()->getFilterObjectTypes(); + return getFilter().getFilterObjectTypes(); } U32 LLInventoryPanel::getFilterPermMask() const { - return getFilter()->getFilterPermissions(); + return getFilter().getFilterPermissions(); } void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) { - getFilter()->setFilterPermissions(filter_perm_mask); + getFilter().setFilterPermissions(filter_perm_mask); } void LLInventoryPanel::setFilterWearableTypes(U64 types) { - getFilter()->setFilterWearableTypes(types); + getFilter().setFilterWearableTypes(types); } void LLInventoryPanel::setFilterSubString(const std::string& string) { - getFilter()->setFilterSubString(string); + getFilter().setFilterSubString(string); } const std::string LLInventoryPanel::getFilterSubString() { - return getFilter()->getFilterSubString(); + return getFilter().getFilterSubString(); } void LLInventoryPanel::setSortOrder(U32 order) { - LLInventorySort sorter(order); - getFilter()->setSortOrder(order); + LLInventorySort sorter(order); if (order != getFolderViewModel()->getSorter().getSortOrder()) { - getFolderViewModel()->setSorter(LLInventorySort(order)); + getFolderViewModel()->setSorter(sorter); // try to keep selection onscreen, even if it wasn't to start with mFolderRoot->scrollToShowSelection(); } @@ -360,27 +359,27 @@ U32 LLInventoryPanel::getSortOrder() const void LLInventoryPanel::setSinceLogoff(BOOL sl) { - getFilter()->setDateRangeLastLogoff(sl); + getFilter().setDateRangeLastLogoff(sl); } void LLInventoryPanel::setHoursAgo(U32 hours) { - getFilter()->setHoursAgo(hours); + getFilter().setHoursAgo(hours); } void LLInventoryPanel::setFilterLinks(U64 filter_links) { - getFilter()->setFilterLinks(filter_links); + getFilter().setFilterLinks(filter_links); } void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) { - getFilter()->setShowFolderState(show); + getFilter().setShowFolderState(show); } LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() { - return getFilter()->getShowFolderState(); + return getFilter().getShowFolderState(); } void LLInventoryPanel::modelChanged(U32 mask) @@ -473,7 +472,7 @@ void LLInventoryPanel::modelChanged(U32 mask) { if (view_folder) { - view_folder->requestSort(); + view_folder->getViewModelItem()->requestSort(); } } @@ -1088,7 +1087,7 @@ bool LLInventoryPanel::attachObject(const LLSD& userdata) BOOL LLInventoryPanel::getSinceLogoff() { - return getFilter()->isSinceLogoff(); + return getFilter().isSinceLogoff(); } // DEBUG ONLY @@ -1214,12 +1213,12 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type) { - getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type)); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type)); } BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const { - return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type)); + return !(getFilter().getFilterCategoryTypes() & (1ULL << folder_type)); } void LLInventoryPanel::addItemID( const LLUUID& id, LLFolderViewItem* itemp ) @@ -1321,7 +1320,7 @@ public: { LLInventoryPanel::initFromParams(p); // turn on inbox for recent items - getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX)); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX)); } protected: diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index b66b53f642..e9bfcb0ccf 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -120,6 +120,12 @@ public: {} }; + struct InventoryState : public LLInitParam::Block + { + Mandatory filter; + Mandatory sort; + }; + //-------------------------------------------------------------------- // Initialization //-------------------------------------------------------------------- @@ -155,8 +161,8 @@ public: void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); void setSelectCallback(const boost::function& items, BOOL user_action)>& cb); void clearSelection(); - LLInventoryFilter* getFilter(); - const LLInventoryFilter* getFilter() const; + LLInventoryFilter& getFilter(); + const LLInventoryFilter& getFilter() const; void setFilterTypes(U64 filter, LLInventoryFilter::EFilterType = LLInventoryFilter::FILTERTYPE_OBJECT); U32 getFilterObjectTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 1a4f3708ac..9225ea3d53 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -247,10 +247,7 @@ void LLLandmarksPanel::onSearchEdit(const std::string& string) LLPlacesInventoryPanel* inventory_list = dynamic_cast(tab->getAccordionView()); if (NULL == inventory_list) continue; - if (inventory_list->getFilter()) - { - filter_list(inventory_list, string); - } + filter_list(inventory_list, string); } if (sFilterSubString != string) @@ -365,9 +362,6 @@ void LLLandmarksPanel::onSelectorButtonClicked() void LLLandmarksPanel::updateShowFolderState() { - if (!mLandmarksInventoryPanel->getFilter()) - return; - bool show_all_folders = mLandmarksInventoryPanel->getFilterSubString().empty(); if (show_all_folders) { @@ -547,7 +541,7 @@ void LLLandmarksPanel::initFavoritesInventoryPanel() mFavoritesInventoryPanel = getChild("favorites_list"); initLandmarksPanel(mFavoritesInventoryPanel); - mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems"); + mFavoritesInventoryPanel->getFilter().setEmptyLookupMessage("FavoritesNoMatchingItems"); initAccordion("tab_favorites", mFavoritesInventoryPanel, true); } @@ -558,12 +552,7 @@ void LLLandmarksPanel::initLandmarksInventoryPanel() initLandmarksPanel(mLandmarksInventoryPanel); - // Check if mLandmarksInventoryPanel is properly initialized and has a Filter created. - // In case of a dummy widget getFilter() will return NULL. - if (mLandmarksInventoryPanel->getFilter()) - { - mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); - } + mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); // subscribe to have auto-rename functionality while creating New Folder mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2)); @@ -599,12 +588,7 @@ void LLLandmarksPanel::initLibraryInventoryPanel() void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list) { - // In case of a dummy widget further we have no Folder View widget and no Filter, - // so further initialization leads to crash. - if (!inventory_list->getFilter()) - return; - - inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems"); + inventory_list->getFilter().setEmptyLookupMessage("PlacesNoMatchingItems"); inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2)); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index fea27b37d3..e1aa70cc4a 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -89,9 +89,9 @@ public: static void selectNoTypes(void* user_data); private: LLPanelMainInventory* mPanelMainInventory; - LLSpinCtrl* mSpinSinceDays; - LLSpinCtrl* mSpinSinceHours; - LLInventoryFilter* mFilter; + LLSpinCtrl* mSpinSinceDays; + LLSpinCtrl* mSpinSinceHours; + LLInventoryFilter* mFilter; }; ///---------------------------------------------------------------------------- @@ -131,7 +131,7 @@ BOOL LLPanelMainInventory::postBuild() mFilterTabs = getChild("inventory filter tabs"); mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); - //panel->getFilter()->markDefault(); + //panel->getFilter().markDefault(); // Set up the default inv. panel/filter settings. mActivePanel = getChild("All Items"); @@ -139,7 +139,7 @@ BOOL LLPanelMainInventory::postBuild() { // "All Items" is the previous only view, so it gets the InventorySortOrder mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); - mActivePanel->getFilter()->markDefault(); + mActivePanel->getFilter().markDefault(); mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); mResortActivePanel = true; @@ -150,7 +150,7 @@ BOOL LLPanelMainInventory::postBuild() recent_items_panel->setSinceLogoff(TRUE); recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - recent_items_panel->getFilter()->markDefault(); + recent_items_panel->getFilter().markDefault(); recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); } @@ -169,14 +169,14 @@ BOOL LLPanelMainInventory::postBuild() // Note that the "All Items" settings do not persist. if(recent_items_panel) { - if(savedFilterState.has(recent_items_panel->getFilter()->getName())) + if(savedFilterState.has(recent_items_panel->getFilter().getName())) { LLSD recent_items = savedFilterState.get( - recent_items_panel->getFilter()->getName()); + recent_items_panel->getFilter().getName()); LLInventoryFilter::Params p; LLParamSDParser parser; parser.readSD(recent_items, p); - recent_items_panel->getFilter()->fromParams(p); + recent_items_panel->getFilter().fromParams(p); } } @@ -213,29 +213,29 @@ LLPanelMainInventory::~LLPanelMainInventory( void ) LLInventoryPanel* all_items_panel = getChild("All Items"); if (all_items_panel) { - LLInventoryFilter* filter = all_items_panel->getFilter(); - if (filter) + LLSD filterState; + LLInventoryPanel::InventoryState p; + all_items_panel->getFilter().toParams(p.filter); + all_items_panel->getRootViewModel().getSorter().toParams(p.sort); + if (p.validateBlock(false)) { - LLSD filterState; - LLInventoryFilter::Params p; - filter->toParams(p); - if (p.validateBlock(false)) - { - LLParamSDParser().writeSD(filterState, p); - filterRoot[filter->getName()] = filterState; - } + LLParamSDParser().writeSD(filterState, p); + filterRoot[all_items_panel->getName()] = filterState; } } - LLInventoryFilter* filter = findChild("Recent Items")->getFilter(); - if (filter) + LLInventoryPanel* panel = findChild("Recent Items"); + if (panel) { LLSD filterState; - LLInventoryFilter::Params p; - filter->toParams(p); - LLParamSDParser parser; - parser.writeSD(filterState, p); - filterRoot[filter->getName()] = filterState; + LLInventoryPanel::InventoryState p; + panel->getFilter().toParams(p.filter); + panel->getRootViewModel().getSorter().toParams(p.sort); + if (p.validateBlock(false)) + { + LLParamSDParser().writeSD(filterState, p); + filterRoot[panel->getName()] = filterState; + } } std::ostringstream filterSaveName; @@ -321,7 +321,7 @@ void LLPanelMainInventory::doCreate(const LLSD& userdata) void LLPanelMainInventory::resetFilters() { LLFloaterInventoryFinder *finder = getFinder(); - getActivePanel()->getFilter()->resetDefault(); + getActivePanel()->getFilter().resetDefault(); if (finder) { finder->updateElementsFromFilter(); @@ -426,7 +426,7 @@ void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) } // save current folder open state if no filter currently applied - if (!mActivePanel->getFilter()->isNotDefault()) + if (!mActivePanel->getFilter().isNotDefault()) { mSavedFolderState->setApply(FALSE); mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); @@ -488,13 +488,13 @@ void LLPanelMainInventory::onFilterSelected() } setFilterSubString(mFilterSubString); - LLInventoryFilter* filter = mActivePanel->getFilter(); + LLInventoryFilter& filter = mActivePanel->getFilter(); LLFloaterInventoryFinder *finder = getFinder(); if (finder) { - finder->changeFilter(filter); + finder->changeFilter(&filter); } - if (filter->isActive()) + if (filter.isActive()) { // If our filter is active we may be the first thing requiring a fetch so we better start it here. LLInventoryModelBackgroundFetch::instance().start(); @@ -607,7 +607,7 @@ void LLPanelMainInventory::onFocusReceived() void LLPanelMainInventory::setFilterTextFromFilter() { - mFilterText = mActivePanel->getFilter()->getFilterText(); + mFilterText = mActivePanel->getFilter().getFilterText(); } void LLPanelMainInventory::toggleFindOptions() @@ -657,7 +657,7 @@ LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view) : LLFloater(LLSD()), mPanelMainInventory(inventory_view), - mFilter(inventory_view->getPanel()->getFilter()) + mFilter(&inventory_view->getPanel()->getFilter()) { buildFromFile("floater_inventory_view_finder.xml"); updateElementsFromFilter(); @@ -1082,14 +1082,14 @@ void LLPanelMainInventory::onCustomAction(const LLSD& userdata) const LLUUID& item_id = static_cast(current_item->getViewModelItem())->getUUID(); const std::string &item_name = current_item->getViewModelItem()->getName(); mFilterSubString = item_name; - LLInventoryFilter *filter = mActivePanel->getFilter(); - filter->setFilterSubString(item_name); + LLInventoryFilter &filter = mActivePanel->getFilter(); + filter.setFilterSubString(item_name); mFilterEditor->setText(item_name); mFilterEditor->setFocus(TRUE); - filter->setFilterUUID(item_id); - filter->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - filter->setFilterLinks(LLInventoryFilter::FILTERLINK_ONLY_LINKS); + filter.setFilterUUID(item_id); + filter.setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + filter.setFilterLinks(LLInventoryFilter::FILTERLINK_ONLY_LINKS); } } diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp index 3547156197..ea0521e3a7 100644 --- a/indra/newview/llpanelmarketplaceinbox.cpp +++ b/indra/newview/llpanelmarketplaceinbox.cpp @@ -95,13 +95,13 @@ LLInventoryPanel * LLPanelMarketplaceInbox::setupInventoryPanel() // Set the sort order newest to oldest mInventoryPanel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_DATE); - mInventoryPanel->getFilter()->markDefault(); + mInventoryPanel->getFilter().markDefault(); // Set selection callback for proper update of inventory status buttons mInventoryPanel->setSelectCallback(boost::bind(&LLPanelMarketplaceInbox::onSelectionChange, this)); // Set up the note to display when the inbox is empty - mInventoryPanel->getFilter()->setEmptyLookupMessage("InventoryInboxNoItems"); + mInventoryPanel->getFilter().setEmptyLookupMessage("InventoryInboxNoItems"); // Hide the placeholder text inbox_inventory_placeholder->setVisible(FALSE); diff --git a/indra/newview/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index 8ad3929999..0d3fbe66d7 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -182,9 +182,9 @@ LLInboxFolderViewItem::LLInboxFolderViewItem(const Params& p) #endif } -BOOL LLInboxFolderViewItem::addToFolder(LLFolderViewFolder* folder) +void LLInboxFolderViewItem::addToFolder(LLFolderViewFolder* folder) { - BOOL retval = LLFolderViewItem::addToFolder(folder); + LLFolderViewItem::addToFolder(folder); #if SUPPORTING_FRESH_ITEM_COUNT // Compute freshness if our parent is the root folder for the inbox @@ -193,8 +193,6 @@ BOOL LLInboxFolderViewItem::addToFolder(LLFolderViewFolder* folder) computeFreshness(); } #endif - - return retval; } BOOL LLInboxFolderViewItem::handleDoubleClick(S32 x, S32 y, MASK mask) diff --git a/indra/newview/llpanelmarketplaceinboxinventory.h b/indra/newview/llpanelmarketplaceinboxinventory.h index d8b8a2fe63..098969aca6 100644 --- a/indra/newview/llpanelmarketplaceinboxinventory.h +++ b/indra/newview/llpanelmarketplaceinboxinventory.h @@ -95,7 +95,7 @@ public: LLInboxFolderViewItem(const Params& p); - BOOL addToFolder(LLFolderViewFolder* folder); + void addToFolder(LLFolderViewFolder* folder); BOOL handleDoubleClick(S32 x, S32 y, MASK mask); void draw(); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 4f2c515bde..82956beb3d 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1567,11 +1567,8 @@ void LLPanelObjectInventory::reset() mFolders = LLUICtrlFactory::create(p); // this ensures that we never say "searching..." or "no items found" //TODO RN: make this happen by manipulating filter object directly - LLInventoryFilter* inventoryFilter = dynamic_cast(mFolders->getFolderViewModel()->getFilter()); - if(inventoryFilter) - { - inventoryFilter->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); - } + LLInventoryFilter& inventoryFilter = dynamic_cast(mFolders->getFolderViewModel()->getFilter()); + inventoryFilter.setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 2d3f144588..65f0290060 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -455,7 +455,7 @@ BOOL LLFloaterTexturePicker::postBuild() // Commented out to scroll to currently selected texture. See EXT-5403. // // store this filter as the default one - // mInventoryPanel->getRootFolder()->getFilter()->markDefault(); + // mInventoryPanel->getRootFolder()->getFilter().markDefault(); // Commented out to stop opening all folders with textures // mInventoryPanel->openDefaultFolderForType(LLFolderType::FT_TEXTURE); @@ -638,10 +638,10 @@ void LLFloaterTexturePicker::draw() LLFolderView* folder_view = mInventoryPanel->getRootFolder(); if (!folder_view) return; - LLFolderViewFilter* filter = static_cast(folder_view->getFolderViewModel())->getFilter(); + LLFolderViewFilter& filter = static_cast(folder_view->getFolderViewModel())->getFilter(); - bool is_filter_active = folder_view->getViewModelItem()->getLastFilterGeneration() < filter->getCurrentGeneration() && - filter->isNotDefault(); + bool is_filter_active = folder_view->getViewModelItem()->getLastFilterGeneration() < filter.getCurrentGeneration() && + filter.isNotDefault(); // After inventory panel filter is applied we have to update // constraint rect for the selected item because of folder view @@ -1012,7 +1012,7 @@ void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) else if (mInventoryPanel->getFilterSubString().empty()) { // first letter in search term, save existing folder open state - if (!mInventoryPanel->getFilter()->isNotDefault()) + if (!mInventoryPanel->getFilter().isNotDefault()) { mSavedFolderState.setApply(FALSE); mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); -- cgit v1.3 From c6d981a8430f02a5a78afbeece9afeb7b2f108c8 Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Wed, 1 Aug 2012 17:29:34 -0700 Subject: CHUI-214: Scrolling to offscreen content now works. Problem was due to the icon height/width not being computed before scrolling to the new item. There was also a problem with the computation that determines if the item being scrolled to is within the visible region. --- indra/llui/llfolderview.cpp | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index e09026fc33..bc286c1868 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1704,9 +1704,6 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr if(item) { LLRect local_rect = item->getLocalRect(); - LLRect item_scrolled_rect; // item position relative to display area of scroller - LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); - S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); S32 label_height = getLabelFontForStyle(mLabelStyle)->getLineHeight(); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder @@ -1815,6 +1812,20 @@ void LLFolderView::update() mNeedsAutoSelect = FALSE; } + BOOL is_visible = isInVisibleChain(); + + //Puts folders/items in proper positions + if ( is_visible ) + { + sanitizeSelection(); + if( needsArrange() ) + { + S32 height = 0; + S32 width = 0; + S32 total_height = arrange( &width, &height ); + notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); + } + } // during filtering process, try to pin selected item's location on screen // this will happen when searching your inventory and when new items arrive @@ -1826,18 +1837,26 @@ void LLFolderView::update() // lets pin it! mPinningSelectedItem = TRUE; - LLRect visible_content_rect = (mScrollContainer ? mScrollContainer->getVisibleContentRect() : LLRect()); + //Computes visible area + const LLRect visible_content_rect = (mScrollContainer ? mScrollContainer->getVisibleContentRect() : LLRect()); LLFolderViewItem* selected_item = mSelectedItems.back(); + //Computes location of selected content, content outside visible area will be scrolled to using below code LLRect item_rect; selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); - // if item is visible in scrolled region - if (visible_content_rect.overlaps(item_rect)) + + //Computes intersected region of the selected content and visible area + LLRect overlap_rect(item_rect); + overlap_rect.intersectWith(visible_content_rect); + + //Don't scroll when the selected content exists within the visible area + if (overlap_rect.getHeight() >= selected_item->getItemHeight()) { // then attempt to keep it in same place on screen mScrollConstraintRect = item_rect; mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); } + //Scroll because the selected content is outside the visible area else { // otherwise we just want it onscreen somewhere @@ -1868,20 +1887,6 @@ void LLFolderView::update() constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); } - BOOL is_visible = isInVisibleChain(); - - if ( is_visible ) - { - sanitizeSelection(); - if( needsArrange() ) - { - S32 height = 0; - S32 width = 0; - S32 total_height = arrange( &width, &height ); - notifyParent(LLSD().with("action", "size_changes").with("height", total_height)); - } - } - if (mSelectedItems.size() && mNeedsScroll) { scrollToShowItem(mSelectedItems.back(), constraint_rect); -- cgit v1.3 From 88e81f99293c992944787289699bf885568bf327 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Wed, 1 Aug 2012 20:07:42 -0700 Subject: CHUI-223 WIP Selecting to cut an inventory item causes all open inventory windows to refresh avoid moving selection when cutting --- indra/llui/llfolderview.cpp | 57 +++++++++++++++++++------------------- indra/llui/llfolderviewitem.cpp | 6 ++++ indra/llui/llfolderviewitem.h | 1 + indra/newview/llinventorypanel.cpp | 17 ++++++------ 4 files changed, 44 insertions(+), 37 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index d714d4623d..5d98dc9663 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -717,33 +717,6 @@ void LLFolderView::closeRenamer( void ) } } -bool isDescendantOfASelectedItem(LLFolderViewItem* item, const std::vector& selectedItems) -{ - LLFolderViewItem* item_parent = dynamic_cast(item->getParent()); - - if (item_parent) - { - for(std::vector::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(parent->getParent()); - } - } - } - - return false; -} - void LLFolderView::removeSelectedItems() { if(getVisible() && getEnabled()) @@ -815,7 +788,7 @@ void LLFolderView::removeSelectedItems() if (!new_selection) { new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && (new_selection->isSelected() || isDescendantOfASelectedItem(new_selection, items))) + while (new_selection && (new_selection->isInSelection())) { new_selection = new_selection->getPreviousOpenNode(FALSE); } @@ -1060,16 +1033,42 @@ void LLFolderView::cut() if(getVisible() && getEnabled() && (count > 0)) { LLFolderViewModelItem* listener = NULL; + + LLFolderViewItem* last_item = *mSelectedItems.rbegin();; + LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); + while(new_selection && new_selection->isSelected()) + { + new_selection = new_selection->getNextOpenNode(FALSE); + } + if (!new_selection) + { + new_selection = last_item->getPreviousOpenNode(FALSE); + while (new_selection && (new_selection->isInSelection())) + { + new_selection = new_selection->getPreviousOpenNode(FALSE); + } + } + selected_items_t::iterator item_it; for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) { - listener = (*item_it)->getViewModelItem(); + LLFolderViewItem* item_to_cut = *item_it; + listener = item_to_cut->getViewModelItem(); if(listener) { listener->cutToClipboard(); listener->removeItem(); } } + + if (new_selection) + { + setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); + } + else + { + setSelection(NULL, mParentPanel->hasFocus()); + } } mSearchString.clear(); } diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 5238bfd7e4..68b442dd9a 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -810,6 +810,12 @@ LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) return getRoot()->getFolderViewModel(); } +bool LLFolderViewItem::isInSelection() const +{ + return mIsSelected || (mParentFolder && mParentFolder->isInSelection()); +} + + ///---------------------------------------------------------------------------- /// Class LLFolderViewFolder diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 4eda02f13f..e75059bc01 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -164,6 +164,7 @@ public: virtual void destroyView(); BOOL isSelected() const { return mIsSelected; } + bool isInSelection() const; void setUnselected() { mIsSelected = FALSE; } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 1b3391f7ee..9403ccdabe 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -281,13 +281,6 @@ void LLInventoryPanel::draw() // Select the desired item (in case it wasn't loaded when the selection was requested) updateSelection(); - // Nudge the filter if the clipboard state changed - if (mClipboardState != LLClipboard::instance().getGeneration()) - { - mClipboardState = LLClipboard::instance().getGeneration(); - getFilter().setModified(LLClipboard::instance().isCutMode() ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); - } - LLPanel::draw(); } @@ -586,7 +579,6 @@ LLUUID LLInventoryPanel::getRootFolderID() } } - // static void LLInventoryPanel::onIdle(void *userdata) { @@ -608,6 +600,15 @@ void LLInventoryPanel::onIdle(void *userdata) void LLInventoryPanel::idle(void* user_data) { LLInventoryPanel* panel = (LLInventoryPanel*)user_data; + // Nudge the filter if the clipboard state changed + if (panel->mClipboardState != LLClipboard::instance().getGeneration()) + { + panel->mClipboardState = LLClipboard::instance().getGeneration(); + panel->getFilter().setModified(LLClipboard::instance().isCutMode() + ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE + : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); + } + panel->mFolderRoot->update(); // while dragging, update selection rendering to reflect single/multi drag status if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) -- cgit v1.3 From faac868b682360df1bf461624667cc6e0bbdd8c6 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 2 Aug 2012 20:45:52 -0700 Subject: CHUI-223 FIX Selecting to cut an inventory item causes all open inventory windows to refresh --- indra/llui/llfolderview.cpp | 95 +++++++++++++------------------------- indra/llui/llfolderview.h | 10 ++-- indra/newview/llinventorypanel.cpp | 22 +++++++-- 3 files changed, 56 insertions(+), 71 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 5d98dc9663..fb09f7f0aa 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -749,28 +749,18 @@ void LLFolderView::removeSelectedItems() // iterate through the new container. count = items.size(); LLUUID new_selection_id; + LLFolderViewItem* item_to_select = getNextUnselectedItem(); + if(count == 1) { LLFolderViewItem* item_to_delete = items[0]; LLFolderViewFolder* parent = item_to_delete->getParentFolder(); - LLFolderViewItem* new_selection = item_to_delete->getNextOpenNode(FALSE); - if (!new_selection) - { - new_selection = item_to_delete->getPreviousOpenNode(FALSE); - } if(parent) { if (item_to_delete->remove()) { // change selection on successful delete - if (new_selection) - { - getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); - } - else - { - getRoot()->setSelection(NULL, mParentPanel->hasFocus()); - } + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel->hasFocus()); } } arrangeAll(); @@ -779,28 +769,8 @@ void LLFolderView::removeSelectedItems() { LLDynamicArray listeners; LLFolderViewModelItem* listener; - LLFolderViewItem* last_item = items[count - 1]; - LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); - while(new_selection && new_selection->isSelected()) - { - new_selection = new_selection->getNextOpenNode(FALSE); - } - if (!new_selection) - { - new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && (new_selection->isInSelection())) - { - new_selection = new_selection->getPreviousOpenNode(FALSE); - } - } - if (new_selection) - { - getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); - } - else - { - getRoot()->setSelection(NULL, mParentPanel->hasFocus()); - } + + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel->hasFocus()); for(S32 i = 0; i < count; ++i) { @@ -1032,28 +1002,13 @@ void LLFolderView::cut() S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { - LLFolderViewModelItem* listener = NULL; - - LLFolderViewItem* last_item = *mSelectedItems.rbegin();; - LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); - while(new_selection && new_selection->isSelected()) - { - new_selection = new_selection->getNextOpenNode(FALSE); - } - if (!new_selection) - { - new_selection = last_item->getPreviousOpenNode(FALSE); - while (new_selection && (new_selection->isInSelection())) - { - new_selection = new_selection->getPreviousOpenNode(FALSE); - } - } + LLFolderViewItem* item_to_select = getNextUnselectedItem(); selected_items_t::iterator item_it; for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) { LLFolderViewItem* item_to_cut = *item_it; - listener = item_to_cut->getViewModelItem(); + LLFolderViewModelItem* listener = item_to_cut->getViewModelItem(); if(listener) { listener->cutToClipboard(); @@ -1061,14 +1016,7 @@ void LLFolderView::cut() } } - if (new_selection) - { - setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); - } - else - { - setSelection(NULL, mParentPanel->hasFocus()); - } + setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel->hasFocus()); } mSearchString.clear(); } @@ -1274,12 +1222,12 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) if (next->isSelected()) { // shrink selection - getRoot()->changeSelection(last_selected, FALSE); + changeSelection(last_selected, FALSE); } else if (last_selected->getParentFolder() == next->getParentFolder()) { // grow selection - getRoot()->changeSelection(next, TRUE); + changeSelection(next, TRUE); } } } @@ -1338,12 +1286,12 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) if (prev->isSelected()) { // shrink selection - getRoot()->changeSelection(last_selected, FALSE); + changeSelection(last_selected, FALSE); } else if (last_selected->getParentFolder() == prev->getParentFolder()) { // grow selection - getRoot()->changeSelection(prev, TRUE); + changeSelection(prev, TRUE); } } } @@ -2083,3 +2031,22 @@ S32 LLFolderView::getItemHeight() } return 0; } + +LLFolderViewItem* LLFolderView::getNextUnselectedItem() +{ + LLFolderViewItem* last_item = *mSelectedItems.rbegin(); + LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); + while(new_selection && new_selection->isSelected()) + { + new_selection = new_selection->getNextOpenNode(FALSE); + } + if (!new_selection) + { + new_selection = last_item->getPreviousOpenNode(FALSE); + while (new_selection && (new_selection->isInSelection())) + { + new_selection = new_selection->getPreviousOpenNode(FALSE); + } + } + return new_selection; +} diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 05beff9bd8..81b0f087e8 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -172,17 +172,19 @@ public: BOOL isOpen() const { return TRUE; } // root folder always open // Copy & paste - virtual void copy(); virtual BOOL canCopy() const; + virtual void copy(); - virtual void cut(); virtual BOOL canCut() const; + virtual void cut(); - virtual void paste(); virtual BOOL canPaste() const; + virtual void paste(); - virtual void doDelete(); virtual BOOL canDoDelete() const; + virtual void doDelete(); + + LLFolderViewItem* getNextUnselectedItem(); // Public rename functionality - can only start the process void startRenamingSelectedItem( void ); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 9403ccdabe..b02d08955f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -604,9 +604,25 @@ void LLInventoryPanel::idle(void* user_data) if (panel->mClipboardState != LLClipboard::instance().getGeneration()) { panel->mClipboardState = LLClipboard::instance().getGeneration(); - panel->getFilter().setModified(LLClipboard::instance().isCutMode() - ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE - : LLInventoryFilter::FILTER_LESS_RESTRICTIVE); + if (LLClipboard::instance().isCutMode()) + { + LLDynamicArray objects; + LLClipboard::instance().pasteFromClipboard(objects); + + for (LLDynamicArray::iterator it = objects.begin(), end_it = objects.end(); + it != end_it; + ++it) + { + LLFolderViewItem* item = panel->getItemByID(*it); + if (item) + { + item->getViewModelItem()->dirtyFilter(); + } + } + /*panel->getFilter().setModified(LLClipboard::instance().isCutMode() + ? LLInventoryFilter::FILTER_MORE_RESTRICTIVE + : LLInventoryFilter::FILTER_LESS_RESTRICTIVE);*/ + } } panel->mFolderRoot->update(); -- cgit v1.3 From 2b026a806617532a0b2c8a796e9530273c110cf4 Mon Sep 17 00:00:00 2001 From: Todd Stinson Date: Wed, 8 Aug 2012 18:17:01 -0700 Subject: CHUI-272: BUGFIX Correcting the inventory filtering so that a large number of items in the inventory are completely processed before the filter's modified flag is cleared. --- indra/llui/llfolderview.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index fedb8bc014..1a8ab63388 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1715,11 +1715,17 @@ void LLFolderView::update() { mNeedsAutoSelect = TRUE; } - getFolderViewModel()->getFilter().clearModified(); // filter to determine visibility before arranging filter(getFolderViewModel()->getFilter()); + // Clear the modified setting on the filter only if the filter count is non-zero after running the filter process + // Note: if the filter count is zero, then the filter most likely halted before completing the entire set of items + if (getFolderViewModel()->getFilter().isModified() && (getFolderViewModel()->getFilter().getFilterCount() > 0)) + { + getFolderViewModel()->getFilter().clearModified(); + } + // automatically show matching items, and select first one if we had a selection if (mNeedsAutoSelect) { -- cgit v1.3 From 381c13d0e51c3c054fdf2afeff8a8bcb6fc7aa11 Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Thu, 20 Sep 2012 16:12:28 -0700 Subject: CHUI-283: Refactor of how the layout is determined for LLFolderViewItem. Changed constant members that defined the layout to non-const member varaibles, which are populated using a .xml file. --- indra/llui/llfolderview.cpp | 20 ++++--- indra/llui/llfolderviewitem.cpp | 63 ++++++++++++++++------ indra/llui/llfolderviewitem.h | 29 ++++++---- indra/newview/llconversationview.cpp | 24 ++++----- indra/newview/llconversationview.h | 2 + .../default/xui/en/panel_outbox_inventory.xml | 9 +++- .../en/widgets/conversation_view_participant.xml | 11 +++- .../xui/en/widgets/conversation_view_session.xml | 9 +++- .../default/xui/en/widgets/folder_view_item.xml | 8 ++- .../xui/en/widgets/inbox_folder_view_folder.xml | 8 ++- 10 files changed, 130 insertions(+), 53 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 11004fe390..ab4efea4dd 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -56,11 +56,7 @@ const S32 RENAME_WIDTH_PAD = 4; const S32 RENAME_HEIGHT_PAD = 1; const S32 AUTO_OPEN_STACK_DEPTH = 16; -const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH - + LLFolderViewItem::ICON_PAD - + LLFolderViewItem::ARROW_SIZE - + LLFolderViewItem::TEXT_PAD - + /*first few characters*/ 40; + const S32 MINIMUM_RENAMER_WIDTH = 80; // *TODO: move in params in xml if necessary. Requires modification of LLFolderView & LLInventoryPanel Params. @@ -211,10 +207,11 @@ LLFolderView::LLFolderView(const Params& p) // Textbox LLTextBox::Params text_p; LLFontGL* font = getLabelFontForStyle(mLabelStyle); - LLRect new_r = LLRect(rect.mLeft + ICON_PAD, - rect.mTop - TEXT_PAD, + //mIconPad, mTextPad are set in folder_view_item.xml + LLRect new_r = LLRect(rect.mLeft + mIconPad, + rect.mTop - mTextPad, rect.mRight, - rect.mTop - TEXT_PAD - font->getLineHeight()); + rect.mTop - mTextPad - font->getLineHeight()); text_p.rect(new_r); text_p.name(std::string(p.name)); text_p.font(font); @@ -1652,12 +1649,13 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); 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(); + S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + item->getIconPad()) : local_rect.getHeight(); // get portion of item that we want to see... LLRect item_local_rect = LLRect(item->getIndentation(), local_rect.getHeight(), - llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()), + //+32 is supposed to include few first characters + llmin(item->getLabelXPos() + 32, local_rect.getWidth()), llmax(0, local_rect.getHeight() - max_height_to_show)); LLRect item_doc_rect; @@ -1874,7 +1872,7 @@ void LLFolderView::updateRenamerPosition() if(mRenameItem) { // See also LLFolderViewItem::draw() - S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mRenameItem->getIndentation(); + S32 x = mRenameItem->getLabelXPos(); S32 y = mRenameItem->getRect().getHeight() - mRenameItem->getItemHeight() - RENAME_HEIGHT_PAD; mRenameItem->localPointToScreen( x, y, &x, &y ); screenPointToLocal( x, y, &x, &y ); diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 171af92e73..9632612752 100755 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -90,7 +90,14 @@ LLFolderViewItem::Params::Params() item_height("item_height"), item_top_pad("item_top_pad"), creation_date(), - allow_open("allow_open", true) + allow_open("allow_open", true), + left_pad("left_pad", 0), + icon_pad("icon_pad", 0), + icon_width("icon_width", 0), + text_pad("text_pad", 0), + text_pad_right("text_pad_right", 0), + arrow_size("arrow_size", 0), + max_folder_item_overlap("max_folder_item_overlap", 0) {} // Default constructor @@ -98,7 +105,7 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) : LLView(p), mLabelWidth(0), mLabelWidthDirty(false), - mLabelPaddingRight(DEFAULT_TEXT_PADDING_RIGHT), + mLabelPaddingRight(DEFAULT_LABEL_PADDING_RIGHT), mParentFolder( NULL ), mIsSelected( FALSE ), mIsCurSelection( FALSE ), @@ -114,7 +121,14 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p) mRoot(p.root), mViewModelItem(p.listener), mIsMouseOverTitle(false), - mAllowOpen(p.allow_open) + mAllowOpen(p.allow_open), + mLeftPad(p.left_pad), + mIconPad(p.icon_pad), + mIconWidth(p.icon_width), + mTextPad(p.text_pad), + mTextPadRight(p.text_pad_right), + mArrowSize(p.arrow_size), + mMaxFolderItemOverlap(p.max_folder_item_overlap) { if (mViewModelItem) { @@ -291,11 +305,11 @@ S32 LLFolderViewItem::arrange( S32* width, S32* height ) : 0; if (mLabelWidthDirty) { - mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight; + mLabelWidth = getLabelXPos() + getLabelFontForStyle(mLabelStyle)->getWidth(mLabel) + getLabelFontForStyle(mLabelStyle)->getWidth(mLabelSuffix) + mLabelPaddingRight; mLabelWidthDirty = false; } - *width = llmax(*width, mLabelWidth + mIndentation); + *width = llmax(*width, mLabelWidth); // determine if we need to use ellipses to avoid horizontal scroll. EXT-719 bool use_ellipses = getRoot()->getUseEllipses(); @@ -313,6 +327,21 @@ S32 LLFolderViewItem::getItemHeight() return mItemHeight; } +S32 LLFolderViewItem::getLabelXPos() +{ + return getIndentation() + mArrowSize + mTextPad + mIconWidth + mIconPad; +} + +S32 LLFolderViewItem::getIconPad() +{ + return mIconPad; +} + +S32 LLFolderViewItem::getTextPad() +{ + return mTextPad; +} + // *TODO: This can be optimized a lot by simply recording that it is // selected in the appropriate places, and assuming that set selection // means 'deselect' for a leaf item. Do this optimization after @@ -734,8 +763,8 @@ void LLFolderViewItem::draw() { LLUIImage* arrow_image = default_params.folder_arrow_image; gl_draw_scaled_rotated_image( - mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD - TOP_PAD, - ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, arrow_image->getImage(), sFgColor); + mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, + mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), sFgColor); } @@ -744,7 +773,7 @@ void LLFolderViewItem::draw() //--------------------------------------------------------------------------------// // Draw open icon // - const S32 icon_x = mIndentation + ARROW_SIZE + TEXT_PAD; + const S32 icon_x = mIndentation + mArrowSize + mTextPad; if (!mIconOpen.isNull() && (llabs(mControlLabelRotation) > 80)) // For open folders { mIconOpen->draw(icon_x, getRect().getHeight() - mIconOpen->getHeight() - TOP_PAD + 1); @@ -769,8 +798,8 @@ void LLFolderViewItem::draw() std::string::size_type filter_string_length = mViewModelItem->hasFilterStringMatch() ? mViewModelItem->getFilterStringSize() : 0; F32 right_x = 0; - F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; - F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); + F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; + F32 text_left = (F32)getLabelXPos(); std::string combined_string = mLabel + mLabelSuffix; if (filter_string_length > 0) @@ -804,11 +833,15 @@ void LLFolderViewItem::draw() if (filter_string_length > 0) { F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mViewModelItem->getFilterStringOffset()); - F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; + F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x, FALSE ); } + + //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to + //be distorted...oddly. I initially added this in but didn't need it after all. So removing to prevent unnecessary bug. + //LLView::draw(); } const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const @@ -984,7 +1017,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) folders_t::iterator fit = iter++; // number of pixels that bottom of folder label is from top of parent folder if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + > llround(mCurHeight) + mMaxFolderItemOverlap) { // hide if beyond current folder height (*fit)->setVisible(FALSE); @@ -997,7 +1030,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) items_t::iterator iit = iter++; // number of pixels that bottom of item label is from top of parent folder if (getRect().getHeight() - (*iit)->getRect().mBottom - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + > llround(mCurHeight) + mMaxFolderItemOverlap) { (*iit)->setVisible(FALSE); } @@ -1757,7 +1790,7 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) } if( !handled ) { - if(mIndentation < x && x < mIndentation + ARROW_SIZE + TEXT_PAD) + if(mIndentation < x && x < mIndentation + mArrowSize + mTextPad) { toggleOpen(); handled = TRUE; @@ -1781,7 +1814,7 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) } if( !handled ) { - if(mIndentation < x && x < mIndentation + ARROW_SIZE + TEXT_PAD) + if(mIndentation < x && x < mIndentation + mArrowSize + mTextPad) { // don't select when user double-clicks plus sign // so as not to contradict single-click behavior diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index 5c97407bc1..b7e0091aca 100755 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -60,18 +60,18 @@ public: Optional creation_date; Optional allow_open; + Optional left_pad, + icon_pad, + icon_width, + text_pad, + text_pad_right, + arrow_size, + max_folder_item_overlap; Params(); }; - // layout constants - static const S32 LEFT_PAD = 5, - ICON_PAD = 2, - ICON_WIDTH = 16, - TEXT_PAD = 1, - DEFAULT_TEXT_PADDING_RIGHT = 4, - ARROW_SIZE = 12, - MAX_FOLDER_ITEM_OVERLAP = 2; - + + static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4; // animation parameters static const F32 FOLDER_CLOSE_TIME_CONSTANT, FOLDER_OPEN_TIME_CONSTANT; @@ -99,6 +99,14 @@ protected: S32 mDragStartX, mDragStartY; + S32 mLeftPad, + mIconPad, + mIconWidth, + mTextPad, + mTextPadRight, + mArrowSize, + mMaxFolderItemOverlap; + F32 mControlLabelRotation; LLFolderView* mRoot; bool mHasVisibleChildren, @@ -136,6 +144,9 @@ public: // makes sure that this view and it's children are the right size. virtual S32 arrange( S32* width, S32* height ); virtual S32 getItemHeight(); + virtual S32 getLabelXPos(); + S32 getIconPad(); + S32 getTextPad(); // If 'selection' is 'this' then note that otherwise ignore. // Returns TRUE if this item ends up being selected. diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 721abd5892..6860415377 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -109,8 +109,8 @@ void LLConversationViewSession::draw() { LLUIImage* arrow_image = default_params.folder_arrow_image; gl_draw_scaled_rotated_image( - mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD - TOP_PAD, - ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, arrow_image->getImage(), sFgColor); + mIndentation, getRect().getHeight() - mArrowSize - mTextPad - TOP_PAD, + mArrowSize, mArrowSize, mControlLabelRotation, arrow_image->getImage(), sFgColor); } @@ -227,7 +227,7 @@ void LLConversationViewSession::draw() // virtual S32 LLConversationViewSession::arrange(S32* width, S32* height) { - LLRect rect(getIndentation() + ARROW_SIZE, + LLRect rect(getIndentation() + mArrowSize, getLocalRect().mTop, getLocalRect().mRight, getLocalRect().mTop - getItemHeight()); @@ -336,7 +336,7 @@ void LLConversationViewParticipant::initFromParams(const LLConversationViewParti applyXUILayout(avatar_icon_params, this); LLAvatarIconCtrl * avatarIcon = LLUICtrlFactory::create(avatar_icon_params); addChild(avatarIcon); - + LLButton::Params info_button_params(params.info_button()); applyXUILayout(info_button_params, this); LLButton * button = LLUICtrlFactory::create(info_button_params); @@ -381,16 +381,11 @@ void LLConversationViewParticipant::draw() const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE); const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled - const LLFolderViewItem::Params& default_params = LLUICtrlFactory::getDefaultParams(); - const S32 TOP_PAD = default_params.item_top_pad; - const LLFontGL* font = getLabelFontForStyle(mLabelStyle); F32 right_x = 0; - //TEXT_PAD, TOP_PAD, ICON_PAD and mIndentation are temporary values and will non-const eventually since they don't - //apply to every single layout - F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD; - F32 text_left = (F32)(mAvatarIcon->getRect().mRight + ICON_PAD + mIndentation); + F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad; + F32 text_left = (F32)getLabelXPos(); LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor; drawHighlight(show_context, filled, sHighlightBgColor, sFocusOutlineColor, sMouseOverColor); @@ -448,6 +443,11 @@ void LLConversationViewParticipant::onMouseLeave(S32 x, S32 y, MASK mask) LLFolderViewItem::onMouseEnter(x, y, mask); } +S32 LLConversationViewParticipant::getLabelXPos() +{ + return mAvatarIcon->getRect().mRight + mIconPad; +} + // static void LLConversationViewParticipant::initChildrenWidths(LLConversationViewParticipant* self) { @@ -465,7 +465,7 @@ void LLConversationViewParticipant::initChildrenWidths(LLConversationViewPartici void LLConversationViewParticipant::computeLabelRightPadding() { - mLabelPaddingRight = DEFAULT_TEXT_PADDING_RIGHT; + mLabelPaddingRight = DEFAULT_LABEL_PADDING_RIGHT; LLView* control; S32 ctrl_width; diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 075ad09d5b..5bc4678b7b 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -101,6 +101,8 @@ public: void onMouseEnter(S32 x, S32 y, MASK mask); void onMouseLeave(S32 x, S32 y, MASK mask); + /*virtual*/ S32 getLabelXPos(); + protected: friend class LLUICtrlFactory; LLConversationViewParticipant( const Params& p ); diff --git a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml index 203febbf18..c80e5b168a 100644 --- a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml @@ -20,6 +20,13 @@ folder_indentation="8" item_height="20" item_top_pad="4" - selection_image="Rounded_Square"/> + selection_image="Rounded_Square" + left_pad="5" + icon_pad="2" + icon_width="16" + text_pad="1" + text_pad_right="4" + arrow_size="12" + max_folder_item_overlap="2"/> diff --git a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml index 7ddcfe3b03..a28d6e0209 100755 --- a/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml +++ b/indra/newview/skins/default/xui/en/widgets/conversation_view_participant.xml @@ -1,12 +1,19 @@ + follows="left|top|right" + left_pad="5" + icon_pad="2" + icon_width="16" + text_pad="1" + text_pad_right="4" + arrow_size="12" + max_folder_item_overlap="2"/> diff --git a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml index 6fa74f403d..bbd53ccb12 100644 --- a/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml +++ b/indra/newview/skins/default/xui/en/widgets/folder_view_item.xml @@ -7,4 +7,10 @@ selection_image="Rounded_Square" mouse_opaque="true" follows="left|top|right" - /> + left_pad="5" + icon_pad="2" + icon_width="16" + text_pad="1" + text_pad_right="4" + arrow_size="12" + max_folder_item_overlap="2"/> diff --git a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml index 77d8024cb2..590a4730a9 100644 --- a/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml +++ b/indra/newview/skins/default/xui/en/widgets/inbox_folder_view_folder.xml @@ -5,7 +5,13 @@ item_height="20" item_top_pad="4" selection_image="Rounded_Square" - > + left_pad="5" + icon_pad="2" + icon_width="16" + text_pad="1" + text_pad_right="4" + arrow_size="12" + max_folder_item_overlap="2"> Date: Thu, 20 Sep 2012 16:33:21 -0700 Subject: CHUI-283: within LLFolderView::scrollToShowItem(), adjusted the calculation that scrolls to the selected item. My prior commit changed this calculation and adjusted it in this commit to preserve prior behavior. --- indra/llui/llfolderview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index ab4efea4dd..ce1bc5914c 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1654,8 +1654,8 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr // get portion of item that we want to see... LLRect item_local_rect = LLRect(item->getIndentation(), local_rect.getHeight(), - //+32 is supposed to include few first characters - llmin(item->getLabelXPos() + 32, local_rect.getWidth()), + //+40 is supposed to include few first characters + llmin(item->getLabelXPos() - item->getIndentation() + 40, local_rect.getWidth()), llmax(0, local_rect.getHeight() - max_height_to_show)); LLRect item_doc_rect; -- cgit v1.3 From 11a148415e810706f2a1835b6b717a0a062d458f Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Fri, 28 Sep 2012 18:22:05 -0700 Subject: CHUI-102: Now the participants and one-on-one conversations have right-click-menus. These menus are functional as well, but 'chat history' does not yet work. --- indra/llui/llfolderview.cpp | 5 +- indra/llui/llfolderview.h | 2 + indra/newview/llconversationmodel.cpp | 44 +++++ indra/newview/llconversationmodel.h | 18 +- indra/newview/llimfloater.h | 1 + indra/newview/llimfloatercontainer.cpp | 192 ++++++++++++++++++++- indra/newview/llimfloatercontainer.h | 5 + indra/newview/llinventorypanel.cpp | 1 + .../skins/default/xui/en/menu_conversation.xml | 109 ++++++++++++ 9 files changed, 372 insertions(+), 5 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/menu_conversation.xml (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index ce1bc5914c..327a064228 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -138,7 +138,8 @@ LLFolderView::Params::Params() use_label_suffix("use_label_suffix"), allow_multiselect("allow_multiselect", true), show_empty_message("show_empty_message", true), - use_ellipses("use_ellipses", false) + use_ellipses("use_ellipses", false), + options_menu("options_menu", "") { folder_indentation = -4; } @@ -228,7 +229,7 @@ LLFolderView::LLFolderView(const Params& p) // make the popup menu available - LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); if (!menu) { menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 81b0f087e8..260275269d 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -94,6 +94,8 @@ public: use_ellipses, show_item_link_overlays; Mandatory view_model; + Optional options_menu; + Params(); }; diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 7d0ffa0788..1c4c7aefae 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -28,6 +28,7 @@ #include "llviewerprecompiledheaders.h" #include "llconversationmodel.h" +#include "llmenugl.h" // // Conversation items : common behaviors @@ -84,6 +85,24 @@ void LLConversationItem::showProperties(void) { } +void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items) +{ + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); +} + // // LLConversationItemSession // @@ -191,6 +210,22 @@ void LLConversationItemSession::setDistance(const LLUUID& participant_id, F64 di } } +void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLConversationItemParticipant::buildContextMenu()" << llendl; + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + if(this->getType() == CONV_SESSION_1_ON_1) + { + items.push_back(std::string("close_conversation")); + items.push_back(std::string("separator_disconnect_from_voice")); + buildParticipantMenuOptions(items); + } + + hide_context_entries(menu, items, disabled_items); +} + // The time of activity of a session is the time of the most recent activity, session and participants included const bool LLConversationItemSession::getTime(F64& time) const { @@ -249,6 +284,15 @@ LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, mConvType = CONV_PARTICIPANT; } +void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + menuentry_vec_t items; + menuentry_vec_t disabled_items; + + buildParticipantMenuOptions(items); + hide_context_entries(menu, items, disabled_items); +} + void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_name) { mName = av_name.mUsername; diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 30f94d51ae..43fa66e8e2 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -41,6 +41,8 @@ class LLConversationItemParticipant; typedef std::map conversations_items_map; typedef std::map conversations_widgets_map; +typedef std::vector menuentry_vec_t; + // Conversation items: we hold a list of those and create an LLFolderViewItem widget for each // that we tuck into the mConversationsListPanel. class LLConversationItem : public LLFolderViewModelItemCommon @@ -124,6 +126,8 @@ public: void resetRefresh() { mNeedsRefresh = false; } bool needsRefresh() { return mNeedsRefresh; } + void buildParticipantMenuOptions(menuentry_vec_t& items); + protected: std::string mName; // Name of the session or the participant LLUUID mUUID; // UUID of the session or the participant @@ -155,6 +159,7 @@ public: bool isLoaded() { return mIsLoaded; } + void buildContextMenu(LLMenuGL& menu, U32 flags); virtual const bool getTime(F64& time) const; void dumpDebugData(); @@ -178,7 +183,8 @@ public: void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; } void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; } void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; } - + + void buildContextMenu(LLMenuGL& menu, U32 flags); void onAvatarNameCache(const LLAvatarName& av_name); virtual const bool getDistanceToAgent(F64& dist) const { dist = mDistToAgent; return (dist >= 0.0); } @@ -273,4 +279,14 @@ public: private: }; +// Utility function to hide all entries except those in the list +// Can be called multiple times on the same menu (e.g. if multiple items +// are selected). If "append" is false, then only common enabled items +// are set as enabled. + +//(defined in inventorybridge.cpp) +void hide_context_entries(LLMenuGL& menu, + const menuentry_vec_t &entries_to_show, + const menuentry_vec_t &disabled_entries); + #endif // LL_LLCONVERSATIONMODEL_H diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index e4a67a3d56..fbaf009939 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -128,6 +128,7 @@ public: static void onIMChicletCreated(const LLUUID& session_id); bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; } + LLUUID getOtherParticipantUUID() {return mOtherParticipantUUID;} static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb); static floater_showed_signal_t sIMFloaterShowedSignal; diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 14d40d4685..b4802c71f9 100755 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -58,8 +58,12 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) mConversationsRoot(NULL), mInitialized(false) { + mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2)); mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLIMFloaterContainer::onCustomAction, this, _2)); - mEnableCallbackRegistrar.add("IMFloaterContainer.Check", boost::bind(&LLIMFloaterContainer::isActionChecked, this, _2)); + + mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLIMFloaterContainer::checkContextMenuItem, this, _2)); + mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLIMFloaterContainer::enableContextMenuItem, this, _2)); + mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLIMFloaterContainer::doToSelected, this, _2)); // Firstly add our self to IMSession observers, so we catch session events LLIMMgr::getInstance()->addSessionObserver(this); @@ -133,7 +137,9 @@ BOOL LLIMFloaterContainer::postBuild() p.listener = base_item; p.view_model = &mConversationViewModel; p.root = NULL; + p.options_menu = "menu_conversation.xml"; mConversationsRoot = LLUICtrlFactory::create(p); + mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); // a scroller for folder view LLRect scroller_view_rect = mConversationsListPanel->getRect(); @@ -341,7 +347,7 @@ void LLIMFloaterContainer::idle(void* user_data) { self->setNearbyDistances(); } - + self->mConversationsRoot->update(); } @@ -661,6 +667,188 @@ void LLIMFloaterContainer::setSortOrder(const LLConversationSort& order) gSavedSettings.setU32("ConversationSortOrder", (U32)order); } +void LLIMFloaterContainer::getSelectedUUIDs(uuid_vec_t& selected_uuids) +{ + const std::set selectedItems = mConversationsRoot->getSelectionList(); + + std::set::const_iterator it = selectedItems.begin(); + const std::set::const_iterator it_end = selectedItems.end(); + LLConversationItem * conversationItem; + + for (; it != it_end; ++it) + { + conversationItem = static_cast((*it)->getViewModelItem()); + selected_uuids.push_back(conversationItem->getUUID()); + } +} +void LLIMFloaterContainer::doToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + uuid_vec_t selected_uuids; + LLUUID currentSelectedUUID; + LLIMFloater * conversation; + + getSelectedUUIDs(selected_uuids); + conversation = LLIMFloater::findInstance(selected_uuids.front()); + + if(conversation && + static_cast(mConversationsRoot->getCurSelectedItem()->getViewModelItem())->getType() == LLConversationItem::CONV_SESSION_1_ON_1) + { + currentSelectedUUID = conversation->getOtherParticipantUUID(); + } + else + { + currentSelectedUUID = selected_uuids.front(); + } + + //Close the selected conversation + if(conversation && "close_conversation" == command) + { + LLFloater::onClickClose(conversation); + } + else if ("view_profile" == command) + { + LLAvatarActions::showProfile(currentSelectedUUID); + } + else if("im" == command) + { + LLAvatarActions::startIM(currentSelectedUUID); + } + else if("offer_teleport" == command) + { + LLAvatarActions::offerTeleport(selected_uuids); + } + else if("voice_call" == command) + { + LLAvatarActions::startCall(currentSelectedUUID); + } + else if("add_friend" == command) + { + LLAvatarActions::requestFriendshipDialog(currentSelectedUUID); + } + else if("remove_friend" == command) + { + LLAvatarActions::removeFriendDialog(currentSelectedUUID); + } + else if("invite_to_group" == command) + { + LLAvatarActions::inviteToGroup(currentSelectedUUID); + } + else if("map" == command) + { + LLAvatarActions::showOnMap(currentSelectedUUID); + } + else if("share" == command) + { + LLAvatarActions::share(currentSelectedUUID); + } + else if("pay" == command) + { + LLAvatarActions::pay(currentSelectedUUID); + } + else if("block_unblock" == command) + { + LLAvatarActions::toggleBlock(currentSelectedUUID); + } +} + +bool LLIMFloaterContainer::enableContextMenuItem(const LLSD& userdata) +{ + std::string item = userdata.asString(); + uuid_vec_t mUUIDs; + getSelectedUUIDs(mUUIDs); + + // Note: can_block and can_delete is used only for one person selected menu + // so we don't need to go over all uuids. + + if (item == std::string("can_block")) + { + const LLUUID& id = mUUIDs.front(); + return LLAvatarActions::canBlock(id); + } + else if (item == std::string("can_add")) + { + // We can add friends if: + // - there are selected people + // - and there are no friends among selection yet. + + //EXT-7389 - disable for more than 1 + if(mUUIDs.size() > 1) + { + return false; + } + + bool result = (mUUIDs.size() > 0); + + uuid_vec_t::const_iterator + id = mUUIDs.begin(), + uuids_end = mUUIDs.end(); + + for (;id != uuids_end; ++id) + { + if ( LLAvatarActions::isFriend(*id) ) + { + result = false; + break; + } + } + + return result; + } + else if (item == std::string("can_delete")) + { + // We can remove friends if: + // - there are selected people + // - and there are only friends among selection. + + bool result = (mUUIDs.size() > 0); + + uuid_vec_t::const_iterator + id = mUUIDs.begin(), + uuids_end = mUUIDs.end(); + + for (;id != uuids_end; ++id) + { + if ( !LLAvatarActions::isFriend(*id) ) + { + result = false; + break; + } + } + + return result; + } + else if (item == std::string("can_call")) + { + return LLAvatarActions::canCall(); + } + else if (item == std::string("can_show_on_map")) + { + const LLUUID& id = mUUIDs.front(); + + return (LLAvatarTracker::instance().isBuddyOnline(id) && is_agent_mappable(id)) + || gAgent.isGodlike(); + } + else if(item == std::string("can_offer_teleport")) + { + return LLAvatarActions::canOfferTeleport(mUUIDs); + } + return false; +} + +bool LLIMFloaterContainer::checkContextMenuItem(const LLSD& userdata) +{ + std::string item = userdata.asString(); + const LLUUID& id = static_cast(mConversationsRoot->getCurSelectedItem()->getViewModelItem())->getUUID(); + + if (item == std::string("is_blocked")) + { + return LLAvatarActions::isBlocked(id); + } + + return false; +} + void LLIMFloaterContainer::repositioningWidgets() { if (!mInitialized) diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index e8d185297c..cc2d0ce6ab 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -111,6 +111,11 @@ private: void setSortOrderParticipants(const LLConversationFilter::ESortOrderType order); void setSortOrder(const LLConversationSort& order); + void getSelectedUUIDs(uuid_vec_t& selected_uuids); + void doToSelected(const LLSD& userdata); + bool checkContextMenuItem(const LLSD& userdata); + bool enableContextMenuItem(const LLSD& userdata); + LLButton* mExpandCollapseBtn; LLLayoutPanel* mMessagesPane; LLLayoutPanel* mConversationsPane; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 2a84616ddf..6e692adf2a 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -172,6 +172,7 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id ) p.show_empty_message = mShowEmptyMessage; p.show_item_link_overlays = mShowItemLinkOverlays; p.root = NULL; + p.options_menu = "menu_inventory.xml"; return LLUICtrlFactory::create(p); } diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml new file mode 100644 index 0000000000..94399be61c --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_conversation.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.3 From 8e1a9e2813da6b9d5c17795b375098fb6a386ee1 Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Mon, 1 Oct 2012 13:54:53 -0700 Subject: CHUI-102: Cleaned up code after code review. --- indra/llui/llfolderview.cpp | 4 ++++ indra/llui/llfolderview.h | 2 +- indra/newview/llconversationmodel.cpp | 1 - indra/newview/llconversationmodel.h | 1 + indra/newview/llimfloater.h | 2 +- indra/newview/llimfloatercontainer.cpp | 9 ++++++++- 6 files changed, 15 insertions(+), 4 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 327a064228..9a4a90206b 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1531,14 +1531,18 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) && menu ) { if (mCallbackRegistrar) + { mCallbackRegistrar->pushScope(); + } updateMenuOptions(menu); menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); if (mCallbackRegistrar) + { mCallbackRegistrar->popScope(); + } } else { diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 260275269d..487391a477 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -94,7 +94,7 @@ public: use_ellipses, show_item_link_overlays; Mandatory view_model; - Optional options_menu; + Mandatory options_menu; Params(); diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 1c4c7aefae..f587ef8428 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -28,7 +28,6 @@ #include "llviewerprecompiledheaders.h" #include "llconversationmodel.h" -#include "llmenugl.h" // // Conversation items : common behaviors diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 43fa66e8e2..f84fbe39f1 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -285,6 +285,7 @@ private: // are set as enabled. //(defined in inventorybridge.cpp) +//TODO: Gilbert Linden - Refactor to make this function non-global void hide_context_entries(LLMenuGL& menu, const menuentry_vec_t &entries_to_show, const menuentry_vec_t &disabled_entries); diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index fbaf009939..489e430b26 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -128,7 +128,7 @@ public: static void onIMChicletCreated(const LLUUID& session_id); bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; } - LLUUID getOtherParticipantUUID() {return mOtherParticipantUUID;} + const LLUUID& getOtherParticipantUUID() {return mOtherParticipantUUID;} static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb); static floater_showed_signal_t sIMFloaterShowedSignal; diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index b4802c71f9..58d2020801 100755 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -689,13 +689,20 @@ void LLIMFloaterContainer::doToSelected(const LLSD& userdata) LLIMFloater * conversation; getSelectedUUIDs(selected_uuids); + //Find the conversation floater associated with the selected id conversation = LLIMFloater::findInstance(selected_uuids.front()); - + + //When a one-on-one conversation exists, retrieve the participant id from the conversation floater b/c + //selected_uuids.front() does not pertain to the UUID of the person you are having the conversation with. if(conversation && + mConversationsRoot && + mConversationsRoot->getCurSelectedItem() && + mConversationsRoot->getCurSelectedItem()->getViewModelItem() && static_cast(mConversationsRoot->getCurSelectedItem()->getViewModelItem())->getType() == LLConversationItem::CONV_SESSION_1_ON_1) { currentSelectedUUID = conversation->getOtherParticipantUUID(); } + //Otherwise can get the UUID directly from selected_uuids else { currentSelectedUUID = selected_uuids.front(); -- cgit v1.3 From 89ba6b793a5a8b3e0599cd2c8db2f1b479ec0fb4 Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Fri, 19 Oct 2012 13:50:55 +0300 Subject: CHUI-418 FIXED Check the existence of mViewModelItem before calling potentiallyVisible(). --- indra/llui/llfolderview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index c1a11851e2..c8b8bcae48 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -504,7 +504,11 @@ void LLFolderView::sanitizeSelection() LLFolderViewItem* item = *item_iter; // ensure that each ancestor is open and potentially passes filtering - BOOL visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item + BOOL visible = false; + if(item->getViewModelItem()) + { + visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item + } // modify with parent open and filters states LLFolderViewFolder* parent_folder = item->getParentFolder(); // Move up through parent folders and see what's visible -- cgit v1.3 From a780eb1a92811c2531c2fc1d211e8e5dd03da103 Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Tue, 23 Oct 2012 13:20:53 +0300 Subject: CHUI-418 FIXED Check that mViewModelItem is not NULL --- indra/llui/llfolderview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index c8b8bcae48..c31a832141 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -505,7 +505,7 @@ void LLFolderView::sanitizeSelection() // ensure that each ancestor is open and potentially passes filtering BOOL visible = false; - if(item->getViewModelItem()) + if(item->getViewModelItem() != NULL) { visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item } -- cgit v1.3 From 7f2ea292e10b10958b3e00a641b50b194f131e41 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 31 Oct 2012 19:27:41 -0700 Subject: CHUI-474 : Fixed. Refresh the participants list in torn off dialog more often. --- indra/llui/llfolderview.cpp | 2 +- indra/newview/llimconversation.cpp | 40 +++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index c31a832141..a33ffc4240 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -566,7 +566,7 @@ void LLFolderView::sanitizeSelection() parent_folder; parent_folder = parent_folder->getParentFolder()) { - if (parent_folder->getViewModelItem()->potentiallyVisible()) + if (parent_folder->getViewModelItem() && parent_folder->getViewModelItem()->potentiallyVisible()) { // give initial selection to first ancestor folder that potentially passes the filter if (!new_selection) diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp index 3b6294f43b..aee6642150 100644 --- a/indra/newview/llimconversation.cpp +++ b/indra/newview/llimconversation.cpp @@ -376,7 +376,44 @@ void LLIMConversation::updateConversationViewParticipant(const LLUUID& participa void LLIMConversation::refreshConversation() { - // *TODO: check that all participant models do have a view (debug consistency check) + // Debug : Check that all participant models do have a view (debug consistency check) + /* + LLParticipantList* item = getParticipantList(); + llinfos << "Merov debug : Start consistency check" << llendl; + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); + while (current_participant_model != end_participant_model) + { + LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); + if (participant_model != NULL) + { + LLUUID uuid = participant_model->getUUID(); + LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,uuid); + if (!widget) + { + llinfos << "Merov debug : Consistency error! Couldn't find widget for " << participant_model->getName() << llendl; + } + else + { + llinfos << "Merov debug : Consistency check pass for " << participant_model->getName() << llendl; + } + } + else + { + llinfos << "Merov debug : Consistency check, skip non participant child" << llendl; + } + current_participant_model++; + } + llinfos << "Merov debug : End consistency check" << llendl; + */ + + conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); + while (widget_it != mConversationsWidgets.end()) + { + widget_it->second->refresh(); + widget_it->second->setVisible(TRUE); + ++widget_it; + } mConversationViewModel.requestSortAll(); mConversationsRoot->arrangeAll(); mConversationsRoot->update(); @@ -629,6 +666,7 @@ void LLIMConversation::onTearOffClicked() initRectControl(); LLFloater::onClickTearOff(this); updateHeaderAndToolbar(); + refreshConversation(); } // static -- cgit v1.3 From 090636f107a2d3ba3438a6690f36eac3ec257314 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 20 Dec 2012 18:36:01 -0800 Subject: CHUI-429 : Fixed! Add a flag to filter multi/single selection situations in menu building. Implement in conversation contextual menu. --- indra/llui/llfolderview.cpp | 5 +- indra/llui/llfolderview.h | 1 + indra/newview/llconversationmodel.cpp | 67 ++++++++++++---------- indra/newview/llconversationmodel.h | 2 +- indra/newview/llfloaterimcontainer.cpp | 1 - .../skins/default/xui/en/menu_conversation.xml | 7 +++ 6 files changed, 50 insertions(+), 33 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index a33ffc4240..7ae79d94fe 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1913,14 +1913,15 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu) // Successively filter out invalid options - U32 flags = FIRST_SELECTED_ITEM; + U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0); + U32 flags = multi_select_flag | FIRST_SELECTED_ITEM; for (selected_items_t::iterator item_itor = mSelectedItems.begin(); item_itor != mSelectedItems.end(); ++item_itor) { LLFolderViewItem* selected_item = (*item_itor); selected_item->buildContextMenu(*menu, flags); - flags = 0x0; + flags = multi_select_flag; } addNoOptions(menu); diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index d4a1434c73..2ee7417240 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -400,5 +400,6 @@ public: // Flags for buildContextMenu() const U32 SUPPRESS_OPEN_ITEM = 0x1; const U32 FIRST_SELECTED_ITEM = 0x2; +const U32 ITEM_IN_MULTI_SELECTION = 0x4; #endif // LL_LLFOLDERVIEW_H diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index d03ad92fbc..005439301a 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -102,35 +102,44 @@ void LLConversationItem::showProperties(void) { } -void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items) -{ - items.push_back(std::string("view_profile")); - items.push_back(std::string("im")); - items.push_back(std::string("offer_teleport")); - items.push_back(std::string("voice_call")); - items.push_back(std::string("chat_history")); - items.push_back(std::string("separator_chat_history")); - items.push_back(std::string("add_friend")); - items.push_back(std::string("remove_friend")); - items.push_back(std::string("invite_to_group")); - items.push_back(std::string("separator_invite_to_group")); - items.push_back(std::string("map")); - items.push_back(std::string("share")); - items.push_back(std::string("pay")); - items.push_back(std::string("block_unblock")); - items.push_back(std::string("MuteText")); - - if(this->getType() != CONV_SESSION_1_ON_1 && mDisplayModeratorOptions) +void LLConversationItem::buildParticipantMenuOptions(menuentry_vec_t& items, U32 flags) +{ + if (flags & ITEM_IN_MULTI_SELECTION) { - items.push_back(std::string("Moderator Options Separator")); - items.push_back(std::string("Moderator Options")); - items.push_back(std::string("AllowTextChat")); - items.push_back(std::string("moderate_voice_separator")); - items.push_back(std::string("ModerateVoiceToggleMuteSelected")); - items.push_back(std::string("ModerateVoiceMute")); - items.push_back(std::string("ModerateVoiceUnmute")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("remove_friends")); + } + else + { + items.push_back(std::string("view_profile")); + items.push_back(std::string("im")); + items.push_back(std::string("offer_teleport")); + items.push_back(std::string("voice_call")); + items.push_back(std::string("chat_history")); + items.push_back(std::string("separator_chat_history")); + items.push_back(std::string("add_friend")); + items.push_back(std::string("remove_friend")); + items.push_back(std::string("invite_to_group")); + items.push_back(std::string("separator_invite_to_group")); + items.push_back(std::string("map")); + items.push_back(std::string("share")); + items.push_back(std::string("pay")); + items.push_back(std::string("block_unblock")); + items.push_back(std::string("MuteText")); + + if ((getType() != CONV_SESSION_1_ON_1) && mDisplayModeratorOptions) + { + items.push_back(std::string("Moderator Options Separator")); + items.push_back(std::string("Moderator Options")); + items.push_back(std::string("AllowTextChat")); + items.push_back(std::string("moderate_voice_separator")); + items.push_back(std::string("ModerateVoiceToggleMuteSelected")); + items.push_back(std::string("ModerateVoiceMute")); + items.push_back(std::string("ModerateVoiceUnmute")); + } } - } // @@ -306,7 +315,7 @@ void LLConversationItemSession::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("close_conversation")); items.push_back(std::string("separator_disconnect_from_voice")); - buildParticipantMenuOptions(items); + buildParticipantMenuOptions(items, flags); } else if(this->getType() == CONV_SESSION_GROUP) { @@ -440,7 +449,7 @@ void LLConversationItemParticipant::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - buildParticipantMenuOptions(items); + buildParticipantMenuOptions(items, flags); hide_context_entries(menu, items, disabled_items); } diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 743a6ba40b..02002d8f70 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -130,7 +130,7 @@ public: void postEvent(const std::string& event_type, LLConversationItemSession* session, LLConversationItemParticipant* participant); - void buildParticipantMenuOptions(menuentry_vec_t& items); + void buildParticipantMenuOptions(menuentry_vec_t& items, U32 flags); protected: std::string mName; // Name of the session or the participant diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 92ea6dacde..2019a35faa 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1232,7 +1232,6 @@ void LLFloaterIMContainer::showConversation(const LLUUID& session_id) void LLFloaterIMContainer::clearAllFlashStates() { - llinfos << "Merov debug : clear all flash states" << llendl; conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); for (;widget_it != mConversationsWidgets.end(); ++widget_it) { diff --git a/indra/newview/skins/default/xui/en/menu_conversation.xml b/indra/newview/skins/default/xui/en/menu_conversation.xml index e0edf384d6..46c6e19fa5 100644 --- a/indra/newview/skins/default/xui/en/menu_conversation.xml +++ b/indra/newview/skins/default/xui/en/menu_conversation.xml @@ -75,6 +75,13 @@ + + + + Date: Tue, 8 Jan 2013 21:46:00 -0800 Subject: CHUI-659 : Fixed : Reimplemented open selection on hitting return the right way --- indra/llui/llfolderview.cpp | 86 -------------------------------------- indra/llui/llfolderview.h | 4 -- indra/llui/llfolderviewmodel.h | 2 +- indra/newview/llinventorypanel.cpp | 20 ++++++++- indra/newview/llinventorypanel.h | 1 + 5 files changed, 20 insertions(+), 93 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 7ae79d94fe..324142f6c3 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -275,17 +275,6 @@ BOOL LLFolderView::canFocusChildren() const void LLFolderView::addFolder( LLFolderViewFolder* folder) { LLFolderViewFolder::addFolder(folder); - - // TODO RN: enforce sort order of My Inventory followed by Library - //mFolders.remove(folder); - //if (((LLFolderViewModelItemInventory*)folder->getViewModelItem())->getUUID() == gInventory.getLibraryRootFolderID()) - //{ - // mFolders.push_back(folder); - //} - //else - //{ - // mFolders.insert(mFolders.begin(), folder); - //} } void LLFolderView::closeAllFolders() @@ -793,76 +782,6 @@ void LLFolderView::removeSelectedItems() } } -// TODO RN: abstract -// open the selected item. -void LLFolderView::openSelectedItems( void ) -{ - //TODO RN: get working again - //if(getVisible() && getEnabled()) - //{ - // if (mSelectedItems.size() == 1) - // { - // mSelectedItems.front()->openItem(); - // } - // else - // { - // LLMultiPreview* multi_previewp = new LLMultiPreview(); - // LLMultiProperties* multi_propertiesp = new LLMultiProperties(); - - // selected_items_t::iterator item_it; - // for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - // { - // // IT_{OBJECT,ATTACHMENT} creates LLProperties - // // floaters; others create LLPreviews. Put - // // each one in the right type of container. - // LLFolderViewModelItemInventory* listener = static_cast((*item_it)->getViewModelItem()); - // bool is_prop = listener && (listener->getInventoryType() == LLInventoryType::IT_OBJECT || listener->getInventoryType() == LLInventoryType::IT_ATTACHMENT); - // if (is_prop) - // LLFloater::setFloaterHost(multi_propertiesp); - // else - // LLFloater::setFloaterHost(multi_previewp); - // listener->openItem(); - // } - - // LLFloater::setFloaterHost(NULL); - // // *NOTE: LLMulti* will safely auto-delete when open'd - // // without any children. - // multi_previewp->openFloater(LLSD()); - // multi_propertiesp->openFloater(LLSD()); - // } - //} - } - -void LLFolderView::propertiesSelectedItems( void ) -{ - //TODO RN: get working again - //if(getVisible() && getEnabled()) - //{ - // if (mSelectedItems.size() == 1) - // { - // LLFolderViewItem* folder_item = mSelectedItems.front(); - // if(!folder_item) return; - // folder_item->getViewModelItem()->showProperties(); - // } - // else - // { - // LLMultiProperties* multi_propertiesp = new LLMultiProperties(); - - // LLFloater::setFloaterHost(multi_propertiesp); - - // selected_items_t::iterator item_it; - // for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - // { - // (*item_it)->getViewModelItem()->showProperties(); - // } - - // LLFloater::setFloaterHost(NULL); - // multi_propertiesp->openFloater(LLSD()); - // } - //} - } - - void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { if ((mAutoOpenItems.check() == item) || @@ -1151,11 +1070,6 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) mSearchString.clear(); handled = TRUE; } - else - { - LLFolderView::openSelectedItems(); - handled = TRUE; - } } break; diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 2ee7417240..a6e0a3b4c0 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -163,10 +163,6 @@ public: // Deletion functionality void removeSelectedItems(); - // Open the selected item - void openSelectedItems( void ); - void propertiesSelectedItems( void ); - void autoOpenItem(LLFolderViewFolder* item); void closeAutoOpenedFolders(); BOOL autoOpenTest(LLFolderViewFolder* item); diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 5837052565..1b61212c0e 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -127,7 +127,7 @@ public: virtual bool startDrag(std::vector& items) = 0; }; -// This is am abstract base class that users of the folderview classes +// This is an abstract base class that users of the folderview classes // would use to bridge the folder view with the underlying data class LLFolderViewModelItem : public LLRefCount { diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 81e7f166e1..25dc365467 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -684,8 +684,9 @@ void LLInventoryPanel::initializeViews() } else { - buildNewViews(gInventory.getRootFolderID()); - buildNewViews(gInventory.getLibraryRootFolderID()); + // Default case: always add "My Inventory" first, "Library" second + buildNewViews(gInventory.getRootFolderID()); // My Inventory + buildNewViews(gInventory.getLibraryRootFolderID()); // Library } gIdleCallbacks.addFunction(idle, this); @@ -1354,6 +1355,21 @@ void LLInventoryPanel::doToSelected(const LLSD& userdata) return; } +BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) +{ + BOOL handled = FALSE; + switch (key) + { + case KEY_RETURN: + // Open selected items if enter key hit on the inventory panel + if (mask == MASK_NONE) + { + LLInventoryAction::doToSelected(mInventory, mFolderRoot, "open"); + handled = TRUE; + } + } + return handled; +} /************************************************************************/ /* Recent Inventory Panel related class */ diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 9639086c11..6eb85fbad2 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -143,6 +143,7 @@ public: // LLView methods void draw(); + /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); BOOL handleHover(S32 x, S32 y, MASK mask); BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, -- cgit v1.3 From d0204ab367f5ceb5eab89e2273b897975acbfe5a Mon Sep 17 00:00:00 2001 From: Gilbert Gonzales Date: Wed, 23 Jan 2013 09:51:17 -0800 Subject: CHUI-687: Problem: User sees inventory offer notifications for deleted items when logging in from do not disturb mode. Resolution: If an item that is deletes has a DND notification saved, then remove that notification so that it doesn't appear onec the user exists DND mode. --- indra/llui/llfolderview.cpp | 6 +++++- indra/llui/llfolderview.h | 3 ++- .../newview/lldonotdisturbnotificationstorage.cpp | 22 +++++++++++++--------- indra/newview/lldonotdisturbnotificationstorage.h | 6 +++++- indra/newview/llfloaterimcontainer.cpp | 2 +- indra/newview/llimview.cpp | 2 +- indra/newview/llinventoryfunctions.cpp | 22 ++++++++++++++++++++++ indra/newview/llinventoryfunctions.h | 1 + 8 files changed, 50 insertions(+), 14 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 324142f6c3..7c1ca017d7 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -399,6 +399,10 @@ LLFolderViewItem* LLFolderView::getCurSelectedItem( void ) return NULL; } +LLFolderView::selected_items_t& LLFolderView::getSelectedItems( void ) +{ + return mSelectedItems; +} // Record the selected item and pass it down the hierachy. BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, @@ -752,8 +756,8 @@ void LLFolderView::removeSelectedItems() { // change selection on successful delete setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel->hasFocus()); - } } + } arrangeAll(); } else if (count > 1) diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index a6e0a3b4c0..05b2abb9d3 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -101,6 +101,7 @@ public: }; friend class LLFolderViewScrollContainer; + typedef std::deque selected_items_t; LLFolderView(const Params&); virtual ~LLFolderView( void ); @@ -138,6 +139,7 @@ public: // Get the last selected item virtual LLFolderViewItem* getCurSelectedItem( void ); + selected_items_t& getSelectedItems( void ); // Record the selected item and pass it down the hierarchy. virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, @@ -261,7 +263,6 @@ protected: protected: LLHandle mPopupMenuHandle; - typedef std::deque selected_items_t; selected_items_t mSelectedItems; BOOL mKeyboardSelection; BOOL mAllowMultiSelect; diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index 824ff67972..abceb5c10d 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -43,7 +43,8 @@ #include "lluuid.h" static const F32 DND_TIMER = 3.0; -const std::string toastName = "IMToast"; +const char * LLDoNotDisturbNotificationStorage::toastName = "IMToast"; +const char * LLDoNotDisturbNotificationStorage::offerName = "UserGiveItem"; LLDoNotDisturbNotificationStorageTimer::LLDoNotDisturbNotificationStorageTimer() : LLEventTimer(DND_TIMER) { @@ -72,6 +73,8 @@ LLDoNotDisturbNotificationStorage::LLDoNotDisturbNotificationStorage() , LLNotificationStorage(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "dnd_notifications.xml")) , mDirty(false) { + nameToPayloadParameterMap[toastName] = "SESSION_ID"; + nameToPayloadParameterMap[offerName] = "object_id"; } LLDoNotDisturbNotificationStorage::~LLDoNotDisturbNotificationStorage() @@ -234,15 +237,16 @@ LLNotificationChannelPtr LLDoNotDisturbNotificationStorage::getCommunicationChan return channelPtr; } -void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& session_id) +void LLDoNotDisturbNotificationStorage::removeNotification(const char * name, const LLUUID& id) { LLNotifications& instance = LLNotifications::instance(); LLNotificationChannelPtr channelPtr = getCommunicationChannel(); LLCommunicationChannel *commChannel = dynamic_cast(channelPtr.get()); LLNotificationPtr notification; - LLSD substitutions; - LLUUID notificationSessionID; + LLSD payload; + LLUUID notificationObjectID; std::string notificationName; + std::string payloadVariable = nameToPayloadParameterMap[name]; LLCommunicationChannel::history_list_t::iterator it; std::vector itemsToRemove; @@ -252,18 +256,18 @@ void LLDoNotDisturbNotificationStorage::removeIMNotification(const LLUUID& sessi ++it) { notification = it->second; - substitutions = notification->getSubstitutions(); - notificationSessionID = substitutions["SESSION_ID"].asUUID(); + payload = notification->getPayload(); + notificationObjectID = payload[payloadVariable].asUUID(); notificationName = notification->getName(); - if(notificationName == toastName - && session_id == notificationSessionID) + if(notificationName == name + && id == notificationObjectID) { itemsToRemove.push_back(it); } } - + //Remove the notifications if(itemsToRemove.size()) { diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index fd7cc7ee82..6e68b0d1be 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -49,6 +49,9 @@ class LLDoNotDisturbNotificationStorage : public LLSingleton nameToPayloadParameterMap; }; #endif // LL_LLDONOTDISTURBNOTIFICATIONSTORAGE_H diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index f73db6b166..6e9f7a380f 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -1316,7 +1316,7 @@ BOOL LLFloaterIMContainer::selectConversationPair(const LLUUID& session_id, bool //Nearby chat (Null) IMs are not stored while in DND mode, so can ignore removal if(gAgent.isDoNotDisturb() && session_id.notNull()) { - LLDoNotDisturbNotificationStorage::getInstance()->removeIMNotification(session_id); + LLDoNotDisturbNotificationStorage::getInstance()->removeNotification(LLDoNotDisturbNotificationStorage::toastName, session_id); } } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d0a8dfc0c8..cb03c1d234 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -144,7 +144,7 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id, args["FROM"] = av_name.getCompleteName(); args["FROM_ID"] = msg["from_id"]; args["SESSION_ID"] = msg["session_id"]; - LLNotificationsUtil::add("IMToast", args, LLSD(), boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); + LLNotificationsUtil::add("IMToast", args, args, boost::bind(&LLFloaterIMContainer::showConversation, LLFloaterIMContainer::getInstance(), msg["session_id"].asUUID())); } void on_new_message(const LLSD& msg) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 6474d56414..7f9474ae70 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -46,6 +46,7 @@ #include "llappearancemgr.h" #include "llappviewer.h" #include "llclipboard.h" +#include "lldonotdisturbnotificationstorage.h" #include "llfloaterinventory.h" #include "llfloatersidepanelcontainer.h" #include "llfocusmgr.h" @@ -1132,11 +1133,32 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root } } +void LLInventoryAction::removeItemFromDND(LLFolderView* root) +{ + //Get selected items + LLFolderView::selected_items_t selectedItems = root->getSelectedItems(); + LLFolderViewModelItemInventory * viewModel = NULL; + + //If user is in DND and deletes item, make sure the notification is not displayed by removing the notification + //from DND history and .xml file. Once this is done, upon exit of DND mode the item deleted will not show a notification. + for(LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it) + { + viewModel = dynamic_cast((*it)->getViewModelItem()); + + if(viewModel && viewModel->getUUID().notNull()) + { + //Will remove the item offer notification + LLDoNotDisturbNotificationStorage::instance().removeNotification(LLDoNotDisturbNotificationStorage::offerName, viewModel->getUUID()); + } + } +} + void LLInventoryAction::onItemsRemovalConfirmation( const LLSD& notification, const LLSD& response, LLFolderView* root ) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0) { + removeItemFromDND(root); root->removeSelectedItems(); } } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 11fc17ce9b..f1066a4dc9 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -433,6 +433,7 @@ struct LLInventoryAction static void doToSelected(class LLInventoryModel* model, class LLFolderView* root, const std::string& action); static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLFolderView* root); + static void removeItemFromDND(LLFolderView* root); }; -- cgit v1.3 From 6a68f16f2e908838b89216543b36f07e2a71c360 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 4 Feb 2013 19:29:05 -0800 Subject: CHUI-732 : Fixed! Do not iterate through selection while modufying it at the same time, use a temp set. --- indra/llui/llfolderview.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 7c1ca017d7..c756ff84e1 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -924,23 +924,27 @@ void LLFolderView::cut() { // clear the inventory clipboard LLClipboard::instance().reset(); - S32 count = mSelectedItems.size(); - if(getVisible() && getEnabled() && (count > 0)) + if(getVisible() && getEnabled() && (mSelectedItems.size() > 0)) { + // Find out which item will be selected once the selection will be cut LLFolderViewItem* item_to_select = getNextUnselectedItem(); + + // Get the selection: removeItem() modified mSelectedItems and makes iterating on it unwise + std::set inventory_selected = getSelectionList(); - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + // Move each item to the clipboard and out of their folder + for (std::set::iterator item_it = inventory_selected.begin(); item_it != inventory_selected.end(); ++item_it) { LLFolderViewItem* item_to_cut = *item_it; LLFolderViewModelItem* listener = item_to_cut->getViewModelItem(); - if(listener) + if (listener) { listener->cutToClipboard(); listener->removeItem(); } } - + + // Update the selection setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel->hasFocus()); } mSearchString.clear(); -- cgit v1.3 From 7ed270ff9dfdbc905dbee70907d3057a5ae490e7 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 6 Feb 2013 18:11:52 -0800 Subject: CHUI-735 : Fixed! Move the delete key handling from the llfolderview to the llinventorypanel level. --- indra/llui/llfolderview.cpp | 23 ----------------------- indra/llui/llfolderview.h | 3 --- indra/newview/llinventorypanel.cpp | 8 ++++++++ 3 files changed, 8 insertions(+), 26 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index c756ff84e1..dca14cc48f 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1336,29 +1336,6 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) } -BOOL LLFolderView::canDoDelete() const -{ - if (mSelectedItems.size() == 0) return FALSE; - - for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) - { - if (!(*item_it)->getViewModelItem()->isItemRemovable()) - { - return FALSE; - } - } - return TRUE; -} - -void LLFolderView::doDelete() -{ - if(mSelectedItems.size() > 0) - { - removeSelectedItems(); - } -} - - BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) { mKeyboardSelection = FALSE; diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 05b2abb9d3..11fccdace4 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -180,9 +180,6 @@ public: virtual BOOL canPaste() const; virtual void paste(); - virtual BOOL canDoDelete() const; - virtual void doDelete(); - LLFolderViewItem* getNextUnselectedItem(); // Public rename functionality - can only start the process diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 019ba8f5b2..0653a097f5 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1365,6 +1365,14 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) LLInventoryAction::doToSelected(mInventory, mFolderRoot, "open"); handled = TRUE; } + break; + case KEY_DELETE: + if (mask == MASK_NONE) + { + LLInventoryAction::doToSelected(mInventory, mFolderRoot, "delete"); + handled = TRUE; + } + break; } return handled; } -- cgit v1.3 From dac026a7d6ad932ef185b4e5c5b5efd7b059e911 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 7 Feb 2013 13:27:32 -0800 Subject: CHUI-735 : Fixed! Handle the backspace case, suppress the search string handling from LLFolderView (it's in the search edit field now). --- indra/llui/llfolderview.cpp | 14 -------------- indra/newview/llinventorypanel.cpp | 3 +++ 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'indra/llui/llfolderview.cpp') diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index dca14cc48f..8feaf654f0 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1275,20 +1275,6 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) break; } - if (!handled && mParentPanel->hasFocus()) - { - if (key == KEY_BACKSPACE) - { - mSearchTimer.reset(); - if (mSearchString.size()) - { - mSearchString.erase(mSearchString.size() - 1, 1); - } - search(getCurSelectedItem(), mSearchString, FALSE); - handled = TRUE; - } - } - return handled; } diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 0653a097f5..578b83fd28 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1367,6 +1367,9 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) } break; case KEY_DELETE: + case KEY_BACKSPACE: + // Delete selected items if delete or backspace key hit on the inventory panel + // Note: on Mac laptop keyboards, backspace and delete are one and the same if (mask == MASK_NONE) { LLInventoryAction::doToSelected(mInventory, mFolderRoot, "delete"); -- cgit v1.3