1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/datavgen.cpp 
   3 // Purpose:     wxDataViewCtrl generic implementation 
   4 // Author:      Robert Roebling 
   5 // Modified by: Francesco Montorsi, Guru Kathiresan, Bo Yang 
   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" 
  36     #include "wx/dcscreen.h" 
  39 #include "wx/stockitem.h" 
  40 #include "wx/calctrl.h" 
  41 #include "wx/popupwin.h" 
  42 #include "wx/renderer.h" 
  43 #include "wx/dcbuffer.h" 
  46 #include "wx/listimpl.cpp" 
  47 #include "wx/imaglist.h" 
  48 #include "wx/headerctrl.h" 
  50 //----------------------------------------------------------------------------- 
  52 //----------------------------------------------------------------------------- 
  56 static const int SCROLL_UNIT_X 
= 15; 
  58 // the cell padding on the left/right 
  59 static const int PADDING_RIGHTLEFT 
= 3; 
  61 // the expander space margin 
  62 static const int EXPANDER_MARGIN 
= 4; 
  65 static const int EXPANDER_OFFSET 
= 4; 
  67 static const int EXPANDER_OFFSET 
= 1; 
  70 //Below is the compare stuff 
  71 //For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed 
  72 static wxDataViewModel 
* g_model
; 
  73 static int g_column 
= -2; 
  74 static bool g_asending 
= true; 
  76 //----------------------------------------------------------------------------- 
  77 // wxDataViewHeaderWindow 
  78 //----------------------------------------------------------------------------- 
  80 class wxDataViewHeaderWindow 
: public wxHeaderCtrl
 
  83     wxDataViewHeaderWindow(wxDataViewCtrl 
*parent
) 
  84         : wxHeaderCtrl(parent
) 
  88     wxDataViewCtrl 
*GetOwner() const 
  89         { return static_cast<wxDataViewCtrl 
*>(GetParent()); } 
  92     // implement/override wxHeaderCtrl functions by forwarding them to the main 
  94     virtual wxHeaderColumn
& GetColumn(unsigned int idx
) 
  96         return *(GetOwner()->GetColumn(idx
)); 
  99     virtual bool UpdateColumnWidthToFit(unsigned int idx
, int widthTitle
) 
 101         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 103         int widthContents 
= owner
->GetBestColumnWidth(idx
); 
 104         owner
->GetColumn(idx
)->SetWidth(wxMax(widthTitle
, widthContents
)); 
 105         owner
->OnColumnChange(idx
); 
 111     bool SendEvent(wxEventType type
, unsigned int n
) 
 113         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 114         wxDataViewEvent 
event(type
, owner
->GetId()); 
 116         event
.SetEventObject(owner
); 
 118         event
.SetDataViewColumn(owner
->GetColumn(n
)); 
 119         event
.SetModel(owner
->GetModel()); 
 121         // for events created by wxDataViewHeaderWindow the 
 122         // row / value fields are not valid 
 123         return owner
->GetEventHandler()->ProcessEvent(event
); 
 126     void OnClick(wxHeaderCtrlEvent
& event
) 
 128         const unsigned idx 
= event
.GetColumn(); 
 130         if ( SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
, idx
) ) 
 133         // default handling for the column click is to sort by this column or 
 134         // toggle its sort order 
 135         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 136         wxDataViewColumn 
* const col 
= owner
->GetColumn(idx
); 
 137         if ( !col
->IsSortable() ) 
 139             // no default handling for non-sortable columns 
 144         if ( col
->IsSortKey() ) 
 146             // already using this column for sorting, just change the order 
 147             col
->ToggleSortOrder(); 
 149         else // not using this column for sorting yet 
 151             // first unset the old sort column if any 
 152             int oldSortKey 
= owner
->GetSortingColumnIndex(); 
 153             if ( oldSortKey 
!= wxNOT_FOUND 
) 
 155                 owner
->GetColumn(oldSortKey
)->UnsetAsSortKey(); 
 156                 owner
->OnColumnChange(oldSortKey
); 
 159             owner
->SetSortingColumnIndex(idx
); 
 163         wxDataViewModel 
* const model 
= owner
->GetModel(); 
 167         owner
->OnColumnChange(idx
); 
 170     void OnRClick(wxHeaderCtrlEvent
& event
) 
 172         if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
, 
 177     void OnEndResize(wxHeaderCtrlEvent
& event
) 
 179         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 181         const unsigned col 
= event
.GetColumn(); 
 182         owner
->GetColumn(col
)->SetWidth(event
.GetWidth()); 
 183         GetOwner()->OnColumnChange(col
); 
 186     void OnEndReorder(wxHeaderCtrlEvent
& event
) 
 188         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 189         owner
->ColumnMoved(owner
->GetColumn(event
.GetColumn()), 
 190                            event
.GetNewOrder()); 
 193     DECLARE_EVENT_TABLE() 
 194     DECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow
) 
 197 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
, wxHeaderCtrl
) 
 198     EVT_HEADER_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnClick
) 
 199     EVT_HEADER_RIGHT_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnRClick
) 
 201     EVT_HEADER_END_RESIZE(wxID_ANY
, wxDataViewHeaderWindow::OnEndResize
) 
 203     EVT_HEADER_END_REORDER(wxID_ANY
, wxDataViewHeaderWindow::OnEndReorder
) 
 206 //----------------------------------------------------------------------------- 
 207 // wxDataViewRenameTimer 
 208 //----------------------------------------------------------------------------- 
 210 class wxDataViewRenameTimer
: public wxTimer
 
 213     wxDataViewMainWindow 
*m_owner
; 
 216     wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
); 
 220 //----------------------------------------------------------------------------- 
 221 // wxDataViewTreeNode 
 222 //----------------------------------------------------------------------------- 
 223 class wxDataViewTreeNode
; 
 224 WX_DEFINE_ARRAY( wxDataViewTreeNode 
*, wxDataViewTreeNodes 
); 
 225 WX_DEFINE_ARRAY( void* , wxDataViewTreeLeaves
); 
 227 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, wxDataViewTreeNode 
** node2
); 
 228 int LINKAGEMODE 
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
); 
 230 class wxDataViewTreeNode
 
 233     wxDataViewTreeNode( wxDataViewTreeNode 
* parent 
= NULL 
) 
 240         m_hasChildren 
= false; 
 244     ~wxDataViewTreeNode() 
 248     wxDataViewTreeNode 
* GetParent() const { return m_parent
; } 
 249     void SetParent( wxDataViewTreeNode 
* parent 
) { m_parent 
= parent
; } 
 250     wxDataViewTreeNodes 
&  GetNodes() { return m_nodes
; } 
 251     wxDataViewTreeLeaves 
& GetChildren() { return m_leaves
; } 
 253     void AddNode( wxDataViewTreeNode 
* node 
) 
 255         m_leaves
.Add( node
->GetItem().GetID() ); 
 257             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 260             m_nodes
.Sort( &wxGenericTreeModelNodeCmp 
); 
 262     void AddLeaf( void * leaf 
) 
 264         m_leaves
.Add( leaf 
); 
 266             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 269     wxDataViewItem 
& GetItem() { return m_item
; } 
 270     const wxDataViewItem 
& GetItem() const { return m_item
; } 
 271     void SetItem( const wxDataViewItem 
& item 
) { m_item 
= item
; } 
 273     unsigned int GetChildrenNumber() const { return m_leaves
.GetCount(); } 
 274     unsigned int GetNodeNumber() const { return m_nodes
.GetCount(); } 
 275     int GetIndentLevel() const 
 278         const wxDataViewTreeNode 
* node 
= this; 
 279         while( node
->GetParent()->GetParent() != NULL 
) 
 281             node 
= node
->GetParent(); 
 294         int len 
= m_nodes
.GetCount(); 
 296         for ( int i 
= 0;i 
< len
; i 
++) 
 297             sum 
+= m_nodes
[i
]->GetSubTreeCount(); 
 299         sum 
+= m_leaves
.GetCount(); 
 302             ChangeSubTreeCount(-sum
); 
 308             ChangeSubTreeCount(sum
); 
 311     bool HasChildren() const { return m_hasChildren
; } 
 312     void SetHasChildren( bool has 
){ m_hasChildren 
= has
; } 
 314     void SetSubTreeCount( int num 
) { m_subTreeCount 
= num
; } 
 315     int GetSubTreeCount() const { return m_subTreeCount
; } 
 316     void ChangeSubTreeCount( int num 
) 
 320         m_subTreeCount 
+= num
; 
 322             m_parent
->ChangeSubTreeCount(num
); 
 329             m_nodes
.Sort( &wxGenericTreeModelNodeCmp 
); 
 330             int len 
= m_nodes
.GetCount(); 
 331             for (int i 
= 0; i 
< len
; i 
++) 
 332                 m_nodes
[i
]->Resort(); 
 333             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 338     wxDataViewTreeNode  
*m_parent
; 
 339     wxDataViewTreeNodes  m_nodes
; 
 340     wxDataViewTreeLeaves m_leaves
; 
 341     wxDataViewItem       m_item
; 
 347 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, wxDataViewTreeNode 
** node2
) 
 349     return g_model
->Compare( (*node1
)->GetItem(), (*node2
)->GetItem(), g_column
, g_asending 
); 
 352 int LINKAGEMODE 
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
) 
 354     return g_model
->Compare( *id1
, *id2
, g_column
, g_asending 
); 
 359 //----------------------------------------------------------------------------- 
 360 // wxDataViewMainWindow 
 361 //----------------------------------------------------------------------------- 
 363 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
, 
 365 WX_DECLARE_LIST(wxDataViewItem
, ItemList
); 
 366 WX_DEFINE_LIST(ItemList
) 
 368 class wxDataViewMainWindow
: public wxWindow
 
 371     wxDataViewMainWindow( wxDataViewCtrl 
*parent
, 
 373                             const wxPoint 
&pos 
= wxDefaultPosition
, 
 374                             const wxSize 
&size 
= wxDefaultSize
, 
 375                             const wxString 
&name 
= wxT("wxdataviewctrlmainwindow") ); 
 376     virtual ~wxDataViewMainWindow(); 
 378     bool IsVirtualList() const { return m_root 
== NULL
; } 
 380     // notifications from wxDataViewModel 
 381     bool ItemAdded( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 382     bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 383     bool ItemChanged( const wxDataViewItem 
&item 
); 
 384     bool ValueChanged( const wxDataViewItem 
&item
, unsigned int col 
); 
 388         if (!IsVirtualList()) 
 398         g_model 
= GetOwner()->GetModel(); 
 399         wxDataViewColumn
* col 
= GetOwner()->GetSortingColumn(); 
 402             if (g_model
->HasDefaultCompare()) 
 410         g_column 
= col
->GetModelColumn(); 
 411         g_asending 
= col
->IsSortOrderAscending(); 
 414     void SetOwner( wxDataViewCtrl
* owner 
) { m_owner 
= owner
; } 
 415     wxDataViewCtrl 
*GetOwner() { return m_owner
; } 
 416     const wxDataViewCtrl 
*GetOwner() const { return m_owner
; } 
 418     void OnPaint( wxPaintEvent 
&event 
); 
 419     void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
); 
 420     void OnChar( wxKeyEvent 
&event 
); 
 421     void OnMouse( wxMouseEvent 
&event 
); 
 422     void OnSetFocus( wxFocusEvent 
&event 
); 
 423     void OnKillFocus( wxFocusEvent 
&event 
); 
 425     void UpdateDisplay(); 
 426     void RecalculateDisplay(); 
 427     void OnInternalIdle(); 
 429     void OnRenameTimer(); 
 431     void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
= NULL 
); 
 432     void ScrollTo( int rows
, int column 
); 
 434     bool HasCurrentRow() { return m_currentRow 
!= (unsigned int)-1; } 
 435     void ChangeCurrentRow( unsigned int row 
); 
 437     bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); } 
 438     bool IsEmpty() { return GetRowCount() == 0; } 
 440     int GetCountPerPage() const; 
 441     int GetEndOfLastCol() const; 
 442     unsigned int GetFirstVisibleRow() const; 
 443     //I change this method to un const because in the tree view, the displaying number of the tree are changing along with the expanding/collapsing of the tree nodes 
 444     unsigned int GetLastVisibleRow(); 
 445     unsigned int GetRowCount(); 
 447     wxDataViewItem 
