1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/datavgen.cpp 
   3 // Purpose:     wxDataViewCtrl generic implementation 
   4 // Author:      Robert Roebling 
   5 // Modified by: Francesco Montorsi, Guru Kathiresan, Otto Wyss 
   7 // Copyright:   (c) 1998 Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 // For compilers that support precompilation, includes "wx.h". 
  12 #include "wx/wxprec.h" 
  18 #if wxUSE_DATAVIEWCTRL 
  20 #include "wx/dataview.h" 
  22 #ifdef wxUSE_GENERICDATAVIEWCTRL 
  26         #include "wx/msw/private.h" 
  27         #include "wx/msw/wrapwin.h" 
  28         #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  32     #include "wx/dcclient.h" 
  34     #include "wx/settings.h" 
  35     #include "wx/msgdlg.h" 
  38 #include "wx/stockitem.h" 
  39 #include "wx/calctrl.h" 
  40 #include "wx/popupwin.h" 
  41 #include "wx/renderer.h" 
  42 #include "wx/dcbuffer.h" 
  45 //----------------------------------------------------------------------------- 
  47 //----------------------------------------------------------------------------- 
  51 static const int SCROLL_UNIT_X 
= 15; 
  53 // the cell padding on the left/right 
  54 static const int PADDING_RIGHTLEFT 
= 3; 
  56 // the cell padding on the top/bottom 
  57 static const int PADDING_TOPBOTTOM 
= 1; 
  60 //----------------------------------------------------------------------------- 
  61 // wxDataViewHeaderWindow 
  62 //----------------------------------------------------------------------------- 
  64 #define USE_NATIVE_HEADER_WINDOW    1 
  66 class wxDataViewHeaderWindowBase 
: public wxControl
 
  69     wxDataViewHeaderWindowBase() 
  72     bool Create(wxDataViewCtrl 
*parent
, wxWindowID id
, 
  73                 const wxPoint 
&pos
, const wxSize 
&size
,  
  76         return wxWindow::Create(parent
, id
, pos
, size
, wxNO_BORDER
, name
); 
  79     void SetOwner( wxDataViewCtrl
* owner 
) { m_owner 
= owner
; } 
  80     wxDataViewCtrl 
*GetOwner() { return m_owner
; } 
  82     // called on column addition/removal 
  83     virtual void UpdateDisplay() { /* by default, do nothing */ } 
  85     // returns the n-th column 
  86     virtual wxDataViewColumn 
*GetColumn(unsigned int n
) 
  89         wxDataViewColumn 
*ret 
= m_owner
->GetColumn(n
);  
  96     wxDataViewCtrl      
*m_owner
; 
  98     // sends an event generated from the n-th wxDataViewColumn 
  99     void SendEvent(wxEventType type
, unsigned int n
); 
 102 // on wxMSW the header window (only that part however) can be made native! 
 103 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW 
 105 #define COLUMN_WIDTH_OFFSET         2 
 106 #define wxDataViewHeaderWindowMSW   wxDataViewHeaderWindow 
 108 class wxDataViewHeaderWindowMSW 
: public wxDataViewHeaderWindowBase
 
 112     wxDataViewHeaderWindowMSW( wxDataViewCtrl 
*parent
, 
 114                                const wxPoint 
&pos 
= wxDefaultPosition
, 
 115                                const wxSize 
&size 
= wxDefaultSize
, 
 116                                const wxString 
&name 
= wxT("wxdataviewctrlheaderwindow") ) 
 118         Create(parent
, id
, pos
, size
, name
); 
 121     bool Create(wxDataViewCtrl 
*parent
, wxWindowID id
, 
 122                 const wxPoint 
&pos
, const wxSize 
&size
,  
 123                 const wxString 
&name
); 
 125     ~wxDataViewHeaderWindowMSW(); 
 127     // called when any column setting is changed and/or changed 
 129     virtual void UpdateDisplay(); 
 131     // called when the main window gets scrolled 
 132     virtual void ScrollWindow(int dx
, int dy
, const wxRect 
*rect 
= NULL
); 
 135     virtual bool MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
); 
 136     virtual void DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
); 
 138     unsigned int GetColumnIdxFromHeader(NMHEADER 
*nmHDR
); 
 140     wxDataViewColumn 
*GetColumnFromHeader(NMHEADER 
*nmHDR
) 
 141         { return GetColumn(GetColumnIdxFromHeader(nmHDR
)); } 
 144     DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW
) 
 147 #else       // !defined(__WXMSW__) 
 149 #define HEADER_WINDOW_HEIGHT            25 
 150 #define HEADER_HORIZ_BORDER             5 
 151 #define HEADER_VERT_BORDER              3 
 152 #define wxGenericDataViewHeaderWindow   wxDataViewHeaderWindow 
 154 class wxGenericDataViewHeaderWindow 
: public wxDataViewHeaderWindowBase
 
 157     wxGenericDataViewHeaderWindow( wxDataViewCtrl 
*parent
, 
 159                                     const wxPoint 
&pos 
= wxDefaultPosition
, 
 160                                     const wxSize 
&size 
= wxDefaultSize
, 
 161                                     const wxString 
&name 
= wxT("wxdataviewctrlheaderwindow") ) 
 164         Create(parent
, id
, pos
, size
, name
); 
 167     bool Create(wxDataViewCtrl 
*parent
, wxWindowID id
, 
 168                 const wxPoint 
&pos
, const wxSize 
&size
,  
 169                 const wxString 
&name
); 
 171     ~wxGenericDataViewHeaderWindow() 
 173         delete m_resizeCursor
; 
 178     void OnPaint( wxPaintEvent 
&event 
); 
 179     void OnMouse( wxMouseEvent 
&event 
); 
 180     void OnSetFocus( wxFocusEvent 
&event 
); 
 185     // vars used for column resizing: 
 187     wxCursor            
*m_resizeCursor
; 
 188     const wxCursor      
*m_currentCursor
; 
 191     bool                 m_dirty
;     // needs refresh? 
 192     int                  m_column
;    // index of the column being resized 
 193     int                  m_currentX
;  // divider line position in logical (unscrolled) coords 
 194     int                  m_minX
;      // minimal position beyond which the divider line  
 195                                       // can't be dragged in logical coords 
 197     // the pen used to draw the current column width drag line 
 198     // when resizing the columsn 
 202     // internal utilities: 
 206         m_currentCursor 
= (wxCursor 
*) NULL
; 
 207         m_resizeCursor 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 209         m_isDragging 
= false; 
 212         m_column 
= wxNOT_FOUND
; 
 216         wxColour col 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 217         m_penCurrent 
= wxPen(col
, 1, wxSOLID
); 
 221     void AdjustDC(wxDC
& dc
); 
 224     DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow
) 
 225     DECLARE_EVENT_TABLE() 
 228 #endif      // defined(__WXMSW__) 
 230 //----------------------------------------------------------------------------- 
 231 // wxDataViewRenameTimer 
 232 //----------------------------------------------------------------------------- 
 234 class wxDataViewRenameTimer
: public wxTimer
 
 237     wxDataViewMainWindow 
*m_owner
; 
 240     wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
); 
 244 //----------------------------------------------------------------------------- 
 245 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing 
 246 //----------------------------------------------------------------------------- 
 248 class wxDataViewTextCtrlWrapper 
: public wxEvtHandler
 
 251     // NB: text must be a valid object but not Create()d yet 
 252     wxDataViewTextCtrlWrapper( wxDataViewMainWindow 
*owner
, 
 254                                wxDataViewListModel 
*model
, 
 255                                unsigned int col
, unsigned int row
, 
 258     wxTextCtrl 
*GetText() const { return m_text
; } 
 260     void AcceptChangesAndFinish(); 
 263     void OnChar( wxKeyEvent 
&event 
); 
 264     void OnKeyUp( wxKeyEvent 
&event 
); 
 265     void OnKillFocus( wxFocusEvent 
&event 
); 
 267     bool AcceptChanges(); 
 271     wxDataViewMainWindow   
*m_owner
; 
 273     wxString                m_startValue
; 
 274     wxDataViewListModel    
*m_model
; 
 278     bool                    m_aboutToFinish
; 
 280     DECLARE_EVENT_TABLE() 
 283 //----------------------------------------------------------------------------- 
 284 // wxDataViewMainWindow 
 285 //----------------------------------------------------------------------------- 
 287 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
,  
 290 class wxDataViewMainWindow
: public wxWindow
 
 293     wxDataViewMainWindow( wxDataViewCtrl 
*parent
, 
 295                             const wxPoint 
&pos 
= wxDefaultPosition
, 
 296                             const wxSize 
&size 
= wxDefaultSize
, 
 297                             const wxString 
&name 
= wxT("wxdataviewctrlmainwindow") ); 
 298     virtual ~wxDataViewMainWindow(); 
 300     // notifications from wxDataViewListModel 
 303     bool RowInserted( unsigned int before 
); 
 304     bool RowDeleted( unsigned int row 
); 
 305     bool RowChanged( unsigned int row 
); 
 306     bool ValueChanged( unsigned int col
, unsigned int row 
); 
 307     bool RowsReordered( unsigned int *new_order 
); 
 310     void SetOwner( wxDataViewCtrl
* owner 
) { m_owner 
= owner
; } 
 311     wxDataViewCtrl 
*GetOwner() { return m_owner
; } 
 312     const wxDataViewCtrl 
*GetOwner() const { return m_owner
; } 
 314     void OnPaint( wxPaintEvent 
&event 
); 
 315     void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
); 
 316     void OnChar( wxKeyEvent 
&event 
); 
 317     void OnMouse( wxMouseEvent 
&event 
); 
 318     void OnSetFocus( wxFocusEvent 
&event 
); 
 319     void OnKillFocus( wxFocusEvent 
&event 
); 
 321     void UpdateDisplay(); 
 322     void RecalculateDisplay(); 
 323     void OnInternalIdle(); 
 325     void OnRenameTimer(); 
 326     void FinishEditing( wxTextCtrl 
*text 
); 
 328     void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
