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