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