536 lines
16 KiB
C++
536 lines
16 KiB
C++
/**
|
|
* @file llflatlistview.h
|
|
* @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
|
|
*
|
|
* $LicenseInfo:firstyear=2009&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$
|
|
*/
|
|
|
|
#ifndef LL_LLFLATLISTVIEW_H
|
|
#define LL_LLFLATLISTVIEW_H
|
|
|
|
#include "llpanel.h"
|
|
#include "llscrollcontainer.h"
|
|
#include "lltextbox.h"
|
|
|
|
|
|
/**
|
|
* LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's.
|
|
* LLSD can be associated with each added item, it can keep data from an item in digested form.
|
|
* Associated LLSD's can be of any type (singular, a map etc.).
|
|
* Items (LLPanel's subclasses) can be of different height.
|
|
* The list is LLPanel created in itself and grows in height while new items are added.
|
|
*
|
|
* The control can manage selection of its items when the flag "allow_select" is set. Also ability to select
|
|
* multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag
|
|
* is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items)
|
|
* since any item of the list was selected.
|
|
*
|
|
* Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to
|
|
* manage the list of pick items.
|
|
*
|
|
* ASSUMPTIONS AND STUFF
|
|
* - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise
|
|
* - Order of returned selected items are not guaranteed
|
|
* - The control assumes that all items being added are unique.
|
|
*/
|
|
class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler
|
|
{
|
|
LOG_CLASS(LLFlatListView);
|
|
public:
|
|
|
|
/**
|
|
* Abstract comparator for comparing flat list items in a form of LLPanel
|
|
*/
|
|
class ItemComparator
|
|
{
|
|
public:
|
|
ItemComparator() {};
|
|
virtual ~ItemComparator() {};
|
|
|
|
/** Returns true if item1 < item2, false otherwise */
|
|
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0;
|
|
};
|
|
|
|
/**
|
|
* Represents reverse comparator which acts as a decorator for a comparator that need to be reversed
|
|
*/
|
|
class ItemReverseComparator : public ItemComparator
|
|
{
|
|
public:
|
|
ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {};
|
|
virtual ~ItemReverseComparator() {};
|
|
|
|
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const
|
|
{
|
|
return mComparator.compare(item2, item1);
|
|
}
|
|
|
|
private:
|
|
const ItemComparator& mComparator;
|
|
};
|
|
|
|
|
|
struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params>
|
|
{
|
|
/** turning on/off selection support */
|
|
Optional<bool> allow_select;
|
|
|
|
/** turning on/off multiple selection (works while clicking and holding CTRL)*/
|
|
Optional<bool> multi_select;
|
|
|
|
/** don't allow to deselect all selected items (for mouse events on items only) */
|
|
Optional<bool> keep_one_selected;
|
|
|
|
/** try to keep selection visible after reshape */
|
|
Optional<bool> keep_selection_visible_on_reshape;
|
|
|
|
/** padding between items */
|
|
Optional<U32> item_pad;
|
|
|
|
/** textbox with info message when list is empty*/
|
|
Optional<LLTextBox::Params> no_items_text;
|
|
|
|
Params();
|
|
};
|
|
|
|
// disable traversal when finding widget to hand focus off to
|
|
/*virtual*/ BOOL canFocusChildren() const { return FALSE; }
|
|
|
|
/**
|
|
* Connects callback to signal called when Return key is pressed.
|
|
*/
|
|
boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
|
|
|
|
/** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */
|
|
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
|
|
|
/** Returns full rect of child panel */
|
|
const LLRect& getItemsRect() const;
|
|
|
|
LLRect getRequiredRect() { return getItemsRect(); }
|
|
|
|
/** Returns distance between items */
|
|
const S32 getItemsPad() { return mItemPad; }
|
|
|
|
/**
|
|
* Adds and item and LLSD value associated with it to the list at specified position
|
|
* @return true if the item was added, false otherwise
|
|
*/
|
|
virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true);
|
|
|
|
/**
|
|
* Insert item_to_add along with associated value to the list right after the after_item.
|
|
* @return true if the item was successfully added, false otherwise
|
|
*/
|
|
virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null);
|
|
|
|
/**
|
|
* Remove specified item
|
|
* @return true if the item was removed, false otherwise
|
|
*/
|
|
virtual bool removeItem(LLPanel* item, bool rearrange = true);
|
|
|
|
/**
|
|
* Remove an item specified by value
|
|
* @return true if the item was removed, false otherwise
|
|
*/
|
|
virtual bool removeItemByValue(const LLSD& value, bool rearrange = true);
|
|
|
|
/**
|
|
* Remove an item specified by uuid
|
|
* @return true if the item was removed, false otherwise
|
|
*/
|
|
virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true);
|
|
|
|
/**
|
|
* Get an item by value
|
|
* @return the item as LLPanel if associated with value, NULL otherwise
|
|
*/
|
|
virtual LLPanel* getItemByValue(const LLSD& value) const;
|
|
|
|
template<class T>
|
|
T* getTypedItemByValue(const LLSD& value) const
|
|
{
|
|
return dynamic_cast<T*>(getItemByValue(value));
|
|
}
|
|
|
|
/**
|
|
* Select or deselect specified item based on select
|
|
* @return true if succeed, false otherwise
|
|
*/
|
|
virtual bool selectItem(LLPanel* item, bool select = true);
|
|
|
|
/**
|
|
* Select or deselect an item by associated value based on select
|
|
* @return true if succeed, false otherwise
|
|
*/
|
|
virtual bool selectItemByValue(const LLSD& value, bool select = true);
|
|
|
|
/**
|
|
* Select or deselect an item by associated uuid based on select
|
|
* @return true if succeed, false otherwise
|
|
*/
|
|
virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true);
|
|
|
|
/**
|
|
* Get all panels stored in the list.
|
|
*/
|
|
virtual void getItems(std::vector<LLPanel*>& items) const;
|
|
|
|
/**
|
|
* Get all items values.
|
|
*/
|
|
virtual void getValues(std::vector<LLSD>& values) const;
|
|
|
|
/**
|
|
* Get LLSD associated with the first selected item
|
|
*/
|
|
virtual LLSD getSelectedValue() const;
|
|
|
|
/**
|
|
* Get LLSD's associated with selected items.
|
|
* @param selected_values std::vector being populated with LLSD associated with selected items
|
|
*/
|
|
virtual void getSelectedValues(std::vector<LLSD>& selected_values) const;
|
|
|
|
|
|
/**
|
|
* Get LLUUID associated with selected item
|
|
* @return LLUUID if such was associated with selected item
|
|
*/
|
|
virtual LLUUID getSelectedUUID() const;
|
|
|
|
/**
|
|
* Get LLUUIDs associated with selected items
|
|
* @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items
|
|
*/
|
|
virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const;
|
|
|
|
/** Get the top selected item */
|
|
virtual LLPanel* getSelectedItem() const;
|
|
|
|
/**
|
|
* Get selected items
|
|
* @param selected_items An std::vector being populated with pointers to selected items
|
|
*/
|
|
virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const;
|
|
|
|
|
|
/**
|
|
* Resets selection of items.
|
|
*
|
|
* It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true"
|
|
* argument for current Flat List.
|
|
* @param no_commit_on_deselection - if true onCommit callback will not be called
|
|
*/
|
|
virtual void resetSelection(bool no_commit_on_deselection = false);
|
|
|
|
/**
|
|
* Sets comment text which will be shown in the list is it is empty.
|
|
*
|
|
* Textbox to hold passed text is created while this method is called at the first time.
|
|
*
|
|
* @param comment_text - string to be shown as a comment.
|
|
*/
|
|
void setNoItemsCommentText( const std::string& comment_text);
|
|
|
|
/** Turn on/off multiple selection support */
|
|
void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; }
|
|
|
|
/** Turn on/off selection support */
|
|
void setAllowSelection(bool can_select) { mAllowSelection = can_select; }
|
|
|
|
/** Sets flag whether onCommit should be fired if selection was changed */
|
|
// FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly.
|
|
void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; }
|
|
|
|
/** Get number of selected items in the list */
|
|
U32 numSelected() const {return mSelectedItemPairs.size(); }
|
|
|
|
/** Get number of (visible) items in the list */
|
|
U32 size(const bool only_visible_items = true) const;
|
|
|
|
/** Removes all items from the list */
|
|
virtual void clear();
|
|
|
|
/**
|
|
* Removes all items that can be detached from the list but doesn't destroy
|
|
* them, caller responsible to manage items after they are detached.
|
|
* Detachable item should accept "detach" action via notify() method,
|
|
* where it disconnect all callbacks, does other valuable routines and
|
|
* return 1.
|
|
*/
|
|
void detachItems(std::vector<LLPanel*>& detached_items);
|
|
|
|
/**
|
|
* Set comparator to use for future sorts.
|
|
*
|
|
* This class does NOT manage lifetime of the comparator
|
|
* but assumes that the comparator is always alive.
|
|
*/
|
|
void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
|
|
void sort();
|
|
|
|
bool updateValue(const LLSD& old_value, const LLSD& new_value);
|
|
|
|
void scrollToShowFirstSelectedItem();
|
|
|
|
void selectFirstItem ();
|
|
void selectLastItem ();
|
|
|
|
virtual S32 notify(const LLSD& info) ;
|
|
|
|
virtual ~LLFlatListView();
|
|
|
|
protected:
|
|
|
|
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
|
|
typedef std::pair<LLPanel*, LLSD> item_pair_t;
|
|
|
|
typedef std::list<item_pair_t*> pairs_list_t;
|
|
typedef pairs_list_t::iterator pairs_iterator_t;
|
|
typedef pairs_list_t::const_iterator pairs_const_iterator_t;
|
|
|
|
/** An adapter for a ItemComparator */
|
|
struct ComparatorAdaptor
|
|
{
|
|
ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {};
|
|
|
|
bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2)
|
|
{
|
|
return mComparator.compare(item_pair1->first, item_pair2->first);
|
|
}
|
|
|
|
const ItemComparator& mComparator;
|
|
};
|
|
|
|
|
|
friend class LLUICtrlFactory;
|
|
LLFlatListView(const LLFlatListView::Params& p);
|
|
|
|
/** Manage selection on mouse events */
|
|
void onItemMouseClick(item_pair_t* item_pair, MASK mask);
|
|
|
|
void onItemRightMouseClick(item_pair_t* item_pair, MASK mask);
|
|
|
|
/**
|
|
* Updates position of items.
|
|
* It does not take into account invisible items.
|
|
*/
|
|
virtual void rearrangeItems();
|
|
|
|
virtual item_pair_t* getItemPair(LLPanel* item) const;
|
|
|
|
virtual item_pair_t* getItemPair(const LLSD& value) const;
|
|
|
|
virtual bool selectItemPair(item_pair_t* item_pair, bool select);
|
|
|
|
virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection);
|
|
|
|
virtual BOOL canSelectAll() const;
|
|
virtual void selectAll();
|
|
|
|
virtual bool isSelected(item_pair_t* item_pair) const;
|
|
|
|
virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange);
|
|
|
|
bool addItemPairs(pairs_list_t panel_list, bool rearrange = true);
|
|
|
|
/**
|
|
* Notify parent about changed size of internal controls with "size_changes" action
|
|
*
|
|
* Size includes Items Rect width and either Items Rect height or comment text height.
|
|
* Comment text height is included if comment text is set and visible.
|
|
* List border size is also included into notified size.
|
|
*/
|
|
void notifyParentItemsRectChanged();
|
|
|
|
virtual BOOL handleKeyHere(KEY key, MASK mask);
|
|
|
|
virtual BOOL postBuild();
|
|
|
|
virtual void onFocusReceived();
|
|
|
|
virtual void onFocusLost();
|
|
|
|
virtual void draw();
|
|
|
|
LLRect getLastSelectedItemRect();
|
|
|
|
void ensureSelectedVisible();
|
|
|
|
const pairs_list_t& getItemPairs() { return mItemPairs; }
|
|
|
|
private:
|
|
|
|
void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;}
|
|
|
|
void setNoItemsCommentVisible(bool visible) const;
|
|
|
|
protected:
|
|
|
|
/** Comparator to use when sorting the list. */
|
|
const ItemComparator* mItemComparator;
|
|
|
|
|
|
private:
|
|
|
|
LLPanel* mItemsPanel;
|
|
|
|
S32 mItemsNoScrollWidth;
|
|
|
|
S32 mBorderThickness;
|
|
|
|
/** Items padding */
|
|
S32 mItemPad;
|
|
|
|
/** Selection support flag */
|
|
bool mAllowSelection;
|
|
|
|
/** Multiselection support flag, ignored if selection is not supported */
|
|
bool mMultipleSelection;
|
|
|
|
/**
|
|
* Flag specified whether onCommit be called if selection is changed in the list.
|
|
*
|
|
* Can be ignored in the resetSelection() method.
|
|
* @see resetSelection()
|
|
*/
|
|
bool mCommitOnSelectionChange;
|
|
|
|
bool mKeepOneItemSelected;
|
|
|
|
bool mIsConsecutiveSelection;
|
|
|
|
bool mKeepSelectionVisibleOnReshape;
|
|
|
|
/** All pairs of the list */
|
|
pairs_list_t mItemPairs;
|
|
|
|
/** Selected pairs for faster access */
|
|
pairs_list_t mSelectedItemPairs;
|
|
|
|
/**
|
|
* Rectangle contained previous size of items parent notified last time.
|
|
* Is used to reduce amount of parentNotify() calls if size was not changed.
|
|
*/
|
|
LLRect mPrevNotifyParentRect;
|
|
|
|
LLTextBox* mNoItemsCommentTextbox;
|
|
|
|
LLViewBorder* mSelectedItemsBorder;
|
|
|
|
commit_signal_t mOnReturnSignal;
|
|
};
|
|
|
|
/**
|
|
* Extends LLFlatListView functionality to show different messages when there are no items in the
|
|
* list depend on whether they are filtered or not.
|
|
*
|
|
* Class provides one message per case of empty list.
|
|
* It also provides protected updateNoItemsMessage() method to be called each time when derived list
|
|
* is changed to update base mNoItemsCommentTextbox value.
|
|
*
|
|
* It is implemented to avoid duplication of this functionality in concrete implementations of the
|
|
* lists. It is intended to be used as a base class for lists which should support two different
|
|
* messages for empty state. Can be improved to support more than two messages via state-to-message map.
|
|
*/
|
|
class LLFlatListViewEx : public LLFlatListView
|
|
{
|
|
public:
|
|
LOG_CLASS(LLFlatListViewEx);
|
|
|
|
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
|
|
{
|
|
/**
|
|
* Contains a message for empty list when it does not contain any items at all.
|
|
*/
|
|
Optional<std::string> no_items_msg;
|
|
|
|
/**
|
|
* Contains a message for empty list when its items are removed by filtering.
|
|
*/
|
|
Optional<std::string> no_filtered_items_msg;
|
|
Params();
|
|
};
|
|
|
|
// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
|
|
// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
|
|
void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
|
|
void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
|
|
|
|
bool getForceShowingUnmatchedItems();
|
|
|
|
void setForceShowingUnmatchedItems(bool show);
|
|
|
|
/**
|
|
* Sets up new filter string and filters the list.
|
|
*/
|
|
void setFilterSubString(const std::string& filter_str, bool notify_parent);
|
|
std::string getFilterSubString() { return mFilterSubString; }
|
|
|
|
/**
|
|
* Filters the list, rearranges and notifies parent about shape changes.
|
|
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
|
|
*/
|
|
void filterItems(bool re_sort, bool notify_parent);
|
|
|
|
/**
|
|
* Returns true if last call of filterItems() found at least one matching item
|
|
*/
|
|
bool hasMatchedItems();
|
|
|
|
protected:
|
|
LLFlatListViewEx(const Params& p);
|
|
|
|
/**
|
|
* Applies a message for empty list depend on passed argument.
|
|
*
|
|
* @param filter_string - if is not empty, message for filtered items will be set, otherwise for
|
|
* completely empty list. Value of filter string will be passed as search_term in SLURL.
|
|
*/
|
|
void updateNoItemsMessage(const std::string& filter_string);
|
|
|
|
/**
|
|
* Applies visibility acording to action and LLFlatListView settings.
|
|
*
|
|
* @param item - item we are changing
|
|
* @param item - action - parameters to determin visibility from
|
|
*/
|
|
bool updateItemVisibility(LLPanel* item, const LLSD &action);
|
|
|
|
private:
|
|
std::string mNoFilteredItemsMsg;
|
|
std::string mNoItemsMsg;
|
|
std::string mFilterSubString;
|
|
/**
|
|
* Show list items that don't match current filter
|
|
*/
|
|
bool mForceShowingUnmatchedItems;
|
|
/**
|
|
* True if last call of filterItems() found at least one matching item
|
|
*/
|
|
bool mHasMatchedItems;
|
|
};
|
|
|
|
#endif
|