= NULL 
); 
 330     bool HasCurrentRow() { return m_currentRow 
!= (unsigned int)-1; } 
 331     void ChangeCurrentRow( unsigned int row 
); 
 333     bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); }; 
 334     bool IsEmpty() { return GetRowCount() == 0; } 
 336     int GetCountPerPage() const; 
 337     int GetEndOfLastCol() const; 
 338     unsigned int GetFirstVisibleRow() const; 
 339     unsigned int GetLastVisibleRow() const; 
 340     unsigned int GetRowCount() const; 
 342     void Select( const wxArrayInt
& aSelections 
); 
 343     void SelectAllRows( bool on 
); 
 344     void SelectRow( unsigned int row
, bool on 
); 
 345     void SelectRows( unsigned int from
, unsigned int to
, bool on 
); 
 346     void ReverseRowSelection( unsigned int row 
); 
 347     bool IsRowSelected( unsigned int row 
); 
 349     void RefreshRow( unsigned int row 
); 
 350     void RefreshRows( unsigned int from
, unsigned int to 
); 
 351     void RefreshRowsAfter( unsigned int firstRow 
); 
 353     // returns the colour to be used for drawing the rules 
 354     wxColour 
GetRuleColour() const 
 356         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 359     //void EnsureVisible( unsigned int row ); 
 360     wxRect 
GetLineRect( unsigned int row 
) const; 
 363     wxDataViewCtrl             
*m_owner
; 
 367     wxDataViewColumn           
*m_currentCol
; 
 368     unsigned int                      m_currentRow
; 
 369     wxDataViewSelection         m_selection
; 
 371     wxDataViewRenameTimer      
*m_renameTimer
; 
 372     wxDataViewTextCtrlWrapper  
*m_textctrlWrapper
; 
 380     // for double click logic 
 381     unsigned int m_lineLastClicked
, 
 382            m_lineBeforeLastClicked
, 
 383            m_lineSelectSingleOnUp
; 
 385     // the pen used to draw horiz/vertical rules 
 389     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
) 
 390     DECLARE_EVENT_TABLE() 
 393 // --------------------------------------------------------- 
 394 // wxGenericDataViewListModelNotifier 
 395 // --------------------------------------------------------- 
 397 class wxGenericDataViewListModelNotifier
: public wxDataViewListModelNotifier
 
 400     wxGenericDataViewListModelNotifier( wxDataViewMainWindow 
*mainWindow 
) 
 401         { m_mainWindow 
= mainWindow
; } 
 403     virtual bool RowAppended() 
 404         { return m_mainWindow
->RowAppended(); } 
 405     virtual bool RowPrepended() 
 406         { return m_mainWindow
->RowPrepended(); } 
 407     virtual bool RowInserted( unsigned int before 
) 
 408         { return m_mainWindow
->RowInserted( before 
); } 
 409     virtual bool RowDeleted( unsigned int row 
) 
 410         { return m_mainWindow
->RowDeleted( row 
); } 
 411     virtual bool RowChanged( unsigned int row 
) 
 412         { return m_mainWindow
->RowChanged( row 
); } 
 413     virtual bool ValueChanged( unsigned int col
, unsigned int row 
) 
 414         { return m_mainWindow
->ValueChanged( col
, row 
); } 
 415     virtual bool RowsReordered( unsigned int *new_order 
) 
 416         { return m_mainWindow
->RowsReordered( new_order 
); } 
 417     virtual bool Cleared() 
 418         { return m_mainWindow
->Cleared(); } 
 420     wxDataViewMainWindow    
*m_mainWindow
; 
 423 // --------------------------------------------------------- 
 424 // wxDataViewRenderer 
 425 // --------------------------------------------------------- 
 427 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
) 
 429 wxDataViewRenderer::wxDataViewRenderer( const wxString 
&varianttype
,  
 430                                         wxDataViewCellMode mode
, 
 432     wxDataViewRendererBase( varianttype
, mode
, align 
) 
 439 wxDataViewRenderer::~wxDataViewRenderer() 
 445 wxDC 
*wxDataViewRenderer::GetDC() 
 449         if (GetOwner() == NULL
) 
 451         if (GetOwner()->GetOwner() == NULL
) 
 453         m_dc 
= new wxClientDC( GetOwner()->GetOwner() ); 
 460 // --------------------------------------------------------- 
 461 // wxDataViewCustomRenderer 
 462 // --------------------------------------------------------- 
 464 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
) 
 466 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString 
&varianttype
, 
 467                           wxDataViewCellMode mode
, int align 
) : 
 468     wxDataViewRenderer( varianttype
, mode
, align 
) 
 472 // --------------------------------------------------------- 
 473 // wxDataViewTextRenderer 
 474 // --------------------------------------------------------- 
 476 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewCustomRenderer
) 
 478 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString 
&varianttype
,  
 479                                                 wxDataViewCellMode mode
, int align 
) : 
 480     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 484 bool wxDataViewTextRenderer::SetValue( const wxVariant 
&value 
) 
 486     m_text 
= value
.GetString(); 
 491 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 496 bool wxDataViewTextRenderer::Render( wxRect cell
, wxDC 
*dc
, int state 
) 
 498     wxDataViewCtrl 
*view 
= GetOwner()->GetOwner(); 
 499     wxColour col 
= (state 
& wxDATAVIEW_CELL_SELECTED
) ? 
 500                         wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) : 
 501                         view
->GetForegroundColour(); 
 503     dc
->SetTextForeground(col
); 
 504     dc
->DrawText( m_text
, cell
.x
, cell
.y 
); 
 509 wxSize 
wxDataViewTextRenderer::GetSize() const 
 511     const wxDataViewCtrl 
*view 
= GetView(); 
 515         view
->GetTextExtent( m_text
, &x
, &y 
); 
 516         return wxSize( x
, y 
); 
 518     return wxSize(80,20); 
 521 // --------------------------------------------------------- 
 522 // wxDataViewBitmapRenderer 
 523 // --------------------------------------------------------- 
 525 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewCustomRenderer
) 
 527 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString 
&varianttype
,  
 528                                                     wxDataViewCellMode mode
, int align 
) : 
 529     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 533 bool wxDataViewBitmapRenderer::SetValue( const wxVariant 
&value 
) 
 535     if (value
.GetType() == wxT("wxBitmap")) 
 537     if (value
.GetType() == wxT("wxIcon")) 
 543 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 548 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 551         dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y 
); 
 552     else if (m_icon
.Ok()) 
 553         dc
->DrawIcon( m_icon
, cell
.x
, cell
.y 
); 
 558 wxSize 
wxDataViewBitmapRenderer::GetSize() const 
 561         return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() ); 
 562     else if (m_icon
.Ok()) 
 563         return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() ); 
 565     return wxSize(16,16); 
 568 // --------------------------------------------------------- 
 569 // wxDataViewToggleRenderer 
 570 // --------------------------------------------------------- 
 572 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewCustomRenderer
) 
 574 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString 
&varianttype
, 
 575                         wxDataViewCellMode mode
, int align 
) : 
 576     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 581 bool wxDataViewToggleRenderer::SetValue( const wxVariant 
&value 
) 
 583     m_toggle 
= value
.GetBool(); 
 588 bool wxDataViewToggleRenderer::GetValue( wxVariant 
&WXUNUSED(value
) ) const 
 593 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 595     // User wxRenderer here 
 598     rect
.x 
= cell
.x 
+ cell
.width
/2 - 10; 
 600     rect
.y 
= cell
.y 
+ cell
.height
/2 - 10; 
 605         flags 
|= wxCONTROL_CHECKED
; 
 606     if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
) 
 607         flags 
|= wxCONTROL_DISABLED
; 
 609     wxRendererNative::Get().DrawCheckBox( 
 610             GetOwner()->GetOwner(), 
 618 bool wxDataViewToggleRenderer::Activate( wxRect 
WXUNUSED(cell
),  
 619                                          wxDataViewListModel 
*model
,  
 620                                          unsigned int col
, unsigned int row 
) 
 622     bool value 
= !m_toggle
; 
 623     wxVariant variant 
= value
; 
 624     model
->SetValue( variant
, col
, row 
); 
 625     model
->ValueChanged( col
, row 
); 
 629 wxSize 
wxDataViewToggleRenderer::GetSize() const 
 631     return wxSize(20,20); 
 634 // --------------------------------------------------------- 
 635 // wxDataViewProgressRenderer 
 636 // --------------------------------------------------------- 
 638 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
) 
 640 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString 
&label
, 
 641     const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
 642     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 648 wxDataViewProgressRenderer::~wxDataViewProgressRenderer() 
 652 bool wxDataViewProgressRenderer::SetValue( const wxVariant 
&value 
) 
 654     m_value 
