PageRenderTime 42ms CodeModel.GetById 1ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llflatlistview.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 520 lines | 168 code | 119 blank | 233 comment | 0 complexity | fdf817c74fd01c353a9a15d73e0c1a1a MD5 | raw file
  1/** 
  2 * @file llflatlistview.h
  3 * @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
  4 *
  5 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_LLFLATLISTVIEW_H
 28#define LL_LLFLATLISTVIEW_H
 29
 30#include "llpanel.h"
 31#include "llscrollcontainer.h"
 32#include "lltextbox.h"
 33
 34
 35/**
 36 * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's.
 37 * LLSD can be associated with each added item, it can keep data from an item in digested form.
 38 * Associated LLSD's can be of any type (singular, a map etc.).
 39 * Items (LLPanel's subclasses) can be of different height.
 40 * The list is LLPanel created in itself and grows in height while new items are added. 
 41 * 
 42 * The control can manage selection of its items when the flag "allow_select" is set. Also ability to select
 43 * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag 
 44 * is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items)
 45 * since any item of the list was selected.
 46 *
 47 * Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to 
 48 * manage the list of pick items.
 49 *
 50 * ASSUMPTIONS AND STUFF
 51 * - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise
 52 * - Order of returned selected items are not guaranteed
 53 * - The control assumes that all items being added are unique.
 54 */
 55class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler
 56{
 57	LOG_CLASS(LLFlatListView);
 58public:
 59
 60	/**
 61	 * Abstract comparator for comparing flat list items in a form of LLPanel
 62	 */
 63	class ItemComparator
 64	{
 65	public:
 66		ItemComparator() {};
 67		virtual ~ItemComparator() {};
 68
 69		/** Returns true if item1 < item2, false otherwise */
 70		virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0;
 71	};
 72
 73	/**
 74	 * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed
 75	 */
 76	class ItemReverseComparator : public ItemComparator
 77	{
 78	public:
 79		ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {};
 80		virtual ~ItemReverseComparator() {};
 81
 82		virtual bool compare(const LLPanel* item1, const LLPanel* item2) const
 83		{
 84			return mComparator.compare(item2, item1);
 85		}
 86
 87	private:
 88		const ItemComparator& mComparator;
 89	};
 90
 91
 92	struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params>
 93	{
 94		/** turning on/off selection support */
 95		Optional<bool> allow_select;
 96
 97		/** turning on/off multiple selection (works while clicking and holding CTRL)*/
 98		Optional<bool> multi_select;
 99
100		/** don't allow to deselect all selected items (for mouse events on items only) */
101		Optional<bool> keep_one_selected;
102
103		/** try to keep selection visible after reshape */
104		Optional<bool> keep_selection_visible_on_reshape;
105
106		/** padding between items */
107		Optional<U32> item_pad; 
108
109		/** textbox with info message when list is empty*/
110		Optional<LLTextBox::Params> no_items_text;
111
112		Params();
113	};
114	
115	// disable traversal when finding widget to hand focus off to
116	/*virtual*/ BOOL canFocusChildren() const { return FALSE; }
117
118	/**
119	 * Connects callback to signal called when Return key is pressed.
120	 */
121	boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
122
123	/** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */
124	virtual void reshape(S32 width, S32 height, BOOL called_from_parent  = TRUE);
125
126	/** Returns full rect of child panel */
127	const LLRect& getItemsRect() const;
128
129	LLRect getRequiredRect() { return getItemsRect(); }
130
131	/** Returns distance between items */
132	const S32 getItemsPad() { return mItemPad; }
133
134	/**
135	 * Adds and item and LLSD value associated with it to the list at specified position
136	 * @return true if the item was added, false otherwise 
137	 */
138	virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true);
139
140	/**
141	 * Insert item_to_add along with associated value to the list right after the after_item.
142	 * @return true if the item was successfully added, false otherwise
143	 */
144	virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null);
145
146	/** 
147	 * Remove specified item
148	 * @return true if the item was removed, false otherwise 
149	 */
150	virtual bool removeItem(LLPanel* item, bool rearrange = true);
151
152	/** 
153	 * Remove an item specified by value
154	 * @return true if the item was removed, false otherwise 
155	 */
156	virtual bool removeItemByValue(const LLSD& value, bool rearrange = true);
157
158	/** 
159	 * Remove an item specified by uuid
160	 * @return true if the item was removed, false otherwise 
161	 */
162	virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true);
163
164	/** 
165	 * Get an item by value 
166	 * @return the item as LLPanel if associated with value, NULL otherwise
167	 */
168	virtual LLPanel* getItemByValue(const LLSD& value) const;
169
170	template<class T>
171	T* getTypedItemByValue(const LLSD& value) const
172	{
173		return dynamic_cast<T*>(getItemByValue(value));
174	}
175
176	/** 
177	 * Select or deselect specified item based on select
178	 * @return true if succeed, false otherwise
179	 */
180	virtual bool selectItem(LLPanel* item, bool select = true);
181
182	/** 
183	 * Select or deselect an item by associated value based on select
184	 * @return true if succeed, false otherwise
185	 */
186	virtual bool selectItemByValue(const LLSD& value, bool select = true);
187
188	/** 
189	 * Select or deselect an item by associated uuid based on select
190	 * @return true if succeed, false otherwise
191	 */
192	virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true);
193
194	/**
195	 * Get all panels stored in the list.
196	 */
197	virtual void getItems(std::vector<LLPanel*>& items) const;
198
199	/**
200	 * Get all items values.
201	 */
202	virtual void getValues(std::vector<LLSD>& values) const;
203	
204	/**
205	 * Get LLSD associated with the first selected item
206	 */
207	virtual LLSD getSelectedValue() const;
208
209	/**
210	 * Get LLSD's associated with selected items.
211	 * @param selected_values std::vector being populated with LLSD associated with selected items
212 	 */
213	virtual void getSelectedValues(std::vector<LLSD>& selected_values) const;
214
215
216	/** 
217	 * Get LLUUID associated with selected item
218	 * @return LLUUID if such was associated with selected item 
219	 */
220	virtual LLUUID getSelectedUUID() const;
221
222	/** 
223	 * Get LLUUIDs associated with selected items
224	 * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items
225	 */
226	virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const;
227
228	/** Get the top selected item */
229	virtual LLPanel* getSelectedItem() const;
230
231	/** 
232	 * Get selected items
233	 * @param selected_items An std::vector being populated with pointers to selected items
234	 */
235	virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const;
236
237
238	/**
239	 * Resets selection of items.
240	 * 
241	 * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true"
242	 * argument for current Flat List.
243	 * @param no_commit_on_deselection - if true onCommit callback will not be called
244	 */
245	virtual void resetSelection(bool no_commit_on_deselection = false);
246
247	/**
248	 * Sets comment text which will be shown in the list is it is empty.
249	 *
250	 * Textbox to hold passed text is created while this method is called at the first time.
251	 *
252	 * @param comment_text - string to be shown as a comment.
253	 */
254	void setNoItemsCommentText( const std::string& comment_text);
255
256	/** Turn on/off multiple selection support */
257	void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; }
258
259	/** Turn on/off selection support */
260	void setAllowSelection(bool can_select) { mAllowSelection = can_select; }
261
262	/** Sets flag whether onCommit should be fired if selection was changed */
263	// FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly.
264	void setCommitOnSelectionChange(bool b)		{ mCommitOnSelectionChange = b; }
265
266	/** Get number of selected items in the list */
267	U32 numSelected() const {return mSelectedItemPairs.size(); }
268
269	/** Get number of (visible) items in the list */
270	U32 size(const bool only_visible_items = true) const;
271
272	/** Removes all items from the list */
273	virtual void clear();
274
275	/**
276	 * Removes all items that can be detached from the list but doesn't destroy
277	 * them, caller responsible to manage items after they are detached.
278	 * Detachable item should accept "detach" action via notify() method,
279	 * where it disconnect all callbacks, does other valuable routines and
280	 * return 1.
281	 */
282	void detachItems(std::vector<LLPanel*>& detached_items);
283
284	/**
285	 * Set comparator to use for future sorts.
286	 * 
287	 * This class does NOT manage lifetime of the comparator
288	 * but assumes that the comparator is always alive.
289	 */
290	void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
291	void sort();
292
293	bool updateValue(const LLSD& old_value, const LLSD& new_value);
294
295	void scrollToShowFirstSelectedItem();
296
297	void selectFirstItem	();
298	void selectLastItem		();
299
300	virtual S32	notify(const LLSD& info) ;
301
302protected:
303
304	/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
305	typedef std::pair<LLPanel*, LLSD> item_pair_t;
306
307	typedef std::list<item_pair_t*> pairs_list_t;
308	typedef pairs_list_t::iterator pairs_iterator_t;
309	typedef pairs_list_t::const_iterator pairs_const_iterator_t;
310
311	/** An adapter for a ItemComparator */
312	struct ComparatorAdaptor
313	{
314		ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {};
315
316		bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2)
317		{
318			return mComparator.compare(item_pair1->first, item_pair2->first);
319		}
320
321		const ItemComparator& mComparator;
322	};
323
324
325	friend class LLUICtrlFactory;
326	LLFlatListView(const LLFlatListView::Params& p);
327
328	/** Manage selection on mouse events */
329	void onItemMouseClick(item_pair_t* item_pair, MASK mask);
330
331	void onItemRightMouseClick(item_pair_t* item_pair, MASK mask);
332
333	/**
334	 *	Updates position of items.
335	 *	It does not take into account invisible items.
336	 */
337	virtual void rearrangeItems();
338
339	virtual item_pair_t* getItemPair(LLPanel* item) const;
340
341	virtual item_pair_t* getItemPair(const LLSD& value) const;
342
343	virtual bool selectItemPair(item_pair_t* item_pair, bool select);
344
345	virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection);
346
347	virtual BOOL canSelectAll() const;
348	virtual void selectAll();
349
350	virtual bool isSelected(item_pair_t* item_pair) const;
351
352	virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange);
353
354	/**
355	 * Notify parent about changed size of internal controls with "size_changes" action
356	 * 
357	 * Size includes Items Rect width and either Items Rect height or comment text height.
358	 * Comment text height is included if comment text is set and visible.
359	 * List border size is also included into notified size.
360	 */
361	void notifyParentItemsRectChanged();
362
363	virtual BOOL handleKeyHere(KEY key, MASK mask);
364
365	virtual BOOL postBuild();
366
367	virtual void onFocusReceived();
368
369	virtual void onFocusLost();
370
371	virtual void draw();
372
373	LLRect getLastSelectedItemRect();
374
375	void   ensureSelectedVisible();
376
377private:
378
379	void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;}
380
381	void setNoItemsCommentVisible(bool visible) const;
382
383protected:
384
385	/** Comparator to use when sorting the list. */
386	const ItemComparator* mItemComparator;
387
388
389private:
390
391	LLPanel* mItemsPanel;
392
393	S32 mItemsNoScrollWidth;
394
395	S32 mBorderThickness;
396
397	/** Items padding */
398	S32 mItemPad;
399
400	/** Selection support flag */
401	bool mAllowSelection;
402
403	/** Multiselection support flag, ignored if selection is not supported */
404	bool mMultipleSelection;
405
406	/**
407	 * Flag specified whether onCommit be called if selection is changed in the list.
408	 * 
409	 * Can be ignored in the resetSelection() method.
410	 * @see resetSelection()
411	 */
412	bool mCommitOnSelectionChange;
413
414	bool mKeepOneItemSelected;
415
416	bool mIsConsecutiveSelection;
417
418	bool mKeepSelectionVisibleOnReshape;
419
420	/** All pairs of the list */
421	pairs_list_t mItemPairs;
422
423	/** Selected pairs for faster access */
424	pairs_list_t mSelectedItemPairs;
425
426	/**
427	 * Rectangle contained previous size of items parent notified last time.
428	 * Is used to reduce amount of parentNotify() calls if size was not changed.
429	 */
430	LLRect mPrevNotifyParentRect;
431
432	LLTextBox* mNoItemsCommentTextbox;
433
434	LLViewBorder* mSelectedItemsBorder;
435
436	commit_signal_t	mOnReturnSignal;
437};
438
439/**
440 * Extends LLFlatListView functionality to show different messages when there are no items in the
441 * list depend on whether they are filtered or not.
442 *
443 * Class provides one message per case of empty list.
444 * It also provides protected updateNoItemsMessage() method to be called each time when derived list
445 * is changed to update base mNoItemsCommentTextbox value.
446 *
447 * It is implemented to avoid duplication of this functionality in concrete implementations of the
448 * lists. It is intended to be used as a base class for lists which should support two different
449 * messages for empty state. Can be improved to support more than two messages via state-to-message map.
450 */
451class LLFlatListViewEx : public LLFlatListView
452{
453public:
454	LOG_CLASS(LLFlatListViewEx);
455
456	struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
457	{
458		/**
459		 * Contains a message for empty list when it does not contain any items at all.
460		 */
461		Optional<std::string>	no_items_msg;
462
463		/**
464		 * Contains a message for empty list when its items are removed by filtering.
465		 */
466		Optional<std::string>	no_filtered_items_msg;
467		Params();
468	};
469
470	// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
471	// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
472	void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
473	void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
474
475	bool getForceShowingUnmatchedItems();
476
477	void setForceShowingUnmatchedItems(bool show);
478
479	/**
480	 * Sets up new filter string and filters the list.
481	 */
482	void setFilterSubString(const std::string& filter_str);
483	
484	/**
485	 * Filters the list, rearranges and notifies parent about shape changes.
486	 * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
487	 */
488	void filterItems();
489
490	/**
491	 * Returns true if last call of filterItems() found at least one matching item
492	 */
493	bool hasMatchedItems();
494
495protected:
496	LLFlatListViewEx(const Params& p);
497
498	/**
499	 * Applies a message for empty list depend on passed argument.
500	 *
501	 * @param filter_string - if is not empty, message for filtered items will be set, otherwise for
502	 * completely empty list. Value of filter string will be passed as search_term in SLURL.
503	 */
504	void updateNoItemsMessage(const std::string& filter_string);
505
506private:
507	std::string mNoFilteredItemsMsg;
508	std::string mNoItemsMsg;
509	std::string	mFilterSubString;
510	/**
511	 * Show list items that don't match current filter
512	 */
513	bool mForceShowingUnmatchedItems;
514	/**
515	 * True if last call of filterItems() found at least one matching item
516	 */
517	bool mHasMatchedItems;
518};
519
520#endif