1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/listctrl_mac.cpp
3 // Purpose:     wxListCtrl
4 // Author:      Julian Smart
5 // Modified by: Agron Selimaj
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #if wxUSE_LISTCTRL
27 
28 #include "wx/listctrl.h"
29 
30 #ifndef WX_PRECOMP
31     #include "wx/intl.h"
32     #include "wx/settings.h"
33 #endif
34 
35 #include "wx/osx/uma.h"
36 
37 #include "wx/imaglist.h"
38 #include "wx/sysopt.h"
39 #include "wx/timer.h"
40 
41 #include "wx/hashmap.h"
42 
43 WX_DECLARE_HASH_MAP( int, wxListItem*, wxIntegerHash, wxIntegerEqual, wxListItemList );
44 
45 #include "wx/listimpl.cpp"
46 WX_DEFINE_LIST(wxColumnList)
47 
48 // so we can check for column clicks
49 static const EventTypeSpec eventList[] =
50 {
51     { kEventClassControl, kEventControlHit },
52     { kEventClassControl, kEventControlDraw }
53 };
54 
wxMacListCtrlEventHandler(EventHandlerCallRef handler,EventRef event,void * data)55 static pascal OSStatus wxMacListCtrlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
56 {
57     OSStatus result = eventNotHandledErr ;
58 
59     wxMacCarbonEvent cEvent( event ) ;
60 
61     ControlRef controlRef ;
62     cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
63 
64     wxListCtrl *window = (wxListCtrl*) data ;
65     wxListEvent le( wxEVT_LIST_COL_CLICK, window->GetId() );
66     le.SetEventObject( window );
67 
68     switch ( GetEventKind( event ) )
69     {
70         // check if the column was clicked on and fire an event if so
71         case kEventControlHit :
72             {
73                 ControlPartCode result = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart, typeControlPartCode) ;
74                 if (result == kControlButtonPart){
75                     DataBrowserPropertyID col;
76                     GetDataBrowserSortProperty(controlRef, &col);
77 
78                     DataBrowserTableViewColumnIndex column = 0;
79                     verify_noerr( GetDataBrowserTableViewColumnPosition( controlRef, col, &column ) );
80 
81                     le.m_col = column;
82                     // FIXME: we can't use the sort property for virtual listctrls
83                     // so we need to find a better way to determine which column was clicked...
84                     if (!window->IsVirtual())
85                         window->HandleWindowEvent( le );
86                 }
87                 result = CallNextEventHandler(handler, event);
88                 break;
89             }
90         case kEventControlDraw:
91             {
92                 CGContextRef context = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef, typeCGContextRef) ;
93                 window->MacSetDrawingContext(context);
94                 result = CallNextEventHandler(handler, event);
95                 window->MacSetDrawingContext(NULL);
96                 break;
97             }
98         default :
99             break ;
100     }
101 
102 
103     return result ;
104 }
105 
106 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacListCtrlEventHandler )
107 
108 class wxMacListCtrlItem : public wxMacDataItem
109 {
110 public:
111     wxMacListCtrlItem();
112 
113     virtual void Notification(wxMacDataItemBrowserControl *owner ,
114         DataBrowserItemNotification message,
115         DataBrowserItemDataRef itemData ) const;
116 
117     virtual void SetColumnInfo( unsigned int column, wxListItem* item );
118     virtual wxListItem* GetColumnInfo( unsigned int column );
119     virtual bool HasColumnInfo( unsigned int column );
120 
121     virtual void SetColumnTextValue( unsigned int column, const wxString& text );
122     virtual wxString GetColumnTextValue( unsigned int column );
123 
124     virtual int GetColumnImageValue( unsigned int column );
125     virtual void SetColumnImageValue( unsigned int column, int imageIndex );
126 
127     virtual ~wxMacListCtrlItem();
128 protected:
129     wxListItemList m_rowItems;
130 };
131 
132 DataBrowserDrawItemUPP gDataBrowserDrawItemUPP = NULL;
133 //DataBrowserEditItemUPP gDataBrowserEditItemUPP = NULL;
134 DataBrowserHitTestUPP gDataBrowserHitTestUPP = NULL;
135 
136 // TODO: Make a better name!!
137 class wxMacDataBrowserListCtrlControl : public wxMacDataItemBrowserControl
138 {
139 public:
140     wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style );
wxMacDataBrowserListCtrlControl()141     wxMacDataBrowserListCtrlControl() {}
142     virtual ~wxMacDataBrowserListCtrlControl();
143 
144     // create a list item (can be a subclass of wxMacListBoxItem)
145 
146     virtual void MacInsertItem( unsigned int n, wxListItem* item );
147     virtual void MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item );
148     virtual void MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item );
149     virtual void UpdateState(wxMacDataItem* dataItem, wxListItem* item);
GetFlags()150     int GetFlags() { return m_flags; }
151 
152 protected:
153     // we need to override to provide specialized handling for virtual wxListCtrls
154     virtual OSStatus GetSetItemData(DataBrowserItemID itemID,
155                         DataBrowserPropertyID property,
156                         DataBrowserItemDataRef itemData,
157                         Boolean changeValue );
158 
159     virtual void    ItemNotification(
160                         DataBrowserItemID itemID,
161                         DataBrowserItemNotification message,
162                         DataBrowserItemDataRef itemData);
163 
164     virtual Boolean CompareItems(DataBrowserItemID itemOneID,
165                         DataBrowserItemID itemTwoID,
166                         DataBrowserPropertyID sortProperty);
167 
168     static pascal void    DataBrowserDrawItemProc(ControlRef browser,
169                         DataBrowserItemID item,
170                         DataBrowserPropertyID property,
171                         DataBrowserItemState itemState,
172                         const Rect *theRect,
173                         SInt16 gdDepth,
174                         Boolean colorDevice);
175 
176     virtual void        DrawItem(DataBrowserItemID itemID,
177                             DataBrowserPropertyID property,
178                             DataBrowserItemState itemState,
179                             const Rect *itemRect,
180                             SInt16 gdDepth,
181                             Boolean colorDevice);
182 
183     static pascal Boolean  DataBrowserEditTextProc(ControlRef browser,
184                                     DataBrowserItemID item,
185                                     DataBrowserPropertyID property,
186                                     CFStringRef theString,
187                                     Rect *maxEditTextRect,
188                                     Boolean *shrinkToFit);
189 
DataBrowserHitTestProc(ControlRef WXUNUSED (browser),DataBrowserItemID WXUNUSED (itemID),DataBrowserPropertyID WXUNUSED (property),const Rect * WXUNUSED (theRect),const Rect * WXUNUSED (mouseRect))190     static pascal Boolean  DataBrowserHitTestProc(ControlRef WXUNUSED(browser),
191                                     DataBrowserItemID WXUNUSED(itemID),
192                                     DataBrowserPropertyID WXUNUSED(property),
193                                     const Rect *WXUNUSED(theRect),
194                                     const Rect *WXUNUSED(mouseRect)) { return true; }
195 
196     virtual bool        ConfirmEditText(DataBrowserItemID item,
197                                     DataBrowserPropertyID property,
198                                     CFStringRef theString,
199                                     Rect *maxEditTextRect,
200                                     Boolean *shrinkToFit);
201 
202 
203 
204     wxClientDataType m_clientDataItemsType;
205     bool m_isVirtual;
206     int m_flags;
207     DECLARE_DYNAMIC_CLASS_NO_COPY(wxMacDataBrowserListCtrlControl)
208 };
209 
210 class wxMacListCtrlEventDelegate : public wxEvtHandler
211 {
212 public:
213     wxMacListCtrlEventDelegate( wxListCtrl* list, int id );
214     virtual bool ProcessEvent( wxEvent& event );
215 
216 private:
217     wxListCtrl* m_list;
218     int         m_id;
219 };
220 
wxMacListCtrlEventDelegate(wxListCtrl * list,int id)221 wxMacListCtrlEventDelegate::wxMacListCtrlEventDelegate( wxListCtrl* list, int id )
222 {
223     m_list = list;
224     m_id = id;
225 }
226 
ProcessEvent(wxEvent & event)227 bool wxMacListCtrlEventDelegate::ProcessEvent( wxEvent& event )
228 {
229     int id = event.GetId();
230     wxObject* obj = event.GetEventObject();
231 
232     // even though we use a generic list ctrl underneath, make sure
233     // we present ourselves as wxListCtrl.
234     event.SetEventObject( m_list );
235     event.SetId( m_id );
236 
237     if ( !event.IsKindOf( CLASSINFO( wxCommandEvent ) ) )
238     {
239         if (m_list->GetEventHandler()->ProcessEvent( event ))
240         {
241             event.SetId(id);
242             event.SetEventObject(obj);
243             return true;
244         }
245     }
246     // Also try with the original id
247     bool success = wxEvtHandler::ProcessEvent(event);
248     event.SetId(id);
249     event.SetEventObject(obj);
250     if (!success && id != m_id)
251         success = wxEvtHandler::ProcessEvent(event);
252     return success;
253 }
254 
255 //-----------------------------------------------------------------------------
256 // wxListCtrlRenameTimer (internal)
257 //-----------------------------------------------------------------------------
258 
259 class wxListCtrlRenameTimer: public wxTimer
260 {
261 private:
262     wxListCtrl *m_owner;
263 
264 public:
265     wxListCtrlRenameTimer( wxListCtrl *owner );
266     void Notify();
267 };
268 
269 //-----------------------------------------------------------------------------
270 // wxListCtrlTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing
271 //-----------------------------------------------------------------------------
272 
273 class wxListCtrlTextCtrlWrapper : public wxEvtHandler
274 {
275 public:
276     // NB: text must be a valid object but not Create()d yet
277     wxListCtrlTextCtrlWrapper(wxListCtrl *owner,
278                           wxTextCtrl *text,
279                           long itemEdit);
280 
GetText() const281     wxTextCtrl *GetText() const { return m_text; }
282 
283     void AcceptChangesAndFinish();
284 
285 protected:
286     void OnChar( wxKeyEvent &event );
287     void OnKeyUp( wxKeyEvent &event );
288     void OnKillFocus( wxFocusEvent &event );
289 
290     bool AcceptChanges();
291     void Finish();
292 
293 private:
294     wxListCtrl         *m_owner;
295     wxTextCtrl         *m_text;
296     wxString            m_startValue;
297     long              m_itemEdited;
298     bool                m_finished;
299     bool                m_aboutToFinish;
300 
301     DECLARE_EVENT_TABLE()
302 };
303 
304 //-----------------------------------------------------------------------------
305 // wxListCtrlRenameTimer (internal)
306 //-----------------------------------------------------------------------------
307 
wxListCtrlRenameTimer(wxListCtrl * owner)308 wxListCtrlRenameTimer::wxListCtrlRenameTimer( wxListCtrl *owner )
309 {
310     m_owner = owner;
311 }
312 
Notify()313 void wxListCtrlRenameTimer::Notify()
314 {
315     m_owner->OnRenameTimer();
316 }
317 
318 //-----------------------------------------------------------------------------
319 // wxListCtrlTextCtrlWrapper (internal)
320 //-----------------------------------------------------------------------------
321 
BEGIN_EVENT_TABLE(wxListCtrlTextCtrlWrapper,wxEvtHandler)322 BEGIN_EVENT_TABLE(wxListCtrlTextCtrlWrapper, wxEvtHandler)
323     EVT_CHAR           (wxListCtrlTextCtrlWrapper::OnChar)
324     EVT_KEY_UP         (wxListCtrlTextCtrlWrapper::OnKeyUp)
325     EVT_KILL_FOCUS     (wxListCtrlTextCtrlWrapper::OnKillFocus)
326 END_EVENT_TABLE()
327 
328 wxListCtrlTextCtrlWrapper::wxListCtrlTextCtrlWrapper(wxListCtrl *owner,
329                                              wxTextCtrl *text,
330                                              long itemEdit)
331               : m_startValue(owner->GetItemText(itemEdit)),
332                 m_itemEdited(itemEdit)
333 {
334     m_owner = owner;
335     m_text = text;
336     m_finished = false;
337     m_aboutToFinish = false;
338 
339     wxRect rectLabel;
340     int offset = 8;
341     owner->GetItemRect(itemEdit, rectLabel);
342 
343     m_text->Create(owner, wxID_ANY, m_startValue,
344                    wxPoint(rectLabel.x+offset,rectLabel.y),
345                    wxSize(rectLabel.width-offset,rectLabel.height));
346     m_text->SetFocus();
347 
348     m_text->PushEventHandler(this);
349 }
350 
Finish()351 void wxListCtrlTextCtrlWrapper::Finish()
352 {
353     if ( !m_finished )
354     {
355         m_finished = true;
356 
357         m_text->RemoveEventHandler(this);
358         m_owner->FinishEditing(m_text);
359 
360         wxPendingDelete.Append( this );
361     }
362 }
363 
AcceptChanges()364 bool wxListCtrlTextCtrlWrapper::AcceptChanges()
365 {
366     const wxString value = m_text->GetValue();
367 
368     if ( value == m_startValue )
369         // nothing changed, always accept
370         return true;
371 
372     if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
373         // vetoed by the user
374         return false;
375 
376     // accepted, do rename the item
377     m_owner->SetItemText(m_itemEdited, value);
378 
379     return true;
380 }
381 
AcceptChangesAndFinish()382 void wxListCtrlTextCtrlWrapper::AcceptChangesAndFinish()
383 {
384     m_aboutToFinish = true;
385 
386     // Notify the owner about the changes
387     AcceptChanges();
388 
389     // Even if vetoed, close the control (consistent with MSW)
390     Finish();
391 }
392 
OnChar(wxKeyEvent & event)393 void wxListCtrlTextCtrlWrapper::OnChar( wxKeyEvent &event )
394 {
395     switch ( event.m_keyCode )
396     {
397         case WXK_RETURN:
398             AcceptChangesAndFinish();
399             break;
400 
401         case WXK_ESCAPE:
402             m_owner->OnRenameCancelled( m_itemEdited );
403             Finish();
404             break;
405 
406         default:
407             event.Skip();
408     }
409 }
410 
OnKeyUp(wxKeyEvent & event)411 void wxListCtrlTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
412 {
413     if (m_finished)
414     {
415         event.Skip();
416         return;
417     }
418 
419     // auto-grow the textctrl:
420     wxSize parentSize = m_owner->GetSize();
421     wxPoint myPos = m_text->GetPosition();
422     wxSize mySize = m_text->GetSize();
423     int sx, sy;
424     m_text->GetTextExtent(m_text->GetValue() + wxT("MM"), &sx, &sy);
425     if (myPos.x + sx > parentSize.x)
426         sx = parentSize.x - myPos.x;
427     if (mySize.x > sx)
428         sx = mySize.x;
429     m_text->SetSize(sx, wxDefaultCoord);
430 
431     event.Skip();
432 }
433 
OnKillFocus(wxFocusEvent & event)434 void wxListCtrlTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
435 {
436     if ( !m_finished && !m_aboutToFinish )
437     {
438         if ( !AcceptChanges() )
439             m_owner->OnRenameCancelled( m_itemEdited );
440 
441         Finish();
442     }
443 
444     // We must let the native text control handle focus
445     event.Skip();
446 }
447 
448 // ============================================================================
449 // implementation
450 // ============================================================================
451 
GetListPeer() const452 wxMacDataBrowserListCtrlControl* wxListCtrl::GetListPeer() const
453 {
454     return dynamic_cast<wxMacDataBrowserListCtrlControl*> ( GetPeer() );
455 }
456 
457 // ----------------------------------------------------------------------------
458 // wxListCtrl construction
459 // ----------------------------------------------------------------------------
460 
Init()461 void wxListCtrl::Init()
462 {
463     m_imageListNormal = NULL;
464     m_imageListSmall = NULL;
465     m_imageListState = NULL;
466 
467     // keep track of if we created our own image lists, or if they were assigned
468     // to us.
469     m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = false;
470     m_colCount = 0;
471     m_count = 0;
472     m_textCtrl = NULL;
473     m_genericImpl = NULL;
474     m_dbImpl = NULL;
475     m_compareFunc = NULL;
476     m_compareFuncData = 0;
477     m_colsInfo = wxColumnList();
478     m_textColor = wxNullColour;
479     m_bgColor = wxNullColour;
480     m_textctrlWrapper = NULL;
481     m_current = -1;
482     m_renameTimer = NULL;
483 }
484 
485 class wxGenericListCtrlHook : public wxGenericListCtrl
486 {
487 public:
wxGenericListCtrlHook(wxListCtrl * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)488     wxGenericListCtrlHook(wxListCtrl* parent,
489                           wxWindowID id,
490                           const wxPoint& pos,
491                           const wxSize& size,
492                           long style,
493                           const wxValidator& validator,
494                           const wxString& name)
495         : wxGenericListCtrl(parent, id, pos, size, style, validator, name),
496           m_nativeListCtrl(parent)
497     {
498     }
499 
500 protected:
OnGetItemAttr(long item) const501     virtual wxListItemAttr * OnGetItemAttr(long item) const
502     {
503         return m_nativeListCtrl->OnGetItemAttr(item);
504     }
505 
OnGetItemImage(long item) const506     virtual int OnGetItemImage(long item) const
507     {
508         return m_nativeListCtrl->OnGetItemImage(item);
509     }
510 
OnGetItemColumnImage(long item,long column) const511     virtual int OnGetItemColumnImage(long item, long column) const
512     {
513         return m_nativeListCtrl->OnGetItemColumnImage(item, column);
514     }
515 
OnGetItemText(long item,long column) const516     virtual wxString OnGetItemText(long item, long column) const
517     {
518         return m_nativeListCtrl->OnGetItemText(item, column);
519     }
520 
521     wxListCtrl* m_nativeListCtrl;
522 
523 };
524 
OnLeftDown(wxMouseEvent & event)525 void wxListCtrl::OnLeftDown(wxMouseEvent& event)
526 {
527     if ( m_textctrlWrapper )
528     {
529         m_current = -1;
530         m_textctrlWrapper->AcceptChangesAndFinish();
531     }
532 
533     int hitResult;
534     long current = HitTest(event.GetPosition(), hitResult);
535     if ((current == m_current) &&
536         (hitResult & wxLIST_HITTEST_ONITEMLABEL) &&
537         HasFlag(wxLC_EDIT_LABELS) )
538     {
539         if ( m_renameTimer )
540             m_renameTimer->Start( 250, true );
541     }
542     else
543     {
544         m_current = current;
545     }
546     event.Skip();
547 }
548 
OnDblClick(wxMouseEvent & event)549 void wxListCtrl::OnDblClick(wxMouseEvent& event)
550 {
551     if ( m_renameTimer && m_renameTimer->IsRunning() )
552         m_renameTimer->Stop();
553     event.Skip();
554 }
555 
OnRightDown(wxMouseEvent & event)556 void wxListCtrl::OnRightDown(wxMouseEvent& event)
557 {
558     if (m_dbImpl)
559         FireMouseEvent(wxEVT_LIST_ITEM_RIGHT_CLICK, event.GetPosition());
560     event.Skip();
561 }
562 
OnMiddleDown(wxMouseEvent & event)563 void wxListCtrl::OnMiddleDown(wxMouseEvent& event)
564 {
565     if (m_dbImpl)
566         FireMouseEvent(wxEVT_LIST_ITEM_MIDDLE_CLICK, event.GetPosition());
567     event.Skip();
568 }
569 
FireMouseEvent(wxEventType eventType,wxPoint position)570 void wxListCtrl::FireMouseEvent(wxEventType eventType, wxPoint position)
571 {
572     wxListEvent le( eventType, GetId() );
573     le.SetEventObject(this);
574     le.m_pointDrag = position;
575     le.m_itemIndex = -1;
576 
577     int flags;
578     long item = HitTest(position, flags);
579     if (flags & wxLIST_HITTEST_ONITEM)
580     {
581         le.m_itemIndex = item;
582         le.m_item.m_itemId = item;
583         GetItem(le.m_item);
584         HandleWindowEvent(le);
585     }
586 }
587 
OnChar(wxKeyEvent & event)588 void wxListCtrl::OnChar(wxKeyEvent& event)
589 {
590 
591 
592     if (m_dbImpl)
593     {
594         wxListEvent le( wxEVT_LIST_KEY_DOWN, GetId() );
595         le.SetEventObject(this);
596         le.m_code = event.GetKeyCode();
597         le.m_itemIndex = -1;
598 
599         if (m_current == -1)
600         {
601             // if m_current isn't set, check if there's been a selection
602             // made before continuing
603             m_current = GetNextItem(-1, wxLIST_NEXT_BELOW, wxLIST_STATE_SELECTED);
604         }
605 
606         // We need to determine m_current ourselves when navigation keys
607         // are used. Note that PAGEUP and PAGEDOWN do not alter the current
608         // item on native Mac ListCtrl, so we only handle up and down keys.
609         switch ( event.GetKeyCode() )
610         {
611             case WXK_UP:
612                 if ( m_current > 0 )
613                     m_current -= 1;
614                 else
615                     m_current = 0;
616 
617                 break;
618 
619             case WXK_DOWN:
620                 if ( m_current < GetItemCount() - 1 )
621                     m_current += 1;
622                 else
623                     m_current = GetItemCount() - 1;
624 
625                 break;
626         }
627 
628         if (m_current != -1)
629         {
630             le.m_itemIndex = m_current;
631             le.m_item.m_itemId = m_current;
632             GetItem(le.m_item);
633             HandleWindowEvent(le);
634         }
635     }
636     event.Skip();
637 }
638 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)639 bool wxListCtrl::Create(wxWindow *parent,
640                         wxWindowID id,
641                         const wxPoint& pos,
642                         const wxSize& size,
643                         long style,
644                         const wxValidator& validator,
645                         const wxString& name)
646 {
647 
648     // for now, we'll always use the generic list control for ICON and LIST views,
649     // because they dynamically change the number of columns on resize.
650     // Also, allow the user to set it to use the list ctrl as well.
651     if ( (wxSystemOptions::HasOption( wxMAC_ALWAYS_USE_GENERIC_LISTCTRL )
652             && (wxSystemOptions::GetOptionInt( wxMAC_ALWAYS_USE_GENERIC_LISTCTRL ) == 1)) ||
653             (style & wxLC_ICON) || (style & wxLC_SMALL_ICON) || (style & wxLC_LIST) )
654     {
655         long paneStyle = style;
656         paneStyle &= ~wxSIMPLE_BORDER;
657         paneStyle &= ~wxDOUBLE_BORDER;
658         paneStyle &= ~wxSUNKEN_BORDER;
659         paneStyle &= ~wxRAISED_BORDER;
660         paneStyle &= ~wxSTATIC_BORDER;
661         if ( !wxWindow::Create(parent, id, pos, size, paneStyle | wxNO_BORDER, name) )
662             return false;
663 
664         // since the generic control is a child, make sure we position it at 0, 0
665         m_genericImpl = new wxGenericListCtrlHook(this, id, wxPoint(0, 0), size, style, validator, name);
666         m_genericImpl->PushEventHandler( new wxMacListCtrlEventDelegate( this, GetId() ) );
667         return true;
668     }
669 
670     else
671     {
672         DontCreatePeer();
673         if ( !wxWindow::Create(parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), name) )
674             return false;
675         m_dbImpl = new wxMacDataBrowserListCtrlControl( this, pos, size, style );
676         SetPeer(m_dbImpl);
677 
678         MacPostControlCreate( pos, size );
679 
680         InstallControlEventHandler( GetPeer()->GetControlRef() , GetwxMacListCtrlEventHandlerUPP(),
681             GetEventTypeCount(eventList), eventList, this,
682             (EventHandlerRef *)&m_macListCtrlEventHandler);
683 
684         m_renameTimer = new wxListCtrlRenameTimer( this );
685 
686         Connect( wxID_ANY, wxEVT_CHAR, wxCharEventHandler(wxListCtrl::OnChar), NULL, this );
687         Connect( wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(wxListCtrl::OnLeftDown), NULL, this );
688         Connect( wxID_ANY, wxEVT_LEFT_DCLICK, wxMouseEventHandler(wxListCtrl::OnDblClick), NULL, this );
689         Connect( wxID_ANY, wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxListCtrl::OnMiddleDown), NULL, this );
690         Connect( wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxListCtrl::OnRightDown), NULL, this );
691     }
692 
693     return true;
694 }
695 
~wxListCtrl()696 wxListCtrl::~wxListCtrl()
697 {
698     if (m_genericImpl)
699     {
700         m_genericImpl->PopEventHandler(/* deleteHandler = */ true);
701     }
702 
703     if (m_ownsImageListNormal)
704         delete m_imageListNormal;
705     if (m_ownsImageListSmall)
706         delete m_imageListSmall;
707     if (m_ownsImageListState)
708         delete m_imageListState;
709 
710     delete m_renameTimer;
711 
712     WX_CLEAR_LIST(wxColumnList, m_colsInfo);
713 }
714 
715 /*static*/
716 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))717 wxListCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
718 {
719     wxVisualAttributes attr;
720 
721     attr.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
722     attr.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX );
723     static wxFont font = wxFont(wxOSX_SYSTEM_FONT_VIEWS);
724     attr.font = font;
725 
726     return attr;
727 }
728 
729 // ----------------------------------------------------------------------------
730 // set/get/change style
731 // ----------------------------------------------------------------------------
732 
733 // Add or remove a single window style
SetSingleStyle(long style,bool add)734 void wxListCtrl::SetSingleStyle(long style, bool add)
735 {
736     long flag = GetWindowStyleFlag();
737 
738     // Get rid of conflicting styles
739     if ( add )
740     {
741         if ( style & wxLC_MASK_TYPE)
742             flag = flag & ~wxLC_MASK_TYPE;
743         if ( style & wxLC_MASK_ALIGN )
744             flag = flag & ~wxLC_MASK_ALIGN;
745         if ( style & wxLC_MASK_SORT )
746             flag = flag & ~wxLC_MASK_SORT;
747     }
748 
749     if ( add )
750         flag |= style;
751     else
752         flag &= ~style;
753 
754     SetWindowStyleFlag(flag);
755 }
756 
757 // Set the whole window style
SetWindowStyleFlag(long flag)758 void wxListCtrl::SetWindowStyleFlag(long flag)
759 {
760     if ( flag != m_windowStyle )
761     {
762         m_windowStyle = flag;
763 
764         if (m_genericImpl)
765         {
766             m_genericImpl->SetWindowStyleFlag(flag);
767         }
768 
769         Refresh();
770     }
771 }
772 
DoSetSize(int x,int y,int width,int height,int sizeFlags)773 void wxListCtrl::DoSetSize( int x, int y, int width, int height, int sizeFlags )
774 {
775     wxListCtrlBase::DoSetSize(x, y, width, height, sizeFlags);
776 
777     if (m_genericImpl)
778         m_genericImpl->SetSize(0, 0, width, height, sizeFlags);
779 
780     // determine if we need a horizontal scrollbar, and add it if so
781     if (m_dbImpl)
782     {
783         int totalWidth = 0;
784         for (int column = 0; column < GetColumnCount(); column++)
785         {
786               totalWidth += m_dbImpl->GetColumnWidth( column );
787         }
788 
789         if ( !(m_dbImpl->GetFlags() & wxHSCROLL) )
790         {
791             Boolean vertScrollBar;
792             GetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), NULL, &vertScrollBar );
793             if (totalWidth > width)
794                 SetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), true, vertScrollBar );
795             else
796                 SetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), false, vertScrollBar );
797         }
798     }
799 }
800 
SetFont(const wxFont & font)801 bool wxListCtrl::SetFont(const wxFont& font)
802 {
803     bool rv = wxListCtrlBase::SetFont(font);
804     if (m_genericImpl)
805         rv = m_genericImpl->SetFont(font);
806     return rv;
807 }
808 
SetForegroundColour(const wxColour & colour)809 bool wxListCtrl::SetForegroundColour(const wxColour& colour)
810 {
811     bool rv = true;
812     if (m_genericImpl)
813         rv = m_genericImpl->SetForegroundColour(colour);
814     if (m_dbImpl)
815         SetTextColour(colour);
816     return rv;
817 }
818 
SetBackgroundColour(const wxColour & colour)819 bool wxListCtrl::SetBackgroundColour(const wxColour& colour)
820 {
821     bool rv = true;
822     if (m_genericImpl)
823         rv = m_genericImpl->SetBackgroundColour(colour);
824     if (m_dbImpl)
825         m_bgColor = colour;
826     return rv;
827 }
828 
GetBackgroundColour() const829 wxColour wxListCtrl::GetBackgroundColour() const
830 {
831     if (m_genericImpl)
832         return m_genericImpl->GetBackgroundColour();
833     if (m_dbImpl)
834         return m_bgColor;
835 
836     return wxNullColour;
837 }
838 
Freeze()839 void wxListCtrl::Freeze ()
840 {
841     if (m_genericImpl)
842         m_genericImpl->Freeze();
843     wxListCtrlBase::Freeze();
844 }
845 
Thaw()846 void wxListCtrl::Thaw ()
847 {
848     if (m_genericImpl)
849         m_genericImpl->Thaw();
850     wxListCtrlBase::Thaw();
851 }
852 
Update()853 void wxListCtrl::Update ()
854 {
855     if (m_genericImpl)
856         m_genericImpl->Update();
857     wxListCtrlBase::Update();
858 }
859 
860 // ----------------------------------------------------------------------------
861 // accessors
862 // ----------------------------------------------------------------------------
863 
864 // Gets information about this column
GetColumn(int col,wxListItem & item) const865 bool wxListCtrl::GetColumn(int col, wxListItem& item) const
866 {
867     if (m_genericImpl)
868         return m_genericImpl->GetColumn(col, item);
869 
870     bool success = true;
871 
872     if (m_dbImpl)
873     {
874         wxColumnList::compatibility_iterator node = m_colsInfo.Item( col );
875         wxASSERT_MSG( node, wxT("invalid column index in wxMacListCtrlItem") );
876         wxListItem* column = node->GetData();
877 
878         long mask = column->GetMask();
879         if (mask & wxLIST_MASK_TEXT)
880             item.SetText(column->GetText());
881         if (mask & wxLIST_MASK_DATA)
882             item.SetData(column->GetData());
883         if (mask & wxLIST_MASK_IMAGE)
884             item.SetImage(column->GetImage());
885         if (mask & wxLIST_MASK_STATE)
886             item.SetState(column->GetState());
887         if (mask & wxLIST_MASK_FORMAT)
888             item.SetAlign(column->GetAlign());
889         if (mask & wxLIST_MASK_WIDTH)
890             item.SetWidth(column->GetWidth());
891     }
892 
893     return success;
894 }
895 
896 // Sets information about this column
SetColumn(int col,const wxListItem & item)897 bool wxListCtrl::SetColumn(int col, const wxListItem& item)
898 {
899     if (m_genericImpl)
900         return m_genericImpl->SetColumn(col, item);
901 
902     if (m_dbImpl)
903     {
904         wxASSERT_MSG( col < (int)m_colsInfo.GetCount(), wxT("invalid column index in wxMacListCtrlItem") );
905 
906         long mask = item.GetMask();
907         {
908             wxListItem listItem;
909             GetColumn( col, listItem );
910 
911             if (mask & wxLIST_MASK_TEXT)
912                 listItem.SetText(item.GetText());
913             if (mask & wxLIST_MASK_DATA)
914                 listItem.SetData(item.GetData());
915             if (mask & wxLIST_MASK_IMAGE)
916                 listItem.SetImage(item.GetImage());
917             if (mask & wxLIST_MASK_STATE)
918                 listItem.SetState(item.GetState());
919             if (mask & wxLIST_MASK_FORMAT)
920                 listItem.SetAlign(item.GetAlign());
921             if (mask & wxLIST_MASK_WIDTH)
922                 listItem.SetWidth(item.GetWidth());
923         }
924 
925         // change the appearance in the databrowser.
926         DataBrowserListViewHeaderDesc columnDesc;
927         columnDesc.version=kDataBrowserListViewLatestHeaderDesc;
928 
929         DataBrowserTableViewColumnID id = 0;
930         verify_noerr( m_dbImpl->GetColumnIDFromIndex( col, &id ) );
931         verify_noerr( m_dbImpl->GetHeaderDesc( id, &columnDesc ) );
932 
933         /*
934         if (item.GetMask() & wxLIST_MASK_TEXT)
935         {
936             wxFontEncoding enc;
937             if ( m_font.IsOk() )
938                 enc = GetFont().GetEncoding();
939             else
940                 enc = wxLocale::GetSystemEncoding();
941             wxCFStringRef cfTitle;
942             cfTitle.Assign( item.GetText() , enc );
943             if(columnDesc.titleString)
944                 CFRelease(columnDesc.titleString);
945             columnDesc.titleString = cfTitle;
946         }
947         */
948 
949         if (item.GetMask() & wxLIST_MASK_IMAGE && item.GetImage() != -1 )
950         {
951             wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
952             if (imageList && imageList->GetImageCount() > 0 )
953             {
954                 wxBitmap bmp = imageList->GetBitmap( item.GetImage() );
955                 IconRef icon = bmp.GetIconRef();
956                 columnDesc.btnContentInfo.u.iconRef = icon;
957                 columnDesc.btnContentInfo.contentType = kControlContentIconRef;
958             }
959         }
960 
961         verify_noerr( m_dbImpl->SetHeaderDesc( id, &columnDesc ) );
962 
963     }
964     return true;
965 }
966 
GetColumnCount() const967 int wxListCtrl::GetColumnCount() const
968 {
969     if (m_genericImpl)
970         return m_genericImpl->GetColumnCount();
971 
972     if (m_dbImpl)
973     {
974         UInt32 count;
975         m_dbImpl->GetColumnCount(&count);
976         return count;
977     }
978 
979     return m_colCount;
980 }
981 
982 // Gets the column width
GetColumnWidth(int col) const983 int wxListCtrl::GetColumnWidth(int col) const
984 {
985     if (m_genericImpl)
986         return m_genericImpl->GetColumnWidth(col);
987 
988     if (m_dbImpl)
989     {
990         return m_dbImpl->GetColumnWidth(col);
991     }
992 
993     return 0;
994 }
995 
996 // Sets the column width
SetColumnWidth(int col,int width)997 bool wxListCtrl::SetColumnWidth(int col, int width)
998 {
999     if (m_genericImpl)
1000         return m_genericImpl->SetColumnWidth(col, width);
1001 
1002     if (m_dbImpl)
1003     {
1004         if ( width == wxLIST_AUTOSIZE_USEHEADER )
1005         {
1006             width = 150; // FIXME
1007         }
1008 
1009         if (col == -1)
1010         {
1011             for (int column = 0; column < GetColumnCount(); column++)
1012             {
1013                 wxListItem colInfo;
1014                 GetColumn(column, colInfo);
1015 
1016                 colInfo.SetWidth(width);
1017                 SetColumn(column, colInfo);
1018 
1019                 const int mywidth = (width == wxLIST_AUTOSIZE)
1020                                     ? CalcColumnAutoWidth(column) : width;
1021                 m_dbImpl->SetColumnWidth(column, mywidth);
1022             }
1023         }
1024         else
1025         {
1026             if ( width == wxLIST_AUTOSIZE )
1027                 width = CalcColumnAutoWidth(col);
1028 
1029             wxListItem colInfo;
1030             GetColumn(col, colInfo);
1031 
1032             colInfo.SetWidth(width);
1033             SetColumn(col, colInfo);
1034             m_dbImpl->SetColumnWidth(col, width);
1035         }
1036         return true;
1037     }
1038 
1039     return false;
1040 }
1041 
1042 // Gets the number of items that can fit vertically in the
1043 // visible area of the list control (list or report view)
1044 // or the total number of items in the list control (icon
1045 // or small icon view)
GetCountPerPage() const1046 int wxListCtrl::GetCountPerPage() const
1047 {
1048     if (m_genericImpl)
1049         return m_genericImpl->GetCountPerPage();
1050 
1051     if (m_dbImpl)
1052     {
1053         UInt16 height = 1;
1054         m_dbImpl->GetDefaultRowHeight( &height );
1055         if (height > 0)
1056             return GetClientSize().y / height;
1057     }
1058 
1059     return 1;
1060 }
1061 
1062 // Gets the edit control for editing labels.
GetEditControl() const1063 wxTextCtrl* wxListCtrl::GetEditControl() const
1064 {
1065     if (m_genericImpl)
1066         return m_genericImpl->GetEditControl();
1067 
1068     return NULL;
1069 }
1070 
1071 // Gets information about the item
GetItem(wxListItem & info) const1072 bool wxListCtrl::GetItem(wxListItem& info) const
1073 {
1074     if (m_genericImpl)
1075         return m_genericImpl->GetItem(info);
1076 
1077     if (m_dbImpl)
1078     {
1079         if (!IsVirtual())
1080         {
1081             if (info.m_itemId >= 0 && info.m_itemId < GetItemCount())
1082             {
1083                 m_dbImpl->MacGetColumnInfo(info.m_itemId, info.m_col, info);
1084                 // MacGetColumnInfo returns erroneous information in the state field, so zero it.
1085                 info.SetState(0);
1086                 if (info.GetMask() & wxLIST_MASK_STATE)
1087                 {
1088                     DataBrowserItemID id = (DataBrowserItemID)m_dbImpl->GetItemFromLine(info.m_itemId);
1089                     if (IsDataBrowserItemSelected( m_dbImpl->GetControlRef(), id ))
1090                         info.SetState(info.GetState() | wxLIST_STATE_SELECTED);
1091                 }
1092             }
1093         }
1094         else
1095         {
1096             if (info.m_itemId >= 0 && info.m_itemId < GetItemCount())
1097             {
1098                 info.SetText( OnGetItemText(info.m_itemId, info.m_col) );
1099                 info.SetImage( OnGetItemColumnImage(info.m_itemId, info.m_col) );
1100                 if (info.GetMask() & wxLIST_MASK_STATE)
1101                 {
1102                     if (IsDataBrowserItemSelected( m_dbImpl->GetControlRef(), info.m_itemId+1 ))
1103                         info.SetState(info.GetState() | wxLIST_STATE_SELECTED);
1104                 }
1105 
1106                 wxListItemAttr* attrs = OnGetItemAttr( info.m_itemId );
1107                 if (attrs)
1108                 {
1109                     info.SetFont( attrs->GetFont() );
1110                     info.SetBackgroundColour( attrs->GetBackgroundColour() );
1111                     info.SetTextColour( attrs->GetTextColour() );
1112                 }
1113             }
1114         }
1115     }
1116     bool success = true;
1117     return success;
1118 }
1119 
1120 // Sets information about the item
SetItem(wxListItem & info)1121 bool wxListCtrl::SetItem(wxListItem& info)
1122 {
1123     if (m_genericImpl)
1124         return m_genericImpl->SetItem(info);
1125 
1126     if (m_dbImpl)
1127         m_dbImpl->MacSetColumnInfo( info.m_itemId, info.m_col, &info );
1128 
1129     return true;
1130 }
1131 
SetItem(long index,int col,const wxString & label,int imageId)1132 long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
1133 {
1134     if (m_genericImpl)
1135         return m_genericImpl->SetItem(index, col, label, imageId);
1136 
1137     wxListItem info;
1138     info.m_text = label;
1139     info.m_mask = wxLIST_MASK_TEXT;
1140     info.m_itemId = index;
1141     info.m_col = col;
1142     if ( imageId > -1 )
1143     {
1144         info.m_image = imageId;
1145         info.m_mask |= wxLIST_MASK_IMAGE;
1146     }
1147     return SetItem(info);
1148 }
1149 
1150 
1151 // Gets the item state
GetItemState(long item,long stateMask) const1152 int wxListCtrl::GetItemState(long item, long stateMask) const
1153 {
1154     if (m_genericImpl)
1155         return m_genericImpl->GetItemState(item, stateMask);
1156 
1157     if (m_dbImpl)
1158     {
1159         if ( HasFlag(wxLC_VIRTUAL) )
1160         {
1161             if (stateMask == wxLIST_STATE_SELECTED)
1162             {
1163                 if (IsDataBrowserItemSelected( m_dbImpl->GetControlRef(), item+1 ))
1164                     return wxLIST_STATE_SELECTED;
1165                 else
1166                     return 0;
1167             }
1168         }
1169         else
1170         {
1171             wxListItem info;
1172 
1173             info.m_mask = wxLIST_MASK_STATE;
1174             info.m_stateMask = stateMask;
1175             info.m_itemId = item;
1176 
1177             if (!GetItem(info))
1178                 return 0;
1179 
1180             return info.m_state;
1181         }
1182     }
1183 
1184     return 0;
1185 }
1186 
1187 // Sets the item state
SetItemState(long item,long state,long stateMask)1188 bool wxListCtrl::SetItemState(long item, long state, long stateMask)
1189 {
1190     if (m_genericImpl)
1191         return m_genericImpl->SetItemState(item, state, stateMask);
1192 
1193     if (m_dbImpl)
1194     {
1195         DataBrowserSetOption option = kDataBrowserItemsAdd;
1196         if ( (stateMask & wxLIST_STATE_SELECTED) && state == 0 )
1197             option = kDataBrowserItemsRemove;
1198 
1199         if (item == -1)
1200         {
1201             if ( HasFlag(wxLC_VIRTUAL) )
1202             {
1203                 wxMacDataItemBrowserSelectionSuppressor suppressor(m_dbImpl);
1204                 m_dbImpl->SetSelectedAllItems(option);
1205             }
1206             else
1207             {
1208                 for(int i = 0; i < GetItemCount();i++)
1209                 {
1210                     wxListItem info;
1211                     info.m_itemId = i;
1212                     info.m_mask = wxLIST_MASK_STATE;
1213                     info.m_stateMask = stateMask;
1214                     info.m_state = state;
1215                     SetItem(info);
1216                 }
1217             }
1218         }
1219         else
1220         {
1221             if ( HasFlag(wxLC_VIRTUAL) )
1222             {
1223                 long itemID = item+1;
1224                 bool isSelected = IsDataBrowserItemSelected(m_dbImpl->GetControlRef(), (DataBrowserItemID)itemID );
1225                 bool isSelectedState = (state == wxLIST_STATE_SELECTED);
1226 
1227                 // toggle the selection state if wxListInfo state and actual state don't match.
1228                 if ( (stateMask & wxLIST_STATE_SELECTED) && isSelected != isSelectedState )
1229                 {
1230                 SetDataBrowserSelectedItems(m_dbImpl->GetControlRef(), 1, (DataBrowserItemID*)&itemID, option);
1231             }
1232             }
1233             else
1234             {
1235                 wxListItem info;
1236                 info.m_itemId = item;
1237                 info.m_mask = wxLIST_MASK_STATE;
1238                 info.m_stateMask = stateMask;
1239                 info.m_state = state;
1240                 return SetItem(info);
1241             }
1242         }
1243     }
1244     return true;
1245 }
1246 
1247 // Sets the item image
SetItemImage(long item,int image,int WXUNUSED (selImage))1248 bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
1249 {
1250     return SetItemColumnImage(item, 0, image);
1251 }
1252 
1253 // Sets the item image
SetItemColumnImage(long item,long column,int image)1254 bool wxListCtrl::SetItemColumnImage(long item, long column, int image)
1255 {
1256     if (m_genericImpl)
1257         return m_genericImpl->SetItemColumnImage(item, column, image);
1258 
1259     wxListItem info;
1260 
1261     info.m_mask = wxLIST_MASK_IMAGE;
1262     info.m_image = image;
1263     info.m_itemId = item;
1264     info.m_col = column;
1265 
1266     return SetItem(info);
1267 }
1268 
1269 // Gets the item text
GetItemText(long item,int column) const1270 wxString wxListCtrl::GetItemText(long item, int column) const
1271 {
1272     if (m_genericImpl)
1273         return m_genericImpl->GetItemText(item, column);
1274 
1275     wxListItem info;
1276 
1277     info.m_mask = wxLIST_MASK_TEXT;
1278     info.m_itemId = item;
1279     info.m_col = column;
1280 
1281     if (!GetItem(info))
1282         return wxEmptyString;
1283     return info.m_text;
1284 }
1285 
1286 // Sets the item text
SetItemText(long item,const wxString & str)1287 void wxListCtrl::SetItemText(long item, const wxString& str)
1288 {
1289     if (m_genericImpl)
1290         return m_genericImpl->SetItemText(item, str);
1291 
1292     wxListItem info;
1293 
1294     info.m_mask = wxLIST_MASK_TEXT;
1295     info.m_itemId = item;
1296     info.m_text = str;
1297 
1298     SetItem(info);
1299 }
1300 
1301 // Gets the item data
GetItemData(long item) const1302 long wxListCtrl::GetItemData(long item) const
1303 {
1304     if (m_genericImpl)
1305         return m_genericImpl->GetItemData(item);
1306 
1307     wxListItem info;
1308 
1309     info.m_mask = wxLIST_MASK_DATA;
1310     info.m_itemId = item;
1311 
1312     if (!GetItem(info))
1313         return 0;
1314     return info.m_data;
1315 }
1316 
1317 // Sets the item data
SetItemPtrData(long item,wxUIntPtr data)1318 bool wxListCtrl::SetItemPtrData(long item, wxUIntPtr data)
1319 {
1320     if (m_genericImpl)
1321         return m_genericImpl->SetItemData(item, data);
1322 
1323     wxListItem info;
1324 
1325     info.m_mask = wxLIST_MASK_DATA;
1326     info.m_itemId = item;
1327     info.m_data = data;
1328 
1329     return SetItem(info);
1330 }
1331 
GetViewRect() const1332 wxRect wxListCtrl::GetViewRect() const
1333 {
1334     wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
1335                     wxT("wxListCtrl::GetViewRect() only works in icon mode") );
1336 
1337     if (m_genericImpl)
1338         return m_genericImpl->GetViewRect();
1339 
1340     wxRect rect;
1341     return rect;
1342 }
1343 
GetSubItemRect(long item,long subItem,wxRect & rect,int code) const1344 bool wxListCtrl::GetSubItemRect( long item, long subItem, wxRect& rect, int code ) const
1345 {
1346     if (m_genericImpl)
1347         return m_genericImpl->GetSubItemRect(item, subItem, rect, code);
1348 
1349     // TODO: implement for DataBrowser implementation
1350     return false;
1351 }
1352 
1353 // Gets the item rectangle
GetItemRect(long item,wxRect & rect,int code) const1354 bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
1355 {
1356     if (m_genericImpl)
1357         return m_genericImpl->GetItemRect(item, rect, code);
1358 
1359 
1360     if (m_dbImpl)
1361     {
1362         DataBrowserItemID id;
1363 
1364         DataBrowserTableViewColumnID col = 0;
1365         verify_noerr( m_dbImpl->GetColumnIDFromIndex( 0, &col ) );
1366 
1367         Rect bounds;
1368         DataBrowserPropertyPart part = kDataBrowserPropertyEnclosingPart;
1369         if ( code == wxLIST_RECT_LABEL )
1370             part = kDataBrowserPropertyTextPart;
1371         else if ( code == wxLIST_RECT_ICON )
1372             part = kDataBrowserPropertyIconPart;
1373 
1374         if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL) )
1375         {
1376             wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(item);
1377             id = (DataBrowserItemID) thisItem;
1378         }
1379         else
1380             id = item+1;
1381 
1382         GetDataBrowserItemPartBounds( m_dbImpl->GetControlRef(), id, col, part, &bounds );
1383 
1384         rect.x = bounds.left;
1385         rect.y = bounds.top;
1386         rect.width = bounds.right - bounds.left; //GetClientSize().x; // we need the width of the whole row, not just the item.
1387         rect.height = bounds.bottom - bounds.top;
1388         //fprintf("id = %d, bounds = %d, %d, %d, %d\n", id, rect.x, rect.y, rect.width, rect.height);
1389     }
1390     return true;
1391 }
1392 
1393 // Gets the item position
GetItemPosition(long item,wxPoint & pos) const1394 bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
1395 {
1396     if (m_genericImpl)
1397         return m_genericImpl->GetItemPosition(item, pos);
1398 
1399     bool success = false;
1400 
1401     if (m_dbImpl)
1402     {
1403         wxRect itemRect;
1404         GetItemRect(item, itemRect);
1405         pos = itemRect.GetPosition();
1406         success = true;
1407     }
1408 
1409     return success;
1410 }
1411 
1412 // Sets the item position.
SetItemPosition(long item,const wxPoint & pos)1413 bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
1414 {
1415     if (m_genericImpl)
1416         return m_genericImpl->SetItemPosition(item, pos);
1417 
1418     return false;
1419 }
1420 
1421 // Gets the number of items in the list control
GetItemCount() const1422 int wxListCtrl::GetItemCount() const
1423 {
1424     if (m_genericImpl)
1425         return m_genericImpl->GetItemCount();
1426 
1427     if (m_dbImpl)
1428         return m_dbImpl->MacGetCount();
1429 
1430     return m_count;
1431 }
1432 
SetItemSpacing(int spacing,bool isSmall)1433 void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
1434 {
1435     if (m_genericImpl)
1436         m_genericImpl->SetItemSpacing(spacing, isSmall);
1437 }
1438 
GetItemSpacing() const1439 wxSize wxListCtrl::GetItemSpacing() const
1440 {
1441     if (m_genericImpl)
1442         return m_genericImpl->GetItemSpacing();
1443 
1444     return wxSize(0, 0);
1445 }
1446 
SetItemTextColour(long item,const wxColour & col)1447 void wxListCtrl::SetItemTextColour( long item, const wxColour &col )
1448 {
1449     if (m_genericImpl)
1450     {
1451         m_genericImpl->SetItemTextColour(item, col);
1452         return;
1453     }
1454 
1455     wxListItem info;
1456     info.m_itemId = item;
1457     info.SetTextColour( col );
1458     SetItem( info );
1459 }
1460 
GetItemTextColour(long item) const1461 wxColour wxListCtrl::GetItemTextColour( long item ) const
1462 {
1463     if (m_genericImpl)
1464         return m_genericImpl->GetItemTextColour(item);
1465 
1466     if (m_dbImpl)
1467     {
1468         wxListItem info;
1469         if (GetItem(info))
1470             return info.GetTextColour();
1471     }
1472     return wxNullColour;
1473 }
1474 
SetItemBackgroundColour(long item,const wxColour & col)1475 void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
1476 {
1477     if (m_genericImpl)
1478     {
1479         m_genericImpl->SetItemBackgroundColour(item, col);
1480         return;
1481     }
1482 
1483     wxListItem info;
1484     info.m_itemId = item;
1485     info.SetBackgroundColour( col );
1486     SetItem( info );
1487 }
1488 
GetItemBackgroundColour(long item) const1489 wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
1490 {
1491     if (m_genericImpl)
1492         return m_genericImpl->GetItemBackgroundColour(item);
1493 
1494     if (m_dbImpl)
1495     {
1496         wxListItem info;
1497         if (GetItem(info))
1498             return info.GetBackgroundColour();
1499     }
1500     return wxNullColour;
1501 }
1502 
SetItemFont(long item,const wxFont & f)1503 void wxListCtrl::SetItemFont( long item, const wxFont &f )
1504 {
1505     if (m_genericImpl)
1506     {
1507         m_genericImpl->SetItemFont(item, f);
1508         return;
1509     }
1510 
1511     wxListItem info;
1512     info.m_itemId = item;
1513     info.SetFont( f );
1514     SetItem( info );
1515 }
1516 
GetItemFont(long item) const1517 wxFont wxListCtrl::GetItemFont( long item ) const
1518 {
1519     if (m_genericImpl)
1520         return m_genericImpl->GetItemFont(item);
1521 
1522     if (m_dbImpl)
1523     {
1524         wxListItem info;
1525         if (GetItem(info))
1526             return info.GetFont();
1527     }
1528 
1529     return wxNullFont;
1530 }
1531 
1532 // Gets the number of selected items in the list control
GetSelectedItemCount() const1533 int wxListCtrl::GetSelectedItemCount() const
1534 {
1535     if (m_genericImpl)
1536         return m_genericImpl->GetSelectedItemCount();
1537 
1538     if (m_dbImpl)
1539         return m_dbImpl->GetSelectedItemCount(NULL, true);
1540 
1541     return 0;
1542 }
1543 
1544 // Gets the text colour of the listview
GetTextColour() const1545 wxColour wxListCtrl::GetTextColour() const
1546 {
1547     if (m_genericImpl)
1548         return m_genericImpl->GetTextColour();
1549 
1550     // TODO: we need owner drawn list items to customize text color.
1551     if (m_dbImpl)
1552         return m_textColor;
1553 
1554     return wxNullColour;
1555 }
1556 
1557 // Sets the text colour of the listview
SetTextColour(const wxColour & col)1558 void wxListCtrl::SetTextColour(const wxColour& col)
1559 {
1560     if (m_genericImpl)
1561     {
1562         m_genericImpl->SetTextColour(col);
1563         return;
1564     }
1565 
1566     if (m_dbImpl)
1567         m_textColor = col;
1568 }
1569 
1570 // Gets the index of the topmost visible item when in
1571 // list or report view
GetTopItem() const1572 long wxListCtrl::GetTopItem() const
1573 {
1574     if (m_genericImpl)
1575         return m_genericImpl->GetTopItem();
1576 
1577     if (m_dbImpl)
1578     {
1579         int flags = 0;
1580         long item = HitTest( wxPoint(1, 1), flags);
1581         if (flags == wxLIST_HITTEST_ONITEM)
1582             return item;
1583     }
1584 
1585     return 0;
1586 }
1587 
1588 // Searches for an item, starting from 'item'.
1589 // 'geometry' is one of
1590 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1591 // 'state' is a state bit flag, one or more of
1592 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1593 // item can be -1 to find the first item that matches the
1594 // specified flags.
1595 // Returns the item or -1 if unsuccessful.
GetNextItem(long item,int geom,int state) const1596 long wxListCtrl::GetNextItem(long item, int geom, int state) const
1597 {
1598     if (m_genericImpl)
1599         return m_genericImpl->GetNextItem(item, geom, state);
1600 
1601     // TODO: implement all geometry and state options?
1602     if ( m_dbImpl )
1603     {
1604         if ( geom == wxLIST_NEXT_ALL || geom == wxLIST_NEXT_BELOW )
1605         {
1606             long count = m_dbImpl->MacGetCount() ;
1607             for ( long line = item + 1 ; line < count; line++ )
1608             {
1609                 DataBrowserItemID id = line + 1;
1610                 if ( !IsVirtual() )
1611                     id = (DataBrowserItemID)m_dbImpl->GetItemFromLine(line);
1612 
1613                 if ( (state & wxLIST_STATE_FOCUSED) && (m_current == line))
1614                     return line;
1615 
1616                 if ( (state == wxLIST_STATE_DONTCARE ) )
1617                     return line;
1618 
1619                 if ( (state & wxLIST_STATE_SELECTED) && IsDataBrowserItemSelected(m_dbImpl->GetControlRef(), id ) )
1620                     return line;
1621             }
1622         }
1623 
1624         if ( geom == wxLIST_NEXT_ABOVE )
1625         {
1626             int item2 = item;
1627             if ( item2 == -1 )
1628                 item2 = m_dbImpl->MacGetCount();
1629 
1630             for ( long line = item2 - 1 ; line >= 0; line-- )
1631             {
1632                 DataBrowserItemID id = line + 1;
1633                 if ( !IsVirtual() )
1634                     id = (DataBrowserItemID)m_dbImpl->GetItemFromLine(line);
1635 
1636                 if ( (state & wxLIST_STATE_FOCUSED) && (m_current == line))
1637                     return line;
1638 
1639                 if ( (state == wxLIST_STATE_DONTCARE ) )
1640                     return line;
1641 
1642                 if ( (state & wxLIST_STATE_SELECTED) && IsDataBrowserItemSelected(m_dbImpl->GetControlRef(), id ) )
1643                     return line;
1644             }
1645         }
1646     }
1647 
1648     return -1;
1649 }
1650 
1651 
GetImageList(int which) const1652 wxImageList *wxListCtrl::GetImageList(int which) const
1653 {
1654     if (m_genericImpl)
1655         return m_genericImpl->GetImageList(which);
1656 
1657     if ( which == wxIMAGE_LIST_NORMAL )
1658     {
1659         return m_imageListNormal;
1660     }
1661     else if ( which == wxIMAGE_LIST_SMALL )
1662     {
1663         return m_imageListSmall;
1664     }
1665     else if ( which == wxIMAGE_LIST_STATE )
1666     {
1667         return m_imageListState;
1668     }
1669     return NULL;
1670 }
1671 
SetImageList(wxImageList * imageList,int which)1672 void wxListCtrl::SetImageList(wxImageList *imageList, int which)
1673 {
1674     if (m_genericImpl)
1675     {
1676         m_genericImpl->SetImageList(imageList, which);
1677         return;
1678     }
1679 
1680     if ( which == wxIMAGE_LIST_NORMAL )
1681     {
1682         if (m_ownsImageListNormal) delete m_imageListNormal;
1683         m_imageListNormal = imageList;
1684         m_ownsImageListNormal = false;
1685     }
1686     else if ( which == wxIMAGE_LIST_SMALL )
1687     {
1688         if (m_ownsImageListSmall) delete m_imageListSmall;
1689         m_imageListSmall = imageList;
1690         m_ownsImageListSmall = false;
1691     }
1692     else if ( which == wxIMAGE_LIST_STATE )
1693     {
1694         if (m_ownsImageListState) delete m_imageListState;
1695         m_imageListState = imageList;
1696         m_ownsImageListState = false;
1697     }
1698 }
1699 
AssignImageList(wxImageList * imageList,int which)1700 void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
1701 {
1702     if (m_genericImpl)
1703     {
1704         m_genericImpl->AssignImageList(imageList, which);
1705         return;
1706     }
1707 
1708     SetImageList(imageList, which);
1709     if ( which == wxIMAGE_LIST_NORMAL )
1710         m_ownsImageListNormal = true;
1711     else if ( which == wxIMAGE_LIST_SMALL )
1712         m_ownsImageListSmall = true;
1713     else if ( which == wxIMAGE_LIST_STATE )
1714         m_ownsImageListState = true;
1715 }
1716 
1717 // ----------------------------------------------------------------------------
1718 // Operations
1719 // ----------------------------------------------------------------------------
1720 
1721 // Arranges the items
Arrange(int flag)1722 bool wxListCtrl::Arrange(int flag)
1723 {
1724     if (m_genericImpl)
1725         return m_genericImpl->Arrange(flag);
1726     return false;
1727 }
1728 
1729 // Deletes an item
DeleteItem(long item)1730 bool wxListCtrl::DeleteItem(long item)
1731 {
1732     if (m_genericImpl)
1733         return m_genericImpl->DeleteItem(item);
1734 
1735     if (m_dbImpl)
1736     {
1737         m_dbImpl->MacDelete(item);
1738         wxListEvent event( wxEVT_LIST_DELETE_ITEM, GetId() );
1739         event.SetEventObject( this );
1740         event.m_itemIndex = item;
1741         HandleWindowEvent( event );
1742 
1743     }
1744     return true;
1745 }
1746 
1747 // Deletes all items
DeleteAllItems()1748 bool wxListCtrl::DeleteAllItems()
1749 {
1750     m_current = -1;
1751     if (m_genericImpl)
1752         return m_genericImpl->DeleteAllItems();
1753 
1754     if (m_dbImpl)
1755     {
1756         m_dbImpl->MacClear();
1757         wxListEvent event( wxEVT_LIST_DELETE_ALL_ITEMS, GetId() );
1758         event.SetEventObject( this );
1759         HandleWindowEvent( event );
1760     }
1761     return true;
1762 }
1763 
1764 // Deletes all items
DeleteAllColumns()1765 bool wxListCtrl::DeleteAllColumns()
1766 {
1767     if (m_genericImpl)
1768         return m_genericImpl->DeleteAllColumns();
1769 
1770     if (m_dbImpl)
1771     {
1772         UInt32 cols;
1773         m_dbImpl->GetColumnCount(&cols);
1774         for (UInt32 col = 0; col < cols; col++)
1775         {
1776                 DeleteColumn(0);
1777         }
1778     }
1779 
1780     return true;
1781 }
1782 
1783 // Deletes a column
DeleteColumn(int col)1784 bool wxListCtrl::DeleteColumn(int col)
1785 {
1786     if (m_genericImpl)
1787         return m_genericImpl->DeleteColumn(col);
1788 
1789     if (m_dbImpl)
1790     {
1791         OSStatus err = m_dbImpl->RemoveColumn(col);
1792         return err == noErr;
1793     }
1794 
1795     return true;
1796 }
1797 
1798 // Clears items, and columns if there are any.
ClearAll()1799 void wxListCtrl::ClearAll()
1800 {
1801     if (m_genericImpl)
1802     {
1803         m_genericImpl->ClearAll();
1804         return;
1805     }
1806 
1807     if (m_dbImpl)
1808     {
1809         DeleteAllItems();
1810         DeleteAllColumns();
1811     }
1812 }
1813 
EditLabel(long item,wxClassInfo * textControlClass)1814 wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
1815 {
1816     if (m_genericImpl)
1817         return m_genericImpl->EditLabel(item, textControlClass);
1818 
1819     if (m_dbImpl)
1820     {
1821         wxCHECK_MSG( (item >= 0) && ((long)item < GetItemCount()), NULL,
1822                      wxT("wrong index in wxListCtrl::EditLabel()") );
1823 
1824         wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)),
1825                      wxT("EditLabel() needs a text control") );
1826 
1827         wxListEvent le( wxEVT_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
1828         le.SetEventObject( this );
1829         le.m_itemIndex = item;
1830         le.m_col = 0;
1831         GetItem( le.m_item );
1832 
1833         if ( GetParent()->HandleWindowEvent( le ) && !le.IsAllowed() )
1834         {
1835             // vetoed by user code
1836             return NULL;
1837         }
1838 
1839         wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
1840         m_textctrlWrapper = new wxListCtrlTextCtrlWrapper(this, text, item);
1841         return m_textctrlWrapper->GetText();
1842     }
1843     return NULL;
1844 }
1845 
1846 // End label editing, optionally cancelling the edit
EndEditLabel(bool WXUNUSED (cancel))1847 bool wxListCtrl::EndEditLabel(bool WXUNUSED(cancel))
1848 {
1849     // TODO: generic impl. doesn't have this method - is it needed for us?
1850     if (m_genericImpl)
1851         return true; // m_genericImpl->EndEditLabel(cancel);
1852 
1853     if (m_dbImpl)
1854     {
1855         DataBrowserTableViewColumnID id = 0;
1856         verify_noerr( m_dbImpl->GetColumnIDFromIndex( 0, &id ) );
1857         verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), kDataBrowserNoItem, id ) );
1858     }
1859     return true;
1860 }
1861 
1862 // Ensures this item is visible
EnsureVisible(long item)1863 bool wxListCtrl::EnsureVisible(long item)
1864 {
1865     if (m_genericImpl)
1866         return m_genericImpl->EnsureVisible(item);
1867 
1868     if (m_dbImpl)
1869     {
1870         wxMacDataItem* dataItem = m_dbImpl->GetItemFromLine(item);
1871         m_dbImpl->RevealItem(dataItem, kDataBrowserRevealWithoutSelecting);
1872     }
1873 
1874     return true;
1875 }
1876 
1877 // Find an item whose label matches this string, starting from the item after 'start'
1878 // or the beginning if 'start' is -1.
FindItem(long start,const wxString & str,bool partial)1879 long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
1880 {
1881     if (m_genericImpl)
1882         return m_genericImpl->FindItem(start, str, partial);
1883 
1884     wxString str_upper = str.Upper();
1885 
1886     long idx = start;
1887     if (idx < 0)
1888         idx = 0;
1889     long count = GetItemCount();
1890 
1891     while (idx < count)
1892     {
1893         wxString line_upper = GetItemText(idx).Upper();
1894         if (!partial)
1895         {
1896             if (line_upper == str_upper )
1897                 return idx;
1898         }
1899         else
1900         {
1901             if (line_upper.find(str_upper) == 0)
1902                 return idx;
1903         }
1904 
1905         idx++;
1906     };
1907 
1908     return wxNOT_FOUND;
1909 }
1910 
1911 // Find an item whose data matches this data, starting from the item after 'start'
1912 // or the beginning if 'start' is -1.
FindItem(long start,long data)1913 long wxListCtrl::FindItem(long start, long data)
1914 {
1915     if (m_genericImpl)
1916         return m_genericImpl->FindItem(start, data);
1917 
1918     long idx = start;
1919     if (idx < 0)
1920         idx = 0;
1921     long count = GetItemCount();
1922 
1923     while (idx < count)
1924     {
1925         if (GetItemData(idx) == data)
1926             return idx;
1927         idx++;
1928     };
1929 
1930     return wxNOT_FOUND;
1931 }
1932 
1933 // Find an item nearest this position in the specified direction, starting from
1934 // the item after 'start' or the beginning if 'start' is -1.
FindItem(long start,const wxPoint & pt,int direction)1935 long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
1936 {
1937     if (m_genericImpl)
1938         return m_genericImpl->FindItem(start, pt, direction);
1939     return -1;
1940 }
1941 
1942 static void calculateCGDrawingBounds(CGRect inItemRect, CGRect *outIconRect, CGRect *outTextRect, bool hasIcon);
1943 
1944 // Determines which item (if any) is at the specified point,
1945 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1946 long
HitTest(const wxPoint & point,int & flags,long * ptrSubItem) const1947 wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const
1948 {
1949     if (ptrSubItem)
1950         *ptrSubItem = -1;
1951 
1952     if (m_genericImpl)
1953         return m_genericImpl->HitTest(point, flags, ptrSubItem);
1954 
1955     flags = wxLIST_HITTEST_NOWHERE;
1956     if (m_dbImpl)
1957     {
1958         int colHeaderHeight = 22; // TODO: Find a way to get this value from the db control?
1959         UInt16 rowHeight = 0;
1960         m_dbImpl->GetDefaultRowHeight(&rowHeight);
1961 
1962         int y = point.y;
1963         // get the actual row by taking scroll position into account
1964         UInt32 offsetX, offsetY;
1965         m_dbImpl->GetScrollPosition( &offsetY, &offsetX );
1966         y += offsetY;
1967 
1968         if ( !(GetWindowStyleFlag() & wxLC_NO_HEADER) )
1969             y -= colHeaderHeight;
1970 
1971         if ( y < 0 )
1972             return -1;
1973 
1974         int row = y / rowHeight;
1975         DataBrowserItemID id;
1976         m_dbImpl->GetItemID( (DataBrowserTableViewRowIndex) row, &id );
1977 
1978         CGPoint click_point = CGPointMake( point.x, point.y );
1979         if (row < GetItemCount() )
1980         {
1981             short column;
1982             for( column = 0; column < GetColumnCount(); column++ )
1983             {
1984                Rect enclosingRect;
1985                CGRect enclosingCGRect, iconCGRect, textCGRect;
1986                int imgIndex = -1;
1987                wxMacListCtrlItem* lcItem;
1988 
1989                WXUNUSED_UNLESS_DEBUG( OSStatus status = ) m_dbImpl->GetItemPartBounds( id, kMinColumnId + column, kDataBrowserPropertyEnclosingPart, &enclosingRect );
1990                wxASSERT( status == noErr );
1991 
1992                enclosingCGRect = CGRectMake(enclosingRect.left,
1993                                             enclosingRect.top,
1994                                             enclosingRect.right - enclosingRect.left,
1995                                             enclosingRect.bottom - enclosingRect.top);
1996 
1997                if (column >= 0)
1998                {
1999                    if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL ) )
2000                    {
2001                        lcItem = (wxMacListCtrlItem*) id;
2002                        if (lcItem->HasColumnInfo(column))
2003                        {
2004                            wxListItem* item = lcItem->GetColumnInfo(column);
2005 
2006                            if (item->GetMask() & wxLIST_MASK_IMAGE)
2007                            {
2008                                imgIndex = item->GetImage();
2009                            }
2010                        }
2011                    }
2012                    else
2013                    {
2014                        long itemNum = (long)id-1;
2015                        if (itemNum >= 0 && itemNum < GetItemCount())
2016                        {
2017                            imgIndex = OnGetItemColumnImage( itemNum, column );
2018                        }
2019                    }
2020                }
2021 
2022                calculateCGDrawingBounds(enclosingCGRect, &iconCGRect, &textCGRect, (imgIndex != -1) );
2023 
2024                if ( CGRectContainsPoint( iconCGRect, click_point ) )
2025                {
2026                    flags = wxLIST_HITTEST_ONITEMICON;
2027                    if (ptrSubItem)
2028                        *ptrSubItem = column;
2029                    return row;
2030                }
2031                else if ( CGRectContainsPoint( textCGRect, click_point ) )
2032                {
2033                    flags = wxLIST_HITTEST_ONITEMLABEL;
2034                    if (ptrSubItem)
2035                        *ptrSubItem = column;
2036                    return row;
2037                }
2038            }
2039 
2040            if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL ) )
2041            {
2042                wxMacListCtrlItem* lcItem;
2043                lcItem = (wxMacListCtrlItem*) id;
2044                if (lcItem)
2045                {
2046                    flags = wxLIST_HITTEST_ONITEM;
2047                    if (ptrSubItem)
2048                        *ptrSubItem = column;
2049                    return row;
2050                }
2051            }
2052            else
2053            {
2054                flags = wxLIST_HITTEST_ONITEM;
2055                if (ptrSubItem)
2056                    *ptrSubItem = column;
2057                return row;
2058            }
2059          }
2060          else
2061          {
2062              if ( wxControl::HitTest( point ) )
2063                  flags = wxLIST_HITTEST_NOWHERE;
2064          }
2065     }
2066 
2067     return -1;
2068 }
2069 
GetScrollPos(int orient) const2070 int wxListCtrl::GetScrollPos(int orient) const
2071 {
2072     if (m_genericImpl)
2073         return m_genericImpl->GetScrollPos(orient);
2074 
2075     if (m_dbImpl)
2076     {
2077         UInt32 offsetX, offsetY;
2078         m_dbImpl->GetScrollPosition( &offsetY, &offsetX );
2079         if ( orient == wxHORIZONTAL )
2080            return offsetX;
2081         else
2082            return offsetY;
2083     }
2084 
2085     return 0;
2086 }
2087 
2088 // Inserts an item, returning the index of the new item if successful,
2089 // -1 otherwise.
InsertItem(wxListItem & info)2090 long wxListCtrl::InsertItem(wxListItem& info)
2091 {
2092     wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
2093 
2094     if (m_genericImpl)
2095         return m_genericImpl->InsertItem(info);
2096 
2097     if (m_dbImpl && !IsVirtual())
2098     {
2099         int count = GetItemCount();
2100 
2101         if (info.m_itemId > count)
2102             info.m_itemId = count;
2103 
2104         m_dbImpl->MacInsertItem(info.m_itemId, &info );
2105 
2106         wxListEvent event( wxEVT_LIST_INSERT_ITEM, GetId() );
2107         event.SetEventObject( this );
2108         event.m_itemIndex = info.m_itemId;
2109         HandleWindowEvent( event );
2110         return info.m_itemId;
2111     }
2112     return -1;
2113 }
2114 
InsertItem(long index,const wxString & label)2115 long wxListCtrl::InsertItem(long index, const wxString& label)
2116 {
2117     if (m_genericImpl)
2118         return m_genericImpl->InsertItem(index, label);
2119 
2120     wxListItem info;
2121     info.m_text = label;
2122     info.m_mask = wxLIST_MASK_TEXT;
2123     info.m_itemId = index;
2124     return InsertItem(info);
2125 }
2126 
2127 // Inserts an image item
InsertItem(long index,int imageIndex)2128 long wxListCtrl::InsertItem(long index, int imageIndex)
2129 {
2130     if (m_genericImpl)
2131         return m_genericImpl->InsertItem(index, imageIndex);
2132 
2133     wxListItem info;
2134     info.m_image = imageIndex;
2135     info.m_mask = wxLIST_MASK_IMAGE;
2136     info.m_itemId = index;
2137     return InsertItem(info);
2138 }
2139 
2140 // Inserts an image/string item
InsertItem(long index,const wxString & label,int imageIndex)2141 long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
2142 {
2143     if (m_genericImpl)
2144         return m_genericImpl->InsertItem(index, label, imageIndex);
2145 
2146     wxListItem info;
2147     info.m_image = imageIndex;
2148     info.m_text = label;
2149     info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
2150     info.m_itemId = index;
2151     return InsertItem(info);
2152 }
2153 
2154 // For list view mode (only), inserts a column.
DoInsertColumn(long col,const wxListItem & item)2155 long wxListCtrl::DoInsertColumn(long col, const wxListItem& item)
2156 {
2157     if (m_genericImpl)
2158         return m_genericImpl->InsertColumn(col, item);
2159 
2160     if (m_dbImpl)
2161     {
2162         int width = item.GetWidth();
2163         if ( !(item.GetMask() & wxLIST_MASK_WIDTH) )
2164             width = 150;
2165 
2166         DataBrowserPropertyType type = kDataBrowserCustomType; //kDataBrowserTextType;
2167         wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
2168         if (imageList && imageList->GetImageCount() > 0)
2169         {
2170             wxBitmap bmp = imageList->GetBitmap(0);
2171             //if (bmp.IsOk())
2172             //    type = kDataBrowserIconAndTextType;
2173         }
2174 
2175         SInt16 just = teFlushDefault;
2176         if (item.GetMask() & wxLIST_MASK_FORMAT)
2177         {
2178             if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2179                 just = teFlushLeft;
2180             else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2181                 just = teCenter;
2182             else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2183                 just = teFlushRight;
2184         }
2185         m_dbImpl->InsertColumn(col, type, item.GetText(), just, width);
2186 
2187         wxListItem* listItem = new wxListItem(item);
2188         m_colsInfo.Insert( col, listItem );
2189         SetColumn(col, item);
2190 
2191         // set/remove options based on the wxListCtrl type.
2192         DataBrowserTableViewColumnID id;
2193         m_dbImpl->GetColumnIDFromIndex(col, &id);
2194         DataBrowserPropertyFlags flags;
2195         verify_noerr(m_dbImpl->GetPropertyFlags(id, &flags));
2196         if (GetWindowStyleFlag() & wxLC_EDIT_LABELS)
2197             flags |= kDataBrowserPropertyIsEditable;
2198 
2199         if (GetWindowStyleFlag() & wxLC_VIRTUAL){
2200             flags &= ~kDataBrowserListViewSortableColumn;
2201         }
2202         verify_noerr(m_dbImpl->SetPropertyFlags(id, flags));
2203     }
2204 
2205     return col;
2206 }
2207 
2208 // scroll the control by the given number of pixels (exception: in list view,
2209 // dx is interpreted as number of columns)
ScrollList(int dx,int dy)2210 bool wxListCtrl::ScrollList(int dx, int dy)
2211 {
2212     if (m_genericImpl)
2213         return m_genericImpl->ScrollList(dx, dy);
2214 
2215     if (m_dbImpl)
2216     {
2217         // Notice that the parameter order is correct here: first argument is
2218         // the "top" displacement, second one is the "left" one.
2219         m_dbImpl->SetScrollPosition(dy, dx);
2220     }
2221     return true;
2222 }
2223 
2224 
SortItems(wxListCtrlCompare fn,wxIntPtr data)2225 bool wxListCtrl::SortItems(wxListCtrlCompare fn, wxIntPtr data)
2226 {
2227     if (m_genericImpl)
2228         return m_genericImpl->SortItems(fn, data);
2229 
2230     if (m_dbImpl)
2231     {
2232         m_compareFunc = fn;
2233         m_compareFuncData = data;
2234         SortDataBrowserContainer( m_dbImpl->GetControlRef(), kDataBrowserNoItem, true);
2235 
2236         // we need to do this after each call, else we get a crash from wxPython when
2237         // SortItems is called the second time.
2238         m_compareFunc = NULL;
2239         m_compareFuncData = 0;
2240     }
2241 
2242     return true;
2243 }
2244 
OnRenameTimer()2245 void wxListCtrl::OnRenameTimer()
2246 {
2247     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2248 
2249     EditLabel( m_current );
2250 }
2251 
OnRenameAccept(long itemEdit,const wxString & value)2252 bool wxListCtrl::OnRenameAccept(long itemEdit, const wxString& value)
2253 {
2254     wxListEvent le( wxEVT_LIST_END_LABEL_EDIT, GetId() );
2255     le.SetEventObject( this );
2256     le.m_itemIndex = itemEdit;
2257 
2258     GetItem( le.m_item );
2259     le.m_item.m_text = value;
2260     return !HandleWindowEvent( le ) ||
2261                 le.IsAllowed();
2262 }
2263 
OnRenameCancelled(long itemEdit)2264 void wxListCtrl::OnRenameCancelled(long itemEdit)
2265 {
2266     // let owner know that the edit was cancelled
2267     wxListEvent le( wxEVT_LIST_END_LABEL_EDIT, GetParent()->GetId() );
2268 
2269     le.SetEditCanceled(true);
2270 
2271     le.SetEventObject( this );
2272     le.m_itemIndex = itemEdit;
2273 
2274     GetItem( le.m_item );
2275     HandleWindowEvent( le );
2276 }
2277 
2278 // ----------------------------------------------------------------------------
2279 // virtual list controls
2280 // ----------------------------------------------------------------------------
2281 
OnGetItemText(long WXUNUSED (item),long WXUNUSED (col)) const2282 wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
2283 {
2284     // this is a pure virtual function, in fact - which is not really pure
2285     // because the controls which are not virtual don't need to implement it
2286     wxFAIL_MSG( wxT("wxListCtrl::OnGetItemText not supposed to be called") );
2287 
2288     return wxEmptyString;
2289 }
2290 
OnGetItemImage(long WXUNUSED (item)) const2291 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
2292 {
2293     wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
2294                 -1,
2295                 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
2296     return -1;
2297 }
2298 
OnGetItemColumnImage(long item,long column) const2299 int wxListCtrl::OnGetItemColumnImage(long item, long column) const
2300 {
2301     if (!column)
2302         return OnGetItemImage(item);
2303 
2304     return -1;
2305 }
2306 
SetItemCount(long count)2307 void wxListCtrl::SetItemCount(long count)
2308 {
2309     wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") );
2310 
2311     if (m_genericImpl)
2312     {
2313         m_genericImpl->SetItemCount(count);
2314         return;
2315     }
2316 
2317     if (m_dbImpl)
2318     {
2319         // we need to temporarily disable the new item creation notification
2320         // procedure to speed things up
2321         // FIXME: Even this doesn't seem to help much...
2322 
2323         // FIXME: Find a more efficient way to do this.
2324         m_dbImpl->MacClear();
2325 
2326         DataBrowserCallbacks callbacks;
2327         DataBrowserItemNotificationUPP itemUPP;
2328         GetDataBrowserCallbacks(m_dbImpl->GetControlRef(), &callbacks);
2329         itemUPP = callbacks.u.v1.itemNotificationCallback;
2330         callbacks.u.v1.itemNotificationCallback = 0;
2331         m_dbImpl->SetCallbacks(&callbacks);
2332         ::AddDataBrowserItems(m_dbImpl->GetControlRef(), kDataBrowserNoItem,
2333             count, NULL, kDataBrowserItemNoProperty);
2334         callbacks.u.v1.itemNotificationCallback = itemUPP;
2335         m_dbImpl->SetCallbacks(&callbacks);
2336     }
2337     m_count = count;
2338 }
2339 
RefreshItem(long item)2340 void wxListCtrl::RefreshItem(long item)
2341 {
2342     if (m_genericImpl)
2343     {
2344         m_genericImpl->RefreshItem(item);
2345         return;
2346     }
2347 
2348     if (m_dbImpl)
2349     {
2350         DataBrowserItemID id;
2351 
2352         if ( !IsVirtual() )
2353         {
2354             wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(item);
2355             id = (DataBrowserItemID) thisItem;
2356         }
2357         else
2358             id = item+1;
2359 
2360         m_dbImpl->wxMacDataBrowserControl::UpdateItems
2361                   (
2362                     kDataBrowserNoItem,
2363                     1, &id,
2364                     kDataBrowserItemNoProperty, // preSortProperty
2365                     kDataBrowserNoItem // update all columns
2366                   );
2367     }
2368 }
2369 
RefreshItems(long itemFrom,long itemTo)2370 void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
2371 {
2372     if (m_genericImpl)
2373     {
2374         m_genericImpl->RefreshItems(itemFrom, itemTo);
2375         return;
2376     }
2377 
2378     if (m_dbImpl)
2379     {
2380         const long count = itemTo - itemFrom + 1;
2381         DataBrowserItemID *ids = new DataBrowserItemID[count];
2382 
2383         if ( !IsVirtual() )
2384         {
2385             for ( long i = 0; i < count; i++ )
2386             {
2387                 wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(itemFrom+i);
2388                 ids[i] = (DataBrowserItemID) thisItem;
2389             }
2390         }
2391         else
2392         {
2393             for ( long i = 0; i < count; i++ )
2394                 ids[i] = itemFrom+i+1;
2395         }
2396 
2397         m_dbImpl->wxMacDataBrowserControl::UpdateItems
2398                   (
2399                     kDataBrowserNoItem,
2400                     count, ids,
2401                     kDataBrowserItemNoProperty, // preSortProperty
2402                     kDataBrowserNoItem // update all columns
2403                   );
2404 
2405         delete[] ids;
2406     }
2407 }
2408 
SetDropTarget(wxDropTarget * dropTarget)2409 void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget )
2410 {
2411 #if wxUSE_DRAG_AND_DROP
2412     if (m_genericImpl)
2413         m_genericImpl->SetDropTarget( dropTarget );
2414 
2415     if (m_dbImpl)
2416         wxWindow::SetDropTarget( dropTarget );
2417 #endif
2418 }
2419 
GetDropTarget() const2420 wxDropTarget *wxListCtrl::GetDropTarget() const
2421 {
2422 #if wxUSE_DRAG_AND_DROP
2423     if (m_genericImpl)
2424         return m_genericImpl->GetDropTarget();
2425 
2426     if (m_dbImpl)
2427         return wxWindow::GetDropTarget();
2428 #endif
2429     return NULL;
2430 }
2431 
2432 #if wxABI_VERSION >= 20801
SetFocus()2433 void wxListCtrl::SetFocus()
2434 {
2435         if (m_genericImpl)
2436         {
2437                 m_genericImpl->SetFocus();
2438                 return;
2439         }
2440 
2441         wxWindow::SetFocus();
2442 }
2443 #endif
2444 
2445 // wxMac internal data structures
2446 
~wxMacListCtrlItem()2447 wxMacListCtrlItem::~wxMacListCtrlItem()
2448 {
2449     WX_CLEAR_HASH_MAP( wxListItemList, m_rowItems );
2450 }
2451 
Notification(wxMacDataItemBrowserControl * owner,DataBrowserItemNotification message,DataBrowserItemDataRef WXUNUSED (itemData)) const2452 void wxMacListCtrlItem::Notification(wxMacDataItemBrowserControl *owner ,
2453     DataBrowserItemNotification message,
2454     DataBrowserItemDataRef WXUNUSED(itemData) ) const
2455 {
2456 
2457     wxMacDataBrowserListCtrlControl *lb = wxDynamicCast(owner, wxMacDataBrowserListCtrlControl);
2458 
2459     // we want to depend on as little as possible to make sure tear-down of controls is safe
2460     if ( message == kDataBrowserItemRemoved)
2461     {
2462         delete this;
2463         return;
2464     }
2465     else if ( message == kDataBrowserItemAdded )
2466     {
2467         // we don't issue events on adding, the item is not really stored in the list yet, so we
2468         // avoid asserts by gettting out now
2469         return  ;
2470     }
2471 
2472     wxListCtrl *list = wxDynamicCast( owner->GetWXPeer() , wxListCtrl );
2473     if ( list && lb )
2474     {
2475         bool trigger = false;
2476 
2477         wxListEvent event( wxEVT_LIST_ITEM_SELECTED, list->GetId() );
2478         bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
2479 
2480         event.SetEventObject( list );
2481         event.m_itemIndex = owner->GetLineFromItem( this ) ;
2482         event.m_item.m_itemId = event.m_itemIndex;
2483         list->GetItem(event.m_item);
2484 
2485         switch (message)
2486         {
2487             case kDataBrowserItemDeselected:
2488                 event.SetEventType(wxEVT_LIST_ITEM_DESELECTED);
2489                 if ( !isSingle )
2490                     trigger = !lb->IsSelectionSuppressed();
2491                 break;
2492 
2493             case kDataBrowserItemSelected:
2494                 trigger = !lb->IsSelectionSuppressed();
2495                 break;
2496 
2497             case kDataBrowserItemDoubleClicked:
2498                 event.SetEventType( wxEVT_LIST_ITEM_ACTIVATED );
2499                 trigger = true;
2500                 break;
2501 
2502             case kDataBrowserEditStarted :
2503                 // TODO : how to veto ?
2504                 event.SetEventType( wxEVT_LIST_BEGIN_LABEL_EDIT ) ;
2505                 trigger = true ;
2506                 break ;
2507 
2508             case kDataBrowserEditStopped :
2509                 // TODO probably trigger only upon the value store callback, because
2510                 // here IIRC we cannot veto
2511                 event.SetEventType( wxEVT_LIST_END_LABEL_EDIT ) ;
2512                 trigger = true ;
2513                 break ;
2514 
2515             default:
2516                 break;
2517         }
2518 
2519         if ( trigger )
2520         {
2521             // direct notification is not always having the listbox GetSelection() having in synch with event
2522             wxPostEvent( list->GetEventHandler(), event );
2523         }
2524     }
2525 
2526 }
2527 
IMPLEMENT_DYNAMIC_CLASS(wxMacDataBrowserListCtrlControl,wxMacDataItemBrowserControl)2528 IMPLEMENT_DYNAMIC_CLASS(wxMacDataBrowserListCtrlControl, wxMacDataItemBrowserControl )
2529 
2530 wxMacDataBrowserListCtrlControl::wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style)
2531     : wxMacDataItemBrowserControl( peer, pos, size, style )
2532 {
2533     OSStatus err = noErr;
2534     m_clientDataItemsType = wxClientData_None;
2535     m_isVirtual = false;
2536     m_flags = 0;
2537 
2538     if ( style & wxLC_VIRTUAL )
2539         m_isVirtual = true;
2540 
2541     DataBrowserSelectionFlags  options = kDataBrowserDragSelect;
2542     if ( style & wxLC_SINGLE_SEL )
2543     {
2544         options |= kDataBrowserSelectOnlyOne;
2545     }
2546     else
2547     {
2548         options |= kDataBrowserCmdTogglesSelection;
2549     }
2550 
2551     err = SetSelectionFlags( options );
2552     verify_noerr( err );
2553 
2554     DataBrowserCustomCallbacks callbacks;
2555     InitializeDataBrowserCustomCallbacks( &callbacks, kDataBrowserLatestCustomCallbacks );
2556 
2557     if ( gDataBrowserDrawItemUPP == NULL )
2558         gDataBrowserDrawItemUPP = NewDataBrowserDrawItemUPP(DataBrowserDrawItemProc);
2559 
2560     if ( gDataBrowserHitTestUPP == NULL )
2561         gDataBrowserHitTestUPP = NewDataBrowserHitTestUPP(DataBrowserHitTestProc);
2562 
2563     callbacks.u.v1.drawItemCallback = gDataBrowserDrawItemUPP;
2564     callbacks.u.v1.hitTestCallback = gDataBrowserHitTestUPP;
2565 
2566     SetDataBrowserCustomCallbacks( GetControlRef(), &callbacks );
2567 
2568     if ( style & wxLC_LIST )
2569     {
2570         InsertColumn(0, kDataBrowserIconAndTextType, wxEmptyString, -1, -1);
2571         verify_noerr( AutoSizeColumns() );
2572     }
2573 
2574     if ( style & wxLC_LIST || style & wxLC_NO_HEADER )
2575         verify_noerr( SetHeaderButtonHeight( 0 ) );
2576 
2577     if ( m_isVirtual )
2578         SetSortProperty( kMinColumnId - 1 );
2579     else
2580         SetSortProperty( kMinColumnId );
2581 
2582     m_sortOrder = SortOrder_None;
2583 
2584     if ( style & wxLC_SORT_DESCENDING )
2585     {
2586         SetSortOrder( kDataBrowserOrderDecreasing );
2587     }
2588     else if ( style & wxLC_SORT_ASCENDING )
2589     {
2590         SetSortOrder( kDataBrowserOrderIncreasing );
2591     }
2592 
2593     if ( style & wxLC_VRULES )
2594     {
2595         verify_noerr( DataBrowserChangeAttributes(m_controlRef, kDataBrowserAttributeListViewDrawColumnDividers, kDataBrowserAttributeNone) );
2596     }
2597 
2598     verify_noerr( SetHiliteStyle(kDataBrowserTableViewFillHilite ) );
2599     verify_noerr( SetHasScrollBars( (style & wxHSCROLL) != 0 , true ) );
2600 }
2601 
DataBrowserEditTextProc(ControlRef browser,DataBrowserItemID itemID,DataBrowserPropertyID property,CFStringRef theString,Rect * maxEditTextRect,Boolean * shrinkToFit)2602 pascal Boolean wxMacDataBrowserListCtrlControl::DataBrowserEditTextProc(
2603         ControlRef browser,
2604         DataBrowserItemID itemID,
2605         DataBrowserPropertyID property,
2606         CFStringRef theString,
2607         Rect *maxEditTextRect,
2608         Boolean *shrinkToFit)
2609 {
2610     Boolean result = false;
2611     wxMacDataBrowserListCtrlControl* ctl = wxDynamicCast(wxMacControl::GetReferenceFromNativeControl( browser ), wxMacDataBrowserListCtrlControl);
2612     if ( ctl != 0 )
2613     {
2614         result = ctl->ConfirmEditText(itemID, property, theString, maxEditTextRect, shrinkToFit);
2615         theString = CFSTR("Hello!");
2616     }
2617     return result;
2618 }
2619 
ConfirmEditText(DataBrowserItemID WXUNUSED (itemID),DataBrowserPropertyID WXUNUSED (property),CFStringRef WXUNUSED (theString),Rect * WXUNUSED (maxEditTextRect),Boolean * WXUNUSED (shrinkToFit))2620 bool wxMacDataBrowserListCtrlControl::ConfirmEditText(
2621         DataBrowserItemID WXUNUSED(itemID),
2622         DataBrowserPropertyID WXUNUSED(property),
2623         CFStringRef WXUNUSED(theString),
2624         Rect *WXUNUSED(maxEditTextRect),
2625         Boolean *WXUNUSED(shrinkToFit))
2626 {
2627     return false;
2628 }
2629 
DataBrowserDrawItemProc(ControlRef browser,DataBrowserItemID itemID,DataBrowserPropertyID property,DataBrowserItemState itemState,const Rect * itemRect,SInt16 gdDepth,Boolean colorDevice)2630 pascal void wxMacDataBrowserListCtrlControl::DataBrowserDrawItemProc(
2631         ControlRef browser,
2632         DataBrowserItemID itemID,
2633         DataBrowserPropertyID property,
2634         DataBrowserItemState itemState,
2635         const Rect *itemRect,
2636         SInt16 gdDepth,
2637         Boolean colorDevice)
2638 {
2639     wxMacDataBrowserListCtrlControl* ctl = wxDynamicCast(wxMacControl::GetReferenceFromNativeControl( browser ), wxMacDataBrowserListCtrlControl);
2640     if ( ctl != 0 )
2641     {
2642         ctl->DrawItem(itemID, property, itemState, itemRect, gdDepth, colorDevice);
2643     }
2644 }
2645 
2646 // routines needed for DrawItem
2647 enum
2648 {
2649   kIconWidth = 16,
2650   kIconHeight = 16,
2651   kTextBoxHeight = 14,
2652   kIconTextSpacingV = 2,
2653   kItemPadding = 4,
2654   kContentHeight = kIconHeight + kTextBoxHeight + kIconTextSpacingV
2655 };
2656 
calculateCGDrawingBounds(CGRect inItemRect,CGRect * outIconRect,CGRect * outTextRect,bool hasIcon=false)2657 static void calculateCGDrawingBounds(CGRect inItemRect, CGRect *outIconRect, CGRect *outTextRect, bool hasIcon = false)
2658 {
2659   float textBottom;
2660   float iconW = 0;
2661   float padding = kItemPadding;
2662   if (hasIcon)
2663   {
2664     iconW = kIconWidth;
2665     padding = padding*2;
2666   }
2667 
2668   textBottom = inItemRect.origin.y;
2669 
2670   *outIconRect = CGRectMake(inItemRect.origin.x + kItemPadding,
2671                 textBottom + kIconTextSpacingV, kIconWidth,
2672                 kIconHeight);
2673 
2674   *outTextRect = CGRectMake(inItemRect.origin.x + padding + iconW,
2675                 textBottom + kIconTextSpacingV, inItemRect.size.width - padding - iconW,
2676                 inItemRect.size.height - kIconTextSpacingV);
2677 }
2678 
DrawItem(DataBrowserItemID itemID,DataBrowserPropertyID property,DataBrowserItemState itemState,const Rect * WXUNUSED (itemRect),SInt16 gdDepth,Boolean colorDevice)2679 void wxMacDataBrowserListCtrlControl::DrawItem(
2680         DataBrowserItemID itemID,
2681         DataBrowserPropertyID property,
2682         DataBrowserItemState itemState,
2683         const Rect *WXUNUSED(itemRect),
2684         SInt16 gdDepth,
2685         Boolean colorDevice)
2686 {
2687     wxString text;
2688     wxFont font = wxNullFont;
2689     int imgIndex = -1;
2690 
2691     DataBrowserTableViewColumnIndex listColumn = 0;
2692     GetColumnPosition( property, &listColumn );
2693 
2694     wxListCtrl* list = wxDynamicCast( GetWXPeer() , wxListCtrl );
2695     wxMacListCtrlItem* lcItem;
2696     wxColour color = *wxBLACK;
2697     wxColour bgColor = wxNullColour;
2698 
2699     if (listColumn >= 0)
2700     {
2701         if (!m_isVirtual)
2702         {
2703             lcItem = (wxMacListCtrlItem*) itemID;
2704             if (lcItem->HasColumnInfo(listColumn))
2705             {
2706                 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2707 
2708                 // we always use the 0 column to get font and text/background colors.
2709                 if (lcItem->HasColumnInfo(0))
2710                 {
2711                     wxListItem* firstItem = lcItem->GetColumnInfo(0);
2712                     color = firstItem->GetTextColour();
2713                     bgColor = firstItem->GetBackgroundColour();
2714                     font = firstItem->GetFont();
2715                 }
2716 
2717                 if (item->GetMask() & wxLIST_MASK_TEXT)
2718                     text = item->GetText();
2719                 if (item->GetMask() & wxLIST_MASK_IMAGE)
2720                     imgIndex = item->GetImage();
2721             }
2722 
2723         }
2724         else
2725         {
2726             long itemNum = (long)itemID-1;
2727             if (itemNum >= 0 && itemNum < list->GetItemCount())
2728             {
2729                 text = list->OnGetItemText( itemNum, listColumn );
2730                 imgIndex = list->OnGetItemColumnImage( itemNum, listColumn );
2731                 wxListItemAttr* attrs = list->OnGetItemAttr( itemNum );
2732                 if (attrs)
2733                 {
2734                     if (attrs->HasBackgroundColour())
2735                         bgColor = attrs->GetBackgroundColour();
2736                     if (attrs->HasTextColour())
2737                         color = attrs->GetTextColour();
2738                     if (attrs->HasFont())
2739                         font = attrs->GetFont();
2740                 }
2741             }
2742         }
2743     }
2744 
2745     wxColour listBgColor = list->GetBackgroundColour();
2746     if (bgColor == wxNullColour)
2747         bgColor = listBgColor;
2748 
2749     if (!font.IsOk())
2750         font = list->GetFont();
2751 
2752     wxCFStringRef cfString( text, wxLocale::GetSystemEncoding() );
2753 
2754     Rect enclosingRect;
2755     CGRect enclosingCGRect, iconCGRect, textCGRect;
2756     Boolean active;
2757     ThemeDrawingState savedState = NULL;
2758     CGContextRef context = (CGContextRef)list->MacGetDrawingContext();
2759     wxMacCGContextStateSaver top_saver_cg( context );
2760 
2761     RGBColor labelColor;
2762     labelColor.red = 0;
2763     labelColor.green = 0;
2764     labelColor.blue = 0;
2765 
2766     RGBColor backgroundColor;
2767     backgroundColor.red = 255;
2768     backgroundColor.green = 255;
2769     backgroundColor.blue = 255;
2770 
2771     GetDataBrowserItemPartBounds(GetControlRef(), itemID, property, kDataBrowserPropertyEnclosingPart,
2772               &enclosingRect);
2773 
2774     enclosingCGRect = CGRectMake(enclosingRect.left,
2775                       enclosingRect.top,
2776                       enclosingRect.right - enclosingRect.left,
2777                       enclosingRect.bottom - enclosingRect.top);
2778 
2779     bool hasFocus = (wxWindow::FindFocus() == list);
2780     active = IsControlActive(GetControlRef());
2781 
2782     // don't paint the background over the vertical rule line
2783     if ( list->GetWindowStyleFlag() & wxLC_VRULES )
2784     {
2785         enclosingCGRect.origin.x += 1;
2786         enclosingCGRect.size.width -= 1;
2787     }
2788     if (itemState == kDataBrowserItemIsSelected)
2789     {
2790 
2791         GetThemeDrawingState(&savedState);
2792 
2793         if (active && hasFocus)
2794         {
2795             GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &backgroundColor);
2796             GetThemeTextColor(kThemeTextColorWhite, gdDepth, colorDevice, &labelColor);
2797         }
2798         else
2799         {
2800             GetThemeBrushAsColor(kThemeBrushSecondaryHighlightColor, 32, true, &backgroundColor);
2801             GetThemeTextColor(kThemeTextColorBlack, gdDepth, colorDevice, &labelColor);
2802         }
2803         wxMacCGContextStateSaver cg( context );
2804 
2805         CGContextSetRGBFillColor(context, (CGFloat)backgroundColor.red / (CGFloat)USHRT_MAX,
2806                       (CGFloat)backgroundColor.green / (CGFloat)USHRT_MAX,
2807                       (CGFloat)backgroundColor.blue / (CGFloat)USHRT_MAX, (CGFloat) 1.0);
2808         CGContextFillRect(context, enclosingCGRect);
2809     }
2810     else
2811     {
2812 
2813         if (color.IsOk())
2814             color.GetRGBColor(&labelColor);
2815         else if (list->GetTextColour().IsOk())
2816             list->GetTextColour().GetRGBColor(&labelColor);
2817 
2818         if (bgColor.IsOk())
2819         {
2820             bgColor.GetRGBColor(&backgroundColor);
2821             CGContextSaveGState(context);
2822 
2823             CGContextSetRGBFillColor(context, (CGFloat)backgroundColor.red / (CGFloat)USHRT_MAX,
2824                           (CGFloat)backgroundColor.green / (CGFloat)USHRT_MAX,
2825                           (CGFloat)backgroundColor.blue / (CGFloat)USHRT_MAX, (CGFloat) 1.0);
2826             CGContextFillRect(context, enclosingCGRect);
2827 
2828             CGContextRestoreGState(context);
2829         }
2830     }
2831 
2832     calculateCGDrawingBounds(enclosingCGRect, &iconCGRect, &textCGRect, (imgIndex != -1) );
2833 
2834     if (imgIndex != -1)
2835     {
2836         wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2837         if (imageList && imageList->GetImageCount() > 0)
2838         {
2839             wxBitmap bmp = imageList->GetBitmap(imgIndex);
2840             IconRef icon = bmp.GetIconRef();
2841 
2842             wxMacCGContextStateSaver cg( context );
2843 
2844             CGContextTranslateCTM(context, 0,iconCGRect.origin.y + CGRectGetMaxY(iconCGRect));
2845             CGContextScaleCTM(context,1.0f,-1.0f);
2846             PlotIconRefInContext(context, &iconCGRect, kAlignNone,
2847               active ? kTransformNone : kTransformDisabled, NULL,
2848               kPlotIconRefNormalFlags, icon);
2849         }
2850     }
2851 
2852     HIThemeTextHorizontalFlush hFlush = kHIThemeTextHorizontalFlushLeft;
2853     HIThemeTextInfo info;
2854 
2855     info.version = kHIThemeTextInfoVersionOne;
2856     info.fontID = kThemeViewsFont;
2857     if (font.IsOk())
2858     {
2859         info.fontID = kThemeSpecifiedFont;
2860         info.font = (CTFontRef) font.OSXGetCTFont();
2861     }
2862 
2863     wxListItem item;
2864     list->GetColumn(listColumn, item);
2865     if (item.GetMask() & wxLIST_MASK_FORMAT)
2866     {
2867         if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2868             hFlush = kHIThemeTextHorizontalFlushLeft;
2869         else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2870             hFlush = kHIThemeTextHorizontalFlushCenter;
2871         else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2872         {
2873             hFlush = kHIThemeTextHorizontalFlushRight;
2874             textCGRect.origin.x -= kItemPadding; // give a little extra paddding
2875         }
2876     }
2877 
2878     info.state = active ? kThemeStateActive : kThemeStateInactive;
2879     info.horizontalFlushness = hFlush;
2880     info.verticalFlushness = kHIThemeTextVerticalFlushCenter;
2881     info.options = kHIThemeTextBoxOptionNone;
2882     info.truncationPosition = kHIThemeTextTruncationEnd;
2883     info.truncationMaxLines = 1;
2884 
2885     {
2886         wxMacCGContextStateSaver cg( context );
2887         CGContextSetRGBFillColor (context, (CGFloat)labelColor.red / (CGFloat)USHRT_MAX,
2888                       (CGFloat)labelColor.green / (CGFloat)USHRT_MAX,
2889                       (CGFloat)labelColor.blue / (CGFloat)USHRT_MAX, (CGFloat) 1.0);
2890 
2891         HIThemeDrawTextBox(cfString, &textCGRect, &info, context, kHIThemeOrientationNormal);
2892     }
2893 
2894 #ifndef __LP64__
2895     if (savedState != NULL)
2896         SetThemeDrawingState(savedState, true);
2897 #endif
2898 }
2899 
GetSetItemData(DataBrowserItemID itemID,DataBrowserPropertyID property,DataBrowserItemDataRef itemData,Boolean changeValue)2900 OSStatus wxMacDataBrowserListCtrlControl::GetSetItemData(DataBrowserItemID itemID,
2901                         DataBrowserPropertyID property,
2902                         DataBrowserItemDataRef itemData,
2903                         Boolean changeValue )
2904 {
2905     wxString text;
2906     int imgIndex = -1;
2907 
2908     DataBrowserTableViewColumnIndex listColumn = 0;
2909     verify_noerr( GetColumnPosition( property, &listColumn ) );
2910 
2911     OSStatus err = errDataBrowserPropertyNotSupported;
2912     wxListCtrl* list = wxDynamicCast( GetWXPeer() , wxListCtrl );
2913     wxMacListCtrlItem* lcItem = NULL;
2914 
2915     if (listColumn >= 0)
2916     {
2917         if (!m_isVirtual)
2918         {
2919             lcItem = (wxMacListCtrlItem*) itemID;
2920             if (lcItem && lcItem->HasColumnInfo(listColumn)){
2921                 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2922                 if (item->GetMask() & wxLIST_MASK_TEXT)
2923                     text = item->GetText();
2924                 if (item->GetMask() & wxLIST_MASK_IMAGE)
2925                     imgIndex = item->GetImage();
2926             }
2927         }
2928         else
2929         {
2930             long itemNum = (long)itemID-1;
2931             if (itemNum >= 0 && itemNum < list->GetItemCount())
2932             {
2933                 text = list->OnGetItemText( itemNum, listColumn );
2934                 imgIndex = list->OnGetItemColumnImage( itemNum, listColumn );
2935             }
2936         }
2937     }
2938 
2939     if ( !changeValue )
2940     {
2941         switch (property)
2942         {
2943             case kDataBrowserItemIsEditableProperty :
2944                 if ( list && list->HasFlag( wxLC_EDIT_LABELS ) )
2945                 {
2946                     verify_noerr(SetDataBrowserItemDataBooleanValue( itemData, true ));
2947                     err = noErr ;
2948                 }
2949                 break ;
2950             default :
2951                 if ( property >= kMinColumnId )
2952                 {
2953                     if (!text.IsEmpty()){
2954                         wxCFStringRef cfStr( text, wxLocale::GetSystemEncoding() );
2955                         err = ::SetDataBrowserItemDataText( itemData, cfStr );
2956                         err = noErr;
2957                     }
2958 
2959 
2960 
2961                     if ( imgIndex != -1 )
2962                     {
2963                         wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2964                         if (imageList && imageList->GetImageCount() > 0){
2965                             wxBitmap bmp = imageList->GetBitmap(imgIndex);
2966                             IconRef icon = bmp.GetIconRef();
2967                             ::SetDataBrowserItemDataIcon(itemData, icon);
2968                         }
2969                     }
2970 
2971                 }
2972                 break ;
2973         }
2974 
2975     }
2976     else
2977     {
2978         switch (property)
2979         {
2980              default:
2981                 if ( property >= kMinColumnId )
2982                 {
2983                     DataBrowserTableViewColumnIndex listColumn = 0;
2984                     verify_noerr( GetColumnPosition( property, &listColumn ) );
2985 
2986                     // TODO probably send the 'end edit' from here, as we
2987                     // can then deal with the veto
2988                     CFStringRef sr ;
2989                     verify_noerr( GetDataBrowserItemDataText( itemData , &sr ) ) ;
2990                     wxCFStringRef cfStr(sr) ;;
2991                     if (m_isVirtual)
2992                         list->SetItem( (long)itemData-1 , listColumn, cfStr.AsString() ) ;
2993                     else
2994                     {
2995                         if (lcItem)
2996                             lcItem->SetColumnTextValue( listColumn, cfStr.AsString() );
2997                     }
2998                     err = noErr ;
2999                 }
3000                 break;
3001         }
3002     }
3003     return err;
3004 }
3005 
ItemNotification(DataBrowserItemID itemID,DataBrowserItemNotification message,DataBrowserItemDataRef itemData)3006 void wxMacDataBrowserListCtrlControl::ItemNotification(DataBrowserItemID itemID,
3007     DataBrowserItemNotification message,
3008     DataBrowserItemDataRef itemData )
3009 {
3010     wxMacListCtrlItem *item = NULL;
3011     if ( !m_isVirtual )
3012     {
3013         item = (wxMacListCtrlItem *) itemID;
3014     }
3015 
3016     // we want to depend on as little as possible to make sure tear-down of controls is safe
3017     if ( message == kDataBrowserItemRemoved )
3018     {
3019         if ( item )
3020             item->Notification(this, message, itemData);
3021         return;
3022     }
3023     else if ( message == kDataBrowserItemAdded )
3024     {
3025         // we don't issue events on adding, the item is not really stored in the list yet, so we
3026         // avoid asserts by getting out now
3027         if ( item )
3028             item->Notification(this, message, itemData);
3029         return  ;
3030     }
3031 
3032     wxListCtrl *list = wxDynamicCast( GetWXPeer() , wxListCtrl );
3033     if ( list )
3034     {
3035         bool trigger = false;
3036 
3037         wxListEvent event( wxEVT_LIST_ITEM_SELECTED, list->GetId() );
3038 
3039         event.SetEventObject( list );
3040         if ( !list->IsVirtual() )
3041         {
3042             DataBrowserTableViewRowIndex result = 0;
3043             verify_noerr( GetItemRow( itemID, &result ) ) ;
3044             event.m_itemIndex = result;
3045         }
3046         else
3047         {
3048             event.m_itemIndex = (long)itemID-1;
3049         }
3050         event.m_item.m_itemId = event.m_itemIndex;
3051         list->GetItem(event.m_item);
3052 
3053         switch (message)
3054         {
3055             case kDataBrowserItemDeselected:
3056                 event.SetEventType(wxEVT_LIST_ITEM_DESELECTED);
3057                 // as the generic implementation is also triggering this
3058                 // event for single selection, we do the same (different than listbox)
3059                 trigger = !IsSelectionSuppressed();
3060                 break;
3061 
3062             case kDataBrowserItemSelected:
3063                 trigger = !IsSelectionSuppressed();
3064 
3065                 break;
3066 
3067             case kDataBrowserItemDoubleClicked:
3068                 event.SetEventType( wxEVT_LIST_ITEM_ACTIVATED );
3069                 trigger = true;
3070                 break;
3071 
3072             case kDataBrowserEditStarted :
3073                 // TODO : how to veto ?
3074                 event.SetEventType( wxEVT_LIST_BEGIN_LABEL_EDIT ) ;
3075                 trigger = true ;
3076                 break ;
3077 
3078             case kDataBrowserEditStopped :
3079                 // TODO probably trigger only upon the value store callback, because
3080                 // here IIRC we cannot veto
3081                 event.SetEventType( wxEVT_LIST_END_LABEL_EDIT ) ;
3082                 trigger = true ;
3083                 break ;
3084 
3085             default:
3086                 break;
3087         }
3088 
3089         if ( trigger )
3090         {
3091             // direct notification is not always having the listbox GetSelection() having in synch with event
3092             wxPostEvent( list->GetEventHandler(), event );
3093         }
3094     }
3095 }
3096 
CompareItems(DataBrowserItemID itemOneID,DataBrowserItemID itemTwoID,DataBrowserPropertyID sortProperty)3097 Boolean wxMacDataBrowserListCtrlControl::CompareItems(DataBrowserItemID itemOneID,
3098                         DataBrowserItemID itemTwoID,
3099                         DataBrowserPropertyID sortProperty)
3100 {
3101 
3102     bool retval = false;
3103     wxString itemText;
3104     wxString otherItemText;
3105     long itemOrder;
3106     long otherItemOrder;
3107 
3108     DataBrowserTableViewColumnIndex colId = 0;
3109     verify_noerr( GetColumnPosition( sortProperty, &colId ) );
3110 
3111     wxListCtrl* list = wxDynamicCast( GetWXPeer() , wxListCtrl );
3112 
3113     DataBrowserSortOrder sort;
3114     verify_noerr(GetSortOrder(&sort));
3115 
3116     if (colId >= 0)
3117     {
3118         if (!m_isVirtual)
3119         {
3120             wxMacListCtrlItem* item = (wxMacListCtrlItem*)itemOneID;
3121             wxMacListCtrlItem* otherItem = (wxMacListCtrlItem*)itemTwoID;
3122 
3123             itemOrder = item->GetOrder();
3124             otherItemOrder = otherItem->GetOrder();
3125 
3126             wxListCtrlCompare func = list->GetCompareFunc();
3127             if (func != NULL)
3128             {
3129 
3130                 long item1 = -1;
3131                 long item2 = -1;
3132                 if (item && item->HasColumnInfo(0))
3133                     item1 = item->GetColumnInfo(0)->GetData();
3134                 if (otherItem && otherItem->HasColumnInfo(0))
3135                     item2 = otherItem->GetColumnInfo(0)->GetData();
3136 
3137                 if (item1 > -1 && item2 > -1)
3138                 {
3139                     int result = func(item1, item2, list->GetCompareFuncData());
3140                     if (sort == kDataBrowserOrderIncreasing)
3141                         return result >= 0;
3142                     else
3143                         return result < 0;
3144                 }
3145             }
3146 
3147             // we can't use the native control's sorting abilities, so just
3148             // sort by item id.
3149             return itemOrder < otherItemOrder;
3150         }
3151         else
3152         {
3153 
3154             long itemNum = (long)itemOneID;
3155             long otherItemNum = (long)itemTwoID;
3156 
3157             // virtual listctrls don't support sorting
3158             return itemNum < otherItemNum;
3159         }
3160     }
3161     else{
3162         // fallback for undefined cases
3163         retval = itemOneID < itemTwoID;
3164     }
3165 
3166     return retval;
3167 }
3168 
~wxMacDataBrowserListCtrlControl()3169 wxMacDataBrowserListCtrlControl::~wxMacDataBrowserListCtrlControl()
3170 {
3171 }
3172 
MacSetColumnInfo(unsigned int row,unsigned int column,wxListItem * item)3173 void wxMacDataBrowserListCtrlControl::MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item )
3174 {
3175     wxMacDataItem* dataItem = GetItemFromLine(row);
3176     wxASSERT_MSG( dataItem, wxT("could not obtain wxMacDataItem for row in MacSetColumnInfo. Is row a valid wxListCtrl row?") );
3177     if (item)
3178     {
3179         wxMacListCtrlItem* listItem = static_cast<wxMacListCtrlItem *>(dataItem);
3180         bool hasInfo = listItem->HasColumnInfo( column );
3181         listItem->SetColumnInfo( column, item );
3182         listItem->SetOrder(row);
3183         UpdateState(dataItem, item);
3184 
3185         wxListCtrl* list = wxDynamicCast( GetWXPeer() , wxListCtrl );
3186 
3187         // NB: When this call was made before a control was completely shown, it would
3188         // update the item prematurely (i.e. no text would be listed) and, on show,
3189         // only the sorted column would be refreshed, meaning only first column text labels
3190         // would be shown. Making sure not to update items until the control is visible
3191         // seems to fix this issue.
3192         if (hasInfo && list->IsShown())
3193         {
3194             DataBrowserTableViewColumnID id = 0;
3195             verify_noerr( GetColumnIDFromIndex( column, &id ) );
3196             UpdateItem( wxMacDataBrowserRootContainer, listItem , id );
3197         }
3198     }
3199 }
3200 
3201 // apply changes that need to happen immediately, rather than when the
3202 // databrowser control fires a callback.
UpdateState(wxMacDataItem * dataItem,wxListItem * listItem)3203 void wxMacDataBrowserListCtrlControl::UpdateState(wxMacDataItem* dataItem, wxListItem* listItem)
3204 {
3205     bool isSelected = IsItemSelected( dataItem );
3206     bool isSelectedState = (listItem->GetState() == wxLIST_STATE_SELECTED);
3207 
3208     // toggle the selection state if wxListInfo state and actual state don't match.
3209     if ( listItem->GetMask() & wxLIST_MASK_STATE && isSelected != isSelectedState )
3210     {
3211         DataBrowserSetOption options = kDataBrowserItemsAdd;
3212         if (!isSelectedState)
3213             options = kDataBrowserItemsRemove;
3214         SetSelectedItem(dataItem, options);
3215     }
3216     // TODO: Set column width if item width > than current column width
3217 }
3218 
MacGetColumnInfo(unsigned int row,unsigned int column,wxListItem & item)3219 void wxMacDataBrowserListCtrlControl::MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item )
3220 {
3221     wxMacDataItem* dataItem = GetItemFromLine(row);
3222     wxASSERT_MSG( dataItem, wxT("could not obtain wxMacDataItem in MacGetColumnInfo. Is row a valid wxListCtrl row?") );
3223     // CS should this guard against dataItem = 0 ? , as item is not a pointer if (item) is not appropriate
3224     //if (item)
3225     {
3226         wxMacListCtrlItem* listItem = static_cast<wxMacListCtrlItem *>(dataItem);
3227 
3228         if (!listItem->HasColumnInfo( column ))
3229             return;
3230 
3231         wxListItem* oldItem = listItem->GetColumnInfo( column );
3232 
3233         if (oldItem)
3234         {
3235             long mask = item.GetMask();
3236             if ( !mask )
3237                 // by default, get everything for backwards compatibility
3238                 mask = -1;
3239 
3240             if ( mask & wxLIST_MASK_TEXT )
3241                 item.SetText(oldItem->GetText());
3242             if ( mask & wxLIST_MASK_IMAGE )
3243                 item.SetImage(oldItem->GetImage());
3244             if ( mask & wxLIST_MASK_DATA )
3245                 item.SetData(oldItem->GetData());
3246             if ( mask & wxLIST_MASK_STATE )
3247                 item.SetState(oldItem->GetState());
3248             if ( mask & wxLIST_MASK_WIDTH )
3249                 item.SetWidth(oldItem->GetWidth());
3250             if ( mask & wxLIST_MASK_FORMAT )
3251                 item.SetAlign(oldItem->GetAlign());
3252 
3253             item.SetTextColour(oldItem->GetTextColour());
3254             item.SetBackgroundColour(oldItem->GetBackgroundColour());
3255             item.SetFont(oldItem->GetFont());
3256         }
3257     }
3258 }
3259 
MacInsertItem(unsigned int n,wxListItem * item)3260 void wxMacDataBrowserListCtrlControl::MacInsertItem( unsigned int n, wxListItem* item )
3261 {
3262 
3263     wxMacDataItemBrowserControl::MacInsert(n, new wxMacListCtrlItem() );
3264     MacSetColumnInfo(n, 0, item);
3265 }
3266 
wxMacListCtrlItem()3267 wxMacListCtrlItem::wxMacListCtrlItem()
3268 {
3269     m_rowItems = wxListItemList();
3270 }
3271 
GetColumnImageValue(unsigned int column)3272 int wxMacListCtrlItem::GetColumnImageValue( unsigned int column )
3273 {
3274     if ( HasColumnInfo(column) )
3275         return GetColumnInfo(column)->GetImage();
3276 
3277     return -1;
3278 }
3279 
SetColumnImageValue(unsigned int column,int imageIndex)3280 void wxMacListCtrlItem::SetColumnImageValue( unsigned int column, int imageIndex )
3281 {
3282     if ( HasColumnInfo(column) )
3283         GetColumnInfo(column)->SetImage(imageIndex);
3284 }
3285 
GetColumnTextValue(unsigned int column)3286 wxString wxMacListCtrlItem::GetColumnTextValue( unsigned int column )
3287 {
3288 /* TODO CHECK REMOVE
3289     if ( column == 0 )
3290         return GetLabel();
3291 */
3292     if ( HasColumnInfo(column) )
3293         return GetColumnInfo(column)->GetText();
3294 
3295     return wxEmptyString;
3296 }
3297 
SetColumnTextValue(unsigned int column,const wxString & text)3298 void wxMacListCtrlItem::SetColumnTextValue( unsigned int column, const wxString& text )
3299 {
3300     if ( HasColumnInfo(column) )
3301         GetColumnInfo(column)->SetText(text);
3302 
3303 /* TODO CHECK REMOVE
3304     // for compatibility with superclass APIs
3305     if ( column == 0 )
3306         SetLabel(text);
3307 */
3308 }
3309 
GetColumnInfo(unsigned int column)3310 wxListItem* wxMacListCtrlItem::GetColumnInfo( unsigned int column )
3311 {
3312     wxASSERT_MSG( HasColumnInfo(column), wxT("invalid column index in wxMacListCtrlItem") );
3313     return m_rowItems[column];
3314 }
3315 
HasColumnInfo(unsigned int column)3316 bool wxMacListCtrlItem::HasColumnInfo( unsigned int column )
3317 {
3318     return !(m_rowItems.find( column ) == m_rowItems.end());
3319 }
3320 
SetColumnInfo(unsigned int column,wxListItem * item)3321 void wxMacListCtrlItem::SetColumnInfo( unsigned int column, wxListItem* item )
3322 {
3323 
3324     if ( !HasColumnInfo(column) )
3325     {
3326         wxListItem* listItem = new wxListItem(*item);
3327         m_rowItems[column] = listItem;
3328     }
3329     else
3330     {
3331         wxListItem* listItem = GetColumnInfo( column );
3332         long mask = item->GetMask();
3333         if (mask & wxLIST_MASK_TEXT)
3334             listItem->SetText(item->GetText());
3335         if (mask & wxLIST_MASK_DATA)
3336             listItem->SetData(item->GetData());
3337         if (mask & wxLIST_MASK_IMAGE)
3338             listItem->SetImage(item->GetImage());
3339         if (mask & wxLIST_MASK_STATE)
3340             listItem->SetState(item->GetState());
3341         if (mask & wxLIST_MASK_FORMAT)
3342             listItem->SetAlign(item->GetAlign());
3343         if (mask & wxLIST_MASK_WIDTH)
3344             listItem->SetWidth(item->GetWidth());
3345 
3346         if ( item->HasAttributes() )
3347         {
3348             if ( listItem->HasAttributes() )
3349                 listItem->GetAttributes()->AssignFrom(*item->GetAttributes());
3350             else
3351             {
3352                 listItem->SetTextColour(item->GetTextColour());
3353                 listItem->SetBackgroundColour(item->GetBackgroundColour());
3354                 listItem->SetFont(item->GetFont());
3355             }
3356         }
3357     }
3358 }
3359 
CalcColumnAutoWidth(int col) const3360 int wxListCtrl::CalcColumnAutoWidth(int col) const
3361 {
3362     int width = 0;
3363 
3364     for ( int i = 0; i < GetItemCount(); i++ )
3365     {
3366         wxListItem info;
3367         info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE);
3368         info.SetId(i);
3369         info.SetColumn(col);
3370         GetItem(info);
3371 
3372         const wxFont font = info.GetFont();
3373 
3374         int w = 0;
3375         if ( font.IsOk() )
3376             GetTextExtent(info.GetText(), &w, NULL, NULL, NULL, &font);
3377         else
3378             GetTextExtent(info.GetText(), &w, NULL);
3379 
3380         w += 2 * kItemPadding;
3381 
3382         if ( info.GetImage() != -1 )
3383             w += kIconWidth;
3384 
3385         width = wxMax(width, w);
3386     }
3387 
3388     return width;
3389 }
3390 
3391 #endif // wxUSE_LISTCTRL
3392 
3393