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