GetSelection() const; 
 448     wxDataViewSelection 
GetSelections(){ return m_selection
; } 
 449     void SetSelections( const wxDataViewSelection 
& sel 
) { m_selection 
= sel
; UpdateDisplay(); } 
 450     void Select( const wxArrayInt
& aSelections 
); 
 451     void SelectAllRows( bool on 
); 
 452     void SelectRow( unsigned int row
, bool on 
); 
 453     void SelectRows( unsigned int from
, unsigned int to
, bool on 
); 
 454     void ReverseRowSelection( unsigned int row 
); 
 455     bool IsRowSelected( unsigned int row 
); 
 456     void SendSelectionChangedEvent( const wxDataViewItem
& item
); 
 458     void RefreshRow( unsigned int row 
); 
 459     void RefreshRows( unsigned int from
, unsigned int to 
); 
 460     void RefreshRowsAfter( unsigned int firstRow 
); 
 462     // returns the colour to be used for drawing the rules 
 463     wxColour 
GetRuleColour() const 
 465         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 468     wxRect 
GetLineRect( unsigned int row 
) const; 
 470     int GetLineStart( unsigned int row 
) const;  // row * m_lineHeight in fixed mode 
 471     int GetLineHeight( unsigned int row 
) const; // m_lineHeight in fixed mode 
 472     int GetLineAt( unsigned int y 
) const;       // y / m_lineHeight in fixed mode 
 474     //Some useful functions for row and item mapping 
 475     wxDataViewItem 
GetItemByRow( unsigned int row 
) const; 
 476     int GetRowByItem( const wxDataViewItem 
& item 
) const; 
 478     //Methods for building the mapping tree 
 479     void BuildTree( wxDataViewModel  
* model 
); 
 481     void HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, wxDataViewColumn
* &column 
); 
 482     wxRect 
GetItemRect( const wxDataViewItem 
& item
, const wxDataViewColumn
* column 
); 
 484     void Expand( unsigned int row 
) { OnExpanding( row 
); } 
 485     void Collapse( unsigned int row 
) { OnCollapsing( row 
); } 
 486     bool IsExpanded( unsigned int row 
) const; 
 488     wxDataViewTreeNode 
* GetTreeNodeByRow( unsigned int row 
) const; 
 489     //We did not need this temporarily 
 490     //wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item ); 
 492     int RecalculateCount(); 
 494     wxDataViewEvent 
SendExpanderEvent( wxEventType type
, const wxDataViewItem 
& item 
); 
 495     void OnExpanding( unsigned int row 
); 
 496     void OnCollapsing( unsigned int row 
); 
 498     wxDataViewTreeNode 
* FindNode( const wxDataViewItem 
& item 
); 
 501     wxDataViewCtrl             
*m_owner
; 
 505     wxDataViewColumn           
*m_currentCol
; 
 506     unsigned int                m_currentRow
; 
 507     wxDataViewSelection         m_selection
; 
 509     wxDataViewRenameTimer      
*m_renameTimer
; 
 517     // for double click logic 
 518     unsigned int m_lineLastClicked
, 
 519            m_lineBeforeLastClicked
, 
 520            m_lineSelectSingleOnUp
; 
 522     // the pen used to draw horiz/vertical rules 
 525     // the pen used to draw the expander and the lines 
 528     //This is the tree structure of the model 
 529     wxDataViewTreeNode 
* m_root
; 
 531     //This is the tree node under the cursor 
 532     wxDataViewTreeNode 
* m_underMouse
; 
 534     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
) 
 535     DECLARE_EVENT_TABLE() 
 538 // --------------------------------------------------------- 
 539 // wxGenericDataViewModelNotifier 
 540 // --------------------------------------------------------- 
 542 class wxGenericDataViewModelNotifier
: public wxDataViewModelNotifier
 
 545     wxGenericDataViewModelNotifier( wxDataViewMainWindow 
*mainWindow 
) 
 546         { m_mainWindow 
= mainWindow
; } 
 548     virtual bool ItemAdded( const wxDataViewItem 
& parent
, const wxDataViewItem 
& item 
) 
 549         { return m_mainWindow
->ItemAdded( parent 
, item 
); } 
 550     virtual bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
) 
 551         { return m_mainWindow
->ItemDeleted( parent
, item 
); } 
 552     virtual bool ItemChanged( const wxDataViewItem 
& item 
) 
 553         { return m_mainWindow
->ItemChanged(item
);  } 
 554     virtual bool ValueChanged( const wxDataViewItem 
& item 
, unsigned int col 
) 
 555         { return m_mainWindow
->ValueChanged( item
, col 
); } 
 556     virtual bool Cleared() 
 557         { return m_mainWindow
->Cleared(); } 
 558     virtual void Resort() 
 559          { m_mainWindow
->Resort(); } 
 561     wxDataViewMainWindow    
*m_mainWindow
; 
 564 // --------------------------------------------------------- 
 565 // wxDataViewRenderer 
 566 // --------------------------------------------------------- 
 568 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
) 
 570 wxDataViewRenderer::wxDataViewRenderer( const wxString 
&varianttype
, 
 571                                         wxDataViewCellMode mode
, 
 573     wxDataViewRendererBase( varianttype
, mode
, align 
) 
 582 wxDataViewRenderer::~wxDataViewRenderer() 
 588 wxDC 
*wxDataViewRenderer::GetDC() 
 592         if (GetOwner() == NULL
) 
 594         if (GetOwner()->GetOwner() == NULL
) 
 596         m_dc 
= new wxClientDC( GetOwner()->GetOwner() ); 
 602 void wxDataViewRenderer::SetAlignment( int align 
) 
 607 int wxDataViewRenderer::GetAlignment() const 
 612 int wxDataViewRenderer::CalculateAlignment() const 
 614     if (m_align 
== wxDVR_DEFAULT_ALIGNMENT
) 
 616         if (GetOwner() == NULL
) 
 617            return wxALIGN_LEFT 
| wxALIGN_CENTRE_VERTICAL
; 
 619         return GetOwner()->GetAlignment() | wxALIGN_CENTRE_VERTICAL
; 
 625 // --------------------------------------------------------- 
 626 // wxDataViewCustomRenderer 
 627 // --------------------------------------------------------- 
 629 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
) 
 631 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString 
&varianttype
, 
 632                           wxDataViewCellMode mode
, int align 
) : 
 633     wxDataViewRenderer( varianttype
, mode
, align 
) 
 637 void wxDataViewCustomRenderer::RenderText( const wxString 
&text
, int xoffset
, wxRect cell
, wxDC 
*dc
, int state 
) 
 639     wxDataViewCtrl 
*view 
= GetOwner()->GetOwner(); 
 640     wxColour col 
= (state 
& wxDATAVIEW_CELL_SELECTED
) ? 
 641                         wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) : 
 642                         view
->GetForegroundColour(); 
 643     dc
->SetTextForeground(col
); 
 644     dc
->DrawText( text
, cell
.x 
+ xoffset
, cell
.y 
+ ((cell
.height 
- dc
->GetCharHeight()) / 2)); 
 647 // --------------------------------------------------------- 
 648 // wxDataViewTextRenderer 
 649 // --------------------------------------------------------- 
 651 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewCustomRenderer
) 
 653 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString 
&varianttype
, 
 654                                                 wxDataViewCellMode mode
, int align 
) : 
 655     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 659 bool wxDataViewTextRenderer::SetValue( const wxVariant 
&value 
) 
 661     m_text 
= value
.GetString(); 
 666 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 671 bool wxDataViewTextRenderer::HasEditorCtrl() 
 676 wxControl
* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow 
*parent
, 
 677         wxRect labelRect
, const wxVariant 
&value 
) 
 679     return new wxTextCtrl( parent
, wxID_ANY
, value
, 
 680                            wxPoint(labelRect
.x
,labelRect
.y
), 
 681                            wxSize(labelRect
.width
,labelRect
.height
) ); 
 684 bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl 
*editor
, wxVariant 
&value 
) 
 686     wxTextCtrl 
*text 
= (wxTextCtrl
*) editor
; 
 687     value 
= text
->GetValue(); 
 691 bool wxDataViewTextRenderer::Render( wxRect cell
, wxDC 
*dc
, int state 
) 
 693     RenderText( m_text
, 0, cell
, dc
, state 
); 
 697 wxSize 
wxDataViewTextRenderer::GetSize() const 
 699     const wxDataViewCtrl 
*view 
= GetView(); 
 703         view
->GetTextExtent( m_text
, &x
, &y 
); 
 704         return wxSize( x
, y 
); 
 706     return wxSize(80,20); 
 709 // --------------------------------------------------------- 
 710 // wxDataViewTextRendererAttr 
 711 // --------------------------------------------------------- 
 713 IMPLEMENT_CLASS(wxDataViewTextRendererAttr
, wxDataViewTextRenderer
) 
 715 wxDataViewTextRendererAttr::wxDataViewTextRendererAttr( const wxString 
&varianttype
, 
 716                             wxDataViewCellMode mode
, int align 
) : 
 717     wxDataViewTextRenderer( varianttype
, mode
, align 
) 
 722 bool wxDataViewTextRendererAttr::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 729         if (m_attr
.HasColour()) 
 731             colour 
= dc
->GetTextForeground(); 
 732             dc
->SetTextForeground( m_attr
.GetColour() ); 
 735         if (m_attr
.GetBold() || m_attr
.GetItalic()) 
 737              font 
= dc
->GetFont(); 
 738              wxFont myfont 
= font
; 
 739              if (m_attr
.GetBold()) 
 740                  myfont
.SetWeight( wxFONTWEIGHT_BOLD 
); 
 741              if (m_attr
.GetItalic()) 
 742                  myfont
.SetStyle( wxFONTSTYLE_ITALIC 
); 
 743              dc
->SetFont( myfont 
); 
 747     dc
->DrawText( m_text
, cell
.x
, cell
.y 
+ ((cell
.height 
- dc
->GetCharHeight()) / 2)); 
 752         if (m_attr
.HasColour()) 
 753             dc
->SetTextForeground( colour 
); 
 755         if (m_attr
.GetBold() || m_attr
.GetItalic()) 
 763 // --------------------------------------------------------- 
 764 // wxDataViewBitmapRenderer 
 765 // --------------------------------------------------------- 
 767 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewCustomRenderer
) 
 769 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString 
&varianttype
, 
 770                                                     wxDataViewCellMode mode
, int align 
) : 
 771     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 775 bool wxDataViewBitmapRenderer::SetValue( const wxVariant 
&value 
) 
 777     if (value
.GetType() == wxT("wxBitmap")) 
 779     if (value
.GetType() == wxT("wxIcon")) 
 785 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 790 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 793         dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y 
); 
 794     else if (m_icon
.Ok()) 
 795         dc
->DrawIcon( m_icon
, cell
.x
, cell
.y 
); 
 800 wxSize 
wxDataViewBitmapRenderer::GetSize() const 
 803         return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() ); 
 804     else if (m_icon
.Ok()) 
 805         return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() ); 
 807     return wxSize(16,16); 
 810 // --------------------------------------------------------- 
 811 // wxDataViewToggleRenderer 
 812 // --------------------------------------------------------- 
 814 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewCustomRenderer
) 
 816 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString 
&varianttype
, 
 817                         wxDataViewCellMode mode
, int align 
) : 
 818     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 823 bool wxDataViewToggleRenderer::SetValue( const wxVariant 
&value 
) 
 825     m_toggle 
= value
.GetBool(); 
 830 bool wxDataViewToggleRenderer::GetValue( wxVariant 
&WXUNUSED(value
) ) const 
 835 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 837     // User wxRenderer here 
 840     rect
.x 
= cell
.x 
+ cell
.width
/2 - 10; 
 842     rect
.y 
= cell
.y 
+ cell
.height
/2 - 10; 
 847         flags 
|= wxCONTROL_CHECKED
; 
 848     if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
) 
 849         flags 
