]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/listctrl_mac.cpp
Sizing fixes for generic control.
[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 & wxNO_BORDER, 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 wxSize wxListCtrl::DoGetBestSize() const
494 {
495 if (m_genericImpl)
496 return m_genericImpl->GetBestSize();
497
498 return wxWindow::DoGetBestSize();
499 }
500
501 bool wxListCtrl::SetFont(const wxFont& font)
502 {
503 bool rv = true;
504 rv = wxControl::SetFont(font);
505 if (m_genericImpl)
506 rv = m_genericImpl->SetFont(font);
507 return rv;
508 }
509
510 bool wxListCtrl::SetForegroundColour(const wxColour& colour)
511 {
512 bool rv = true;
513 if (m_genericImpl)
514 rv = m_genericImpl->SetForegroundColour(colour);
515 if (m_dbImpl)
516 SetTextColour(colour);
517 return rv;
518 }
519
520 bool wxListCtrl::SetBackgroundColour(const wxColour& colour)
521 {
522 bool rv = true;
523 if (m_genericImpl)
524 rv = m_genericImpl->SetBackgroundColour(colour);
525 if (m_dbImpl)
526 m_bgColor = colour;
527 return rv;
528 }
529
530 wxColour wxListCtrl::GetBackgroundColour()
531 {
532 if (m_genericImpl)
533 return m_genericImpl->GetBackgroundColour();
534 if (m_dbImpl)
535 return m_bgColor;
536
537 return wxNullColour;
538 }
539
540 // ----------------------------------------------------------------------------
541 // accessors
542 // ----------------------------------------------------------------------------
543
544 // Gets information about this column
545 bool wxListCtrl::GetColumn(int col, wxListItem& item) const
546 {
547 if (m_genericImpl)
548 return m_genericImpl->GetColumn(col, item);
549
550 bool success = true;
551
552 if (m_dbImpl)
553 {
554
555 wxColumnList::compatibility_iterator node = m_colsInfo.Item( col );
556 wxASSERT_MSG( node, _T("invalid column index in wxMacListCtrlItem") );
557 wxListItem* column = node->GetData();
558
559 long mask = column->GetMask();
560 if (mask & wxLIST_MASK_TEXT)
561 item.SetText(column->GetText());
562 if (mask & wxLIST_MASK_DATA)
563 item.SetData(column->GetData());
564 if (mask & wxLIST_MASK_IMAGE)
565 item.SetImage(column->GetImage());
566 if (mask & wxLIST_MASK_STATE)
567 item.SetState(column->GetState());
568 if (mask & wxLIST_MASK_FORMAT)
569 item.SetAlign(column->GetAlign());
570 if (mask & wxLIST_MASK_WIDTH)
571 item.SetWidth(column->GetWidth());
572 }
573
574 return success;
575 }
576
577 // Sets information about this column
578 bool wxListCtrl::SetColumn(int col, wxListItem& item)
579 {
580 if (m_genericImpl)
581 return m_genericImpl->SetColumn(col, item);
582
583 if (m_dbImpl)
584 {
585 if ( col >= (int)m_colsInfo.GetCount() )
586 {
587 wxListItem* listItem = new wxListItem(item);
588 m_colsInfo.Append( listItem );
589 }
590 else
591 {
592 wxListItem listItem;
593 GetColumn( col, listItem );
594 long mask = item.GetMask();
595 if (mask & wxLIST_MASK_TEXT)
596 listItem.SetText(item.GetText());
597 if (mask & wxLIST_MASK_DATA)
598 listItem.SetData(item.GetData());
599 if (mask & wxLIST_MASK_IMAGE)
600 listItem.SetImage(item.GetImage());
601 if (mask & wxLIST_MASK_STATE)
602 listItem.SetState(item.GetState());
603 if (mask & wxLIST_MASK_FORMAT)
604 listItem.SetAlign(item.GetAlign());
605 if (mask & wxLIST_MASK_WIDTH)
606 listItem.SetWidth(item.GetWidth());
607 }
608
609 // change the appearance in the databrowser.
610 DataBrowserListViewHeaderDesc columnDesc;
611 columnDesc.version=kDataBrowserListViewLatestHeaderDesc;
612 verify_noerr( m_dbImpl->GetHeaderDesc( kMinColumnId + col, &columnDesc ) );
613
614 /*
615 if (item.GetMask() & wxLIST_MASK_TEXT)
616 {
617 wxFontEncoding enc;
618 if ( m_font.Ok() )
619 enc = m_font.GetEncoding();
620 else
621 enc = wxLocale::GetSystemEncoding();
622 wxMacCFStringHolder cfTitle;
623 cfTitle.Assign( item.GetText() , enc );
624 if(columnDesc.titleString)
625 CFRelease(columnDesc.titleString);
626 columnDesc.titleString = cfTitle;
627 }
628 */
629
630 if (item.GetMask() & wxLIST_MASK_IMAGE && item.GetImage() != -1 )
631 {
632 columnDesc.btnContentInfo.contentType = kControlContentIconRef;
633 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
634 if (imageList && imageList->GetImageCount() > 0 )
635 {
636 wxBitmap bmp = imageList->GetBitmap( item.GetImage() );
637 IconRef icon = bmp.GetBitmapData()->GetIconRef();
638 columnDesc.btnContentInfo.u.iconRef = icon;
639 }
640 }
641
642 verify_noerr( m_dbImpl->SetHeaderDesc( kMinColumnId + col, &columnDesc ) );
643
644 }
645 return true;
646 }
647
648 int wxListCtrl::GetColumnCount() const
649 {
650 if (m_genericImpl)
651 return m_genericImpl->GetColumnCount();
652
653 if (m_dbImpl)
654 {
655 UInt32 count;
656 m_dbImpl->GetColumnCount(&count);
657 return count;
658 }
659
660 return m_colCount;
661 }
662
663 // Gets the column width
664 int wxListCtrl::GetColumnWidth(int col) const
665 {
666 if (m_genericImpl)
667 return m_genericImpl->GetColumnWidth(col);
668
669 if (m_dbImpl)
670 {
671 return m_dbImpl->GetColumnWidth(col);
672 }
673
674 return 0;
675 }
676
677 // Sets the column width
678 bool wxListCtrl::SetColumnWidth(int col, int width)
679 {
680 if (m_genericImpl)
681 return m_genericImpl->SetColumnWidth(col, width);
682
683 if (m_dbImpl)
684 {
685 int mywidth = width;
686 if (width == wxLIST_AUTOSIZE || width == wxLIST_AUTOSIZE_USEHEADER)
687 mywidth = 150;
688
689 if (col == -1)
690 {
691 for (int column = 0; column < GetColumnCount(); column++)
692 {
693 m_dbImpl->SetColumnWidth(col, mywidth);
694 }
695 }
696 else{
697 m_dbImpl->SetColumnWidth(col, mywidth);
698 }
699 return true;
700 }
701
702 return false;
703 }
704
705 // Gets the number of items that can fit vertically in the
706 // visible area of the list control (list or report view)
707 // or the total number of items in the list control (icon
708 // or small icon view)
709 int wxListCtrl::GetCountPerPage() const
710 {
711 if (m_genericImpl)
712 return m_genericImpl->GetCountPerPage();
713
714 if (m_dbImpl)
715 {
716 }
717
718 return 1;
719 }
720
721 // Gets the edit control for editing labels.
722 wxTextCtrl* wxListCtrl::GetEditControl() const
723 {
724 if (m_genericImpl)
725 return m_genericImpl->GetEditControl();
726
727 return NULL;
728 }
729
730 // Gets information about the item
731 bool wxListCtrl::GetItem(wxListItem& info) const
732 {
733 if (m_genericImpl)
734 return m_genericImpl->GetItem(info);
735
736 if (m_dbImpl)
737 {
738 if (!IsVirtual())
739 m_dbImpl->MacGetColumnInfo(info.m_itemId, info.m_col, info);
740 else
741 {
742 info.SetText( OnGetItemText(info.m_itemId, info.m_col) );
743 info.SetImage( OnGetItemColumnImage(info.m_itemId, info.m_col) );
744 wxListItemAttr* attrs = OnGetItemAttr( info.m_itemId );
745 if (attrs)
746 {
747 info.SetFont( attrs->GetFont() );
748 info.SetBackgroundColour( attrs->GetBackgroundColour() );
749 info.SetTextColour( attrs->GetTextColour() );
750 }
751 }
752 }
753 bool success = true;
754 return success;
755 }
756
757 // Sets information about the item
758 bool wxListCtrl::SetItem(wxListItem& info)
759 {
760 if (m_genericImpl)
761 return m_genericImpl->SetItem(info);
762
763 if (m_dbImpl)
764 m_dbImpl->MacSetColumnInfo( info.m_itemId, info.m_col, &info );
765
766 return true;
767 }
768
769 long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
770 {
771 if (m_genericImpl)
772 return m_genericImpl->SetItem(index, col, label, imageId);
773
774 wxListItem info;
775 info.m_text = label;
776 info.m_mask = wxLIST_MASK_TEXT;
777 info.m_itemId = index;
778 info.m_col = col;
779 if ( imageId > -1 )
780 {
781 info.m_image = imageId;
782 info.m_mask |= wxLIST_MASK_IMAGE;
783 }
784 return SetItem(info);
785 }
786
787
788 // Gets the item state
789 int wxListCtrl::GetItemState(long item, long stateMask) const
790 {
791 if (m_genericImpl)
792 return m_genericImpl->GetItemState(item, stateMask);
793
794 wxListItem info;
795
796 info.m_mask = wxLIST_MASK_STATE;
797 info.m_stateMask = stateMask;
798 info.m_itemId = item;
799
800 if (!GetItem(info))
801 return 0;
802
803 return info.m_state;
804 }
805
806 // Sets the item state
807 bool wxListCtrl::SetItemState(long item, long state, long stateMask)
808 {
809 if (m_genericImpl)
810 return m_genericImpl->SetItemState(item, state, stateMask);
811
812 wxListItem info;
813 info.m_mask = wxLIST_MASK_STATE;
814 info.m_stateMask = stateMask;
815 info.m_state = state;
816 info.m_itemId = item;
817 return SetItem(info);
818 }
819
820 // Sets the item image
821 bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
822 {
823 return SetItemColumnImage(item, 0, image);
824 }
825
826 // Sets the item image
827 bool wxListCtrl::SetItemColumnImage(long item, long column, int image)
828 {
829 if (m_genericImpl)
830 return m_genericImpl->SetItemColumnImage(item, column, image);
831
832 wxListItem info;
833
834 info.m_mask = wxLIST_MASK_IMAGE;
835 info.m_image = image;
836 info.m_itemId = item;
837 info.m_col = column;
838
839 return SetItem(info);
840 }
841
842 // Gets the item text
843 wxString wxListCtrl::GetItemText(long item) const
844 {
845 if (m_genericImpl)
846 return m_genericImpl->GetItemText(item);
847
848 wxListItem info;
849
850 info.m_mask = wxLIST_MASK_TEXT;
851 info.m_itemId = item;
852
853 if (!GetItem(info))
854 return wxEmptyString;
855 return info.m_text;
856 }
857
858 // Sets the item text
859 void wxListCtrl::SetItemText(long item, const wxString& str)
860 {
861 if (m_genericImpl)
862 return m_genericImpl->SetItemText(item, str);
863
864 wxListItem info;
865
866 info.m_mask = wxLIST_MASK_TEXT;
867 info.m_itemId = item;
868 info.m_text = str;
869
870 SetItem(info);
871 }
872
873 // Gets the item data
874 long wxListCtrl::GetItemData(long item) const
875 {
876 if (m_genericImpl)
877 return m_genericImpl->GetItemData(item);
878
879 wxListItem info;
880
881 info.m_mask = wxLIST_MASK_DATA;
882 info.m_itemId = item;
883
884 if (!GetItem(info))
885 return 0;
886 return info.m_data;
887 }
888
889 // Sets the item data
890 bool wxListCtrl::SetItemData(long item, long data)
891 {
892 if (m_genericImpl)
893 return m_genericImpl->SetItemData(item, data);
894
895 wxListItem info;
896
897 info.m_mask = wxLIST_MASK_DATA;
898 info.m_itemId = item;
899 info.m_data = data;
900
901 return SetItem(info);
902 }
903
904 wxRect wxListCtrl::GetViewRect() const
905 {
906 wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
907 _T("wxListCtrl::GetViewRect() only works in icon mode") );
908
909 if (m_genericImpl)
910 return m_genericImpl->GetViewRect();
911
912 wxRect rect;
913 return rect;
914 }
915
916 // Gets the item rectangle
917 bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
918 {
919 if (m_genericImpl)
920 return m_genericImpl->GetItemRect(item, rect, code);
921
922
923 if (m_dbImpl)
924 {
925 DataBrowserItemID id;
926 DataBrowserPropertyID col = kMinColumnId;
927 Rect bounds;
928 DataBrowserPropertyPart part = kDataBrowserPropertyEnclosingPart;
929 if ( code == wxLIST_RECT_LABEL )
930 part = kDataBrowserPropertyTextPart;
931 else if ( code == wxLIST_RECT_ICON )
932 part = kDataBrowserPropertyIconPart;
933
934 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL) )
935 {
936 wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(item);
937 id = (DataBrowserItemID) thisItem;
938 }
939 else
940 id = item;
941
942 GetDataBrowserItemPartBounds( m_dbImpl->GetControlRef(), id, col, part, &bounds );
943
944 rect.x = bounds.left;
945 rect.y = bounds.top;
946 rect.width = GetClientSize().x; // we need the width of the whole row, not just the item.
947 rect.height = bounds.bottom - bounds.top;
948 }
949 return true;
950 }
951
952 // Gets the item position
953 bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
954 {
955 if (m_genericImpl)
956 return m_genericImpl->GetItemPosition(item, pos);
957
958 bool success = false;
959
960 if (m_dbImpl)
961 {
962 wxRect itemRect;
963 GetItemRect(item, itemRect);
964 pos = itemRect.GetPosition();
965 success = true;
966 }
967
968 return success;
969 }
970
971 // Sets the item position.
972 bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
973 {
974 if (m_genericImpl)
975 return m_genericImpl->SetItemPosition(item, pos);
976
977 return false;
978 }
979
980 // Gets the number of items in the list control
981 int wxListCtrl::GetItemCount() const
982 {
983 if (m_genericImpl)
984 return m_genericImpl->GetItemCount();
985
986 if (m_dbImpl)
987 return m_dbImpl->MacGetCount();
988
989 return m_count;
990 }
991
992 void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
993 {
994 if (m_genericImpl)
995 m_genericImpl->SetItemSpacing(spacing, isSmall);
996 }
997
998 wxSize wxListCtrl::GetItemSpacing() const
999 {
1000 if (m_genericImpl)
1001 return m_genericImpl->GetItemSpacing();
1002
1003 return wxSize(0, 0);
1004 }
1005
1006 void wxListCtrl::SetItemTextColour( long item, const wxColour &col )
1007 {
1008 if (m_genericImpl)
1009 {
1010 m_genericImpl->SetItemTextColour(item, col);
1011 return;
1012 }
1013
1014 wxListItem info;
1015 info.m_itemId = item;
1016 info.SetTextColour( col );
1017 SetItem( info );
1018 }
1019
1020 wxColour wxListCtrl::GetItemTextColour( long item ) const
1021 {
1022 if (m_genericImpl)
1023 return m_genericImpl->GetItemTextColour(item);
1024
1025 if (m_dbImpl)
1026 {
1027 wxListItem info;
1028 if (GetItem(info))
1029 return info.GetTextColour();
1030 }
1031 return wxNullColour;
1032 }
1033
1034 void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
1035 {
1036 if (m_genericImpl)
1037 {
1038 m_genericImpl->SetItemBackgroundColour(item, col);
1039 return;
1040 }
1041
1042 wxListItem info;
1043 info.m_itemId = item;
1044 info.SetBackgroundColour( col );
1045 SetItem( info );
1046 }
1047
1048 wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
1049 {
1050 if (m_genericImpl)
1051 return m_genericImpl->GetItemBackgroundColour(item);
1052
1053 if (m_dbImpl)
1054 {
1055 wxListItem info;
1056 if (GetItem(info))
1057 return info.GetBackgroundColour();
1058 }
1059 return wxNullColour;
1060 }
1061
1062 void wxListCtrl::SetItemFont( long item, const wxFont &f )
1063 {
1064 if (m_genericImpl)
1065 {
1066 m_genericImpl->SetItemFont(item, f);
1067 return;
1068 }
1069
1070 wxListItem info;
1071 info.m_itemId = item;
1072 info.SetFont( f );
1073 SetItem( info );
1074 }
1075
1076 wxFont wxListCtrl::GetItemFont( long item ) const
1077 {
1078 if (m_genericImpl)
1079 return m_genericImpl->GetItemFont(item);
1080
1081 if (m_dbImpl)
1082 {
1083 wxListItem info;
1084 if (GetItem(info))
1085 return info.GetFont();
1086 }
1087
1088 return wxNullFont;
1089 }
1090
1091 // Gets the number of selected items in the list control
1092 int wxListCtrl::GetSelectedItemCount() const
1093 {
1094 if (m_genericImpl)
1095 return m_genericImpl->GetSelectedItemCount();
1096
1097 if (m_dbImpl)
1098 return m_dbImpl->GetSelectedItemCount(NULL, true);
1099
1100 return 0;
1101 }
1102
1103 // Gets the text colour of the listview
1104 wxColour wxListCtrl::GetTextColour() const
1105 {
1106 if (m_genericImpl)
1107 return m_genericImpl->GetTextColour();
1108
1109 // TODO: we need owner drawn list items to customize text color.
1110 if (m_dbImpl)
1111 return m_textColor;
1112
1113 return wxNullColour;
1114 }
1115
1116 // Sets the text colour of the listview
1117 void wxListCtrl::SetTextColour(const wxColour& col)
1118 {
1119 if (m_genericImpl)
1120 {
1121 m_genericImpl->SetTextColour(col);
1122 return;
1123 }
1124
1125 if (m_dbImpl)
1126 m_textColor = col;
1127 }
1128
1129 // Gets the index of the topmost visible item when in
1130 // list or report view
1131 long wxListCtrl::GetTopItem() const
1132 {
1133 if (m_genericImpl)
1134 return m_genericImpl->GetTopItem();
1135
1136 return 0;
1137 }
1138
1139 // Searches for an item, starting from 'item'.
1140 // 'geometry' is one of
1141 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1142 // 'state' is a state bit flag, one or more of
1143 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1144 // item can be -1 to find the first item that matches the
1145 // specified flags.
1146 // Returns the item or -1 if unsuccessful.
1147 long wxListCtrl::GetNextItem(long item, int geom, int state) const
1148 {
1149 if (m_genericImpl)
1150 return m_genericImpl->GetNextItem(item, geom, state);
1151
1152 if (m_dbImpl && geom == wxLIST_NEXT_ALL && state == wxLIST_STATE_SELECTED )
1153 {
1154 long count = m_dbImpl->MacGetCount() ;
1155 for ( long line = item + 1 ; line < count; line++ )
1156 {
1157 wxMacDataItem* id = m_dbImpl->GetItemFromLine(line);
1158 if ( m_dbImpl->IsItemSelected(id ) )
1159 return line;
1160 }
1161 return -1;
1162 }
1163
1164 return 0;
1165 }
1166
1167
1168 wxImageList *wxListCtrl::GetImageList(int which) const
1169 {
1170 if (m_genericImpl)
1171 return m_genericImpl->GetImageList(which);
1172
1173 if ( which == wxIMAGE_LIST_NORMAL )
1174 {
1175 return m_imageListNormal;
1176 }
1177 else if ( which == wxIMAGE_LIST_SMALL )
1178 {
1179 return m_imageListSmall;
1180 }
1181 else if ( which == wxIMAGE_LIST_STATE )
1182 {
1183 return m_imageListState;
1184 }
1185 return NULL;
1186 }
1187
1188 void wxListCtrl::SetImageList(wxImageList *imageList, int which)
1189 {
1190 if (m_genericImpl)
1191 {
1192 m_genericImpl->SetImageList(imageList, which);
1193 return;
1194 }
1195
1196 if ( which == wxIMAGE_LIST_NORMAL )
1197 {
1198 if (m_ownsImageListNormal) delete m_imageListNormal;
1199 m_imageListNormal = imageList;
1200 m_ownsImageListNormal = false;
1201 }
1202 else if ( which == wxIMAGE_LIST_SMALL )
1203 {
1204 if (m_ownsImageListSmall) delete m_imageListSmall;
1205 m_imageListSmall = imageList;
1206 m_ownsImageListSmall = false;
1207 }
1208 else if ( which == wxIMAGE_LIST_STATE )
1209 {
1210 if (m_ownsImageListState) delete m_imageListState;
1211 m_imageListState = imageList;
1212 m_ownsImageListState = false;
1213 }
1214 }
1215
1216 void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
1217 {
1218 if (m_genericImpl)
1219 {
1220 m_genericImpl->AssignImageList(imageList, which);
1221 return;
1222 }
1223
1224 SetImageList(imageList, which);
1225 if ( which == wxIMAGE_LIST_NORMAL )
1226 m_ownsImageListNormal = true;
1227 else if ( which == wxIMAGE_LIST_SMALL )
1228 m_ownsImageListSmall = true;
1229 else if ( which == wxIMAGE_LIST_STATE )
1230 m_ownsImageListState = true;
1231 }
1232
1233 // ----------------------------------------------------------------------------
1234 // Operations
1235 // ----------------------------------------------------------------------------
1236
1237 // Arranges the items
1238 bool wxListCtrl::Arrange(int flag)
1239 {
1240 if (m_genericImpl)
1241 return m_genericImpl->Arrange(flag);
1242 return false;
1243 }
1244
1245 // Deletes an item
1246 bool wxListCtrl::DeleteItem(long item)
1247 {
1248 if (m_genericImpl)
1249 return m_genericImpl->DeleteItem(item);
1250
1251 if (m_dbImpl)
1252 {
1253 m_dbImpl->MacDelete(item);
1254 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ITEM, GetId() );
1255 event.SetEventObject( this );
1256 event.m_itemIndex = item;
1257 GetEventHandler()->ProcessEvent( event );
1258
1259 }
1260 return true;
1261 }
1262
1263 // Deletes all items
1264 bool wxListCtrl::DeleteAllItems()
1265 {
1266 if (m_genericImpl)
1267 return m_genericImpl->DeleteAllItems();
1268
1269 if (m_dbImpl)
1270 {
1271 m_dbImpl->MacClear();
1272 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetId() );
1273 event.SetEventObject( this );
1274 GetEventHandler()->ProcessEvent( event );
1275 }
1276 return true;
1277 }
1278
1279 // Deletes all items
1280 bool wxListCtrl::DeleteAllColumns()
1281 {
1282 if (m_genericImpl)
1283 return m_genericImpl->DeleteAllColumns();
1284
1285 if (m_dbImpl)
1286 {
1287 UInt32 cols;
1288 m_dbImpl->GetColumnCount(&cols);
1289 for (UInt32 col = 0; col < cols; col++)
1290 {
1291 DeleteColumn(col);
1292 }
1293 }
1294
1295 return true;
1296 }
1297
1298 // Deletes a column
1299 bool wxListCtrl::DeleteColumn(int col)
1300 {
1301 if (m_genericImpl)
1302 return m_genericImpl->DeleteColumn(col);
1303
1304 if (m_dbImpl)
1305 {
1306 OSStatus err = m_dbImpl->RemoveColumn(col);
1307 return err == noErr;
1308 }
1309
1310 return true;
1311 }
1312
1313 // Clears items, and columns if there are any.
1314 void wxListCtrl::ClearAll()
1315 {
1316 if (m_genericImpl)
1317 {
1318 m_genericImpl->ClearAll();
1319 return;
1320 }
1321
1322 if (m_dbImpl)
1323 {
1324 DeleteAllItems();
1325 DeleteAllColumns();
1326 }
1327 }
1328
1329 wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
1330 {
1331 if (m_genericImpl)
1332 return m_genericImpl->EditLabel(item, textControlClass);
1333
1334 if (m_dbImpl)
1335 {
1336 wxMacDataItem* id = m_dbImpl->GetItemFromLine(item);
1337 verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), (DataBrowserItemID)id, kMinColumnId) );
1338 }
1339 return NULL;
1340 }
1341
1342 // End label editing, optionally cancelling the edit
1343 bool wxListCtrl::EndEditLabel(bool cancel)
1344 {
1345 // TODO: generic impl. doesn't have this method - is it needed for us?
1346 if (m_genericImpl)
1347 return true; // m_genericImpl->EndEditLabel(cancel);
1348
1349 if (m_dbImpl)
1350 verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), kDataBrowserNoItem, kMinColumnId) );
1351 return true;
1352 }
1353
1354 // Ensures this item is visible
1355 bool wxListCtrl::EnsureVisible(long item)
1356 {
1357 if (m_genericImpl)
1358 return m_genericImpl->EnsureVisible(item);
1359
1360 if (m_dbImpl)
1361 {
1362 wxMacDataItem* dataItem = m_dbImpl->GetItemFromLine(item);
1363 m_dbImpl->RevealItem(dataItem, kDataBrowserRevealWithoutSelecting);
1364 }
1365
1366 return true;
1367 }
1368
1369 // Find an item whose label matches this string, starting from the item after 'start'
1370 // or the beginning if 'start' is -1.
1371 long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
1372 {
1373 if (m_genericImpl)
1374 return m_genericImpl->FindItem(start, str, partial);
1375
1376 return -1;
1377 }
1378
1379 // Find an item whose data matches this data, starting from the item after 'start'
1380 // or the beginning if 'start' is -1.
1381 long wxListCtrl::FindItem(long start, long data)
1382 {
1383 if (m_genericImpl)
1384 return m_genericImpl->FindItem(start, data);
1385
1386 long idx = start + 1;
1387 long count = GetItemCount();
1388
1389 while (idx < count)
1390 {
1391 if (GetItemData(idx) == data)
1392 return idx;
1393 idx++;
1394 };
1395
1396 return -1;
1397 }
1398
1399 // Find an item nearest this position in the specified direction, starting from
1400 // the item after 'start' or the beginning if 'start' is -1.
1401 long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
1402 {
1403 if (m_genericImpl)
1404 return m_genericImpl->FindItem(start, pt, direction);
1405 return -1;
1406 }
1407
1408 // Determines which item (if any) is at the specified point,
1409 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1410 long
1411 wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const
1412 {
1413 if (m_genericImpl)
1414 return m_genericImpl->HitTest(point, flags, ptrSubItem);
1415
1416 flags = wxLIST_HITTEST_NOWHERE;
1417 if (m_dbImpl)
1418 {
1419 int colHeaderHeight = 22; // TODO: Find a way to get this value from the db control?
1420 UInt16 rowHeight = 0;
1421 m_dbImpl->GetDefaultRowHeight(&rowHeight);
1422
1423 int y = point.y;
1424 if ( !(GetWindowStyleFlag() & wxLC_NO_HEADER) )
1425 y -= colHeaderHeight;
1426
1427 int row = y / rowHeight;
1428 DataBrowserItemID id;
1429 m_dbImpl->GetItemID( (DataBrowserTableViewRowIndex) row, &id );
1430
1431 // TODO: Use GetDataBrowserItemPartBounds to return if we are in icon or label
1432 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL ) )
1433 {
1434 wxMacListCtrlItem* lcItem;
1435 lcItem = (wxMacListCtrlItem*) id;
1436 if (lcItem)
1437 {
1438 flags = wxLIST_HITTEST_ONITEM;
1439 return row;
1440 }
1441 }
1442 else
1443 {
1444 if (row < GetItemCount() )
1445 {
1446 flags = wxLIST_HITTEST_ONITEM;
1447 return row;
1448 }
1449 }
1450
1451 }
1452 return -1;
1453 }
1454
1455
1456 // Inserts an item, returning the index of the new item if successful,
1457 // -1 otherwise.
1458 long wxListCtrl::InsertItem(wxListItem& info)
1459 {
1460 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
1461
1462 if (m_genericImpl)
1463 return m_genericImpl->InsertItem(info);
1464
1465 if (m_dbImpl)
1466 {
1467 int count = GetItemCount();
1468
1469 if (info.m_itemId > count)
1470 info.m_itemId = count;
1471
1472 m_dbImpl->MacInsertItem(info.m_itemId, &info );
1473 wxListEvent event( wxEVT_COMMAND_LIST_INSERT_ITEM, GetId() );
1474 event.SetEventObject( this );
1475 event.m_itemIndex = info.m_itemId;
1476 GetEventHandler()->ProcessEvent( event );
1477 }
1478
1479 return info.m_itemId;
1480 }
1481
1482 long wxListCtrl::InsertItem(long index, const wxString& label)
1483 {
1484 if (m_genericImpl)
1485 return m_genericImpl->InsertItem(index, label);
1486
1487 wxListItem info;
1488 info.m_text = label;
1489 info.m_mask = wxLIST_MASK_TEXT;
1490 info.m_itemId = index;
1491 return InsertItem(info);
1492 }
1493
1494 // Inserts an image item
1495 long wxListCtrl::InsertItem(long index, int imageIndex)
1496 {
1497 if (m_genericImpl)
1498 return m_genericImpl->InsertItem(index, imageIndex);
1499
1500 wxListItem info;
1501 info.m_image = imageIndex;
1502 info.m_mask = wxLIST_MASK_IMAGE;
1503 info.m_itemId = index;
1504 return InsertItem(info);
1505 }
1506
1507 // Inserts an image/string item
1508 long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
1509 {
1510 if (m_genericImpl)
1511 return m_genericImpl->InsertItem(index, label, imageIndex);
1512
1513 wxListItem info;
1514 info.m_image = imageIndex;
1515 info.m_text = label;
1516 info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
1517 info.m_itemId = index;
1518 return InsertItem(info);
1519 }
1520
1521 // For list view mode (only), inserts a column.
1522 long wxListCtrl::InsertColumn(long col, wxListItem& item)
1523 {
1524 if (m_genericImpl)
1525 return m_genericImpl->InsertColumn(col, item);
1526
1527 if (m_dbImpl)
1528 {
1529 int width = item.GetWidth();
1530 if ( !(item.GetMask() & wxLIST_MASK_WIDTH) )
1531 width = 150;
1532
1533 DataBrowserPropertyType type = kDataBrowserCustomType; //kDataBrowserTextType;
1534 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
1535 if (imageList && imageList->GetImageCount() > 0)
1536 {
1537 wxBitmap bmp = imageList->GetBitmap(0);
1538 //if (bmp.Ok())
1539 // type = kDataBrowserIconAndTextType;
1540 }
1541
1542 SInt16 just = teFlushDefault;
1543 if (item.GetMask() & wxLIST_MASK_FORMAT)
1544 {
1545 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
1546 just = teFlushLeft;
1547 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
1548 just = teCenter;
1549 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
1550 just = teFlushRight;
1551 }
1552 m_dbImpl->InsertColumn(col, type, item.GetText(), just, width);
1553 SetColumn(col, item);
1554
1555 // set/remove options based on the wxListCtrl type.
1556 DataBrowserTableViewColumnID id;
1557 m_dbImpl->GetColumnIDFromIndex(col, &id);
1558 DataBrowserPropertyFlags flags;
1559 verify_noerr(m_dbImpl->GetPropertyFlags(id, &flags));
1560 if (GetWindowStyleFlag() & wxLC_EDIT_LABELS)
1561 flags |= kDataBrowserPropertyIsEditable;
1562
1563 if (GetWindowStyleFlag() & wxLC_VIRTUAL){
1564 flags &= ~kDataBrowserListViewSortableColumn;
1565 }
1566 verify_noerr(m_dbImpl->SetPropertyFlags(id, flags));
1567 }
1568
1569 return col;
1570 }
1571
1572 long wxListCtrl::InsertColumn(long col,
1573 const wxString& heading,
1574 int format,
1575 int width)
1576 {
1577 if (m_genericImpl)
1578 return m_genericImpl->InsertColumn(col, heading, format, width);
1579
1580 wxListItem item;
1581 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
1582 item.m_text = heading;
1583 if ( width > -1 )
1584 {
1585 item.m_mask |= wxLIST_MASK_WIDTH;
1586 item.m_width = width;
1587 }
1588 item.m_format = format;
1589
1590 return InsertColumn(col, item);
1591 }
1592
1593 // scroll the control by the given number of pixels (exception: in list view,
1594 // dx is interpreted as number of columns)
1595 bool wxListCtrl::ScrollList(int dx, int dy)
1596 {
1597 if (m_genericImpl)
1598 return m_genericImpl->ScrollList(dx, dy);
1599
1600 if (m_dbImpl)
1601 {
1602 m_dbImpl->SetScrollPosition(dx, dy);
1603 }
1604 return true;
1605 }
1606
1607
1608 bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
1609 {
1610 if (m_genericImpl)
1611 return m_genericImpl->SortItems(fn, data);
1612
1613 if (m_dbImpl)
1614 {
1615 m_compareFunc = fn;
1616 m_compareFuncData = data;
1617 }
1618
1619 return true;
1620 }
1621
1622 // ----------------------------------------------------------------------------
1623 // virtual list controls
1624 // ----------------------------------------------------------------------------
1625
1626 wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
1627 {
1628 // this is a pure virtual function, in fact - which is not really pure
1629 // because the controls which are not virtual don't need to implement it
1630 wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") );
1631
1632 return wxEmptyString;
1633 }
1634
1635 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
1636 {
1637 wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
1638 -1,
1639 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
1640 return -1;
1641 }
1642
1643 int wxListCtrl::OnGetItemColumnImage(long item, long column) const
1644 {
1645 if (!column)
1646 return OnGetItemImage(item);
1647
1648 return -1;
1649 }
1650
1651 wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
1652 {
1653 wxASSERT_MSG( item >= 0 && item < GetItemCount(),
1654 _T("invalid item index in OnGetItemAttr()") );
1655
1656 // no attributes by default
1657 return NULL;
1658 }
1659
1660 void wxListCtrl::SetItemCount(long count)
1661 {
1662 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
1663
1664 if (m_genericImpl)
1665 {
1666 m_genericImpl->SetItemCount(count);
1667 return;
1668 }
1669
1670 if (m_dbImpl)
1671 {
1672 // we need to temporarily disable the new item creation notification
1673 // procedure to speed things up
1674 // FIXME: Even this doesn't seem to help much...
1675 DataBrowserCallbacks callbacks;
1676 DataBrowserItemNotificationUPP itemUPP;
1677 GetDataBrowserCallbacks(m_dbImpl->GetControlRef(), &callbacks);
1678 itemUPP = callbacks.u.v1.itemNotificationCallback;
1679 callbacks.u.v1.itemNotificationCallback = 0;
1680 m_dbImpl->SetCallbacks(&callbacks);
1681 ::AddDataBrowserItems(m_dbImpl->GetControlRef(), kDataBrowserNoItem,
1682 count, NULL, kDataBrowserItemNoProperty);
1683 callbacks.u.v1.itemNotificationCallback = itemUPP;
1684 m_dbImpl->SetCallbacks(&callbacks);
1685 }
1686 m_count = count;
1687 }
1688
1689 void wxListCtrl::RefreshItem(long item)
1690 {
1691 if (m_genericImpl)
1692 {
1693 m_genericImpl->RefreshItem(item);
1694 return;
1695 }
1696
1697 wxRect rect;
1698 GetItemRect(item, rect);
1699 RefreshRect(rect);
1700 }
1701
1702 void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
1703 {
1704 if (m_genericImpl)
1705 {
1706 m_genericImpl->RefreshItems(itemFrom, itemTo);
1707 return;
1708 }
1709
1710 wxRect rect1, rect2;
1711 GetItemRect(itemFrom, rect1);
1712 GetItemRect(itemTo, rect2);
1713
1714 wxRect rect = rect1;
1715 rect.height = rect2.GetBottom() - rect1.GetTop();
1716
1717 RefreshRect(rect);
1718 }
1719
1720
1721 // wxMac internal data structures
1722
1723 wxMacListCtrlItem::~wxMacListCtrlItem()
1724 {
1725 }
1726
1727 void wxMacListCtrlItem::Notification(wxMacDataItemBrowserControl *owner ,
1728 DataBrowserItemNotification message,
1729 DataBrowserItemDataRef itemData ) const
1730 {
1731
1732 wxMacDataBrowserListCtrlControl *lb = dynamic_cast<wxMacDataBrowserListCtrlControl*>(owner);
1733
1734 // we want to depend on as little as possible to make sure tear-down of controls is safe
1735 if ( message == kDataBrowserItemRemoved)
1736 {
1737 if ( lb != NULL && lb->GetClientDataType() == wxClientData_Object )
1738 {
1739 delete (wxClientData*) (m_data);
1740 }
1741
1742 delete this;
1743 return;
1744 }
1745 else if ( message == kDataBrowserItemAdded )
1746 {
1747 // we don't issue events on adding, the item is not really stored in the list yet, so we
1748 // avoid asserts by gettting out now
1749 return ;
1750 }
1751
1752 wxListCtrl *list = wxDynamicCast( owner->GetPeer() , wxListCtrl );
1753 if ( list )
1754 {
1755 bool trigger = false;
1756
1757 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
1758 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
1759
1760 event.SetEventObject( list );
1761 event.m_itemIndex = owner->GetLineFromItem( this ) ;
1762 if ( !list->IsVirtual() )
1763 {
1764 lb->MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
1765 }
1766
1767 switch (message)
1768 {
1769 case kDataBrowserItemDeselected:
1770 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
1771 if ( !isSingle )
1772 trigger = !lb->IsSelectionSuppressed();
1773 break;
1774
1775 case kDataBrowserItemSelected:
1776 trigger = !lb->IsSelectionSuppressed();
1777 break;
1778
1779 case kDataBrowserItemDoubleClicked:
1780 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
1781 trigger = true;
1782 break;
1783
1784 case kDataBrowserEditStarted :
1785 // TODO : how to veto ?
1786 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
1787 trigger = true ;
1788 break ;
1789
1790 case kDataBrowserEditStopped :
1791 // TODO probably trigger only upon the value store callback, because
1792 // here IIRC we cannot veto
1793 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
1794 trigger = true ;
1795 break ;
1796
1797 default:
1798 break;
1799 }
1800
1801 if ( trigger )
1802 {
1803 // direct notification is not always having the listbox GetSelection() having in synch with event
1804 wxPostEvent( list->GetEventHandler(), event );
1805 }
1806 }
1807
1808 }
1809
1810 wxMacDataBrowserListCtrlControl::wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style)
1811 : wxMacDataItemBrowserControl( peer, pos, size, style )
1812 {
1813 OSStatus err = noErr;
1814 m_clientDataItemsType = wxClientData_None;
1815 m_isVirtual = false;
1816
1817 if ( style & wxLC_VIRTUAL )
1818 m_isVirtual = true;
1819
1820 DataBrowserSelectionFlags options = kDataBrowserDragSelect;
1821 if ( style & wxLC_SINGLE_SEL )
1822 {
1823 options |= kDataBrowserSelectOnlyOne;
1824 }
1825 else
1826 {
1827 options |= kDataBrowserCmdTogglesSelection;
1828 }
1829
1830 err = SetSelectionFlags( options );
1831 verify_noerr( err );
1832
1833 DataBrowserCustomCallbacks callbacks;
1834 InitializeDataBrowserCustomCallbacks( &callbacks, kDataBrowserLatestCustomCallbacks );
1835
1836 if ( gDataBrowserDrawItemUPP == NULL )
1837 gDataBrowserDrawItemUPP = NewDataBrowserDrawItemUPP(DataBrowserDrawItemProc);
1838
1839 // if ( gDataBrowserEditItemUPP == NULL )
1840 // gDataBrowserEditItemUPP = NewDataBrowserEditItemUPP(DataBrowserEditTextProc);
1841
1842 if ( gDataBrowserHitTestUPP == NULL )
1843 gDataBrowserHitTestUPP = NewDataBrowserHitTestUPP(DataBrowserHitTestProc);
1844
1845 callbacks.u.v1.drawItemCallback = gDataBrowserDrawItemUPP;
1846 // callbacks.u.v1.editTextCallback = gDataBrowserEditItemUPP;
1847 callbacks.u.v1.hitTestCallback = gDataBrowserHitTestUPP;
1848
1849 SetDataBrowserCustomCallbacks( GetControlRef(), &callbacks );
1850
1851 if ( style & wxLC_LIST )
1852 {
1853 InsertColumn(0, kDataBrowserIconAndTextType, wxEmptyString, -1, -1);
1854 verify_noerr( AutoSizeColumns() );
1855 }
1856
1857 if ( style & wxLC_LIST || style & wxLC_NO_HEADER )
1858 verify_noerr( SetHeaderButtonHeight( 0 ) );
1859
1860 if ( m_isVirtual )
1861 SetSortProperty( kMinColumnId - 1 );
1862 else
1863 SetSortProperty( kMinColumnId );
1864 if ( style & wxLC_SORT_ASCENDING )
1865 {
1866 m_sortOrder = SortOrder_Text_Ascending;
1867 SetSortOrder( kDataBrowserOrderIncreasing );
1868 }
1869 else if ( style & wxLC_SORT_DESCENDING )
1870 {
1871 m_sortOrder = SortOrder_Text_Descending;
1872 SetSortOrder( kDataBrowserOrderDecreasing );
1873 }
1874 else
1875 {
1876 m_sortOrder = SortOrder_None;
1877 }
1878
1879 if ( style & wxLC_VRULES )
1880 {
1881 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1882 verify_noerr( DataBrowserChangeAttributes(m_controlRef, kDataBrowserAttributeListViewDrawColumnDividers, kDataBrowserAttributeNone) );
1883 #endif
1884 }
1885
1886 verify_noerr( SetHiliteStyle(kDataBrowserTableViewFillHilite ) );
1887 err = SetHasScrollBars( (style & wxHSCROLL) != 0 , true );
1888 }
1889
1890 pascal Boolean wxMacDataBrowserListCtrlControl::DataBrowserEditTextProc(
1891 ControlRef browser,
1892 DataBrowserItemID itemID,
1893 DataBrowserPropertyID property,
1894 CFStringRef theString,
1895 Rect *maxEditTextRect,
1896 Boolean *shrinkToFit)
1897 {
1898 Boolean result = false;
1899 wxMacDataBrowserListCtrlControl* ctl = dynamic_cast<wxMacDataBrowserListCtrlControl*>( wxMacControl::GetReferenceFromNativeControl( browser ) );
1900 if ( ctl != 0 )
1901 {
1902 result = ctl->ConfirmEditText(itemID, property, theString, maxEditTextRect, shrinkToFit);
1903 theString = CFSTR("Hello!");
1904 }
1905 return result;
1906 }
1907
1908 bool wxMacDataBrowserListCtrlControl::ConfirmEditText(
1909 DataBrowserItemID itemID,
1910 DataBrowserPropertyID property,
1911 CFStringRef theString,
1912 Rect *maxEditTextRect,
1913 Boolean *shrinkToFit)
1914 {
1915 //wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
1916 return false;
1917 }
1918
1919 pascal void wxMacDataBrowserListCtrlControl::DataBrowserDrawItemProc(
1920 ControlRef browser,
1921 DataBrowserItemID itemID,
1922 DataBrowserPropertyID property,
1923 DataBrowserItemState itemState,
1924 const Rect *itemRect,
1925 SInt16 gdDepth,
1926 Boolean colorDevice)
1927 {
1928 wxMacDataBrowserListCtrlControl* ctl = dynamic_cast<wxMacDataBrowserListCtrlControl*>( wxMacControl::GetReferenceFromNativeControl( browser ) );
1929 if ( ctl != 0 )
1930 {
1931 ctl->DrawItem(itemID, property, itemState, itemRect, gdDepth, colorDevice);
1932 }
1933 }
1934
1935 // routines needed for DrawItem
1936 enum
1937 {
1938 kIconWidth = 16,
1939 kIconHeight = 16,
1940 kTextBoxHeight = 14,
1941 kIconTextSpacingV = 2,
1942 kItemPadding = 4,
1943 kContentHeight = kIconHeight + kTextBoxHeight + kIconTextSpacingV
1944 };
1945
1946 static void calculateCGDrawingBounds(CGRect inItemRect, CGRect *outIconRect, CGRect *outTextRect, bool hasIcon = false)
1947 {
1948 float textBottom;
1949 float iconH, iconW = 0;
1950 float padding = kItemPadding;
1951 if (hasIcon)
1952 {
1953 iconH = kIconHeight;
1954 iconW = kIconWidth;
1955 padding = padding*2;
1956 }
1957
1958 textBottom = inItemRect.origin.y;
1959
1960 *outIconRect = CGRectMake(inItemRect.origin.x + kItemPadding,
1961 textBottom + kIconTextSpacingV, kIconWidth,
1962 kIconHeight);
1963
1964 *outTextRect = CGRectMake(inItemRect.origin.x + padding + iconW,
1965 textBottom + kIconTextSpacingV, inItemRect.size.width - padding - iconW,
1966 inItemRect.size.height - kIconTextSpacingV);
1967 }
1968
1969 void wxMacDataBrowserListCtrlControl::DrawItem(
1970 DataBrowserItemID itemID,
1971 DataBrowserPropertyID property,
1972 DataBrowserItemState itemState,
1973 const Rect *itemRect,
1974 SInt16 gdDepth,
1975 Boolean colorDevice)
1976 {
1977 wxString text;
1978 wxFont font = wxNullFont;
1979 int imgIndex = -1;
1980 short listColumn = property - kMinColumnId;
1981
1982 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
1983 wxMacListCtrlItem* lcItem;
1984 wxColour color = *wxBLACK;
1985 wxColour bgColor = wxNullColour;
1986
1987 if (listColumn >= 0)
1988 {
1989 if (!m_isVirtual)
1990 {
1991 lcItem = (wxMacListCtrlItem*) itemID;
1992 if (lcItem->HasColumnInfo(listColumn)){
1993 wxListItem* item = lcItem->GetColumnInfo(listColumn);
1994
1995 // we always use the 0 column to get font and text/background colors.
1996 if (lcItem->HasColumnInfo(0))
1997 {
1998 wxListItem* firstItem = lcItem->GetColumnInfo(0);
1999 color = firstItem->GetTextColour();
2000 bgColor = firstItem->GetBackgroundColour();
2001 font = firstItem->GetFont();
2002 }
2003
2004 if (item->GetMask() & wxLIST_MASK_TEXT)
2005 text = item->GetText();
2006 if (item->GetMask() & wxLIST_MASK_IMAGE)
2007 imgIndex = item->GetImage();
2008 }
2009
2010 }
2011 else
2012 {
2013 text = list->OnGetItemText( (long)itemID-1, listColumn );
2014 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2015 wxListItemAttr* attrs = list->OnGetItemAttr( (long)itemID-1 );
2016 if (attrs)
2017 {
2018 if (attrs->HasBackgroundColour())
2019 bgColor = attrs->GetBackgroundColour();
2020 if (attrs->HasTextColour())
2021 color = attrs->GetTextColour();
2022 if (attrs->HasFont())
2023 font = attrs->GetFont();
2024 }
2025 }
2026 }
2027
2028 wxColour listBgColor = list->GetBackgroundColour();
2029 if (bgColor == wxNullColour)
2030 bgColor = listBgColor;
2031
2032 wxFont listFont = list->GetFont();
2033 if (font == wxNullFont)
2034 font = listFont;
2035
2036 wxMacCFStringHolder cfString;
2037 cfString.Assign( text, wxLocale::GetSystemEncoding() );
2038
2039 Rect enclosingRect;
2040 CGRect enclosingCGRect, iconCGRect, textCGRect;
2041 Boolean active;
2042 ThemeDrawingState savedState = NULL;
2043 CGContextRef context = (CGContextRef)list->MacGetDrawingContext();
2044 RGBColor labelColor;
2045
2046 GetDataBrowserItemPartBounds(GetControlRef(), itemID, property, kDataBrowserPropertyEnclosingPart,
2047 &enclosingRect);
2048
2049 enclosingCGRect = CGRectMake(enclosingRect.left,
2050 enclosingRect.top,
2051 enclosingRect.right - enclosingRect.left,
2052 enclosingRect.bottom - enclosingRect.top);
2053
2054 active = IsControlActive(GetControlRef());
2055
2056 if (itemState == kDataBrowserItemIsSelected)
2057 {
2058 RGBColor foregroundColor;
2059
2060 GetThemeDrawingState(&savedState);
2061
2062 GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &foregroundColor);
2063 GetThemeTextColor(kThemeTextColorWhite, gdDepth, colorDevice, &labelColor);
2064
2065 CGContextSaveGState(context);
2066
2067 CGContextSetRGBFillColor(context, (float)foregroundColor.red / (float)USHRT_MAX,
2068 (float)foregroundColor.green / (float)USHRT_MAX,
2069 (float)foregroundColor.blue / (float)USHRT_MAX, 1.0);
2070 CGContextFillRect(context, enclosingCGRect);
2071
2072 CGContextRestoreGState(context);
2073 }
2074 else
2075 {
2076
2077 if (color.Ok())
2078 labelColor = MAC_WXCOLORREF( color.GetPixel() );
2079 else if (list->GetTextColour().Ok())
2080 labelColor = MAC_WXCOLORREF( list->GetTextColour().GetPixel() );
2081 else
2082 {
2083 labelColor.red = 0;
2084 labelColor.green = 0;
2085 labelColor.blue = 0;
2086 }
2087
2088 if (bgColor.Ok())
2089 {
2090 RGBColor foregroundColor = MAC_WXCOLORREF( bgColor.GetPixel() );
2091 CGContextSaveGState(context);
2092
2093 CGContextSetRGBFillColor(context, (float)foregroundColor.red / (float)USHRT_MAX,
2094 (float)foregroundColor.green / (float)USHRT_MAX,
2095 (float)foregroundColor.blue / (float)USHRT_MAX, 1.0);
2096 CGContextFillRect(context, enclosingCGRect);
2097
2098 CGContextRestoreGState(context);
2099 }
2100 }
2101
2102 calculateCGDrawingBounds(enclosingCGRect, &iconCGRect, &textCGRect, (imgIndex != -1) );
2103
2104 if (imgIndex != -1)
2105 {
2106 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2107 if (imageList && imageList->GetImageCount() > 0){
2108 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2109 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2110
2111 RGBColor iconLabel;
2112 iconLabel.red = 0;
2113 iconLabel.green = 0;
2114 iconLabel.blue = 0;
2115
2116 CGContextSaveGState(context);
2117 CGContextTranslateCTM(context, 0,iconCGRect.origin.y + CGRectGetMaxY(iconCGRect));
2118 CGContextScaleCTM(context,1.0f,-1.0f);
2119 PlotIconRefInContext(context, &iconCGRect, kAlignNone,
2120 active ? kTransformNone : kTransformDisabled, &iconLabel,
2121 kPlotIconRefNormalFlags, icon);
2122
2123 CGContextRestoreGState(context);
2124 }
2125 }
2126
2127 HIThemeTextHorizontalFlush hFlush = kHIThemeTextHorizontalFlushLeft;
2128 UInt16 fontID = kThemeViewsFont;
2129
2130 if (font.Ok())
2131 {
2132 if (font.GetFamily() != wxFONTFAMILY_DEFAULT)
2133 fontID = font.MacGetThemeFontID();
2134
2135 // FIXME: replace these with CG or ATSUI calls so we can remove this #ifndef.
2136 #ifndef __LP64__
2137 ::TextSize( (short)(font.MacGetFontSize()) ) ;
2138 ::TextFace( font.MacGetFontStyle() ) ;
2139 #endif
2140 }
2141
2142 wxListItem item;
2143 list->GetColumn(listColumn, item);
2144 if (item.GetMask() & wxLIST_MASK_FORMAT)
2145 {
2146 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2147 hFlush = kHIThemeTextHorizontalFlushLeft;
2148 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2149 hFlush = kHIThemeTextHorizontalFlushCenter;
2150 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2151 {
2152 hFlush = kHIThemeTextHorizontalFlushRight;
2153 textCGRect.origin.x -= kItemPadding; // give a little extra paddding
2154 }
2155 }
2156
2157 HIThemeTextInfo info;
2158 info.version = kHIThemeTextInfoVersionZero;
2159 info.state = active ? kThemeStateActive : kThemeStateInactive;
2160 info.fontID = fontID;
2161 info.horizontalFlushness = hFlush;
2162 info.verticalFlushness = kHIThemeTextVerticalFlushCenter;
2163 info.options = kHIThemeTextBoxOptionNone;
2164 info.truncationPosition = kHIThemeTextTruncationEnd;
2165 info.truncationMaxLines = 1;
2166
2167 CGContextSaveGState(context);
2168 CGContextSetRGBFillColor (context, (float)labelColor.red / (float)USHRT_MAX,
2169 (float)labelColor.green / (float)USHRT_MAX,
2170 (float)labelColor.blue / (float)USHRT_MAX, 1.0);
2171
2172 HIThemeDrawTextBox(cfString, &textCGRect, &info, context, kHIThemeOrientationNormal);
2173
2174 CGContextRestoreGState(context);
2175
2176 if (savedState != NULL)
2177 SetThemeDrawingState(savedState, true);
2178 }
2179
2180 OSStatus wxMacDataBrowserListCtrlControl::GetSetItemData(DataBrowserItemID itemID,
2181 DataBrowserPropertyID property,
2182 DataBrowserItemDataRef itemData,
2183 Boolean changeValue )
2184 {
2185 wxString text;
2186 int imgIndex = -1;
2187 short listColumn = property - kMinColumnId;
2188
2189 OSStatus err = errDataBrowserPropertyNotSupported;
2190 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2191 wxMacListCtrlItem* lcItem;
2192
2193 if (listColumn >= 0)
2194 {
2195 if (!m_isVirtual)
2196 {
2197 lcItem = (wxMacListCtrlItem*) itemID;
2198 if (lcItem->HasColumnInfo(listColumn)){
2199 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2200 if (item->GetMask() & wxLIST_MASK_TEXT)
2201 text = item->GetText();
2202 if (item->GetMask() & wxLIST_MASK_IMAGE)
2203 imgIndex = item->GetImage();
2204 }
2205 }
2206 else
2207 {
2208 text = list->OnGetItemText( (long)itemID-1, listColumn );
2209 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2210 }
2211 }
2212
2213 if ( !changeValue )
2214 {
2215 switch (property)
2216 {
2217 case kDataBrowserItemIsEditableProperty :
2218 if ( list && list->HasFlag( wxLC_EDIT_LABELS ) )
2219 {
2220 verify_noerr(SetDataBrowserItemDataBooleanValue( itemData, true ));
2221 err = noErr ;
2222 }
2223 break ;
2224 default :
2225 if ( property >= kMinColumnId )
2226 {
2227 wxMacCFStringHolder cfStr;
2228
2229 if (text){
2230 cfStr.Assign( text, wxLocale::GetSystemEncoding() );
2231 err = ::SetDataBrowserItemDataText( itemData, cfStr );
2232 err = noErr;
2233 }
2234
2235
2236
2237 if ( imgIndex != -1 )
2238 {
2239 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2240 if (imageList && imageList->GetImageCount() > 0){
2241 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2242 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2243 ::SetDataBrowserItemDataIcon(itemData, icon);
2244 }
2245 }
2246
2247 }
2248 break ;
2249 }
2250
2251 }
2252 else
2253 {
2254 switch (property)
2255 {
2256 default:
2257 if ( property >= kMinColumnId )
2258 {
2259 short listColumn = property - kMinColumnId;
2260
2261 // TODO probably send the 'end edit' from here, as we
2262 // can then deal with the veto
2263 CFStringRef sr ;
2264 verify_noerr( GetDataBrowserItemDataText( itemData , &sr ) ) ;
2265 wxMacCFStringHolder cfStr(sr) ;;
2266 if (m_isVirtual)
2267 list->SetItem( (long)itemData-1 , listColumn, cfStr.AsString() ) ;
2268 else
2269 {
2270 if (lcItem)
2271 lcItem->SetColumnTextValue( listColumn, cfStr.AsString() );
2272 }
2273 err = noErr ;
2274 }
2275 break;
2276 }
2277 }
2278 return err;
2279 }
2280
2281 void wxMacDataBrowserListCtrlControl::ItemNotification(DataBrowserItemID itemID,
2282 DataBrowserItemNotification message,
2283 DataBrowserItemDataRef itemData )
2284 {
2285 // we want to depend on as little as possible to make sure tear-down of controls is safe
2286 if ( message == kDataBrowserItemRemoved)
2287 {
2288 // make sure MacDelete does the proper teardown.
2289 return;
2290 }
2291 else if ( message == kDataBrowserItemAdded )
2292 {
2293 // we don't issue events on adding, the item is not really stored in the list yet, so we
2294 // avoid asserts by getting out now
2295 return ;
2296 }
2297
2298 wxListCtrl *list = wxDynamicCast( GetPeer() , wxListCtrl );
2299 if ( list )
2300 {
2301 bool trigger = false;
2302
2303 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
2304 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
2305
2306 event.SetEventObject( list );
2307 if ( !list->IsVirtual() )
2308 {
2309 DataBrowserTableViewRowIndex result = 0;
2310 verify_noerr( GetItemRow( itemID, &result ) ) ;
2311 event.m_itemIndex = result;
2312
2313 if (event.m_itemIndex >= 0)
2314 MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
2315 }
2316 else
2317 {
2318 event.m_itemIndex = (long)itemID;
2319 }
2320
2321 switch (message)
2322 {
2323 case kDataBrowserItemDeselected:
2324 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
2325 if ( !isSingle )
2326 trigger = !IsSelectionSuppressed();
2327 break;
2328
2329 case kDataBrowserItemSelected:
2330 trigger = !IsSelectionSuppressed();
2331
2332 break;
2333
2334 case kDataBrowserItemDoubleClicked:
2335 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
2336 trigger = true;
2337 break;
2338
2339 case kDataBrowserEditStarted :
2340 // TODO : how to veto ?
2341 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
2342 trigger = true ;
2343 break ;
2344
2345 case kDataBrowserEditStopped :
2346 // TODO probably trigger only upon the value store callback, because
2347 // here IIRC we cannot veto
2348 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
2349 trigger = true ;
2350 break ;
2351
2352 default:
2353 break;
2354 }
2355
2356 if ( trigger )
2357 {
2358 // direct notification is not always having the listbox GetSelection() having in synch with event
2359 wxPostEvent( list->GetEventHandler(), event );
2360 }
2361 }
2362 }
2363
2364 Boolean wxMacDataBrowserListCtrlControl::CompareItems(DataBrowserItemID itemOneID,
2365 DataBrowserItemID itemTwoID,
2366 DataBrowserPropertyID sortProperty)
2367 {
2368
2369 bool retval = false;
2370 wxString itemText;
2371 wxString otherItemText;
2372 int colId = sortProperty - kMinColumnId;
2373 long itemNum = 0;
2374 long otherItemNum = 0;
2375
2376 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2377
2378 // means we need to
2379 if (colId >= 0)
2380 {
2381 if (!m_isVirtual)
2382 {
2383 wxMacListCtrlItem* item = (wxMacListCtrlItem*)itemOneID;
2384 wxMacListCtrlItem* otherItem = (wxMacListCtrlItem*)itemTwoID;
2385 wxListCtrlCompare func = list->GetCompareFunc();
2386 if (func != NULL && item->HasColumnInfo(colId) && otherItem->HasColumnInfo(colId))
2387 return func(item->GetColumnInfo(colId)->GetData(), otherItem->GetColumnInfo(colId)->GetData(), list->GetCompareFuncData()) >= 0;
2388
2389 itemNum = item->GetOrder();
2390 otherItemNum = otherItem->GetOrder();
2391 if (item->HasColumnInfo(colId))
2392 itemText = item->GetColumnInfo(colId)->GetText();
2393 if (otherItem->HasColumnInfo(colId))
2394 otherItemText = otherItem->GetColumnInfo(colId)->GetText();
2395 }
2396 else
2397 {
2398 itemNum = (long)itemOneID;
2399 otherItemNum = (long)itemTwoID;
2400 itemText = list->OnGetItemText( itemNum-1, colId );
2401 otherItemText = list->OnGetItemText( otherItemNum-1, colId );
2402
2403 }
2404
2405 DataBrowserSortOrder sort;
2406 verify_noerr(GetSortOrder(&sort));
2407
2408 if ( sort == kDataBrowserOrderIncreasing )
2409 {
2410 retval = itemText.CmpNoCase( otherItemText ) > 0;
2411 }
2412 else if ( sort == kDataBrowserOrderDecreasing )
2413 {
2414 retval = itemText.CmpNoCase( otherItemText ) < 0;
2415 }
2416 }
2417 else{
2418 // fallback for undefined cases
2419 retval = itemOneID < itemTwoID;
2420 }
2421
2422 return retval;
2423 }
2424
2425 wxMacDataBrowserListCtrlControl::~wxMacDataBrowserListCtrlControl()
2426 {
2427 }
2428
2429 void wxMacDataBrowserListCtrlControl::MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item )
2430 {
2431 wxMacDataItem* dataItem = GetItemFromLine(row);
2432 if (item)
2433 {
2434 wxMacListCtrlItem* listItem = dynamic_cast<wxMacListCtrlItem*>(dataItem);
2435 listItem->SetColumnInfo( column, item );
2436 UpdateState(dataItem, item);
2437 }
2438 }
2439
2440 // apply changes that need to happen immediately, rather than when the
2441 // databrowser control fires a callback.
2442 void wxMacDataBrowserListCtrlControl::UpdateState(wxMacDataItem* dataItem, wxListItem* listItem)
2443 {
2444 bool isSelected = IsItemSelected( dataItem );
2445 bool isSelectedState = (listItem->GetState() == wxLIST_STATE_SELECTED);
2446
2447 // toggle the selection state if wxListInfo state and actual state don't match.
2448 if ( isSelected != isSelectedState )
2449 {
2450 DataBrowserSetOption options = kDataBrowserItemsAdd;
2451 if (!isSelectedState)
2452 options = kDataBrowserItemsRemove;
2453 SetSelectedItem(dataItem, options);
2454 }
2455 // TODO: Set column width if item width > than current column width
2456 }
2457
2458 void wxMacDataBrowserListCtrlControl::MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item )
2459 {
2460 wxMacDataItem* dataItem = GetItemFromLine(row);
2461 // CS should this guard against dataItem = 0 ? , as item is not a pointer if (item) is not appropriate
2462 //if (item)
2463 {
2464 wxMacListCtrlItem* listItem = dynamic_cast<wxMacListCtrlItem*>(dataItem);
2465 wxListItem* oldItem = listItem->GetColumnInfo( column );
2466
2467 long mask = item.GetMask();
2468 if ( !mask )
2469 // by default, get everything for backwards compatibility
2470 mask = -1;
2471
2472 if ( mask & wxLIST_MASK_TEXT )
2473 item.SetText(oldItem->GetText());
2474 if ( mask & wxLIST_MASK_IMAGE )
2475 item.SetImage(oldItem->GetImage());
2476 if ( mask & wxLIST_MASK_DATA )
2477 item.SetData(oldItem->GetData());
2478 if ( mask & wxLIST_MASK_STATE )
2479 item.SetState(oldItem->GetState());
2480 if ( mask & wxLIST_MASK_WIDTH )
2481 item.SetWidth(oldItem->GetWidth());
2482 if ( mask & wxLIST_MASK_FORMAT )
2483 item.SetAlign(oldItem->GetAlign());
2484
2485 item.SetTextColour(oldItem->GetTextColour());
2486 item.SetBackgroundColour(oldItem->GetBackgroundColour());
2487 item.SetFont(oldItem->GetFont());
2488 }
2489 }
2490
2491 void wxMacDataBrowserListCtrlControl::MacInsertItem( unsigned int n, wxListItem* item )
2492 {
2493 wxMacDataItemBrowserControl::MacInsert(n, item->GetText());
2494 MacSetColumnInfo(n, 0, item);
2495 }
2496
2497 wxMacDataItem* wxMacDataBrowserListCtrlControl::CreateItem()
2498 {
2499 return new wxMacListCtrlItem();
2500 }
2501
2502 wxMacListCtrlItem::wxMacListCtrlItem()
2503 {
2504 m_rowItems = wxListItemList();
2505 }
2506
2507 int wxMacListCtrlItem::GetColumnImageValue( unsigned int column )
2508 {
2509 return GetColumnInfo(column)->GetImage();
2510 }
2511
2512 void wxMacListCtrlItem::SetColumnImageValue( unsigned int column, int imageIndex )
2513 {
2514 GetColumnInfo(column)->SetImage(imageIndex);
2515 }
2516
2517 const wxString& wxMacListCtrlItem::GetColumnTextValue( unsigned int column )
2518 {
2519 if ( column == 0 )
2520 return GetLabel();
2521
2522 return GetColumnInfo(column)->GetText();
2523 }
2524
2525 void wxMacListCtrlItem::SetColumnTextValue( unsigned int column, const wxString& text )
2526 {
2527 GetColumnInfo(column)->SetText(text);
2528
2529 // for compatibility with superclass APIs
2530 if ( column == 0 )
2531 SetLabel(text);
2532 }
2533
2534 wxListItem* wxMacListCtrlItem::GetColumnInfo( unsigned int column )
2535 {
2536 wxListItemList::compatibility_iterator node = m_rowItems.Item( column );
2537 wxASSERT_MSG( node, _T("invalid column index in wxMacListCtrlItem") );
2538
2539 return node->GetData();
2540 }
2541
2542 bool wxMacListCtrlItem::HasColumnInfo( unsigned int column )
2543 {
2544 return m_rowItems.GetCount() > column;
2545 }
2546
2547 void wxMacListCtrlItem::SetColumnInfo( unsigned int column, wxListItem* item )
2548 {
2549
2550 if ( column >= m_rowItems.GetCount() )
2551 {
2552 wxListItem* listItem = new wxListItem(*item);
2553 m_rowItems.Append( listItem );
2554 }
2555 else
2556 {
2557 wxListItem* listItem = GetColumnInfo( column );
2558 long mask = item->GetMask();
2559 if (mask & wxLIST_MASK_TEXT)
2560 listItem->SetText(item->GetText());
2561 if (mask & wxLIST_MASK_DATA)
2562 listItem->SetData(item->GetData());
2563 if (mask & wxLIST_MASK_IMAGE)
2564 listItem->SetImage(item->GetImage());
2565 if (mask & wxLIST_MASK_STATE)
2566 listItem->SetState(item->GetState());
2567 if (mask & wxLIST_MASK_FORMAT)
2568 listItem->SetAlign(item->GetAlign());
2569 if (mask & wxLIST_MASK_WIDTH)
2570 listItem->SetWidth(item->GetWidth());
2571
2572 listItem->SetTextColour(item->GetTextColour());
2573 listItem->SetBackgroundColour(item->GetBackgroundColour());
2574 listItem->SetFont(item->GetFont());
2575 }
2576 }
2577
2578 #endif // wxUSE_LISTCTRL