]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/listctrl_mac.cpp
e761dc6e48b135490d04f51d52606f64dda6d3ee
[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
703 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
704 return false;
705 m_dbImpl = new wxMacDataBrowserListCtrlControl( this, pos, size, style );
706 m_peer = m_dbImpl;
707
708 MacPostControlCreate( pos, size );
709
710 InstallControlEventHandler( m_peer->GetControlRef() , GetwxMacListCtrlEventHandlerUPP(),
711 GetEventTypeCount(eventList), eventList, this,
712 (EventHandlerRef *)&m_macListCtrlEventHandler);
713 }
714
715 return true;
716 }
717
718 wxListCtrl::~wxListCtrl()
719 {
720 if (m_genericImpl)
721 {
722 m_genericImpl->PopEventHandler(/* deleteHandler = */ true);
723 }
724
725 if (m_ownsImageListNormal)
726 delete m_imageListNormal;
727 if (m_ownsImageListSmall)
728 delete m_imageListSmall;
729 if (m_ownsImageListState)
730 delete m_imageListState;
731
732 delete m_renameTimer;
733 }
734
735 // ----------------------------------------------------------------------------
736 // set/get/change style
737 // ----------------------------------------------------------------------------
738
739 // Add or remove a single window style
740 void wxListCtrl::SetSingleStyle(long style, bool add)
741 {
742 long flag = GetWindowStyleFlag();
743
744 // Get rid of conflicting styles
745 if ( add )
746 {
747 if ( style & wxLC_MASK_TYPE)
748 flag = flag & ~wxLC_MASK_TYPE;
749 if ( style & wxLC_MASK_ALIGN )
750 flag = flag & ~wxLC_MASK_ALIGN;
751 if ( style & wxLC_MASK_SORT )
752 flag = flag & ~wxLC_MASK_SORT;
753 }
754
755 if ( add )
756 flag |= style;
757 else
758 flag &= ~style;
759
760 SetWindowStyleFlag(flag);
761 }
762
763 // Set the whole window style
764 void wxListCtrl::SetWindowStyleFlag(long flag)
765 {
766 if ( flag != m_windowStyle )
767 {
768 m_windowStyle = flag;
769
770 if (m_genericImpl)
771 {
772 m_genericImpl->SetWindowStyleFlag(flag);
773 }
774
775 Refresh();
776 }
777 }
778
779 void wxListCtrl::DoSetSize( int x, int y, int width, int height, int sizeFlags )
780 {
781 wxControl::DoSetSize(x, y, width, height, sizeFlags);
782
783 if (m_genericImpl)
784 m_genericImpl->SetSize(0, 0, width, height, sizeFlags);
785
786 // determine if we need a horizontal scrollbar, and add it if so
787 if (m_dbImpl)
788 {
789 int totalWidth = 0;
790 for (int column = 0; column < GetColumnCount(); column++)
791 {
792 totalWidth += m_dbImpl->GetColumnWidth( column );
793 }
794
795 Boolean vertScrollBar;
796 GetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), NULL, &vertScrollBar );
797 if (totalWidth > width)
798 SetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), true, vertScrollBar );
799 else
800 SetDataBrowserHasScrollBars( m_dbImpl->GetControlRef(), false, vertScrollBar );
801 }
802 }
803
804 wxSize wxListCtrl::DoGetBestSize() const
805 {
806 return wxWindow::DoGetBestSize();
807 }
808
809 bool wxListCtrl::SetFont(const wxFont& font)
810 {
811 bool rv = true;
812 rv = wxControl::SetFont(font);
813 if (m_genericImpl)
814 rv = m_genericImpl->SetFont(font);
815 return rv;
816 }
817
818 bool wxListCtrl::SetForegroundColour(const wxColour& colour)
819 {
820 bool rv = true;
821 if (m_genericImpl)
822 rv = m_genericImpl->SetForegroundColour(colour);
823 if (m_dbImpl)
824 SetTextColour(colour);
825 return rv;
826 }
827
828 bool wxListCtrl::SetBackgroundColour(const wxColour& colour)
829 {
830 bool rv = true;
831 if (m_genericImpl)
832 rv = m_genericImpl->SetBackgroundColour(colour);
833 if (m_dbImpl)
834 m_bgColor = colour;
835 return rv;
836 }
837
838 wxColour wxListCtrl::GetBackgroundColour()
839 {
840 if (m_genericImpl)
841 return m_genericImpl->GetBackgroundColour();
842 if (m_dbImpl)
843 return m_bgColor;
844
845 return wxNullColour;
846 }
847
848 // ----------------------------------------------------------------------------
849 // accessors
850 // ----------------------------------------------------------------------------
851
852 // Gets information about this column
853 bool wxListCtrl::GetColumn(int col, wxListItem& item) const
854 {
855 if (m_genericImpl)
856 return m_genericImpl->GetColumn(col, item);
857
858 bool success = true;
859
860 if (m_dbImpl)
861 {
862 wxColumnList::compatibility_iterator node = m_colsInfo.Item( col );
863 wxASSERT_MSG( node, _T("invalid column index in wxMacListCtrlItem") );
864 wxListItem* column = node->GetData();
865
866 long mask = column->GetMask();
867 if (mask & wxLIST_MASK_TEXT)
868 item.SetText(column->GetText());
869 if (mask & wxLIST_MASK_DATA)
870 item.SetData(column->GetData());
871 if (mask & wxLIST_MASK_IMAGE)
872 item.SetImage(column->GetImage());
873 if (mask & wxLIST_MASK_STATE)
874 item.SetState(column->GetState());
875 if (mask & wxLIST_MASK_FORMAT)
876 item.SetAlign(column->GetAlign());
877 if (mask & wxLIST_MASK_WIDTH)
878 item.SetWidth(column->GetWidth());
879 }
880
881 return success;
882 }
883
884 // Sets information about this column
885 bool wxListCtrl::SetColumn(int col, wxListItem& item)
886 {
887 if (m_genericImpl)
888 return m_genericImpl->SetColumn(col, item);
889
890 if (m_dbImpl)
891 {
892 long mask = item.GetMask();
893 if ( col >= (int)m_colsInfo.GetCount() )
894 {
895 wxListItem* listItem = new wxListItem(item);
896 m_colsInfo.Append( listItem );
897 }
898 else
899 {
900 wxListItem listItem;
901 GetColumn( col, listItem );
902
903 if (mask & wxLIST_MASK_TEXT)
904 listItem.SetText(item.GetText());
905 if (mask & wxLIST_MASK_DATA)
906 listItem.SetData(item.GetData());
907 if (mask & wxLIST_MASK_IMAGE)
908 listItem.SetImage(item.GetImage());
909 if (mask & wxLIST_MASK_STATE)
910 listItem.SetState(item.GetState());
911 if (mask & wxLIST_MASK_FORMAT)
912 listItem.SetAlign(item.GetAlign());
913 if (mask & wxLIST_MASK_WIDTH)
914 listItem.SetWidth(item.GetWidth());
915 }
916
917 // change the appearance in the databrowser.
918 DataBrowserListViewHeaderDesc columnDesc;
919 columnDesc.version=kDataBrowserListViewLatestHeaderDesc;
920 verify_noerr( m_dbImpl->GetHeaderDesc( kMinColumnId + col, &columnDesc ) );
921
922 /*
923 if (item.GetMask() & wxLIST_MASK_TEXT)
924 {
925 wxFontEncoding enc;
926 if ( m_font.Ok() )
927 enc = m_font.GetEncoding();
928 else
929 enc = wxLocale::GetSystemEncoding();
930 wxMacCFStringHolder cfTitle;
931 cfTitle.Assign( item.GetText() , enc );
932 if(columnDesc.titleString)
933 CFRelease(columnDesc.titleString);
934 columnDesc.titleString = cfTitle;
935 }
936 */
937
938 if (item.GetMask() & wxLIST_MASK_IMAGE && item.GetImage() != -1 )
939 {
940 columnDesc.btnContentInfo.contentType = kControlContentIconRef;
941 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
942 if (imageList && imageList->GetImageCount() > 0 )
943 {
944 wxBitmap bmp = imageList->GetBitmap( item.GetImage() );
945 IconRef icon = bmp.GetBitmapData()->GetIconRef();
946 columnDesc.btnContentInfo.u.iconRef = icon;
947 }
948 }
949
950 verify_noerr( m_dbImpl->SetHeaderDesc( kMinColumnId + col, &columnDesc ) );
951
952 }
953 return true;
954 }
955
956 int wxListCtrl::GetColumnCount() const
957 {
958 if (m_genericImpl)
959 return m_genericImpl->GetColumnCount();
960
961 if (m_dbImpl)
962 {
963 UInt32 count;
964 m_dbImpl->GetColumnCount(&count);
965 return count;
966 }
967
968 return m_colCount;
969 }
970
971 // Gets the column width
972 int wxListCtrl::GetColumnWidth(int col) const
973 {
974 if (m_genericImpl)
975 return m_genericImpl->GetColumnWidth(col);
976
977 if (m_dbImpl)
978 {
979 return m_dbImpl->GetColumnWidth(col);
980 }
981
982 return 0;
983 }
984
985 // Sets the column width
986 bool wxListCtrl::SetColumnWidth(int col, int width)
987 {
988 if (m_genericImpl)
989 return m_genericImpl->SetColumnWidth(col, width);
990
991 if (m_dbImpl)
992 {
993 int mywidth = width;
994 if (width == wxLIST_AUTOSIZE || width == wxLIST_AUTOSIZE_USEHEADER)
995 mywidth = 150;
996
997 if (col == -1)
998 {
999 for (int column = 0; column < GetColumnCount(); column++)
1000 {
1001 wxListItem colInfo;
1002 GetColumn(col, colInfo);
1003
1004 colInfo.SetWidth(width);
1005 SetColumn(col, colInfo);
1006
1007 m_dbImpl->SetColumnWidth(col, mywidth);
1008 }
1009 }
1010 else
1011 {
1012 wxListItem colInfo;
1013 GetColumn(col, colInfo);
1014
1015 colInfo.SetWidth(width);
1016 SetColumn(col, colInfo);
1017 m_dbImpl->SetColumnWidth(col, mywidth);
1018 }
1019 return true;
1020 }
1021
1022 return false;
1023 }
1024
1025 // Gets the number of items that can fit vertically in the
1026 // visible area of the list control (list or report view)
1027 // or the total number of items in the list control (icon
1028 // or small icon view)
1029 int wxListCtrl::GetCountPerPage() const
1030 {
1031 if (m_genericImpl)
1032 return m_genericImpl->GetCountPerPage();
1033
1034 if (m_dbImpl)
1035 {
1036 }
1037
1038 return 1;
1039 }
1040
1041 // Gets the edit control for editing labels.
1042 wxTextCtrl* wxListCtrl::GetEditControl() const
1043 {
1044 if (m_genericImpl)
1045 return m_genericImpl->GetEditControl();
1046
1047 return NULL;
1048 }
1049
1050 // Gets information about the item
1051 bool wxListCtrl::GetItem(wxListItem& info) const
1052 {
1053 if (m_genericImpl)
1054 return m_genericImpl->GetItem(info);
1055
1056 if (m_dbImpl)
1057 {
1058 if (!IsVirtual())
1059 m_dbImpl->MacGetColumnInfo(info.m_itemId, info.m_col, info);
1060 else
1061 {
1062 info.SetText( OnGetItemText(info.m_itemId, info.m_col) );
1063 info.SetImage( OnGetItemColumnImage(info.m_itemId, info.m_col) );
1064 if (info.GetMask() & wxLIST_MASK_STATE)
1065 {
1066 if (IsDataBrowserItemSelected( m_dbImpl->GetControlRef(), info.m_itemId+1 ))
1067 info.SetState(info.GetState() | wxLIST_STATE_SELECTED);
1068 }
1069
1070 wxListItemAttr* attrs = OnGetItemAttr( info.m_itemId );
1071 if (attrs)
1072 {
1073 info.SetFont( attrs->GetFont() );
1074 info.SetBackgroundColour( attrs->GetBackgroundColour() );
1075 info.SetTextColour( attrs->GetTextColour() );
1076 }
1077 }
1078 }
1079 bool success = true;
1080 return success;
1081 }
1082
1083 // Sets information about the item
1084 bool wxListCtrl::SetItem(wxListItem& info)
1085 {
1086 if (m_genericImpl)
1087 return m_genericImpl->SetItem(info);
1088
1089 if (m_dbImpl)
1090 m_dbImpl->MacSetColumnInfo( info.m_itemId, info.m_col, &info );
1091
1092 return true;
1093 }
1094
1095 long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
1096 {
1097 if (m_genericImpl)
1098 return m_genericImpl->SetItem(index, col, label, imageId);
1099
1100 wxListItem info;
1101 info.m_text = label;
1102 info.m_mask = wxLIST_MASK_TEXT;
1103 info.m_itemId = index;
1104 info.m_col = col;
1105 if ( imageId > -1 )
1106 {
1107 info.m_image = imageId;
1108 info.m_mask |= wxLIST_MASK_IMAGE;
1109 }
1110 return SetItem(info);
1111 }
1112
1113
1114 // Gets the item state
1115 int wxListCtrl::GetItemState(long item, long stateMask) const
1116 {
1117 if (m_genericImpl)
1118 return m_genericImpl->GetItemState(item, stateMask);
1119
1120 if (m_dbImpl)
1121 {
1122 if ( HasFlag(wxLC_VIRTUAL) )
1123 {
1124 if (stateMask == wxLIST_STATE_SELECTED)
1125 {
1126 if (IsDataBrowserItemSelected( m_dbImpl->GetControlRef(), item+1 ))
1127 return wxLIST_STATE_SELECTED;
1128 else
1129 return 0;
1130 }
1131 }
1132 else
1133 {
1134 wxListItem info;
1135
1136 info.m_mask = wxLIST_MASK_STATE;
1137 info.m_stateMask = stateMask;
1138 info.m_itemId = item;
1139
1140 if (!GetItem(info))
1141 return 0;
1142
1143 return info.m_state;
1144 }
1145 }
1146
1147 return 0;
1148 }
1149
1150 // Sets the item state
1151 bool wxListCtrl::SetItemState(long item, long state, long stateMask)
1152 {
1153 if (m_genericImpl)
1154 return m_genericImpl->SetItemState(item, state, stateMask);
1155
1156 if (m_dbImpl)
1157 {
1158 DataBrowserSetOption option = kDataBrowserItemsAdd;
1159 if ( stateMask == wxLIST_STATE_SELECTED && state == 0 )
1160 option = kDataBrowserItemsRemove;
1161
1162 if (item == -1)
1163 {
1164 if ( HasFlag(wxLC_VIRTUAL) )
1165 {
1166 wxMacDataItemBrowserSelectionSuppressor suppressor(m_dbImpl);
1167 m_dbImpl->SetSelectedAllItems(option);
1168 }
1169 else
1170 {
1171 for(int i = 0; i < GetItemCount();i++)
1172 {
1173 wxListItem info;
1174 info.m_itemId = i;
1175 info.m_mask = wxLIST_MASK_STATE;
1176 info.m_stateMask = stateMask;
1177 info.m_state = state;
1178 SetItem(info);
1179 }
1180 }
1181 }
1182 else
1183 {
1184 if ( HasFlag(wxLC_VIRTUAL) )
1185 {
1186 long itemID = item+1;
1187 SetDataBrowserSelectedItems(m_dbImpl->GetControlRef(), 1, (DataBrowserItemID*)&itemID, option);
1188 }
1189 else
1190 {
1191 wxListItem info;
1192 info.m_itemId = item;
1193 info.m_mask = wxLIST_MASK_STATE;
1194 info.m_stateMask = stateMask;
1195 info.m_state = state;
1196 return SetItem(info);
1197 }
1198 }
1199 }
1200 return true;
1201 }
1202
1203 // Sets the item image
1204 bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
1205 {
1206 return SetItemColumnImage(item, 0, image);
1207 }
1208
1209 // Sets the item image
1210 bool wxListCtrl::SetItemColumnImage(long item, long column, int image)
1211 {
1212 if (m_genericImpl)
1213 return m_genericImpl->SetItemColumnImage(item, column, image);
1214
1215 wxListItem info;
1216
1217 info.m_mask = wxLIST_MASK_IMAGE;
1218 info.m_image = image;
1219 info.m_itemId = item;
1220 info.m_col = column;
1221
1222 return SetItem(info);
1223 }
1224
1225 // Gets the item text
1226 wxString wxListCtrl::GetItemText(long item) const
1227 {
1228 if (m_genericImpl)
1229 return m_genericImpl->GetItemText(item);
1230
1231 wxListItem info;
1232
1233 info.m_mask = wxLIST_MASK_TEXT;
1234 info.m_itemId = item;
1235
1236 if (!GetItem(info))
1237 return wxEmptyString;
1238 return info.m_text;
1239 }
1240
1241 // Sets the item text
1242 void wxListCtrl::SetItemText(long item, const wxString& str)
1243 {
1244 if (m_genericImpl)
1245 return m_genericImpl->SetItemText(item, str);
1246
1247 wxListItem info;
1248
1249 info.m_mask = wxLIST_MASK_TEXT;
1250 info.m_itemId = item;
1251 info.m_text = str;
1252
1253 SetItem(info);
1254 }
1255
1256 // Gets the item data
1257 long wxListCtrl::GetItemData(long item) const
1258 {
1259 if (m_genericImpl)
1260 return m_genericImpl->GetItemData(item);
1261
1262 wxListItem info;
1263
1264 info.m_mask = wxLIST_MASK_DATA;
1265 info.m_itemId = item;
1266
1267 if (!GetItem(info))
1268 return 0;
1269 return info.m_data;
1270 }
1271
1272 // Sets the item data
1273 bool wxListCtrl::SetItemData(long item, long data)
1274 {
1275 if (m_genericImpl)
1276 return m_genericImpl->SetItemData(item, data);
1277
1278 wxListItem info;
1279
1280 info.m_mask = wxLIST_MASK_DATA;
1281 info.m_itemId = item;
1282 info.m_data = data;
1283
1284 return SetItem(info);
1285 }
1286
1287 wxRect wxListCtrl::GetViewRect() const
1288 {
1289 wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
1290 _T("wxListCtrl::GetViewRect() only works in icon mode") );
1291
1292 if (m_genericImpl)
1293 return m_genericImpl->GetViewRect();
1294
1295 wxRect rect;
1296 return rect;
1297 }
1298
1299 // Gets the item rectangle
1300 bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
1301 {
1302 if (m_genericImpl)
1303 return m_genericImpl->GetItemRect(item, rect, code);
1304
1305
1306 if (m_dbImpl)
1307 {
1308 DataBrowserItemID id;
1309 DataBrowserPropertyID col = kMinColumnId;
1310 Rect bounds;
1311 DataBrowserPropertyPart part = kDataBrowserPropertyEnclosingPart;
1312 if ( code == wxLIST_RECT_LABEL )
1313 part = kDataBrowserPropertyTextPart;
1314 else if ( code == wxLIST_RECT_ICON )
1315 part = kDataBrowserPropertyIconPart;
1316
1317 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL) )
1318 {
1319 wxMacDataItem* thisItem = m_dbImpl->GetItemFromLine(item);
1320 id = (DataBrowserItemID) thisItem;
1321 }
1322 else
1323 id = item+1;
1324
1325 GetDataBrowserItemPartBounds( m_dbImpl->GetControlRef(), id, col, part, &bounds );
1326
1327 rect.x = bounds.left;
1328 rect.y = bounds.top;
1329 rect.width = bounds.right - bounds.left; //GetClientSize().x; // we need the width of the whole row, not just the item.
1330 rect.height = bounds.bottom - bounds.top;
1331 //fprintf("id = %d, bounds = %d, %d, %d, %d\n", id, rect.x, rect.y, rect.width, rect.height);
1332 }
1333 return true;
1334 }
1335
1336 // Gets the item position
1337 bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
1338 {
1339 if (m_genericImpl)
1340 return m_genericImpl->GetItemPosition(item, pos);
1341
1342 bool success = false;
1343
1344 if (m_dbImpl)
1345 {
1346 wxRect itemRect;
1347 GetItemRect(item, itemRect);
1348 pos = itemRect.GetPosition();
1349 success = true;
1350 }
1351
1352 return success;
1353 }
1354
1355 // Sets the item position.
1356 bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
1357 {
1358 if (m_genericImpl)
1359 return m_genericImpl->SetItemPosition(item, pos);
1360
1361 return false;
1362 }
1363
1364 // Gets the number of items in the list control
1365 int wxListCtrl::GetItemCount() const
1366 {
1367 if (m_genericImpl)
1368 return m_genericImpl->GetItemCount();
1369
1370 if (m_dbImpl)
1371 return m_dbImpl->MacGetCount();
1372
1373 return m_count;
1374 }
1375
1376 void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
1377 {
1378 if (m_genericImpl)
1379 m_genericImpl->SetItemSpacing(spacing, isSmall);
1380 }
1381
1382 wxSize wxListCtrl::GetItemSpacing() const
1383 {
1384 if (m_genericImpl)
1385 return m_genericImpl->GetItemSpacing();
1386
1387 return wxSize(0, 0);
1388 }
1389
1390 void wxListCtrl::SetItemTextColour( long item, const wxColour &col )
1391 {
1392 if (m_genericImpl)
1393 {
1394 m_genericImpl->SetItemTextColour(item, col);
1395 return;
1396 }
1397
1398 wxListItem info;
1399 info.m_itemId = item;
1400 info.SetTextColour( col );
1401 SetItem( info );
1402 }
1403
1404 wxColour wxListCtrl::GetItemTextColour( long item ) const
1405 {
1406 if (m_genericImpl)
1407 return m_genericImpl->GetItemTextColour(item);
1408
1409 if (m_dbImpl)
1410 {
1411 wxListItem info;
1412 if (GetItem(info))
1413 return info.GetTextColour();
1414 }
1415 return wxNullColour;
1416 }
1417
1418 void wxListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
1419 {
1420 if (m_genericImpl)
1421 {
1422 m_genericImpl->SetItemBackgroundColour(item, col);
1423 return;
1424 }
1425
1426 wxListItem info;
1427 info.m_itemId = item;
1428 info.SetBackgroundColour( col );
1429 SetItem( info );
1430 }
1431
1432 wxColour wxListCtrl::GetItemBackgroundColour( long item ) const
1433 {
1434 if (m_genericImpl)
1435 return m_genericImpl->GetItemBackgroundColour(item);
1436
1437 if (m_dbImpl)
1438 {
1439 wxListItem info;
1440 if (GetItem(info))
1441 return info.GetBackgroundColour();
1442 }
1443 return wxNullColour;
1444 }
1445
1446 void wxListCtrl::SetItemFont( long item, const wxFont &f )
1447 {
1448 if (m_genericImpl)
1449 {
1450 m_genericImpl->SetItemFont(item, f);
1451 return;
1452 }
1453
1454 wxListItem info;
1455 info.m_itemId = item;
1456 info.SetFont( f );
1457 SetItem( info );
1458 }
1459
1460 wxFont wxListCtrl::GetItemFont( long item ) const
1461 {
1462 if (m_genericImpl)
1463 return m_genericImpl->GetItemFont(item);
1464
1465 if (m_dbImpl)
1466 {
1467 wxListItem info;
1468 if (GetItem(info))
1469 return info.GetFont();
1470 }
1471
1472 return wxNullFont;
1473 }
1474
1475 // Gets the number of selected items in the list control
1476 int wxListCtrl::GetSelectedItemCount() const
1477 {
1478 if (m_genericImpl)
1479 return m_genericImpl->GetSelectedItemCount();
1480
1481 if (m_dbImpl)
1482 return m_dbImpl->GetSelectedItemCount(NULL, true);
1483
1484 return 0;
1485 }
1486
1487 // Gets the text colour of the listview
1488 wxColour wxListCtrl::GetTextColour() const
1489 {
1490 if (m_genericImpl)
1491 return m_genericImpl->GetTextColour();
1492
1493 // TODO: we need owner drawn list items to customize text color.
1494 if (m_dbImpl)
1495 return m_textColor;
1496
1497 return wxNullColour;
1498 }
1499
1500 // Sets the text colour of the listview
1501 void wxListCtrl::SetTextColour(const wxColour& col)
1502 {
1503 if (m_genericImpl)
1504 {
1505 m_genericImpl->SetTextColour(col);
1506 return;
1507 }
1508
1509 if (m_dbImpl)
1510 m_textColor = col;
1511 }
1512
1513 // Gets the index of the topmost visible item when in
1514 // list or report view
1515 long wxListCtrl::GetTopItem() const
1516 {
1517 if (m_genericImpl)
1518 return m_genericImpl->GetTopItem();
1519
1520 if (m_dbImpl)
1521 {
1522 int flags = 0;
1523 long item = HitTest( wxPoint(1, 1), flags);
1524 if (flags == wxLIST_HITTEST_ONITEM)
1525 return item;
1526 }
1527
1528 return 0;
1529 }
1530
1531 // Searches for an item, starting from 'item'.
1532 // 'geometry' is one of
1533 // wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1534 // 'state' is a state bit flag, one or more of
1535 // wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1536 // item can be -1 to find the first item that matches the
1537 // specified flags.
1538 // Returns the item or -1 if unsuccessful.
1539 long wxListCtrl::GetNextItem(long item, int geom, int state) const
1540 {
1541 if (m_genericImpl)
1542 return m_genericImpl->GetNextItem(item, geom, state);
1543
1544 if (m_dbImpl && geom == wxLIST_NEXT_ALL && state == wxLIST_STATE_SELECTED )
1545 {
1546 long count = m_dbImpl->MacGetCount() ;
1547 for ( long line = item + 1 ; line < count; line++ )
1548 {
1549 wxMacDataItem* id = m_dbImpl->GetItemFromLine(line);
1550 if ( m_dbImpl->IsItemSelected(id ) )
1551 return line;
1552 }
1553 return -1;
1554 }
1555
1556 return 0;
1557 }
1558
1559
1560 wxImageList *wxListCtrl::GetImageList(int which) const
1561 {
1562 if (m_genericImpl)
1563 return m_genericImpl->GetImageList(which);
1564
1565 if ( which == wxIMAGE_LIST_NORMAL )
1566 {
1567 return m_imageListNormal;
1568 }
1569 else if ( which == wxIMAGE_LIST_SMALL )
1570 {
1571 return m_imageListSmall;
1572 }
1573 else if ( which == wxIMAGE_LIST_STATE )
1574 {
1575 return m_imageListState;
1576 }
1577 return NULL;
1578 }
1579
1580 void wxListCtrl::SetImageList(wxImageList *imageList, int which)
1581 {
1582 if (m_genericImpl)
1583 {
1584 m_genericImpl->SetImageList(imageList, which);
1585 return;
1586 }
1587
1588 if ( which == wxIMAGE_LIST_NORMAL )
1589 {
1590 if (m_ownsImageListNormal) delete m_imageListNormal;
1591 m_imageListNormal = imageList;
1592 m_ownsImageListNormal = false;
1593 }
1594 else if ( which == wxIMAGE_LIST_SMALL )
1595 {
1596 if (m_ownsImageListSmall) delete m_imageListSmall;
1597 m_imageListSmall = imageList;
1598 m_ownsImageListSmall = false;
1599 }
1600 else if ( which == wxIMAGE_LIST_STATE )
1601 {
1602 if (m_ownsImageListState) delete m_imageListState;
1603 m_imageListState = imageList;
1604 m_ownsImageListState = false;
1605 }
1606 }
1607
1608 void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
1609 {
1610 if (m_genericImpl)
1611 {
1612 m_genericImpl->AssignImageList(imageList, which);
1613 return;
1614 }
1615
1616 SetImageList(imageList, which);
1617 if ( which == wxIMAGE_LIST_NORMAL )
1618 m_ownsImageListNormal = true;
1619 else if ( which == wxIMAGE_LIST_SMALL )
1620 m_ownsImageListSmall = true;
1621 else if ( which == wxIMAGE_LIST_STATE )
1622 m_ownsImageListState = true;
1623 }
1624
1625 // ----------------------------------------------------------------------------
1626 // Operations
1627 // ----------------------------------------------------------------------------
1628
1629 // Arranges the items
1630 bool wxListCtrl::Arrange(int flag)
1631 {
1632 if (m_genericImpl)
1633 return m_genericImpl->Arrange(flag);
1634 return false;
1635 }
1636
1637 // Deletes an item
1638 bool wxListCtrl::DeleteItem(long item)
1639 {
1640 if (m_genericImpl)
1641 return m_genericImpl->DeleteItem(item);
1642
1643 if (m_dbImpl)
1644 {
1645 m_dbImpl->MacDelete(item);
1646 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ITEM, GetId() );
1647 event.SetEventObject( this );
1648 event.m_itemIndex = item;
1649 GetEventHandler()->ProcessEvent( event );
1650
1651 }
1652 return true;
1653 }
1654
1655 // Deletes all items
1656 bool wxListCtrl::DeleteAllItems()
1657 {
1658 if (m_genericImpl)
1659 return m_genericImpl->DeleteAllItems();
1660
1661 if (m_dbImpl)
1662 {
1663 m_dbImpl->MacClear();
1664 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetId() );
1665 event.SetEventObject( this );
1666 GetEventHandler()->ProcessEvent( event );
1667 }
1668 return true;
1669 }
1670
1671 // Deletes all items
1672 bool wxListCtrl::DeleteAllColumns()
1673 {
1674 if (m_genericImpl)
1675 return m_genericImpl->DeleteAllColumns();
1676
1677 if (m_dbImpl)
1678 {
1679 UInt32 cols;
1680 m_dbImpl->GetColumnCount(&cols);
1681 for (UInt32 col = 0; col < cols; col++)
1682 {
1683 DeleteColumn(0);
1684 }
1685 }
1686
1687 return true;
1688 }
1689
1690 // Deletes a column
1691 bool wxListCtrl::DeleteColumn(int col)
1692 {
1693 if (m_genericImpl)
1694 return m_genericImpl->DeleteColumn(col);
1695
1696 if (m_dbImpl)
1697 {
1698 OSStatus err = m_dbImpl->RemoveColumn(col);
1699 return err == noErr;
1700 }
1701
1702 return true;
1703 }
1704
1705 // Clears items, and columns if there are any.
1706 void wxListCtrl::ClearAll()
1707 {
1708 if (m_genericImpl)
1709 {
1710 m_genericImpl->ClearAll();
1711 return;
1712 }
1713
1714 if (m_dbImpl)
1715 {
1716 DeleteAllItems();
1717 DeleteAllColumns();
1718 }
1719 }
1720
1721 wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
1722 {
1723 if (m_genericImpl)
1724 return m_genericImpl->EditLabel(item, textControlClass);
1725
1726 if (m_dbImpl)
1727 {
1728 wxCHECK_MSG( (item >= 0) && ((long)item < GetItemCount()), NULL,
1729 wxT("wrong index in wxListCtrl::EditLabel()") );
1730
1731 wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)),
1732 wxT("EditLabel() needs a text control") );
1733
1734 wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
1735 le.SetEventObject( this );
1736 le.m_itemIndex = item;
1737 le.m_col = 0;
1738 GetItem( le.m_item );
1739
1740 if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() )
1741 {
1742 // vetoed by user code
1743 return NULL;
1744 }
1745
1746 wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
1747 m_textctrlWrapper = new wxListCtrlTextCtrlWrapper(this, text, item);
1748 return m_textctrlWrapper->GetText();
1749 }
1750 return NULL;
1751 }
1752
1753 // End label editing, optionally cancelling the edit
1754 bool wxListCtrl::EndEditLabel(bool cancel)
1755 {
1756 // TODO: generic impl. doesn't have this method - is it needed for us?
1757 if (m_genericImpl)
1758 return true; // m_genericImpl->EndEditLabel(cancel);
1759
1760 if (m_dbImpl)
1761 verify_noerr( SetDataBrowserEditItem(m_dbImpl->GetControlRef(), kDataBrowserNoItem, kMinColumnId) );
1762 return true;
1763 }
1764
1765 // Ensures this item is visible
1766 bool wxListCtrl::EnsureVisible(long item)
1767 {
1768 if (m_genericImpl)
1769 return m_genericImpl->EnsureVisible(item);
1770
1771 if (m_dbImpl)
1772 {
1773 wxMacDataItem* dataItem = m_dbImpl->GetItemFromLine(item);
1774 m_dbImpl->RevealItem(dataItem, kDataBrowserRevealWithoutSelecting);
1775 }
1776
1777 return true;
1778 }
1779
1780 // Find an item whose label matches this string, starting from the item after 'start'
1781 // or the beginning if 'start' is -1.
1782 long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
1783 {
1784 if (m_genericImpl)
1785 return m_genericImpl->FindItem(start, str, partial);
1786
1787 wxString str_upper = str.Upper();
1788
1789 long idx = start;
1790 if (idx < 0)
1791 idx = 0;
1792 long count = GetItemCount();
1793
1794 while (idx < count)
1795 {
1796 wxString line_upper = GetItemText(idx).Upper();
1797 if (!partial)
1798 {
1799 if (line_upper == str_upper )
1800 return idx;
1801 }
1802 else
1803 {
1804 if (line_upper.find(str_upper) == 0)
1805 return idx;
1806 }
1807
1808 idx++;
1809 };
1810
1811 return wxNOT_FOUND;
1812 }
1813
1814 // Find an item whose data matches this data, starting from the item after 'start'
1815 // or the beginning if 'start' is -1.
1816 long wxListCtrl::FindItem(long start, long data)
1817 {
1818 if (m_genericImpl)
1819 return m_genericImpl->FindItem(start, data);
1820
1821 long idx = start;
1822 if (idx < 0)
1823 idx = 0;
1824 long count = GetItemCount();
1825
1826 while (idx < count)
1827 {
1828 if (GetItemData(idx) == data)
1829 return idx;
1830 idx++;
1831 };
1832
1833 return wxNOT_FOUND;
1834 }
1835
1836 // Find an item nearest this position in the specified direction, starting from
1837 // the item after 'start' or the beginning if 'start' is -1.
1838 long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
1839 {
1840 if (m_genericImpl)
1841 return m_genericImpl->FindItem(start, pt, direction);
1842 return -1;
1843 }
1844
1845 // Determines which item (if any) is at the specified point,
1846 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
1847 long
1848 wxListCtrl::HitTest(const wxPoint& point, int& flags, long *ptrSubItem) const
1849 {
1850 if (m_genericImpl)
1851 return m_genericImpl->HitTest(point, flags, ptrSubItem);
1852
1853 flags = wxLIST_HITTEST_NOWHERE;
1854 if (m_dbImpl)
1855 {
1856 int colHeaderHeight = 22; // TODO: Find a way to get this value from the db control?
1857 UInt16 rowHeight = 0;
1858 m_dbImpl->GetDefaultRowHeight(&rowHeight);
1859
1860 int y = point.y;
1861 // get the actual row by taking scroll position into account
1862 UInt32 offsetX, offsetY;
1863 m_dbImpl->GetScrollPosition( &offsetY, &offsetX );
1864 y += offsetY;
1865
1866 if ( !(GetWindowStyleFlag() & wxLC_NO_HEADER) )
1867 y -= colHeaderHeight;
1868
1869 if ( y < 0 )
1870 return -1;
1871
1872 int row = y / rowHeight;
1873 DataBrowserItemID id;
1874 m_dbImpl->GetItemID( (DataBrowserTableViewRowIndex) row, &id );
1875
1876 // TODO: Use GetDataBrowserItemPartBounds to return if we are in icon or label
1877 if ( !(GetWindowStyleFlag() & wxLC_VIRTUAL ) )
1878 {
1879 wxMacListCtrlItem* lcItem;
1880 lcItem = (wxMacListCtrlItem*) id;
1881 if (lcItem)
1882 {
1883 flags = wxLIST_HITTEST_ONITEM;
1884 return row;
1885 }
1886 }
1887 else
1888 {
1889 if (row < GetItemCount() )
1890 {
1891 flags = wxLIST_HITTEST_ONITEM;
1892 return row;
1893 }
1894 }
1895
1896 }
1897 return -1;
1898 }
1899
1900 int wxListCtrl::GetScrollPos(int orient) const
1901 {
1902 if (m_genericImpl)
1903 return m_genericImpl->GetScrollPos(orient);
1904
1905 if (m_dbImpl)
1906 {
1907 UInt32 offsetX, offsetY;
1908 m_dbImpl->GetScrollPosition( &offsetY, &offsetX );
1909 if ( orient == wxHORIZONTAL )
1910 return offsetX;
1911 else
1912 return offsetY;
1913 }
1914
1915 return 0;
1916 }
1917
1918 // Inserts an item, returning the index of the new item if successful,
1919 // -1 otherwise.
1920 long wxListCtrl::InsertItem(wxListItem& info)
1921 {
1922 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
1923
1924 if (m_genericImpl)
1925 return m_genericImpl->InsertItem(info);
1926
1927 if (m_dbImpl && !IsVirtual())
1928 {
1929 int count = GetItemCount();
1930
1931 if (info.m_itemId > count)
1932 info.m_itemId = count;
1933
1934 m_dbImpl->MacInsertItem(info.m_itemId, &info );
1935 wxMacDataItem* dataItem = m_dbImpl->GetItemFromLine(info.m_itemId);
1936
1937 wxListEvent event( wxEVT_COMMAND_LIST_INSERT_ITEM, GetId() );
1938 event.SetEventObject( this );
1939 event.m_itemIndex = info.m_itemId;
1940 GetEventHandler()->ProcessEvent( event );
1941 return info.m_itemId;
1942 }
1943 return -1;
1944 }
1945
1946 long wxListCtrl::InsertItem(long index, const wxString& label)
1947 {
1948 if (m_genericImpl)
1949 return m_genericImpl->InsertItem(index, label);
1950
1951 wxListItem info;
1952 info.m_text = label;
1953 info.m_mask = wxLIST_MASK_TEXT;
1954 info.m_itemId = index;
1955 return InsertItem(info);
1956 }
1957
1958 // Inserts an image item
1959 long wxListCtrl::InsertItem(long index, int imageIndex)
1960 {
1961 if (m_genericImpl)
1962 return m_genericImpl->InsertItem(index, imageIndex);
1963
1964 wxListItem info;
1965 info.m_image = imageIndex;
1966 info.m_mask = wxLIST_MASK_IMAGE;
1967 info.m_itemId = index;
1968 return InsertItem(info);
1969 }
1970
1971 // Inserts an image/string item
1972 long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
1973 {
1974 if (m_genericImpl)
1975 return m_genericImpl->InsertItem(index, label, imageIndex);
1976
1977 wxListItem info;
1978 info.m_image = imageIndex;
1979 info.m_text = label;
1980 info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
1981 info.m_itemId = index;
1982 return InsertItem(info);
1983 }
1984
1985 // For list view mode (only), inserts a column.
1986 long wxListCtrl::InsertColumn(long col, wxListItem& item)
1987 {
1988 if (m_genericImpl)
1989 return m_genericImpl->InsertColumn(col, item);
1990
1991 if (m_dbImpl)
1992 {
1993 int width = item.GetWidth();
1994 if ( !(item.GetMask() & wxLIST_MASK_WIDTH) )
1995 width = 150;
1996
1997 DataBrowserPropertyType type = kDataBrowserCustomType; //kDataBrowserTextType;
1998 wxImageList* imageList = GetImageList(wxIMAGE_LIST_SMALL);
1999 if (imageList && imageList->GetImageCount() > 0)
2000 {
2001 wxBitmap bmp = imageList->GetBitmap(0);
2002 //if (bmp.Ok())
2003 // type = kDataBrowserIconAndTextType;
2004 }
2005
2006 SInt16 just = teFlushDefault;
2007 if (item.GetMask() & wxLIST_MASK_FORMAT)
2008 {
2009 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2010 just = teFlushLeft;
2011 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2012 just = teCenter;
2013 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2014 just = teFlushRight;
2015 }
2016 m_dbImpl->InsertColumn(col, type, item.GetText(), just, width);
2017 SetColumn(col, item);
2018
2019 // set/remove options based on the wxListCtrl type.
2020 DataBrowserTableViewColumnID id;
2021 m_dbImpl->GetColumnIDFromIndex(col, &id);
2022 DataBrowserPropertyFlags flags;
2023 verify_noerr(m_dbImpl->GetPropertyFlags(id, &flags));
2024 if (GetWindowStyleFlag() & wxLC_EDIT_LABELS)
2025 flags |= kDataBrowserPropertyIsEditable;
2026
2027 if (GetWindowStyleFlag() & wxLC_VIRTUAL){
2028 flags &= ~kDataBrowserListViewSortableColumn;
2029 }
2030 verify_noerr(m_dbImpl->SetPropertyFlags(id, flags));
2031 }
2032
2033 return col;
2034 }
2035
2036 long wxListCtrl::InsertColumn(long col,
2037 const wxString& heading,
2038 int format,
2039 int width)
2040 {
2041 if (m_genericImpl)
2042 return m_genericImpl->InsertColumn(col, heading, format, width);
2043
2044 wxListItem item;
2045 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
2046 item.m_text = heading;
2047 if ( width > -1 )
2048 {
2049 item.m_mask |= wxLIST_MASK_WIDTH;
2050 item.m_width = width;
2051 }
2052 item.m_format = format;
2053
2054 return InsertColumn(col, item);
2055 }
2056
2057 // scroll the control by the given number of pixels (exception: in list view,
2058 // dx is interpreted as number of columns)
2059 bool wxListCtrl::ScrollList(int dx, int dy)
2060 {
2061 if (m_genericImpl)
2062 return m_genericImpl->ScrollList(dx, dy);
2063
2064 if (m_dbImpl)
2065 {
2066 m_dbImpl->SetScrollPosition(dx, dy);
2067 }
2068 return true;
2069 }
2070
2071
2072 bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
2073 {
2074 if (m_genericImpl)
2075 return m_genericImpl->SortItems(fn, data);
2076
2077 if (m_dbImpl)
2078 {
2079 m_compareFunc = fn;
2080 m_compareFuncData = data;
2081 SortDataBrowserContainer( m_dbImpl->GetControlRef(), kDataBrowserNoItem, true);
2082
2083 // we need to do this after each call, else we get a crash from wxPython when
2084 // SortItems is called the second time.
2085 m_compareFunc = NULL;
2086 m_compareFuncData = 0;
2087 }
2088
2089 return true;
2090 }
2091
2092 void wxListCtrl::OnRenameTimer()
2093 {
2094 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2095
2096 EditLabel( m_current );
2097 }
2098
2099 bool wxListCtrl::OnRenameAccept(long itemEdit, const wxString& value)
2100 {
2101 wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetId() );
2102 le.SetEventObject( this );
2103 le.m_itemIndex = itemEdit;
2104
2105 GetItem( le.m_item );
2106 le.m_item.m_text = value;
2107 return !GetEventHandler()->ProcessEvent( le ) ||
2108 le.IsAllowed();
2109 }
2110
2111 void wxListCtrl::OnRenameCancelled(long itemEdit)
2112 {
2113 // let owner know that the edit was cancelled
2114 wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
2115
2116 le.SetEditCanceled(true);
2117
2118 le.SetEventObject( this );
2119 le.m_itemIndex = itemEdit;
2120
2121 GetItem( le.m_item );
2122 GetEventHandler()->ProcessEvent( le );
2123 }
2124
2125 // ----------------------------------------------------------------------------
2126 // virtual list controls
2127 // ----------------------------------------------------------------------------
2128
2129 wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
2130 {
2131 // this is a pure virtual function, in fact - which is not really pure
2132 // because the controls which are not virtual don't need to implement it
2133 wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") );
2134
2135 return wxEmptyString;
2136 }
2137
2138 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
2139 {
2140 wxCHECK_MSG(!GetImageList(wxIMAGE_LIST_SMALL),
2141 -1,
2142 wxT("List control has an image list, OnGetItemImage or OnGetItemColumnImage should be overridden."));
2143 return -1;
2144 }
2145
2146 int wxListCtrl::OnGetItemColumnImage(long item, long column) const
2147 {
2148 if (!column)
2149 return OnGetItemImage(item);
2150
2151 return -1;
2152 }
2153
2154 wxListItemAttr *wxListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
2155 {
2156 wxASSERT_MSG( item >= 0 && item < GetItemCount(),
2157 _T("invalid item index in OnGetItemAttr()") );
2158
2159 // no attributes by default
2160 return NULL;
2161 }
2162
2163 void wxListCtrl::SetItemCount(long count)
2164 {
2165 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
2166
2167 if (m_genericImpl)
2168 {
2169 m_genericImpl->SetItemCount(count);
2170 return;
2171 }
2172
2173 if (m_dbImpl)
2174 {
2175 // we need to temporarily disable the new item creation notification
2176 // procedure to speed things up
2177 // FIXME: Even this doesn't seem to help much...
2178
2179 // FIXME: Find a more efficient way to do this.
2180 m_dbImpl->MacClear();
2181
2182 DataBrowserCallbacks callbacks;
2183 DataBrowserItemNotificationUPP itemUPP;
2184 GetDataBrowserCallbacks(m_dbImpl->GetControlRef(), &callbacks);
2185 itemUPP = callbacks.u.v1.itemNotificationCallback;
2186 callbacks.u.v1.itemNotificationCallback = 0;
2187 m_dbImpl->SetCallbacks(&callbacks);
2188 ::AddDataBrowserItems(m_dbImpl->GetControlRef(), kDataBrowserNoItem,
2189 count, NULL, kDataBrowserItemNoProperty);
2190 callbacks.u.v1.itemNotificationCallback = itemUPP;
2191 m_dbImpl->SetCallbacks(&callbacks);
2192 }
2193 m_count = count;
2194 }
2195
2196 void wxListCtrl::RefreshItem(long item)
2197 {
2198 if (m_genericImpl)
2199 {
2200 m_genericImpl->RefreshItem(item);
2201 return;
2202 }
2203
2204 wxRect rect;
2205 GetItemRect(item, rect);
2206 RefreshRect(rect);
2207 }
2208
2209 void wxListCtrl::RefreshItems(long itemFrom, long itemTo)
2210 {
2211 if (m_genericImpl)
2212 {
2213 m_genericImpl->RefreshItems(itemFrom, itemTo);
2214 return;
2215 }
2216
2217 wxRect rect1, rect2;
2218 GetItemRect(itemFrom, rect1);
2219 GetItemRect(itemTo, rect2);
2220
2221 wxRect rect = rect1;
2222 rect.height = rect2.GetBottom() - rect1.GetTop();
2223
2224 RefreshRect(rect);
2225 }
2226
2227 void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget )
2228 {
2229 #if wxUSE_DRAG_AND_DROP
2230 if (m_genericImpl)
2231 m_genericImpl->SetDropTarget( dropTarget );
2232
2233 if (m_dbImpl)
2234 wxWindow::SetDropTarget( dropTarget );
2235 #endif
2236 }
2237
2238 wxDropTarget *wxListCtrl::GetDropTarget() const
2239 {
2240 #if wxUSE_DRAG_AND_DROP
2241 if (m_genericImpl)
2242 return m_genericImpl->GetDropTarget();
2243
2244 if (m_dbImpl)
2245 return wxWindow::GetDropTarget();
2246 #endif
2247 return NULL;
2248 }
2249
2250 #if wxABI_VERSION >= 20801
2251 void wxListCtrl::SetFocus()
2252 {
2253 if (m_genericImpl)
2254 {
2255 m_genericImpl->SetFocus();
2256 return;
2257 }
2258
2259 wxWindow::SetFocus();
2260 }
2261 #endif
2262
2263 // wxMac internal data structures
2264
2265 wxMacListCtrlItem::~wxMacListCtrlItem()
2266 {
2267 }
2268
2269 void wxMacListCtrlItem::Notification(wxMacDataItemBrowserControl *owner ,
2270 DataBrowserItemNotification message,
2271 DataBrowserItemDataRef itemData ) const
2272 {
2273
2274 wxMacDataBrowserListCtrlControl *lb = wxDynamicCast(owner, wxMacDataBrowserListCtrlControl);
2275
2276 // we want to depend on as little as possible to make sure tear-down of controls is safe
2277 if ( message == kDataBrowserItemRemoved)
2278 {
2279 if ( lb != NULL && lb->GetClientDataType() == wxClientData_Object )
2280 {
2281 delete (wxClientData*) (m_data);
2282 }
2283
2284 delete this;
2285 return;
2286 }
2287 else if ( message == kDataBrowserItemAdded )
2288 {
2289 // we don't issue events on adding, the item is not really stored in the list yet, so we
2290 // avoid asserts by gettting out now
2291 return ;
2292 }
2293
2294 wxListCtrl *list = wxDynamicCast( owner->GetPeer() , wxListCtrl );
2295 if ( list && lb )
2296 {
2297 bool trigger = false;
2298
2299 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
2300 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
2301
2302 event.SetEventObject( list );
2303 event.m_itemIndex = owner->GetLineFromItem( this ) ;
2304 if ( !list->IsVirtual() )
2305 {
2306 lb->MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
2307 }
2308
2309 switch (message)
2310 {
2311 case kDataBrowserItemDeselected:
2312 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
2313 if ( !isSingle )
2314 trigger = !lb->IsSelectionSuppressed();
2315 break;
2316
2317 case kDataBrowserItemSelected:
2318 trigger = !lb->IsSelectionSuppressed();
2319 break;
2320
2321 case kDataBrowserItemDoubleClicked:
2322 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
2323 trigger = true;
2324 break;
2325
2326 case kDataBrowserEditStarted :
2327 // TODO : how to veto ?
2328 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
2329 trigger = true ;
2330 break ;
2331
2332 case kDataBrowserEditStopped :
2333 // TODO probably trigger only upon the value store callback, because
2334 // here IIRC we cannot veto
2335 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
2336 trigger = true ;
2337 break ;
2338
2339 default:
2340 break;
2341 }
2342
2343 if ( trigger )
2344 {
2345 // direct notification is not always having the listbox GetSelection() having in synch with event
2346 wxPostEvent( list->GetEventHandler(), event );
2347 }
2348 }
2349
2350 }
2351
2352 IMPLEMENT_DYNAMIC_CLASS(wxMacDataBrowserListCtrlControl, wxMacDataItemBrowserControl )
2353
2354 wxMacDataBrowserListCtrlControl::wxMacDataBrowserListCtrlControl( wxWindow *peer, const wxPoint& pos, const wxSize& size, long style)
2355 : wxMacDataItemBrowserControl( peer, pos, size, style )
2356 {
2357 OSStatus err = noErr;
2358 m_clientDataItemsType = wxClientData_None;
2359 m_isVirtual = false;
2360
2361 if ( style & wxLC_VIRTUAL )
2362 m_isVirtual = true;
2363
2364 DataBrowserSelectionFlags options = kDataBrowserDragSelect;
2365 if ( style & wxLC_SINGLE_SEL )
2366 {
2367 options |= kDataBrowserSelectOnlyOne;
2368 }
2369 else
2370 {
2371 options |= kDataBrowserCmdTogglesSelection;
2372 }
2373
2374 err = SetSelectionFlags( options );
2375 verify_noerr( err );
2376
2377 DataBrowserCustomCallbacks callbacks;
2378 InitializeDataBrowserCustomCallbacks( &callbacks, kDataBrowserLatestCustomCallbacks );
2379
2380 if ( gDataBrowserDrawItemUPP == NULL )
2381 gDataBrowserDrawItemUPP = NewDataBrowserDrawItemUPP(DataBrowserDrawItemProc);
2382
2383 if ( gDataBrowserHitTestUPP == NULL )
2384 gDataBrowserHitTestUPP = NewDataBrowserHitTestUPP(DataBrowserHitTestProc);
2385
2386 callbacks.u.v1.drawItemCallback = gDataBrowserDrawItemUPP;
2387 callbacks.u.v1.hitTestCallback = gDataBrowserHitTestUPP;
2388
2389 SetDataBrowserCustomCallbacks( GetControlRef(), &callbacks );
2390
2391 if ( style & wxLC_LIST )
2392 {
2393 InsertColumn(0, kDataBrowserIconAndTextType, wxEmptyString, -1, -1);
2394 verify_noerr( AutoSizeColumns() );
2395 }
2396
2397 if ( style & wxLC_LIST || style & wxLC_NO_HEADER )
2398 verify_noerr( SetHeaderButtonHeight( 0 ) );
2399
2400 if ( m_isVirtual )
2401 SetSortProperty( kMinColumnId - 1 );
2402 else
2403 SetSortProperty( kMinColumnId );
2404
2405 m_sortOrder = SortOrder_None;
2406
2407 if ( style & wxLC_SORT_DESCENDING )
2408 {
2409 SetSortOrder( kDataBrowserOrderDecreasing );
2410 }
2411 else if ( style & wxLC_SORT_ASCENDING )
2412 {
2413 SetSortOrder( kDataBrowserOrderIncreasing );
2414 }
2415
2416 if ( style & wxLC_VRULES )
2417 {
2418 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
2419 verify_noerr( DataBrowserChangeAttributes(m_controlRef, kDataBrowserAttributeListViewDrawColumnDividers, kDataBrowserAttributeNone) );
2420 #endif
2421 }
2422
2423 verify_noerr( SetHiliteStyle(kDataBrowserTableViewFillHilite ) );
2424 err = SetHasScrollBars( (style & wxHSCROLL) != 0 , true );
2425 }
2426
2427 pascal Boolean wxMacDataBrowserListCtrlControl::DataBrowserEditTextProc(
2428 ControlRef browser,
2429 DataBrowserItemID itemID,
2430 DataBrowserPropertyID property,
2431 CFStringRef theString,
2432 Rect *maxEditTextRect,
2433 Boolean *shrinkToFit)
2434 {
2435 Boolean result = false;
2436 wxMacDataBrowserListCtrlControl* ctl = wxDynamicCast(wxMacControl::GetReferenceFromNativeControl( browser ), wxMacDataBrowserListCtrlControl);
2437 if ( ctl != 0 )
2438 {
2439 result = ctl->ConfirmEditText(itemID, property, theString, maxEditTextRect, shrinkToFit);
2440 theString = CFSTR("Hello!");
2441 }
2442 return result;
2443 }
2444
2445 bool wxMacDataBrowserListCtrlControl::ConfirmEditText(
2446 DataBrowserItemID itemID,
2447 DataBrowserPropertyID property,
2448 CFStringRef theString,
2449 Rect *maxEditTextRect,
2450 Boolean *shrinkToFit)
2451 {
2452 return false;
2453 }
2454
2455 pascal void wxMacDataBrowserListCtrlControl::DataBrowserDrawItemProc(
2456 ControlRef browser,
2457 DataBrowserItemID itemID,
2458 DataBrowserPropertyID property,
2459 DataBrowserItemState itemState,
2460 const Rect *itemRect,
2461 SInt16 gdDepth,
2462 Boolean colorDevice)
2463 {
2464 wxMacDataBrowserListCtrlControl* ctl = wxDynamicCast(wxMacControl::GetReferenceFromNativeControl( browser ), wxMacDataBrowserListCtrlControl);
2465 if ( ctl != 0 )
2466 {
2467 ctl->DrawItem(itemID, property, itemState, itemRect, gdDepth, colorDevice);
2468 }
2469 }
2470
2471 // routines needed for DrawItem
2472 enum
2473 {
2474 kIconWidth = 16,
2475 kIconHeight = 16,
2476 kTextBoxHeight = 14,
2477 kIconTextSpacingV = 2,
2478 kItemPadding = 4,
2479 kContentHeight = kIconHeight + kTextBoxHeight + kIconTextSpacingV
2480 };
2481
2482 static void calculateCGDrawingBounds(CGRect inItemRect, CGRect *outIconRect, CGRect *outTextRect, bool hasIcon = false)
2483 {
2484 float textBottom;
2485 float iconH, iconW = 0;
2486 float padding = kItemPadding;
2487 if (hasIcon)
2488 {
2489 iconH = kIconHeight;
2490 iconW = kIconWidth;
2491 padding = padding*2;
2492 }
2493
2494 textBottom = inItemRect.origin.y;
2495
2496 *outIconRect = CGRectMake(inItemRect.origin.x + kItemPadding,
2497 textBottom + kIconTextSpacingV, kIconWidth,
2498 kIconHeight);
2499
2500 *outTextRect = CGRectMake(inItemRect.origin.x + padding + iconW,
2501 textBottom + kIconTextSpacingV, inItemRect.size.width - padding - iconW,
2502 inItemRect.size.height - kIconTextSpacingV);
2503 }
2504
2505 void wxMacDataBrowserListCtrlControl::DrawItem(
2506 DataBrowserItemID itemID,
2507 DataBrowserPropertyID property,
2508 DataBrowserItemState itemState,
2509 const Rect *itemRect,
2510 SInt16 gdDepth,
2511 Boolean colorDevice)
2512 {
2513 wxString text;
2514 wxFont font = wxNullFont;
2515 int imgIndex = -1;
2516 short listColumn = property - kMinColumnId;
2517
2518 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2519 wxMacListCtrlItem* lcItem;
2520 wxColour color = *wxBLACK;
2521 wxColour bgColor = wxNullColour;
2522
2523 if (listColumn >= 0)
2524 {
2525 if (!m_isVirtual)
2526 {
2527 lcItem = (wxMacListCtrlItem*) itemID;
2528 if (lcItem->HasColumnInfo(listColumn)){
2529 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2530
2531 // we always use the 0 column to get font and text/background colors.
2532 if (lcItem->HasColumnInfo(0))
2533 {
2534 wxListItem* firstItem = lcItem->GetColumnInfo(0);
2535 color = firstItem->GetTextColour();
2536 bgColor = firstItem->GetBackgroundColour();
2537 font = firstItem->GetFont();
2538 }
2539
2540 if (item->GetMask() & wxLIST_MASK_TEXT)
2541 text = item->GetText();
2542 if (item->GetMask() & wxLIST_MASK_IMAGE)
2543 imgIndex = item->GetImage();
2544 }
2545
2546 }
2547 else
2548 {
2549 text = list->OnGetItemText( (long)itemID-1, listColumn );
2550 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2551 wxListItemAttr* attrs = list->OnGetItemAttr( (long)itemID-1 );
2552 if (attrs)
2553 {
2554 if (attrs->HasBackgroundColour())
2555 bgColor = attrs->GetBackgroundColour();
2556 if (attrs->HasTextColour())
2557 color = attrs->GetTextColour();
2558 if (attrs->HasFont())
2559 font = attrs->GetFont();
2560 }
2561 }
2562 }
2563
2564 wxColour listBgColor = list->GetBackgroundColour();
2565 if (bgColor == wxNullColour)
2566 bgColor = listBgColor;
2567
2568 wxFont listFont = list->GetFont();
2569 if (font == wxNullFont)
2570 font = listFont;
2571
2572 wxMacCFStringHolder cfString;
2573 cfString.Assign( text, wxLocale::GetSystemEncoding() );
2574
2575 Rect enclosingRect;
2576 CGRect enclosingCGRect, iconCGRect, textCGRect;
2577 Boolean active;
2578 ThemeDrawingState savedState = NULL;
2579 CGContextRef context = (CGContextRef)list->MacGetDrawingContext();
2580 RGBColor labelColor;
2581 labelColor.red = 0;
2582 labelColor.green = 0;
2583 labelColor.blue = 0;
2584
2585 RGBColor backgroundColor;
2586 backgroundColor.red = 255;
2587 backgroundColor.green = 255;
2588 backgroundColor.blue = 255;
2589
2590 GetDataBrowserItemPartBounds(GetControlRef(), itemID, property, kDataBrowserPropertyEnclosingPart,
2591 &enclosingRect);
2592
2593 enclosingCGRect = CGRectMake(enclosingRect.left,
2594 enclosingRect.top,
2595 enclosingRect.right - enclosingRect.left,
2596 enclosingRect.bottom - enclosingRect.top);
2597
2598 active = IsControlActive(GetControlRef());
2599
2600 // don't paint the background over the vertical rule line
2601 if ( list->GetWindowStyleFlag() & wxLC_VRULES )
2602 {
2603 enclosingCGRect.origin.x += 1;
2604 enclosingCGRect.size.width -= 1;
2605 }
2606 if (itemState == kDataBrowserItemIsSelected)
2607 {
2608
2609 GetThemeDrawingState(&savedState);
2610
2611 GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &backgroundColor);
2612 GetThemeTextColor(kThemeTextColorWhite, gdDepth, colorDevice, &labelColor);
2613
2614 CGContextSaveGState(context);
2615
2616 CGContextSetRGBFillColor(context, (float)backgroundColor.red / (float)USHRT_MAX,
2617 (float)backgroundColor.green / (float)USHRT_MAX,
2618 (float)backgroundColor.blue / (float)USHRT_MAX, 1.0);
2619 CGContextFillRect(context, enclosingCGRect);
2620
2621 CGContextRestoreGState(context);
2622 }
2623 else
2624 {
2625
2626 if (color.Ok())
2627 labelColor = MAC_WXCOLORREF( color.GetPixel() );
2628 else if (list->GetTextColour().Ok())
2629 labelColor = MAC_WXCOLORREF( list->GetTextColour().GetPixel() );
2630
2631 if (bgColor.Ok())
2632 {
2633 backgroundColor = MAC_WXCOLORREF( bgColor.GetPixel() );
2634 CGContextSaveGState(context);
2635
2636 CGContextSetRGBFillColor(context, (float)backgroundColor.red / (float)USHRT_MAX,
2637 (float)backgroundColor.green / (float)USHRT_MAX,
2638 (float)backgroundColor.blue / (float)USHRT_MAX, 1.0);
2639 CGContextFillRect(context, enclosingCGRect);
2640
2641 CGContextRestoreGState(context);
2642 }
2643 }
2644
2645 calculateCGDrawingBounds(enclosingCGRect, &iconCGRect, &textCGRect, (imgIndex != -1) );
2646
2647 if (imgIndex != -1)
2648 {
2649 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2650 if (imageList && imageList->GetImageCount() > 0){
2651 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2652 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2653
2654 CGContextSaveGState(context);
2655 CGContextTranslateCTM(context, 0,iconCGRect.origin.y + CGRectGetMaxY(iconCGRect));
2656 CGContextScaleCTM(context,1.0f,-1.0f);
2657 PlotIconRefInContext(context, &iconCGRect, kAlignNone,
2658 active ? kTransformNone : kTransformDisabled, NULL,
2659 kPlotIconRefNormalFlags, icon);
2660
2661 CGContextRestoreGState(context);
2662 }
2663 }
2664
2665 HIThemeTextHorizontalFlush hFlush = kHIThemeTextHorizontalFlushLeft;
2666 UInt16 fontID = kThemeViewsFont;
2667
2668 if (font.Ok())
2669 {
2670 if (font.GetFamily() != wxFONTFAMILY_DEFAULT)
2671 fontID = font.MacGetThemeFontID();
2672
2673 // FIXME: replace these with CG or ATSUI calls so we can remove this #ifndef.
2674 #ifndef __LP64__
2675 ::TextSize( (short)(font.MacGetFontSize()) ) ;
2676 ::TextFace( font.MacGetFontStyle() ) ;
2677 #endif
2678 }
2679
2680 wxListItem item;
2681 list->GetColumn(listColumn, item);
2682 if (item.GetMask() & wxLIST_MASK_FORMAT)
2683 {
2684 if (item.GetAlign() == wxLIST_FORMAT_LEFT)
2685 hFlush = kHIThemeTextHorizontalFlushLeft;
2686 else if (item.GetAlign() == wxLIST_FORMAT_CENTER)
2687 hFlush = kHIThemeTextHorizontalFlushCenter;
2688 else if (item.GetAlign() == wxLIST_FORMAT_RIGHT)
2689 {
2690 hFlush = kHIThemeTextHorizontalFlushRight;
2691 textCGRect.origin.x -= kItemPadding; // give a little extra paddding
2692 }
2693 }
2694
2695 HIThemeTextInfo info;
2696 info.version = kHIThemeTextInfoVersionZero;
2697 info.state = active ? kThemeStateActive : kThemeStateInactive;
2698 info.fontID = fontID;
2699 info.horizontalFlushness = hFlush;
2700 info.verticalFlushness = kHIThemeTextVerticalFlushCenter;
2701 info.options = kHIThemeTextBoxOptionNone;
2702 info.truncationPosition = kHIThemeTextTruncationEnd;
2703 info.truncationMaxLines = 1;
2704
2705 CGContextSaveGState(context);
2706 CGContextSetRGBFillColor (context, (float)labelColor.red / (float)USHRT_MAX,
2707 (float)labelColor.green / (float)USHRT_MAX,
2708 (float)labelColor.blue / (float)USHRT_MAX, 1.0);
2709
2710 HIThemeDrawTextBox(cfString, &textCGRect, &info, context, kHIThemeOrientationNormal);
2711
2712 CGContextRestoreGState(context);
2713
2714 if (savedState != NULL)
2715 SetThemeDrawingState(savedState, true);
2716 }
2717
2718 OSStatus wxMacDataBrowserListCtrlControl::GetSetItemData(DataBrowserItemID itemID,
2719 DataBrowserPropertyID property,
2720 DataBrowserItemDataRef itemData,
2721 Boolean changeValue )
2722 {
2723 wxString text;
2724 int imgIndex = -1;
2725 short listColumn = property - kMinColumnId;
2726
2727 OSStatus err = errDataBrowserPropertyNotSupported;
2728 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2729 wxMacListCtrlItem* lcItem;
2730
2731 if (listColumn >= 0)
2732 {
2733 if (!m_isVirtual)
2734 {
2735 lcItem = (wxMacListCtrlItem*) itemID;
2736 if (lcItem && lcItem->HasColumnInfo(listColumn)){
2737 wxListItem* item = lcItem->GetColumnInfo(listColumn);
2738 if (item->GetMask() & wxLIST_MASK_TEXT)
2739 text = item->GetText();
2740 if (item->GetMask() & wxLIST_MASK_IMAGE)
2741 imgIndex = item->GetImage();
2742 }
2743 }
2744 else
2745 {
2746 text = list->OnGetItemText( (long)itemID-1, listColumn );
2747 imgIndex = list->OnGetItemColumnImage( (long)itemID-1, listColumn );
2748 }
2749 }
2750
2751 if ( !changeValue )
2752 {
2753 switch (property)
2754 {
2755 case kDataBrowserItemIsEditableProperty :
2756 if ( list && list->HasFlag( wxLC_EDIT_LABELS ) )
2757 {
2758 verify_noerr(SetDataBrowserItemDataBooleanValue( itemData, true ));
2759 err = noErr ;
2760 }
2761 break ;
2762 default :
2763 if ( property >= kMinColumnId )
2764 {
2765 wxMacCFStringHolder cfStr;
2766
2767 if (text){
2768 cfStr.Assign( text, wxLocale::GetSystemEncoding() );
2769 err = ::SetDataBrowserItemDataText( itemData, cfStr );
2770 err = noErr;
2771 }
2772
2773
2774
2775 if ( imgIndex != -1 )
2776 {
2777 wxImageList* imageList = list->GetImageList(wxIMAGE_LIST_SMALL);
2778 if (imageList && imageList->GetImageCount() > 0){
2779 wxBitmap bmp = imageList->GetBitmap(imgIndex);
2780 IconRef icon = bmp.GetBitmapData()->GetIconRef();
2781 ::SetDataBrowserItemDataIcon(itemData, icon);
2782 }
2783 }
2784
2785 }
2786 break ;
2787 }
2788
2789 }
2790 else
2791 {
2792 switch (property)
2793 {
2794 default:
2795 if ( property >= kMinColumnId )
2796 {
2797 short listColumn = property - kMinColumnId;
2798
2799 // TODO probably send the 'end edit' from here, as we
2800 // can then deal with the veto
2801 CFStringRef sr ;
2802 verify_noerr( GetDataBrowserItemDataText( itemData , &sr ) ) ;
2803 wxMacCFStringHolder cfStr(sr) ;;
2804 if (m_isVirtual)
2805 list->SetItem( (long)itemData-1 , listColumn, cfStr.AsString() ) ;
2806 else
2807 {
2808 if (lcItem)
2809 lcItem->SetColumnTextValue( listColumn, cfStr.AsString() );
2810 }
2811 err = noErr ;
2812 }
2813 break;
2814 }
2815 }
2816 return err;
2817 }
2818
2819 void wxMacDataBrowserListCtrlControl::ItemNotification(DataBrowserItemID itemID,
2820 DataBrowserItemNotification message,
2821 DataBrowserItemDataRef itemData )
2822 {
2823 // we want to depend on as little as possible to make sure tear-down of controls is safe
2824 if ( message == kDataBrowserItemRemoved)
2825 {
2826 // make sure MacDelete does the proper teardown.
2827 return;
2828 }
2829 else if ( message == kDataBrowserItemAdded )
2830 {
2831 // we don't issue events on adding, the item is not really stored in the list yet, so we
2832 // avoid asserts by getting out now
2833 return ;
2834 }
2835
2836 wxListCtrl *list = wxDynamicCast( GetPeer() , wxListCtrl );
2837 if ( list )
2838 {
2839 bool trigger = false;
2840
2841 wxListEvent event( wxEVT_COMMAND_LIST_ITEM_SELECTED, list->GetId() );
2842 bool isSingle = (list->GetWindowStyle() & wxLC_SINGLE_SEL) != 0;
2843
2844 event.SetEventObject( list );
2845 if ( !list->IsVirtual() )
2846 {
2847 DataBrowserTableViewRowIndex result = 0;
2848 verify_noerr( GetItemRow( itemID, &result ) ) ;
2849 event.m_itemIndex = result;
2850
2851 if (event.m_itemIndex >= 0)
2852 MacGetColumnInfo(event.m_itemIndex,0,event.m_item);
2853 }
2854 else
2855 {
2856 event.m_itemIndex = (long)itemID-1;
2857 }
2858
2859 switch (message)
2860 {
2861 case kDataBrowserItemDeselected:
2862 event.SetEventType(wxEVT_COMMAND_LIST_ITEM_DESELECTED);
2863 if ( !isSingle )
2864 trigger = !IsSelectionSuppressed();
2865 break;
2866
2867 case kDataBrowserItemSelected:
2868 trigger = !IsSelectionSuppressed();
2869
2870 break;
2871
2872 case kDataBrowserItemDoubleClicked:
2873 event.SetEventType( wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
2874 trigger = true;
2875 break;
2876
2877 case kDataBrowserEditStarted :
2878 // TODO : how to veto ?
2879 event.SetEventType( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT ) ;
2880 trigger = true ;
2881 break ;
2882
2883 case kDataBrowserEditStopped :
2884 // TODO probably trigger only upon the value store callback, because
2885 // here IIRC we cannot veto
2886 event.SetEventType( wxEVT_COMMAND_LIST_END_LABEL_EDIT ) ;
2887 trigger = true ;
2888 break ;
2889
2890 default:
2891 break;
2892 }
2893
2894 if ( trigger )
2895 {
2896 // direct notification is not always having the listbox GetSelection() having in synch with event
2897 wxPostEvent( list->GetEventHandler(), event );
2898 }
2899 }
2900 }
2901
2902 Boolean wxMacDataBrowserListCtrlControl::CompareItems(DataBrowserItemID itemOneID,
2903 DataBrowserItemID itemTwoID,
2904 DataBrowserPropertyID sortProperty)
2905 {
2906
2907 bool retval = false;
2908 wxString itemText;
2909 wxString otherItemText;
2910 long itemOrder;
2911 long otherItemOrder;
2912
2913 int colId = sortProperty - kMinColumnId;
2914
2915 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2916
2917 DataBrowserSortOrder sort;
2918 verify_noerr(GetSortOrder(&sort));
2919
2920 if (colId >= 0)
2921 {
2922 if (!m_isVirtual)
2923 {
2924 wxMacListCtrlItem* item = (wxMacListCtrlItem*)itemOneID;
2925 wxMacListCtrlItem* otherItem = (wxMacListCtrlItem*)itemTwoID;
2926
2927 itemOrder = item->GetOrder();
2928 otherItemOrder = item->GetOrder();
2929
2930 wxListCtrlCompare func = list->GetCompareFunc();
2931 if (func != NULL)
2932 {
2933 long item1 = -1;
2934 long item2 = -1;
2935 if (item && item->HasColumnInfo(0))
2936 item1 = item->GetColumnInfo(0)->GetData();
2937 if (otherItem && otherItem->HasColumnInfo(0))
2938 item2 = otherItem->GetColumnInfo(0)->GetData();
2939
2940 if (item1 > -1 && item2 > -1)
2941 {
2942 int result = func(item1, item2, list->GetCompareFuncData());
2943 if (sort == kDataBrowserOrderIncreasing)
2944 return result >= 0;
2945 else
2946 return result < 0;
2947 }
2948 }
2949
2950 // we can't use the native control's sorting abilities, so just
2951 // sort by item id.
2952 return itemOrder < otherItemOrder;
2953 }
2954 else
2955 {
2956
2957 long itemNum = (long)itemOneID;
2958 long otherItemNum = (long)itemTwoID;
2959 itemText = list->OnGetItemText( itemNum-1, colId );
2960 otherItemText = list->OnGetItemText( otherItemNum-1, colId );
2961
2962 // virtual listctrls don't support sorting
2963 return itemNum < otherItemNum;
2964 }
2965 }
2966 else{
2967 // fallback for undefined cases
2968 retval = itemOneID < itemTwoID;
2969 }
2970
2971 return retval;
2972 }
2973
2974 wxMacDataBrowserListCtrlControl::~wxMacDataBrowserListCtrlControl()
2975 {
2976 }
2977
2978 void wxMacDataBrowserListCtrlControl::MacSetColumnInfo( unsigned int row, unsigned int column, wxListItem* item )
2979 {
2980 wxMacDataItem* dataItem = GetItemFromLine(row);
2981 wxASSERT_MSG( dataItem, _T("could not obtain wxMacDataItem for row in MacSetColumnInfo. Is row a valid wxListCtrl row?") );
2982 if (item)
2983 {
2984 wxMacListCtrlItem* listItem = wx_static_cast(wxMacListCtrlItem*,dataItem);
2985 bool hasInfo = listItem->HasColumnInfo( column );
2986 listItem->SetColumnInfo( column, item );
2987 listItem->SetOrder(row);
2988 UpdateState(dataItem, item);
2989
2990 wxListCtrl* list = wxDynamicCast( GetPeer() , wxListCtrl );
2991
2992 // NB: When this call was made before a control was completely shown, it would
2993 // update the item prematurely (i.e. no text would be listed) and, on show,
2994 // only the sorted column would be refreshed, meaning only first column text labels
2995 // would be shown. Making sure not to update items until the control is visible
2996 // seems to fix this issue.
2997 if (hasInfo && list->IsShown())
2998 UpdateItem( wxMacDataBrowserRootContainer, listItem , kMinColumnId + column );
2999 }
3000 }
3001
3002 // apply changes that need to happen immediately, rather than when the
3003 // databrowser control fires a callback.
3004 void wxMacDataBrowserListCtrlControl::UpdateState(wxMacDataItem* dataItem, wxListItem* listItem)
3005 {
3006 bool isSelected = IsItemSelected( dataItem );
3007 bool isSelectedState = (listItem->GetState() == wxLIST_STATE_SELECTED);
3008
3009 // toggle the selection state if wxListInfo state and actual state don't match.
3010 if ( isSelected != isSelectedState )
3011 {
3012 DataBrowserSetOption options = kDataBrowserItemsAdd;
3013 if (!isSelectedState)
3014 options = kDataBrowserItemsRemove;
3015 SetSelectedItem(dataItem, options);
3016 }
3017 // TODO: Set column width if item width > than current column width
3018 }
3019
3020 void wxMacDataBrowserListCtrlControl::MacGetColumnInfo( unsigned int row, unsigned int column, wxListItem& item )
3021 {
3022 wxMacDataItem* dataItem = GetItemFromLine(row);
3023 wxASSERT_MSG( dataItem, _T("could not obtain wxMacDataItem in MacGetColumnInfo. Is row a valid wxListCtrl row?") );
3024 // CS should this guard against dataItem = 0 ? , as item is not a pointer if (item) is not appropriate
3025 //if (item)
3026 {
3027 wxMacListCtrlItem* listItem =wx_static_cast(wxMacListCtrlItem*,dataItem);
3028
3029 if (!listItem->HasColumnInfo( column ))
3030 return;
3031
3032 wxListItem* oldItem = listItem->GetColumnInfo( column );
3033
3034 if (oldItem)
3035 {
3036 long mask = item.GetMask();
3037 if ( !mask )
3038 // by default, get everything for backwards compatibility
3039 mask = -1;
3040
3041 if ( mask & wxLIST_MASK_TEXT )
3042 item.SetText(oldItem->GetText());
3043 if ( mask & wxLIST_MASK_IMAGE )
3044 item.SetImage(oldItem->GetImage());
3045 if ( mask & wxLIST_MASK_DATA )
3046 item.SetData(oldItem->GetData());
3047 if ( mask & wxLIST_MASK_STATE )
3048 item.SetState(oldItem->GetState());
3049 if ( mask & wxLIST_MASK_WIDTH )
3050 item.SetWidth(oldItem->GetWidth());
3051 if ( mask & wxLIST_MASK_FORMAT )
3052 item.SetAlign(oldItem->GetAlign());
3053
3054 item.SetTextColour(oldItem->GetTextColour());
3055 item.SetBackgroundColour(oldItem->GetBackgroundColour());
3056 item.SetFont(oldItem->GetFont());
3057 }
3058 }
3059 }
3060
3061 void wxMacDataBrowserListCtrlControl::MacInsertItem( unsigned int n, wxListItem* item )
3062 {
3063 wxMacDataItemBrowserControl::MacInsert(n, item->GetText());
3064 MacSetColumnInfo(n, 0, item);
3065 }
3066
3067 wxMacDataItem* wxMacDataBrowserListCtrlControl::CreateItem()
3068 {
3069 return new wxMacListCtrlItem();
3070 }
3071
3072 wxMacListCtrlItem::wxMacListCtrlItem()
3073 {
3074 m_rowItems = wxListItemList();
3075 }
3076
3077 int wxMacListCtrlItem::GetColumnImageValue( unsigned int column )
3078 {
3079 if ( HasColumnInfo(column) )
3080 return GetColumnInfo(column)->GetImage();
3081
3082 return -1;
3083 }
3084
3085 void wxMacListCtrlItem::SetColumnImageValue( unsigned int column, int imageIndex )
3086 {
3087 if ( HasColumnInfo(column) )
3088 GetColumnInfo(column)->SetImage(imageIndex);
3089 }
3090
3091 wxString wxMacListCtrlItem::GetColumnTextValue( unsigned int column )
3092 {
3093 if ( column == 0 )
3094 return GetLabel();
3095
3096 if ( HasColumnInfo(column) )
3097 return GetColumnInfo(column)->GetText();
3098
3099 return wxEmptyString;
3100 }
3101
3102 void wxMacListCtrlItem::SetColumnTextValue( unsigned int column, const wxString& text )
3103 {
3104 if ( HasColumnInfo(column) )
3105 GetColumnInfo(column)->SetText(text);
3106
3107 // for compatibility with superclass APIs
3108 if ( column == 0 )
3109 SetLabel(text);
3110 }
3111
3112 wxListItem* wxMacListCtrlItem::GetColumnInfo( unsigned int column )
3113 {
3114 wxASSERT_MSG( HasColumnInfo(column), _T("invalid column index in wxMacListCtrlItem") );
3115 return m_rowItems[column];
3116 }
3117
3118 bool wxMacListCtrlItem::HasColumnInfo( unsigned int column )
3119 {
3120 return !(m_rowItems.find( column ) == m_rowItems.end());
3121 }
3122
3123 void wxMacListCtrlItem::SetColumnInfo( unsigned int column, wxListItem* item )
3124 {
3125
3126 if ( !HasColumnInfo(column) )
3127 {
3128 wxListItem* listItem = new wxListItem(*item);
3129 m_rowItems[column] = listItem;
3130 }
3131 else
3132 {
3133 wxListItem* listItem = GetColumnInfo( column );
3134 long mask = item->GetMask();
3135 if (mask & wxLIST_MASK_TEXT)
3136 listItem->SetText(item->GetText());
3137 if (mask & wxLIST_MASK_DATA)
3138 listItem->SetData(item->GetData());
3139 if (mask & wxLIST_MASK_IMAGE)
3140 listItem->SetImage(item->GetImage());
3141 if (mask & wxLIST_MASK_STATE)
3142 listItem->SetState(item->GetState());
3143 if (mask & wxLIST_MASK_FORMAT)
3144 listItem->SetAlign(item->GetAlign());
3145 if (mask & wxLIST_MASK_WIDTH)
3146 listItem->SetWidth(item->GetWidth());
3147
3148 if ( item->HasAttributes() )
3149 {
3150 if ( listItem->HasAttributes() )
3151 listItem->GetAttributes()->AssignFrom(*item->GetAttributes());
3152 else
3153 {
3154 listItem->SetTextColour(item->GetTextColour());
3155 listItem->SetBackgroundColour(item->GetBackgroundColour());
3156 listItem->SetFont(item->GetFont());
3157 }
3158 }
3159 }
3160 }
3161
3162 #endif // wxUSE_LISTCTRL