|= wxCONTROL_DISABLED
; 
 851     wxRendererNative::Get().DrawCheckBox( 
 852             GetOwner()->GetOwner(), 
 860 bool wxDataViewToggleRenderer::Activate( wxRect 
WXUNUSED(cell
), 
 861                                          wxDataViewModel 
*model
, 
 862                                          const wxDataViewItem 
& item
, unsigned int col
) 
 864     bool value 
= !m_toggle
; 
 865     wxVariant variant 
= value
; 
 866     model
->SetValue( variant
, item
, col
); 
 867     model
->ValueChanged( item
, col 
); 
 871 wxSize 
wxDataViewToggleRenderer::GetSize() const 
 873     return wxSize(20,20); 
 876 // --------------------------------------------------------- 
 877 // wxDataViewProgressRenderer 
 878 // --------------------------------------------------------- 
 880 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
) 
 882 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString 
&label
, 
 883     const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
 884     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 890 wxDataViewProgressRenderer::~wxDataViewProgressRenderer() 
 894 bool wxDataViewProgressRenderer::SetValue( const wxVariant 
&value 
) 
 896     m_value 
= (long) value
; 
 898     if (m_value 
< 0) m_value 
= 0; 
 899     if (m_value 
> 100) m_value 
= 100; 
 904 bool wxDataViewProgressRenderer::GetValue( wxVariant 
&value 
) const 
 906     value 
= (long) m_value
; 
 910 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 912     double pct 
= (double)m_value 
/ 100.0; 
 914     bar
.width 
= (int)(cell
.width 
* pct
); 
 915     dc
->SetPen( *wxTRANSPARENT_PEN 
); 
 916     dc
->SetBrush( *wxBLUE_BRUSH 
); 
 917     dc
->DrawRectangle( bar 
); 
 919     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
 920     dc
->SetPen( *wxBLACK_PEN 
); 
 921     dc
->DrawRectangle( cell 
); 
 926 wxSize 
wxDataViewProgressRenderer::GetSize() const 
 928     return wxSize(40,12); 
 931 // --------------------------------------------------------- 
 932 // wxDataViewDateRenderer 
 933 // --------------------------------------------------------- 
 935 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN) 
 937 #if wxUSE_DATE_RENDERER_POPUP 
 939 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
 
 942     wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime 
*value
, 
 943         wxDataViewModel 
*model
, const wxDataViewItem 
& item
, unsigned int col
) : 
 944         wxPopupTransientWindow( parent
, wxBORDER_SIMPLE 
), 
 949         m_cal 
= new wxCalendarCtrl( this, wxID_ANY
, *value 
); 
 950         wxBoxSizer 
*sizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 951         sizer
->Add( m_cal
, 1, wxGROW 
); 
 956     void OnCalendar( wxCalendarEvent 
&event 
); 
 958     wxCalendarCtrl      
*m_cal
; 
 959     wxDataViewModel 
*m_model
; 
 961     const wxDataViewItem 
&   m_item
; 
 964     virtual void OnDismiss() 
 969     DECLARE_EVENT_TABLE() 
 972 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
) 
 973     EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar 
) 
 976 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent 
&event 
) 
 978     wxDateTime date 
= event
.GetDate(); 
 979     wxVariant value 
= date
; 
 980     m_model
->SetValue( value
, m_item
, m_col 
); 
 981     m_model
->ValueChanged( m_item
, m_col 
); 
 985 #endif // wxUSE_DATE_RENDERER_POPUP 
 987 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
) 
 989 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString 
&varianttype
, 
 990                         wxDataViewCellMode mode
, int align 
) : 
 991     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
 995 bool wxDataViewDateRenderer::SetValue( const wxVariant 
&value 
) 
 997     m_date 
= value
.GetDateTime(); 
1002 bool wxDataViewDateRenderer::GetValue( wxVariant 
&value 
) const 
1008 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC 
*dc
, int state 
) 
1010     wxString tmp 
= m_date
.FormatDate(); 
1011     RenderText( tmp
, 0, cell
, dc
, state 
); 
1015 wxSize 
wxDataViewDateRenderer::GetSize() const 
1017     const wxDataViewCtrl
* view 
= GetView(); 
1018     wxString tmp 
= m_date
.FormatDate(); 
1020     view
->GetTextExtent( tmp
, &x
, &y
, &d 
); 
1021     return wxSize(x
,y
+d
); 
1024 bool wxDataViewDateRenderer::Activate( wxRect 
WXUNUSED(cell
), wxDataViewModel 
*model
, 
1025                                        const wxDataViewItem 
& item
, unsigned int col 
) 
1028     model
->GetValue( variant
, item
, col 
); 
1029     wxDateTime value 
= variant
.GetDateTime(); 
1031 #if wxUSE_DATE_RENDERER_POPUP 
1032     wxDataViewDateRendererPopupTransient 
*popup 
= new wxDataViewDateRendererPopupTransient( 
1033         GetOwner()->GetOwner()->GetParent(), &value
, model
, item
, col
); 
1034     wxPoint pos 
= wxGetMousePosition(); 
1037     popup
->Popup( popup
->m_cal 
); 
1038 #else // !wxUSE_DATE_RENDERER_POPUP 
1039     wxMessageBox(value
.Format()); 
1040 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP 
1044 // --------------------------------------------------------- 
1045 // wxDataViewIconTextRenderer 
1046 // --------------------------------------------------------- 
1048 IMPLEMENT_CLASS(wxDataViewIconTextRenderer
, wxDataViewCustomRenderer
) 
1050 wxDataViewIconTextRenderer::wxDataViewIconTextRenderer( 
1051   const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
1052     wxDataViewCustomRenderer( varianttype
, mode
, align 
) 
1055     SetAlignment(align
); 
1058 wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer() 
1062 bool wxDataViewIconTextRenderer::SetValue( const wxVariant 
&value 
) 
1068 bool wxDataViewIconTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
1073 bool wxDataViewIconTextRenderer::Render( wxRect cell
, wxDC 
*dc
, int state 
) 
1076     const wxIcon 
&icon 
= m_value
.GetIcon(); 
1079         dc
->DrawIcon( icon
, cell
.x
, cell
.y 
+ ((cell
.height 
- icon
.GetHeight()) / 2)); 
1080         xoffset 
=  icon
.GetWidth()+4; 
1083     RenderText( m_value
.GetText(), xoffset
, cell
, dc
, state 
); 
1088 wxSize 
wxDataViewIconTextRenderer::GetSize() const 
1090     const wxDataViewCtrl 
*view 
= GetView(); 
1091     if (!m_value
.GetText().empty()) 
1094         view
->GetTextExtent( m_value
.GetText(), &x
, &y 
); 
1096         if (m_value
.GetIcon().IsOk()) 
1097             x 
+= m_value
.GetIcon().GetWidth() + 4; 
1098         return wxSize( x
, y 
); 
1100     return wxSize(80,20); 
1104 wxDataViewIconTextRenderer::CreateEditorCtrl(wxWindow 
* WXUNUSED(parent
), 
1105                                              wxRect 
WXUNUSED(labelRect
), 
1106                                              const wxVariant
& WXUNUSED(value
)) 
1112 wxDataViewIconTextRenderer::GetValueFromEditorCtrl(wxControl
* WXUNUSED(editor
), 
1113                                                    wxVariant
& WXUNUSED(value
)) 
1118 //----------------------------------------------------------------------------- 
1119 // wxDataViewRenameTimer 
1120 //----------------------------------------------------------------------------- 
1122 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
) 
1127 void wxDataViewRenameTimer::Notify() 
1129     m_owner
->OnRenameTimer(); 
1132 //----------------------------------------------------------------------------- 
1133 // wxDataViewMainWindow 
1134 //----------------------------------------------------------------------------- 
1136 //The tree building helper, declared firstly 
1137 static void BuildTreeHelper( wxDataViewModel 
* model
,  wxDataViewItem 
& item
, wxDataViewTreeNode 
* node
); 
1139 int LINKAGEMODE 
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2 
) 
1141     if (row1 
> row2
) return 1; 
1142     if (row1 
== row2
) return 0; 
1147 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
) 
1149 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
) 
1150     EVT_PAINT         (wxDataViewMainWindow::OnPaint
) 
1151     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse
) 
1152     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus
) 
1153     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus
) 
1154     EVT_CHAR          (wxDataViewMainWindow::OnChar
) 
1157 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl 
*parent
, wxWindowID id
, 
1158     const wxPoint 
&pos
, const wxSize 
&size
, const wxString 
&name 
) : 
1159     wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
|wxBORDER_NONE
, name 
), 
1160     m_selection( wxDataViewSelectionCmp 
) 
1165     m_lastOnSame 
= false; 
1166     m_renameTimer 
= new wxDataViewRenameTimer( this ); 
1168     // TODO: user better initial values/nothing selected 
1169     m_currentCol 
= NULL
; 
1172     m_lineHeight 
= wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1 
1175     m_dragStart 
= wxPoint(0,0); 
1176     m_lineLastClicked 
= (unsigned int) -1; 
1177     m_lineBeforeLastClicked 
= (unsigned int) -1; 
1178     m_lineSelectSingleOnUp 
= (unsigned int) -1; 
1182     SetBackgroundColour( *wxWHITE 
); 
1184     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
1186     m_penRule 
= wxPen(GetRuleColour()); 
1188     //Here I compose a pen can draw black lines, maybe there are something system colour to use 
1189     m_penExpander 
= wxPen(wxColour(0,0,0)); 
1190     //Some new added code to deal with the tree structure 
1191     m_root 
= new wxDataViewTreeNode( NULL 
); 
1192     m_root
->SetHasChildren(true); 
1194     //Make m_count = -1 will cause the class recaculate the real displaying number of rows. 
1196     m_underMouse 
= NULL
; 
1200 wxDataViewMainWindow::~wxDataViewMainWindow() 
1203     delete m_renameTimer
; 
1206 void wxDataViewMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1208     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1209     wxAutoBufferedPaintDC 
dc( this ); 
1212     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1213     dc
.SetBrush( wxBrush( GetBackgroundColour()) ); 
1214     dc
.SetBrush( *wxWHITE_BRUSH 
); 
1215     wxSize 
size( GetClientSize() ); 
1216     dc
.DrawRectangle( 0,0,size
.x
,size
.y 
); 
1220     GetOwner()->PrepareDC( dc 
); 
1221     dc
.SetFont( GetFont() ); 
1223     wxRect update 
= GetUpdateRegion().GetBox(); 
1224     m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y 
); 
1226     // compute which items needs to be redrawn 
1227     unsigned int item_start 
= GetLineAt( wxMax(0,update
.y
) ); 
1228     unsigned int item_count 
= 
1229         wxMin( (int)(  GetLineAt( wxMax(0,update
.y
+update
.height
) ) - item_start 
+ 1), 
1230                (int)(GetRowCount( ) - item_start
)); 
1231     unsigned int item_last 
= item_start 
+ item_count
; 
1233     // compute which columns needs to be redrawn 
1234     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1235     unsigned int col_start 
= 0; 
1236     unsigned int x_start
; 
1237     for (x_start 
= 0; col_start 
< cols
; col_start
++) 
1239         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_start
); 
1240         if (col
->IsHidden()) 
1241             continue;      // skip it! 
1243         unsigned int w 
= col
->GetWidth(); 
1244         if (x_start
+w 
>= (unsigned int)update
.x
) 
1250     unsigned int col_last 
= col_start
; 
1251     unsigned int x_last 
= x_start
; 
1252     for (; col_last 
< cols
; col_last
++) 
1254         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_last
); 
1255         if (col
->IsHidden()) 
1256             continue;      // skip it! 
1258         if (x_last 
> (unsigned int)update
.GetRight()) 
1261         x_last 
+= col
->GetWidth(); 
1264     // Draw horizontal rules if required 
1265     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
1267         dc
.SetPen(m_penRule
); 
1268         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1270         for (unsigned int i 
= item_start
; i 
<= item_last
+1; i
++) 
1272             int y 
= GetLineStart( i 
); 
1273             dc
.DrawLine(x_start
, y
, x_last
, y
); 
1277     // Draw vertical rules if required 
1278     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
1280         dc
.SetPen(m_penRule
); 
1281         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1284         for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1286             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(i
); 
1287             if (col
->IsHidden()) 
1288                 continue;       // skip it 
1290             dc
.DrawLine(x
, GetLineStart( item_start 
), 
1291                         x
, GetLineStart( item_last 
) ); 
1293             x 
+= col
->GetWidth(); 
1296         // Draw last vertical rule 
1297         dc
.DrawLine(x
, GetLineStart( item_start 
), 
1298                     x
, GetLineStart( item_last 
) ); 
1301     // redraw the background for the items which are selected/current 
1302     for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1304         bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1305         if (selected 
|| item 
== m_currentRow
) 
1307             int flags 
= selected 
? (int)wxCONTROL_SELECTED 
: 0; 
1308             if (item 
== m_currentRow
) 
1309                 flags 
|= wxCONTROL_CURRENT
; 
1311                 flags 
|= wxCONTROL_FOCUSED
; 
1313             wxRect 
rect( x_start
, GetLineStart( item 
), x_last
, GetLineHeight( item 
) ); 
1314             wxRendererNative::Get().DrawItemSelectionRect
 
