]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: wx/ctrlsub.h (read: "wxConTRoL with SUBitems") | |
3 | // Purpose: wxControlWithItems interface | |
4 | // Author: Vadim Zeitlin | |
5 | // Modified by: | |
6 | // Created: 22.10.99 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) wxWidgets team | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #ifndef _WX_CTRLSUB_H_BASE_ | |
13 | #define _WX_CTRLSUB_H_BASE_ | |
14 | ||
15 | #include "wx/defs.h" | |
16 | ||
17 | #if wxUSE_CONTROLS | |
18 | ||
19 | #include "wx/arrstr.h" | |
20 | #include "wx/control.h" // base class | |
21 | ||
22 | // ---------------------------------------------------------------------------- | |
23 | // wxItemContainer defines an interface which is implemented by all controls | |
24 | // which have string subitems each of which may be selected. | |
25 | // | |
26 | // It is decomposed in wxItemContainerImmutable which omits all methods | |
27 | // adding/removing items and is used by wxRadioBox and wxItemContainer itself. | |
28 | // | |
29 | // Examples: wxListBox, wxCheckListBox, wxChoice and wxComboBox (which | |
30 | // implements an extended interface deriving from this one) | |
31 | // ---------------------------------------------------------------------------- | |
32 | ||
33 | class WXDLLIMPEXP_CORE wxItemContainerImmutable | |
34 | { | |
35 | public: | |
36 | wxItemContainerImmutable() { } | |
37 | virtual ~wxItemContainerImmutable(); | |
38 | ||
39 | // accessing strings | |
40 | // ----------------- | |
41 | ||
42 | virtual unsigned int GetCount() const = 0; | |
43 | bool IsEmpty() const { return GetCount() == 0; } | |
44 | ||
45 | virtual wxString GetString(unsigned int n) const = 0; | |
46 | wxArrayString GetStrings() const; | |
47 | virtual void SetString(unsigned int n, const wxString& s) = 0; | |
48 | ||
49 | // finding string natively is either case sensitive or insensitive | |
50 | // but never both so fall back to this base version for not | |
51 | // supported search type | |
52 | virtual int FindString(const wxString& s, bool bCase = false) const | |
53 | { | |
54 | unsigned int count = GetCount(); | |
55 | ||
56 | for ( unsigned int i = 0; i < count ; ++i ) | |
57 | { | |
58 | if (GetString(i).IsSameAs( s , bCase )) | |
59 | return (int)i; | |
60 | } | |
61 | ||
62 | return wxNOT_FOUND; | |
63 | } | |
64 | ||
65 | ||
66 | // selection | |
67 | // --------- | |
68 | ||
69 | virtual void SetSelection(int n) = 0; | |
70 | virtual int GetSelection() const = 0; | |
71 | ||
72 | // set selection to the specified string, return false if not found | |
73 | bool SetStringSelection(const wxString& s); | |
74 | ||
75 | // return the selected string or empty string if none | |
76 | virtual wxString GetStringSelection() const; | |
77 | ||
78 | // this is the same as SetSelection( for single-selection controls but | |
79 | // reads better for multi-selection ones | |
80 | void Select(int n) { SetSelection(n); } | |
81 | ||
82 | ||
83 | protected: | |
84 | // check that the index is valid | |
85 | bool IsValid(unsigned int n) const { return n < GetCount(); } | |
86 | bool IsValidInsert(unsigned int n) const { return n <= GetCount(); } | |
87 | }; | |
88 | ||
89 | // ---------------------------------------------------------------------------- | |
90 | // wxItemContainer extends wxItemContainerImmutable interface with methods | |
91 | // for adding/removing items. | |
92 | // | |
93 | // Classes deriving from this one must override DoInsertItems() to implement | |
94 | // adding items to the control. This can often be implemented more efficiently | |
95 | // than simply looping over the elements and inserting them but if this is not | |
96 | // the case, the generic DoInsertItemsInLoop can be used in implementation, but | |
97 | // in this case DoInsertItem() needs to be overridden. | |
98 | // ---------------------------------------------------------------------------- | |
99 | ||
100 | class WXDLLIMPEXP_CORE wxItemContainer : public wxItemContainerImmutable | |
101 | { | |
102 | private: | |
103 | // AppendItems() and InsertItems() helpers just call DoAppend/InsertItems() | |
104 | // after doing some checks | |
105 | // | |
106 | // NB: they're defined here so that they're inlined when used in public part | |
107 | int AppendItems(const wxArrayStringsAdapter& items, | |
108 | void **clientData, | |
109 | wxClientDataType type) | |
110 | { | |
111 | if ( items.IsEmpty() ) | |
112 | return wxNOT_FOUND; | |
113 | ||
114 | return DoAppendItems(items, clientData, type); | |
115 | } | |
116 | ||
117 | int AppendItems(const wxArrayStringsAdapter& items) | |
118 | { | |
119 | return AppendItems(items, NULL, wxClientData_None); | |
120 | } | |
121 | ||
122 | int AppendItems(const wxArrayStringsAdapter& items, void **clientData) | |
123 | { | |
124 | wxASSERT_MSG( GetClientDataType() != wxClientData_Object, | |
125 | _T("can't mix different types of client data") ); | |
126 | ||
127 | return AppendItems(items, clientData, wxClientData_Void); | |
128 | } | |
129 | ||
130 | int AppendItems(const wxArrayStringsAdapter& items, | |
131 | wxClientData **clientData) | |
132 | { | |
133 | wxASSERT_MSG( GetClientDataType() != wxClientData_Void, | |
134 | _T("can't mix different types of client data") ); | |
135 | ||
136 | return AppendItems(items, reinterpret_cast<void **>(clientData), | |
137 | wxClientData_Object); | |
138 | } | |
139 | ||
140 | int InsertItems(const wxArrayStringsAdapter& items, | |
141 | unsigned int pos, | |
142 | void **clientData, | |
143 | wxClientDataType type) | |
144 | { | |
145 | wxASSERT_MSG( !IsSorted(), _T("can't insert items in sorted control") ); | |
146 | ||
147 | wxCHECK_MSG( pos <= GetCount(), wxNOT_FOUND, | |
148 | _T("position out of range") ); | |
149 | ||
150 | // not all derived classes handle empty arrays correctly in | |
151 | // DoInsertItems() and besides it really doesn't make much sense to do | |
152 | // this (for append it could correspond to creating an initially empty | |
153 | // control but why would anybody need to insert 0 items?) | |
154 | wxCHECK_MSG( !items.IsEmpty(), wxNOT_FOUND, | |
155 | _T("need something to insert") ); | |
156 | ||
157 | return DoInsertItems(items, pos, clientData, type); | |
158 | } | |
159 | ||
160 | int InsertItems(const wxArrayStringsAdapter& items, unsigned int pos) | |
161 | { | |
162 | return InsertItems(items, pos, NULL, wxClientData_None); | |
163 | } | |
164 | ||
165 | int InsertItems(const wxArrayStringsAdapter& items, | |
166 | unsigned int pos, | |
167 | void **clientData) | |
168 | { | |
169 | wxASSERT_MSG( GetClientDataType() != wxClientData_Object, | |
170 | _T("can't mix different types of client data") ); | |
171 | ||
172 | return InsertItems(items, pos, clientData, wxClientData_Void); | |
173 | } | |
174 | ||
175 | int InsertItems(const wxArrayStringsAdapter& items, | |
176 | unsigned int pos, | |
177 | wxClientData **clientData) | |
178 | { | |
179 | wxASSERT_MSG( GetClientDataType() != wxClientData_Void, | |
180 | _T("can't mix different types of client data") ); | |
181 | ||
182 | return InsertItems(items, pos, | |
183 | reinterpret_cast<void **>(clientData), | |
184 | wxClientData_Object); | |
185 | } | |
186 | ||
187 | public: | |
188 | wxItemContainer() { m_clientDataItemsType = wxClientData_None; } | |
189 | virtual ~wxItemContainer(); | |
190 | ||
191 | // adding items | |
192 | // ------------ | |
193 | ||
194 | // append single item, return its position in the control (which can be | |
195 | // different from the last one if the control is sorted) | |
196 | int Append(const wxString& item) | |
197 | { return AppendItems(item); } | |
198 | int Append(const wxString& item, void *clientData) | |
199 | { return AppendItems(item, &clientData); } | |
200 | int Append(const wxString& item, wxClientData *clientData) | |
201 | { return AppendItems(item, &clientData); } | |
202 | ||
203 | // append several items at once to the control, return the position of the | |
204 | // last item appended | |
205 | int Append(const wxArrayString& items) | |
206 | { return AppendItems(items); } | |
207 | int Append(const wxArrayString& items, void **clientData) | |
208 | { return AppendItems(items, clientData); } | |
209 | int Append(const wxArrayString& items, wxClientData **clientData) | |
210 | { return AppendItems(items, clientData); } | |
211 | int Append(unsigned int n, const wxString *items) | |
212 | { return AppendItems(wxArrayStringsAdapter(n, items)); } | |
213 | int Append(unsigned int n, const wxString *items, void **clientData) | |
214 | { return AppendItems(wxArrayStringsAdapter(n, items), clientData); } | |
215 | int Append(unsigned int n, | |
216 | const wxString *items, | |
217 | wxClientData **clientData) | |
218 | { return AppendItems(wxArrayStringsAdapter(n, items), clientData); } | |
219 | ||
220 | // only for RTTI needs (separate name) | |
221 | void AppendString(const wxString& item) | |
222 | { Append(item); } | |
223 | ||
224 | ||
225 | // inserting items: not for sorted controls! | |
226 | // ----------------------------------------- | |
227 | ||
228 | // insert single item at the given position, return its effective position | |
229 | int Insert(const wxString& item, unsigned int pos) | |
230 | { return InsertItems(item, pos); } | |
231 | int Insert(const wxString& item, unsigned int pos, void *clientData) | |
232 | { return InsertItems(item, pos, &clientData); } | |
233 | int Insert(const wxString& item, unsigned int pos, wxClientData *clientData) | |
234 | { return InsertItems(item, pos, &clientData); } | |
235 | ||
236 | // insert several items at once into the control, return the index of the | |
237 | // last item inserted | |
238 | int Insert(const wxArrayString& items, unsigned int pos) | |
239 | { return InsertItems(items, pos); } | |
240 | int Insert(const wxArrayString& items, unsigned int pos, void **clientData) | |
241 | { return InsertItems(items, pos, clientData); } | |
242 | int Insert(const wxArrayString& items, | |
243 | unsigned int pos, | |
244 | wxClientData **clientData) | |
245 | { return InsertItems(items, pos, clientData); } | |
246 | int Insert(unsigned int n, const wxString *items, unsigned int pos) | |
247 | { return InsertItems(wxArrayStringsAdapter(n, items), pos); } | |
248 | int Insert(unsigned int n, | |
249 | const wxString *items, | |
250 | unsigned int pos, | |
251 | void **clientData) | |
252 | { return InsertItems(wxArrayStringsAdapter(n, items), pos, clientData); } | |
253 | int Insert(unsigned int n, | |
254 | const wxString *items, | |
255 | unsigned int pos, | |
256 | wxClientData **clientData) | |
257 | { return InsertItems(wxArrayStringsAdapter(n, items), pos, clientData); } | |
258 | ||
259 | ||
260 | // replacing items | |
261 | // --------------- | |
262 | ||
263 | void Set(const wxArrayString& items) | |
264 | { Clear(); Append(items); } | |
265 | void Set(const wxArrayString& items, void **clientData) | |
266 | { Clear(); Append(items, clientData); } | |
267 | void Set(const wxArrayString& items, wxClientData **clientData) | |
268 | { Clear(); Append(items, clientData); } | |
269 | void Set(unsigned int n, const wxString *items) | |
270 | { Clear(); Append(n, items); } | |
271 | void Set(unsigned int n, const wxString *items, void **clientData) | |
272 | { Clear(); Append(n, items, clientData); } | |
273 | void Set(unsigned int n, const wxString *items, wxClientData **clientData) | |
274 | { Clear(); Append(n, items, clientData); } | |
275 | ||
276 | // deleting items | |
277 | // -------------- | |
278 | ||
279 | void Clear(); | |
280 | void Delete(unsigned int pos); | |
281 | ||
282 | ||
283 | // various accessors | |
284 | // ----------------- | |
285 | ||
286 | // The control may maintain its items in a sorted order in which case | |
287 | // items are automatically inserted at the right position when they are | |
288 | // inserted or appended. Derived classes have to override this method if | |
289 | // they implement sorting, typically by returning HasFlag(wxXX_SORT) | |
290 | virtual bool IsSorted() const { return false; } | |
291 | ||
292 | ||
293 | // client data stuff | |
294 | // ----------------- | |
295 | ||
296 | void SetClientData(unsigned int n, void* clientData); | |
297 | void* GetClientData(unsigned int n) const; | |
298 | ||
299 | void SetClientObject(unsigned int n, wxClientData* clientData); | |
300 | wxClientData* GetClientObject(unsigned int n) const; | |
301 | ||
302 | // return the type of client data stored in this control: usually it just | |
303 | // returns m_clientDataItemsType but must be overridden in the controls | |
304 | // which delegate their client data storage to another one (e.g. wxChoice | |
305 | // in wxUniv which stores data in wxListBox which it uses anyhow); don't | |
306 | // forget to override SetClientDataType() if you override this one | |
307 | // | |
308 | // NB: for this to work no code should ever access m_clientDataItemsType | |
309 | // directly but only via this function! | |
310 | virtual wxClientDataType GetClientDataType() const | |
311 | { return m_clientDataItemsType; } | |
312 | ||
313 | bool HasClientData() const | |
314 | { return GetClientDataType() != wxClientData_None; } | |
315 | bool HasClientObjectData() const | |
316 | { return GetClientDataType() == wxClientData_Object; } | |
317 | bool HasClientUntypedData() const | |
318 | { return GetClientDataType() == wxClientData_Void; } | |
319 | ||
320 | protected: | |
321 | // there is usually no need to override this method but you can do it if it | |
322 | // is more convenient to only do "real" insertions in DoInsertItems() and | |
323 | // to implement items appending here (in which case DoInsertItems() should | |
324 | // call this method if pos == GetCount() as it can still be called in this | |
325 | // case if public Insert() is called with such position) | |
326 | virtual int DoAppendItems(const wxArrayStringsAdapter& items, | |
327 | void **clientData, | |
328 | wxClientDataType type) | |
329 | { | |
330 | return DoInsertItems(items, GetCount(), clientData, type); | |
331 | } | |
332 | ||
333 | // this method must be implemented to insert the items into the control at | |
334 | // position pos which can be GetCount() meaning that the items should be | |
335 | // appended; for the sorted controls the position can be ignored | |
336 | // | |
337 | // the derived classes typically use AssignNewItemClientData() to | |
338 | // associate the data with the items as they're being inserted | |
339 | // | |
340 | // the method should return the index of the position the last item was | |
341 | // inserted into or wxNOT_FOUND if an error occurred | |
342 | virtual int DoInsertItems(const wxArrayStringsAdapter & items, | |
343 | unsigned int pos, | |
344 | void **clientData, | |
345 | wxClientDataType type) = 0; | |
346 | ||
347 | // before the client data is set for the first time for the control which | |
348 | // hadn't had it before, DoInitItemClientData() is called which gives the | |
349 | // derived class the possibility to initialize its client data storage only | |
350 | // when client data is really used | |
351 | virtual void DoInitItemClientData() { } | |
352 | virtual void DoSetItemClientData(unsigned int n, void *clientData) = 0; | |
353 | virtual void *DoGetItemClientData(unsigned int n) const = 0; | |
354 | ||
355 | virtual void DoClear() = 0; | |
356 | virtual void DoDeleteOneItem(unsigned int pos) = 0; | |
357 | ||
358 | ||
359 | // methods useful for the derived classes which don't have any better way | |
360 | // of adding multiple items to the control than doing it one by one: such | |
361 | // classes should call DoInsertItemsInLoop() from their DoInsert() and | |
362 | // override DoInsertOneItem() to perform the real insertion | |
363 | virtual int DoInsertOneItem(const wxString& item, unsigned int pos); | |
364 | int DoInsertItemsInLoop(const wxArrayStringsAdapter& items, | |
365 | unsigned int pos, | |
366 | void **clientData, | |
367 | wxClientDataType type); | |
368 | ||
369 | ||
370 | // helper for DoInsertItems(): n is the index into clientData, pos is the | |
371 | // position of the item in the control | |
372 | void AssignNewItemClientData(unsigned int pos, | |
373 | void **clientData, | |
374 | unsigned int n, | |
375 | wxClientDataType type); | |
376 | ||
377 | // free the client object associated with the item at given position and | |
378 | // set it to NULL (must only be called if HasClientObjectData()) | |
379 | void ResetItemClientObject(unsigned int n); | |
380 | ||
381 | // set the type of the client data stored in this control: override this if | |
382 | // you override GetClientDataType() | |
383 | virtual void SetClientDataType(wxClientDataType clientDataItemsType) | |
384 | { | |
385 | m_clientDataItemsType = clientDataItemsType; | |
386 | } | |
387 | ||
388 | private: | |
389 | // the type of the client data for the items | |
390 | wxClientDataType m_clientDataItemsType; | |
391 | }; | |
392 | ||
393 | // this macro must (unfortunately) be used in any class deriving from both | |
394 | // wxItemContainer and wxControl because otherwise there is ambiguity when | |
395 | // calling GetClientXXX() functions -- the compiler can't choose between the | |
396 | // two versions | |
397 | #define wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST \ | |
398 | void SetClientData(void *data) \ | |
399 | { wxEvtHandler::SetClientData(data); } \ | |
400 | void *GetClientData() const \ | |
401 | { return wxEvtHandler::GetClientData(); } \ | |
402 | void SetClientObject(wxClientData *data) \ | |
403 | { wxEvtHandler::SetClientObject(data); } \ | |
404 | wxClientData *GetClientObject() const \ | |
405 | { return wxEvtHandler::GetClientObject(); } \ | |
406 | void SetClientData(unsigned int n, void* clientData) \ | |
407 | { wxItemContainer::SetClientData(n, clientData); } \ | |
408 | void* GetClientData(unsigned int n) const \ | |
409 | { return wxItemContainer::GetClientData(n); } \ | |
410 | void SetClientObject(unsigned int n, wxClientData* clientData) \ | |
411 | { wxItemContainer::SetClientObject(n, clientData); } \ | |
412 | wxClientData* GetClientObject(unsigned int n) const \ | |
413 | { return wxItemContainer::GetClientObject(n); } | |
414 | ||
415 | class WXDLLIMPEXP_CORE wxControlWithItemsBase : public wxControl, | |
416 | public wxItemContainer | |
417 | { | |
418 | public: | |
419 | wxControlWithItemsBase() { } | |
420 | ||
421 | // we have to redefine these functions here to avoid ambiguities in classes | |
422 | // deriving from us which would arise otherwise because both base classses | |
423 | // have the methods with the same names - hopefully, a smart compiler can | |
424 | // optimize away these simple inline wrappers so we don't suffer much from | |
425 | // this | |
426 | wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST | |
427 | ||
428 | // usually the controls like list/combo boxes have their own background | |
429 | // colour | |
430 | virtual bool ShouldInheritColours() const { return false; } | |
431 | ||
432 | protected: | |
433 | // fill in the client object or data field of the event as appropriate | |
434 | // | |
435 | // calls InitCommandEvent() and, if n != wxNOT_FOUND, also sets the per | |
436 | // item client data | |
437 | void InitCommandEventWithItems(wxCommandEvent& event, int n); | |
438 | ||
439 | private: | |
440 | wxDECLARE_NO_COPY_CLASS(wxControlWithItemsBase); | |
441 | }; | |
442 | ||
443 | // define the platform-specific wxControlWithItems class | |
444 | #if defined(__WXMSW__) | |
445 | #include "wx/msw/ctrlsub.h" | |
446 | #elif defined(__WXMOTIF__) | |
447 | #include "wx/motif/ctrlsub.h" | |
448 | #else | |
449 | class WXDLLIMPEXP_CORE wxControlWithItems : public wxControlWithItemsBase | |
450 | { | |
451 | public: | |
452 | wxControlWithItems() { } | |
453 | ||
454 | private: | |
455 | DECLARE_ABSTRACT_CLASS(wxControlWithItems) | |
456 | wxDECLARE_NO_COPY_CLASS(wxControlWithItems); | |
457 | }; | |
458 | #endif | |
459 | ||
460 | #endif // wxUSE_CONTROLS | |
461 | ||
462 | #endif // _WX_CTRLSUB_H_BASE_ |