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