= (long) value
; 
 656     if (m_value 
< 0) m_value 
= 0; 
 657     if (m_value 
> 100) m_value 
= 100; 
 662 bool wxDataViewProgressRenderer::GetValue( wxVariant 
&value 
) const 
 664     value 
= (long) m_value
; 
 668 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 670     double pct 
= (double)m_value 
/ 100.0; 
 672     bar
.width 
= (int)(cell
.width 
* pct
); 
 673     dc
->SetPen( *wxTRANSPARENT_PEN 
); 
 674     dc
->SetBrush( *wxBLUE_BRUSH 
); 
 675     dc
->DrawRectangle( bar 
); 
 677     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
 678     dc
->SetPen( *wxBLACK_PEN 
); 
 679     dc
->DrawRectangle( cell 
); 
 684 wxSize 
wxDataViewProgressRenderer::GetSize() const 
 686     return wxSize(40,12); 
 689 // --------------------------------------------------------- 
 690 // wxDataViewDateRenderer 
 691 // --------------------------------------------------------- 
 693 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN) 
 695 #if wxUSE_DATE_RENDERER_POPUP 
 697 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
 
 700     wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime 
*value
, 
 701         wxDataViewListModel 
*model
, unsigned int col
, unsigned int row 
) : 
 702         wxPopupTransientWindow( parent
, wxBORDER_SIMPLE 
) 
 707         m_cal 
= new wxCalendarCtrl( this, wxID_ANY
, *value 
); 
 708         wxBoxSizer 
*sizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 709         sizer
->Add( m_cal
, 1, wxGROW 
); 
 714     void OnCalendar( wxCalendarEvent 
&event 
); 
 716     wxCalendarCtrl      
*m_cal
; 
 717     wxDataViewListModel 
*m_model
; 
 722     virtual void OnDismiss() 
 727     DECLARE_EVENT_TABLE() 
 730 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
) 
 731     EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar 
) 
 734 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent 
&event 
) 
 736     wxDateTime date 
= event
.GetDate(); 
 737     wxVariant value 
= date
; 
 738     m_model
->SetValue( value
, m_col
, m_row 
); 
 739     m_model
->ValueChanged( m_col
, m_row 
); 
 743 #endif // wxUSE_DATE_RENDERER_POPUP 
 745 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
) 
 747 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString 
&varianttype
, 
 748                         wxDataViewCellMode mode
, int align 
) : 
 749     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 753 bool wxDataViewDateRenderer::SetValue( const wxVariant 
&value 
) 
 755     m_date 
= value
.GetDateTime(); 
 760 bool wxDataViewDateRenderer::GetValue( wxVariant 
&value 
) const 
 766 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 768     dc
->SetFont( GetOwner()->GetOwner()->GetFont() ); 
 769     wxString tmp 
= m_date
.FormatDate(); 
 770     dc
->DrawText( tmp
, cell
.x
, cell
.y 
); 
 775 wxSize 
wxDataViewDateRenderer::GetSize() const 
 777     const wxDataViewCtrl
* view 
= GetView(); 
 778     wxString tmp 
= m_date
.FormatDate(); 
 780     view
->GetTextExtent( tmp
, &x
, &y
, &d 
); 
 781     return wxSize(x
,y
+d
); 
 784 bool wxDataViewDateRenderer::Activate( wxRect 
WXUNUSED(cell
), wxDataViewListModel 
*model
,  
 785                                        unsigned int col
, unsigned int row 
) 
 788     model
->GetValue( variant
, col
, row 
); 
 789     wxDateTime value 
= variant
.GetDateTime(); 
 791 #if wxUSE_DATE_RENDERER_POPUP 
 792     wxDataViewDateRendererPopupTransient 
*popup 
= new wxDataViewDateRendererPopupTransient( 
 793         GetOwner()->GetOwner()->GetParent(), &value
, model
, col
, row 
); 
 794     wxPoint pos 
= wxGetMousePosition(); 
 797     popup
->Popup( popup
->m_cal 
); 
 798 #else // !wxUSE_DATE_RENDERER_POPUP 
 799     wxMessageBox(value
.Format()); 
 800 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP 
 804 // --------------------------------------------------------- 
 806 // --------------------------------------------------------- 
 808 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
) 
 810 wxDataViewColumn::wxDataViewColumn( const wxString 
&title
, wxDataViewRenderer 
*cell
,  
 811                                     unsigned int model_column
, 
 812                                     int width
, wxAlignment align
, int flags 
) : 
 813     wxDataViewColumnBase( title
, cell
, model_column
, width
, align
, flags 
) 
 819     Init(width 
< 0 ? wxDVC_DEFAULT_WIDTH 
: width
); 
 822 wxDataViewColumn::wxDataViewColumn( const wxBitmap 
&bitmap
, wxDataViewRenderer 
*cell
,  
 823                                     unsigned int model_column
, 
 824                                     int width
, wxAlignment align
, int flags 
) : 
 825     wxDataViewColumnBase( bitmap
, cell
, model_column
, width
, align
, flags 
) 
 830     Init(width 
< 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH 
: width
); 
 833 wxDataViewColumn::~wxDataViewColumn() 
 837 void wxDataViewColumn::Init( int width 
) 
 840     m_minWidth 
= wxDVC_DEFAULT_MINWIDTH
; 
 843 void wxDataViewColumn::SetResizeable( bool resizeable 
) 
 846         m_flags 
|= wxDATAVIEW_COL_RESIZABLE
; 
 848         m_flags 
&= ~wxDATAVIEW_COL_RESIZABLE
; 
 851 void wxDataViewColumn::SetHidden( bool hidden 
) 
 854         m_flags 
|= wxDATAVIEW_COL_HIDDEN
; 
 856         m_flags 
&= ~wxDATAVIEW_COL_HIDDEN
; 
 858     // tell our owner to e.g. update its scrollbars: 
 860         GetOwner()->OnColumnChange(); 
 863 void wxDataViewColumn::SetSortable( bool sortable 
) 
 866         m_flags 
|= wxDATAVIEW_COL_SORTABLE
; 
 868         m_flags 
&= ~wxDATAVIEW_COL_SORTABLE
; 
 871 void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending
) ) 
 876 bool wxDataViewColumn::IsSortOrderAscending() const 
 882 void wxDataViewColumn::SetInternalWidth( int width 
) 
 886     // the scrollbars of the wxDataViewCtrl needs to be recalculated! 
 887     if (m_owner 
&& m_owner
->m_clientArea
) 
 888         m_owner
->m_clientArea
->RecalculateDisplay(); 
 891 void wxDataViewColumn::SetWidth( int width 
) 
 893     m_owner
->m_headerArea
->UpdateDisplay(); 
 895     SetInternalWidth(width
); 
 899 //----------------------------------------------------------------------------- 
 900 // wxDataViewHeaderWindowBase 
 901 //----------------------------------------------------------------------------- 
 903 void wxDataViewHeaderWindowBase::SendEvent(wxEventType type
, unsigned int n
) 
 905     wxWindow 
*parent 
= GetParent(); 
 906     wxDataViewEvent 
le(type
, parent
->GetId()); 
 908     le
.SetEventObject(parent
); 
 910     le
.SetDataViewColumn(GetColumn(n
)); 
 911     le
.SetModel(GetOwner()->GetModel()); 
 913     // for events created by wxDataViewHeaderWindow the 
 914     // row / value fields are not valid 
 916     parent
->GetEventHandler()->ProcessEvent(le
); 
 919 #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW 
 921 // implemented in msw/listctrl.cpp: 
 922 unsigned int wxMSWGetColumnClicked(NMHDR 
*nmhdr
, POINT 
*ptClick
); 
 924 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW
, wxWindow
) 
 926 bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl 
*parent
, wxWindowID id
, 
 927                                         const wxPoint 
&pos
, const wxSize 
&size
,  
 928                                         const wxString 
&name 
) 
 932     if ( !CreateControl(parent
, id
, pos
, size
, 0, wxDefaultValidator
, name
) ) 
 935     int x 
= pos
.x 
== wxDefaultCoord 
? 0 : pos
.x
, 
 936         y 
= pos
.y 
== wxDefaultCoord 
? 0 : pos
.y
, 
 937         w 
= size
.x 
== wxDefaultCoord 
? 1 : size
.x
, 
 938         h 
= size
.y 
== wxDefaultCoord 
? 22 : size
.y
; 
 940     // create the native WC_HEADER window: 
 941     WXHWND hwndParent 
= (HWND
)parent
->GetHandle(); 
 942     WXDWORD msStyle 
= WS_CHILD 
| HDS_BUTTONS 
| HDS_HORZ 
| HDS_HOTTRACK 
| HDS_FULLDRAG
; 
 943     m_hWnd 
