Include wx/dynarray.h according to precompiled headers of wx/wx.h (with other minor...
[wxWidgets.git] / src / mac / carbon / listbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/listbox.cpp
3 // Purpose: wxListBox
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_LISTBOX
15
16 #ifndef WX_PRECOMP
17 #include "wx/dynarray.h"
18 #endif
19
20 #include "wx/app.h"
21 #include "wx/listbox.h"
22 #include "wx/button.h"
23 #include "wx/settings.h"
24 #include "wx/toplevel.h"
25 #include "wx/log.h"
26
27 #include "wx/utils.h"
28
29 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
30
31 BEGIN_EVENT_TABLE(wxListBox, wxControl)
32 END_EVENT_TABLE()
33
34 #include "wx/mac/uma.h"
35 #include "wx/dynarray.h"
36 #include "wx/arrstr.h"
37
38 // ============================================================================
39 // list box control implementation
40 // ============================================================================
41
42 wxListBox::wxListBox()
43 {
44 }
45
46 bool wxListBox::Create(
47 wxWindow *parent,
48 wxWindowID id,
49 const wxPoint& pos,
50 const wxSize& size,
51 const wxArrayString& choices,
52 long style,
53 const wxValidator& validator,
54 const wxString& name )
55 {
56 wxCArrayString chs(choices);
57
58 return Create(
59 parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
60 style, validator, name );
61 }
62
63 wxMacListControl* wxListBox::GetPeer() const
64 {
65 return dynamic_cast<wxMacListControl*>(m_peer);
66 }
67
68 bool wxListBox::Create(
69 wxWindow *parent,
70 wxWindowID id,
71 const wxPoint& pos,
72 const wxSize& size,
73 int n,
74 const wxString choices[],
75 long style,
76 const wxValidator& validator,
77 const wxString& name )
78 {
79 m_macIsUserPane = false;
80
81 wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED),
82 wxT("only a single listbox selection mode can be specified") );
83
84 if ( !wxListBoxBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) )
85 return false;
86
87 wxMacDataBrowserListControl* control = new wxMacDataBrowserListControl( this, pos, size, style );
88 control->SetClientDataType( m_clientDataItemsType );
89 m_peer = control;
90
91 MacPostControlCreate( pos, size );
92
93 InsertItems( n, choices, 0 );
94
95 // Needed because it is a wxControlWithItems
96 SetBestSize( size );
97
98 return true;
99 }
100
101 wxListBox::~wxListBox()
102 {
103 FreeData();
104 m_peer->SetReference( 0 );
105 }
106
107 void wxListBox::FreeData()
108 {
109 GetPeer()->MacClear();
110 }
111
112 void wxListBox::DoSetFirstItem(int n)
113 {
114 GetPeer()->MacScrollTo( n );
115 }
116
117 void wxListBox::EnsureVisible(int n)
118 {
119 GetPeer()->MacScrollTo( n );
120 }
121
122 void wxListBox::Delete(unsigned int n)
123 {
124 wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::Delete") );
125
126 GetPeer()->MacDelete( n );
127 }
128
129 int wxListBox::DoAppend(const wxString& item)
130 {
131 InvalidateBestSize();
132
133 return GetPeer()->MacAppend( item );
134 }
135
136 void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData)
137 {
138 Clear();
139
140 unsigned int n = choices.GetCount();
141
142 for ( size_t i = 0; i < n; ++i )
143 {
144 if ( clientData )
145 {
146 Append( choices[i], clientData[i] );
147 }
148 else
149 Append( choices[i] );
150 }
151
152 }
153
154 int wxListBox::FindString(const wxString& s, bool bCase) const
155 {
156 for ( size_t i = 0; i < GetCount(); ++ i )
157 {
158 if (s.IsSameAs( GetString( i ), bCase) )
159 return (int)i;
160 }
161
162 return wxNOT_FOUND;
163 }
164
165 void wxListBox::Clear()
166 {
167 FreeData();
168 }
169
170 void wxListBox::DoSetSelection(int n, bool select)
171 {
172 wxCHECK_RET( n == wxNOT_FOUND || IsValid(n),
173 wxT("invalid index in wxListBox::SetSelection") );
174
175 if ( n == wxNOT_FOUND )
176 GetPeer()->MacDeselectAll();
177 else
178 GetPeer()->MacSetSelection( n, select );
179 }
180
181 bool wxListBox::IsSelected(int n) const
182 {
183 wxCHECK_MSG( IsValid(n), false, wxT("invalid index in wxListBox::Selected") );
184
185 return GetPeer()->MacIsSelected( n );
186 }
187
188 void *wxListBox::DoGetItemClientData(unsigned int n) const
189 {
190 wxCHECK_MSG( IsValid(n), NULL, wxT("invalid index in wxListBox::GetClientData"));
191 return GetPeer()->MacGetClientData( n );
192 }
193
194 wxClientData *wxListBox::DoGetItemClientObject(unsigned int n) const
195 {
196 return (wxClientData*)DoGetItemClientData( n );
197 }
198
199 void wxListBox::DoSetItemClientData(unsigned int n, void *clientData)
200 {
201 wxCHECK_RET( IsValid(n), wxT("invalid index in wxListBox::SetClientData") );
202 GetPeer()->MacSetClientData( n , clientData);
203 }
204
205 void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
206 {
207 DoSetItemClientData(n, clientData);
208 }
209
210 // Return number of selections and an array of selected integers
211 int wxListBox::GetSelections(wxArrayInt& aSelections) const
212 {
213 return GetPeer()->MacGetSelections( aSelections );
214 }
215
216 // Get single selection, for single choice list items
217 int wxListBox::GetSelection() const
218 {
219 return GetPeer()->MacGetSelection();
220 }
221
222 // Find string for position
223 wxString wxListBox::GetString(unsigned int n) const
224 {
225 wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("invalid index in wxListBox::GetString") );
226 return GetPeer()->MacGetString(n);
227 }
228
229 void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
230 {
231 wxCHECK_RET( IsValidInsert(pos), wxT("invalid index in wxListBox::InsertItems") );
232
233 InvalidateBestSize();
234
235 GetPeer()->MacInsert( pos, items );
236 }
237
238 void wxListBox::SetString(unsigned int n, const wxString& s)
239 {
240 GetPeer()->MacSetString( n, s );
241 }
242
243 wxSize wxListBox::DoGetBestSize() const
244 {
245 int lbWidth = 100; // some defaults
246 int lbHeight = 110;
247 int wLine;
248
249 {
250 wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef)MacGetTopLevelWindowRef() ) );
251
252 // TODO: clean this up
253 if ( m_font.Ok() )
254 {
255 ::TextFont( m_font.MacGetFontNum() );
256 ::TextSize( m_font.MacGetFontSize() );
257 ::TextFace( m_font.MacGetFontStyle() );
258 }
259 else
260 {
261 ::TextFont( kFontIDMonaco );
262 ::TextSize( 9 );
263 ::TextFace( 0 );
264 }
265
266 // Find the widest line
267 for (unsigned int i = 0; i < GetCount(); i++)
268 {
269 wxString str( GetString( i ) );
270
271 #if wxUSE_UNICODE
272 Point bounds = {0, 0};
273 SInt16 baseline;
274
275 // NB: what if m_font.Ok() == false ???
276 ::GetThemeTextDimensions(
277 wxMacCFStringHolder( str, m_font.GetEncoding() ),
278 kThemeCurrentPortFont,
279 kThemeStateActive,
280 false,
281 &bounds,
282 &baseline );
283 wLine = bounds.h;
284 #else
285 wLine = ::TextWidth( str.c_str(), 0, str.length() );
286 #endif
287
288 lbWidth = wxMax( lbWidth, wLine );
289 }
290
291 // Add room for the scrollbar
292 lbWidth += wxSystemSettings::GetMetric( wxSYS_VSCROLL_X );
293
294 // And just a bit more
295 int cy = 12;
296 int cx = ::TextWidth( "X", 0, 1 );
297 lbWidth += cx;
298
299 // don't make the listbox too tall (limit height to around 10 items)
300 // but don't make it too small neither
301 lbHeight = wxMax( (cy + 4) * wxMin( wxMax( GetCount(), 3 ), 10 ), 70 );
302 }
303
304 return wxSize( lbWidth, lbHeight );
305 }
306
307 unsigned int wxListBox::GetCount() const
308 {
309 return GetPeer()->MacGetCount();
310 }
311
312 void wxListBox::Refresh(bool eraseBack, const wxRect *rect)
313 {
314 wxControl::Refresh( eraseBack, rect );
315 }
316
317 // Some custom controls depend on this
318 /* static */ wxVisualAttributes
319 wxListBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
320 {
321 wxVisualAttributes attr;
322
323 attr.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
324 attr.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX );
325 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
326
327 return attr;
328 }
329
330 int wxListBox::DoListHitTest(const wxPoint& inpoint) const
331 {
332 OSStatus err;
333
334 // There are few reasons why this is complicated:
335 // 1) There is no native HitTest function for Mac
336 // 2) GetDataBrowserItemPartBounds only works on visible items
337 // 3) We can't do it through GetDataBrowserTableView[Item]RowHeight
338 // because what it returns is basically inaccurate in the context
339 // of the coordinates we want here, but we use this as a guess
340 // for where the first visible item lies
341
342 wxPoint point = inpoint;
343
344 // interestingly enough 10.2 (and below?) have GetDataBrowserItemPartBounds
345 // giving root window coordinates but 10.3 and above give client coordinates
346 // so we only compare using root window coordinates on 10.3 and up
347 if ( UMAGetSystemVersion() < 0x1030 )
348 MacClientToRootWindow(&point.x, &point.y);
349
350 // get column property ID (req. for call to itempartbounds)
351 DataBrowserTableViewColumnID colId = 0;
352 err = GetDataBrowserTableViewColumnProperty(m_peer->GetControlRef(), 0, &colId);
353 wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewColumnProperty"));
354
355 // OK, first we need to find the first visible item we have -
356 // this will be the "low" for our binary search. There is no real
357 // easy way around this, as we will need to do a SLOW linear search
358 // until we find a visible item, but we can do a cheap calculation
359 // via the row height to speed things up a bit
360 UInt32 scrollx, scrolly;
361 err = GetDataBrowserScrollPosition(m_peer->GetControlRef(), &scrollx, &scrolly);
362 wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserScrollPosition"));
363
364 UInt16 height;
365 err = GetDataBrowserTableViewRowHeight(m_peer->GetControlRef(), &height);
366 wxCHECK_MSG(err == noErr, wxNOT_FOUND, wxT("Unexpected error from GetDataBrowserTableViewRowHeight"));
367
368 // these indices are 0-based, as usual, so we need to add 1 to them when
369 // passing them to data browser functions which use 1-based indices
370 int low = scrolly / height,
371 high = GetCount() - 1;
372
373 // search for the first visible item (note that the scroll guess above
374 // is the low bounds of where the item might lie so we only use that as a
375 // starting point - we should reach it within 1 or 2 iterations of the loop)
376 while ( low <= high )
377 {
378 Rect bounds;
379 err = GetDataBrowserItemPartBounds(
380 m_peer->GetControlRef(), low + 1, colId,
381 kDataBrowserPropertyEnclosingPart,
382 &bounds); // note +1 to translate to Mac ID
383 if ( err == noErr )
384 break;
385
386 // errDataBrowserItemNotFound is expected as it simply means that the
387 // item is not currently visible -- but other errors are not
388 wxCHECK_MSG( err == errDataBrowserItemNotFound, wxNOT_FOUND,
389 wxT("Unexpected error from GetDataBrowserItemPartBounds") );
390
391 low++;
392 }
393
394 // NOW do a binary search for where the item lies, searching low again if
395 // we hit an item that isn't visible
396 while ( low <= high )
397 {
398 int mid = (low + high) / 2;
399
400 Rect bounds;
401 err = GetDataBrowserItemPartBounds(
402 m_peer->GetControlRef(), mid + 1, colId,
403 kDataBrowserPropertyEnclosingPart,
404 &bounds); //note +1 to trans to mac id
405 wxCHECK_MSG( err == noErr || err == errDataBrowserItemNotFound,
406 wxNOT_FOUND,
407 wxT("Unexpected error from GetDataBrowserItemPartBounds") );
408
409 if ( err == errDataBrowserItemNotFound )
410 {
411 // item not visible, attempt to find a visible one
412 // search lower
413 high = mid - 1;
414 }
415 else // visible item, do actual hitttest
416 {
417 // if point is within the bounds, return this item (since we assume
418 // all x coords of items are equal we only test the x coord in
419 // equality)
420 if ((point.x >= bounds.left && point.x <= bounds.right) &&
421 (point.y >= bounds.top && point.y <= bounds.bottom) )
422 {
423 // found!
424 return mid;
425 }
426
427 if ( point.y < bounds.top )
428 // index(bounds) greater then key(point)
429 high = mid - 1;
430 else
431 // index(bounds) less then key(point)
432 low = mid + 1;
433 }
434 }
435
436 return wxNOT_FOUND;
437 }
438
439 // ============================================================================
440 // data browser based implementation
441 // ============================================================================
442
443 const short kTextColumnId = 1024;
444 const short kNumericOrderColumnId = 1025;
445
446 wxMacListBoxItem::wxMacListBoxItem()
447 {
448 m_data = NULL;
449 m_order = 0;
450 }
451
452 wxMacListBoxItem::~wxMacListBoxItem()
453 {
454 }
455
456 void wxMacListBoxItem::SetOrder( SInt32 order )
457 {
458 m_order = order;
459 }
460
461 SInt32 wxMacListBoxItem::GetOrder() const
462 {
463 return m_order;
464 }
465
466 void wxMacListBoxItem::SetData( void* data)
467 {
468 m_data = data;
469 }
470
471 void* wxMacListBoxItem::GetData() const
472 {
473 return m_data;
474 }
475
476 void wxMacListBoxItem::SetLabel( const wxString& str)
477 {
478 m_label = str;
479 m_cfLabel.Assign( str , wxLocale::GetSystemEncoding());
480 }
481
482 const wxString& wxMacListBoxItem::GetLabel() const
483 {
484 return m_label;
485 }
486
487 bool wxMacListBoxItem::IsLessThan(wxMacDataItemBrowserControl *owner ,
488 const wxMacDataItem* rhs,
489 DataBrowserPropertyID sortProperty) const
490 {
491 const wxMacListBoxItem* otherItem = dynamic_cast<const wxMacListBoxItem*>(rhs);
492 bool retval = false;
493 switch (sortProperty)
494 {
495 case kTextColumnId:
496 retval = m_label.CmpNoCase( otherItem->m_label) < 0;
497 break;
498
499 case kNumericOrderColumnId:
500 retval = m_order < otherItem->m_order;
501 break;
502
503 default:
504 break;
505 };
506
507 return retval;
508 }
509
510 OSStatus wxMacListBoxItem::GetSetData( wxMacDataItemBrowserControl *owner ,
511 DataBrowserPropertyID property,
512 DataBrowserItemDataRef itemData,
513 bool changeValue )
514 {
515 OSStatus err = errDataBrowserPropertyNotSupported;
516 wxListBox *list = wxDynamicCast( owner->GetPeer() , wxListBox );
517 wxCHECK_MSG( list != NULL , errDataBrowserPropertyNotSupported , wxT("Listbox expected"));
518 wxCheckListBox *checklist = wxDynamicCast( list , wxCheckListBox );
519
520 if ( !changeValue )
521 {
522 switch (property)
523 {
524 case kTextColumnId:
525 err = ::SetDataBrowserItemDataText( itemData, m_cfLabel );
526 err = noErr;
527 break;
528
529 case kNumericOrderColumnId:
530 err = ::SetDataBrowserItemDataValue( itemData, m_order );
531 err = noErr;
532 break;
533
534 default:
535 break;
536 }
537 }
538 else
539 {
540 switch (property)
541 {
542 // no editable props here
543 default:
544 break;
545 }
546 }
547
548 return err;
549 }
550
551 void wxMacListBoxItem::Notification(wxMacDataItemBrowserControl *owner ,
552 DataBrowserItemNotification message,
553 DataBrowserItemDataRef itemData ) const
554 {
555 wxMacDataBrowserListControl *lb = dynamic_cast<wxMacDataBrowserListControl*>(owner);
556
557 // we want to depend on as little as possible to make sure tear-down of controls is safe
558
559 if ( message == kDataBrowserItemRemoved)
560 {
561 if ( lb != NULL && lb->GetClientDataType() == wxClientData_Object )
562 {
563 delete (wxClientData*) (m_data);
564 }
565
566 delete this;
567 return;
568 }
569
570 wxListBox *list = wxDynamicCast( owner->GetPeer() , wxListBox );
571 wxCHECK_RET( list != NULL , wxT("Listbox expected"));
572
573 bool trigger = false;
574 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_SELECTED, list->GetId() );
575 switch (message)
576 {
577 case kDataBrowserItemDeselected:
578 if ( list->HasMultipleSelection() )
579 trigger = !lb->IsSelectionSuppressed();
580 break;
581
582 case kDataBrowserItemSelected:
583 trigger = !lb->IsSelectionSuppressed();
584 break;
585
586 case kDataBrowserItemDoubleClicked:
587 event.SetEventType( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED );
588 trigger = true;
589 break;
590
591 default:
592 break;
593 }
594
595 if ( trigger )
596 {
597 event.SetEventObject( list );
598 if ( list->HasClientObjectData() )
599 event.SetClientObject( (wxClientData*) m_data );
600 else if ( list->HasClientUntypedData() )
601 event.SetClientData( m_data );
602 event.SetString( m_label );
603 event.SetInt( owner->GetLineFromItem( this ) );
604 event.SetExtraLong( list->HasMultipleSelection() ? message == kDataBrowserItemSelected : true );
605 wxPostEvent( list->GetEventHandler(), event );
606
607 // direct notification is not always having the listbox GetSelection() having in synch with event
608 // list->GetEventHandler()->ProcessEvent(event);
609 }
610 }
611
612 wxMacDataBrowserListControl::wxMacDataBrowserListControl( wxListBox *peer, const wxPoint& pos, const wxSize& size, long style)
613 : wxMacDataItemBrowserControl( peer, pos, size, style )
614 {
615 OSStatus err = noErr;
616 m_clientDataItemsType = wxClientData_None;
617 m_stringSorted = style & wxLB_SORT;
618
619 DataBrowserSelectionFlags options = kDataBrowserDragSelect;
620 if ( style & wxLB_MULTIPLE )
621 {
622 options |= kDataBrowserAlwaysExtendSelection | kDataBrowserCmdTogglesSelection;
623 }
624 else if ( style & wxLB_EXTENDED )
625 {
626 // default behaviour
627 }
628 else
629 {
630 options |= kDataBrowserSelectOnlyOne;
631 }
632 err = SetSelectionFlags( options );
633 verify_noerr( err );
634
635 DataBrowserListViewColumnDesc columnDesc;
636 columnDesc.headerBtnDesc.titleOffset = 0;
637 columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
638
639 columnDesc.headerBtnDesc.btnFontStyle.flags =
640 kControlUseFontMask | kControlUseJustMask;
641
642 columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlNoContent;
643 columnDesc.headerBtnDesc.btnFontStyle.just = teFlushDefault;
644 columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
645 columnDesc.headerBtnDesc.btnFontStyle.style = normal;
646 columnDesc.headerBtnDesc.titleString = NULL;
647
648 columnDesc.headerBtnDesc.minimumWidth = 0;
649 columnDesc.headerBtnDesc.maximumWidth = 10000;
650
651 columnDesc.propertyDesc.propertyID = kTextColumnId;
652 columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
653 columnDesc.propertyDesc.propertyFlags = kDataBrowserTableViewSelectionColumn;
654 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
655 columnDesc.propertyDesc.propertyFlags |= kDataBrowserListViewTypeSelectColumn;
656 #endif
657
658 verify_noerr( AddColumn( &columnDesc, kDataBrowserListViewAppendColumn ) );
659
660 columnDesc.headerBtnDesc.minimumWidth = 0;
661 columnDesc.headerBtnDesc.maximumWidth = 0;
662 columnDesc.propertyDesc.propertyID = kNumericOrderColumnId;
663 columnDesc.propertyDesc.propertyType = kDataBrowserPropertyRelevanceRankPart;
664 columnDesc.propertyDesc.propertyFlags = kDataBrowserTableViewSelectionColumn;
665 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
666 columnDesc.propertyDesc.propertyFlags |= kDataBrowserListViewTypeSelectColumn;
667 #endif
668
669 verify_noerr( AddColumn( &columnDesc, kDataBrowserListViewAppendColumn ) );
670
671 SetDataBrowserSortProperty( m_controlRef , kTextColumnId);
672 if ( m_stringSorted )
673 {
674 SetDataBrowserSortProperty( m_controlRef , kTextColumnId);
675 SetDataBrowserSortOrder( m_controlRef , kDataBrowserOrderIncreasing);
676 }
677 else
678 {
679 SetDataBrowserSortProperty( m_controlRef , kNumericOrderColumnId);
680 SetDataBrowserSortOrder( m_controlRef , kDataBrowserOrderIncreasing);
681 }
682
683 verify_noerr( AutoSizeColumns() );
684 verify_noerr( SetHiliteStyle(kDataBrowserTableViewFillHilite ) );
685 verify_noerr( SetHeaderButtonHeight( 0 ) );
686 err = SetHasScrollBars( (style & wxHSCROLL) != 0 , true );
687 #if 0
688 // shouldn't be necessary anymore under 10.2
689 m_peer->SetData( kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, (Boolean)false );
690 m_peer->SetNeedsFocusRect( true );
691 #endif
692 }
693
694 wxMacDataBrowserListControl::~wxMacDataBrowserListControl()
695 {
696 }
697
698
699 wxMacListBoxItem* wxMacDataBrowserListControl::CreateItem()
700 {
701 return new wxMacListBoxItem();
702 }
703
704 wxListBox * wxMacDataBrowserListControl::GetPeer() const
705 {
706 return wxDynamicCast( wxMacControl::GetPeer() , wxListBox );
707 }
708
709 wxClientDataType wxMacDataBrowserListControl::GetClientDataType() const
710 {
711 return m_clientDataItemsType;
712 }
713 void wxMacDataBrowserListControl::SetClientDataType(wxClientDataType clientDataItemsType)
714 {
715 m_clientDataItemsType = clientDataItemsType;
716 }
717
718 unsigned int wxMacDataBrowserListControl::MacGetCount() const
719 {
720 return GetItemCount(wxMacDataBrowserRootContainer,false,kDataBrowserItemNoState);
721 }
722
723 void wxMacDataBrowserListControl::MacDelete( unsigned int n )
724 {
725 wxMacListBoxItem* item = (wxMacListBoxItem*)GetItemFromLine( n );
726 RemoveItem( wxMacDataBrowserRootContainer, item );
727 }
728
729 void wxMacDataBrowserListControl::MacInsert( unsigned int n, const wxString& text)
730 {
731 wxMacListBoxItem* newItem = CreateItem();
732 newItem->SetLabel( text );
733
734 if ( !m_stringSorted )
735 {
736 // increase the order of the lines to be shifted
737 unsigned int lines = MacGetCount();
738 for ( unsigned int i = n; i < lines; ++i)
739 {
740 wxMacListBoxItem* iter = (wxMacListBoxItem*) GetItemFromLine(i);
741 iter->SetOrder( iter->GetOrder() + 1 );
742 }
743
744 SInt32 frontLineOrder = 0;
745 if ( n > 0 )
746 {
747 wxMacListBoxItem* iter = (wxMacListBoxItem*) GetItemFromLine(n-1);
748 frontLineOrder = iter->GetOrder();
749 }
750 newItem->SetOrder( frontLineOrder + 1 );
751 }
752
753 AddItem( wxMacDataBrowserRootContainer, newItem );
754 }
755
756 void wxMacDataBrowserListControl::MacInsert( unsigned int n, const wxArrayString& items)
757 {
758 size_t itemsCount = items.GetCount();
759 if ( itemsCount == 0 )
760 return;
761
762 SInt32 frontLineOrder = 0;
763
764 if ( !m_stringSorted )
765 {
766 // increase the order of the lines to be shifted
767 unsigned int lines = MacGetCount();
768 for ( unsigned int i = n; i < lines; ++i)
769 {
770 wxMacListBoxItem* iter = (wxMacListBoxItem*) GetItemFromLine(i);
771 iter->SetOrder( iter->GetOrder() + itemsCount );
772 }
773 if ( n > 0 )
774 {
775 wxMacListBoxItem* iter = (wxMacListBoxItem*) GetItemFromLine(n-1);
776 frontLineOrder = iter->GetOrder();
777 }
778 }
779
780 wxArrayMacDataItemPtr ids;
781 ids.SetCount( itemsCount );
782
783 for ( unsigned int i = 0; i < itemsCount; ++i )
784 {
785 wxMacListBoxItem* item = CreateItem();
786 item->SetLabel( items[i]);
787 if ( !m_stringSorted )
788 item->SetOrder( frontLineOrder + 1 + i );
789
790 ids[i] = item;
791 }
792
793 AddItems( wxMacDataBrowserRootContainer, ids );
794 }
795
796 int wxMacDataBrowserListControl::MacAppend( const wxString& text)
797 {
798 wxMacListBoxItem* item = CreateItem();
799 item->SetLabel( text );
800 if ( !m_stringSorted )
801 {
802 unsigned int lines = MacGetCount();
803 if ( lines == 0 )
804 item->SetOrder( 1 );
805 else
806 {
807 wxMacListBoxItem* frontItem = (wxMacListBoxItem*) GetItemFromLine(lines-1);
808 item->SetOrder( frontItem->GetOrder() + 1 );
809 }
810 }
811 AddItem( wxMacDataBrowserRootContainer, item );
812
813 return GetLineFromItem(item);
814 }
815
816 void wxMacDataBrowserListControl::MacClear()
817 {
818 wxMacDataItemBrowserSelectionSuppressor suppressor(this);
819 RemoveAllItems(wxMacDataBrowserRootContainer);
820 }
821
822 void wxMacDataBrowserListControl::MacDeselectAll()
823 {
824 wxMacDataItemBrowserSelectionSuppressor suppressor(this);
825 SetSelectedAllItems( kDataBrowserItemsRemove );
826 }
827
828 void wxMacDataBrowserListControl::MacSetSelection( unsigned int n, bool select )
829 {
830 wxMacListBoxItem* item = (wxMacListBoxItem*) GetItemFromLine(n);
831 wxMacDataItemBrowserSelectionSuppressor suppressor(this);
832
833 if ( IsItemSelected( item ) != select )
834 {
835 if ( select )
836 SetSelectedItem( item, GetPeer()->HasMultipleSelection() ? kDataBrowserItemsAdd : kDataBrowserItemsAssign );
837 else
838 SetSelectedItem( item, kDataBrowserItemsRemove );
839 }
840
841 MacScrollTo( n );
842 }
843
844 bool wxMacDataBrowserListControl::MacIsSelected( unsigned int n ) const
845 {
846 wxMacListBoxItem* item = (wxMacListBoxItem*) GetItemFromLine(n);
847 return IsItemSelected( item );
848 }
849
850 int wxMacDataBrowserListControl::MacGetSelection() const
851 {
852 wxMacDataItemPtr first, last;
853 GetSelectionAnchor( &first, &last );
854
855 if ( first != NULL )
856 {
857 return GetLineFromItem( first );
858 }
859
860 return -1;
861 }
862
863 int wxMacDataBrowserListControl::MacGetSelections( wxArrayInt& aSelections ) const
864 {
865 aSelections.Empty();
866 wxArrayMacDataItemPtr selectedItems;
867 GetItems( wxMacDataBrowserRootContainer, false , kDataBrowserItemIsSelected, selectedItems);
868
869 int count = selectedItems.GetCount();
870
871 for ( int i = 0; i < count; ++i)
872 {
873 aSelections.Add(GetLineFromItem(selectedItems[i]));
874 }
875
876 return count;
877 }
878
879 void wxMacDataBrowserListControl::MacSetString( unsigned int n, const wxString& text )
880 {
881 // as we don't store the strings we only have to issue a redraw
882 wxMacListBoxItem* item = (wxMacListBoxItem*) GetItemFromLine( n);
883 item->SetLabel( text );
884 UpdateItem( wxMacDataBrowserRootContainer, item , kTextColumnId );
885 }
886
887 wxString wxMacDataBrowserListControl::MacGetString( unsigned int n ) const
888 {
889 wxMacListBoxItem * item = (wxMacListBoxItem*) GetItemFromLine( n );
890 return item->GetLabel();
891 }
892
893 void wxMacDataBrowserListControl::MacSetClientData( unsigned int n, void * data)
894 {
895 wxMacListBoxItem* item = (wxMacListBoxItem*) GetItemFromLine( n);
896 item->SetData( data );
897 // not displayed, therefore no Update infos to DataBrowser
898 }
899
900 void * wxMacDataBrowserListControl::MacGetClientData( unsigned int n) const
901 {
902 wxMacListBoxItem * item = (wxMacListBoxItem*) GetItemFromLine( n );
903 return item->GetData();
904 }
905
906 void wxMacDataBrowserListControl::MacScrollTo( unsigned int n )
907 {
908 RevealItem( GetItemFromLine( n) , kDataBrowserRevealWithoutSelecting );
909 }
910
911 #if 0
912
913 // in case we need that one day
914
915 // ============================================================================
916 // HIView owner-draw-based implementation
917 // ============================================================================
918
919 static pascal void ListBoxDrawProc(
920 ControlRef browser, DataBrowserItemID item, DataBrowserPropertyID property,
921 DataBrowserItemState itemState, const Rect *itemRect, SInt16 depth, Boolean isColorDevice )
922 {
923 CFStringRef cfString;
924 ThemeDrawingState themeState;
925 long systemVersion;
926
927 GetThemeDrawingState( &themeState );
928 cfString = CFStringCreateWithFormat( NULL, NULL, CFSTR("Row %d"), item );
929
930 // In this sample we handle the "selected" state; all others fall through to our "active" state
931 if ( itemState == kDataBrowserItemIsSelected )
932 {
933 ThemeBrush colorBrushID;
934
935 // TODO: switch over to wxSystemSettingsNative::GetColour() when kThemeBrushSecondaryHighlightColor
936 // is incorporated Panther DB starts using kThemeBrushSecondaryHighlightColor
937 // for inactive browser highlighting
938 Gestalt( gestaltSystemVersion, &systemVersion );
939 if ( (systemVersion >= 0x00001030) && !IsControlActive( browser ) )
940 colorBrushID = kThemeBrushSecondaryHighlightColor;
941 else
942 colorBrushID = kThemeBrushPrimaryHighlightColor;
943
944 // First paint the hilite rect, then the text on top
945 SetThemePen( colorBrushID, 32, true );
946 PaintRect( itemRect );
947 SetThemeDrawingState( themeState, false );
948 }
949
950 DrawThemeTextBox( cfString, kThemeApplicationFont, kThemeStateActive, true, itemRect, teFlushDefault, NULL );
951 SetThemeDrawingState( themeState, true );
952
953 if ( cfString != NULL )
954 CFRelease( cfString );
955 }
956
957 #endif
958
959
960 #endif