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