]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/cocoa/listbox.mm
set m_isBeingDeleted to true (only) in SendDestroyEvent(); call it as early as possib...
[wxWidgets.git] / src / cocoa / listbox.mm
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/cocoa/listbox.mm
3// Purpose: wxListBox
4// Author: David Elliott
5// Modified by:
6// Created: 2003/03/18
7// Id: $Id$
8// Copyright: (c) 2003 David Elliott
9// Licence: wxWidgets licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#if wxUSE_LISTBOX
15
16#include "wx/listbox.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/log.h"
20 #include "wx/app.h"
21#endif //WX_PRECOMP
22
23#include "wx/cocoa/string.h"
24#include "wx/cocoa/autorelease.h"
25#include "wx/cocoa/ObjcRef.h"
26#include "wx/cocoa/private/scrollview.h"
27#include "wx/cocoa/NSTableDataSource.h"
28
29#import <Foundation/NSArray.h>
30#import <Foundation/NSEnumerator.h>
31#import <AppKit/NSTableView.h>
32#import <AppKit/NSTableColumn.h>
33#import <AppKit/NSScrollView.h>
34#import <AppKit/NSCell.h>
35
36
37// ============================================================================
38// helper functions
39// ============================================================================
40
41static CGFloat _TableColumnMaxWidthForItems(NSTableColumn *tableColumn, NSArray *items)
42{
43 wxAutoNSAutoreleasePool pool;
44
45 NSCell *dataCell = [[[tableColumn dataCell] copy] autorelease];
46 CGFloat width = 0.0f;
47 NSEnumerator *itemEnum = [items objectEnumerator];
48 NSString *item;
49 while( (item = [itemEnum nextObject]) != nil )
50 {
51 [dataCell setStringValue: item];
52 NSSize itemSize = [dataCell cellSize];
53 CGFloat itemWidth = itemSize.width;
54 if(itemWidth > width)
55 width = itemWidth;
56 }
57 return width;
58}
59
60static void _SetWidthOfTableColumnToFitItems(NSTableColumn *tableColumn, NSArray *items)
61{
62 CGFloat width = _TableColumnMaxWidthForItems(tableColumn, items);
63 [tableColumn setWidth:width];
64 [tableColumn setMinWidth:width];
65}
66
67// ============================================================================
68// class wxListBox
69// ============================================================================
70
71IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
72BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
73END_EVENT_TABLE()
74WX_IMPLEMENT_COCOA_OWNER(wxListBox,NSTableView,NSControl,NSView)
75
76bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
77 const wxPoint& pos,
78 const wxSize& size,
79 const wxArrayString& choices,
80 long style,
81 const wxValidator& validator,
82 const wxString& name)
83{
84 wxCArrayString chs(choices);
85
86 return Create(parent, winid, pos, size, chs.GetCount(), chs.GetStrings(),
87 style, validator, name);
88}
89
90bool wxListBox::Create(wxWindow *parent, wxWindowID winid,
91 const wxPoint& pos,
92 const wxSize& size,
93 int n, const wxString choices[],
94 long style,
95 const wxValidator& validator,
96 const wxString& name)
97{
98/*
99wxLB_SINGLE
100Single-selection list.
101
102wxLB_MULTIPLE
103Multiple-selection list: the user can toggle multiple items on and off.
104
105wxLB_EXTENDED
106Extended-selection list: the user can select multiple items using the SHIFT key and the mouse or special key combinations.
107
108wxLB_HSCROLL
109Create horizontal scrollbar if contents are too wide (Windows only).
110
111wxLB_ALWAYS_SB
112Always show a vertical scrollbar.
113
114wxLB_NEEDED_SB
115Only create a vertical scrollbar if needed.
116
117wxLB_SORT
118The listbox contents are sorted in alphabetical order.
119*/
120 wxAutoNSAutoreleasePool pool;
121 if(!CreateControl(parent,winid,pos,size,style,validator,name))
122 return false;
123
124 // Provide the data
125 m_cocoaItems = wxGCSafeRetain([NSMutableArray arrayWithCapacity:n]);
126 for(int i=0; i < n; i++)
127 {
128 [m_cocoaItems addObject: wxNSStringWithWxString(choices[i])];
129 }
130 // Remove everything
131 m_itemClientData.Clear();
132 // Initialize n elements to NULL
133 m_itemClientData.SetCount(n,NULL);
134
135 SetNSTableView([[NSTableView alloc] initWithFrame: MakeDefaultNSRect(size)]);
136 [m_cocoaNSView release];
137 [GetNSTableView() setHeaderView: nil];
138
139 // Set up the data source
140 m_cocoaDataSource = [[WX_GET_OBJC_CLASS(wxCocoaNSTableDataSource) alloc] init];
141 [GetNSTableView() setDataSource:m_cocoaDataSource];
142
143 // Add the single column
144 NSTableColumn *tableColumn = [[NSTableColumn alloc] initWithIdentifier:nil];
145 [GetNSTableView() addTableColumn: tableColumn];
146 // By default, entries should not be editable
147 [tableColumn setEditable:NO];
148 [tableColumn release];
149
150 [GetNSTableView() sizeToFit];
151 // Finish
152 if(m_parent)
153 m_parent->CocoaAddChild(this);
154 // NSTableView does WEIRD things with sizes. Wrapping it in an
155 // NSScrollView seems to be the only reasonable solution.
156 CocoaCreateNSScrollView();
157 SetInitialFrameRect(pos,size);
158
159 if ((style & wxLB_NEEDED_SB) || (style & wxLB_ALWAYS_SB))
160 {
161 [m_wxCocoaScrollView->GetNSScrollView() setHasVerticalScroller: YES];
162 }
163
164 if (style & wxLB_HSCROLL)
165 {
166 [m_wxCocoaScrollView->GetNSScrollView() setHasHorizontalScroller: YES];
167 }
168
169 // We can't set auto-hiding individually for horizontal/vertical scrollers,
170 // so we have settled on always allowing hiding for both unless the vertical
171 // setting is "always show".
172 if (((style & wxLB_NEEDED_SB) || (style & wxLB_HSCROLL)) && !(style & wxLB_ALWAYS_SB))
173 {
174 if ([m_wxCocoaScrollView->GetNSScrollView() respondsToSelector:@selector(setAutohidesScrollers:)])
175 {
176 [m_wxCocoaScrollView->GetNSScrollView() setAutohidesScrollers: YES];
177 }
178 }
179
180 // Set up extended/multiple selection flags
181 if ((style & wxLB_EXTENDED) || (style & wxLB_MULTIPLE))
182 //diff is that mult requires shift down for multi selection
183 [GetNSTableView() setAllowsMultipleSelection:true];
184
185 [GetNSTableView() setAllowsColumnSelection:false];
186 _SetWidthOfTableColumnToFitItems(tableColumn, m_cocoaItems);
187 return true;
188}
189
190wxSize wxListBox::DoGetBestSize() const
191{
192 wxSize size = wxControlWithItems::DoGetBestSize();
193 // Limit best size to 100x100. It can be smaller if none of the items are very
194 // wide or if there aren't many items, but anything bigger than 100x100 ought
195 // to be asked for by the programmer. The 100x100 size is based on being barely
196 // enough for a scroller to be usable.
197 if(size.GetWidth() > 100)
198 size.SetWidth(100);
199 if(size.GetHeight() > 100)
200 size.SetHeight(100);
201 return size;
202}
203
204wxListBox::~wxListBox()
205{
206 [GetNSTableView() setDataSource: nil];
207 [m_cocoaDataSource release];
208 wxGCSafeRelease(m_cocoaItems);
209 m_cocoaItems = nil;
210 DisassociateNSTableView(GetNSTableView());
211}
212
213bool wxListBox::_WxCocoa_GetNeedsUpdate()
214{
215 return m_needsUpdate;
216}
217
218void wxListBox::_WxCocoa_SetNeedsUpdate(bool needsUpdate)
219{
220 m_needsUpdate = needsUpdate;
221}
222
223void wxListBox::OnInternalIdle()
224{
225 wxControlWithItems::OnInternalIdle();
226 if(_WxCocoa_GetNeedsUpdate())
227 {
228 _SetWidthOfTableColumnToFitItems([[GetNSTableView() tableColumns] objectAtIndex:0], m_cocoaItems);
229 [GetNSTableView() tile];
230 [GetNSTableView() reloadData];
231 _WxCocoa_SetNeedsUpdate(false);
232 }
233}
234
235int wxListBox::CocoaDataSource_numberOfRows()
236{
237 return [m_cocoaItems count];
238}
239
240struct objc_object* wxListBox::CocoaDataSource_objectForTableColumn(
241 WX_NSTableColumn tableColumn, int rowIndex)
242{
243 return [m_cocoaItems objectAtIndex:rowIndex];
244}
245
246// pure virtuals from wxListBoxBase
247bool wxListBox::IsSelected(int n) const
248{
249 return [GetNSTableView() isRowSelected: n];
250}
251
252void wxListBox::DoSetSelection(int n, bool select)
253{
254 if(select)
255 [GetNSTableView() selectRow: n byExtendingSelection:NO];
256 else
257 [GetNSTableView() deselectRow: n];
258}
259
260int wxListBox::GetSelections(wxArrayInt& aSelections) const
261{
262 aSelections.Clear();
263 NSEnumerator *enumerator = [GetNSTableView() selectedRowEnumerator];
264 while(NSNumber *num = [enumerator nextObject])
265 {
266 aSelections.Add([num intValue]);
267 }
268 return [GetNSTableView() numberOfSelectedRows];
269}
270
271int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items, unsigned int pos, void **clientData, wxClientDataType type)
272{
273 wxAutoNSAutoreleasePool pool;
274
275 const unsigned int numItems = items.GetCount();
276 for ( unsigned int i = 0; i < numItems; ++i, ++pos )
277 {
278 [m_cocoaItems insertObject: wxNSStringWithWxString(items[i])
279 atIndex: pos];
280 m_itemClientData.Insert(NULL, pos);
281 AssignNewItemClientData(pos, clientData, i, type);
282 }
283
284 _WxCocoa_SetNeedsUpdate(true);
285 return pos - 1;
286}
287
288void wxListBox::DoSetFirstItem(int n)
289{
290 [m_cocoaItems exchangeObjectAtIndex:0 withObjectAtIndex:n];
291 void* pOld = m_itemClientData[n];
292 m_itemClientData[n] = m_itemClientData[0];
293 m_itemClientData[0] = pOld;
294 _WxCocoa_SetNeedsUpdate(true);
295}
296
297
298// pure virtuals from wxItemContainer
299 // deleting items
300void wxListBox::DoClear()
301{
302 [m_cocoaItems removeAllObjects];
303 m_itemClientData.Clear();
304 _WxCocoa_SetNeedsUpdate(true);
305}
306
307void wxListBox::DoDeleteOneItem(unsigned int n)
308{
309 [m_cocoaItems removeObjectAtIndex:n];
310 m_itemClientData.RemoveAt(n);
311 _WxCocoa_SetNeedsUpdate(true);
312}
313
314 // accessing strings
315unsigned int wxListBox::GetCount() const
316{
317 return (unsigned int)[m_cocoaItems count];
318}
319
320wxString wxListBox::GetString(unsigned int n) const
321{
322 return wxStringWithNSString([m_cocoaItems objectAtIndex:n]);
323}
324
325void wxListBox::SetString(unsigned int n, const wxString& s)
326{
327 wxAutoNSAutoreleasePool pool;
328 [m_cocoaItems removeObjectAtIndex:n];
329 [m_cocoaItems insertObject: wxNSStringWithWxString(s) atIndex: n];
330 _WxCocoa_SetNeedsUpdate(true);
331}
332
333int wxListBox::FindString(const wxString& s, bool bCase) const
334{
335 // FIXME: use wxItemContainerImmutable::FindString for bCase parameter
336 wxAutoNSAutoreleasePool pool;
337 return [m_cocoaItems indexOfObject:wxNSStringWithWxString(s)];
338}
339
340 // selection
341int wxListBox::GetSelection() const
342{
343 return [GetNSTableView() selectedRow];
344}
345
346void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
347{
348 m_itemClientData[n] = clientData;
349}
350
351void* wxListBox::DoGetItemClientData(unsigned int n) const
352{
353 return m_itemClientData[n];
354}
355
356#endif // wxUSE_LISTBOX