= CreateWindowEx(0,  
 954         wxLogLastError(_T("CreateWindowEx")); 
 958     // we need to subclass the m_hWnd to force wxWindow::HandleNotify 
 959     // to call wxDataViewHeaderWindow::MSWOnNotify 
 962     // the following is required to get the default win's font for  
 963     // header windows and must be done befor sending the HDM_LAYOUT msg 
 970     // Retrieve the bounding rectangle of the parent window's  
 971     // client area, and then request size and position values  
 972     // from the header control.  
 973     ::GetClientRect((HWND
)hwndParent
, &rcParent
);  
 977     if (!SendMessage((HWND
)m_hWnd
, HDM_LAYOUT
, 0, (LPARAM
) &hdl
))  
 979         wxLogLastError(_T("SendMessage")); 
 983     // Set the size, position, and visibility of the header control.  
 984     SetWindowPos((HWND
)m_hWnd
,  
 988                  wp
.flags 
| SWP_SHOWWINDOW
); 
 990     // set our size hints: wxDataViewCtrl will put this wxWindow inside 
 991     // a wxBoxSizer and in order to avoid super-big header windows, 
 992     // we need to set our height as fixed 
 993     SetMinSize(wxSize(-1, wp
.cy
)); 
 994     SetMaxSize(wxSize(-1, wp
.cy
)); 
 999 wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow() 
1004 void wxDataViewHeaderWindowMSW::UpdateDisplay() 
1006     // remove old columns 
1007     for (int i
=0, max
=Header_GetItemCount((HWND
)m_hWnd
); i 
< max
; i
++) 
1008         Header_DeleteItem((HWND
)m_hWnd
, 0); 
1010     // add the updated array of columns to the header control 
1011     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1012     unsigned int added 
= 0; 
1013     for (unsigned int i 
= 0; i 
< cols
; i
++) 
1015         wxDataViewColumn 
*col 
= GetColumn( i 
); 
1016         if (col
->IsHidden()) 
1017             continue;      // don't add it! 
1020         hdi
.mask 
= HDI_TEXT 
| HDI_FORMAT 
| HDI_WIDTH
; 
1021         hdi
.pszText 
= (wxChar 
*) col
->GetTitle().c_str(); 
1022         hdi
.cxy 
= col
->GetWidth(); 
1023         hdi
.cchTextMax 
= sizeof(hdi
.pszText
)/sizeof(hdi
.pszText
[0]); 
1024         hdi
.fmt 
= HDF_LEFT 
| HDF_STRING
; 
1026         // lParam is reserved for application's use: 
1027         // we store there the column index to use it later in MSWOnNotify 
1028         // (since columns may have been hidden) 
1029         hdi
.lParam 
= (LPARAM
)i
; 
1031         // the native wxMSW implementation of the header window 
1032         // draws the column separator COLUMN_WIDTH_OFFSET pixels  
1033         // on the right: to correct this effect we make the column 
1034         // exactly COLUMN_WIDTH_OFFSET wider (for the first column): 
1036             hdi
.cxy 
+= COLUMN_WIDTH_OFFSET
; 
1038         switch (col
->GetAlignment()) 
1041             hdi
.fmt 
|= HDF_LEFT
; 
1043         case wxALIGN_CENTER
: 
1044         case wxALIGN_CENTER_HORIZONTAL
: 
1045             hdi
.fmt 
|= HDF_CENTER
; 
1048             hdi
.fmt 
|= HDF_RIGHT
; 
1052             // such alignment is not allowed for the column header! 
1056         SendMessage((HWND
)m_hWnd
, HDM_INSERTITEM
,  
1057                     (WPARAM
)added
, (LPARAM
)&hdi
);  
1062 unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER 
*nmHDR
) 
1066     // NOTE: we don't just return nmHDR->iItem because when there are 
1067     //       hidden columns, nmHDR->iItem may be different from 
1068     //       nmHDR->pitem->lParam 
1070     if (nmHDR
->pitem 
&& nmHDR
->pitem
->mask 
& HDI_LPARAM
) 
1072         idx 
= (unsigned int)nmHDR
->pitem
->lParam
; 
1077     item
.mask 
= HDI_LPARAM
; 
1078     Header_GetItem((HWND
)m_hWnd
, nmHDR
->iItem
, &item
); 
1080     return (unsigned int)item
.lParam
; 
1083 bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
1085     NMHDR 
*nmhdr 
= (NMHDR 
*)lParam
; 
1087     // is it a message from the header? 
1088     if ( nmhdr
->hwndFrom 
!= (HWND
)m_hWnd 
) 
1089         return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
); 
1091     NMHEADER 
*nmHDR 
= (NMHEADER 
*)nmhdr
; 
1092     switch ( nmhdr
->code 
) 
1094         case HDN_BEGINTRACK
: 
1095             // user has started to resize a column: 
1096             // do we need to veto it? 
1097             if (!GetColumn(nmHDR
->iItem
)->IsResizeable()) 
1105             // user has started to reorder a column 
1108         case HDN_ITEMCHANGING
: 
1109             if (nmHDR
->pitem 
!= NULL 
&&  
1110                 (nmHDR
->pitem
->mask 
& HDI_WIDTH
) != 0) 
1112                 int minWidth 
= GetColumnFromHeader(nmHDR
)->GetMinWidth(); 
1113                 if (nmHDR
->pitem
->cxy 
< minWidth
) 
1115                     // do not allow the user to resize this column under  
1116                     // its minimal width: 
1122         case HDN_ITEMCHANGED
:   // user is resizing a column 
1123         case HDN_ENDTRACK
:      // user has finished resizing a column 
1124         case HDN_ENDDRAG
:       // user has finished reordering a column 
1126             // update the width of the modified column: 
1127             if (nmHDR
->pitem 
!= NULL 
&&  
1128                 (nmHDR
->pitem
->mask 
& HDI_WIDTH
) != 0) 
1130                 unsigned int idx 
= GetColumnIdxFromHeader(nmHDR
); 
1131                 unsigned int w 
= nmHDR
->pitem
->cxy
; 
1132                 wxDataViewColumn 
*col 
= GetColumn(idx
); 
1134                 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET 
1135                 if (idx 
== 0 && w 
> COLUMN_WIDTH_OFFSET
) 
1136                     w 
-= COLUMN_WIDTH_OFFSET
; 
1138                 if (w 
>= (unsigned)col
->GetMinWidth()) 
1139                     col
->SetInternalWidth(w
); 
1145                 unsigned int idx 
= GetColumnIdxFromHeader(nmHDR
); 
1146                 wxEventType evt 
= nmHDR
->iButton 
== 0 ?  
1147                         wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK 
: 
1148                         wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
; 
1149                 SendEvent(evt
, idx
); 
1155                 // NOTE: for some reason (i.e. for a bug in Windows) 
1156                 //       the HDN_ITEMCLICK notification is not sent on 
1157                 //       right clicks, so we need to handle NM_RCLICK 
1160                 int column 
= wxMSWGetColumnClicked(nmhdr
, &ptClick
); 
1161                 if (column 
!= wxNOT_FOUND
) 
1164                     item
.mask 
= HDI_LPARAM
; 
1165                     Header_GetItem((HWND
)m_hWnd
, column
, &item
); 
1167                     // 'idx' may be different from 'column' if there are 
1168                     // hidden columns... 
1169                     unsigned int idx 
= (unsigned int)item
.lParam
; 
1170                     SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
, 
1176         case HDN_GETDISPINFOW
: 
1177             // see wxListCtrl::MSWOnNotify for more info! 
1180         case HDN_ITEMDBLCLICK
: 
1182                 unsigned int idx 
= GetColumnIdxFromHeader(nmHDR
); 
1183                 int w 
= GetOwner()->GetBestColumnWidth(idx
); 
1185                 // update the native control: 
1187                 ZeroMemory(&hd
, sizeof(hd
)); 
1188                 hd
.mask 
= HDI_WIDTH
; 
1190                 Header_SetItem(GetHwnd(),  
1191                                nmHDR
->iItem
,  // NOTE: we don't want 'idx' here! 
1194                 // update the wxDataViewColumn class: 
1195                 GetColumn(idx
)->SetInternalWidth(w
); 
1200             return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
); 
1206 void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx
), int WXUNUSED(dy
),  
1207                                              const wxRect 
*WXUNUSED(rect
)) 
1209     wxSize ourSz 
= GetClientSize(); 
1210     wxSize ownerSz 
= m_owner
->GetClientSize(); 
1212     // where should the (logical) origin of this window be placed? 
1214     m_owner
->CalcUnscrolledPosition(0, 0, &x1
, &y1
); 
1216     // put this window on top of our parent and  
1217     SetWindowPos((HWND
)m_hWnd
, HWND_TOP
, -x1
, 0,  
1218                   ownerSz
.GetWidth() + x1
, ourSz
.GetHeight(),  
1222 void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
),  
1223                                           int WXUNUSED(w
), int WXUNUSED(h
),  
1226     // the wxDataViewCtrl's internal wxBoxSizer will call this function when 
1227     // the wxDataViewCtrl window gets resized: the following dummy call 
1228     // to ScrollWindow() is required in order to get this header window 
1229     // correctly repainted when it's (horizontally) scrolled: 
1234 #else       // !defined(__WXMSW__) 
1236 IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow
, wxWindow
) 
1237 BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow
, wxWindow
) 
1238     EVT_PAINT         (wxGenericDataViewHeaderWindow::OnPaint
) 
1239     EVT_MOUSE_EVENTS  (wxGenericDataViewHeaderWindow::OnMouse
) 
1240     EVT_SET_FOCUS     (wxGenericDataViewHeaderWindow::OnSetFocus
) 
1243 bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl 
*parent
, wxWindowID id
, 
1244                                            const wxPoint 
&pos
, const wxSize 
&size
,  
1245                                            const wxString 
&name 
)  
1249     if (!wxDataViewHeaderWindowBase::Create(parent
, id
, pos
, size
, name
)) 
1252     wxVisualAttributes attr 
= wxPanel::GetClassDefaultAttributes(); 
1253     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
1254     SetOwnForegroundColour( attr
.colFg 
); 
1255     SetOwnBackgroundColour( attr
.colBg 
); 
1257         SetOwnFont( attr
.font 
); 
1259     // set our size hints: wxDataViewCtrl will put this wxWindow inside 
1260     // a wxBoxSizer and in order to avoid super-big header windows, 
1261     // we need to set our height as fixed 
1262     SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT
)); 
1263     SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT
)); 
1268 void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1271     GetClientSize( &w
, &h 
); 
1273     wxAutoBufferedPaintDC 
dc( this ); 
1275     dc
.SetBackground(GetBackgroundColour()); 
1279     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1282     m_owner
->GetViewStart( &x
, NULL 
); 
1284     // account for the horz scrollbar offset 
1285     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1287     dc
.SetFont( GetFont() ); 
1289     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1292     for (i 
= 0; i 
< cols
; i
++) 
1294         wxDataViewColumn 
*col 
= GetColumn( i 
); 
1295         if (col
->IsHidden()) 
1296             continue;      // skip it! 
1298         int cw 
= col
->GetWidth(); 
1301         wxRendererNative::Get().DrawHeaderButton
 
