1 #ifndef CUSTOMVIRTLISTITEM_H_
2 #define CUSTOMVIRTLISTITEM_H_
3 
4 #include <wx/listctrl.h>
5 
6 #include <wx/timer.h>
7 #define IDD_TIP_TIMER 696
8 #define IDD_SORT_TIMER 697
9 
10 #include <vector>
11 
12 #include <utility>
13 #include <map>
14 
15 #include "useractions.h"
16 #include "helper/sortutil.h"
17 #include "utils/globalevents.h"
18 #include "utils/mixins.hh"
19 
20 const wxEventType ListctrlDoSortEventType = wxNewEventType();
21 
22 class ListctrlSortEvent : public wxCommandEvent
23 {
24 public:
25 	ListctrlSortEvent( int event_id = wxNewId() )
wxCommandEvent(ListctrlDoSortEventType,event_id)26 		: wxCommandEvent( ListctrlDoSortEventType, event_id )
27 	{}
28 };
29 
30 class SLTipWindow;
31 
32 /** \brief Used as base class for some ListCtrls throughout SL
33  * Provides generic functionality, such as column tooltips, possiblity to prohibit column resizing and selection modifiers. \n
34  * Some of the provided functionality only makes sense for single-select lists (see grouping) \n
35  * Note: the second template param is actually just a dummy to ensure the compiler generates distinct code in case we have different listctrls with same datatype
36  * Note: Tooltips are a bitch and anyone should feel free to revise them (koshi)
37  * \tparam the type of stored data
38  */
39 template < class DataImp, class ListCtrlImp >
40 class CustomVirtListCtrl : public wxListCtrl, public SL::NonCopyable
41 {
42 public:
43 	typedef DataImp DataType;
44 protected:
45 	typedef CustomVirtListCtrl< DataImp, ListCtrlImp> BaseType;
46 	typedef UserActions::ActionType ActionType;
47 	//! used to display tooltips for a certain amount of time
48 	wxTimer m_tiptimer;
49 	//! used to block sorting while mouse is moving
50 	wxTimer m_sort_timer;
51 	//! always set to the currrently displayed tooltip text
52 	wxString m_tiptext;
53 #if wxUSE_TIPWINDOW
54 	//! some wx implementations do not support this yet
55 	SLTipWindow* m_tipwindow;
56 	SLTipWindow** m_controlPointer;
57 #endif
58 	unsigned int m_columnCount;
59 
60 	struct colInfo {
colInfocolInfo61 		colInfo(int n, wxString l, wxString t, bool c, int s):
62 			col_num(n),
63 			label(l),
64 			tip(t),
65 			can_resize(c),
66 			size(s)
67 		{}
colInfocolInfo68 		colInfo():
69 			col_num(0),
70 			can_resize(false),
71 			size(0)
72 		{}
73 
74 		int col_num;
75 		wxString label;
76 		wxString tip;
77 		bool can_resize;
78 		int size;
79 	};
80 
81 	typedef std::vector<colInfo> colInfoVec;
82 
83 	//! maps outward column index to internal
84 	typedef std::map<unsigned int,unsigned int> ColumnMap;
85 
86 	/** global Tooltip thingies (ms)
87 	 */
88 	static const unsigned int m_tooltip_delay    = 1000;
89 	static const unsigned int m_tooltip_duration = 2000;
90 	static const unsigned int m_sort_block_time  = 1500;
91 
92 	/*** these are only meaningful in single selection lists ***/
93 	//! index of curently selected data
94 	long m_selected_index;
95 
96 	//! index of previously selected data
97 	long m_prev_selected_index;
98 	/***********************************************************/
99 
100 	//! stores info about the columns (wxString name,bool isResizable) - pairs
101 	colInfoVec m_colinfovec;
102 	//! primarily used to get coulumn index in mousevents (from cur. mouse pos)
103 	int getColumnFromPosition(wxPoint pos);
104 
105 	//! map: index in visible list <--> index in data vector
106 	typedef std::map<int,int> VisibilityMap;
107 	typedef VisibilityMap::iterator VisibilityMapIter;
108 	/** \brief list indexes of not-filtered items
109 	 * use like this: when adding items set identity mapping \n
110 		 m_visible_idxs[m_data.size() -1] = ( m_data.size() -1 ); \n
111 	   when filtering clear the map, iterate thru data and only set mapping for matching items in data \n
112 	   when acessing data (getColoumText etc.) always access data's index thru this map
113 	 **/
114 	VisibilityMap m_visible_idxs;
115 
116 
117 	wxPoint m_last_mouse_pos;
118 
119 	//! used as label for saving column widths
120 	wxString m_name;
121 
122 	//!controls if highlighting should be considered
123 	bool m_highlight;
124 
125 	//! which action should be considered?
126 	ActionType m_highlightAction;
127 
128 	const wxColour m_bg_color;
129 
130 	//! list should be sorted
131 	bool m_dirty_sort;
132 
133 	virtual void SetTipWindowText( const long item_hit, const wxPoint& position);
134 
135 	ColumnMap m_column_map;
136 
137 	/** @name Sort functionality
138 	 *
139 	 * @{
140 	 */
141 
142 	static SortOrder m_sortorder;
143 	unsigned int m_sort_criteria_count;
144 
145 	/** generic comparator that gets it's real functionality
146 	 * in derived classes via comapre callbakc func that
147 	 * performs the actual comparison of two items **/
148 	template < class ObjImp >
149 	struct ItemComparator {
150 		typedef ObjImp ObjType;
151 		SortOrder& m_order;
152 		typedef int (ListCtrlImp::*CmpFunc)  ( ObjType u1, ObjType u2, int, int ) const;
153 		CmpFunc m_cmp_func;
154 		const unsigned int m_num_criteria;
155 		const BaseType* m_listctrl;
156 
157 		/** \param order SortOrder map that defines which columns should be sorted in what directions
158 		 * \param func the comparison callback func. Should return -1,0,1 for less,equal,greater
159 		 * \param num_criteria set to 1,2 to limit sub-ordering
160 		 * \todo make order const reference to eliminate assumption about existence of entries
161 		 */
162 		ItemComparator( const BaseType* listctrl, SortOrder& order,CmpFunc func, const unsigned int num_criteria = 3 )
m_orderItemComparator163 			:m_order(order),
164 			 m_cmp_func(func),
165 			 m_num_criteria(num_criteria),
166 			 m_listctrl( listctrl )
167 		{}
168 
operatorItemComparator169 		bool operator () ( ObjType u1, ObjType u2 ) const {
170 			int res = (m_listctrl->asImp().*m_cmp_func)( u1, u2, m_order[0].col, m_order[0].direction );
171 			if ( res != 0 )
172 				return res < 0;
173 
174 			if ( m_num_criteria > 1 ) {
175 				res = (m_listctrl->asImp().*m_cmp_func)( u1, u2, m_order[1].col, m_order[1].direction );
176 				if ( res != 0 )
177 					return res < 0;
178 
179 				if ( m_num_criteria > 2 ) {
180 					res = (m_listctrl->asImp().*m_cmp_func)( u1, u2, m_order[2].col, m_order[2].direction );
181 					if ( res != 0 )
182 						return res < 0;
183 				}
184 			}
185 			return false;
186 		}
187 	};
188 
189 	typedef typename ItemComparator<DataImp>::CmpFunc CompareFunction;
190 
191 	//! compare func usable for types with well-defined ordering (and implemented ops <,>)
192 	template < typename Type >
compareSimple(Type o1,Type o2)193 	static inline int compareSimple( Type o1, Type o2 ) {
194 		if ( o1 < o2 )
195 			return -1;
196 		else if ( o1 > o2 )
197 			return 1;
198 		return 0;
199 	}
200 
201 	//! must be implemented in derived classes, should call the actual sorting on data and refreshitems
202 	virtual void Sort( ) = 0;
203 
204 public:
205 	/** only sorts if data is marked dirty, or force is true
206 	 * calls Freeze(), Sort(), Thaw() */
207 	void SortList( bool force = false );
208 	/** @}
209 	 */
210 
211 public:
212 	CustomVirtListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt,
213 			   const wxSize& sz,long style, const wxString& name, unsigned int sort_criteria_count, CompareFunction func, bool highlight = true,
214 			   UserActions::ActionType hlaction = UserActions::ActHighlight, bool periodic_sort = false, unsigned int periodic_sort_interval = 5000 /*miliseconds*/);
215 
216 	virtual ~CustomVirtListCtrl();
217 
218 	void OnSelected( wxListEvent& event );
219 	void OnDeselected( wxListEvent& event );
220 	/** @name Single Selection methods
221 	 * using these funcs in a multi selection list is meaningless at best, harmful in the worst case
222 	 * \todo insert debug asserts to catch that
223 	 * @{
224 	 */
225 	long GetSelectedIndex() const;
226 	void SetSelectedIndex(const long newindex);
227 	DataType GetDataFromIndex ( const  long index );
228 	const DataType GetDataFromIndex ( const  long index ) const;
229 	DataType GetSelectedData();
230 	/** @}
231 	 */
232 
233 	/** @name Multi Selection methods
234 	 * call this before example before sorting, inserting, etc
235 	 */
236 	void SaveSelection();
237 	void ResetSelection();
238 	//! and this afterwards
239 	void RestoreSelection();
240 	/** @}
241 	 */
242 
243 	//! intermediate function to add info to m_colinfovec after calling base class function
244 	void AddColumn(long i, int width, const wxString& label, const wxString& tip, bool = true);
245 	//! this event is triggered when delay timer (set in mousemotion) ended
246 	virtual void OnTimer(wxTimerEvent& event);
247 	//! prohibits resizin if so set in columnInfo
248 	void OnStartResizeCol(wxListEvent& event);
249 	//! we use this to automatically save column width after resizin
250 	virtual void OnEndResizeCol(wxListEvent& event);
251 	//! starts timer, sets tooltiptext
252 	virtual void OnMouseMotion(wxMouseEvent& event);
253 	//! stop timer (before displaying popup f.e.)
254 	void CancelTooltipTimer();
255 	//!Override to have tooltip timer cancelled automatically
256 	bool PopupMenu(wxMenu* menu, const wxPoint& pos = wxDefaultPosition);
257 	//! does nothing
258 	void noOp(wxMouseEvent& event);
259 	//! automatically get saved column width if already saved, otherwise use parameter and save new width
260 	virtual bool SetColumnWidth(int col, int& width);
261 	//! reset columns with current set size (only effects columns with auto-size)
262 	void ResetColumnSizes();
263 
264 	// funcs that should make things easier for group highlighting
265 	///all that needs to be implemented in child class for UpdateHighlights to work
266 
267 	wxListItemAttr* HighlightItemUser( const wxString& name ) const;
268 
269 	void SetHighLightAction( UserActions::ActionType action );
270 	void RefreshVisibleItems();
271 
272 	/** @name Multi Selection methods
273 	 * using these funcs in a single selection list is meaingless at best, harmful in the worst case
274 	 * \todo insert debug asserts to catch that
275 	 * @{
276 	 */
277 	void SelectAll();
278 	void SelectInverse();
279 	/** @}
280 	 */
281 
282 	//! sets selected index to -1
283 	void SelectNone();
284 
285 	//! marks the items in the control to be sorted
286 	void MarkDirtySort();
287 
288 	/** @name overloaded wxFunctions
289 	 * these are used to display items in virtual lists
290 	 * @{
291 	*/
292 	wxString OnGetItemText(long item, long column) const;
293 	int OnGetItemColumnImage(long item, long column) const;
294 	wxListItemAttr* OnGetItemAttr(long item) const;
295 
296 	//! when using the dummy column, we provide diff impl that adjust for that
297 	bool GetColumn(int col, wxListItem& item) const;
298 	bool SetColumn(int col, wxListItem& item);
299 	/** @}
300 	 */
301 
302 	//! delete all data, selections, and whatnot
303 	virtual void Clear();
304 
305 	//! handle sort order updates
306 	void OnColClick( wxListEvent& event );
307 
308 	virtual int GetIndexFromData( const DataType& data ) const = 0;
309 
310 	void ReverseOrder();
311 
312 	void OnQuit( wxCommandEvent& data );
313 	void StartTimer();
314 	void StopTimer();
315 
316 protected:
317 	typedef std::vector< DataImp > DataVector;
318 	typedef typename DataVector::iterator DataIter;
319 	typedef typename DataVector::const_iterator DataCIter;
320 	typedef typename DataVector::reverse_iterator DataRevIter;
321 	typedef typename DataVector::const_reverse_iterator DataRevCIter;
322 	DataVector m_data;
323 
324 	typedef DataType SelectedDataType;
325 	typedef std::vector< SelectedDataType > SelectedDataVector;
326 	SelectedDataVector m_selected_data;
327 
328 	//! the Comparator object passed to the SLInsertionSort function
329 	ItemComparator<DataType> m_comparator;
330 
331 	bool RemoveItem( const DataImp& item );
332 	bool AddItem( const DataImp& item );
333 
334 	long m_periodic_sort_timer_id;
335 	wxTimer m_periodic_sort_timer;
336 	bool m_periodic_sort;
337 	unsigned int m_periodic_sort_interval;
338 	void OnPeriodicSort( wxTimerEvent& evt );
339 	//! this is the sink for a custom event that can be used for async sort
340 	void OnSortEvent( wxCommandEvent& evt );
341 
342 public:
343 	DECLARE_EVENT_TABLE()
344 
345 private:
346 	typedef BaseType ThisType;
asImp()347 	ListCtrlImp& asImp() {
348 		return static_cast<ListCtrlImp&>(*this);
349 	}
asImp()350 	const ListCtrlImp& asImp() const {
351 		return static_cast<const ListCtrlImp&>(*this);
352 	}
353 
354 };
355 
356 template < class ListCtrlType > class SelectionSaver
357 {
358 	ListCtrlType& m_list;
359 
360 public:
SelectionSaver(ListCtrlType & list)361 	SelectionSaver( ListCtrlType& list)
362 		: m_list( list ) {
363 		m_list.SaveSelection();
364 	}
365 
~SelectionSaver()366 	~SelectionSaver() {
367 		m_list.RestoreSelection();
368 	}
369 };
370 
371 #include "customvirtlistctrl.cpp"
372 
373 #endif /*CUSTOMLISTITEM_H_*/
374 
375 /**
376     This file is part of SpringLobby,
377     Copyright (C) 2007-2011
378 
379     SpringLobby is free software: you can redistribute it and/or modify
380     it under the terms of the GNU General Public License version 2 as published by
381     the Free Software Foundation.
382 
383     SpringLobby is distributed in the hope that it will be useful,
384     but WITHOUT ANY WARRANTY; without even the implied warranty of
385     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
386     GNU General Public License for more details.
387 
388     You should have received a copy of the GNU General Public License
389     along with SpringLobby.  If not, see <http://www.gnu.org/licenses/>.
390 **/
391 
392