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