1305                                     wxRect(xpos
, 0, cw
, ch
-1), 
1306                                     m_parent
->IsEnabled() ? 0 
1307                                                           : (int)wxCONTROL_DISABLED
 
1310         // align as required the column title: 
1312         wxSize titleSz 
= dc
.GetTextExtent(col
->GetTitle()); 
1313         switch (col
->GetAlignment()) 
1316             x 
+= HEADER_HORIZ_BORDER
; 
1318         case wxALIGN_CENTER
: 
1319         case wxALIGN_CENTER_HORIZONTAL
: 
1320             x 
+= (cw 
- titleSz
.GetWidth() - 2 * HEADER_HORIZ_BORDER
)/2; 
1323             x 
+= cw 
- titleSz
.GetWidth() - HEADER_HORIZ_BORDER
; 
1327         // always center the title vertically: 
1328         int y 
= wxMax((ch 
- titleSz
.GetHeight()) / 2, HEADER_VERT_BORDER
); 
1330         dc
.SetClippingRegion( xpos
+HEADER_HORIZ_BORDER
,  
1332                               wxMax(cw 
- 2 * HEADER_HORIZ_BORDER
, 1),  // width 
1333                               wxMax(ch 
- 2 * HEADER_VERT_BORDER
, 1));  // height 
1334         dc
.DrawText( col
->GetTitle(), x
, y 
); 
1335         dc
.DestroyClippingRegion(); 
1341 void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent 
&event 
) 
1343     GetParent()->SetFocus(); 
1347 void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent 
&event 
) 
1349     // we want to work with logical coords 
1351     m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
); 
1352     int y 
= event
.GetY(); 
1356         // we don't draw the line beyond our window,  
1357         // but we allow dragging it there 
1359         GetClientSize( &w
, NULL 
); 
1360         m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
); 
1363         // erase the line if it was drawn 
1367         if (event
.ButtonUp())  
1369             m_isDragging 
= false; 
1375             GetColumn(m_column
)->SetWidth(m_currentX 
- m_minX
); 
1378             GetOwner()->Refresh(); 
1382             m_currentX 
= wxMax(m_minX 
+ 7, x
); 
1384             // draw in the new location 
1385             if (m_currentX 
< w
) DrawCurrent(); 
1389     else     // not dragging 
1392         m_column 
= wxNOT_FOUND
; 
1394         bool hit_border 
= false; 
1396         // end of the current column 
1399         // find the column where this event occured 
1400         int countCol 
= m_owner
->GetColumnCount(); 
1401         for (int column 
= 0; column 
< countCol
; column
++)  
1403             wxDataViewColumn 
*p 
= GetColumn(column
); 
1406                 continue;   // skip if not shown 
1408             xpos 
+= p
->GetWidth(); 
1410             if ((abs(x
-xpos
) < 3) && (y 
< 22))  
1418                 // inside the column 
1425         if (m_column 
== wxNOT_FOUND
) 
1428         bool resizeable 
= GetColumn(m_column
)->IsResizeable(); 
1429         if (event
.LeftDClick() && resizeable
) 
1431             GetColumn(m_column
)->SetWidth(GetOwner()->GetBestColumnWidth(m_column
)); 
1434         else if (event
.LeftDown() || event
.RightUp()) 
1436             if (hit_border 
&& event
.LeftDown() && resizeable
)  
1438                 m_isDragging 
= true; 
1443             else    // click on a column 
1445                 wxEventType evt 
= event
.LeftDown() ?  
1446                         wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK 
: 
1447                         wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
; 
1448                 SendEvent(evt
, m_column
); 
1451         else if (event
.Moving()) 
1453             if (hit_border 
&& resizeable
)  
1454                 m_currentCursor 
= m_resizeCursor
; 
1456                 m_currentCursor 
= wxSTANDARD_CURSOR
; 
1458             SetCursor(*m_currentCursor
); 
1463 void wxGenericDataViewHeaderWindow::DrawCurrent() 
1465     int x1 
= m_currentX
; 
1467     ClientToScreen (&x1
, &y1
); 
1469     int x2 
= m_currentX
-1; 
1471     ++x2
; // but why ???? 
1474     m_owner
->GetClientSize( NULL
, &y2 
); 
1475     m_owner
->ClientToScreen( &x2
, &y2 
); 
1478     dc
.SetLogicalFunction(wxINVERT
); 
1479     dc
.SetPen(m_penCurrent
); 
1480     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1482     dc
.DrawLine(x1
, y1
, x2
, y2
); 
1485 void wxGenericDataViewHeaderWindow::AdjustDC(wxDC
& dc
) 
1489     m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL 
); 
1490     m_owner
->GetViewStart( &x
, NULL 
); 
1492     // shift the DC origin to match the position of the main window horizontal 
1493     // scrollbar: this allows us to always use logical coords 
1494     dc
.SetDeviceOrigin( -x 
* xpix
, 0 ); 
1497 #endif      // defined(__WXMSW__) 
1499 //----------------------------------------------------------------------------- 
1500 // wxDataViewRenameTimer 
1501 //----------------------------------------------------------------------------- 
1503 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
) 
1508 void wxDataViewRenameTimer::Notify() 
1510     m_owner
->OnRenameTimer(); 
1513 //----------------------------------------------------------------------------- 
1514 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing 
1515 //----------------------------------------------------------------------------- 
1517 BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper
, wxEvtHandler
) 
1518     EVT_CHAR           (wxDataViewTextCtrlWrapper::OnChar
) 
1519     EVT_KEY_UP         (wxDataViewTextCtrlWrapper::OnKeyUp
) 
1520     EVT_KILL_FOCUS     (wxDataViewTextCtrlWrapper::OnKillFocus
) 
1523 wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper( 
1524                         wxDataViewMainWindow 
*owner
, 
1526                         wxDataViewListModel 
*model
, 
1527                         unsigned int col
, unsigned int row
, 
1537     m_aboutToFinish 
= false; 
1540     model
->GetValue( value
, col
, row 
); 
1541     m_startValue 
= value
.GetString(); 
1543     m_owner
->GetOwner()->CalcScrolledPosition( 
1544         rectLabel
.x
, rectLabel
.y
, &rectLabel
.x
, &rectLabel
.y 
); 
1546     m_text
->Create( owner
, wxID_ANY
, m_startValue
, 
1547                     wxPoint(rectLabel
.x
-2,rectLabel
.y
-2), 
1548                     wxSize(rectLabel
.width
+7,rectLabel
.height
+4) ); 
1551     m_text
->PushEventHandler(this); 
1554 void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish() 
1556     m_aboutToFinish 
= true; 
1558     // Notify the owner about the changes 
1561     // Even if vetoed, close the control (consistent with MSW) 
1565 void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent 
&event 
) 
1567     switch ( event
.m_keyCode 
) 
1570             AcceptChangesAndFinish(); 
1574             // m_owner->OnRenameCancelled( m_itemEdited ); 
1583 void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent 
&event 
) 
1591     // auto-grow the textctrl 
1592     wxSize parentSize 
= m_owner
->GetSize(); 
1593     wxPoint myPos 
= m_text
->GetPosition(); 
1594     wxSize mySize 
= m_text
->GetSize(); 
1596     m_text
->GetTextExtent(m_text
->GetValue() + _T("MM"), &sx
, &sy
); 
1597     if (myPos
.x 
+ sx 
> parentSize
.x
) 
1598         sx 
= parentSize
.x 
- myPos
.x
; 
1601     m_text
->SetSize(sx
, wxDefaultCoord
); 
1606 void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent 
&event 
) 
1608     if ( !m_finished 
&& !m_aboutToFinish 
) 
1611         //if ( !AcceptChanges() ) 
1612         //    m_owner->OnRenameCancelled( m_itemEdited ); 
1617     // We must let the native text control handle focus 
1621 bool wxDataViewTextCtrlWrapper::AcceptChanges() 
1623     const wxString value 
= m_text
->GetValue(); 
1625     if ( value 
== m_startValue 
) 
1626         // nothing changed, always accept 
1629 //    if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) 
1630         // vetoed by the user 
1633     // accepted, do rename the item 
1636     m_model
->SetValue( variant
, m_col
, m_row 
); 
1637     m_model
->ValueChanged( m_col
, m_row 
); 
1642 void wxDataViewTextCtrlWrapper::Finish() 
1648         m_text
->RemoveEventHandler(this); 
1649         m_owner
->FinishEditing(m_text
); 
1652         wxPendingDelete
.Append( this ); 
1656 //----------------------------------------------------------------------------- 
1657 // wxDataViewMainWindow 
1658 //----------------------------------------------------------------------------- 
1660 int LINKAGEMODE 
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2 
) 
1662     if (row1 
> row2
) return 1; 
1663     if (row1 
== row2
) return 0; 
1668 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
) 
1670 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
) 
1671     EVT_PAINT         (wxDataViewMainWindow::OnPaint
) 
1672     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse
) 
1673     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus
) 
1674     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus
) 
1675     EVT_CHAR          (wxDataViewMainWindow::OnChar
) 
1678 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl 
*parent
, wxWindowID id
, 
1679     const wxPoint 
&pos
, const wxSize 
&size
, const wxString 
&name 
) : 
1680     wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
, name 
), 
1681     m_selection( wxDataViewSelectionCmp 
) 
1686     m_lastOnSame 
= false; 
1687     m_renameTimer 
= new wxDataViewRenameTimer( this ); 
1688     m_textctrlWrapper 
= NULL
; 
1690     // TODO: user better initial values/nothing selected 
1691     m_currentCol 
= NULL
; 
1694     // TODO: we need to calculate this smartly 
1701     wxASSERT(m_lineHeight 
> 2*PADDING_TOPBOTTOM
); 
1704     m_dragStart 
= wxPoint(0,0); 
1705     m_lineLastClicked 
= (unsigned int) -1; 
1706     m_lineBeforeLastClicked 
= (unsigned int) -1; 
1707     m_lineSelectSingleOnUp 
= (unsigned int) -1; 
1711     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
1712     SetBackgroundColour( *wxWHITE 
); 
1714     m_penRule 
= wxPen(GetRuleColour(), 1, wxSOLID
); 
1719 wxDataViewMainWindow::~wxDataViewMainWindow() 
1721     delete m_renameTimer
; 
1724 void wxDataViewMainWindow::OnRenameTimer() 
1726     // We have to call this here because changes may just have 
1727     // been made and no screen update taken place. 
1733     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1735     for (i 
= 0; i 
< cols
; i
++) 
1737         wxDataViewColumn 
*c 
= GetOwner()->GetColumn( i 
); 
1739             continue;      // skip it! 
1741         if (c 
== m_currentCol
) 
1743         xpos 
+= c
->GetWidth(); 
1745     wxRect 
labelRect( xpos
, m_currentRow 
* m_lineHeight
,  
1746                       m_currentCol
->GetWidth(), m_lineHeight 
); 
1748     wxClassInfo 
*textControlClass 
= CLASSINFO(wxTextCtrl
); 
1750     wxTextCtrl 
* const text 
= (wxTextCtrl 
*)textControlClass
->CreateObject(); 
1751     m_textctrlWrapper 
= new wxDataViewTextCtrlWrapper(this, text
, GetOwner()->GetModel(), 
1752         m_currentCol
->GetModelColumn(), m_currentRow
, labelRect 
); 
1755 void wxDataViewMainWindow::FinishEditing( wxTextCtrl 
*text 
) 
1758     m_textctrlWrapper 
= NULL
; 
1760   //  SetFocusIgnoringChildren(); 
1763 bool wxDataViewMainWindow::RowAppended() 
1768 bool wxDataViewMainWindow::RowPrepended() 
1773 bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before
) ) 
1778 bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row
) ) 
1783 bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row
) ) 
1788 bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col
), unsigned int row 
) 
1790     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 
1791 #define MAX_VIRTUAL_WIDTH       100000 
1793     wxRect 
rect( 0, row
*m_lineHeight
, MAX_VIRTUAL_WIDTH
, m_lineHeight 
); 
1794     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
1795     Refresh( true, &rect 
); 
1800 bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order
) ) 
1807 bool wxDataViewMainWindow::Cleared() 
1812 void wxDataViewMainWindow::UpdateDisplay() 
1817 void wxDataViewMainWindow::OnInternalIdle() 
1819     wxWindow::OnInternalIdle(); 
1823         RecalculateDisplay(); 
1828 void wxDataViewMainWindow::RecalculateDisplay() 
1830     wxDataViewListModel 
*model 
= GetOwner()->GetModel(); 
1837     int width 
= GetEndOfLastCol(); 
1838     int height 
= model
->GetRowCount() * m_lineHeight
; 
1840     SetVirtualSize( width
, height 
); 
1841     GetOwner()->SetScrollRate( 10, m_lineHeight 
); 
1846 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
1848     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
1850     if (GetOwner()->m_headerArea
) 
1851         GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 ); 
1854 void wxDataViewMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1856     wxDataViewListModel 
*model 
= GetOwner()->GetModel(); 
1857     wxAutoBufferedPaintDC 
dc( this ); 
1860     dc
.SetBackground(GetBackgroundColour()); 
1862     GetOwner()->PrepareDC( dc 
); 
1863     dc
.SetFont( GetFont() ); 
1865     wxRect update 
= GetUpdateRegion().GetBox(); 
1866     m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y 
); 
1868     // compute which items needs to be redrawn 
1869     unsigned int item_start 
= wxMax( 0, (update
.y 
/ m_lineHeight
) ); 
1870     unsigned int item_count 
=  
1871         wxMin( (int)(((update
.y 
+ update
.height
) / m_lineHeight
) - item_start 
+ 1), 
1872                (int)(model
->GetRowCount() - item_start
) ); 
1873     unsigned int item_last 
= item_start 
+ item_count
; 
1875     // compute which columns needs to be redrawn 
1876     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1877     unsigned int col_start 
= 0; 
1878     unsigned int x_start 
= 0; 
1879     for (x_start 
= 0; col_start 
< cols
; col_start
++) 
1881         wxDataViewColumn 
*col 
= GetOwner()->GetColumn(col_start
); 
1882         if (col
->IsHidden()) 
1883             continue;      // skip it! 
1885         unsigned int w 
= col
->GetWidth(); 
1886         if (x_start
+w 
>= (unsigned int)update
.x
) 
1892     unsigned int col_last 
= col_start
; 
1893     unsigned int x_last 
= x_start
; 
1894     for (; col_last 
< cols
; col_last
++) 
1896         wxDataViewColumn 
*col 
= GetOwner()->GetColumn(col_last
); 
1897         if (col
->IsHidden()) 
1898             continue;      // skip it! 
1900         if (x_last 
> (unsigned int)update
.GetRight()) 
1903         x_last 
+= col
->GetWidth(); 
1906     // Draw horizontal rules if required 
1907     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
1909         dc
.SetPen(m_penRule
); 
1910         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1912         for (unsigned int i 
= item_start
; i 
<= item_last
+1; i
++) 
1914             int y 
= i 
* m_lineHeight
; 
1915             dc
.DrawLine(x_start
, y
, x_last
, y
); 
1919     // Draw vertical rules if required 
1920     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
1922         dc
.SetPen(m_penRule
); 
1923         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1926         for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1928             wxDataViewColumn 
*col 
= GetOwner()->GetColumn(i
); 
1929             if (col
->IsHidden()) 
1930                 continue;       // skip it 
1932             dc
.DrawLine(x
, item_start 
* m_lineHeight
, 
1933                         x
, item_last 
* m_lineHeight
); 
1935             x 
+= col
->GetWidth(); 
1938         // Draw last vertical rule 
1939         dc
.DrawLine(x
, item_start 
* m_lineHeight
,  
1940                     x
, item_last 
* m_lineHeight
); 
1943     // redraw the background for the items which are selected/current 
1944     for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1946         bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1947         if (selected 
|| item 
== m_currentRow
) 
1949             int flags 
= selected 
? (int)wxCONTROL_SELECTED 
: 0; 
1950             if (item 
== m_currentRow
) 
1951                 flags 
|= wxCONTROL_CURRENT
; 
1953                 flags 
|= wxCONTROL_FOCUSED
; 
1955             wxRect 
rect( x_start
, item
*m_lineHeight
, x_last
, m_lineHeight 
); 
1956             wxRendererNative::Get().DrawItemSelectionRect
 
