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  */
50 class CMuleListCtrl : public MuleExtern::wxGenericListCtrl
51 {
52 public:
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 	 */
SetSortFunc(MuleListCtrlCompare func)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 	 */
ClearAll()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 	 */
DeleteColumn(int WXUNUSED (col))222 	bool DeleteColumn(int WXUNUSED(col))	{ wxFAIL; return false; }
223 
224 	/**
225 	 * Indicates if we're in the process of sorting.
226 	 */
IsSorting()227 	bool IsSorting() const { return m_isSorting; }
228 
229 protected:
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 	 */
SetTableName(const wxString & name)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 	 */
GetSortColumn()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 	 */
GetSortOrder()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 
355 private:
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:
MuleSortData(CSortingList sort_orders,MuleListCtrlCompare sort_func)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;
ColNameEntry(int _index,int _defaultWidth,const 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