]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/listctrl_mac.cpp
changing guard to support popupwindows as well
[wxWidgets.git] / src / mac / carbon / listctrl_mac.cpp
... / ...
CommitLineData
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
44WX_DEFINE_FLAGS( wxListCtrlStyle )
45
46wxBEGIN_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
89wxEND_FLAGS( wxListCtrlStyle )
90
91IMPLEMENT_DYNAMIC_CLASS_XTI(wxListCtrl, wxControl,"wx/listctrl.h")
92
93wxBEGIN_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
97wxEND_PROPERTIES_TABLE()
98
99wxBEGIN_HANDLERS_TABLE(wxListCtrl)
100wxEND_HANDLERS_TABLE()
101
102wxCONSTRUCTOR_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
108IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
109#endif
110
111IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
112IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
113
114IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
115
116WX_DECLARE_HASH_MAP( int, wxListItem*, wxIntegerHash, wxIntegerEqual, wxListItemList );
117
118#include "wx/listimpl.cpp"
119WX_DEFINE_LIST(wxColumnList)
120
121// so we can check for column clicks
122static const EventTypeSpec eventList[] =
123{
124 { kEventClassControl, kEventControlHit },
125 { kEventClassControl, kEventControlDraw }
126};
127
128static 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
176DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacListCtrlEventHandler )
177
178class wxMacListCtrlItem : public wxMacListBoxItem
179{
180public:
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();
198protected:
199 wxListItemList m_rowItems;
200};
201
202DataBrowserDrawItemUPP gDataBrowserDrawItemUPP = NULL;
203//DataBrowserEditItemUPP gDataBrowserEditItemUPP = NULL;
204DataBrowserHitTestUPP gDataBrowserHitTestUPP = NULL;
205
206// TODO: Make a better name!!
207class wxMacDataBrowserListCtrlControl : public wxMacDataItemBrowserControl
208{
209public:
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
224protected:
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
282class wxMacListCtrlEventDelegate : public wxEvtHandler
283{
284public:
285 wxMacListCtrlEventDelegate( wxListCtrl* list, int id );
286 virtual bool ProcessEvent( wxEvent& event );
287
288private:
289 wxListCtrl* m_list;
290 int m_id;
291};
292
293wxMacListCtrlEventDelegate::wxMacListCtrlEventDelegate( wxListCtrl* list, int id )
294{
295 m_list = list;
296 m_id = id;
297}
298
299bool 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
318class wxListCtrlRenameTimer: public wxTimer
319{
320private:
321 wxListCtrl *m_owner;
322
323public:
324 wxListCtrlRenameTimer( wxListCtrl *owner );
325 void Notify();
326};
327
328//-----------------------------------------------------------------------------
329// wxListCtrlTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing
330//-----------------------------------------------------------------------------
331
332class wxListCtrlTextCtrlWrapper : public wxEvtHandler
333{
334public:
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
344protected:
345 void OnChar( wxKeyEvent &event );
346 void OnKeyUp( wxKeyEvent &event );
347 void OnKillFocus( wxFocusEvent &event );
348
349 bool AcceptChanges();
350 void Finish();
351
352private:
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
367wxListCtrlRenameTimer::wxListCtrlRenameTimer( wxListCtrl *owner )
368{
369 m_owner = owner;
370}
371
372void wxListCtrlRenameTimer::Notify()
373{
374 m_owner->OnRenameTimer();
375}
376
377//-----------------------------------------------------------------------------
378// wxListCtrlTextCtrlWrapper (internal)
379//-----------------------------------------------------------------------------
380
381BEGIN_EVENT_TABLE(wxListCtrlTextCtrlWrapper, wxEvtHandler)
382 EVT_CHAR (wxListCtrlTextCtrlWrapper::OnChar)
383 EVT_KEY_UP (wxListCtrlTextCtrlWrapper::OnKeyUp)
384 EVT_KILL_FOCUS (wxListCtrlTextCtrlWrapper::OnKillFocus)
385END_EVENT_TABLE()
386
387wxListCtrlTextCtrlWrapper::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
410void 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
423bool 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
441void 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
452void 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
470void 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
493void 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
507BEGIN_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)
513END_EVENT_TABLE()
514
515// ============================================================================
516// implementation
517// ============================================================================
518
519wxMacListControl* 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
529void 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
553class wxGenericListCtrlHook : public wxGenericListCtrl
554{
555public:
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
568protected:
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
593void 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
616void wxListCtrl::OnDblClick(wxMouseEvent& event)
617{
618 m_current = -1;
619 event.Skip();
620}
621
622#if wxABI_VERSION >= 20801
623void wxListCtrl::OnRightDown(wxMouseEvent& event)
624{
625 if (m_dbImpl)
626 FireMouseEvent(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition());
627 event.Skip();
628}
629
630void wxListCtrl::OnMiddleDown(wxMouseEvent& event)
631{
632 if (m_dbImpl)
633 FireMouseEvent(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK, event.GetPosition());
634 event.Skip();
635}
636
637void 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
655void 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
707bool 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
758wxListCtrl::~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
780void 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
804void 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
819void 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
847wxSize wxListCtrl::DoGetBestSize() const
848{
849 return wxWindow::DoGetBestSize();
850}
851
852bool 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
861bool 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
871bool 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
881wxColour 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
896bool 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
928bool 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
999int 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
1015int 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
1029bool 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)
1072int 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.
1089wxTextCtrl* 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
1098bool 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
1145bool 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
1156long 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
1176int 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
1212bool 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
1272bool wxListCtrl::SetItemImage(long item, int image, int WXUNUSED(selImage))
1273{
1274 return SetItemColumnImage(item, 0, image);
1275}
1276
1277// Sets the item image
1278bool 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
1294wxString 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
1310void 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
1325long 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
1341bool 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
1355wxRect 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
1368bool 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
1405bool 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.
1424bool 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
1433int 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
1444void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
1445{
1446 if (m_genericImpl)
1447 m_genericImpl->SetItemSpacing(spacing, isSmall);
1448}
1449
1450wxSize wxListCtrl::GetItemSpacing() const
1451{
1452 if (m_genericImpl)
1453 return m_genericImpl->GetItemSpacing();
1454
1455 return wxSize(0, 0);
1456}
1457
1458void 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
1472wxColour 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
1486void 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
1500wxColour 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
1514void 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
1528wxFont 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
1544int 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
1556wxColour 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
1569void 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
1583long 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.
1607long 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
1657wxImageList *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
1677void 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
1705void 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
1727bool wxListCtrl::Arrange(int flag)
1728{
1729 if (m_genericImpl)
1730 return m_genericImpl->Arrange(flag);
1731 return false;
1732}
1733
1734// Deletes an item
1735bool 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
1753bool 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
1769bool 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
1788bool 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.
1803void 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
1818wxTextCtrl* 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
1851bool 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
1863bool 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.
1879long 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.
1913long 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.
1935long 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)
1944long
1945wxListCtrl::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
1997int 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.
2017long 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
2042long 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
2055long 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
2068long 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.
2082long 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
2132long 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)
2155bool 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
2168bool 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
2188void wxListCtrl::OnRenameTimer()
2189{
2190 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
2191
2192 EditLabel( m_current );
2193}
2194
2195bool 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
2207void 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
2225wxString 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
2234int 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
2242int wxListCtrl::OnGetItemColumnImage(long item, long column) const
2243{
2244 if (!column)
2245 return OnGetItemImage(item);
2246
2247 return -1;
2248}
2249
2250wxListItemAttr *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
2259void 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
2292void 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
2305void 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
2323void 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
2334wxDropTarget *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
2347void 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
2361wxMacListCtrlItem::~wxMacListCtrlItem()
2362{
2363}
2364
2365void 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
2446IMPLEMENT_DYNAMIC_CLASS(wxMacDataBrowserListCtrlControl, wxMacDataItemBrowserControl )
2447
2448wxMacDataBrowserListCtrlControl::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
2520pascal 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
2538bool 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
2548pascal 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
2565enum
2566{
2567 kIconWidth = 16,
2568 kIconHeight = 16,
2569 kTextBoxHeight = 14,
2570 kIconTextSpacingV = 2,
2571 kItemPadding = 4,
2572 kContentHeight = kIconHeight + kTextBoxHeight + kIconTextSpacingV
2573};
2574
2575static 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
2598void 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
2839OSStatus 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
2942void 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
3024Boolean 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
3094wxMacDataBrowserListCtrlControl::~wxMacDataBrowserListCtrlControl()
3095{
3096}
3097
3098void 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.
3124void 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
3140void 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
3181void wxMacDataBrowserListCtrlControl::MacInsertItem( unsigned int n, wxListItem* item )
3182{
3183 wxMacDataItemBrowserControl::MacInsert(n, item->GetText());
3184 MacSetColumnInfo(n, 0, item);
3185}
3186
3187wxMacDataItem* wxMacDataBrowserListCtrlControl::CreateItem()
3188{
3189 return new wxMacListCtrlItem();
3190}
3191
3192wxMacListCtrlItem::wxMacListCtrlItem()
3193{
3194 m_rowItems = wxListItemList();
3195}
3196
3197int wxMacListCtrlItem::GetColumnImageValue( unsigned int column )
3198{
3199 if ( HasColumnInfo(column) )
3200 return GetColumnInfo(column)->GetImage();
3201
3202 return -1;
3203}
3204
3205void wxMacListCtrlItem::SetColumnImageValue( unsigned int column, int imageIndex )
3206{
3207 if ( HasColumnInfo(column) )
3208 GetColumnInfo(column)->SetImage(imageIndex);
3209}
3210
3211wxString 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
3222void 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
3232wxListItem* wxMacListCtrlItem::GetColumnInfo( unsigned int column )
3233{
3234 wxASSERT_MSG( HasColumnInfo(column), _T("invalid column index in wxMacListCtrlItem") );
3235 return m_rowItems[column];
3236}
3237
3238bool wxMacListCtrlItem::HasColumnInfo( unsigned int column )
3239{
3240 return !(m_rowItems.find( column ) == m_rowItems.end());
3241}
3242
3243void 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