1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26#ifndef MULELISTCTRL_H
27#define MULELISTCTRL_H
28
29#ifdef _WIN32
30#include <wx/msw/winundef.h>
31#endif
32
33#include <wx/defs.h> // Do_not_auto_remove (Mac, Win32, and just good practice)
34#include "extern/wxWidgets/listctrl.h"
35
36#include <vector>
37#include <list>
38
39/**
40 * Enhanced wxListCtrl provided custom-drawing among other things.
41 *
42 * This class provides these features which the original wxListCtrl lacks:
43 *  - Automatic sort arrows upon clicks on the column headers
44 *  - Custom drawing of items.
45 *  - Hiding of columns through auto-generated popup-menu.
46 *  - Helper function for inserting items pre-sorted.
47 *  - Loading and saving of column properties.
48 *  - Selection of items by typing an initial part of the text (TTS).
49 */
50class CMuleListCtrl : public MuleExtern::wxGenericListCtrl
51{
52public:
53	/**
54	 * The various ways in which a column can be sorted.
55	 *
56	 * If SORT_DES is not set, sorting is taken to be
57	 * ascending. If SORT_ALT is not set, sorting is
58	 * taken to be normal.
59	 */
60	enum MLOrder
61	{
62		//! If set, sorting is to be in descending order.
63		SORT_DES	= 0x1000,
64
65		//! If sorting should use alternate method.
66		//! Is specified in with or without DEC.
67		SORT_ALT	= 0x2000
68	};
69
70	//! Mask which covers the column part of the sort-data.
71	static const unsigned COLUMN_MASK = 0xfff;
72
73	//! Mask which covers the sorting part of the sort-data.
74	static const unsigned SORTING_MASK = 0x3000;
75
76	/**
77	 * Constructor.
78	 *
79	 * @see wxGenericListCtrl::wxGenericListCtrl for documentation of parameters.
80	 */
81	 CMuleListCtrl(
82		       wxWindow *parent,
83		       wxWindowID winid = -1,
84		       const wxPoint &pos = wxDefaultPosition,
85		       const wxSize &size = wxDefaultSize,
86		       long style = wxLC_ICON,
87		       const wxValidator& validator = wxDefaultValidator,
88		       const wxString &name = wxT("mulelistctrl") );
89
90	/**
91	 * Destructor.
92	 *
93	 * If a name for the table has been specified with SetTableName, then
94	 * column settings will be saved automatically.
95	 */
96	virtual ~CMuleListCtrl();
97
98	/**
99	 * Saves column settings.
100	 *
101	 * Currently saves the width of all columns, hidden columns, the column
102	 * to sort by and in which direction to sort.
103	 */
104	virtual void SaveSettings();
105
106	/**
107	 * Loads column settings.
108	 *
109	 * Currently loads the width of all columns, hidden columns, the column
110	 * to sort by and in which direction to sort. This function also ensures
111	 * that the items are sorted after the settings have been read.
112	 */
113	virtual void LoadSettings();
114
115	/**
116	 * This function tries to locate the best place to insert an item.
117	 *
118	 * @param The userdata of the new item.
119	 *
120	 * This function does a binary type search to locate the best place to
121	 * insert the new item with the specified userdata. It then returns the
122	 * item after this position. To do this, the sorter-function must be set
123	 * through the SetSortFunc function, otherwise it will just return the
124	 * position after the last item.
125	 */
126	long GetInsertPos( wxUIntPtr data );
127
128	/**
129	 * Sorts the list.
130	 *
131	 * Before you can use this function, you will need to specify a sorter
132	 * function using SetSortFunc. wxListCtrl needs such a function to
133	 * perform the sort.
134	 */
135	virtual void SortList();
136
137	//! The type of the list of item specific data
138	typedef std::vector<wxUIntPtr> ItemDataList;
139
140	/**
141	 * Returns a list the user-data of all selected items.
142	 *
143	 * @return A list of data associated with the selected items.
144	 *
145	 * This function will return the user-data for each selected item in a
146	 * vector, which can then be manipulated with regards to changes made
147	 * in the current order of the listctrl items.
148	 */
149	ItemDataList GetSelectedItems() const;
150
151	/**
152	 * Sets the sorter function.
153	 *
154	 * @param func
155	 *
156	 * See the documentation on wxListCtrl::SortItems for more information
157	 * about the expected function type.
158	 */
159	void SetSortFunc(MuleListCtrlCompare func)	{ m_sort_func = func; }
160
161	/**
162	 * Deselects all selected items, but does not change focus.
163	 */
164	void ClearSelection();
165
166	/**
167	 * Insert a new column.
168	 *
169	 * @param[in] col	Column will be inserted at this position.
170	 * @param[in] heading	Heading text for the column.
171	 * @param[in] format	Format (alignment) of the column.
172	 * @param[in] width	The column width.
173	 * @param[in] name	Internal name of the column.
174	 *
175	 * We override this method to allow a name to be specified for each
176	 * column. The name is used for saving/loading column settings
177	 * independently of their index. It is necessary to set a unique name
178	 * for each column, to let column settings be saved/loaded. If you
179	 * don't set a name for a column, settings for that column won't be
180	 * saved.
181	 *
182	 * Requirements about column names:
183	 * - they must not contain the ':' (colon) and ',' (comma) characters,
184	 * - they should be at least one character long.
185	 *
186	 * @note Changing the internal name of one column results in width of
187	 * that column being reset to default, and if sorting was done by that
188	 * column, sorting being forgotten. If you change the name of a column,
189	 * don't forget to update the list GetOldColumnOrder() returns, if
190	 * necessary.
191	 *
192	 * For more information refer to the wxWidgets documentation of
193	 * wxListCtrl::InsertColumn()
194	 */
195	long InsertColumn(
196			  long col,
197			  const wxString& heading,
198			  int format = wxLIST_FORMAT_LEFT,
199			  int width = -1,
200			  const wxString& name = wxEmptyString
201			  );
202
203	/**
204	 * Clears all items and all columns.
205	 *
206	 * Intercepted to clear column name list.
207	 *
208	 * For more information see the wxWidgets documentation of
209	 * wxListCtrl::ClearAll()
210	 */
211	void ClearAll()
212	{
213		m_column_names.clear();
214		MuleExtern::wxGenericListCtrl::ClearAll();
215	}
216
217	/**
218	 * Delete one column from the list.
219	 *
220	 * Not implemented yet, intercepted here just as a sanity check.
221	 */
222	bool DeleteColumn(int WXUNUSED(col))	{ wxFAIL; return false; }
223
224	/**
225	 * Indicates if we're in the process of sorting.
226	 */
227	bool IsSorting() const { return m_isSorting; }
228
229protected:
230
231	/**
232	 * Must be overwritten to enable alternate sorting.
233	 *
234	 * @param The column being sorted.
235	 *
236	 * Subclasses of CMuleListCtrl can allow alternative sorting
237	 * of columns. This is done by overriding this function and
238	 * returning true for the columns where alternative sorting
239	 * is desired.
240	 */
241	virtual bool AltSortAllowed(unsigned column) const;
242
243	/**
244	 * Returns the string used when selecting rows via Type-To-Select.
245	 *
246	 * @param item The index of the item being examined.
247	 *
248	 * By default, this function simply returns the text in the first
249	 * column for the given item. However, when owner-drawing is
250	 * enabled, this function _must_ be overriden.
251	 */
252	virtual wxString GetTTSText(unsigned item) const;
253
254	/**
255	 * Sets the internally used table-name.
256	 *
257	 * @param name The new name or an empty string to disable.
258	 *
259	 * You need to call this function with a unique name before you can
260	 * make use of the LoadSettings/SaveSettings functions. CMuleListCtrl
261	 * uses the name specified in this command to create unique keynames.
262	 */
263	void SetTableName(const wxString& name)		{ m_name = name; }
264
265	/**
266	 * Return old column order.
267	 *
268	 * @return The pre-2.2.2 column order.
269	 *
270	 * This function should be overridden in descendant classes to return a
271	 * comma-separated list of the old column order, when column data was
272	 * saved/loaded by index. The default implementation returns an empty
273	 * string, meaning that old settings (if any) should be discarded.
274	 *
275	 * @note When you add or remove columns from the list control, DO NOT
276	 * change this list. This list may only be updated if you changed a
277	 * column name that is already in this list, to reflect the name
278	 * change. List order also must be preserved.
279	 */
280	virtual wxString GetOldColumnOrder() const;
281
282	/**
283	 * Returns the column which is currently used to sort the list.
284	 */
285	unsigned GetSortColumn() const	{ return m_sort_orders.front().first; }
286
287	/**
288	 * Returns the current sorting order, a combination of the DES and ALT flags.
289	 */
290	unsigned GetSortOrder() const	{ return m_sort_orders.front().second; }
291
292	/**
293	 * Set the sort column
294	 *
295	 * @param column The column with which the list should be sorted.
296	 * @param order The order in which to sort the column.
297	 *
298	 * Note that attempting to sort a column in an unsupported order
299	 * is an illegal operation.
300	 */
301	virtual void SetSorting(unsigned column, unsigned order);
302
303	/**
304	 * Returns true if the item is sorted compared to its neighbours.
305	 */
306	bool IsItemSorted(long item);
307
308	/**
309	 * Check and fix selection state.
310	 *
311	 * @param event The event which triggered the selection.
312	 * @return The index of the item selected or -1 if none.
313	 *
314	 * This function checks if the clicked item is selected.
315	 * If not, then the item is selected and all other items
316	 * are deselected.
317	 */
318	//@{
319	long CheckSelection(wxListEvent& event);
320	long CheckSelection(wxMouseEvent& event);
321	//@}
322
323	/**
324	 * Event handler for right-clicks on the column headers.
325	 */
326	void OnColumnRClick(wxListEvent& evt);
327
328	/**
329	 * Event handler for left-clicks on the column headers.
330	 */
331	void OnColumnLClick(wxListEvent& evt);
332
333	/**
334	 * Event handler for the hide/show menu items.
335	 */
336	void OnMenuSelected(wxCommandEvent& evt);
337
338	/**
339	 * Event handler for the mouse wheel.
340	 */
341	void OnMouseWheel(wxMouseEvent &event);
342
343	/**
344	 * Event handler for key-presses, needed by TTS.
345	 */
346	void OnChar(wxKeyEvent& evt);
347
348	/**
349	 * Event handler for item selection/deletion, needed by TTS.
350	 */
351	void OnItemSelected(wxListEvent& evt);
352	void OnItemDeleted(wxListEvent& evt);
353	void OnAllItemsDeleted(wxListEvent& evt);
354
355private:
356	/**
357	 * Resets the current TTS session.
358	 */
359	void ResetTTS();
360
361	/**
362	 * Sets the image of a specific column.
363	 *
364	 * @param col The column to change.
365	 * @param order The sorting order to represent. Zero unsets the image.
366	 */
367	void SetColumnImage(unsigned col, int image);
368
369	//! The name of the table. Used to load/save settings.
370	wxString		m_name;
371
372	//! The sorter function needed by wxListCtrl.
373	MuleListCtrlCompare	m_sort_func;
374
375	//! Contains the current search string.
376	wxString		m_tts_text;
377
378	//! Timestamp for the last TTS event.
379	unsigned		m_tts_time;
380
381	//! The index of the last item selected via TTS.
382	int			m_tts_item;
383
384	/**
385	 * Wrapper around the user-provided sorter function.
386	 *
387	 * This function ensures that items are sorted in the order
388	 * specified by clicking on column-headers, and also enforces
389	 * that different entries are never considered equal. This is
390	 * required for lists that make use of child-items, since
391	 * otherwise, parents may not end up properly located in
392	 * relation to child-items.
393	 */
394	static int wxCALLBACK SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData);
395
396	/** Compares two items in the list, using the current sort sequence. */
397	int CompareItems(wxUIntPtr item1, wxUIntPtr item2);
398
399	//! This pair contains a column number and its sorting order.
400	typedef std::pair<unsigned, unsigned> CColPair;
401	typedef std::list<CColPair> CSortingList;
402
403	class MuleSortData {
404	public:
405		MuleSortData(CSortingList sort_orders, MuleListCtrlCompare sort_func) : m_sort_orders(sort_orders), m_sort_func(sort_func) { };
406
407		CSortingList m_sort_orders;
408		MuleListCtrlCompare m_sort_func;
409	};
410
411	//! This list contains in order the columns sequence to sort by.
412	CSortingList m_sort_orders;
413
414	/**
415	 * Get the column name by index.
416	 *
417	 * @param[in] column Index of the column whose name we're looking for.
418	 *
419	 * @return The column name or an empty string if index is invalid
420	 * (out of range), or the column name hasn't been set.
421	 */
422	const wxString& GetColumnName(int column) const;
423
424	/**
425	 * Get the column default width by index.
426	 *
427	 * @param[in] column Index of the column whose name we're looking for.
428	 *
429	 * @return The column default width or wx default width if index is invalid
430	 * (out of range), or the column name hasn't been set.
431	 */
432	int GetColumnDefaultWidth(int column) const;
433
434	/**
435	 * Get column index by name.
436	 *
437	 * @param[in] name Internal name of the colunm whose index is needed.
438	 *
439	 * @return The column index, or -1 in case the name was invalid.
440	 */
441	int GetColumnIndex(const wxString& name) const;
442
443	/**
444	 * Find out the new index of the column by the old index.
445	 *
446	 * @param[in] oldindex Old column index which we want to turn into a
447	 * new index.
448	 *
449	 * @return The new index of the column, or -1 if an error occured.
450	 */
451	int GetNewColumnIndex(int oldindex) const;
452
453	/**
454	 * Parses old config entries.
455	 *
456	 * @param[in] sortOrders	Old sort orders line.
457	 * @param[in] columnWidths	Old column widths line.
458	 */
459	void ParseOldConfigEntries(const wxString& sortOrders, const wxString& columnWidths);
460
461	/// This class contains a column index, its default width and its name.
462	class ColNameEntry {
463	public:
464		int index;
465		int	defaultWidth;
466		wxString name;
467		ColNameEntry(int _index, int _defaultWidth, const wxString& _name)
468			:	index(_index), defaultWidth(_defaultWidth), name(_name) {}
469	};
470
471	/// This list contains the columns' names.
472	typedef std::list<ColNameEntry>		ColNameList;
473
474	/// Container for column names, sorted by column index.
475	ColNameList	m_column_names;
476
477	/// This vector contains a cache of the columns' sizes.
478	typedef std::vector<int>		ColSizeVector;
479
480	/// Container for column sizes cache.
481	ColSizeVector	m_column_sizes;
482
483	// True while sorting.
484	bool m_isSorting;
485
486	DECLARE_EVENT_TABLE()
487};
488
489#endif // MULELISTCTRL_H
490// File_checked_for_headers
491