1324     wxDataViewColumn 
*expander 
= GetOwner()->GetExpanderColumn(); 
1327         // TODO-RTL: last column for RTL support 
1328         expander 
= GetOwner()->GetColumnAt( 0 ); 
1329         GetOwner()->SetExpanderColumn(expander
); 
1332     // redraw all cells for all rows which must be repainted and all columns 
1334     cell_rect
.x 
= x_start
; 
1335     for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1338         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt( i 
); 
1339         wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
1340         cell_rect
.width 
= col
->GetWidth(); 
1342         if (col
->IsHidden()) 
1343             continue;       // skip it! 
1345         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1347             // get the cell value and set it into the renderer 
1349             wxDataViewTreeNode 
*node 
= NULL
; 
1350             wxDataViewItem dataitem
; 
1352             if (!IsVirtualList()) 
1354                 node 
= GetTreeNodeByRow(item
); 
1358                 dataitem 
= node
->GetItem(); 
1360                 if ((i 
> 0) && model
->IsContainer(dataitem
) && !model
->HasContainerColumns(dataitem
)) 
1365                 dataitem 
= wxDataViewItem( wxUIntToPtr(item
) ); 
1368             model
->GetValue( value
, dataitem
, col
->GetModelColumn()); 
1369             cell
->SetValue( value 
); 
1371             if (cell
->GetWantsAttr()) 
1373                 wxDataViewItemAttr attr
; 
1374                 bool ret 
= model
->GetAttr( dataitem
, col
->GetModelColumn(), attr 
); 
1376                     cell
->SetAttr( attr 
); 
1377                 cell
->SetHasAttr( ret 
); 
1381             cell_rect
.y 
= GetLineStart( item 
); 
1382             cell_rect
.height 
= GetLineHeight( item 
);     // -1 is for the horizontal rules (?) 
1384             //Draw the expander here. 
1386             if ((!IsVirtualList()) && (col 
== expander
)) 
1388                 indent 
= node
->GetIndentLevel(); 
1390                 //Calculate the indent first 
1391                 indent 
= cell_rect
.x 
+ GetOwner()->GetIndent() * indent
; 
1393                 int expander_width 
= m_lineHeight 
- 2*EXPANDER_MARGIN
; 
1394                 // change the cell_rect.x to the appropriate pos 
1395                 int  expander_x 
= indent 
+ EXPANDER_MARGIN
; 
1396                 int expander_y 
= cell_rect
.y 
+ EXPANDER_MARGIN 
+ (GetLineHeight(item
) / 2) - (expander_width
/2) - EXPANDER_OFFSET
; 
1397                 indent 
= indent 
+ m_lineHeight
;  //try to use the m_lineHeight as the expander space 
1398                 dc
.SetPen( m_penExpander 
); 
1399                 dc
.SetBrush( wxNullBrush 
); 
1400                 if( node
->HasChildren() ) 
1402                     wxRect 
rect( expander_x 
, expander_y
, expander_width
, expander_width
); 
1404                     if (m_underMouse 
== node
) 
1406                         flag 
|= wxCONTROL_CURRENT
; 
1408                     if( node
->IsOpen() ) 
1409                         wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
|wxCONTROL_EXPANDED 
); 
1411                         wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
); 
1413                  //force the expander column to left-center align 
1414                  cell
->SetAlignment( wxALIGN_CENTER_VERTICAL 
); 
1416             if (node 
&& !node
->HasChildren()) 
1418                 // Yes, if the node does not have any child, it must be a leaf which 
1419                 // mean that it is a temporarily created by GetTreeNodeByRow 
1423             // cannot be bigger than allocated space 
1424             wxSize size 
= cell
->GetSize(); 
1425             // Because of the tree structure indent, here we should minus the width of the cell for drawing 
1426             size
.x 
= wxMin( size
.x 
+ 2*PADDING_RIGHTLEFT
, cell_rect
.width 
- indent 
); 
1427             // size.y = wxMin( size.y, cell_rect.height ); 
1428             size
.y 
= cell_rect
.height
; 
1430             wxRect 
item_rect(cell_rect
.GetTopLeft(), size
); 
1431             int align 
= cell
->CalculateAlignment(); 
1433             // horizontal alignment: 
1434             item_rect
.x 
= cell_rect
.x
; 
1435             if (align 
& wxALIGN_CENTER_HORIZONTAL
) 
1436                 item_rect
.x 
= cell_rect
.x 
+ (cell_rect
.width 
/ 2) - (size
.x 
/ 2); 
1437             else if (align 
& wxALIGN_RIGHT
) 
1438                 item_rect
.x 
= cell_rect
.x 
+ cell_rect
.width 
- size
.x
; 
1439             //else: wxALIGN_LEFT is the default 
1441             // vertical alignment: 
1442             item_rect
.y 
= cell_rect
.y
; 
1443             if (align 
& wxALIGN_CENTER_VERTICAL
) 
1444                 item_rect
.y 
= cell_rect
.y 
+ (cell_rect
.height 
/ 2) - (size
.y 
/ 2); 
1445             else if (align 
& wxALIGN_BOTTOM
) 
1446                 item_rect
.y 
= cell_rect
.y 
+ cell_rect
.height 
- size
.y
; 
1447             //else: wxALIGN_TOP is the default 
1450             item_rect
.x 
+= PADDING_RIGHTLEFT
; 
1451             item_rect
.width 
= size
.x 
- 2 * PADDING_RIGHTLEFT
; 
1453             //Here we add the tree indent 
1454             item_rect
.x 
+= indent
; 
1457             if (m_hasFocus 
&& (m_selection
.Index(item
) != wxNOT_FOUND
)) 
1458                 state 
|= wxDATAVIEW_CELL_SELECTED
; 
1460             // TODO: it would be much more efficient to create a clipping 
1461             //       region for the entire column being rendered (in the OnPaint 
1462             //       of wxDataViewMainWindow) instead of a single clip region for 
1463             //       each cell. However it would mean that each renderer should 
1464             //       respect the given wxRect's top & bottom coords, eventually 
1465             //       violating only the left & right coords - however the user can 
1466             //       make its own renderer and thus we cannot be sure of that. 
1467             dc
.SetClippingRegion( item_rect 
); 
1468             cell
->Render( item_rect
, &dc
, state 
); 
1469             dc
.DestroyClippingRegion(); 
1472         cell_rect
.x 
+= cell_rect
.width
; 
1476 void wxDataViewMainWindow::OnRenameTimer() 
1478     // We have to call this here because changes may just have 
1479     // been made and no screen update taken place. 
1484     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1486     for (i 
= 0; i 
< cols
; i
++) 
1488         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt( i 
); 
1490             continue;      // skip it! 
1492         if (c 
== m_currentCol
) 
1494         xpos 
+= c
->GetWidth(); 
1496     wxRect 
labelRect( xpos
, 
1497                       GetLineStart( m_currentRow 
), 
1498                       m_currentCol
->GetWidth(), 
1499                       GetLineHeight( m_currentRow 
) ); 
1501     GetOwner()->CalcScrolledPosition( labelRect
.x
, labelRect
.y
, 
1502                                      &labelRect
.x
, &labelRect
.y
); 
1504     wxDataViewItem item 
= GetItemByRow( m_currentRow 
); 
1505     m_currentCol
->GetRenderer()->StartEditing( item
, labelRect 
); 
1509 //------------------------------------------------------------------ 
1510 // Helper class for do operation on the tree node 
1511 //------------------------------------------------------------------ 
1516     virtual ~DoJob() { } 
1518     //The return value control how the tree-walker tranverse the tree 
1519     // 0: Job done, stop tranverse and return 
1520     // 1: Ignore the current node's subtree and continue 
1521     // 2: Job not done, continue 
1522     enum  { OK 
= 0 , IGR 
= 1, CONT 
= 2 }; 
1523     virtual int operator() ( wxDataViewTreeNode 
* node 
) = 0; 
1524     virtual int operator() ( void * n 
) = 0; 
1527 bool Walker( wxDataViewTreeNode 
* node
, DoJob 
& func 
) 
1532     switch( func( node 
) ) 
1543     wxDataViewTreeNodes nodes 
= node
->GetNodes(); 
1544     wxDataViewTreeLeaves leaves 
= node
->GetChildren(); 
1546     int len_nodes 
= nodes
.GetCount(); 
1547     int len 
= leaves
.GetCount(); 
1548     int i 
= 0, nodes_i 
= 0; 
1550     for(; i 
< len
; i 
++ ) 
1552         void * n 
= leaves
[i
]; 
1553         if( nodes_i 
< len_nodes 
&& n 
== nodes
[nodes_i
]->GetItem().GetID() ) 
1555             wxDataViewTreeNode 
* nd 
= nodes
[nodes_i
]; 
1558             if( Walker( nd 
, func 
) ) 
1577 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem 
& parent
, const wxDataViewItem 
& item
) 
1588     wxDataViewTreeNode 
* node
; 
1589     node 
= FindNode(parent
); 
1594     node
->SetHasChildren( true ); 
1596     if( g_model
->IsContainer( item 
) ) 
1598         wxDataViewTreeNode 
* newnode 
= new wxDataViewTreeNode( node 
); 
1599         newnode
->SetItem(item
); 
1600         newnode
->SetHasChildren( true ); 
1601         node
->AddNode( newnode
); 
1604         node
->AddLeaf( item
.GetID() ); 
1606     node
->ChangeSubTreeCount(1); 
1614 static void DestroyTreeHelper( wxDataViewTreeNode 
* node
); 
1616 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem
& parent
, 
1617                                        const wxDataViewItem
& item
) 
1622         if( m_currentRow 
> GetRowCount() ) 
1623             m_currentRow 
= m_count 
- 1; 
1625         m_selection
.Empty(); 
1632     wxDataViewTreeNode 
* node 
= FindNode(parent
); 
1634     wxCHECK_MSG( node 
!= NULL
, false, "item not found" ); 
1635     wxCHECK_MSG( node
->GetChildren().Index( item
.GetID() ) != wxNOT_FOUND
, false, "item not found" ); 
1638     node
->GetChildren().Remove( item
.GetID() ); 
1639     //Manuplate selection 
1640     if( m_selection
.GetCount() > 1 ) 
1642         m_selection
.Empty(); 
1644     bool isContainer 
= false; 
1645     wxDataViewTreeNodes nds 
= node
->GetNodes(); 
1646     for (size_t i 
= 0; i 
< nds
.GetCount(); i 
++) 
1648         if (nds
[i
]->GetItem() == item
) 
1656         wxDataViewTreeNode 
* n 
= NULL
; 
1657         wxDataViewTreeNodes nodes 
= node
->GetNodes(); 
1658         int len 
= nodes
.GetCount(); 
1659         for( int i 
= 0; i 
< len
; i 
++) 
1661             if( nodes
[i
]->GetItem() == item 
) 
1668         wxCHECK_MSG( n 
!= NULL
, false, "item not found" ); 
1670         node
->GetNodes().Remove( n 
); 
1671         sub 
-= n
->GetSubTreeCount(); 
1672         ::DestroyTreeHelper(n
); 
1674     //Make the row number invalid and get a new valid one when user call GetRowCount 
1676     node
->ChangeSubTreeCount(sub
); 
1678     //Change the current row to the last row if the current exceed the max row number 
1679     if( m_currentRow 
> GetRowCount() ) 
1680         m_currentRow 
= m_count 
- 1; 
1687 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem 
& item
) 
1693     wxWindow 
*parent 
= GetParent(); 
1694     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
1695     le
.SetEventObject(parent
); 
1696     le
.SetModel(GetOwner()->GetModel()); 
1698     parent
->GetEventHandler()->ProcessEvent(le
); 
1703 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem 
& item
, unsigned int col 
) 
1705     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 
1706 /*#define MAX_VIRTUAL_WIDTH       100000 
1708     wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight ); 
1709     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); 
1710     Refresh( true, &rect ); 
1718     wxWindow 
*parent 
= GetParent(); 
1719     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
1720     le
.SetEventObject(parent
); 
1721     le
.SetModel(GetOwner()->GetModel()); 
1724     le
.SetDataViewColumn(GetOwner()->GetColumn(col
)); 
1725     parent
->GetEventHandler()->ProcessEvent(le
); 
1730 bool wxDataViewMainWindow::Cleared() 
1735     BuildTree( GetOwner()->GetModel() ); 
1742 void wxDataViewMainWindow::UpdateDisplay() 
1747 void wxDataViewMainWindow::OnInternalIdle() 
1749     wxWindow::OnInternalIdle(); 
1753         RecalculateDisplay(); 
1758 void wxDataViewMainWindow::RecalculateDisplay() 
1760     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1767     int width 
= GetEndOfLastCol(); 
1768     int height 
= GetLineStart( GetRowCount() ); 
1770     SetVirtualSize( width
, height 
); 
1771     GetOwner()->SetScrollRate( 10, m_lineHeight 
); 
1776 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
1778     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
1780     if (GetOwner()->m_headerArea
) 
1781         GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 ); 
1784 void wxDataViewMainWindow::ScrollTo( int rows
, int column 
) 
1787     m_owner
->GetScrollPixelsPerUnit( &x
, &y 
); 
1788     int sy 
= GetLineStart( rows 
)/y
; 
1792         wxRect rect 
= GetClientRect(); 
1796         m_owner
->CalcUnscrolledPosition( rect
.x
, rect
.y
, &xx
, &yy 
); 
1797         for (x_start 
= 0; colnum 
< column
; colnum
++) 
1799             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(colnum
); 
1800             if (col
->IsHidden()) 
1801                 continue;      // skip it! 
1803             w 
= col
->GetWidth(); 
1807         int x_end 
= x_start 
+ w
; 
1808         xe 
= xx 
+ rect
.width
; 
1811             sx 
= ( xx 
+ x_end 
- xe 
)/x
; 
1818     m_owner
->Scroll( sx
, sy 
); 
1821 int wxDataViewMainWindow::GetCountPerPage() const 
1823     wxSize size 
= GetClientSize(); 
1824     return size
.y 
/ m_lineHeight
; 
1827 int wxDataViewMainWindow::GetEndOfLastCol() const 
1831     for (i 
= 0; i 
< GetOwner()->GetColumnCount(); i
++) 
1833         const wxDataViewColumn 
*c 
= 
1834             const_cast<wxDataViewCtrl
*>(GetOwner())->GetColumnAt( i 
); 
1837             width 
+= c
->GetWidth(); 
1842 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const 
1846     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
1848     return GetLineAt( y 
); 
1851 unsigned int wxDataViewMainWindow::GetLastVisibleRow() 
1853     wxSize client_size 
= GetClientSize(); 
1854     m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
, 
1855                                      &client_size
.x
, &client_size
.y 
); 
1857     //we should deal with the pixel here 
1858     unsigned int row 
= GetLineAt(client_size
.y
) - 1; 
1860     return wxMin( GetRowCount()-1, row 
); 
1863 unsigned int wxDataViewMainWindow::GetRowCount() 
1865     if ( m_count 
== -1 ) 
1867         m_count 
= RecalculateCount(); 
1873 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row 
) 
1880 void wxDataViewMainWindow::SelectAllRows( bool on 
) 
1887         m_selection
.Clear(); 
1888         for (unsigned int i 
= 0; i 
< GetRowCount(); i
++) 
1889             m_selection
.Add( i 
); 
1894         unsigned int first_visible 
= GetFirstVisibleRow(); 
1895         unsigned int last_visible 
= GetLastVisibleRow(); 
1897         for (i 
= 0; i 
< m_selection
.GetCount(); i
++) 
1899             unsigned int row 
= m_selection
[i
]; 
1900             if ((row 
>= first_visible
) && (row 
<= last_visible
)) 
1903         m_selection
.Clear(); 
1907 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on 
) 
1909     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
1913             m_selection
.Add( row 
); 
1921             m_selection
.Remove( row 
); 
1927 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on 
) 
1931         unsigned int tmp 
= from
; 
1937     for (i 
= from
; i 
<= to
; i
++) 
1939         if (m_selection
.Index( i 
) == wxNOT_FOUND
) 
1942                 m_selection
.Add( i 
); 
1947                 m_selection
.Remove( i 
); 
1950     RefreshRows( from
, to 
); 
1953 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections 
) 
1955     for (size_t i
=0; i 
< aSelections
.GetCount(); i
++) 
1957         int n 
= aSelections
[i
]; 
1959         m_selection
.Add( n 
); 
1964 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row 
) 
1966     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
1967         m_selection
.Add( row 
); 
1969         m_selection
.Remove( row 
); 
1973 bool wxDataViewMainWindow::IsRowSelected( unsigned int row 
) 
1975     return (m_selection
.Index( row 
) != wxNOT_FOUND
); 
1978 void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem
& item
) 
1980     wxWindow 
*parent 
= GetParent(); 
1981     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED
, parent
->GetId()); 
1983     le
.SetEventObject(parent
); 
1984     le
.SetModel(GetOwner()->GetModel()); 
1987     parent
->GetEventHandler()->ProcessEvent(le
); 
1990 void wxDataViewMainWindow::RefreshRow( unsigned int row 
) 
1992     wxRect 
rect( 0, GetLineStart( row 
), GetEndOfLastCol(), GetLineHeight( row 
) ); 
1993     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
1995     wxSize client_size 
= GetClientSize(); 
1996     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
1997     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
1998     if (intersect_rect
.width 
> 0) 
1999         Refresh( true, &intersect_rect 
); 
2002 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to 
) 
2006         unsigned int tmp 
= to
; 
2011     wxRect 
rect( 0, GetLineStart( from 
), GetEndOfLastCol(), GetLineStart( (to
-from
+1) ) ); 
2012     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2014     wxSize client_size 
= GetClientSize(); 
2015     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2016     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2017     if (intersect_rect
.width 
> 0) 
2018         Refresh( true, &intersect_rect 
); 
2021 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow 
) 
2023     wxSize client_size 
= GetClientSize(); 
2024     int start 
= GetLineStart( firstRow 
); 
2025     m_owner
->CalcScrolledPosition( start
, 0, &start
, NULL 
); 
2026     if (start 
> client_size
.y
) return; 
2028     wxRect 
rect( 0, start
, client_size
.x
, client_size
.y 
- start 
); 
2030     Refresh( true, &rect 
); 
2033 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
) 
2035     wxCHECK_RET( newCurrent 
< GetRowCount(), 
2036                  _T("invalid item index in OnArrowChar()") ); 
2038     // if there is no selection, we cannot move it anywhere 
2039     if (!HasCurrentRow()) 
2042     unsigned int oldCurrent 
= m_currentRow
; 
2044     // in single selection we just ignore Shift as we can't select several 
2046     if ( event
.ShiftDown() && !IsSingleSel() ) 
2048         RefreshRow( oldCurrent 
); 
2050         ChangeCurrentRow( newCurrent 
); 
2052         // select all the items between the old and the new one 
2053         if ( oldCurrent 
> newCurrent 
) 
2055             newCurrent 
= oldCurrent
; 
2056             oldCurrent 
= m_currentRow
; 
2059         SelectRows( oldCurrent
, newCurrent
, true ); 
2060         if (oldCurrent
!=newCurrent
) 
2061             SendSelectionChangedEvent(GetItemByRow(m_selection
[0])); 
2065         RefreshRow( oldCurrent 
); 
2067         // all previously selected items are unselected unless ctrl is held 
2068         if ( !event
.ControlDown() ) 
2069             SelectAllRows(false); 
2071         ChangeCurrentRow( newCurrent 
); 
2073         if ( !event
.ControlDown() ) 
2075             SelectRow( m_currentRow
, true ); 
2076             SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
2079             RefreshRow( m_currentRow 
); 
2082     GetOwner()->EnsureVisible( m_currentRow
, -1 ); 
2085 wxRect 
wxDataViewMainWindow::GetLineRect( unsigned int row 
) const 
2089     rect
.y 
= GetLineStart( row 
); 
2090     rect
.width 
= GetEndOfLastCol(); 
2091     rect
.height 
= GetLineHeight( row 
); 
2096 int wxDataViewMainWindow::GetLineStart( unsigned int row 
) const 
2098     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2100     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2102         // TODO make more efficient 
2107         for (r 
= 0; r 
< row
; r
++) 
2109             const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(r
); 
2110             if (!node
) return start
; 
2112             wxDataViewItem item 
= node
->GetItem(); 
2114             if (node 
&& !node
->HasChildren()) 
2116                 // Yes, if the node does not have any child, it must be a leaf which 
2117                 // mean that it is a temporarily created by GetTreeNodeByRow 
2121             unsigned int cols 
= GetOwner()->GetColumnCount(); 
2123             int height 
= m_lineHeight
; 
2124             for (col 
= 0; col 
< cols
; col
++) 
2126                 const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2127                 if (column
->IsHidden()) 
2128                     continue;      // skip it! 
2130                 if ((col 
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
)) 
2131                     continue;      // skip it! 
2133                 const wxDataViewRenderer 
*renderer 
= column
->GetRenderer(); 
2135                 model
->GetValue( value
, item
, column
->GetModelColumn() ); 
2136                 wxDataViewRenderer 
*renderer2 
= const_cast<wxDataViewRenderer
*>(renderer
); 
2137                 renderer2
->SetValue( value 
); 
2138                 height 
= wxMax( height
, renderer
->GetSize().y 
); 
2149         return row 
* m_lineHeight
; 
2153 int wxDataViewMainWindow::GetLineAt( unsigned int y 
) const 
2155     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2157     // check for the easy case first 
2158     if ( !GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT
) ) 
2159         return y 
/ m_lineHeight
; 
2161     // TODO make more efficient 
2162     unsigned int row 
= 0; 
2163     unsigned int yy 
= 0; 
2166        const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2169            // not really correct... 
2170            return row 
+ ((y
-yy
) / m_lineHeight
); 
2173        wxDataViewItem item 
= node
->GetItem(); 
2175         if (node 
&& !node
->HasChildren()) 
2177             // Yes, if the node does not have any child, it must be a leaf which 
2178             // mean that it is a temporarily created by GetTreeNodeByRow 
2182        unsigned int cols 
= GetOwner()->GetColumnCount(); 
2184        int height 
= m_lineHeight
; 
2185        for (col 
= 0; col 
< cols
; col
++) 
2187             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2188             if (column
->IsHidden()) 
2189                 continue;      // skip it! 
2191             if ((col 
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
)) 
2192                 continue;      // skip it! 
2194             const wxDataViewRenderer 
*renderer 
= column
->GetRenderer(); 
2196             model
->GetValue( value
, item
, column
->GetModelColumn() ); 
2197             wxDataViewRenderer 
*renderer2 
= const_cast<wxDataViewRenderer
*>(renderer
); 
2198             renderer2
->SetValue( value 
); 
2199             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2210 int wxDataViewMainWindow::GetLineHeight( unsigned int row 
) const 
2212     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2214     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2216         wxASSERT( !IsVirtualList() ); 
2218         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2219         // wxASSERT( node ); 
2220         if (!node
) return m_lineHeight
; 
2222         wxDataViewItem item 
= node
->GetItem(); 
2224         if (node 
&& !node
->HasChildren()) 
2226                 // Yes, if the node does not have any child, it must be a leaf which 
2227                 // mean that it is a temporarily created by GetTreeNodeByRow 
2231         int height 
= m_lineHeight
; 
2233         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2235         for (col 
= 0; col 
< cols
; col
++) 
2237             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2238             if (column
->IsHidden()) 
2239                 continue;      // skip it! 
2241             if ((col 
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
)) 
2242                 continue;      // skip it! 
2244             const wxDataViewRenderer 
*renderer 
= column
->GetRenderer(); 
2246             model
->GetValue( value
, item
, column
->GetModelColumn() ); 
2247             wxDataViewRenderer 
*renderer2 
= const_cast<wxDataViewRenderer
*>(renderer
); 
2248             renderer2
->SetValue( value 
); 
2249             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2256         return m_lineHeight
; 
2260 class RowToItemJob
: public DoJob
 
2263     RowToItemJob( unsigned int row 
, int current 
) { this->row 
= row
; this->current 
= current
;} 
2264     virtual ~RowToItemJob() { } 
2266     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2269         if( current 
== static_cast<int>(row
)) 
2271             ret 
= node
->GetItem(); 
2275         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2277             current 
+= node
->GetSubTreeCount(); 
2282             //If the current has no child node, we can find the desired item of the row number directly. 
2283             //This if can speed up finding in some case, and will has a very good effect when it comes to list view 
2284             if( node
->GetNodes().GetCount() == 0) 
2286                 int index 
= static_cast<int>(row
) - current 
- 1; 
2287                 ret 
= node
->GetChildren().Item( index 
); 
2294     virtual int operator() ( void * n 
) 
2297         if( current 
== static_cast<int>(row
)) 
2299             ret 
= wxDataViewItem( n 
); 
2304     wxDataViewItem 
GetResult(){ return ret
; } 
2311 wxDataViewItem 
wxDataViewMainWindow::GetItemByRow(unsigned int row
) const 
2315         return wxDataViewItem( wxUIntToPtr(row
) ); 
2319         RowToItemJob 
job( row
, -2 ); 
2320         Walker( m_root 
, job 
); 
2321         return job
.GetResult(); 
2325 class RowToTreeNodeJob
: public DoJob
 
2328     RowToTreeNodeJob( unsigned int row 
, int current
, wxDataViewTreeNode 
* node 
) 
2331         this->current 
= current
; 
2335     virtual ~RowToTreeNodeJob(){ } 
2337     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2340         if( current 
== static_cast<int>(row
)) 
2346         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2348             current 
+= node
->GetSubTreeCount(); 
2354             //If the current has no child node, we can find the desired item of the row number directly. 
2355             //This if can speed up finding in some case, and will has a very good effect when it comes to list view 
2356             if( node
->GetNodes().GetCount() == 0) 
2358                 int index 
= static_cast<int>(row
) - current 
- 1; 
2359                 void * n 
= node
->GetChildren().Item( index 
); 
2360                 ret 
= new wxDataViewTreeNode( parent 
); 
2361                 ret
->SetItem( wxDataViewItem( n 
)); 
2362                 ret
->SetHasChildren(false); 
2371     virtual int operator() ( void * n 
) 
2374         if( current 
== static_cast<int>(row
)) 
2376             ret 
= new wxDataViewTreeNode( parent 
); 
2377             ret
->SetItem( wxDataViewItem( n 
)); 
2378             ret
->SetHasChildren(false); 
2384     wxDataViewTreeNode 
* GetResult(){ return ret
; } 
2388     wxDataViewTreeNode 
* ret
; 
2389     wxDataViewTreeNode 
* parent
; 
2393 wxDataViewTreeNode 
* wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row
) const 
2395     wxASSERT( !IsVirtualList() ); 
2397     RowToTreeNodeJob 
job( row 
, -2, m_root 
); 
2398     Walker( m_root 
, job 
); 
2399     return job
.GetResult(); 
2402 wxDataViewEvent 
wxDataViewMainWindow::SendExpanderEvent( wxEventType type
, const wxDataViewItem 
& item 
) 
2404     wxWindow 
*parent 
= GetParent(); 
2405     wxDataViewEvent 
le(type
, parent
->GetId()); 
2407     le
.SetEventObject(parent
); 
2408     le
.SetModel(GetOwner()->GetModel()); 
2411     parent
->GetEventHandler()->ProcessEvent(le
); 
2416 bool wxDataViewMainWindow::IsExpanded( unsigned int row 
) const 
2418     if (IsVirtualList()) 
2421     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2425     if (!node
->HasChildren()) 
2428     return node
->IsOpen(); 
2432 void wxDataViewMainWindow::OnExpanding( unsigned int row 
) 
2434     if (IsVirtualList()) 
2437     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2440         if( node
->HasChildren()) 
2442             if( !node
->IsOpen()) 
2444                wxDataViewEvent e 
= SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING
,node
->GetItem()); 
2445                //Check if the user prevent expanding 
2446                if( e
.GetSkipped() ) 
2450                //Here I build the children of current node 
2451                if( node
->GetChildrenNumber() == 0 ) 
2454                    ::BuildTreeHelper(GetOwner()->GetModel(), node
->GetItem(), node
); 
2458                //Send the expanded event 
2459                SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED
,node
->GetItem()); 
2463                 SelectRow( row
, false ); 
2464                 SelectRow( row 
+ 1, true ); 
2465                 ChangeCurrentRow( row 
+ 1 ); 
2466                 SendSelectionChangedEvent( GetItemByRow(row
+1)); 
2474 void wxDataViewMainWindow::OnCollapsing(unsigned int row
) 
2476     if (IsVirtualList()) 
2479     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2482         wxDataViewTreeNode 
* nd 
= node
; 
2484         if( node
->HasChildren() && node
->IsOpen() ) 
2486             wxDataViewEvent e 
= SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING
,node
->GetItem()); 
2487             if( e
.GetSkipped() ) 
2492             SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED
,nd
->GetItem()); 
2496             node 
= node
->GetParent(); 
2499                 int  parent 
= GetRowByItem( node
->GetItem() ); 
2502                     SelectRow( row
, false); 
2503                     SelectRow(parent 
, true ); 
2504                     ChangeCurrentRow( parent 
); 
2505                     SendSelectionChangedEvent( node
->GetItem() ); 
2509         if( !nd
->HasChildren()) 
2514 wxDataViewTreeNode 
* wxDataViewMainWindow::FindNode( const wxDataViewItem 
& item 
) 
2516     wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
2520     //Compose the a parent-chain of the finding item 
2522     list
.DeleteContents( true ); 
2523     wxDataViewItem 
it( item 
); 
2526         wxDataViewItem 
* pItem 
= new wxDataViewItem( it 
); 
2527         list
.Insert( pItem 
); 
2528         it 
= model
->GetParent( it 
); 
2531     //Find the item along the parent-chain. 
2532     //This algorithm is designed to speed up the node-finding method 
2533     wxDataViewTreeNode 
* node 
= m_root
; 
2534     for( ItemList::const_iterator iter 
= list
.begin(); iter 
!=list
.end(); iter
++ ) 
2536         if( node
->HasChildren() ) 
2538             if( node
->GetChildrenNumber() == 0 ) 
2541                 ::BuildTreeHelper(model
, node
->GetItem(), node
); 
2544             wxDataViewTreeNodes nodes 
= node
->GetNodes(); 
2548             for (i 
= 0; i 
< nodes
.GetCount(); i 
++) 
2550                 if (nodes
[i
]->GetItem() == (**iter
)) 
2552                     if (nodes
[i
]->GetItem() == item
) 
2569 void wxDataViewMainWindow::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, wxDataViewColumn
* &column 
) 
2571     wxDataViewColumn 
*col 
= NULL
; 
2572     unsigned int cols 
= GetOwner()->GetColumnCount(); 
2573     unsigned int colnum 
= 0; 
2575     m_owner
->CalcUnscrolledPosition( point
.x
, point
.y
, &x
, &y 
); 
2576     for (unsigned x_start 
= 0; colnum 
< cols
; colnum
++) 
2578         col 
= GetOwner()->GetColumnAt(colnum
); 
2579         if (col
->IsHidden()) 
2580             continue;      // skip it! 
2582         unsigned int w 
= col
->GetWidth(); 
2583         if (x_start
+w 
>= (unsigned int)x
) 
2590     item 
= GetItemByRow( GetLineAt( y 
) ); 
2593 wxRect 
wxDataViewMainWindow::GetItemRect( const wxDataViewItem 
& item
, const wxDataViewColumn
* column 
) 
2595     int row 
= GetRowByItem(item
); 
2596     int y 
= GetLineStart( row 
); 
2597     int h 
= GetLineHeight( m_lineHeight 
); 
2599     wxDataViewColumn 
*col 
= NULL
; 
2600     for( int i 
= 0, cols 
= GetOwner()->GetColumnCount(); i 
< cols
; i 
++ ) 
2602        col 
= GetOwner()->GetColumnAt( i 
); 
2603        x 
+= col
->GetWidth(); 
2604        if( GetOwner()->GetColumnAt(i
+1) == column 
) 
2607     int w 
= col
->GetWidth(); 
2608     m_owner
->CalcScrolledPosition( x
, y
, &x
, &y 
); 
2609     return wxRect(x
, y
, w
, h
); 
2612 int wxDataViewMainWindow::RecalculateCount() 
2616         wxDataViewIndexListModel 
*list_model 
= (wxDataViewIndexListModel
*) GetOwner()->GetModel(); 
2618         return list_model
->GetLastIndex() + 1; 
2620         return list_model
->GetLastIndex() - 1; 
2625         return m_root
->GetSubTreeCount(); 
2629 class ItemToRowJob 
: public DoJob
 
2632     ItemToRowJob(const wxDataViewItem
& item_
, ItemList::const_iterator iter
) 
2639     //Maybe binary search will help to speed up this process 
2640     virtual int operator() ( wxDataViewTreeNode 
* node
) 
2643          if( node
->GetItem() == item 
) 
2648          if( node
->GetItem() == **m_iter 
) 
2655              ret 
+= node
->GetSubTreeCount(); 
2661     virtual int operator() ( void * n 
) 
2664         if( n 
== item
.GetID() ) 
2668     //the row number is begin from zero 
2669     int GetResult() { return ret 
-1; } 
2672     ItemList::const_iterator  m_iter
; 
2673     wxDataViewItem item
; 
2678 int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem 
& item
) const 
2680     const wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
2686         return wxPtrToUInt( item
.GetID() ); 
2693         //Compose the a parent-chain of the finding item 
2695         wxDataViewItem 
* pItem
; 
2696         list
.DeleteContents( true ); 
2697         wxDataViewItem 
it( item 
); 
2700             pItem 
= new wxDataViewItem( it 
); 
2701             list
.Insert( pItem 
); 
2702             it 
= model
->GetParent( it 
); 
2704         pItem 
= new wxDataViewItem( ); 
2705         list
.Insert( pItem 
); 
2707         ItemToRowJob 
job( item
, list
.begin() ); 
2708         Walker(m_root 
, job 
); 
2709         return job
.GetResult(); 
2713 static void BuildTreeHelper( wxDataViewModel 
* model
,  wxDataViewItem 
& item
, wxDataViewTreeNode 
* node
) 
2715     if( !model
->IsContainer( item 
) ) 
2718     wxDataViewItemArray children
; 
2719     unsigned int num 
= model
->GetChildren( item
, children
); 
2720     unsigned int index 
= 0; 
2721     while( index 
< num 
) 
2723         if( model
->IsContainer( children
[index
] ) ) 
2725             wxDataViewTreeNode 
* n 
= new wxDataViewTreeNode( node 
); 
2726             n
->SetItem(children
[index
]); 
2727             n
->SetHasChildren( true ); 
2732             node
->AddLeaf( children
[index
].GetID() ); 
2736     node
->SetSubTreeCount( num 
); 
2737     wxDataViewTreeNode 
* n 
= node
->GetParent(); 
2739         n
->ChangeSubTreeCount(num
); 
2743 void wxDataViewMainWindow::BuildTree(wxDataViewModel 
* model
) 
2747     if (GetOwner()->GetModel()->IsVirtualListModel()) 
2753     m_root 
= new wxDataViewTreeNode( NULL 
); 
2754     m_root
->SetHasChildren(true); 
2756     //First we define a invalid item to fetch the top-level elements 
2757     wxDataViewItem item
; 
2759     BuildTreeHelper( model
, item
, m_root
); 
2763 static void DestroyTreeHelper( wxDataViewTreeNode 
* node 
) 
2765     if( node
->GetNodeNumber() != 0 ) 
2767         int len 
= node
->GetNodeNumber(); 
2769         wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
2770         for(; i 
< len
; i 
++ ) 
2772             DestroyTreeHelper(nodes
[i
]); 
2778 void wxDataViewMainWindow::DestroyTree() 
2780     if (!IsVirtualList()) 
2782        ::DestroyTreeHelper(m_root
); 
2788 void wxDataViewMainWindow::OnChar( wxKeyEvent 
&event 
) 
2790     if ( GetParent()->HandleAsNavigationKey(event
) ) 
2793     // no item -> nothing to do 
2794     if (!HasCurrentRow()) 
2800     // don't use m_linesPerPage directly as it might not be computed yet 
2801     const int pageSize 
= GetCountPerPage(); 
2802     wxCHECK_RET( pageSize
, _T("should have non zero page size") ); 
2804     switch ( event
.GetKeyCode() ) 
2808             if (m_currentRow 
> 0) 
2810                 wxWindow 
*parent 
= GetParent(); 
2811                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId()); 
2812                 le
.SetItem( GetItemByRow(m_currentRow
) ); 
2813                 le
.SetEventObject(parent
); 
2814                 le
.SetModel(GetOwner()->GetModel()); 
2816                 parent
->GetEventHandler()->ProcessEvent(le
); 
2821             if ( m_currentRow 
> 0 ) 
2822                 OnArrowChar( m_currentRow 
- 1, event 
); 
2826             if ( m_currentRow 
< GetRowCount() - 1 ) 
2827                 OnArrowChar( m_currentRow 
+ 1, event 
); 
2829         //Add the process for tree expanding/collapsing 
2831          OnCollapsing(m_currentRow
); 
2834          OnExpanding( m_currentRow
); 
2838                 OnArrowChar( GetRowCount() - 1, event 
); 
2843                 OnArrowChar( 0, event 
); 
2848                 int steps 
= pageSize 
- 1; 
2849                 int index 
= m_currentRow 
- steps
; 
2853                 OnArrowChar( index
, event 
); 
2859                 int steps 
= pageSize 
- 1; 
2860                 unsigned int index 
= m_currentRow 
+ steps
; 
2861                 unsigned int count 
= GetRowCount(); 
2862                 if ( index 
>= count 
) 
2865                 OnArrowChar( index
, event 
); 
2874 void wxDataViewMainWindow::OnMouse( wxMouseEvent 
&event 
) 
2876     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
2878         // let the base handle mouse wheel events. 
2883     int x 
= event
.GetX(); 
2884     int y 
= event
.GetY(); 
2885     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2886     wxDataViewColumn 
*col 
= NULL
; 
2889     unsigned int cols 
= GetOwner()->GetColumnCount(); 
2891     for (i 
= 0; i 
< cols
; i
++) 
2893         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt( i 
); 
2895             continue;      // skip it! 
2897         if (x 
< xpos 
+ c
->GetWidth()) 
2902         xpos 
+= c
->GetWidth(); 
2907     wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
2908     unsigned int current 
= GetLineAt( y 
); 
2909     if ((current 
>= GetRowCount()) || (x 
> GetEndOfLastCol())) 
2911         // Unselect all if below the last row ? 
2915     //Test whether the mouse is hovered on the tree item button 
2917     if ((!IsVirtualList()) && (GetOwner()->GetExpanderColumn() == col
)) 
2919         wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(current
); 
2920         if( node
!=NULL 
&& node
->HasChildren() ) 
2922             int indent 
= node
->GetIndentLevel(); 
2923             indent 
= GetOwner()->GetIndent()*indent
; 
2924             wxRect 
rect( xpos 
+ indent 
+ EXPANDER_MARGIN
, 
2925                          GetLineStart( current 
) + EXPANDER_MARGIN 
+ (GetLineHeight(current
)/2) - (m_lineHeight
/2) - EXPANDER_OFFSET
, 
2926                          m_lineHeight
-2*EXPANDER_MARGIN
, 
2927                          m_lineHeight
-2*EXPANDER_MARGIN 
+ EXPANDER_OFFSET
); 
2928             if( rect
.Contains( x
, y
) ) 
2930                 //So the mouse is over the expander 
2932                 if (m_underMouse 
&& m_underMouse 
!= node
) 
2934                     //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
2935                     RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
2937                 if (m_underMouse 
!= node
) 
2939                     //wxLogMessage("Do the row: %d", current); 
2940                     RefreshRow(current
); 
2942                 m_underMouse 
= node
; 
2945         if (node
!=NULL 
&& !node
->HasChildren()) 
2950         if (m_underMouse 
!= NULL
) 
2952             //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
2953             RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
2954             m_underMouse 
= NULL
; 
2958     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2960     if (event
.Dragging()) 
2962         if (m_dragCount 
== 0) 
2964             // we have to report the raw, physical coords as we want to be 
2965             // able to call HitTest(event.m_pointDrag) from the user code to 
2966             // get the item being dragged 
2967             m_dragStart 
= event
.GetPosition(); 
2972         if (m_dragCount 
!= 3) 
2975         if (event
.LeftIsDown()) 
2977             // Notify cell about drag 
2986     bool forceClick 
= false; 
2988     if (event
.ButtonDClick()) 
2990         m_renameTimer
->Stop(); 
2991         m_lastOnSame 
= false; 
2994     wxDataViewItem item 
= GetItemByRow(current
); 
2995     bool ignore_other_columns 
= 
2996         ((GetOwner()->GetExpanderColumn() != col
) && 
2997          (model
->IsContainer(item
)) && 
2998          (!model
->HasContainerColumns(item
))); 
3000     if (event
.LeftDClick()) 
3002         if ( current 
== m_lineLastClicked 
) 
3004             if ((!ignore_other_columns
) && (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)) 
3007                 model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3008                 cell
->SetValue( value 
); 
3009                 wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3010                                   col
->GetWidth(), GetLineHeight( current 
) ); 
3011                 cell
->Activate( cell_rect
, model
, item
, col
->GetModelColumn() ); 
3016                 wxWindow 
*parent 
= GetParent(); 
3017                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId()); 
3019                 le
.SetEventObject(parent
); 
3020                 le
.SetModel(GetOwner()->GetModel()); 
3022                 parent
->GetEventHandler()->ProcessEvent(le
); 
3028             // The first click was on another item, so don't interpret this as 
3029             // a double click, but as a simple click instead 
3036         if (m_lineSelectSingleOnUp 
!= (unsigned int)-1) 
3038             // select single line 
3039             SelectAllRows( false ); 
3040             SelectRow( m_lineSelectSingleOnUp
, true ); 
3043         //Process the event of user clicking the expander 
3044         bool expander 
= false; 
3045         if ((!IsVirtualList()) && (GetOwner()->GetExpanderColumn() == col
)) 
3047             wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(current
); 
3048             if( node
!=NULL 
&& node
->HasChildren() ) 
3050                 int indent 
= node
->GetIndentLevel(); 
3051                 indent 
= GetOwner()->GetIndent()*indent
; 
3052                 wxRect 
rect( xpos 
+ indent 
+ EXPANDER_MARGIN
, 
3053                          GetLineStart( current 
) + EXPANDER_MARGIN 
+ (GetLineHeight(current
)/2) - (m_lineHeight
/2) - EXPANDER_OFFSET
, 
3054                          m_lineHeight
-2*EXPANDER_MARGIN
, 
3055                          m_lineHeight
-2*EXPANDER_MARGIN 
+ EXPANDER_OFFSET
); 
3057                 if( rect
.Contains( x
, y
) ) 
3060                     if( node
->IsOpen() ) 
3061                         OnCollapsing(current
); 
3063                         OnExpanding( current 
); 
3066             if (node 
&& !node
->HasChildren()) 
3069         //If the user click the expander, we do not do editing even if the column with expander are editable 
3070         if (m_lastOnSame 
&& !expander 
&& !ignore_other_columns
) 
3072             if ((col 
== m_currentCol
) && (current 
== m_currentRow
) && 
3073                 (cell
->GetMode() & wxDATAVIEW_CELL_EDITABLE
) ) 
3075                 m_renameTimer
->Start( 100, true ); 
3079         m_lastOnSame 
= false; 
3080         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3084         // This is necessary, because after a DnD operation in 
3085         // from and to ourself, the up event is swallowed by the 
3086         // DnD code. So on next non-up event (which means here and 
3087         // now) m_lineSelectSingleOnUp should be reset. 
3088         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3091     if (event
.RightDown()) 
3093         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3094         m_lineLastClicked 
= current
; 
3096         // If the item is already selected, do not update the selection. 
3097         // Multi-selections should not be cleared if a selected item is clicked. 
3098         if (!IsRowSelected(current
)) 
3100             SelectAllRows(false); 
3101             ChangeCurrentRow(current
); 
3102             SelectRow(m_currentRow
,true); 
3103             SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3107         model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3108         wxWindow 
*parent 
= GetParent(); 
3109         wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU
, parent
->GetId()); 
3111         le
.SetEventObject(parent
); 
3112         le
.SetModel(GetOwner()->GetModel()); 
3114         parent
->GetEventHandler()->ProcessEvent(le
); 
3116     else if (event
.MiddleDown()) 
3119     if (event
.LeftDown() || forceClick
) 
3123         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3124         m_lineLastClicked 
= current
; 
3126         unsigned int oldCurrentRow 
= m_currentRow
; 
3127         bool oldWasSelected 
= IsRowSelected(m_currentRow
); 
3129         bool cmdModifierDown 
= event
.CmdDown(); 
3130         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3132             if ( IsSingleSel() || !IsRowSelected(current
) ) 
3134                 SelectAllRows( false ); 
3135                 ChangeCurrentRow(current
); 
3136                 SelectRow(m_currentRow
,true); 
3137                 SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3139             else // multi sel & current is highlighted & no mod keys 
3141                 m_lineSelectSingleOnUp 
= current
; 
3142                 ChangeCurrentRow(current
); // change focus 
3145         else // multi sel & either ctrl or shift is down 
3147             if (cmdModifierDown
) 
3149                 ChangeCurrentRow(current
); 
3150                 ReverseRowSelection(m_currentRow
); 
3151                 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) ); 
3153             else if (event
.ShiftDown()) 
3155                 ChangeCurrentRow(current
); 
3157                 unsigned int lineFrom 
= oldCurrentRow
, 
3160                 if ( lineTo 
< lineFrom 
) 
3163                     lineFrom 
= m_currentRow
; 
3166                 SelectRows(lineFrom
, lineTo
, true); 
3167                 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) ); 
3169             else // !ctrl, !shift 
3171                 // test in the enclosing if should make it impossible 
3172                 wxFAIL_MSG( _T("how did we get here?") ); 
3176         if (m_currentRow 
!= oldCurrentRow
) 
3177             RefreshRow( oldCurrentRow 
); 
3179         wxDataViewColumn 
*oldCurrentCol 
= m_currentCol
; 
3181         // Update selection here... 
3184         m_lastOnSame 
= !forceClick 
&& ((col 
== oldCurrentCol
) && 
3185                         (current 
== oldCurrentRow
)) && oldWasSelected
; 
3187         // Call LeftClick after everything else as under GTK+ 
3188         if (cell
->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE
) 
3190             // notify cell about right click 
3192             model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3193             cell
->SetValue( value 
); 
3194             wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3195                           col
->GetWidth(), GetLineHeight( current 
) ); 
3196             /* ignore ret */ cell
->LeftClick( event
.GetPosition(), cell_rect
, model
, item
, col
->GetModelColumn()); 
3201 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent 
&event 
) 
3205     if (HasCurrentRow()) 
3211 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
3215     if (HasCurrentRow()) 
3221 wxDataViewItem 
wxDataViewMainWindow::GetSelection() const 
3223     if( m_selection
.GetCount() != 1 ) 
3224         return wxDataViewItem(); 
3226     return GetItemByRow( m_selection
.Item(0)); 
3229 //----------------------------------------------------------------------------- 
3231 //----------------------------------------------------------------------------- 
3232 WX_DEFINE_LIST(wxDataViewColumnList
) 
3234 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3236 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3237     EVT_SIZE(wxDataViewCtrl::OnSize
) 
3240 wxDataViewCtrl::~wxDataViewCtrl() 
3243         GetModel()->RemoveNotifier( m_notifier 
); 
3248 void wxDataViewCtrl::Init() 
3250     m_cols
.DeleteContents(true); 
3253     // No sorting column at start 
3254     m_sortingColumnIdx 
= wxNOT_FOUND
; 
3256     m_headerArea 
= NULL
; 
3259 bool wxDataViewCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
3260            const wxPoint
& pos
, const wxSize
& size
, 
3261            long style
, const wxValidator
& validator 
) 
3263     if ( (style 
& wxBORDER_MASK
) == 0) 
3264         style 
|= wxBORDER_SUNKEN
; 
3268     if (!wxControl::Create( parent
, id
, pos
, size
, 
3269                             style 
| wxScrolledWindowStyle
, validator
)) 
3272     SetInitialSize(size
); 
3275     MacSetClipChildren( true ); 
3278     m_clientArea 
= new wxDataViewMainWindow( this, wxID_ANY 
); 
3280     if (HasFlag(wxDV_NO_HEADER
)) 
3281         m_headerArea 
= NULL
; 
3283         m_headerArea 
= new wxDataViewHeaderWindow(this); 
3285     SetTargetWindow( m_clientArea 
); 
3287     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
3289         sizer
->Add( m_headerArea
, 0, wxGROW 
); 
3290     sizer
->Add( m_clientArea
, 1, wxGROW 
); 
3297 WXLRESULT 
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
, 
3301     WXLRESULT rc 
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
3304     // we need to process arrows ourselves for scrolling 
3305     if ( nMsg 
== WM_GETDLGCODE 
) 
3307         rc 
|= DLGC_WANTARROWS
; 
3315 wxSize 
wxDataViewCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
3317     wxSize newsize 
= size
; 
3318     if (!HasFlag(wxDV_NO_HEADER
) && (m_headerArea
)) 
3319        newsize
.y 
-= m_headerArea
->GetSize().y
; 
3324 void wxDataViewCtrl::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
3326     // We need to override OnSize so that our scrolled 
3327     // window a) does call Layout() to use sizers for 
3328     // positioning the controls but b) does not query 
3329     // the sizer for their size and use that for setting 
3330     // the scrollable area as set that ourselves by 
3331     // calling SetScrollbar() further down. 
3338 void wxDataViewCtrl::SetFocus() 
3341         m_clientArea
->SetFocus(); 
3344 bool wxDataViewCtrl::AssociateModel( wxDataViewModel 
*model 
) 
3346     if (!wxDataViewCtrlBase::AssociateModel( model 
)) 
3349     m_notifier 
= new wxGenericDataViewModelNotifier( m_clientArea 
); 
3351     model
->AddNotifier( m_notifier 
); 
3353     m_clientArea
->DestroyTree(); 
3355     m_clientArea
->BuildTree(model
); 
3357     m_clientArea
->UpdateDisplay(); 
3362 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn 
*col 
) 
3364     if (!wxDataViewCtrlBase::AppendColumn(col
)) 
3367     m_cols
.Append( col 
); 
3368     OnColumnsCountChanged(); 
3372 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn 
*col 
) 
3374     if (!wxDataViewCtrlBase::PrependColumn(col
)) 
3377     m_cols
.Insert( col 
); 
3378     OnColumnsCountChanged(); 
3382 bool wxDataViewCtrl::InsertColumn( unsigned int pos
, wxDataViewColumn 
*col 
) 
3384     if (!wxDataViewCtrlBase::InsertColumn(pos
,col
)) 
3387     m_cols
.Insert( pos
, col 
); 
3388     OnColumnsCountChanged(); 
3392 void wxDataViewCtrl::OnColumnChange(unsigned int idx
) 
3395         m_headerArea
->UpdateColumn(idx
); 
3397     m_clientArea
->UpdateDisplay(); 
3400 void wxDataViewCtrl::OnColumnsCountChanged() 
3403         m_headerArea
->SetColumnCount(GetColumnCount()); 
3405     m_clientArea
->UpdateDisplay(); 
3408 void wxDataViewCtrl::DoSetExpanderColumn() 
3410     m_clientArea
->UpdateDisplay(); 
3413 void wxDataViewCtrl::DoSetIndent() 
3415     m_clientArea
->UpdateDisplay(); 
3418 unsigned int wxDataViewCtrl::GetColumnCount() const 
3420     return m_cols
.GetCount(); 
3423 wxDataViewColumn
* wxDataViewCtrl::GetColumn( unsigned int idx 
) const 
3428 wxDataViewColumn 
*wxDataViewCtrl::GetColumnAt(unsigned int pos
) const 
3430     // columns can't be reordered if there is no header window which allows 
3432     const unsigned idx 
= m_headerArea 
? m_headerArea
->GetColumnsOrder()[pos
] 
3435     return GetColumn(idx
); 
3438 int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn 
*column
) const 
3440     const unsigned count 
= m_cols
.size(); 
3441     for ( unsigned n 
= 0; n 
< count
; n
++ ) 
3443         if ( m_cols
[n
] == column 
) 
3450 void wxDataViewCtrl::ColumnMoved(wxDataViewColumn 
* WXUNUSED(col
), 
3451                                  unsigned int WXUNUSED(new_pos
)) 
3453     // do _not_ reorder m_cols elements here, they should always be in the 
3454     // order in which columns were added, we only display the columns in 
3456     m_clientArea
->UpdateDisplay(); 
3459 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn 
*column 
) 
3461     wxDataViewColumnList::compatibility_iterator ret 
= m_cols
.Find( column 
); 
3466     OnColumnsCountChanged(); 
3471 bool wxDataViewCtrl::ClearColumns() 
3474     OnColumnsCountChanged(); 
3478 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn 
*column 
) const 
3482     unsigned int len 
= GetColumnCount(); 
3483     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
3485         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
3486         if (col
->IsHidden()) 
3488         ret 
+= col
->GetWidth(); 
3491             CalcScrolledPosition( ret
, dummy
, &ret
, &dummy 
); 
3498 wxDataViewColumn 
*wxDataViewCtrl::GetSortingColumn() const 
3500     return m_sortingColumnIdx 
== wxNOT_FOUND 
? NULL
 
