Newer
Older
/**
* @file llfolderview.cpp
* @brief Implementation of the folder view collection of classes.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* 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
#include "linden_common.h"
#include "llfolderviewmodel.h"
Merov Linden
committed
#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 "lltrans.h"
#include "lluictrlfactory.h"
James Cook
committed
// Linden library includes
#include "lldbstrings.h"
#include "llfocusmgr.h"
#include "llfontgl.h"
#include "llgl.h"
#include "llrender.h"
// Third-party library includes
#include <algorithm>
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
const S32 RENAME_HEIGHT_PAD = 1;
Gilbert Gonzales
committed
Mike Antipov
committed
// *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;
Steven Bennetts
committed
enum {
SIGNAL_NO_KEYBOARD_FOCUS = 1,
SIGNAL_KEYBOARD_FOCUS = 2
};
James Cook
committed
//---------------------------------------------------------------------------
James Cook
committed
// 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
James Cook
committed
public:
LLCloseAllFoldersFunctor(BOOL close) { mOpen = !close; }
virtual ~LLCloseAllFoldersFunctor() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
James Cook
committed
BOOL mOpen;
};
James Cook
committed
void LLCloseAllFoldersFunctor::doFolder(LLFolderViewFolder* folder)
Don Kjer
committed
{
James Cook
committed
folder->setOpenArrangeRecursively(mOpen);
Don Kjer
committed
}
James Cook
committed
// Do nothing.
void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item)
{ }
Kitty Barnett
committed
//---------------------------------------------------------------------------
void LLAllDescendentsPassedFilter::doFolder(LLFolderViewFolder* folder)
{
mAllDescendentsPassedFilter &= (folder) && (folder->passedFilter()) && (folder->descendantsPassedFilter());
}
void LLAllDescendentsPassedFilter::doItem(LLFolderViewItem* item)
{
mAllDescendentsPassedFilter &= (item) && (item->passedFilter());
}
Seth ProductEngine
committed
///----------------------------------------------------------------------------
/// Class LLFolderViewScrollContainer
///----------------------------------------------------------------------------
// virtual
const LLRect LLFolderViewScrollContainer::getScrolledViewRect() const
{
LLRect rect = LLRect::null;
if (mScrolledView)
{
LLFolderView* folder_view = dynamic_cast<LLFolderView*>(mScrolledView);
if (folder_view)
{
S32 height = folder_view->getRect().getHeight();
Seth ProductEngine
committed
rect = mScrolledView->getRect();
rect.setLeftTopAndSize(rect.mLeft, rect.mTop, rect.getWidth(), height);
}
}
return rect;
}
LLFolderViewScrollContainer::LLFolderViewScrollContainer(const LLScrollContainer::Params& p)
: LLScrollContainer(p)
{}
James Cook
committed
///----------------------------------------------------------------------------
/// Class LLFolderView
///----------------------------------------------------------------------------
LLFolderView::Params::Params()
use_label_suffix("use_label_suffix"),
allow_multiselect("allow_multiselect", true),
allow_drag("allow_drag", true),
Leslie Linden
committed
show_empty_message("show_empty_message", true),
suppress_folder_menu("suppress_folder_menu", false),
use_ellipses("use_ellipses", false),
options_menu("options_menu", "")
folder_indentation = -4;
James Cook
committed
// Default constructor
LLFolderView::LLFolderView(const Params& p)
: LLFolderViewFolder(p),
mScrollContainer( NULL ),
mPopupMenuHandle(),
mAllowMultiSelect(p.allow_multiselect),
mAllowDrag(p.allow_drag),
Leslie Linden
committed
mShowEmptyMessage(p.show_empty_message),
James Cook
committed
mShowFolderHierarchy(FALSE),
mRenameItem( NULL ),
mNeedsScroll( FALSE ),
mUseLabelSuffix(p.use_label_suffix),
mSuppressFolderMenu(p.suppress_folder_menu),
mPinningSelectedItem(FALSE),
James Cook
committed
mNeedsAutoSelect( FALSE ),
mAutoSelectOverride(FALSE),
mNeedsAutoRename(FALSE),
mShowSelectionContext(FALSE),
mShowSingleSelection(FALSE),
mArrangeGeneration(0),
mSignalSelectCallback(0),
mMinWidth(0),
mDragAndDropThisFrame(FALSE),
mCallbackRegistrar(NULL),
mUseEllipses(p.use_ellipses),
mDraggingOverItem(NULL),
mShowItemLinkOverlays(p.show_item_link_overlays),
Brad Payne (Vir Linden)
committed
mViewModel(p.view_model),
mGroupedItemModel(p.grouped_item_model)
claimMem(mViewModel);
LLPanel* panel = p.parent_panel;
mParentPanel = panel->getHandle();
mViewModel->setFolderView(this);
mRoot = this;
James Cook
committed
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;
Gilbert Gonzales
committed
mIndentation = getParentFolder() ? getParentFolder()->getIndentation() + mLocalIndentation : 0;
James Cook
committed
//clear label
// go ahead and render root folder as usual
// just make sure the label ("Inventory Folder") never shows up
mLabel = LLStringUtil::null;
James Cook
committed
// 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);
James Cook
committed
params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2));
params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe);
James Cook
committed
params.commit_on_focus_lost(true);
params.visible(false);
mRenamer = LLUICtrlFactory::create<LLLineEditor> (params);
addChild(mRenamer);
// Textbox
LLTextBox::Params text_p;
LLFontGL* font = getLabelFontForStyle(mLabelStyle);
Gilbert Gonzales
committed
//mIconPad, mTextPad are set in folder_view_item.xml
LLRect new_r = LLRect(rect.mLeft + mIconPad,
rect.mTop - mTextPad,
Gilbert Gonzales
committed
rect.mTop - mTextPad - font->getLineHeight());
text_p.rect(new_r);
text_p.name(std::string(p.name));
text_p.font(font);
text_p.visible(false);
Mike Antipov
committed
text_p.wrap(true); // allow multiline text. See EXT-7564, EXT-7047
Mike Antipov
committed
// 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<LLTextBox> (text_p);
mStatusTextBox->setFollowsLeft();
mStatusTextBox->setFollowsTop();
Stinson Linden
committed
addChild(mStatusTextBox);
mViewModelItem->openItem();
James Cook
committed
// Destroys the object
LLFolderView::~LLFolderView( void )
James Cook
committed
// 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;
Richard Linden
committed
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
mPopupMenuHandle.markDead();
James Cook
committed
mAutoOpenItems.removeAllNodes();
clearSelection();
mItems.clear();
mFolders.clear();
James Cook
committed
BOOL LLFolderView::canFocusChildren() const
James Cook
committed
return FALSE;
Don Kjer
committed
}
void LLFolderView::addFolder( LLFolderViewFolder* folder)
LLFolderViewFolder::addFolder(folder);
// Open all the folders
setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
James Cook
committed
arrangeAll();
// Close all the folders
setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
void LLFolderView::openTopLevelFolders()
{
for (folders_t::iterator iter = mFolders.begin();
iter != mFolders.end();)
{
folders_t::iterator fit = iter++;
(*fit)->setOpen(TRUE);
}
}
Merov Linden
committed
// 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 )
James Cook
committed
mMinWidth = 0;
LLFolderViewFolder::arrange(&mMinWidth, &target_height);
James Cook
committed
LLRect scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
callum_linden
committed
reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) );
James Cook
committed
LLRect new_scroll_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
if (new_scroll_rect.getWidth() != scroll_rect.getWidth())
callum_linden
committed
reshape( llmax(scroll_rect.getWidth(), mMinWidth), ll_round(mCurHeight) );
James Cook
committed
// move item renamer text field to item's new position
updateRenamerPosition();
callum_linden
committed
return ll_round(mTargetHeight);
static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View");
void LLFolderView::filter( LLFolderViewFilter& filter )
LL_RECORD_BLOCK_TIME(FTM_FILTER);
static LLUICachedControl<S32> time_visible("FilterItemsMaxTimePerFrameVisible", 10);
static LLUICachedControl<S32> time_invisible("FilterItemsMaxTimePerFrameUnvisible", 1);
filter.resetTime(llclamp(mParentPanel.get()->getVisible() ? time_visible() : time_invisible(), 1, 100));
Merov Linden
committed
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
James Cook
committed
void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)
LLRect scroll_rect;
James Cook
committed
if (mScrollContainer)
LLView::reshape(width, height, called_from_parent);
scroll_rect = mScrollContainer->getContentWindowRect();
Merov Linden
committed
width = llmax(mMinWidth, scroll_rect.getWidth());
callum_linden
committed
height = llmax(ll_round(mCurHeight), scroll_rect.getHeight());
Merov Linden
committed
// Restrict width within scroll container's width
if (mUseEllipses && mScrollContainer)
{
Merov Linden
committed
}
James Cook
committed
LLView::reshape(width, height, called_from_parent);
mReshapeSignal(mSelectedItems, FALSE);
James Cook
committed
void LLFolderView::addToSelectionList(LLFolderViewItem* item)
James Cook
committed
if (item->isSelected())
James Cook
committed
removeFromSelectionList(item);
James Cook
committed
if (mSelectedItems.size())
James Cook
committed
mSelectedItems.back()->setIsCurSelection(FALSE);
James Cook
committed
item->setIsCurSelection(TRUE);
mSelectedItems.push_back(item);
James Cook
committed
void LLFolderView::removeFromSelectionList(LLFolderViewItem* item)
James Cook
committed
if (mSelectedItems.size())
{
mSelectedItems.back()->setIsCurSelection(FALSE);
}
James Cook
committed
selected_items_t::iterator item_iter;
for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end();)
James Cook
committed
if (*item_iter == item)
James Cook
committed
item_iter = mSelectedItems.erase(item_iter);
James Cook
committed
++item_iter;
James Cook
committed
if (mSelectedItems.size())
James Cook
committed
mSelectedItems.back()->setIsCurSelection(TRUE);
James Cook
committed
}
James Cook
committed
LLFolderViewItem* LLFolderView::getCurSelectedItem( void )
{
if(mSelectedItems.size())
James Cook
committed
LLFolderViewItem* itemp = mSelectedItems.back();
llassert(itemp->getIsCurSelection());
return itemp;
James Cook
committed
return NULL;
Gilbert Gonzales
committed
LLFolderView::selected_items_t& LLFolderView::getSelectedItems( void )
{
return mSelectedItems;
}
James Cook
committed
// 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;
James Cook
committed
if( selection == this )
James Cook
committed
return FALSE;
}
James Cook
committed
if( selection && take_keyboard_focus)
{
mParentPanel.get()->setFocus(TRUE);
James Cook
committed
}
James Cook
committed
// clear selection down here because change of keyboard focus can potentially
// affect selection
clearSelection();
James Cook
committed
if(selection)
{
addToSelectionList(selection);
James Cook
committed
BOOL rv = LLFolderViewFolder::setSelection(selection, openitem, take_keyboard_focus);
if(openitem && selection)
James Cook
committed
selection->getParentFolder()->requestArrange();
James Cook
committed
llassert(mSelectedItems.size() <= 1);
James Cook
committed
return rv;
James Cook
committed
BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected)
{
BOOL rv = FALSE;
// can't select root folder
if(!selection || selection == this)
{
return FALSE;
James Cook
committed
if (!mAllowMultiSelect)
James Cook
committed
clearSelection();
James Cook
committed
selected_items_t::iterator item_iter;
for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter)
James Cook
committed
if (*item_iter == selection)
James Cook
committed
break;
James Cook
committed
BOOL on_list = (item_iter != mSelectedItems.end());
if(selected && !on_list)
James Cook
committed
addToSelectionList(selection);
James Cook
committed
if(!selected && on_list)
James Cook
committed
removeFromSelectionList(selection);
James Cook
committed
rv = LLFolderViewFolder::changeSelection(selection, selected);
James Cook
committed
mSignalSelectCallback = SIGNAL_KEYBOARD_FOCUS;
return rv;
}
static LLTrace::BlockTimerStatHandle FTM_SANITIZE_SELECTION("Sanitize Selection");
James Cook
committed
void LLFolderView::sanitizeSelection()
{
LL_RECORD_BLOCK_TIME(FTM_SANITIZE_SELECTION);
James Cook
committed
// store off current item in case it is automatically deselected
// and we want to preserve context
LLFolderViewItem* original_selected_item = getCurSelectedItem();
James Cook
committed
std::vector<LLFolderViewItem*> items_to_remove;
selected_items_t::iterator item_iter;
for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter)
Don Kjer
committed
{
James Cook
committed
LLFolderViewItem* item = *item_iter;
// ensure that each ancestor is open and potentially passes filtering
maxim_productengine
committed
BOOL visible = false;
if(item->getViewModelItem() != NULL)
maxim_productengine
committed
{
visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item
}
James Cook
committed
// modify with parent open and filters states
LLFolderViewFolder* parent_folder = item->getParentFolder();
// Move up through parent folders and see what's visible
James Cook
committed
while(parent_folder)
{
visible = visible && parent_folder->isOpen() && parent_folder->getViewModelItem()->potentiallyVisible();
James Cook
committed
parent_folder = parent_folder->getParentFolder();
}
James Cook
committed
// deselect item if any ancestor is closed or didn't pass filter requirements.
if (!visible)
Don Kjer
committed
{
James Cook
committed
items_to_remove.push_back(item);
James Cook
committed
// 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)
James Cook
committed
LLFolderViewItem* other_item = *other_item_iter;
for( parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder())
James Cook
committed
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);
}
Don Kjer
committed
}
James Cook
committed
std::vector<LLFolderViewItem*>::iterator item_it;
for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it )
Don Kjer
committed
{
James Cook
committed
changeSelection(*item_it, FALSE); // toggle selection (also removes from list)
Don Kjer
committed
}
James Cook
committed
// if nothing selected after prior constraints...
if (mSelectedItems.empty())
Don Kjer
committed
{
Richard Linden
committed
// ...select first available parent of original selection
James Cook
committed
LLFolderViewItem* new_selection = NULL;
if (original_selected_item)
Don Kjer
committed
{
James Cook
committed
for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder();
parent_folder;
parent_folder = parent_folder->getParentFolder())
Merov Linden
committed
if (parent_folder->getViewModelItem() && parent_folder->getViewModelItem()->potentiallyVisible())
James Cook
committed
{
// 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;
}
}
James Cook
committed
else
James Cook
committed
if (new_selection)
James Cook
committed
setSelection(new_selection, FALSE, FALSE);
Don Kjer
committed
}
James Cook
committed
}
}
Don Kjer
committed
James Cook
committed
void LLFolderView::clearSelection()
{
for (selected_items_t::const_iterator item_it = mSelectedItems.begin();
item_it != mSelectedItems.end();
++item_it)
James Cook
committed
{
(*item_it)->setUnselected();
mSelectedItems.clear();
James Cook
committed
}
Don Kjer
committed
std::set<LLFolderViewItem*> LLFolderView::getSelectionList() const
std::set<LLFolderViewItem*> selection;
std::copy(mSelectedItems.begin(), mSelectedItems.end(), std::inserter(selection, selection.begin()));
Loren Shih
committed
return selection;
bool LLFolderView::startDrag()
James Cook
committed
{
std::vector<LLFolderViewModelItem*> selected_items;
James Cook
committed
selected_items_t::iterator item_it;
James Cook
committed
if (!mSelectedItems.empty())
{
for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
{
selected_items.push_back((*item_it)->getViewModelItem());
James Cook
committed
}
return getFolderViewModel()->startDrag(selected_items);
James Cook
committed
}
James Cook
committed
}
James Cook
committed
void LLFolderView::commitRename( const LLSD& data )
James Cook
committed
finishRenamingItem();
Mnikolenko ProductEngine
committed
arrange( NULL, NULL );
James Cook
committed
void LLFolderView::draw()
//LLFontGL* font = getLabelFontForStyle(mLabelStyle);
James Cook
committed
// if cursor has moved off of me during drag and drop
// close all auto opened folders
if (!mDragAndDropThisFrame)
James Cook
committed
closeAutoOpenedFolders();
static LLUICachedControl<F32> type_ahead_timeout("TypeAheadTimeout", 1.5f);
if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || mSearchString.empty())
James Cook
committed
mSearchString.clear();
if (hasVisibleChildren())
mStatusTextBox->setVisible( FALSE );
Leslie Linden
committed
else if (mShowEmptyMessage)
mStatusTextBox->setValue(getFolderViewModel()->getStatusText());
mStatusTextBox->setVisible( TRUE );
Mike Antipov
committed
// 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();
Merov Linden
committed
bool height_changed = (local_rect.getHeight() < pixel_height);
Mike Antipov
committed
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);
Mike Antipov
committed
}
andreykproductengine
committed
if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect()))
andreykproductengine
committed
{
// renamer is not connected to the item we are renaming in any form so manage it manually
andreykproductengine
committed
// TODO: consider stopping on any scroll action instead of when out of visible area
andreykproductengine
committed
}
// skip over LLFolderViewFolder::draw since we don't want the folder icon, label,
// and arrow for the root folder
LLView::draw();
James Cook
committed
mDragAndDropThisFrame = FALSE;
}
James Cook
committed
void LLFolderView::finishRenamingItem( void )
{
if(!mRenamer)
James Cook
committed
if( mRenameItem )
{
mRenameItem->rename( mRenamer->getText() );
}
Brad Payne (Vir Linden)
committed
// This is moved to an inventory observer in llinventorybridge.cpp, to handle updating after operation completed in AISv3 (SH-4611).
// List is re-sorted alphabetically, so scroll to make sure the selected item is visible.
Brad Payne (Vir Linden)
committed
//scrollToShowSelection();
James Cook
committed
}
void LLFolderView::closeRenamer( void )
{
// Triggers onRenamerLost() that actually closes the renamer.
LLUI::getInstance()->removePopup(mRenamer);
James Cook
committed
}
void LLFolderView::removeSelectedItems()
James Cook
committed
if(getVisible() && getEnabled())
James Cook
committed
// 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<LLFolderViewItem*> items;
S32 count = mSelectedItems.size();
James Cook
committed
LLFolderViewItem* item = NULL;
selected_items_t::iterator item_it;
for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
James Cook
committed
item = *item_it;
Vadim ProductEngine
committed
if (item && item->isRemovable())
James Cook
committed
{
items.push_back(item);
}
else
{
Richard Linden
committed
LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL;
James Cook
committed
return;
}
James Cook
committed
// iterate through the new container.
count = items.size();
Richard Linden
committed
LLFolderViewItem* item_to_select = getNextUnselectedItem();
James Cook
committed
if(count == 1)
James Cook
committed
LLFolderViewItem* item_to_delete = items[0];
LLFolderViewFolder* parent = item_to_delete->getParentFolder();
if(parent)
if (item_to_delete->remove())
James Cook
committed
// change selection on successful delete
setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus());
Gilbert Gonzales
committed
}
James Cook
committed
arrangeAll();
James Cook
committed
else if (count > 1)
Richard Linden
committed
std::vector<LLFolderViewModelItem*> listeners;
LLFolderViewModelItem* listener;
Richard Linden
committed
setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus());
James Cook
committed
Richard Linden
committed
listeners.reserve(count);
James Cook
committed
for(S32 i = 0; i < count; ++i)
{
listener = items[i]->getViewModelItem();
Richard Linden
committed
if(listener && (std::find(listeners.begin(), listeners.end(), listener) == listeners.end()))
James Cook
committed
{
Richard Linden
committed
listeners.push_back(listener);
James Cook
committed
}
}
Richard Linden
committed
listener = static_cast<LLFolderViewModelItem*>(listeners.at(0));
James Cook
committed
if(listener)
James Cook
committed
listener->removeBatch(listeners);
James Cook
committed
arrangeAll();
scrollToShowSelection();
James Cook
committed
}
James Cook
committed
void LLFolderView::autoOpenItem( LLFolderViewFolder* item )
Leslie Linden
committed
if ((mAutoOpenItems.check() == item) ||
(mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) ||
item->isOpen())
James Cook
committed
return;
James Cook
committed
// 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();
}
James Cook
committed
item->requestArrange();
James Cook
committed
mAutoOpenItems.push(item);
item->setOpen(TRUE);
LLRect content_rect = (mScrollContainer ? mScrollContainer->getContentWindowRect() : LLRect());
LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0);
scrollToShowItem(item, constraint_rect);
James Cook
committed
void LLFolderView::closeAutoOpenedFolders()
James Cook
committed
while (mAutoOpenItems.check())
James Cook
committed
LLFolderViewFolder* close_item = mAutoOpenItems.pop();
close_item->setOpen(FALSE);
James Cook
committed
if (mAutoOpenCandidate)
James Cook
committed
mAutoOpenCandidate->setAutoOpenCountdown(0.f);
James Cook
committed
mAutoOpenCandidate = NULL;
mAutoOpenTimer.stop();
James Cook
committed
BOOL LLFolderView::autoOpenTest(LLFolderViewFolder* folder)
James Cook
committed
if (folder && mAutoOpenCandidate == folder)
James Cook
committed
if (mAutoOpenTimer.getStarted())
James Cook
committed
if (!mAutoOpenCandidate->isOpen())
James Cook
committed
mAutoOpenCandidate->setAutoOpenCountdown(clamp_rescale(mAutoOpenTimer.getElapsedTimeF32(), 0.f, sAutoOpenTime, 0.f, 1.f));
James Cook
committed
if (mAutoOpenTimer.getElapsedTimeF32() > sAutoOpenTime)
James Cook
committed
autoOpenItem(folder);
mAutoOpenTimer.stop();
return TRUE;
James Cook
committed
return FALSE;
James Cook
committed
// otherwise new candidate, restart timer
if (mAutoOpenCandidate)
James Cook
committed
mAutoOpenCandidate->setAutoOpenCountdown(0.f);
James Cook
committed
mAutoOpenCandidate = folder;
mAutoOpenTimer.start();
return FALSE;
James Cook
committed
BOOL LLFolderView::canCopy() const
James Cook
committed
if (!(getVisible() && getEnabled() && (mSelectedItems.size() > 0)))
James Cook
committed
return FALSE;
James Cook
committed
for (selected_items_t::const_iterator selected_it = mSelectedItems.begin(); selected_it != mSelectedItems.end(); ++selected_it)
James Cook
committed
const LLFolderViewItem* item = *selected_it;
if (!item->getViewModelItem()->isItemCopyable())
James Cook
committed
return FALSE;
James Cook
committed
}
return TRUE;
}
James Cook
committed
// copy selected item
void LLFolderView::copy()
{
// *NOTE: total hack to clear the inventory clipboard
LLClipboard::instance().reset();
James Cook
committed
S32 count = mSelectedItems.size();
if(getVisible() && getEnabled() && (count > 0))
{
LLFolderViewModelItem* listener = NULL;
James Cook
committed
selected_items_t::iterator item_it;
for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it)
listener = (*item_it)->getViewModelItem();
James Cook
committed
if(listener)
James Cook
committed
listener->copyToClipboard();
James Cook
committed
}
mSearchString.clear();
}
James Cook
committed
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;
James Cook
committed
}
void LLFolderView::cut()
{
LLClipboard::instance().reset();
Merov Linden
committed
if(getVisible() && getEnabled() && (mSelectedItems.size() > 0))
Merov Linden
committed
// Find out which item will be selected once the selection will be cut
Richard Linden
committed
LLFolderViewItem* item_to_select = getNextUnselectedItem();
Merov Linden
committed
// Get the selection: removeItem() modified mSelectedItems and makes iterating on it unwise
std::set<LLFolderViewItem*> inventory_selected = getSelectionList();
Richard Linden
committed
Merov Linden
committed
// Move each item to the clipboard and out of their folder
for (std::set<LLFolderViewItem*>::iterator item_it = inventory_selected.begin(); item_it != inventory_selected.end(); ++item_it)
Richard Linden
committed
LLFolderViewItem* item_to_cut = *item_it;
Richard Linden
committed
LLFolderViewModelItem* listener = item_to_cut->getViewModelItem();
Merov Linden
committed
if (listener)
{
listener->cutToClipboard();
}
}
Merov Linden
committed
// Update the selection
setSelection(item_to_select, item_to_select ? item_to_select->isOpen() : false, mParentPanel.get()->hasFocus());
James Cook
committed
}
BOOL LLFolderView::canPaste() const
{
if (mSelectedItems.empty())
{
return FALSE;
James Cook
committed
if(getVisible() && getEnabled())
James Cook
committed
for (selected_items_t::const_iterator item_it = mSelectedItems.begin();
item_it != mSelectedItems.end(); ++item_it)
James Cook
committed
// *TODO: only check folders and parent folders of items
const LLFolderViewItem* item = (*item_it);
const LLFolderViewModelItem* listener = item->getViewModelItem();
James Cook
committed
if(!listener || !listener->isClipboardPasteable())