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