3501                                              : GetColumn(m_sortingColumnIdx
); 
3504 //Selection code with wxDataViewItem as parameters 
3505 wxDataViewItem 
wxDataViewCtrl::GetSelection() const 
3507     return m_clientArea
->GetSelection(); 
3510 int wxDataViewCtrl::GetSelections( wxDataViewItemArray 
& sel 
) const 
3513     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
3514     int len 
= selection
.GetCount(); 
3515     for( int i 
= 0; i 
< len
; i 
++) 
3517         unsigned int row 
= selection
[i
]; 
3518         sel
.Add( m_clientArea
->GetItemByRow( row 
) ); 
3523 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray 
& sel 
) 
3525     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
3526     int len 
= sel
.GetCount(); 
3527     for( int i 
= 0; i 
< len
; i 
++ ) 
3529         int row 
= m_clientArea
->GetRowByItem( sel
[i
] ); 
3531             selection
.Add( static_cast<unsigned int>(row
) ); 
3533     m_clientArea
->SetSelections( selection 
); 
3536 void wxDataViewCtrl::Select( const wxDataViewItem 
& item 
) 
3538     int row 
= m_clientArea
->GetRowByItem( item 
); 
3541         //Unselect all rows before select another in the single select mode 
3542         if (m_clientArea
->IsSingleSel()) 
3543             m_clientArea
->SelectAllRows(false); 
3544         m_clientArea
->SelectRow(row
, true); 
3548 void wxDataViewCtrl::Unselect( const wxDataViewItem 
& item 
) 
3550     int row 
= m_clientArea
->GetRowByItem( item 
); 
3552         m_clientArea
->SelectRow(row
, false); 
3555 bool wxDataViewCtrl::IsSelected( const wxDataViewItem 
& item 
) const 
3557     int row 
= m_clientArea
->GetRowByItem( item 
); 
3560         return m_clientArea
->IsRowSelected(row
); 
3565 //Selection code with row number as parameter 
3566 int wxDataViewCtrl::GetSelections( wxArrayInt 
& sel 
) const 
3569     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
3570     int len 
= selection
.GetCount(); 
3571     for( int i 
= 0; i 
< len
; i 
++) 
3573         unsigned int row 
= selection
[i
]; 
3579 void wxDataViewCtrl::SetSelections( const wxArrayInt 
& sel 
) 
3581     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
3582     int len 
= sel
.GetCount(); 
3583     for( int i 
= 0; i 
< len
; i 
++ ) 
3587             selection
.Add( static_cast<unsigned int>(row
) ); 
3589     m_clientArea
->SetSelections( selection 
); 
3592 void wxDataViewCtrl::Select( int row 
) 
3596         if (m_clientArea
->IsSingleSel()) 
3597             m_clientArea
->SelectAllRows(false); 
3598         m_clientArea
->SelectRow( row
, true ); 
3602 void wxDataViewCtrl::Unselect( int row 
) 
3605         m_clientArea
->SelectRow(row
, false); 
3608 bool wxDataViewCtrl::IsSelected( int row 
) const 
3611         return m_clientArea
->IsRowSelected(row
); 
3615 void wxDataViewCtrl::SelectRange( int from
, int to 
) 
3618     for( int i 
= from
; i 
< to
; i 
++ ) 
3620     m_clientArea
->Select(sel
); 
3623 void wxDataViewCtrl::UnselectRange( int from
, int to 
) 
3625     wxDataViewSelection sel 
= m_clientArea
->GetSelections(); 
3626     for( int i 
= from
; i 
< to
; i 
++ ) 
3627         if( sel
.Index( i 
) != wxNOT_FOUND 
) 
3629     m_clientArea
->SetSelections(sel
); 
3632 void wxDataViewCtrl::SelectAll() 
3634     m_clientArea
->SelectAllRows(true); 
3637 void wxDataViewCtrl::UnselectAll() 
3639     m_clientArea
->SelectAllRows(false); 
3642 void wxDataViewCtrl::EnsureVisible( int row
, int column 
) 
3646     if( row 
> (int) m_clientArea
->GetRowCount() ) 
3647         row 
= m_clientArea
->GetRowCount(); 
3649     int first 
= m_clientArea
->GetFirstVisibleRow(); 
3650     int last 
= m_clientArea
->GetLastVisibleRow(); 
3652         m_clientArea
->ScrollTo( row
, column 
); 
3653     else if( row 
> last 
) 
3654         m_clientArea
->ScrollTo( row 
- last 
+ first
, column 
); 
3656         m_clientArea
->ScrollTo( first
, column 
); 
3659 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem 
& item
, const wxDataViewColumn 
* column 
) 
3661     int row 
= m_clientArea
->GetRowByItem(item
); 
3664         if( column 
== NULL 
) 
3665             EnsureVisible(row
, -1); 
3667             EnsureVisible( row
, GetColumnIndex(column
) ); 
3672 void wxDataViewCtrl::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, wxDataViewColumn
* &column 
) const 
3674     m_clientArea
->HitTest(point
, item
, column
); 
3677 wxRect 
wxDataViewCtrl::GetItemRect( const wxDataViewItem 
& item
, const wxDataViewColumn
* column 
) const 
3679     return m_clientArea
->GetItemRect(item
, column
); 
3682 wxDataViewItem 
wxDataViewCtrl::GetItemByRow( unsigned int row 
) const 
3684     return m_clientArea
->GetItemByRow( row 
); 
3687 int wxDataViewCtrl::GetRowByItem( const wxDataViewItem 
& item 
) const 
3689     return m_clientArea
->GetRowByItem( item 
); 
3692 void wxDataViewCtrl::Expand( const wxDataViewItem 
& item 
) 
3694     int row 
= m_clientArea
->GetRowByItem( item 
); 
3696         m_clientArea
->Expand(row
); 
3699 void wxDataViewCtrl::Collapse( const wxDataViewItem 
& item 
) 
3701     int row 
= m_clientArea
->GetRowByItem( item 
); 
3703         m_clientArea
->Collapse(row
); 
3706 bool wxDataViewCtrl::IsExpanded( const wxDataViewItem 
& item 
) const 
3708     int row 
= m_clientArea
->GetRowByItem( item 
); 
3710         return m_clientArea
->IsExpanded(row
); 
3716     // !wxUSE_GENERICDATAVIEWCTRL 
3719     // wxUSE_DATAVIEWCTRL