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