1966     // redraw all cells for all rows which must be repainted and for all columns 
1968     cell_rect
.x 
= x_start
; 
1969     cell_rect
.height 
= m_lineHeight
;        // -1 is for the horizontal rules 
1970     for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1972         wxDataViewColumn 
*col 
= GetOwner()->GetColumn( i 
); 
1973         wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
1974         cell_rect
.width 
= col
->GetWidth(); 
1976         if (col
->IsHidden()) 
1977             continue;       // skipt it! 
1979         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1981             // get the cell value and set it into the renderer 
1983             model
->GetValue( value
, col
->GetModelColumn(), item 
); 
1984             cell
->SetValue( value 
); 
1986             // update the y offset 
1987             cell_rect
.y 
= item 
* m_lineHeight
; 
1989             // cannot be bigger than allocated space 
1990             wxSize size 
= cell
->GetSize(); 
1991             size
.x 
= wxMin( size
.x 
+ 2*PADDING_RIGHTLEFT
, cell_rect
.width 
); 
1992             size
.y 
= wxMin( size
.y 
+ 2*PADDING_TOPBOTTOM
, cell_rect
.height 
); 
1994             wxRect 
item_rect(cell_rect
.GetTopLeft(), size
); 
1995             int align 
= cell
->GetAlignment(); 
1997             // horizontal alignment: 
1998             item_rect
.x 
= cell_rect
.x
; 
1999             if (align 
& wxALIGN_CENTER_HORIZONTAL
) 
2000                 item_rect
.x 
= cell_rect
.x 
+ (cell_rect
.width 
/ 2) - (size
.x 
/ 2); 
2001             else if (align 
& wxALIGN_RIGHT
) 
2002                 item_rect
.x 
= cell_rect
.x 
+ cell_rect
.width 
- size
.x
; 
2003             //else: wxALIGN_LEFT is the default 
2005             // vertical alignment: 
2006             item_rect
.y 
= cell_rect
.y
; 
2007             if (align 
& wxALIGN_CENTER_VERTICAL
) 
2008                 item_rect
.y 
= cell_rect
.y 
+ (cell_rect
.height 
/ 2) - (size
.y 
/ 2); 
2009             else if (align 
& wxALIGN_BOTTOM
) 
2010                 item_rect
.y 
= cell_rect
.y 
+ cell_rect
.height 
- size
.y
; 
2011             //else: wxALIGN_TOP is the default 
2014             item_rect
.x 
+= PADDING_RIGHTLEFT
; 
2015             item_rect
.y 
+= PADDING_TOPBOTTOM
; 
2016             item_rect
.width 
= size
.x 
- 2 * PADDING_RIGHTLEFT
; 
2017             item_rect
.height 
= size
.y 
- 2 * PADDING_TOPBOTTOM
; 
2020             if (m_selection
.Index(item
) != wxNOT_FOUND
) 
2021                 state 
|= wxDATAVIEW_CELL_SELECTED
; 
2023             // TODO: it would be much more efficient to create a clipping 
2024             //       region for the entire column being rendered (in the OnPaint 
2025             //       of wxDataViewMainWindow) instead of a single clip region for 
2026             //       each cell. However it would mean that each renderer should 
2027             //       respect the given wxRect's top & bottom coords, eventually 
2028             //       violating only the left & right coords - however the user can 
2029             //       make its own renderer and thus we cannot be sure of that. 
2030             dc
.SetClippingRegion( item_rect 
); 
2031             cell
->Render( item_rect
, &dc
, state 
); 
2032             dc
.DestroyClippingRegion(); 
2035         cell_rect
.x 
+= cell_rect
.width
; 
2039 int wxDataViewMainWindow::GetCountPerPage() const 
2041     wxSize size 
= GetClientSize(); 
2042     return size
.y 
/ m_lineHeight
; 
2045 int wxDataViewMainWindow::GetEndOfLastCol() const 
2049     for (i 
= 0; i 
< GetOwner()->GetColumnCount(); i
++) 
2051         const wxDataViewColumn 
*c 
=  
2052             wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetColumn( i 
); 
2055             width 
+= c
->GetWidth(); 
2060 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const 
2064     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2066     return y 
/ m_lineHeight
; 
2069 unsigned int wxDataViewMainWindow::GetLastVisibleRow() const 
2071     wxSize client_size 
= GetClientSize(); 
2072     m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
,  
2073                                      &client_size
.x
, &client_size
.y 
); 
2075     return wxMin( GetRowCount()-1, ((unsigned)client_size
.y
/m_lineHeight
)+1 ); 
2078 unsigned int wxDataViewMainWindow::GetRowCount() const 
2080     return wx_const_cast(wxDataViewCtrl
*, GetOwner())->GetModel()->GetRowCount(); 
2083 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row 
) 
2090 void wxDataViewMainWindow::SelectAllRows( bool on 
) 
2097         m_selection
.Clear(); 
2098         for (unsigned int i 
= 0; i 
< GetRowCount(); i
++) 
2099             m_selection
.Add( i 
); 
2104         unsigned int first_visible 
= GetFirstVisibleRow(); 
2105         unsigned int last_visible 
= GetLastVisibleRow(); 
2107         for (i 
= 0; i 
< m_selection
.GetCount(); i
++) 
2109             unsigned int row 
= m_selection
[i
]; 
2110             if ((row 
>= first_visible
) && (row 
<= last_visible
)) 
2113         m_selection
.Clear(); 
2117 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on 
) 
2119     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2123             m_selection
.Add( row 
); 
2131             m_selection
.Remove( row 
); 
2137 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on 
) 
2141         unsigned int tmp 
= from
; 
2147     for (i 
= from
; i 
<= to
; i
++) 
2149         if (m_selection
.Index( i 
) == wxNOT_FOUND
) 
2152                 m_selection
.Add( i 
); 
2157                 m_selection
.Remove( i 
); 
2160     RefreshRows( from
, to 
); 
2163 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections 
) 
2165     for (size_t i
=0; i 
< aSelections
.GetCount(); i
++) 
2167         int n 
= aSelections
[i
]; 
2169         m_selection
.Add( n 
); 
2174 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row 
) 
2176     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2177         m_selection
.Add( row 
); 
2179         m_selection
.Remove( row 
); 
2183 bool wxDataViewMainWindow::IsRowSelected( unsigned int row 
) 
2185     return (m_selection
.Index( row 
) != wxNOT_FOUND
); 
2188 void wxDataViewMainWindow::RefreshRow( unsigned int row 
) 
2190     wxRect 
rect( 0, row
*m_lineHeight
, GetEndOfLastCol(), m_lineHeight 
); 
2191     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2193     wxSize client_size 
= GetClientSize(); 
2194     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2195     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2196     if (intersect_rect
.width 
> 0) 
2197         Refresh( true, &intersect_rect 
); 
2200 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to 
) 
2204         unsigned int tmp 
= to
; 
2209     wxRect 
rect( 0, from
*m_lineHeight
, GetEndOfLastCol(), (to
-from
+1) * m_lineHeight 
); 
2210     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2212     wxSize client_size 
= GetClientSize(); 
2213     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2214     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2215     if (intersect_rect
.width 
> 0) 
2216         Refresh( true, &intersect_rect 
); 
2219 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow 
) 
2221     unsigned int count 
= GetRowCount(); 
2222     if (firstRow 
> count
) 
2225     wxRect 
rect( 0, firstRow
*m_lineHeight
, GetEndOfLastCol(), count 
* m_lineHeight 
); 
2226     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2228     wxSize client_size 
= GetClientSize(); 
2229     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2230     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2231     if (intersect_rect
.width 
> 0) 
2232         Refresh( true, &intersect_rect 
); 
2235 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
) 
2237     wxCHECK_RET( newCurrent 
< GetRowCount(), 
2238                  _T("invalid item index in OnArrowChar()") ); 
2240     // if there is no selection, we cannot move it anywhere 
2241     if (!HasCurrentRow()) 
2244     unsigned int oldCurrent 
= m_currentRow
; 
2246     // in single selection we just ignore Shift as we can't select several 
2248     if ( event
.ShiftDown() && !IsSingleSel() ) 
2250         RefreshRow( oldCurrent 
); 
2252         ChangeCurrentRow( newCurrent 
); 
2254         // select all the items between the old and the new one 
2255         if ( oldCurrent 
> newCurrent 
) 
2257             newCurrent 
= oldCurrent
; 
2258             oldCurrent 
= m_currentRow
; 
2261         SelectRows( oldCurrent
, newCurrent
, true ); 
2265         RefreshRow( oldCurrent 
); 
2267         // all previously selected items are unselected unless ctrl is held 
2268         if ( !event
.ControlDown() ) 
2269             SelectAllRows(false); 
2271         ChangeCurrentRow( newCurrent 
); 
2273         if ( !event
.ControlDown() ) 
2274             SelectRow( m_currentRow
, true ); 
2276             RefreshRow( m_currentRow 
); 
2279     //EnsureVisible( m_currentRow ); 
2282 wxRect 
wxDataViewMainWindow::GetLineRect( unsigned int row 
) const 
2286     rect
.y 
= m_lineHeight 
* row
; 
2287     rect
.width 
= GetEndOfLastCol(); 
2288     rect
.height 
= m_lineHeight
; 
2293 void wxDataViewMainWindow::OnChar( wxKeyEvent 
&event 
) 
2295     if (event
.GetKeyCode() == WXK_TAB
) 
2297         wxNavigationKeyEvent nevent
; 
2298         nevent
.SetWindowChange( event
.ControlDown() ); 
2299         nevent
.SetDirection( !event
.ShiftDown() ); 
2300         nevent
.SetEventObject( GetParent()->GetParent() ); 
2301         nevent
.SetCurrentFocus( m_parent 
); 
2302         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent 
)) 
2306     // no item -> nothing to do 
2307     if (!HasCurrentRow()) 
2313     // don't use m_linesPerPage directly as it might not be computed yet 
2314     const int pageSize 
= GetCountPerPage(); 
2315     wxCHECK_RET( pageSize
, _T("should have non zero page size") ); 
2317     switch ( event
.GetKeyCode() ) 
2320             if ( m_currentRow 
> 0 ) 
2321                 OnArrowChar( m_currentRow 
- 1, event 
); 
2325             if ( m_currentRow 
< GetRowCount() - 1 ) 
2326                 OnArrowChar( m_currentRow 
+ 1, event 
); 
2331                 OnArrowChar( GetRowCount() - 1, event 
); 
2336                 OnArrowChar( 0, event 
); 
2341                 int steps 
= pageSize 
- 1; 
2342                 int index 
= m_currentRow 
- steps
; 
2346                 OnArrowChar( index
, event 
); 
2352                 int steps 
= pageSize 
- 1; 
2353                 unsigned int index 
= m_currentRow 
+ steps
; 
2354                 unsigned int count 
= GetRowCount(); 
2355                 if ( index 
>= count 
) 
2358                 OnArrowChar( index
, event 
); 
2367 void wxDataViewMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2369     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2371         // let the base handle mouse wheel events. 
2376     int x 
= event
.GetX(); 
2377     int y 
= event
.GetY(); 
2378     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2380     wxDataViewColumn 
*col 
= NULL
; 
2383     unsigned int cols 
= GetOwner()->GetColumnCount(); 
2385     for (i 
= 0; i 
< cols
; i
++) 
2387         wxDataViewColumn 
*c 
= GetOwner()->GetColumn( i 
); 
2389             continue;      // skip it! 
2391         if (x 
< xpos 
+ c
->GetWidth()) 
2396         xpos 
+= c
->GetWidth(); 
2400     wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
2402     unsigned int current 
= y 
/ m_lineHeight
; 
2404     if ((current 
> GetRowCount()) || (x 
> GetEndOfLastCol())) 
2406         // Unselect all if below the last row ? 
2410     wxDataViewListModel 
*model 
= GetOwner()->GetModel(); 
2412     if (event
.Dragging()) 
2414         if (m_dragCount 
== 0) 
2416             // we have to report the raw, physical coords as we want to be 
2417             // able to call HitTest(event.m_pointDrag) from the user code to 
2418             // get the item being dragged 
2419             m_dragStart 
= event
.GetPosition(); 
2424         if (m_dragCount 
!= 3) 
2427         if (event
.LeftIsDown()) 
2429             // Notify cell about drag 
2438     bool forceClick 
= false; 
2440     if (event
.ButtonDClick()) 
2442         m_renameTimer
->Stop(); 
2443         m_lastOnSame 
= false; 
2446     if (event
.LeftDClick()) 
2448         if ( current 
== m_lineLastClicked 
) 
2450             if (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
) 
2453                 model
->GetValue( value
, col
->GetModelColumn(), current 
); 
2454                 cell
->SetValue( value 
); 
2455                 wxRect 
cell_rect( xpos
, current 
* m_lineHeight
,  
2456                                   col
->GetWidth(), m_lineHeight 
); 
2457                 cell
->Activate( cell_rect
, model
, col
->GetModelColumn(), current 
); 
2463             // The first click was on another item, so don't interpret this as 
2464             // a double click, but as a simple click instead 
2471         if (m_lineSelectSingleOnUp 
!= (unsigned int)-1) 
2473             // select single line 
2474             SelectAllRows( false ); 
2475             SelectRow( m_lineSelectSingleOnUp
, true ); 
2480             if ((col 
== m_currentCol
) && (current 
== m_currentRow
) && 
2481                 (cell
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) ) 
2483                 m_renameTimer
->Start( 100, true ); 
2487         m_lastOnSame 
= false; 
2488         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
2492         // This is necessary, because after a DnD operation in 
2493         // from and to ourself, the up event is swallowed by the 
2494         // DnD code. So on next non-up event (which means here and 
2495         // now) m_lineSelectSingleOnUp should be reset. 
2496         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
2499     if (event
.RightDown()) 
2501         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2502         m_lineLastClicked 
= current
; 
2504         // If the item is already selected, do not update the selection. 
2505         // Multi-selections should not be cleared if a selected item is clicked. 
2506         if (!IsRowSelected(current
)) 
2508             SelectAllRows(false); 
2509             ChangeCurrentRow(current
); 
2510             SelectRow(m_currentRow
,true); 
2513         // notify cell about right click 
2516         // Allow generation of context menu event 
2519     else if (event
.MiddleDown()) 
2521         // notify cell about middle click 
2524     if (event
.LeftDown() || forceClick
) 
2530         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
2531         m_lineLastClicked 
= current
; 
2533         unsigned int oldCurrentRow 
= m_currentRow
; 
2534         bool oldWasSelected 
= IsRowSelected(m_currentRow
); 
2536         bool cmdModifierDown 
= event
.CmdDown(); 
2537         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
2539             if ( IsSingleSel() || !IsRowSelected(current
) ) 
2541                 SelectAllRows( false ); 
2543                 ChangeCurrentRow(current
); 
2545                 SelectRow(m_currentRow
,true); 
2547             else // multi sel & current is highlighted & no mod keys 
2549                 m_lineSelectSingleOnUp 
= current
; 
2550                 ChangeCurrentRow(current
); // change focus 
2553         else // multi sel & either ctrl or shift is down 
2555             if (cmdModifierDown
) 
2557                 ChangeCurrentRow(current
); 
2559                 ReverseRowSelection(m_currentRow
); 
2561             else if (event
.ShiftDown()) 
2563                 ChangeCurrentRow(current
); 
2565                 unsigned int lineFrom 
= oldCurrentRow
, 
2568                 if ( lineTo 
< lineFrom 
) 
2571                     lineFrom 
= m_currentRow
; 
2574                 SelectRows(lineFrom
, lineTo
, true); 
2576             else // !ctrl, !shift 
2578                 // test in the enclosing if should make it impossible 
2579                 wxFAIL_MSG( _T("how did we get here?") ); 
2583         if (m_currentRow 
!= oldCurrentRow
) 
2584             RefreshRow( oldCurrentRow 
); 
2586         wxDataViewColumn 
*oldCurrentCol 
= m_currentCol
; 
2588         // Update selection here... 
2591         m_lastOnSame 
= !forceClick 
&& ((col 
== oldCurrentCol
) &&  
2592                         (current 
== oldCurrentRow
)) && oldWasSelected
; 
2596 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent 
&event 
) 
2600     if (HasCurrentRow()) 
2606 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
2610     if (HasCurrentRow()) 
2616 //----------------------------------------------------------------------------- 
2618 //----------------------------------------------------------------------------- 
2620 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
) 
2622 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
) 
2623     EVT_SIZE(wxDataViewCtrl::OnSize
) 
2626 wxDataViewCtrl::~wxDataViewCtrl() 
2629         GetModel()->RemoveNotifier( m_notifier 
); 
2632 void wxDataViewCtrl::Init() 
2637 bool wxDataViewCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
2638            const wxPoint
& pos
, const wxSize
& size
, 
2639            long style
, const wxValidator
& validator 
) 
2641     if (!wxControl::Create( parent
, id
, pos
, size
,  
2642                             style 
| wxScrolledWindowStyle
|wxSUNKEN_BORDER
, validator
)) 
2648     MacSetClipChildren( true ) ; 
2651     m_clientArea 
= new wxDataViewMainWindow( this, wxID_ANY 
); 
2653     if (HasFlag(wxDV_NO_HEADER
)) 
2654         m_headerArea 
= NULL
; 
2656         m_headerArea 
= new wxDataViewHeaderWindow( this, wxID_ANY 
); 
2658     SetTargetWindow( m_clientArea 
); 
2660     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
2662         sizer
->Add( m_headerArea
, 0, wxGROW 
); 
2663     sizer
->Add( m_clientArea
, 1, wxGROW 
); 
2670 WXLRESULT 
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
, 
2674     WXLRESULT rc 
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
2677     // we need to process arrows ourselves for scrolling 
2678     if ( nMsg 
== WM_GETDLGCODE 
) 
2680         rc 
|= DLGC_WANTARROWS
; 
2688 void wxDataViewCtrl::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
2690     // We need to override OnSize so that our scrolled 
2691     // window a) does call Layout() to use sizers for 
2692     // positioning the controls but b) does not query 
2693     // the sizer for their size and use that for setting 
2694     // the scrollable area as set that ourselves by 
2695     // calling SetScrollbar() further down. 
2702 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel 
*model 
) 
2704     if (!wxDataViewCtrlBase::AssociateModel( model 
)) 
2707     m_notifier 
= new wxGenericDataViewListModelNotifier( m_clientArea 
); 
2709     model
->AddNotifier( m_notifier 
); 
2711     m_clientArea
->UpdateDisplay(); 
2716 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn 
*col 
) 
2718     if (!wxDataViewCtrlBase::AppendColumn(col
)) 
2725 void wxDataViewCtrl::OnColumnChange() 
2728         m_headerArea
->UpdateDisplay(); 
2730     m_clientArea
->UpdateDisplay(); 
2733 void wxDataViewCtrl::SetSelection( int row 
) 
2735     m_clientArea
->SelectRow(row
, true); 
2738 void wxDataViewCtrl::SetSelectionRange( unsigned int from
, unsigned int to 
) 
2740     m_clientArea
->SelectRows(from
, to
, true); 
2743 void wxDataViewCtrl::SetSelections( const wxArrayInt
& aSelections 
) 
2745     m_clientArea
->Select(aSelections
); 
2748 void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row
) ) 
2753 bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row
) ) const 
2760 int wxDataViewCtrl::GetSelection() const 
2767 int wxDataViewCtrl::GetSelections(wxArrayInt
& WXUNUSED(aSelections
) ) const 
2775     // !wxUSE_GENERICDATAVIEWCTRL 
2778     // wxUSE_DATAVIEWCTRL