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