]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/listctrl_mac.cpp
Fixing icon drawing and implementing HitTest and GetItemRect for native OS X list...
[wxWidgets.git] / src / mac / carbon / listctrl_mac.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/listctrl_mac.cpp
3 // Purpose: wxListCtrl
4 // Author: Julian Smart
5 // Modified by: Agron Selimaj
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_LISTCTRL
28
29 #include "wx/listctrl.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #endif
34
35 #include "wx/mac/uma.h"
36
37 #include "wx/imaglist.h"
38 #include "wx/sysopt.h"
39
40 #define wxMAC_ALWAYS_USE_GENERIC_LISTCTRL wxT("mac.listctrl.always_use_generic")
41
42 #if wxUSE_EXTENDED_RTTI
43 WX_DEFINE_FLAGS( wxListCtrlStyle )
44
45 wxBEGIN_FLAGS( wxListCtrlStyle )
46 // new style border flags, we put them first to
47 // use them for streaming out
48 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
49 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
50 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
51 wxFLAGS_MEMBER(wxBORDER_RAISED)
52 wxFLAGS_MEMBER(wxBORDER_STATIC)
53 wxFLAGS_MEMBER(wxBORDER_NONE)
54
55 // old style border flags
56 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
57 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
58 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
59 wxFLAGS_MEMBER(wxRAISED_BORDER)
60 wxFLAGS_MEMBER(wxSTATIC_BORDER)
61 wxFLAGS_MEMBER(wxBORDER)
62
63 // standard window styles
64 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
65 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
66 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
67 wxFLAGS_MEMBER(wxWANTS_CHARS)
68 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
69 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
70 wxFLAGS_MEMBER(wxVSCROLL)
71 wxFLAGS_MEMBER(wxHSCROLL)
72
73 wxFLAGS_MEMBER(wxLC_LIST)
74 wxFLAGS_MEMBER(wxLC_REPORT)
75 wxFLAGS_MEMBER(wxLC_ICON)
76 wxFLAGS_MEMBER(wxLC_SMALL_ICON)
77 wxFLAGS_MEMBER(wxLC_ALIGN_TOP)
78 wxFLAGS_MEMBER(wxLC_ALIGN_LEFT)
79 wxFLAGS_MEMBER(wxLC_AUTOARRANGE)
80 wxFLAGS_MEMBER(wxLC_USER_TEXT)
81 wxFLAGS_MEMBER(wxLC_EDIT_LABELS)
82 wxFLAGS_MEMBER(wxLC_NO_HEADER)
83 wxFLAGS_MEMBER(wxLC_SINGLE_SEL)
84 wxFLAGS_MEMBER(wxLC_SORT_ASCENDING)
85 wxFLAGS_MEMBER(wxLC_SORT_DESCENDING)
86 wxFLAGS_MEMBER(wxLC_VIRTUAL)
87
88 wxEND_FLAGS( wxListCtrlStyle )
89
90 IMPLEMENT_DYNAMIC_CLASS_XTI(wxListCtrl, wxControl,"wx/listctrl.h")
91
92 wxBEGIN_PROPERTIES_TABLE(wxListCtrl)
93 wxEVENT_PROPERTY( TextUpdated , wxEVT_COMMAND_TEXT_UPDATED , wxCommandEvent )
94
95 wxPROPERTY_FLAGS( WindowStyle , wxListCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
96 wxEND_PROPERTIES_TABLE()
97
98 wxBEGIN_HANDLERS_TABLE(wxListCtrl)
99 wxEND_HANDLERS_TABLE()
100
101 wxCONSTRUCTOR_5( wxListCtrl , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
102
103 /*
104 TODO : Expose more information of a list's layout etc. via appropriate objects (à la NotebookPageInfo)
105 */
106 #else
107 IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
108 #endif
109
110 IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
111 IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
112
113 IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
114
115 WX_DECLARE_EXPORTED_LIST(wxListItem, wxListItemList);
116 #include "wx/listimpl.cpp"
117 WX_DEFINE_LIST(wxListItemList)
118 WX_DEFINE_LIST(wxColumnList)
119
120 // so we can check for column clicks
121 static const EventTypeSpec eventList[] =
122 {
123 { kEventClassControl, kEventControlHit },
124 { kEventClassControl, kEventControlDraw }
125 };
126
127 static pascal OSStatus wxMacListCtrlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
128 {
129 OSStatus result = eventNotHandledErr ;
130
131 wxMacCarbonEvent cEvent( event ) ;
132
133 ControlRef controlRef ;
134 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
135
136 wxListCtrl *window = (wxListCtrl*) data ;
137 wxListEvent le( wxEVT_COMMAND_LIST_COL_CLICK, window->GetId() );
138 le.SetEventObject( window );
139
140 switch ( GetEventKind( event ) )
141 {
142 // check if the column was clicked on and fire an event if so
143 case kEventControlHit :
144 {
145 ControlPartCode result = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart, typeControlPartCode) ;
146 if (result == kControlButtonPart){
147 DataBrowserPropertyID col;
148 GetDataBrowserSortProperty(controlRef, &col);
149 int column = col - kMinColumnId;
150 le.m_col = column;
151 window->GetEventHandler()->ProcessEvent( le );
152 }
153 result = CallNextEventHandler(handler, event);
154 break;
155 }
156 case kEventControlDraw:
157 {
158 CGContextRef context = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef, typeCGContextRef) ;
159 window->MacSetDrawingContext(context);
160 result = CallNextEventHandler(handler, event);
161 window->MacSetDrawingContext(NULL);
162 break;
163 }
164 default :
165 break ;
166 }
167
168
169 return result ;
170 }
171
172 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacListCtrlEventHandler )
173
174 class wxMacListCtrlItem : public wxMacListBoxItem
175 {
176 public:
177 wxMacListCtrlItem();
178
179 virtual void Notification(wxMacDataItemBrowserControl *owner ,
180 DataBrowserItemNotification message,
181 DataBrowserItemDataRef itemData ) const;
182
183 virtual void SetColumnInfo( unsigned int column, wxListItem* item );
184 virtual wxListItem* GetColumnInfo( unsigned int column );
185 virtual bool HasColumnInfo( unsigned int column );
186
187 virtual void SetColumnTextValue( unsigned int column, const wxString& text );
188 virtual const wxString& GetColumnTextValue( unsigned int column );
189
190 virtual int GetColumnImageValue( unsigned int column );
191 virtual void SetColumnImageValue( unsigned int column, int imageIndex );
192
193 virtual ~wxMacListCtrlItem();
194 protected:
195 wxListItemList m_rowItems;
196 };
197
198 DataBrowserDrawItemUPP gDataBrowserDrawItemUPP = NULL;
199 //DataBrowserEditItemUPP gDataBrowserEditItemUPP = NULL;
200 DataBrowserHitTestUPP gDataBrowserHitTestUPP = NULL;
201
202 // TODO: Make a better name!!
203 class wxMacDataBrowserListCtrlControl : public wxMacDataItemBrowserControl
204 {
205 public:
206 wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style );
207 virtual ~wxMacDataBrowserListCtrlControl();
208
209 // create a list item (can be a subclass of wxMacListBoxItem)
210
211 virtual wxMacDataItem* CreateItem();
212
213 virtual void MacInsertItem( unsigned int n, wxListItem* item );
214 virtual void MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item );
215 virtual void MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item );
216 virtual void UpdateState(wxMacDataItem* dataItem, wxListItem* item);
217
218 protected:
219 // we need to override to provide specialized handling for virtual wxListCtrls
220 virtual OSStatus GetSetItemData(DataBrowserItemID itemID,
221 DataBrowserPropertyID property,
222 DataBrowserItemDataRef itemData,
223 Boolean changeValue );
224
225 virtual void ItemNotification(
226 DataBrowserItemID itemID,
227 DataBrowserItemNotification message,
228 DataBrowserItemDataRef itemData);
229
230 virtual Boolean CompareItems(DataBrowserItemID itemOneID,
231 DataBrowserItemID itemTwoID,
232 DataBrowserPropertyID sortProperty);
233
234 static pascal void DataBrowserDrawItemProc(ControlRef browser,
235 DataBrowserItemID item,
236 DataBrowserPropertyID property,
237 DataBrowserItemState itemState,
238 const Rect *theRect,
239 SInt16 gdDepth,
240 Boolean colorDevice);
241
242 virtual void DrawItem(DataBrowserItemID itemID,
243 DataBrowserPropertyID property,
244 DataBrowserItemState itemState,
245 const Rect *itemRect,
246 SInt16 gdDepth,
247 Boolean colorDevice);
248
249 static pascal Boolean DataBrowserEditTextProc(ControlRef browser,
250 DataBrowserItemID item,
251 DataBrowserPropertyID property,
252 CFStringRef theString,
253 Rect *maxEditTextRect,
254 Boolean *shrinkToFit);
255
256 static pascal Boolean DataBrowserHitTestProc(ControlRef browser,
257 DataBrowserItemID itemID,
258 DataBrowserPropertyID property,
259 const Rect *theRect,
260 const Rect *mouseRect) { return true; }
261
262 virtual bool ConfirmEditText(DataBrowserItemID item,
263 DataBrowserPropertyID property,
264 CFStringRef theString,
265 Rect *maxEditTextRect,
266 Boolean *shrinkToFit);
267
268
269
270 wxClientDataType m_clientDataItemsType;
271 bool m_isVirtual;
272
273 };
274
275 class wxMacListCtrlEventDelegate : public wxEvtHandler
276 {
277 public:
278 wxMacListCtrlEventDelegate( wxListCtrl* list, int id );
279 virtual bool ProcessEvent( wxEvent& event );
280
281 private:
282 wxListCtrl* m_list;
283 int m_id;
284 };
285
286 wxMacListCtrlEventDelegate::wxMacListCtrlEventDelegate( wxListCtrl* list, int id )
287 {
288 m_list = list;
289 m_id = id;
290 }
291
292 bool wxMacListCtrlEventDelegate::ProcessEvent( wxEvent& event )
293 {
294 // even though we use a generic list ctrl underneath, make sure
295 // we present ourselves as wxListCtrl.
296 event.SetEventObject( m_list );
297 event.SetId( m_id );
298
299 if ( !event.IsKindOf( CLASSINFO( wxCommandEvent ) ) )
300 {
301 if (m_list->GetEventHandler()->ProcessEvent( event ))
302 return true;
303 }
304 return wxEvtHandler::ProcessEvent(event);
305 }
306
307 // ============================================================================
308 // implementation
309 // ============================================================================
310
311 wxMacListControl* wxListCtrl::GetPeer() const
312 {
313 return dynamic_cast<wxMacListControl*>(m_peer);
314 }
315
316 // ----------------------------------------------------------------------------
317 // wxListCtrl construction
318 // ----------------------------------------------------------------------------
319
320 void wxListCtrl::Init()
321 {
322 m_imageListNormal = NULL;
323 m_imageListSmall = NULL;
324 m_imageListState = NULL;
325
326 // keep track of if we created our own image lists, or if they were assigned
327 // to us.
328 m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = false;
329 m_colCount = 0;
330 m_count = 0;
331 m_textCtrl = NULL;
332 m_genericImpl = NULL;
333 m_dbImpl = NULL;
334 m_compareFunc = NULL;
335 m_compareFuncData = 0;
336 m_colsInfo = wxColumnList();
337 m_textColor = wxNullColour;
338 m_bgColor = wxNullColour;
339 }
340
341 class wxGenericListCtrlHook : public wxGenericListCtrl
342 {
343 public:
344 wxGenericListCtrlHook(wxListCtrl* parent,
345 wxWindowID id,
346 const wxPoint& pos,
347 const wxSize& size,
348 long style,
349 const wxValidator& validator,
350 const wxString& name)
351 : wxGenericListCtrl(parent, id, pos, size, style, validator, name),
352 m_nativeListCtrl(parent)
353 {
354 }
355
356 protected:
357 virtual wxListItemAttr * OnGetItemAttr(long item) const
358 {
359 return m_nativeListCtrl->OnGetItemAttr(item);
360 }
361
362 virtual int OnGetItemImage(long item) const
363 {
364 return m_nativeListCtrl->OnGetItemImage(item);
365 }
366
367 virtual int OnGetItemColumnImage(long item, long column) const
368 {
369 return m_nativeListCtrl->OnGetItemColumnImage(item, column);
370 }
371
372 virtual wxString OnGetItemText(long item, long column) const
373 {
374 return m_nativeListCtrl->OnGetItemText(item, column);
375 }
376
377 wxListCtrl* m_nativeListCtrl;
378
379 };
380
381 bool wxListCtrl::Create(wxWindow *parent,
382 wxWindowID id,
383 const wxPoint& pos,
384 const wxSize& size,
385 long style,
386 const wxValidator& validator,
387 const wxString& name)
388 {
389
390 // for now, we'll always use the generic list control for ICON and LIST views,
391 // because they dynamically change the number of columns on resize.
392 // Also, allow the user to set it to use the list ctrl as well.
393 // Also, use generic list control in VIRTUAL mode.
394 if ( (wxSystemOptions::HasOption( wxMAC_ALWAYS_USE_GENERIC_LISTCTRL )
395 && (wxSystemOptions::GetOptionInt( wxMAC_ALWAYS_USE_GENERIC_LISTCTRL ) == 1)) ||
396 (style & wxLC_ICON) || (style & wxLC_SMALL_ICON) || (style & wxLC_LIST) || (style & wxLC_EDIT_LABELS) )
397 {
398 m_macIsUserPane = true;
399
400 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
401 return false;
402 m_genericImpl = new wxGenericListCtrlHook(this, id, pos, size, style, validator, name);
403 m_genericImpl->PushEventHandler( new wxMacListCtrlEventDelegate( this, GetId() ) );
404 return true;
405 }
406
407 else
408 {
409 m_macIsUserPane = false;
410
411 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
412 return false;
413 m_dbImpl = new wxMacDataBrowserListCtrlControl( this, pos, size, style );
414 m_peer = m_dbImpl;
415
416 MacPostControlCreate( pos, size );
417
418 InstallControlEventHandler( m_peer->GetControlRef() , GetwxMacListCtrlEventHandlerUPP(),
419 GetEventTypeCount(eventList), eventList, this,
420 (EventHandlerRef *)&m_macListCtrlEventHandler);
421 }
422
423 return true;
424 }
425
426 wxListCtrl::~wxListCtrl()
427 {
428 if (m_genericImpl)
429 {
430 m_genericImpl->PopEventHandler(/* deleteHandler = */ true);
431 }
432
433 if (m_ownsImageListNormal)
434 delete m_imageListNormal;
435 if (m_ownsImageListSmall)
436 delete m_imageListSmall;
437 if (m_ownsImageListState)
438 delete m_imageListState;
439 }
440
441 // ----------------------------------------------------------------------------
442 // set/get/change style
443 // ----------------------------------------------------------------------------
444
445 // Add or remove a single window style
446 void wxListCtrl::SetSingleStyle(long style, bool add)
447 {
448 long flag = GetWindowStyleFlag();
449
450 // Get rid of conflicting styles
451 if ( add )
452 {
453 if ( style & wxLC_MASK_TYPE)
454 flag = flag & ~wxLC_MASK_TYPE;
455 if ( style & wxLC_MASK_ALIGN )
456 flag = flag & ~wxLC_MASK_ALIGN;
457 if ( style & wxLC_MASK_SORT )
458 flag = flag & ~wxLC_MASK_SORT;
459 }
460
461 if ( add )
462 flag |= style;
463 else
464 flag &= ~style;
465
466 SetWindowStyleFlag(flag);
467 }
468
469 // Set the whole window style
470 void wxListCtrl::SetWindowStyleFlag(long flag)
471 {
472 if ( flag != m_windowStyle )
473 {
474 m_windowStyle = flag;
475
476 if (m_genericImpl)
477 {
478 m_genericImpl->SetWindowStyleFlag(flag);
479 }
480
481 Refresh();
482 }
483 }
484
485 void wxListCtrl::DoSetSize( int x, int y, int width, int height, int sizeFlags )
486 {
487 wxControl::DoSetSize(x, y, width, height, sizeFlags);
488
489 if (m_genericImpl)
490 m_genericImpl->SetSize(x, y, width, height, sizeFlags);
491 }
492
493 bool wxListCtrl::SetFont(const wxFont& font)
494 {
495 bool rv = true;
496 rv = wxControl::SetFont(font);
497 if (m_genericImpl)
498 rv = m_genericImpl->SetFont(font);
499 return rv;
500 }
501
502 bool wxListCtrl::SetForegroundColour(const wxColour& colour)
503 {
504 bool rv = true;
505 if (m_genericImpl)
506 rv = m_genericImpl->SetForegroundColour(colour);
507 if (m_dbImpl)
508 SetTextColour(colour);
509 return rv;
510 }
511
512 bool wxListCtrl::SetBackgroundColour(const wxColour& colour)
513 {
514 bool rv = true;
515 if (m_genericImpl)
516 rv = m_genericImpl->SetBackgroundColour(colour);
517 if (m_dbImpl)
518 m_bgColor = colour;
519 return rv;
520 }
521
522 wxColour wxListCtrl::GetBackgroundColour()
523 {
524 if (m_genericImpl)
525 return m_genericImpl->GetBackgroundColour();
526 if (m_dbImpl)
527 return m_bgColor;
528
529 return wxNullColour;
530 }
531
532 // ----------------------------------------------------------------------------
533 // accessors
534 // ----------------------------------------------------------------------------
535
536 // Gets information about this column
537 bool wxListCtrl::GetColumn(int col, wxListItem& item) const
538 {
539 if (m_genericImpl)
540 return m_genericImpl->GetColumn(col, item);
541
542 bool success = true;
543
544 if (m_dbImpl)
545 {
546
547 wxColumnList::compatibility_iterator node = m_colsInfo.Item( col );
548 wxASSERT_MSG( node, _T("invalid column index in wxMacListCtrlItem") );
549 wxListItem* column = node->GetData();
550
551 long mask = column->GetMask();
552 if (mask & wxLIST_MASK_TEXT)
553 item.SetText(column->GetText());
554 if (mask & wxLIST_MASK_DATA)
555 item.SetData(column->GetData());
556 if (mask & wxLIST_MASK_IMAGE)
557 item.SetImage(column->GetImage());
558 if (mask & wxLIST_MASK_STATE)
559 item.SetState(column->GetState());
560 if (mask & wxLIST_MASK_FORMAT)
561 item.SetAlign(column->GetAlign());
562 if (mask & wxLIST_MASK_WIDTH)
563 item.SetWidth(column->GetWidth());
564 }
565
566 return success;
567 }
568
569 // Sets information about this column
570 bool wxListCtrl::SetColumn(int col, wxListItem& item)
571 {
572 if (m_genericImpl)
573 return m_genericImpl->SetColumn(col, item);
574
575 if (m_dbImpl)
576 {
577 if ( col >= (int)m_colsInfo.GetCount() )
578 {
579 wxListItem* listItem = new wxListItem(item);
580 m_colsInfo.Append( listItem );
581 }
582 else
583 {
584 wxListItem listItem;
585 GetColumn( col, listItem );
586 long mask = item.GetMask();
587 if (mask & wxLIST_MASK_TEXT)
588 listItem.SetText(item.GetText());
589 if (mask & wxLIST_MASK_DATA)
590 listItem.SetData(item.GetData());
591 if (mask & wxLIST_MASK_IMAGE)
592 listItem.SetImage(item.GetImage());
593 if (mask & wxLIST_MASK_STATE)
594 listItem.SetState(item.GetState());
595 if (mask & wxLIST_MASK_FORMAT)
596 listItem.SetAlign(item.GetAlign());
597 if (mask & wxLIST_MASK_WIDTH)
598 listItem.SetWidth(item.GetWidth());
599 }
600
601 // change the appearance in the databrowser.
602 DataBrowserListViewHeaderDesc columnDesc;
603 columnDesc.version=kDataBrowserListViewLatestHeaderDesc;
604 verify_noerr( m_dbImpl->GetHeaderDesc( kMinColumnId + col, &columnDesc ) );
605
606 /*
607 if (item.GetMask() & wxLIST_MASK_TEXT)
608 {
609 wxFontEncoding enc;
610 if ( m_font.Ok() )
611 enc = m_font.GetEncoding();
612 else
613 enc = wxLocale::GetSystemEncoding();
614 wxMacCFStringHolder cfTitle;
615 cfTitle.Assign( item.GetText() , enc );
616 if(columnDesc.titleString)
617 CFRelease(columnDesc.titleString);
618 columnDesc.titleString = cfTitle;
619 }
620 */
621
622 if (item.GetMask() & wxLIST_MASK_IMAGE && item.GetImage() != -1 )
623 {
624 columnDesc.btnContentInfo.contentType = kControlContentIconRef;
625 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
626 if (imageList && imageList->GetImageCount() > 0 )
627 {
628 wxBitmap bmp = imageList->GetBitmap( item.GetImage() );
629 IconRef icon = bmp.GetBitmapData()->GetIconRef();
630 columnDesc.btnContentInfo.u.iconRef = icon;
631 }
632 }
633
634 verify_noerr( m_dbImpl->SetHeaderDesc( kMinColumnId + col, &columnDesc ) );
635
636 }
637 return true;
638 }
639
640 int wxListCtrl::GetColumnCount() const
641 {
642 if (m_genericImpl)
643 return m_genericImpl->GetColumnCount();
644
645 if (m_dbImpl)
646 {
647 UInt32 count;
648 m_dbImpl->GetColumnCount(&count);
649 return count;
650 }
651
652 return m_colCount;
653 }
654
655 // Gets the column width
656 int wxListCtrl::GetColumnWidth(int col) const
657 {
658 if (m_genericImpl)
659 return m_genericImpl->GetColumnWidth(col);
660
661 if (m_dbImpl)
662 {
663 return m_dbImpl->GetColumnWidth(col);
664 }
665
666 return 0;
667 }
668
669 // Sets the column width
670 bool wxListCtrl::SetColumnWidth(int col, int width)
671 {
672 if (m_genericImpl)
673 return m_genericImpl->SetColumnWidth(col, width);
674
675 if (m_dbImpl)
676 {
677 int mywidth = width;
678 if (width == wxLIST_AUTOSIZE || width == wxLIST_AUTOSIZE_USEHEADER)
679 mywidth = 150;
680
681 if (col == -1)
682 {
683 for (int column = 0; column < GetColumnCount(); column++)
684 {
685 m_dbImpl->SetColumnWidth(col, mywidth);
686 }
687 }
688 else{
689 m_dbImpl->SetColumnWidth(col, mywidth);
690 }
691 return true;
692 }
693
694 return false;
695 }
696
697 // Gets the number of items that can fit vertically in the
698 // visible area of the list control (list or report view)
699 // or the total number of items in the list control (icon
700 // or small icon view)
701 int wxListCtrl::GetCountPerPage() const
702 {
703 if (m_genericImpl)
704 return m_genericImpl->GetCountPerPage();
705
706 if (m_dbImpl)
707 {
708 }
709
710 return 1;
711 }
712
713 // Gets the edit control for editing labels.
714 wxTextCtrl* wxListCtrl::GetEditControl() const
715 {
716 if (m_genericImpl)
717 return m_genericImpl->GetEditControl();
718
719 return NULL;
720 }
721
722 // Gets information about the item
723 bool wxListCtrl::GetItem(wxListItem& info) const
724 {
725 if (m_genericImpl)
726 return m_genericImpl->GetItem(info);
727
728 if (m_dbImpl)
729 {
730 if (!IsVirtual())
731 m_dbImpl->MacGetColumnInfo(info.m_itemId, info.m_col, info);
732 else
733 {
734 info.SetText( OnGetItemText(info.m_itemId, info.m_col) );
735 info.SetImage( OnGetItemColumnImage(info.m_itemId, info.m_col) );
736 wxListItemAttr* attrs = OnGetItemAttr( info.m_itemId );
737 if (attrs)
738 {
739 info.SetFont( attrs->GetFont() );
740 info.SetBackgroundColour( attrs->GetBackgroundColour() );
741 info.SetTextColour( attrs->GetTextColour() );
742 }
743 }
744 }
745 bool success = true;
746 return success;
747 }
748
749 // Sets information about the item
750 bool wxListCtrl::SetItem(wxListItem& info)
751 {
752 if (m_genericImpl)
753 return m_genericImpl->SetItem(info);
754
755 if (m_dbImpl)
756 m_dbImpl->MacSetColumnInfo( info.m_itemId, info.m_col, &info );
757
758 return true;
759 }
760
761 long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
762 {
763 if (m_genericImpl)
764 return m_genericImpl->SetItem(index, col, label, imageId);
765
766 wxListItem info;
767 info.m_text = label;
768 info.m_mask = wxLIST_MASK_TEXT;
769 info.m_itemId = index;
770 info.m_col = col;
771 if ( imageId > -1 )
772 {
773 info.m_image = imageId;
774 info.m_mask |= wxLIST_MASK_IMAGE;
775 }
776 return SetItem(info);
777 }
778
779
780 // Gets the item state
781 int wxListCtrl::GetItemState(long item, long stateMask) const
782 {
783 if (m_genericImpl)
784 return m_genericImpl->GetItemState(item, stateMask);
785
786 wxListItem info;
787
788 info.m_mask = wxLIST_MASK_STATE;
789 info.m_stateMask = stateMask;
790 info.m_itemId = item;
791
792 if (!GetItem(info))
793 return 0;
794
795 return info.m_state;
796 }
797
798 // Sets the item state
799 bool wxListCtrl::SetItemState(long item, long state, long stateMask)
800 {
801 if (m_genericImpl)
802 return m_genericImpl->SetItemState(item, state, stateMask);
803
804 wxListItem info;
805 info.m_mask = wxLIST_MASK_STATE;
806 info.m_stateMask = stateMask;
807 info.m_state = state;
808 info.m_itemId = item;
809 return SetItem(info);
810 }
811
812 // Sets the item image
813 bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
814 {
815 return SetItemColumnImage(item, 0, image);
816 }
817
818 // Sets the item image
819 bool wxListCtrl::SetItemColumnImage(long item, long column, int image)
820 {
821 if (m_genericImpl)
822 return m_genericImpl->SetItemColumnImage(item, column, image);
823
824 wxListItem info;
825
826 info.m_mask = wxLIST_MASK_IMAGE;
827 info.m_image = image;
828 info.m_itemId = item;
829 info.m_col = column;
830
831 return SetItem(info);
832 }
833
834 // Gets the item text
835 wxString wxListCtrl::GetItemText(long item) const
836 {
837 if (m_genericImpl)
838 return m_genericImpl->GetItemText(item);
839
840 wxListItem info;
841
842 info.m_mask = wxLIST_MASK_TEXT;
843 info.m_itemId = item;
844
845 if (!GetItem(info))
846 return wxEmptyString;
847 return info.m_text;
848 }
849
850 // Sets the item text
851 void wxListCtrl::SetItemText(long item, const wxString& str)
852 {
853 if (m_genericImpl)
854 return m_genericImpl->SetItemText(item, str);
855
856 wxListItem info;
857
858 info.m_mask = wxLIST_MASK_TEXT;
859 info.m_itemId = item;
860 info.m_text = str;
861
862 SetItem(info);
863 }
864
865 // Gets the item data
866 long wxListCtrl::GetItemData(long item) const
867 {
868 if (m_genericImpl)
869 return m_genericImpl->GetItemData(item);
870
871 wxListItem info;
872
873 info.m_mask = wxLIST_MASK_DATA;
874 info.m_itemId = item;
875
876 if (!GetItem(info))
877 return 0;
878 return info.m_data;
879 }
880
881 // Sets the item data
882 bool wxListCtrl::SetItemData(long item, long data)
883 {
884 if (m_genericImpl)
885 return m_genericImpl->SetItemData(item, data);
886
887 wxListItem info;
888
889 info.m_mask = wxLIST_MASK_DATA;
890 info.m_itemId = item;
891 info.m_data = data;
892
893 return SetItem(info);
894 }
895
896 wxRect wxListCtrl::GetViewRect() const
897 {
898 wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
899 _T("wxListCtrl::GetViewRect() only works in icon mode") );
900
901 if (m_genericImpl)
902 return m_genericImpl->GetViewRect();
903
904 wxRect rect;
905 return rect;
906 }
907
908 // Gets the item rectangle
909 bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
910 {
911 if (m_genericImpl)
912 return m_genericImpl->GetItemRect(item, rect, code);
913
914
915 if (m_dbImpl)
916 {
917 DataBrowserItemID id;
918 DataBrowserPropertyID col = kMinColumnId;
919 Rect bounds;
920 DataBrowserPropertyPart part = kDataBrowserPropertyEnclosingPart;
921 if ( code == wxLIST_RECT_LABEL )
922 part = kDataBrowserPropertyTextPart;
923 else if ( code == wxLIST_RECT_ICON )
924 part = kDataBrowserPropertyIconPart;
925
926 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL) )
927 {
928 wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(item);
929 id = (DataBrowserItemID) thisItem;
930 }
931 else
932 id = item;
933
934 GetDataBrowserItemPartBounds( m_dbImpl->GetControlRef(), id, col, part, &bounds );
935
936 rect.x = bounds.left;
937 rect.y = bounds.top;
938 rect.width = GetClientSize().x; // we need the width of the whole row, not just the item.
939 rect.height = bounds.bottom - bounds.top;
940 }
941 return true;
942 }
943
944 // Gets the item position
945 bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
946 {
947 if (m_genericImpl)
948 return m_genericImpl->GetItemPosition(item, pos);
949
950 bool success = false;
951
952 if (m_dbImpl)
953 {
954 wxRect itemRect;
955 GetItemRect(item, itemRect);
956 pos = itemRect.GetPosition();
957 success = true;
958 }
959
960 return success;
961 }
962
963 // Sets the item position.
964 bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
965 {
966 if (m_genericImpl)
967 return m_genericImpl->SetItemPosition(item, pos);
968
969 return false;
970 }
971
972 // Gets the number of items in the list control
973 int wxListCtrl::GetItemCount() const
974 {
975 if (m_genericImpl)
976 return m_genericImpl->GetItemCount();
977
978 if (m_dbImpl)
979 return m_dbImpl->MacGetCount();
980
981 return m_count;
982 }
983
984 void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
985 {
986 if (m_genericImpl)
987 m_genericImpl->SetItemSpacing(spacing, isSmall);
988 }
989
990 wxSize wxListCtrl::GetItemSpacing() const
991 {
992 if (m_genericImpl)
993 return m_genericImpl->GetItemSpacing();
994
995 return wxSize(0, 0);
996 }
997
998 void wxListCtrl::SetItemTextColour( long item, const wxColour &col )
999 {
1000 if (m_genericImpl)
1001 {
1002 m_genericImpl->SetItemTextColour(item, col);
1003 return;
1004 }
1005
1006 wxListItem info;
1007 info.m_itemId = item;
1008 info.SetTextColour( col );
1009 SetItem( info );
1010 }
1011
1012 wxColour wxListCtrl::GetItemTextColour( long item ) const
1013 {
1014 if (m_genericImpl)
1015 return m_genericImpl->GetItemTextColour(item);
1016
1017 if (m_dbImpl)
1018 {
1019 wxListItem info;
1020 if (GetItem(info))
1021 return info.GetTextColour();
1022 }
1023 return wxNullColour;
1024 }
1025
1026 void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
1027 {
1028 if (m_genericImpl)
1029 {
1030 m_genericImpl->SetItemBackgroundColour(item, col);
1031 return;
1032 }
1033
1034 wxListItem info;
1035 info.m_itemId = item;
1036 info.SetBackgroundColour( col );
1037 SetItem( info );
1038 }
1039
1040 wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
1041 {
1042 if (m_genericImpl)
1043 return m_genericImpl->GetItemBackgroundColour(item);
1044
1045 if (m_dbImpl)
1046 {
1047 wxListItem info;
1048 if (GetItem(info))
1049 return info.GetBackgroundColour();
1050 }
1051 return wxNullColour;
1052 }
1053
1054 void wxListCtrl::SetItemFont( long item, const wxFont &f )
1055 {
1056 if (m_genericImpl)
1057 {
1058 m_genericImpl->SetItemFont(item, f);
1059 return;
1060 }
1061
1062 wxListItem info;
1063 info.m_itemId = item;
1064 info.SetFont( f );
1065 SetItem( info );
1066 }
1067
1068 wxFont wxListCtrl::GetItemFont( long item ) const
1069 {
1070 if (m_genericImpl)
1071 return m_genericImpl->GetItemFont(item);
1072
1073 if (m_dbImpl)
1074 {
1075 wxListItem info;
1076 if (GetItem(info))
1077 return info.GetFont();
1078 }
1079
1080 return wxNullFont;
1081 }
1082
1083 // Gets the number of selected items in the list control
1084 int wxListCtrl::GetSelectedItemCount() const
1085 {
1086 if (m_genericImpl)
1087 return m_genericImpl->GetSelectedItemCount();
1088
1089 if (m_dbImpl)
1090 return m_dbImpl->GetSelectedItemCount(NULL, true);
1091
1092 return 0;
1093 }
1094
1095 // Gets the text colour of the listview
1096 wxColour wxListCtrl::GetTextColour() const
1097 {
1098 if (m_genericImpl)
1099 return m_genericImpl->GetTextColour();
1100
1101 // TODO: we need owner drawn list items to customize text color.
1102 if (m_dbImpl)
1103 return m_textColor;
1104
1105 return wxNullColour;
1106 }
1107
1108 // Sets the text colour of the listview
1109 void wxListCtrl::SetTextColour(const wxColour& col)
1110 {
1111 if (m_genericImpl)
1112 {
1113 m_genericImpl->SetTextColour(col);
1114 return;
1115 }
1116
1117 if (m_dbImpl)
1118 m_textColor = col;
1119 }
1120
1121 // Gets the index of the topmost visible item when in
1122 // list or report view
1123 long wxListCtrl::GetTopItem() const
1124 {
1125 if (m_genericImpl)
1126 return m_genericImpl->GetTopItem();
1127
1128 return 0;
1129 }
1130
1131 // Searches for an item, starting from 'item'.
1132 // 'geometry' is one of
1133 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1134 // 'state' is a state bit flag, one or more of
1135 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1136 // item can be -1 to find the first item that matches the
1137 // specified flags.
1138 // Returns the item or -1 if unsuccessful.
1139 long wxListCtrl::GetNextItem(long item, int geom, int state) const
1140 {
1141 if (m_genericImpl)
1142 return m_genericImpl->GetNextItem(item, geom, state);
1143
1144 if (m_dbImpl && geom == wxLIST_NEXT_ALL && state == wxLIST_STATE_SELECTED )
1145 {
1146 long count = m_dbImpl->MacGetCount() ;
1147 for ( long line = item + 1 ; line < count; line++ )
1148 {
1149 wxMacDataItem* id = m_dbImpl->GetItemFromLine(line);
1150 if ( m_dbImpl->IsItemSelected(id ) )
1151 return line;
1152 }
1153 return -1;
1154 }
1155
1156 return 0;
1157 }
1158
1159
1160 wxImageList *wxListCtrl::GetImageList(int which) const
1161 {
1162 if (m_genericImpl)
1163 return m_genericImpl->GetImageList(which);
1164
1165 if ( which == wxIMAGE_LIST_NORMAL )
1166 {
1167 return m_imageListNormal;
1168 }
1169 else if ( which == wxIMAGE_LIST_SMALL )
1170 {
1171 return m_imageListSmall;
1172 }
1173 else if ( which == wxIMAGE_LIST_STATE )
1174 {
1175 return m_imageListState;
1176 }
1177 return NULL;
1178 }
1179
1180 void wxListCtrl::SetImageList(wxImageList *imageList, int which)
1181 {
1182 if (m_genericImpl)
1183 {
1184 m_genericImpl->SetImageList(imageList, which);
1185 return;
1186 }
1187
1188 if ( which == wxIMAGE_LIST_NORMAL )
1189 {
1190 if (m_ownsImageListNormal) delete m_imageListNormal;
1191 m_imageListNormal = imageList;
1192 m_ownsImageListNormal = false;
1193 }
1194 else if ( which == wxIMAGE_LIST_SMALL )
1195 {
1196 if (m_ownsImageListSmall) delete m_imageListSmall;
1197 m_imageListSmall = imageList;
1198 m_ownsImageListSmall = false;
1199 }
1200 else if ( which == wxIMAGE_LIST_STATE )
1201 {
1202 if (m_ownsImageListState) delete m_imageListState;
1203 m_imageListState = imageList;
1204 m_ownsImageListState = false;
1205 }
1206 }
1207
1208 void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
1209 {
1210 if (m_genericImpl)
1211 {
1212 m_genericImpl->AssignImageList(imageList, which);
1213 return;
1214 }
1215
1216 SetImageList(imageList, which);
1217 if ( which == wxIMAGE_LIST_NORMAL )
1218 m_ownsImageListNormal = true;
1219 else if ( which == wxIMAGE_LIST_SMALL )
1220 m_ownsImageListSmall = true;
1221 else if ( which == wxIMAGE_LIST_STATE )
1222 m_ownsImageListState = true;
1223 }
1224
1225 // ----------------------------------------------------------------------------
1226 // Operations
1227 // ----------------------------------------------------------------------------
1228
1229 // Arranges the items
1230 bool wxListCtrl::Arrange(int flag)
1231 {
1232 if (m_genericImpl)
1233 return m_genericImpl->Arrange(flag);
1234 return false;
1235 }
1236
1237 // Deletes an item
1238 bool wxListCtrl::DeleteItem(long item)
1239 {
1240 if (m_genericImpl)
1241 return m_genericImpl->DeleteItem(item);
1242
1243 if (m_dbImpl)
1244 {
1245 m_dbImpl->MacDelete(item);
1246 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ITEM, GetId() );
1247 event.SetEventObject( this );
1248 event.m_itemIndex = item;
1249 GetEventHandler()->ProcessEvent( event );
1250
1251 }
1252 return true;
1253 }
1254
1255 // Deletes all items
1256 bool wxListCtrl::DeleteAllItems()
1257 {
1258 if (m_genericImpl)
1259 return m_genericImpl->DeleteAllItems();
1260
1261 if (m_dbImpl)
1262 {
1263 m_dbImpl->MacClear();
1264 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetId() );
1265 event.SetEventObject( this );
1266 GetEventHandler()->ProcessEvent( event );
1267 }
1268 return true;
1269 }
1270
1271 // Deletes all items
1272 bool wxListCtrl::DeleteAllColumns()
1273 {
1274 if (m_genericImpl)
1275 return m_genericImpl->DeleteAllColumns();
1276
1277 if (m_dbImpl)
1278 {
1279 UInt32 cols;
1280 m_dbImpl->GetColumnCount(&cols);
1281 for (UInt32 col = 0; col < cols; col++)
1282 {
1283 DeleteColumn(col);
1284 }
1285 }
1286
1287 return true;
1288 }
1289
1290 // Deletes a column
1291 bool wxListCtrl::DeleteColumn(int col)
1292 {
1293 if (m_genericImpl)
1294 return m_genericImpl->DeleteColumn(col);
1295
1296 if (m_dbImpl)
1297 {
1298 OSStatus err = m_dbImpl->RemoveColumn(col);
1299 return err == noErr;
1300 }
1301
1302 return true;
1303 }
1304
1305 // Clears items, and columns if there are any.
1306 void wxListCtrl::ClearAll()
1307 {
1308 if (m_genericImpl)
1309 {
1310 m_genericImpl->ClearAll();
1311 return;
1312 }
1313
1314 if (m_dbImpl)
1315 {
1316 DeleteAllItems();
1317 DeleteAllColumns();
1318 }
1319 }
1320
1321 wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
1322 {
1323 if (m_genericImpl)
1324 return m_genericImpl->EditLabel(item, textControlClass);
1325
1326 if (m_dbImpl)
1327 {
1328 wxMacDataItem* id = m_dbImpl->GetItemFromLine(item);
1329 verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), (DataBrowserItemID)id, kMinColumnId) );
1330 }
1331 return NULL;
1332 }
1333
1334 // End label editing, optionally cancelling the edit
1335 bool wxListCtrl::EndEditLabel(bool cancel)
1336 {
1337 // TODO: generic impl. doesn't have this method - is it needed for us?
1338 if (m_genericImpl)
1339 return true; // m_genericImpl->EndEditLabel(cancel);
1340
1341 if (m_dbImpl)
1342 verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), kDataBrowserNoItem, kMinColumnId) );
1343 return true;
1344 }
1345
1346 // Ensures this item is visible
1347 bool wxListCtrl::EnsureVisible(long item)
1348 {
1349 if (m_genericImpl)
1350 return m_genericImpl->EnsureVisible(item);
1351
1352 if (m_dbImpl)
1353 {
1354 wxMacDataItem* dataItem = m_dbImpl->GetItemFromLine(item);
1355 m_dbImpl->RevealItem(dataItem, kDataBrowserRevealWithoutSelecting);
1356 }
1357
1358 return true;
1359 }
1360
1361 // Find an item whose label matches this string, starting from the item after 'start'
1362 // or the beginning if 'start' is -1.
1363 long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
1364 {
1365 if (m_genericImpl)
1366 return m_genericImpl->FindItem(start, str, partial);
1367
1368 return -1;
1369 }
1370
1371 // Find an item whose data matches this data, starting from the item after 'start'
1372 // or the beginning if 'start' is -1.
1373 long wxListCtrl::FindItem(long start, long data)
1374 {
1375 if (m_genericImpl)
1376 return m_genericImpl->FindItem(start, data);
1377
1378 long idx = start + 1;
1379 long count = GetItemCount();
1380
1381 while (idx < count)
1382 {
1383 if (GetItemData(idx) == data)
1384 return idx;
1385 idx++;
1386 };
1387
1388 return -1;
1389 }
1390
1391 // Find an item nearest this position in the specified direction, starting from
1392 // the item after 'start' or the beginning if 'start' is -1.
1393 long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
1394 {
1395 if (m_genericImpl)
1396 return m_genericImpl->FindItem(start, pt, direction);
1397 return -1;
1398 }
1399
1400 // Determines which item (if any) is at the specified point,
1401 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1402 long
1403 wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const
1404 {
1405 if (m_genericImpl)
1406 return m_genericImpl->HitTest(point, flags, ptrSubItem);
1407
1408 flags = wxLIST_HITTEST_NOWHERE;
1409 if (m_dbImpl)
1410 {
1411 int colHeaderHeight = 22; // TODO: Find a way to get this value from the db control?
1412 UInt16 rowHeight = 0;
1413 m_dbImpl->GetDefaultRowHeight(&rowHeight);
1414
1415 int y = point.y;
1416 if ( !(GetWindowStyleFlag() & wxLC_NO_HEADER) )
1417 y -= colHeaderHeight;
1418
1419 int row = y / rowHeight;
1420 DataBrowserItemID id;
1421 m_dbImpl->GetItemID( (DataBrowserTableViewRowIndex) row, &id );
1422
1423 // TODO: Use GetDataBrowserItemPartBounds to return if we are in icon or label
1424 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL ) )
1425 {
1426 wxMacListCtrlItem* lcItem;
1427 lcItem = (wxMacListCtrlItem*) id;
1428 if (lcItem)
1429 {
1430 flags = wxLIST_HITTEST_ONITEM;
1431 return row;
1432 }
1433 }
1434 else
1435 {
1436 if (row < GetItemCount() )
1437 {
1438 flags = wxLIST_HITTEST_ONITEM;
1439 return row;
1440 }
1441 }
1442
1443 }
1444 return -1;
1445 }
1446
1447
1448 // Inserts an item, returning the index of the new item if successful,
1449 // -1 otherwise.
1450 long wxListCtrl::InsertItem(wxListItem& info)
1451 {
1452 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
1453
1454 if (m_genericImpl)
1455 return m_genericImpl->InsertItem(info);
1456
1457 if (m_dbImpl)
1458 {
1459 int count = GetItemCount();
1460
1461 if (info.m_itemId > count)
1462 info.m_itemId = count;
1463
1464 m_dbImpl->MacInsertItem(info.m_itemId, &info );
1465 wxListEvent event( wxEVT_COMMAND_LIST_INSERT_ITEM, GetId() );
1466 event.SetEventObject( this );
1467 event.m_itemIndex = info.m_itemId;
1468 GetEventHandler()->ProcessEvent( event );
1469 }
1470
1471 return info.m_itemId;
1472 }
1473
1474 long wxListCtrl::InsertItem(long index, const wxString& label)
1475 {
1476 if (m_genericImpl)
1477 return m_genericImpl->InsertItem(index, label);
1478
1479 wxListItem info;
1480 info.m_text = label;
1481 info.m_mask = wxLIST_MASK_TEXT;
1482 info.m_itemId = index;
1483 return InsertItem(info);
1484 }
1485
1486 // Inserts an image item
1487 long wxListCtrl::InsertItem(long index, int imageIndex)
1488 {
1489 if (m_genericImpl)
1490 return m_genericImpl->InsertItem(index, imageIndex);
1491
1492 wxListItem info;
1493 info.m_image = imageIndex;
1494 info.m_mask = wxLIST_MASK_IMAGE;
1495 info.m_itemId = index;
1496 return InsertItem(info);
1497 }
1498
1499 // Inserts an image/string item
1500 long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
1501 {
1502 if (m_genericImpl)
1503 return m_genericImpl->InsertItem(index, label, imageIndex);
1504
1505 wxListItem info;
1506 info.m_image = imageIndex;
1507 info.m_text = label;
1508 info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
1509 info.m_itemId = index;
1510 return InsertItem(info);
1511 }
1512
1513 // For list view mode (only), inserts a column.
1514 long wxListCtrl::InsertColumn(long col, wxListItem& item)
1515 {
1516 if (m_genericImpl)
1517 return m_genericImpl->InsertColumn(col, item);
1518
1519 if (m_dbImpl)
1520 {
1521 int width = item.GetWidth();
1522 if ( !(item.GetMask() & wxLIST_MASK_WIDTH) )
1523 width = 150;
1524
1525 DataBrowserPropertyType type = kDataBrowserCustomType; //kDataBrowserTextType;
1526 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
1527 if (imageList && imageList->GetImageCount() > 0)
1528 {
1529 wxBitmap bmp = imageList->GetBitmap(0);
1530 //if (bmp.Ok())
1531 // type = kDataBrowserIconAndTextType;
1532 }
1533
1534 SInt16 just = teFlushDefault;
1535 if (item.GetMask() & wxLIST_MASK_FORMAT)
1536 {
1537 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
1538 just = teFlushLeft;
1539 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
1540 just = teCenter;
1541 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
1542 just = teFlushRight;
1543 }
1544 m_dbImpl->InsertColumn(col, type, item.GetText(), just, width);
1545 SetColumn(col, item);
1546
1547 // set/remove options based on the wxListCtrl type.
1548 DataBrowserTableViewColumnID id;
1549 m_dbImpl->GetColumnIDFromIndex(col, &id);
1550 DataBrowserPropertyFlags flags;
1551 verify_noerr(m_dbImpl->GetPropertyFlags(id, &flags));
1552 if (GetWindowStyleFlag() & wxLC_EDIT_LABELS)
1553 flags |= kDataBrowserPropertyIsEditable;
1554
1555 if (GetWindowStyleFlag() & wxLC_VIRTUAL){
1556 flags &= ~kDataBrowserListViewSortableColumn;
1557 }
1558 verify_noerr(m_dbImpl->SetPropertyFlags(id, flags));
1559 }
1560
1561 return col;
1562 }
1563
1564 long wxListCtrl::InsertColumn(long col,
1565 const wxString& heading,
1566 int format,
1567 int width)
1568 {
1569 if (m_genericImpl)
1570 return m_genericImpl->InsertColumn(col, heading, format, width);
1571
1572 wxListItem item;
1573 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
1574 item.m_text = heading;
1575 if ( width > -1 )
1576 {
1577 item.m_mask |= wxLIST_MASK_WIDTH;
1578 item.m_width = width;
1579 }
1580 item.m_format = format;
1581
1582 return InsertColumn(col, item);
1583 }
1584
1585 // scroll the control by the given number of pixels (exception: in list view,
1586 // dx is interpreted as number of columns)
1587 bool wxListCtrl::ScrollList(int dx, int dy)
1588 {
1589 if (m_genericImpl)
1590 return m_genericImpl->ScrollList(dx, dy);
1591
1592 if (m_dbImpl)
1593 {
1594 m_dbImpl->SetScrollPosition(dx, dy);
1595 }
1596 return true;
1597 }
1598
1599
1600 bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
1601 {
1602 if (m_genericImpl)
1603 return m_genericImpl->SortItems(fn, data);
1604
1605 if (m_dbImpl)
1606 {
1607 m_compareFunc = fn;
1608 m_compareFuncData = data;
1609 }
1610
1611 return true;
1612 }
1613
1614 // ----------------------------------------------------------------------------
1615 // virtual list controls
1616 // ----------------------------------------------------------------------------
1617
1618 wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
1619 {
1620 // this is a pure virtual function, in fact - which is not really pure
1621 // because the controls which are not virtual don't need to implement it
1622 wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") );
1623
1624 return wxEmptyString;
1625 }
1626
1627 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
1628 {
1629 wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
1630 -1,
1631 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
1632 return -1;
1633 }
1634
1635 int wxListCtrl::OnGetItemColumnImage(long item, long column) const
1636 {
1637 if (!column)
1638 return OnGetItemImage(item);
1639
1640 return -1;
1641 }
1642
1643 wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
1644 {
1645 wxASSERT_MSG( item >= 0 && item < GetItemCount(),
1646 _T("invalid item index in OnGetItemAttr()") );
1647
1648 // no attributes by default
1649 return NULL;
1650 }
1651
1652 void wxListCtrl::SetItemCount(long count)
1653 {
1654 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
1655
1656 if (m_genericImpl)
1657 {
1658 m_genericImpl->SetItemCount(count);
1659 return;
1660 }
1661
1662 if (m_dbImpl)
1663 {
1664 // we need to temporarily disable the new item creation notification
1665 // procedure to speed things up
1666 // FIXME: Even this doesn't seem to help much...
1667 DataBrowserCallbacks callbacks;
1668 DataBrowserItemNotificationUPP itemUPP;
1669 GetDataBrowserCallbacks(m_dbImpl->GetControlRef(), &callbacks);
1670 itemUPP = callbacks.u.v1.itemNotificationCallback;
1671 callbacks.u.v1.itemNotificationCallback = 0;
1672 m_dbImpl->SetCallbacks(&callbacks);
1673 ::AddDataBrowserItems(m_dbImpl->GetControlRef(), kDataBrowserNoItem,
1674 count, NULL, kDataBrowserItemNoProperty);
1675 callbacks.u.v1.itemNotificationCallback = itemUPP;
1676 m_dbImpl->SetCallbacks(&callbacks);
1677 }
1678 m_count = count;
1679 }
1680
1681 void wxListCtrl::RefreshItem(long item)
1682 {
1683 if (m_genericImpl)
1684 {
1685 m_genericImpl->RefreshItem(item);
1686 return;
1687 }
1688
1689 wxRect rect;
1690 GetItemRect(item, rect);
1691 RefreshRect(rect);
1692 }
1693
1694 void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
1695 {
1696 if (m_genericImpl)
1697 {
1698 m_genericImpl->RefreshItems(itemFrom, itemTo);
1699 return;
1700 }
1701
1702 wxRect rect1, rect2;
1703 GetItemRect(itemFrom, rect1);
1704 GetItemRect(itemTo, rect2);
1705
1706 wxRect rect = rect1;
1707 rect.height = rect2.GetBottom() - rect1.GetTop();
1708
1709 RefreshRect(rect);
1710 }
1711
1712
1713 // wxMac internal data structures
1714
1715 wxMacListCtrlItem::~wxMacListCtrlItem()
1716 {
1717 }
1718
1719 void wxMacListCtrlItem::Notification(wxMacDataItemBrowserControl *owner ,
1720 DataBrowserItemNotification message,
1721 DataBrowserItemDataRef itemData ) const
1722 {
1723
1724 wxMacDataBrowserListCtrlControl *lb = dynamic_cast<wxMacDataBrowserListCtrlControl*>(owner);
1725
1726 // we want to depend on as little as possible to make sure tear-down of controls is safe
1727 if ( message == kDataBrowserItemRemoved)
1728 {
1729 if ( lb != NULL && lb->GetClientDataType() == wxClientData_Object )
1730 {
1731 delete (wxClientData*) (m_data);
1732 }
1733
1734 delete this;
1735 return;
1736 }
1737 else if ( message == kDataBrowserItemAdded )
1738 {
1739 // we don't issue events on adding, the item is not really stored in the list yet, so we
1740 // avoid asserts by gettting out now
1741 return ;
1742 }
1743
1744 wxListCtrl *list = wxDynamicCast( owner->GetPeer() , wxListCtrl );
1745 if ( list )
1746 {
1747 bool trigger = false;
1748
1749 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
1750 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
1751
1752 event.SetEventObject( list );
1753 event.m_itemIndex = owner->GetLineFromItem( this ) ;
1754 if ( !list->IsVirtual() )
1755 {
1756 lb->MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
1757 }
1758
1759 switch (message)
1760 {
1761 case kDataBrowserItemDeselected:
1762 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
1763 if ( !isSingle )
1764 trigger = !lb->IsSelectionSuppressed();
1765 break;
1766
1767 case kDataBrowserItemSelected:
1768 trigger = !lb->IsSelectionSuppressed();
1769 break;
1770
1771 case kDataBrowserItemDoubleClicked:
1772 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
1773 trigger = true;
1774 break;
1775
1776 case kDataBrowserEditStarted :
1777 // TODO : how to veto ?
1778 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
1779 trigger = true ;
1780 break ;
1781
1782 case kDataBrowserEditStopped :
1783 // TODO probably trigger only upon the value store callback, because
1784 // here IIRC we cannot veto
1785 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
1786 trigger = true ;
1787 break ;
1788
1789 default:
1790 break;
1791 }
1792
1793 if ( trigger )
1794 {
1795 // direct notification is not always having the listbox GetSelection() having in synch with event
1796 wxPostEvent( list->GetEventHandler(), event );
1797 }
1798 }
1799
1800 }
1801
1802 wxMacDataBrowserListCtrlControl::wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style)
1803 : wxMacDataItemBrowserControl( peer, pos, size, style )
1804 {
1805 OSStatus err = noErr;
1806 m_clientDataItemsType = wxClientData_None;
1807 m_isVirtual = false;
1808
1809 if ( style & wxLC_VIRTUAL )
1810 m_isVirtual = true;
1811
1812 DataBrowserSelectionFlags options = kDataBrowserDragSelect;
1813 if ( style & wxLC_SINGLE_SEL )
1814 {
1815 options |= kDataBrowserSelectOnlyOne;
1816 }
1817 else
1818 {
1819 options |= kDataBrowserCmdTogglesSelection;
1820 }
1821
1822 err = SetSelectionFlags( options );
1823 verify_noerr( err );
1824
1825 DataBrowserCustomCallbacks callbacks;
1826 InitializeDataBrowserCustomCallbacks( &callbacks, kDataBrowserLatestCustomCallbacks );
1827
1828 if ( gDataBrowserDrawItemUPP == NULL )
1829 gDataBrowserDrawItemUPP = NewDataBrowserDrawItemUPP(DataBrowserDrawItemProc);
1830
1831 // if ( gDataBrowserEditItemUPP == NULL )
1832 // gDataBrowserEditItemUPP = NewDataBrowserEditItemUPP(DataBrowserEditTextProc);
1833
1834 if ( gDataBrowserHitTestUPP == NULL )
1835 gDataBrowserHitTestUPP = NewDataBrowserHitTestUPP(DataBrowserHitTestProc);
1836
1837 callbacks.u.v1.drawItemCallback = gDataBrowserDrawItemUPP;
1838 // callbacks.u.v1.editTextCallback = gDataBrowserEditItemUPP;
1839 callbacks.u.v1.hitTestCallback = gDataBrowserHitTestUPP;
1840
1841 SetDataBrowserCustomCallbacks( GetControlRef(), &callbacks );
1842
1843 if ( style & wxLC_LIST )
1844 {
1845 InsertColumn(0, kDataBrowserIconAndTextType, wxEmptyString, -1, -1);
1846 verify_noerr( AutoSizeColumns() );
1847 }
1848
1849 if ( style & wxLC_LIST || style & wxLC_NO_HEADER )
1850 verify_noerr( SetHeaderButtonHeight( 0 ) );
1851
1852 if ( m_isVirtual )
1853 SetSortProperty( kMinColumnId - 1 );
1854 else
1855 SetSortProperty( kMinColumnId );
1856 if ( style & wxLC_SORT_ASCENDING )
1857 {
1858 m_sortOrder = SortOrder_Text_Ascending;
1859 SetSortOrder( kDataBrowserOrderIncreasing );
1860 }
1861 else if ( style & wxLC_SORT_DESCENDING )
1862 {
1863 m_sortOrder = SortOrder_Text_Descending;
1864 SetSortOrder( kDataBrowserOrderDecreasing );
1865 }
1866 else
1867 {
1868 m_sortOrder = SortOrder_None;
1869 }
1870
1871 if ( style & wxLC_VRULES )
1872 {
1873 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1874 verify_noerr( DataBrowserChangeAttributes(m_controlRef, kDataBrowserAttributeListViewDrawColumnDividers, kDataBrowserAttributeNone) );
1875 #endif
1876 }
1877
1878 verify_noerr( SetHiliteStyle(kDataBrowserTableViewFillHilite ) );
1879 err = SetHasScrollBars( (style & wxHSCROLL) != 0 , true );
1880 }
1881
1882 pascal Boolean wxMacDataBrowserListCtrlControl::DataBrowserEditTextProc(
1883 ControlRef browser,
1884 DataBrowserItemID itemID,
1885 DataBrowserPropertyID property,
1886 CFStringRef theString,
1887 Rect *maxEditTextRect,
1888 Boolean *shrinkToFit)
1889 {
1890 Boolean result = false;
1891 wxMacDataBrowserListCtrlControl* ctl = dynamic_cast<wxMacDataBrowserListCtrlControl*>( wxMacControl::GetReferenceFromNativeControl( browser ) );
1892 if ( ctl != 0 )
1893 {
1894 result = ctl->ConfirmEditText(itemID, property, theString, maxEditTextRect, shrinkToFit);
1895 theString = CFSTR("Hello!");
1896 }
1897 return result;
1898 }
1899
1900 bool wxMacDataBrowserListCtrlControl::ConfirmEditText(
1901 DataBrowserItemID itemID,
1902 DataBrowserPropertyID property,
1903 CFStringRef theString,
1904 Rect *maxEditTextRect,
1905 Boolean *shrinkToFit)
1906 {
1907 //wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
1908 return false;
1909 }
1910
1911 pascal void wxMacDataBrowserListCtrlControl::DataBrowserDrawItemProc(
1912 ControlRef browser,
1913 DataBrowserItemID itemID,
1914 DataBrowserPropertyID property,
1915 DataBrowserItemState itemState,
1916 const Rect *itemRect,
1917 SInt16 gdDepth,
1918 Boolean colorDevice)
1919 {
1920 wxMacDataBrowserListCtrlControl* ctl = dynamic_cast<wxMacDataBrowserListCtrlControl*>( wxMacControl::GetReferenceFromNativeControl( browser ) );
1921 if ( ctl != 0 )
1922 {
1923 ctl->DrawItem(itemID, property, itemState, itemRect, gdDepth, colorDevice);
1924 }
1925 }
1926
1927 // routines needed for DrawItem
1928 enum
1929 {
1930 kIconWidth = 16,
1931 kIconHeight = 16,
1932 kTextBoxHeight = 14,
1933 kIconTextSpacingV = 2,
1934 kItemPadding = 4,
1935 kContentHeight = kIconHeight + kTextBoxHeight + kIconTextSpacingV
1936 };
1937
1938 static void calculateCGDrawingBounds(CGRect inItemRect, CGRect *outIconRect, CGRect *outTextRect, bool hasIcon = false)
1939 {
1940 float textBottom;
1941 float iconH, iconW = 0;
1942 float padding = kItemPadding;
1943 if (hasIcon)
1944 {
1945 iconH = kIconHeight;
1946 iconW = kIconWidth;
1947 padding = padding*2;
1948 }
1949
1950 textBottom = inItemRect.origin.y;
1951
1952 *outIconRect = CGRectMake(inItemRect.origin.x + kItemPadding,
1953 textBottom + kIconTextSpacingV, kIconWidth,
1954 kIconHeight);
1955
1956 *outTextRect = CGRectMake(inItemRect.origin.x + padding + iconW,
1957 textBottom + kIconTextSpacingV, inItemRect.size.width - padding - iconW,
1958 inItemRect.size.height - kIconTextSpacingV);
1959 }
1960
1961 void wxMacDataBrowserListCtrlControl::DrawItem(
1962 DataBrowserItemID itemID,
1963 DataBrowserPropertyID property,
1964 DataBrowserItemState itemState,
1965 const Rect *itemRect,
1966 SInt16 gdDepth,
1967 Boolean colorDevice)
1968 {
1969 wxString text;
1970 wxFont font = wxNullFont;
1971 int imgIndex = -1;
1972 short listColumn = property - kMinColumnId;
1973
1974 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
1975 wxMacListCtrlItem* lcItem;
1976 wxColour color = *wxBLACK;
1977 wxColour bgColor = wxNullColour;
1978
1979 if (listColumn >= 0)
1980 {
1981 if (!m_isVirtual)
1982 {
1983 lcItem = (wxMacListCtrlItem*) itemID;
1984 if (lcItem->HasColumnInfo(listColumn)){
1985 wxListItem* item = lcItem->GetColumnInfo(listColumn);
1986
1987 // we always use the 0 column to get font and text/background colors.
1988 if (lcItem->HasColumnInfo(0))
1989 {
1990 wxListItem* firstItem = lcItem->GetColumnInfo(0);
1991 color = firstItem->GetTextColour();
1992 bgColor = firstItem->GetBackgroundColour();
1993 font = firstItem->GetFont();
1994 }
1995
1996 if (item->GetMask() & wxLIST_MASK_TEXT)
1997 text = item->GetText();
1998 if (item->GetMask() & wxLIST_MASK_IMAGE)
1999 imgIndex = item->GetImage();
2000 }
2001
2002 }
2003 else
2004 {
2005 text = list->OnGetItemText( (long)itemID-1, listColumn );
2006 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2007 wxListItemAttr* attrs = list->OnGetItemAttr( (long)itemID-1 );
2008 if (attrs)
2009 {
2010 if (attrs->HasBackgroundColour())
2011 bgColor = attrs->GetBackgroundColour();
2012 if (attrs->HasTextColour())
2013 color = attrs->GetTextColour();
2014 if (attrs->HasFont())
2015 font = attrs->GetFont();
2016 }
2017 }
2018 }
2019
2020 wxColour listBgColor = list->GetBackgroundColour();
2021 if (bgColor == wxNullColour)
2022 bgColor = listBgColor;
2023
2024 wxFont listFont = list->GetFont();
2025 if (font == wxNullFont)
2026 font = listFont;
2027
2028 wxMacCFStringHolder cfString;
2029 cfString.Assign( text, wxLocale::GetSystemEncoding() );
2030
2031 Rect enclosingRect;
2032 CGRect enclosingCGRect, iconCGRect, textCGRect;
2033 Boolean active;
2034 ThemeDrawingState savedState = NULL;
2035 CGContextRef context = (CGContextRef)list->MacGetDrawingContext();
2036 RGBColor labelColor;
2037
2038 GetDataBrowserItemPartBounds(GetControlRef(), itemID, property, kDataBrowserPropertyEnclosingPart,
2039 &enclosingRect);
2040
2041 enclosingCGRect = CGRectMake(enclosingRect.left,
2042 enclosingRect.top,
2043 enclosingRect.right - enclosingRect.left,
2044 enclosingRect.bottom - enclosingRect.top);
2045
2046 active = IsControlActive(GetControlRef());
2047
2048 if (itemState == kDataBrowserItemIsSelected)
2049 {
2050 RGBColor foregroundColor;
2051
2052 GetThemeDrawingState(&savedState);
2053
2054 GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &foregroundColor);
2055 GetThemeTextColor(kThemeTextColorWhite, gdDepth, colorDevice, &labelColor);
2056
2057 CGContextSaveGState(context);
2058
2059 CGContextSetRGBFillColor(context, (float)foregroundColor.red / (float)USHRT_MAX,
2060 (float)foregroundColor.green / (float)USHRT_MAX,
2061 (float)foregroundColor.blue / (float)USHRT_MAX, 1.0);
2062 CGContextFillRect(context, enclosingCGRect);
2063
2064 CGContextRestoreGState(context);
2065 }
2066 else
2067 {
2068
2069 if (color.Ok())
2070 labelColor = MAC_WXCOLORREF( color.GetPixel() );
2071 else if (list->GetTextColour().Ok())
2072 labelColor = MAC_WXCOLORREF( list->GetTextColour().GetPixel() );
2073 else
2074 {
2075 labelColor.red = 0;
2076 labelColor.green = 0;
2077 labelColor.blue = 0;
2078 }
2079
2080 if (bgColor.Ok())
2081 {
2082 RGBColor foregroundColor = MAC_WXCOLORREF( bgColor.GetPixel() );
2083 CGContextSaveGState(context);
2084
2085 CGContextSetRGBFillColor(context, (float)foregroundColor.red / (float)USHRT_MAX,
2086 (float)foregroundColor.green / (float)USHRT_MAX,
2087 (float)foregroundColor.blue / (float)USHRT_MAX, 1.0);
2088 CGContextFillRect(context, enclosingCGRect);
2089
2090 CGContextRestoreGState(context);
2091 }
2092 }
2093
2094 calculateCGDrawingBounds(enclosingCGRect, &iconCGRect, &textCGRect, (imgIndex != -1) );
2095
2096 if (imgIndex != -1)
2097 {
2098 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2099 if (imageList && imageList->GetImageCount() > 0){
2100 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2101 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2102
2103 RGBColor iconLabel;
2104 iconLabel.red = 0;
2105 iconLabel.green = 0;
2106 iconLabel.blue = 0;
2107
2108 CGContextSaveGState(context);
2109 CGContextTranslateCTM(context, 0,iconCGRect.origin.y + CGRectGetMaxY(iconCGRect));
2110 CGContextScaleCTM(context,1.0f,-1.0f);
2111 PlotIconRefInContext(context, &iconCGRect, kAlignNone,
2112 active ? kTransformNone : kTransformDisabled, &iconLabel,
2113 kPlotIconRefNormalFlags, icon);
2114
2115 CGContextRestoreGState(context);
2116 }
2117 }
2118
2119 HIThemeTextHorizontalFlush hFlush = kHIThemeTextHorizontalFlushLeft;
2120 UInt16 fontID = kThemeViewsFont;
2121
2122 if (font.Ok())
2123 {
2124 if (font.GetFamily() != wxFONTFAMILY_DEFAULT)
2125 fontID = font.MacGetThemeFontID();
2126
2127 // FIXME: replace these with CG or ATSUI calls so we can remove this #ifndef.
2128 #ifndef __LP64__
2129 ::TextSize( (short)(font.MacGetFontSize()) ) ;
2130 ::TextFace( font.MacGetFontStyle() ) ;
2131 #endif
2132 }
2133
2134 wxListItem item;
2135 list->GetColumn(listColumn, item);
2136 if (item.GetMask() & wxLIST_MASK_FORMAT)
2137 {
2138 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2139 hFlush = kHIThemeTextHorizontalFlushLeft;
2140 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2141 hFlush = kHIThemeTextHorizontalFlushCenter;
2142 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2143 {
2144 hFlush = kHIThemeTextHorizontalFlushRight;
2145 textCGRect.origin.x -= kItemPadding; // give a little extra paddding
2146 }
2147 }
2148
2149 HIThemeTextInfo info;
2150 info.version = kHIThemeTextInfoVersionZero;
2151 info.state = active ? kThemeStateActive : kThemeStateInactive;
2152 info.fontID = fontID;
2153 info.horizontalFlushness = hFlush;
2154 info.verticalFlushness = kHIThemeTextVerticalFlushCenter;
2155 info.options = kHIThemeTextBoxOptionNone;
2156 info.truncationPosition = kHIThemeTextTruncationEnd;
2157 info.truncationMaxLines = 1;
2158
2159 CGContextSaveGState(context);
2160 CGContextSetRGBFillColor (context, (float)labelColor.red / (float)USHRT_MAX,
2161 (float)labelColor.green / (float)USHRT_MAX,
2162 (float)labelColor.blue / (float)USHRT_MAX, 1.0);
2163
2164 HIThemeDrawTextBox(cfString, &textCGRect, &info, context, kHIThemeOrientationNormal);
2165
2166 CGContextRestoreGState(context);
2167
2168 if (savedState != NULL)
2169 SetThemeDrawingState(savedState, true);
2170 }
2171
2172 OSStatus wxMacDataBrowserListCtrlControl::GetSetItemData(DataBrowserItemID itemID,
2173 DataBrowserPropertyID property,
2174 DataBrowserItemDataRef itemData,
2175 Boolean changeValue )
2176 {
2177 wxString text;
2178 int imgIndex = -1;
2179 short listColumn = property - kMinColumnId;
2180
2181 OSStatus err = errDataBrowserPropertyNotSupported;
2182 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2183 wxMacListCtrlItem* lcItem;
2184
2185 if (listColumn >= 0)
2186 {
2187 if (!m_isVirtual)
2188 {
2189 lcItem = (wxMacListCtrlItem*) itemID;
2190 if (lcItem->HasColumnInfo(listColumn)){
2191 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2192 if (item->GetMask() & wxLIST_MASK_TEXT)
2193 text = item->GetText();
2194 if (item->GetMask() & wxLIST_MASK_IMAGE)
2195 imgIndex = item->GetImage();
2196 }
2197 }
2198 else
2199 {
2200 text = list->OnGetItemText( (long)itemID-1, listColumn );
2201 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2202 }
2203 }
2204
2205 if ( !changeValue )
2206 {
2207 switch (property)
2208 {
2209 case kDataBrowserItemIsEditableProperty :
2210 if ( list && list->HasFlag( wxLC_EDIT_LABELS ) )
2211 {
2212 verify_noerr(SetDataBrowserItemDataBooleanValue( itemData, true ));
2213 err = noErr ;
2214 }
2215 break ;
2216 default :
2217 if ( property >= kMinColumnId )
2218 {
2219 wxMacCFStringHolder cfStr;
2220
2221 if (text){
2222 cfStr.Assign( text, wxLocale::GetSystemEncoding() );
2223 err = ::SetDataBrowserItemDataText( itemData, cfStr );
2224 err = noErr;
2225 }
2226
2227
2228
2229 if ( imgIndex != -1 )
2230 {
2231 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2232 if (imageList && imageList->GetImageCount() > 0){
2233 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2234 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2235 ::SetDataBrowserItemDataIcon(itemData, icon);
2236 }
2237 }
2238
2239 }
2240 break ;
2241 }
2242
2243 }
2244 else
2245 {
2246 switch (property)
2247 {
2248 default:
2249 if ( property >= kMinColumnId )
2250 {
2251 short listColumn = property - kMinColumnId;
2252
2253 // TODO probably send the 'end edit' from here, as we
2254 // can then deal with the veto
2255 CFStringRef sr ;
2256 verify_noerr( GetDataBrowserItemDataText( itemData , &sr ) ) ;
2257 wxMacCFStringHolder cfStr(sr) ;;
2258 if (m_isVirtual)
2259 list->SetItem( (long)itemData-1 , listColumn, cfStr.AsString() ) ;
2260 else
2261 {
2262 if (lcItem)
2263 lcItem->SetColumnTextValue( listColumn, cfStr.AsString() );
2264 }
2265 err = noErr ;
2266 }
2267 break;
2268 }
2269 }
2270 return err;
2271 }
2272
2273 void wxMacDataBrowserListCtrlControl::ItemNotification(DataBrowserItemID itemID,
2274 DataBrowserItemNotification message,
2275 DataBrowserItemDataRef itemData )
2276 {
2277 // we want to depend on as little as possible to make sure tear-down of controls is safe
2278 if ( message == kDataBrowserItemRemoved)
2279 {
2280 // make sure MacDelete does the proper teardown.
2281 return;
2282 }
2283 else if ( message == kDataBrowserItemAdded )
2284 {
2285 // we don't issue events on adding, the item is not really stored in the list yet, so we
2286 // avoid asserts by getting out now
2287 return ;
2288 }
2289
2290 wxListCtrl *list = wxDynamicCast( GetPeer() , wxListCtrl );
2291 if ( list )
2292 {
2293 bool trigger = false;
2294
2295 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
2296 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
2297
2298 event.SetEventObject( list );
2299 if ( !list->IsVirtual() )
2300 {
2301 DataBrowserTableViewRowIndex result = 0;
2302 verify_noerr( GetItemRow( itemID, &result ) ) ;
2303 event.m_itemIndex = result;
2304
2305 if (event.m_itemIndex >= 0)
2306 MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
2307 }
2308 else
2309 {
2310 event.m_itemIndex = (long)itemID;
2311 }
2312
2313 switch (message)
2314 {
2315 case kDataBrowserItemDeselected:
2316 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
2317 if ( !isSingle )
2318 trigger = !IsSelectionSuppressed();
2319 break;
2320
2321 case kDataBrowserItemSelected:
2322 trigger = !IsSelectionSuppressed();
2323
2324 break;
2325
2326 case kDataBrowserItemDoubleClicked:
2327 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
2328 trigger = true;
2329 break;
2330
2331 case kDataBrowserEditStarted :
2332 // TODO : how to veto ?
2333 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
2334 trigger = true ;
2335 break ;
2336
2337 case kDataBrowserEditStopped :
2338 // TODO probably trigger only upon the value store callback, because
2339 // here IIRC we cannot veto
2340 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
2341 trigger = true ;
2342 break ;
2343
2344 default:
2345 break;
2346 }
2347
2348 if ( trigger )
2349 {
2350 // direct notification is not always having the listbox GetSelection() having in synch with event
2351 wxPostEvent( list->GetEventHandler(), event );
2352 }
2353 }
2354 }
2355
2356 Boolean wxMacDataBrowserListCtrlControl::CompareItems(DataBrowserItemID itemOneID,
2357 DataBrowserItemID itemTwoID,
2358 DataBrowserPropertyID sortProperty)
2359 {
2360
2361 bool retval = false;
2362 wxString itemText;
2363 wxString otherItemText;
2364 int colId = sortProperty - kMinColumnId;
2365 long itemNum = 0;
2366 long otherItemNum = 0;
2367
2368 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2369
2370 // means we need to
2371 if (colId >= 0)
2372 {
2373 if (!m_isVirtual)
2374 {
2375 wxMacListCtrlItem* item = (wxMacListCtrlItem*)itemOneID;
2376 wxMacListCtrlItem* otherItem = (wxMacListCtrlItem*)itemTwoID;
2377 wxListCtrlCompare func = list->GetCompareFunc();
2378 if (func != NULL && item->HasColumnInfo(colId) && otherItem->HasColumnInfo(colId))
2379 return func(item->GetColumnInfo(colId)->GetData(), otherItem->GetColumnInfo(colId)->GetData(), list->GetCompareFuncData()) >= 0;
2380
2381 itemNum = item->GetOrder();
2382 otherItemNum = otherItem->GetOrder();
2383 if (item->HasColumnInfo(colId))
2384 itemText = item->GetColumnInfo(colId)->GetText();
2385 if (otherItem->HasColumnInfo(colId))
2386 otherItemText = otherItem->GetColumnInfo(colId)->GetText();
2387 }
2388 else
2389 {
2390 itemNum = (long)itemOneID;
2391 otherItemNum = (long)itemTwoID;
2392 itemText = list->OnGetItemText( itemNum-1, colId );
2393 otherItemText = list->OnGetItemText( otherItemNum-1, colId );
2394
2395 }
2396
2397 DataBrowserSortOrder sort;
2398 verify_noerr(GetSortOrder(&sort));
2399
2400 if ( sort == kDataBrowserOrderIncreasing )
2401 {
2402 retval = itemText.CmpNoCase( otherItemText ) > 0;
2403 }
2404 else if ( sort == kDataBrowserOrderDecreasing )
2405 {
2406 retval = itemText.CmpNoCase( otherItemText ) < 0;
2407 }
2408 }
2409 else{
2410 // fallback for undefined cases
2411 retval = itemOneID < itemTwoID;
2412 }
2413
2414 return retval;
2415 }
2416
2417 wxMacDataBrowserListCtrlControl::~wxMacDataBrowserListCtrlControl()
2418 {
2419 }
2420
2421 void wxMacDataBrowserListCtrlControl::MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item )
2422 {
2423 wxMacDataItem* dataItem = GetItemFromLine(row);
2424 if (item)
2425 {
2426 wxMacListCtrlItem* listItem = dynamic_cast<wxMacListCtrlItem*>(dataItem);
2427 listItem->SetColumnInfo( column, item );
2428 UpdateState(dataItem, item);
2429 }
2430 }
2431
2432 // apply changes that need to happen immediately, rather than when the
2433 // databrowser control fires a callback.
2434 void wxMacDataBrowserListCtrlControl::UpdateState(wxMacDataItem* dataItem, wxListItem* listItem)
2435 {
2436 bool isSelected = IsItemSelected( dataItem );
2437 bool isSelectedState = (listItem->GetState() == wxLIST_STATE_SELECTED);
2438
2439 // toggle the selection state if wxListInfo state and actual state don't match.
2440 if ( isSelected != isSelectedState )
2441 {
2442 DataBrowserSetOption options = kDataBrowserItemsAdd;
2443 if (!isSelectedState)
2444 options = kDataBrowserItemsRemove;
2445 SetSelectedItem(dataItem, options);
2446 }
2447 // TODO: Set column width if item width > than current column width
2448 }
2449
2450 void wxMacDataBrowserListCtrlControl::MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item )
2451 {
2452 wxMacDataItem* dataItem = GetItemFromLine(row);
2453 // CS should this guard against dataItem = 0 ? , as item is not a pointer if (item) is not appropriate
2454 //if (item)
2455 {
2456 wxMacListCtrlItem* listItem = dynamic_cast<wxMacListCtrlItem*>(dataItem);
2457 wxListItem* oldItem = listItem->GetColumnInfo( column );
2458
2459 long mask = item.GetMask();
2460 if ( !mask )
2461 // by default, get everything for backwards compatibility
2462 mask = -1;
2463
2464 if ( mask & wxLIST_MASK_TEXT )
2465 item.SetText(oldItem->GetText());
2466 if ( mask & wxLIST_MASK_IMAGE )
2467 item.SetImage(oldItem->GetImage());
2468 if ( mask & wxLIST_MASK_DATA )
2469 item.SetData(oldItem->GetData());
2470 if ( mask & wxLIST_MASK_STATE )
2471 item.SetState(oldItem->GetState());
2472 if ( mask & wxLIST_MASK_WIDTH )
2473 item.SetWidth(oldItem->GetWidth());
2474 if ( mask & wxLIST_MASK_FORMAT )
2475 item.SetAlign(oldItem->GetAlign());
2476
2477 item.SetTextColour(oldItem->GetTextColour());
2478 item.SetBackgroundColour(oldItem->GetBackgroundColour());
2479 item.SetFont(oldItem->GetFont());
2480 }
2481 }
2482
2483 void wxMacDataBrowserListCtrlControl::MacInsertItem( unsigned int n, wxListItem* item )
2484 {
2485 wxMacDataItemBrowserControl::MacInsert(n, item->GetText());
2486 MacSetColumnInfo(n, 0, item);
2487 }
2488
2489 wxMacDataItem* wxMacDataBrowserListCtrlControl::CreateItem()
2490 {
2491 return new wxMacListCtrlItem();
2492 }
2493
2494 wxMacListCtrlItem::wxMacListCtrlItem()
2495 {
2496 m_rowItems = wxListItemList();
2497 }
2498
2499 int wxMacListCtrlItem::GetColumnImageValue( unsigned int column )
2500 {
2501 return GetColumnInfo(column)->GetImage();
2502 }
2503
2504 void wxMacListCtrlItem::SetColumnImageValue( unsigned int column, int imageIndex )
2505 {
2506 GetColumnInfo(column)->SetImage(imageIndex);
2507 }
2508
2509 const wxString& wxMacListCtrlItem::GetColumnTextValue( unsigned int column )
2510 {
2511 if ( column == 0 )
2512 return GetLabel();
2513
2514 return GetColumnInfo(column)->GetText();
2515 }
2516
2517 void wxMacListCtrlItem::SetColumnTextValue( unsigned int column, const wxString& text )
2518 {
2519 GetColumnInfo(column)->SetText(text);
2520
2521 // for compatibility with superclass APIs
2522 if ( column == 0 )
2523 SetLabel(text);
2524 }
2525
2526 wxListItem* wxMacListCtrlItem::GetColumnInfo( unsigned int column )
2527 {
2528 wxListItemList::compatibility_iterator node = m_rowItems.Item( column );
2529 wxASSERT_MSG( node, _T("invalid column index in wxMacListCtrlItem") );
2530
2531 return node->GetData();
2532 }
2533
2534 bool wxMacListCtrlItem::HasColumnInfo( unsigned int column )
2535 {
2536 return m_rowItems.GetCount() > column;
2537 }
2538
2539 void wxMacListCtrlItem::SetColumnInfo( unsigned int column, wxListItem* item )
2540 {
2541
2542 if ( column >= m_rowItems.GetCount() )
2543 {
2544 wxListItem* listItem = new wxListItem(*item);
2545 m_rowItems.Append( listItem );
2546 }
2547 else
2548 {
2549 wxListItem* listItem = GetColumnInfo( column );
2550 long mask = item->GetMask();
2551 if (mask & wxLIST_MASK_TEXT)
2552 listItem->SetText(item->GetText());
2553 if (mask & wxLIST_MASK_DATA)
2554 listItem->SetData(item->GetData());
2555 if (mask & wxLIST_MASK_IMAGE)
2556 listItem->SetImage(item->GetImage());
2557 if (mask & wxLIST_MASK_STATE)
2558 listItem->SetState(item->GetState());
2559 if (mask & wxLIST_MASK_FORMAT)
2560 listItem->SetAlign(item->GetAlign());
2561 if (mask & wxLIST_MASK_WIDTH)
2562 listItem->SetWidth(item->GetWidth());
2563
2564 listItem->SetTextColour(item->GetTextColour());
2565 listItem->SetBackgroundColour(item->GetBackgroundColour());
2566 listItem->SetFont(item->GetFont());
2567 }
2568 }
2569
2570 #endif // wxUSE_LISTCTRL