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