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" 
  40 #include "wx/stockitem.h" 
  41 #include "wx/calctrl.h" 
  42 #include "wx/popupwin.h" 
  43 #include "wx/renderer.h" 
  44 #include "wx/dcbuffer.h" 
  47 #include "wx/listimpl.cpp" 
  48 #include "wx/imaglist.h" 
  49 #include "wx/headerctrl.h" 
  51 #include "wx/stopwatch.h" 
  53 //----------------------------------------------------------------------------- 
  55 //----------------------------------------------------------------------------- 
  57 class wxDataViewColumn
; 
  58 class wxDataViewHeaderWindow
; 
  61 //----------------------------------------------------------------------------- 
  63 //----------------------------------------------------------------------------- 
  65 static const int SCROLL_UNIT_X 
= 15; 
  67 // the cell padding on the left/right 
  68 static const int PADDING_RIGHTLEFT 
= 3; 
  70 // the expander space margin 
  71 static const int EXPANDER_MARGIN 
= 4; 
  74 static const int EXPANDER_OFFSET 
= 4; 
  76 static const int EXPANDER_OFFSET 
= 1; 
  79 // Below is the compare stuff. 
  80 // For the generic implementation, both the leaf nodes and the nodes are sorted for 
  81 // fast search when needed 
  82 static wxDataViewModel
* g_model
; 
  83 static int g_column 
= -2; 
  84 static bool g_asending 
= true; 
  86 //----------------------------------------------------------------------------- 
  88 //----------------------------------------------------------------------------- 
  90 void wxDataViewColumn::Init(int width
, wxAlignment align
, int flags
) 
  97     m_sortAscending 
= true; 
 100 int wxDataViewColumn::GetWidth() const 
 104         case wxCOL_WIDTH_DEFAULT
: 
 105             return wxDVC_DEFAULT_WIDTH
; 
 107         case wxCOL_WIDTH_AUTOSIZE
: 
 108             wxCHECK_MSG( m_owner
, wxDVC_DEFAULT_WIDTH
, "no owner control" ); 
 109             return m_owner
->GetBestColumnWidth(m_owner
->GetColumnIndex(this)); 
 116 void wxDataViewColumn::UpdateDisplay() 
 120         int idx 
= m_owner
->GetColumnIndex( this ); 
 121         m_owner
->OnColumnChange( idx 
); 
 125 //----------------------------------------------------------------------------- 
 126 // wxDataViewHeaderWindow 
 127 //----------------------------------------------------------------------------- 
 129 class wxDataViewHeaderWindow 
: public wxHeaderCtrl
 
 132     wxDataViewHeaderWindow(wxDataViewCtrl 
*parent
) 
 133         : wxHeaderCtrl(parent
) 
 137     wxDataViewCtrl 
*GetOwner() const 
 138         { return static_cast<wxDataViewCtrl 
*>(GetParent()); } 
 141     // implement/override wxHeaderCtrl functions by forwarding them to the main 
 143     virtual const wxHeaderColumn
& GetColumn(unsigned int idx
) const 
 145         return *(GetOwner()->GetColumn(idx
)); 
 148     virtual bool UpdateColumnWidthToFit(unsigned int idx
, int widthTitle
) 
 150         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 152         int widthContents 
= owner
->GetBestColumnWidth(idx
); 
 153         owner
->GetColumn(idx
)->SetWidth(wxMax(widthTitle
, widthContents
)); 
 154         owner
->OnColumnChange(idx
); 
 160     bool SendEvent(wxEventType type
, unsigned int n
) 
 162         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 163         wxDataViewEvent 
event(type
, owner
->GetId()); 
 165         event
.SetEventObject(owner
); 
 167         event
.SetDataViewColumn(owner
->GetColumn(n
)); 
 168         event
.SetModel(owner
->GetModel()); 
 170         // for events created by wxDataViewHeaderWindow the 
 171         // row / value fields are not valid 
 172         return owner
->GetEventHandler()->ProcessEvent(event
); 
 175     void OnClick(wxHeaderCtrlEvent
& event
) 
 177         const unsigned idx 
= event
.GetColumn(); 
 179         if ( SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
, idx
) ) 
 182         // default handling for the column click is to sort by this column or 
 183         // toggle its sort order 
 184         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 185         wxDataViewColumn 
* const col 
= owner
->GetColumn(idx
); 
 186         if ( !col
->IsSortable() ) 
 188             // no default handling for non-sortable columns 
 193         if ( col
->IsSortKey() ) 
 195             // already using this column for sorting, just change the order 
 196             col
->ToggleSortOrder(); 
 198         else // not using this column for sorting yet 
 200             // first unset the old sort column if any 
 201             int oldSortKey 
= owner
->GetSortingColumnIndex(); 
 202             if ( oldSortKey 
!= wxNOT_FOUND 
) 
 204                 owner
->GetColumn(oldSortKey
)->UnsetAsSortKey(); 
 205                 owner
->OnColumnChange(oldSortKey
); 
 208             owner
->SetSortingColumnIndex(idx
); 
 212         wxDataViewModel 
* const model 
= owner
->GetModel(); 
 216         owner
->OnColumnChange(idx
); 
 219     void OnRClick(wxHeaderCtrlEvent
& event
) 
 221         if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
, 
 226     void OnResize(wxHeaderCtrlEvent
& event
) 
 228         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 230         const unsigned col 
= event
.GetColumn(); 
 231         owner
->GetColumn(col
)->SetWidth(event
.GetWidth()); 
 232         GetOwner()->OnColumnChange(col
); 
 235     void OnEndReorder(wxHeaderCtrlEvent
& event
) 
 237         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 238         owner
->ColumnMoved(owner
->GetColumn(event
.GetColumn()), 
 239                         event
.GetNewOrder()); 
 242     DECLARE_EVENT_TABLE() 
 243     wxDECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow
); 
 246 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
, wxHeaderCtrl
) 
 247     EVT_HEADER_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnClick
) 
 248     EVT_HEADER_RIGHT_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnRClick
) 
 250     EVT_HEADER_RESIZING(wxID_ANY
, wxDataViewHeaderWindow::OnResize
) 
 251     EVT_HEADER_END_RESIZE(wxID_ANY
, wxDataViewHeaderWindow::OnResize
) 
 253     EVT_HEADER_END_REORDER(wxID_ANY
, wxDataViewHeaderWindow::OnEndReorder
) 
 256 //----------------------------------------------------------------------------- 
 257 // wxDataViewRenameTimer 
 258 //----------------------------------------------------------------------------- 
 260 class wxDataViewRenameTimer
: public wxTimer
 
 263     wxDataViewMainWindow 
*m_owner
; 
 266     wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
); 
 270 //----------------------------------------------------------------------------- 
 271 // wxDataViewTreeNode 
 272 //----------------------------------------------------------------------------- 
 274 class wxDataViewTreeNode
; 
 275 WX_DEFINE_ARRAY( wxDataViewTreeNode 
*, wxDataViewTreeNodes 
); 
 276 WX_DEFINE_ARRAY( void* , wxDataViewTreeLeaves
); 
 278 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, 
 279                                            wxDataViewTreeNode 
** node2
); 
 280 int LINKAGEMODE 
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
); 
 282 class wxDataViewTreeNode
 
 285     wxDataViewTreeNode( wxDataViewTreeNode 
* parent 
= NULL 
) 
 292         m_hasChildren 
= false; 
 296     ~wxDataViewTreeNode() 
 300     wxDataViewTreeNode 
* GetParent() const { return m_parent
; } 
 301     void SetParent( wxDataViewTreeNode 
* parent 
) { m_parent 
= parent
; } 
 302     wxDataViewTreeNodes 
&  GetNodes() { return m_nodes
; } 
 303     wxDataViewTreeLeaves 
& GetChildren() { return m_leaves
; } 
 305     void AddNode( wxDataViewTreeNode 
* node 
) 
 307         m_leaves
.Add( node
->GetItem().GetID() ); 
 309             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 312             m_nodes
.Sort( &wxGenericTreeModelNodeCmp 
); 
 314     void AddLeaf( void * leaf 
) 
 316         m_leaves
.Add( leaf 
); 
 318             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 321     wxDataViewItem 
& GetItem() { return m_item
; } 
 322     const wxDataViewItem 
& GetItem() const { return m_item
; } 
 323     void SetItem( const wxDataViewItem 
& item 
) { m_item 
= item
; } 
 325     unsigned int GetChildrenNumber() const { return m_leaves
.GetCount(); } 
 326     unsigned int GetNodeNumber() const { return m_nodes
.GetCount(); } 
 327     int GetIndentLevel() const 
 330         const wxDataViewTreeNode 
* node 
= this; 
 331         while( node
->GetParent()->GetParent() != NULL 
) 
 333             node 
= node
->GetParent(); 
 346         int len 
= m_nodes
.GetCount(); 
 348         for ( int i 
= 0;i 
< len
; i 
++) 
 349             sum 
+= m_nodes
[i
]->GetSubTreeCount(); 
 351         sum 
+= m_leaves
.GetCount(); 
 354             ChangeSubTreeCount(-sum
); 
 360             ChangeSubTreeCount(sum
); 
 363     bool HasChildren() const { return m_hasChildren
; } 
 364     void SetHasChildren( bool has 
){ m_hasChildren 
= has
; } 
 366     void SetSubTreeCount( int num 
) { m_subTreeCount 
= num
; } 
 367     int GetSubTreeCount() const { return m_subTreeCount
; } 
 368     void ChangeSubTreeCount( int num 
) 
 372         m_subTreeCount 
+= num
; 
 374             m_parent
->ChangeSubTreeCount(num
); 
 381             m_nodes
.Sort( &wxGenericTreeModelNodeCmp 
); 
 382             int len 
= m_nodes
.GetCount(); 
 383             for (int i 
= 0; i 
< len
; i 
++) 
 384                 m_nodes
[i
]->Resort(); 
 385             m_leaves
.Sort( &wxGenericTreeModelItemCmp 
); 
 390     wxDataViewTreeNode  
*m_parent
; 
 391     wxDataViewTreeNodes  m_nodes
; 
 392     wxDataViewTreeLeaves m_leaves
; 
 393     wxDataViewItem       m_item
; 
 399 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, 
 400                                            wxDataViewTreeNode 
** node2
) 
 402     return g_model
->Compare( (*node1
)->GetItem(), (*node2
)->GetItem(), g_column
, g_asending 
); 
 405 int LINKAGEMODE 
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
) 
 407     return g_model
->Compare( *id1
, *id2
, g_column
, g_asending 
); 
 411 //----------------------------------------------------------------------------- 
 412 // wxDataViewMainWindow 
 413 //----------------------------------------------------------------------------- 
 415 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
, 
 417 WX_DECLARE_LIST(wxDataViewItem
, ItemList
); 
 418 WX_DEFINE_LIST(ItemList
) 
 420 class wxDataViewMainWindow
: public wxWindow
 
 423     wxDataViewMainWindow( wxDataViewCtrl 
*parent
, 
 425                             const wxPoint 
&pos 
= wxDefaultPosition
, 
 426                             const wxSize 
&size 
= wxDefaultSize
, 
 427                             const wxString 
&name 
= wxT("wxdataviewctrlmainwindow") ); 
 428     virtual ~wxDataViewMainWindow(); 
 430     bool IsList() const { return GetOwner()->GetModel()->IsListModel(); } 
 431     bool IsVirtualList() const { return m_root 
== NULL
; } 
 433     // notifications from wxDataViewModel 
 434     bool ItemAdded( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 435     bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 436     bool ItemChanged( const wxDataViewItem 
&item 
); 
 437     bool ValueChanged( const wxDataViewItem 
&item
, unsigned int model_column 
); 
 441         if (!IsVirtualList()) 
 451         g_model 
= GetOwner()->GetModel(); 
 452         wxDataViewColumn
* col 
= GetOwner()->GetSortingColumn(); 
 455             if (g_model
->HasDefaultCompare()) 
 463         g_column 
= col
->GetModelColumn(); 
 464         g_asending 
= col
->IsSortOrderAscending(); 
 467     void SetOwner( wxDataViewCtrl
* owner 
) { m_owner 
= owner
; } 
 468     wxDataViewCtrl 
*GetOwner() { return m_owner
; } 
 469     const wxDataViewCtrl 
*GetOwner() const { return m_owner
; } 
 471 #if wxUSE_DRAG_AND_DROP 
 472     wxBitmap 
CreateItemBitmap( unsigned int row
, int &indent 
); 
 473 #endif // wxUSE_DRAG_AND_DROP 
 474     void OnPaint( wxPaintEvent 
&event 
); 
 475     void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
); 
 476     void OnChar( wxKeyEvent 
&event 
); 
 477     void OnMouse( wxMouseEvent 
&event 
); 
 478     void OnSetFocus( wxFocusEvent 
&event 
); 
 479     void OnKillFocus( wxFocusEvent 
&event 
); 
 481     void UpdateDisplay(); 
 482     void RecalculateDisplay(); 
 483     void OnInternalIdle(); 
 485     void OnRenameTimer(); 
 487     void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
= NULL 
); 
 488     void ScrollTo( int rows
, int column 
); 
 490     unsigned GetCurrentRow() const { return m_currentRow
; } 
 491     bool HasCurrentRow() { return m_currentRow 
!= (unsigned int)-1; } 
 492     void ChangeCurrentRow( unsigned int row 
); 
 494     bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); } 
 495     bool IsEmpty() { return GetRowCount() == 0; } 
 497     int GetCountPerPage() const; 
 498     int GetEndOfLastCol() const; 
 499     unsigned int GetFirstVisibleRow() const; 
 501     // I change this method to un const because in the tree view, 
 502     // the displaying number of the tree are changing along with the 
 503     // expanding/collapsing of the tree nodes 
 504     unsigned int GetLastVisibleRow(); 
 505     unsigned int GetRowCount(); 
 507     wxDataViewItem 
GetSelection() const; 
 508     wxDataViewSelection 
GetSelections(){ return m_selection
; } 
 509     void SetSelections( const wxDataViewSelection 
& sel 
) 
 510         { m_selection 
= sel
; UpdateDisplay(); } 
 511     void Select( const wxArrayInt
& aSelections 
); 
 512     void SelectAllRows( bool on 
); 
 513     void SelectRow( unsigned int row
, bool on 
); 
 514     void SelectRows( unsigned int from
, unsigned int to
, bool on 
); 
 515     void ReverseRowSelection( unsigned int row 
); 
 516     bool IsRowSelected( unsigned int row 
); 
 517     void SendSelectionChangedEvent( const wxDataViewItem
& item
); 
 519     void RefreshRow( unsigned int row 
); 
 520     void RefreshRows( unsigned int from
, unsigned int to 
); 
 521     void RefreshRowsAfter( unsigned int firstRow 
); 
 523     // returns the colour to be used for drawing the rules 
 524     wxColour 
GetRuleColour() const 
 526         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 529     wxRect 
GetLineRect( unsigned int row 
) const; 
 531     int GetLineStart( unsigned int row 
) const;  // row * m_lineHeight in fixed mode 
 532     int GetLineHeight( unsigned int row 
) const; // m_lineHeight in fixed mode 
 533     int GetLineAt( unsigned int y 
) const;       // y / m_lineHeight in fixed mode 
 535     // Some useful functions for row and item mapping 
 536     wxDataViewItem 
GetItemByRow( unsigned int row 
) const; 
 537     int GetRowByItem( const wxDataViewItem 
& item 
) const; 
 539     // Methods for building the mapping tree 
 540     void BuildTree( wxDataViewModel  
* model 
); 
 542     void HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, wxDataViewColumn
* &column 
); 
 543     wxRect 
GetItemRect( const wxDataViewItem 
& item
, const wxDataViewColumn
* column 
); 
 545     void Expand( unsigned int row 
); 
 546     void Collapse( unsigned int row 
); 
 547     bool IsExpanded( unsigned int row 
) const; 
 548     bool HasChildren( unsigned int row 
) const; 
 550 #if wxUSE_DRAG_AND_DROP 
 551     bool EnableDragSource( const wxDataFormat 
&format 
); 
 552     bool EnableDropTarget( const wxDataFormat 
&format 
); 
 554     void RemoveDropHint(); 
 555     wxDragResult 
OnDragOver( wxDataFormat format
, wxCoord x
, wxCoord y
, wxDragResult def 
); 
 556     bool OnDrop( wxDataFormat format
, wxCoord x
, wxCoord y 
); 
 557     wxDragResult 
OnData( wxDataFormat format
, wxCoord x
, wxCoord y
, wxDragResult def 
); 
 559 #endif // wxUSE_DRAG_AND_DROP 
 562     wxDataViewTreeNode 
* GetTreeNodeByRow( unsigned int row 
) const; 
 563     // We did not need this temporarily 
 564     // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item ); 
 566     int RecalculateCount(); 
 568     wxDataViewEvent 
SendExpanderEvent( wxEventType type
, const wxDataViewItem 
& item 
); 
 570     wxDataViewTreeNode 
* FindNode( const wxDataViewItem 
& item 
); 
 573     wxDataViewCtrl             
*m_owner
; 
 577     wxDataViewColumn           
*m_currentCol
; 
 578     unsigned int                m_currentRow
; 
 579     wxDataViewSelection         m_selection
; 
 581     wxDataViewRenameTimer      
*m_renameTimer
; 
 586 #if wxUSE_DRAG_AND_DROP 
 591     wxDataFormat                m_dragFormat
; 
 594     wxDataFormat                m_dropFormat
; 
 596     unsigned int                m_dropHintLine
; 
 597 #endif // wxUSE_DRAG_AND_DROP 
 599     // for double click logic 
 600     unsigned int m_lineLastClicked
, 
 601         m_lineBeforeLastClicked
, 
 602         m_lineSelectSingleOnUp
; 
 604     // the pen used to draw horiz/vertical rules 
 607     // the pen used to draw the expander and the lines 
 610     // This is the tree structure of the model 
 611     wxDataViewTreeNode 
* m_root
; 
 614     // This is the tree node under the cursor 
 615     wxDataViewTreeNode 
* m_underMouse
; 
 618     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
) 
 619     DECLARE_EVENT_TABLE() 
 622 // --------------------------------------------------------- 
 623 // wxGenericDataViewModelNotifier 
 624 // --------------------------------------------------------- 
 626 class wxGenericDataViewModelNotifier
: public wxDataViewModelNotifier
 
 629     wxGenericDataViewModelNotifier( wxDataViewMainWindow 
*mainWindow 
) 
 630         { m_mainWindow 
= mainWindow
; } 
 632     virtual bool ItemAdded( const wxDataViewItem 
& parent
, const wxDataViewItem 
& item 
) 
 633         { return m_mainWindow
->ItemAdded( parent 
, item 
); } 
 634     virtual bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
) 
 635         { return m_mainWindow
->ItemDeleted( parent
, item 
); } 
 636     virtual bool ItemChanged( const wxDataViewItem 
& item 
) 
 637         { return m_mainWindow
->ItemChanged(item
);  } 
 638     virtual bool ValueChanged( const wxDataViewItem 
& item 
, unsigned int col 
) 
 639         { return m_mainWindow
->ValueChanged( item
, col 
); } 
 640     virtual bool Cleared() 
 641         { return m_mainWindow
->Cleared(); } 
 642     virtual void Resort() 
 643         { m_mainWindow
->Resort(); } 
 645     wxDataViewMainWindow    
*m_mainWindow
; 
 648 // --------------------------------------------------------- 
 649 // wxDataViewRenderer 
 650 // --------------------------------------------------------- 
 652 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
) 
 654 wxDataViewRenderer::wxDataViewRenderer( const wxString 
&varianttype
, 
 655                                         wxDataViewCellMode mode
, 
 657     wxDataViewCustomRendererBase( varianttype
, mode
, align 
) 
 661     m_ellipsizeMode 
= wxELLIPSIZE_MIDDLE
; 
 665 wxDataViewRenderer::~wxDataViewRenderer() 
 670 wxDC 
*wxDataViewRenderer::GetDC() 
 674         if (GetOwner() == NULL
) 
 676         if (GetOwner()->GetOwner() == NULL
) 
 678         m_dc 
= new wxClientDC( GetOwner()->GetOwner() ); 
 684 void wxDataViewRenderer::SetAlignment( int align 
) 
 689 int wxDataViewRenderer::GetAlignment() const 
 694 // --------------------------------------------------------- 
 695 // wxDataViewCustomRenderer 
 696 // --------------------------------------------------------- 
 698 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
) 
 700 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString 
&varianttype
, 
 701                         wxDataViewCellMode mode
, int align 
) : 
 702     wxDataViewRenderer( varianttype
, mode
, align 
) 
 706 // --------------------------------------------------------- 
 707 // wxDataViewTextRenderer 
 708 // --------------------------------------------------------- 
 710 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewRenderer
) 
 712 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString 
&varianttype
, 
 713                                                 wxDataViewCellMode mode
, int align 
) : 
 714     wxDataViewRenderer( varianttype
, mode
, align 
) 
 718 bool wxDataViewTextRenderer::SetValue( const wxVariant 
&value 
) 
 720     m_text 
= value
.GetString(); 
 725 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 730 bool wxDataViewTextRenderer::HasEditorCtrl() const 
 735 wxControl
* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow 
*parent
, 
 736         wxRect labelRect
, const wxVariant 
&value 
) 
 738     wxTextCtrl
* ctrl 
= new wxTextCtrl( parent
, wxID_ANY
, value
, 
 739                                        wxPoint(labelRect
.x
,labelRect
.y
), 
 740                                        wxSize(labelRect
.width
,labelRect
.height
) ); 
 742     // select the text in the control an place the cursor at the end 
 743     ctrl
->SetInsertionPointEnd(); 
 749 bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl 
*editor
, wxVariant 
&value 
) 
 751     wxTextCtrl 
*text 
= (wxTextCtrl
*) editor
; 
 752     value 
= text
->GetValue(); 
 756 bool wxDataViewTextRenderer::Render(wxRect rect
, wxDC 
*dc
, int state
) 
 758     RenderText(m_text
, 0, rect
, dc
, state
); 
 762 wxSize 
wxDataViewTextRenderer::GetSize() const 
 765         return GetTextExtent(m_text
); 
 767         return wxSize(wxDVC_DEFAULT_RENDERER_SIZE
,wxDVC_DEFAULT_RENDERER_SIZE
); 
 770 // --------------------------------------------------------- 
 771 // wxDataViewBitmapRenderer 
 772 // --------------------------------------------------------- 
 774 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewRenderer
) 
 776 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString 
&varianttype
, 
 777                                                     wxDataViewCellMode mode
, int align 
) : 
 778     wxDataViewRenderer( varianttype
, mode
, align 
) 
 782 bool wxDataViewBitmapRenderer::SetValue( const wxVariant 
&value 
) 
 784     if (value
.GetType() == wxT("wxBitmap")) 
 786     if (value
.GetType() == wxT("wxIcon")) 
 792 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 797 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 800         dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y 
); 
 801     else if (m_icon
.Ok()) 
 802         dc
->DrawIcon( m_icon
, cell
.x
, cell
.y 
); 
 807 wxSize 
wxDataViewBitmapRenderer::GetSize() const 
 810         return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() ); 
 811     else if (m_icon
.Ok()) 
 812         return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() ); 
 814     return wxSize(wxDVC_DEFAULT_RENDERER_SIZE
,wxDVC_DEFAULT_RENDERER_SIZE
); 
 817 // --------------------------------------------------------- 
 818 // wxDataViewToggleRenderer 
 819 // --------------------------------------------------------- 
 821 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewRenderer
) 
 823 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString 
&varianttype
, 
 824                         wxDataViewCellMode mode
, int align 
) : 
 825     wxDataViewRenderer( varianttype
, mode
, align 
) 
 830 bool wxDataViewToggleRenderer::SetValue( const wxVariant 
&value 
) 
 832     m_toggle 
= value
.GetBool(); 
 837 bool wxDataViewToggleRenderer::GetValue( wxVariant 
&WXUNUSED(value
) ) const 
 842 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 846         flags 
|= wxCONTROL_CHECKED
; 
 847     if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE 
|| 
 848         GetEnabled() == false) 
 849         flags 
|= wxCONTROL_DISABLED
; 
 851     // check boxes we draw must always have the same, standard size (if it's 
 852     // bigger than the cell size the checkbox will be truncated because the 
 853     // caller had set the clipping rectangle to prevent us from drawing outside 
 855     cell
.SetSize(GetSize()); 
 857     wxRendererNative::Get().DrawCheckBox( 
 858             GetOwner()->GetOwner(), 
 866 bool wxDataViewToggleRenderer::WXOnLeftClick(const wxPoint
& WXUNUSED(cursor
), 
 867                                              const wxRect
& WXUNUSED(cell
), 
 868                                              wxDataViewModel 
*model
, 
 869                                              const wxDataViewItem
& item
, 
 872     if (model
->IsEnabled(item
, col
)) 
 874         model
->ChangeValue(!m_toggle
, item
, col
); 
 881 wxSize 
wxDataViewToggleRenderer::GetSize() const 
 883     // the window parameter is not used by GetCheckBoxSize() so it's 
 885     return wxRendererNative::Get().GetCheckBoxSize(NULL
); 
 888 // --------------------------------------------------------- 
 889 // wxDataViewProgressRenderer 
 890 // --------------------------------------------------------- 
 892 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewRenderer
) 
 894 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString 
&label
, 
 895     const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
 896     wxDataViewRenderer( varianttype
, mode
, align 
) 
 902 bool wxDataViewProgressRenderer::SetValue( const wxVariant 
&value 
) 
 904     m_value 
= (long) value
; 
 906     if (m_value 
< 0) m_value 
= 0; 
 907     if (m_value 
> 100) m_value 
= 100; 
 912 bool wxDataViewProgressRenderer::GetValue( wxVariant 
&value 
) const 
 914     value 
= (long) m_value
; 
 919 wxDataViewProgressRenderer::Render(wxRect rect
, wxDC 
*dc
, int WXUNUSED(state
)) 
 921     // deflate the rect to leave a small border between bars in adjacent rows 
 922     wxRect bar 
= rect
.Deflate(0, 1); 
 924     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
 925     dc
->SetPen( *wxBLACK_PEN 
); 
 926     dc
->DrawRectangle( bar 
); 
 928     bar
.width 
= (int)(bar
.width 
* m_value 
/ 100.); 
 929     dc
->SetPen( *wxTRANSPARENT_PEN 
); 
 931     const wxDataViewItemAttr
& attr 
= GetAttr(); 
 932     dc
->SetBrush( attr
.HasColour() ? wxBrush(attr
.GetColour()) 
 934     dc
->DrawRectangle( bar 
); 
 939 wxSize 
wxDataViewProgressRenderer::GetSize() const 
 941     return wxSize(40,12); 
 944 // --------------------------------------------------------- 
 945 // wxDataViewDateRenderer 
 946 // --------------------------------------------------------- 
 948 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN) 
 950 #if wxUSE_DATE_RENDERER_POPUP 
 952 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
 
 955     wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime 
*value
, 
 956         wxDataViewModel 
*model
, const wxDataViewItem 
& item
, unsigned int col
) : 
 957         wxPopupTransientWindow( parent
, wxBORDER_SIMPLE 
), 
 962         m_cal 
= new wxCalendarCtrl( this, wxID_ANY
, *value 
); 
 963         wxBoxSizer 
*sizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 964         sizer
->Add( m_cal
, 1, wxGROW 
); 
 969     void OnCalendar( wxCalendarEvent 
&event 
); 
 971     wxCalendarCtrl      
*m_cal
; 
 972     wxDataViewModel 
*m_model
; 
 974     const wxDataViewItem 
&   m_item
; 
 977     virtual void OnDismiss() 
 982     DECLARE_EVENT_TABLE() 
 985 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
) 
 986     EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar 
) 
 989 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent 
&event 
) 
 991     m_model
->ChangeValue( event
.GetDate(), m_item
, m_col 
); 
 995 #endif // wxUSE_DATE_RENDERER_POPUP 
 997 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewRenderer
) 
 999 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString 
&varianttype
, 
1000                         wxDataViewCellMode mode
, int align 
) : 
1001     wxDataViewRenderer( varianttype
, mode
, align 
) 
1005 bool wxDataViewDateRenderer::SetValue( const wxVariant 
&value 
) 
1007     m_date 
= value
.GetDateTime(); 
1012 bool wxDataViewDateRenderer::GetValue( wxVariant 
&value 
) const 
1018 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC 
*dc
, int state 
) 
1020     wxString tmp 
= m_date
.FormatDate(); 
1021     RenderText( tmp
, 0, cell
, dc
, state 
); 
1025 wxSize 
wxDataViewDateRenderer::GetSize() const 
1027     return GetTextExtent(m_date
.FormatDate()); 
1030 bool wxDataViewDateRenderer::WXOnActivate(const wxRect
& WXUNUSED(cell
), 
1031                                           wxDataViewModel 
*model
, 
1032                                           const wxDataViewItem
& item
, 
1035     wxDateTime dtOld 
= m_date
; 
1037 #if wxUSE_DATE_RENDERER_POPUP 
1038     wxDataViewDateRendererPopupTransient 
*popup 
= new wxDataViewDateRendererPopupTransient( 
1039         GetOwner()->GetOwner()->GetParent(), &dtOld
, model
, item
, col
); 
1040     wxPoint pos 
= wxGetMousePosition(); 
1043     popup
->Popup( popup
->m_cal 
); 
1044 #else // !wxUSE_DATE_RENDERER_POPUP 
1045     wxMessageBox(dtOld
.Format()); 
1046 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP 
1051 // --------------------------------------------------------- 
1052 // wxDataViewIconTextRenderer 
1053 // --------------------------------------------------------- 
1055 IMPLEMENT_CLASS(wxDataViewIconTextRenderer
, wxDataViewRenderer
) 
1057 wxDataViewIconTextRenderer::wxDataViewIconTextRenderer( 
1058 const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
1059     wxDataViewRenderer( varianttype
, mode
, align 
) 
1062     SetAlignment(align
); 
1065 bool wxDataViewIconTextRenderer::SetValue( const wxVariant 
&value 
) 
1071 bool wxDataViewIconTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
1076 bool wxDataViewIconTextRenderer::Render(wxRect rect
, wxDC 
*dc
, int state
) 
1080     const wxIcon
& icon 
= m_value
.GetIcon(); 
1083         dc
->DrawIcon(icon
, rect
.x
, rect
.y 
+ (rect
.height 
- icon
.GetHeight())/2); 
1084         xoffset 
= icon
.GetWidth()+4; 
1087     RenderText(m_value
.GetText(), xoffset
, rect
, dc
, state
); 
1092 wxSize 
wxDataViewIconTextRenderer::GetSize() const 
1094     if (!m_value
.GetText().empty()) 
1096         wxSize size 
= GetTextExtent(m_value
.GetText()); 
1098         if (m_value
.GetIcon().IsOk()) 
1099             size
.x 
+= m_value
.GetIcon().GetWidth() + 4; 
1102     return wxSize(80,20); 
1105 wxControl
* wxDataViewIconTextRenderer::CreateEditorCtrl(wxWindow 
*parent
, wxRect labelRect
, const wxVariant
& value
) 
1107     wxDataViewIconText iconText
; 
1110     wxString text 
= iconText
.GetText(); 
1112     // adjust the label rect to take the width of the icon into account 
1113     if (iconText
.GetIcon().IsOk()) 
1115         int w 
= iconText
.GetIcon().GetWidth() + 4; 
1117         labelRect
.width 
-= w
; 
1120     wxTextCtrl
* ctrl 
= new wxTextCtrl( parent
, wxID_ANY
, text
, 
1121                                        wxPoint(labelRect
.x
,labelRect
.y
), 
1122                                        wxSize(labelRect
.width
,labelRect
.height
) ); 
1124     // select the text in the control an place the cursor at the end 
1125     ctrl
->SetInsertionPointEnd(); 
1131 bool wxDataViewIconTextRenderer::GetValueFromEditorCtrl( wxControl 
*editor
, wxVariant
& value 
) 
1133     wxTextCtrl 
*text 
= (wxTextCtrl
*) editor
; 
1135     wxDataViewIconText 
iconText(text
->GetValue(), m_value
.GetIcon()); 
1140 //----------------------------------------------------------------------------- 
1141 // wxDataViewDropTarget 
1142 //----------------------------------------------------------------------------- 
1144 #if wxUSE_DRAG_AND_DROP 
1146 class wxBitmapCanvas
: public wxWindow
 
1149     wxBitmapCanvas( wxWindow 
*parent
, const wxBitmap 
&bitmap
, const wxSize 
&size 
) : 
1150     wxWindow( parent
, wxID_ANY
, wxPoint(0,0), size 
) 
1153         Connect( wxEVT_PAINT
, wxPaintEventHandler(wxBitmapCanvas::OnPaint
) ); 
1156     void OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1159         dc
.DrawBitmap( m_bitmap
, 0, 0); 
1165 class wxDataViewDropSource
: public wxDropSource
 
1168     wxDataViewDropSource( wxDataViewMainWindow 
*win
, unsigned int row 
) : 
1176     ~wxDataViewDropSource() 
1181     virtual bool GiveFeedback( wxDragResult 
WXUNUSED(effect
) ) 
1183         wxPoint pos 
= wxGetMousePosition(); 
1187             int liney 
= m_win
->GetLineStart( m_row 
); 
1189             m_win
->GetOwner()->CalcUnscrolledPosition( 0, liney
, NULL
, &liney 
); 
1190             m_win
->ClientToScreen( &linex
, &liney 
); 
1191             m_dist_x 
= pos
.x 
- linex
; 
1192             m_dist_y 
= pos
.y 
- liney
; 
1195             wxBitmap ib 
= m_win
->CreateItemBitmap( m_row
, indent 
); 
1197             m_hint 
= new wxFrame( m_win
->GetParent(), wxID_ANY
, wxEmptyString
, 
1198                                         wxPoint(pos
.x 
- m_dist_x
, pos
.y 
+ 5 ), 
1200                                         wxFRAME_TOOL_WINDOW 
| 
1201                                         wxFRAME_FLOAT_ON_PARENT 
| 
1202                                         wxFRAME_NO_TASKBAR 
| 
1204             new wxBitmapCanvas( m_hint
, ib
, ib
.GetSize() ); 
1209             m_hint
->Move( pos
.x 
- m_dist_x
, pos
.y 
+ 5  ); 
1210             m_hint
->SetTransparent( 128 ); 
1216     wxDataViewMainWindow   
*m_win
; 
1219     int m_dist_x
,m_dist_y
; 
1223 class wxDataViewDropTarget
: public wxDropTarget
 
1226     wxDataViewDropTarget( wxDataObject 
*obj
, wxDataViewMainWindow 
*win 
) : 
1232     virtual wxDragResult 
OnDragOver( wxCoord x
, wxCoord y
, wxDragResult def 
) 
1234         wxDataFormat format 
= GetMatchingPair(); 
1235         if (format 
== wxDF_INVALID
) 
1237         return m_win
->OnDragOver( format
, x
, y
, def
); 
1240     virtual bool OnDrop( wxCoord x
, wxCoord y 
) 
1242         wxDataFormat format 
= GetMatchingPair(); 
1243         if (format 
== wxDF_INVALID
) 
1245         return m_win
->OnDrop( format
, x
, y 
); 
1248     virtual wxDragResult 
OnData( wxCoord x
, wxCoord y
, wxDragResult def 
) 
1250         wxDataFormat format 
= GetMatchingPair(); 
1251         if (format 
== wxDF_INVALID
) 
1255         return m_win
->OnData( format
, x
, y
, def 
); 
1258     virtual void OnLeave() 
1259         { m_win
->OnLeave(); } 
1261     wxDataViewMainWindow   
*m_win
; 
1264 #endif // wxUSE_DRAG_AND_DROP 
1266 //----------------------------------------------------------------------------- 
1267 // wxDataViewRenameTimer 
1268 //----------------------------------------------------------------------------- 
1270 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
) 
1275 void wxDataViewRenameTimer::Notify() 
1277     m_owner
->OnRenameTimer(); 
1280 //----------------------------------------------------------------------------- 
1281 // wxDataViewMainWindow 
1282 //----------------------------------------------------------------------------- 
1284 // The tree building helper, declared firstly 
1285 static void BuildTreeHelper( const wxDataViewModel 
* model
,  const wxDataViewItem 
& item
, 
1286                              wxDataViewTreeNode 
* node
); 
1288 int LINKAGEMODE 
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2 
) 
1290     if (row1 
> row2
) return 1; 
1291     if (row1 
== row2
) return 0; 
1295 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
) 
1297 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
) 
1298     EVT_PAINT         (wxDataViewMainWindow::OnPaint
) 
1299     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse
) 
1300     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus
) 
1301     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus
) 
1302     EVT_CHAR          (wxDataViewMainWindow::OnChar
) 
1305 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl 
*parent
, wxWindowID id
, 
1306     const wxPoint 
&pos
, const wxSize 
&size
, const wxString 
&name 
) : 
1307     wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
|wxBORDER_NONE
, name 
), 
1308     m_selection( wxDataViewSelectionCmp 
) 
1313     m_lastOnSame 
= false; 
1314     m_renameTimer 
= new wxDataViewRenameTimer( this ); 
1316     // TODO: user better initial values/nothing selected 
1317     m_currentCol 
= NULL
; 
1320     m_lineHeight 
= wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1 
1322 #if wxUSE_DRAG_AND_DROP 
1324     m_dragStart 
= wxPoint(0,0); 
1326     m_dragEnabled 
= false; 
1327     m_dropEnabled 
= false; 
1329     m_dropHintLine 
= (unsigned int) -1; 
1330 #endif // wxUSE_DRAG_AND_DROP 
1332     m_lineLastClicked 
= (unsigned int) -1; 
1333     m_lineBeforeLastClicked 
= (unsigned int) -1; 
1334     m_lineSelectSingleOnUp 
= (unsigned int) -1; 
1338     SetBackgroundColour( *wxWHITE 
); 
1340     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
1342     m_penRule 
= wxPen(GetRuleColour()); 
1344     // compose a pen whichcan draw black lines 
1345     // TODO: maybe there is something system colour to use 
1346     m_penExpander 
= wxPen(wxColour(0,0,0)); 
1348     m_root 
= new wxDataViewTreeNode( NULL 
); 
1349     m_root
->SetHasChildren(true); 
1351     // Make m_count = -1 will cause the class recaculate the real displaying number of rows. 
1353     m_underMouse 
= NULL
; 
1357 wxDataViewMainWindow::~wxDataViewMainWindow() 
1360     delete m_renameTimer
; 
1364 #if wxUSE_DRAG_AND_DROP 
1365 bool wxDataViewMainWindow::EnableDragSource( const wxDataFormat 
&format 
) 
1367     m_dragFormat 
= format
; 
1368     m_dragEnabled 
= format 
!= wxDF_INVALID
; 
1373 bool wxDataViewMainWindow::EnableDropTarget( const wxDataFormat 
&format 
) 
1375     m_dropFormat 
= format
; 
1376     m_dropEnabled 
= format 
!= wxDF_INVALID
; 
1379         SetDropTarget( new wxDataViewDropTarget( new wxCustomDataObject( format 
), this ) ); 
1384 void wxDataViewMainWindow::RemoveDropHint() 
1389             RefreshRow( m_dropHintLine 
); 
1390             m_dropHintLine 
= (unsigned int) -1; 
1394 wxDragResult 
wxDataViewMainWindow::OnDragOver( wxDataFormat format
, wxCoord x
, 
1395                                                wxCoord y
, wxDragResult def 
) 
1399     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1400     unsigned int row 
= GetLineAt( yy 
); 
1402     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1408     wxDataViewItem item 
= GetItemByRow( row 
); 
1410     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1412     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE
, m_owner
->GetId() ); 
1413     event
.SetEventObject( m_owner 
); 
1414     event
.SetItem( item 
); 
1415     event
.SetModel( model 
); 
1416     event
.SetDataFormat( format 
); 
1417     if (!m_owner
->HandleWindowEvent( event 
)) 
1423     if (!event
.IsAllowed()) 
1430     if (m_dropHint 
&& (row 
!= m_dropHintLine
)) 
1431         RefreshRow( m_dropHintLine 
); 
1433     m_dropHintLine 
= row
; 
1439 bool wxDataViewMainWindow::OnDrop( wxDataFormat format
, wxCoord x
, wxCoord y 
) 
1445     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1446     unsigned int row 
= GetLineAt( yy 
); 
1448     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1451     wxDataViewItem item 
= GetItemByRow( row 
); 
1453     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1455     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE
, m_owner
->GetId() ); 
1456     event
.SetEventObject( m_owner 
); 
1457     event
.SetItem( item 
); 
1458     event
.SetModel( model 
); 
1459     event
.SetDataFormat( format 
); 
1460     if (!m_owner
->HandleWindowEvent( event 
)) 
1463     if (!event
.IsAllowed()) 
1469 wxDragResult 
wxDataViewMainWindow::OnData( wxDataFormat format
, wxCoord x
, wxCoord y
, 
1474     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1475     unsigned int row 
= GetLineAt( yy 
); 
1477     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1480     wxDataViewItem item 
= GetItemByRow( row 
); 
1482     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1484     wxCustomDataObject 
*obj 
= (wxCustomDataObject 
*) GetDropTarget()->GetDataObject(); 
1486     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP
, m_owner
->GetId() ); 
1487     event
.SetEventObject( m_owner 
); 
1488     event
.SetItem( item 
); 
1489     event
.SetModel( model 
); 
1490     event
.SetDataFormat( format 
); 
1491     event
.SetDataSize( obj
->GetSize() ); 
1492     event
.SetDataBuffer( obj
->GetData() ); 
1493     if (!m_owner
->HandleWindowEvent( event 
)) 
1496     if (!event
.IsAllowed()) 
1502 void wxDataViewMainWindow::OnLeave() 
1507 wxBitmap 
wxDataViewMainWindow::CreateItemBitmap( unsigned int row
, int &indent 
) 
1509     int height 
= GetLineHeight( row 
); 
1511     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1513     for (col 
= 0; col 
< cols
; col
++) 
1515         wxDataViewColumn 
*column 
= GetOwner()->GetColumnAt(col
); 
1516         if (column
->IsHidden()) 
1517             continue;      // skip it! 
1518         width 
+= column
->GetWidth(); 
1524         wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
1525         indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
1526         indent 
= indent 
+ m_lineHeight
; 
1527             // try to use the m_lineHeight as the expander space 
1529         if(!node
->HasChildren()) 
1534     wxBitmap 
bitmap( width
, height 
); 
1535     wxMemoryDC 
dc( bitmap 
); 
1536     dc
.SetFont( GetFont() ); 
1537     dc
.SetPen( *wxBLACK_PEN 
); 
1538     dc
.SetBrush( *wxWHITE_BRUSH 
); 
1539     dc
.DrawRectangle( 0,0,width
,height 
); 
1541     wxDataViewModel 
*model 
= m_owner
->GetModel(); 
1543     wxDataViewColumn 
*expander 
= GetOwner()->GetExpanderColumn(); 
1546         // TODO-RTL: last column for RTL support 
1547         expander 
= GetOwner()->GetColumnAt( 0 ); 
1548         GetOwner()->SetExpanderColumn(expander
); 
1553     for (col 
= 0; col 
< cols
; col
++) 
1555         wxDataViewColumn 
*column 
= GetOwner()->GetColumnAt( col 
); 
1556         wxDataViewRenderer 
*cell 
= column
->GetRenderer(); 
1558         if (column
->IsHidden()) 
1559             continue;       // skip it! 
1561         width 
= column
->GetWidth(); 
1563         if (column 
== expander
) 
1566         wxDataViewItem item 
= GetItemByRow( row 
); 
1567         cell
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
1569         wxRect 
item_rect(x
, 0, width
, height
); 
1570         item_rect
.Deflate(PADDING_RIGHTLEFT
, 0); 
1572         // dc.SetClippingRegion( item_rect ); 
1573         cell
->WXCallRender(item_rect
, &dc
, 0); 
1574         // dc.DestroyClippingRegion(); 
1582 #endif // wxUSE_DRAG_AND_DROP 
1585 void wxDataViewMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1587     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
1588     wxAutoBufferedPaintDC 
dc( this ); 
1591     dc
.SetBrush(GetOwner()->GetBackgroundColour()); 
1592     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1593     dc
.DrawRectangle(GetClientSize()); 
1597     GetOwner()->PrepareDC( dc 
); 
1598     dc
.SetFont( GetFont() ); 
1600     wxRect update 
= GetUpdateRegion().GetBox(); 
1601     m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y 
); 
1603     // compute which items needs to be redrawn 
1604     unsigned int item_start 
= GetLineAt( wxMax(0,update
.y
) ); 
1605     unsigned int item_count 
= 
1606         wxMin( (int)(  GetLineAt( wxMax(0,update
.y
+update
.height
) ) - item_start 
+ 1), 
1607             (int)(GetRowCount( ) - item_start
)); 
1608     unsigned int item_last 
= item_start 
+ item_count
; 
1610     // Send the event to wxDataViewCtrl itself. 
1611     wxWindow 
* const parent 
= GetParent(); 
1612     wxDataViewEvent 
cache_event(wxEVT_COMMAND_DATAVIEW_CACHE_HINT
, parent
->GetId()); 
1613     cache_event
.SetEventObject(parent
); 
1614     cache_event
.SetCache(item_start
, item_last 
- 1); 
1615     parent
->ProcessWindowEvent(cache_event
); 
1617     // compute which columns needs to be redrawn 
1618     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1621         // we assume that we have at least one column below and painting an 
1622         // empty control is unnecessary anyhow 
1626     unsigned int col_start 
= 0; 
1627     unsigned int x_start
; 
1628     for (x_start 
= 0; col_start 
< cols
; col_start
++) 
1630         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_start
); 
1631         if (col
->IsHidden()) 
1632             continue;      // skip it! 
1634         unsigned int w 
= col
->GetWidth(); 
1635         if (x_start
+w 
>= (unsigned int)update
.x
) 
1641     unsigned int col_last 
= col_start
; 
1642     unsigned int x_last 
= x_start
; 
1643     for (; col_last 
< cols
; col_last
++) 
1645         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_last
); 
1646         if (col
->IsHidden()) 
1647             continue;      // skip it! 
1649         if (x_last 
> (unsigned int)update
.GetRight()) 
1652         x_last 
+= col
->GetWidth(); 
1655     // Draw horizontal rules if required 
1656     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
1658         dc
.SetPen(m_penRule
); 
1659         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1661         for (unsigned int i 
= item_start
; i 
<= item_last
; i
++) 
1663             int y 
= GetLineStart( i 
); 
1664             dc
.DrawLine(x_start
, y
, x_last
, y
); 
1668     // Draw vertical rules if required 
1669     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
1671         dc
.SetPen(m_penRule
); 
1672         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1674         // NB: Vertical rules are drawn in the last pixel of a column so that 
1675         //     they align perfectly with native MSW wxHeaderCtrl as well as for 
1676         //     consistency with MSW native list control. There's no vertical 
1677         //     rule at the most-left side of the control. 
1679         int x 
= x_start 
- 1; 
1680         for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1682             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(i
); 
1683             if (col
->IsHidden()) 
1684                 continue;       // skip it 
1686             x 
+= col
->GetWidth(); 
1688             dc
.DrawLine(x
, GetLineStart( item_start 
), 
1689                         x
, GetLineStart( item_last 
) ); 
1693     // redraw the background for the items which are selected/current 
1694     for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1696         bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1697         if (selected 
|| item 
== m_currentRow
) 
1699             int flags 
= selected 
? (int)wxCONTROL_SELECTED 
: 0; 
1700             if (item 
== m_currentRow
) 
1701                 flags 
|= wxCONTROL_CURRENT
; 
1703                 flags 
|= wxCONTROL_FOCUSED
; 
1705             wxRect 
rect( x_start
, GetLineStart( item 
), 
1706                          x_last 
- x_start
, GetLineHeight( item 
) ); 
1707             wxRendererNative::Get().DrawItemSelectionRect
 
1717 #if wxUSE_DRAG_AND_DROP 
1720         wxRect 
rect( x_start
, GetLineStart( m_dropHintLine 
), 
1721                      x_last 
- x_start
, GetLineHeight( m_dropHintLine 
) ); 
1722         dc
.SetPen( *wxBLACK_PEN 
); 
1723         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1724         dc
.DrawRectangle( rect 
); 
1726 #endif // wxUSE_DRAG_AND_DROP 
1728     wxDataViewColumn 
*expander 
= GetOwner()->GetExpanderColumn(); 
1731         // TODO-RTL: last column for RTL support 
1732         expander 
= GetOwner()->GetColumnAt( 0 ); 
1733         GetOwner()->SetExpanderColumn(expander
); 
1736     // redraw all cells for all rows which must be repainted and all columns 
1738     cell_rect
.x 
= x_start
; 
1739     for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1741         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt( i 
); 
1742         wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
1743         cell_rect
.width 
= col
->GetWidth(); 
1745         if ( col
->IsHidden() || cell_rect
.width 
<= 0 ) 
1746             continue;       // skip it! 
1748         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1750             // get the cell value and set it into the renderer 
1751             wxDataViewTreeNode 
*node 
= NULL
; 
1752             wxDataViewItem dataitem
; 
1754             if (!IsVirtualList()) 
1756                 node 
= GetTreeNodeByRow(item
); 
1760                 dataitem 
= node
->GetItem(); 
1762                 if ((i 
> 0) && model
->IsContainer(dataitem
) && 
1763                     !model
->HasContainerColumns(dataitem
)) 
1768                 dataitem 
= wxDataViewItem( wxUIntToPtr(item
+1) ); 
1771             cell
->PrepareForItem(model
, dataitem
, col
->GetModelColumn()); 
1774             cell_rect
.y 
= GetLineStart( item 
); 
1775             cell_rect
.height 
= GetLineHeight( item 
); 
1777             // deal with the expander 
1779             if ((!IsList()) && (col 
== expander
)) 
1781                 // Calculate the indent first 
1782                 indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
1784                 // we reserve m_lineHeight of horizontal space for the expander 
1785                 // but leave EXPANDER_MARGIN around the expander itself 
1786                 int exp_x 
= cell_rect
.x 
+ indent 
+ EXPANDER_MARGIN
; 
1788                 indent 
+= m_lineHeight
; 
1790                 // draw expander if needed and visible 
1791                 if ( node
->HasChildren() && exp_x 
< cell_rect
.GetRight() ) 
1793                     dc
.SetPen( m_penExpander 
); 
1794                     dc
.SetBrush( wxNullBrush 
); 
1796                     int exp_size 
= m_lineHeight 
- 2*EXPANDER_MARGIN
; 
1797                     int exp_y 
= cell_rect
.y 
+ (cell_rect
.height 
- exp_size
)/2 
1798                                    + EXPANDER_MARGIN 
- EXPANDER_OFFSET
; 
1800                     const wxRect 
rect(exp_x
, exp_y
, exp_size
, exp_size
); 
1803                     if ( m_underMouse 
== node 
) 
1804                         flag 
|= wxCONTROL_CURRENT
; 
1805                     if ( node
->IsOpen() ) 
1806                         flag 
|= wxCONTROL_EXPANDED
; 
1808                     // ensure that we don't overflow the cell (which might 
1809                     // happen if the column is very narrow) 
1810                     wxDCClipper 
clip(dc
, cell_rect
); 
1812                     wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
); 
1815                 // force the expander column to left-center align 
1816                 cell
->SetAlignment( wxALIGN_CENTER_VERTICAL 
); 
1818             if (node 
&& !node
->HasChildren()) 
1820                 // Yes, if the node does not have any child, it must be a leaf which 
1821                 // mean that it is a temporarily created by GetTreeNodeByRow 
1825             wxRect item_rect 
= cell_rect
; 
1826             item_rect
.Deflate(PADDING_RIGHTLEFT
, 0); 
1828             // account for the tree indent (harmless if we're not indented) 
1829             item_rect
.x 
+= indent
; 
1830             item_rect
.width 
-= indent
; 
1832             if ( item_rect
.width 
<= 0 ) 
1836             if (m_hasFocus 
&& (m_selection
.Index(item
) != wxNOT_FOUND
)) 
1837                 state 
|= wxDATAVIEW_CELL_SELECTED
; 
1839             // TODO: it would be much more efficient to create a clipping 
1840             //       region for the entire column being rendered (in the OnPaint 
1841             //       of wxDataViewMainWindow) instead of a single clip region for 
1842             //       each cell. However it would mean that each renderer should 
1843             //       respect the given wxRect's top & bottom coords, eventually 
1844             //       violating only the left & right coords - however the user can 
1845             //       make its own renderer and thus we cannot be sure of that. 
1846             wxDCClipper 
clip(dc
, item_rect
); 
1848             cell
->WXCallRender(item_rect
, &dc
, state
); 
1851         cell_rect
.x 
+= cell_rect
.width
; 
1855 void wxDataViewMainWindow::OnRenameTimer() 
1857     // We have to call this here because changes may just have 
1858     // been made and no screen update taken place. 
1861         // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead 
1862         //       (needs to be tested!) 
1866     wxDataViewItem item 
= GetItemByRow( m_currentRow 
); 
1868     wxRect labelRect 
= GetItemRect(item
, m_currentCol
); 
1870     m_currentCol
->GetRenderer()->StartEditing( item
, labelRect 
); 
1873 //----------------------------------------------------------------------------- 
1874 // Helper class for do operation on the tree node 
1875 //----------------------------------------------------------------------------- 
1880     virtual ~DoJob() { } 
1882     // The return value control how the tree-walker tranverse the tree 
1883     // 0: Job done, stop tranverse and return 
1884     // 1: Ignore the current node's subtree and continue 
1885     // 2: Job not done, continue 
1886     enum  { OK 
= 0 , IGR 
= 1, CONT 
= 2 }; 
1887     virtual int operator() ( wxDataViewTreeNode 
* node 
) = 0; 
1888     virtual int operator() ( void * n 
) = 0; 
1891 bool Walker( wxDataViewTreeNode 
* node
, DoJob 
& func 
) 
1896     switch( func( node 
) ) 
1907     const wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
1908     const wxDataViewTreeLeaves
& leaves 
= node
->GetChildren(); 
1910     int len_nodes 
= nodes
.GetCount(); 
1911     int len 
= leaves
.GetCount(); 
1912     int i 
= 0, nodes_i 
= 0; 
1914     for(; i 
< len
; i 
++ ) 
1916         void * n 
= leaves
[i
]; 
1917         if( nodes_i 
< len_nodes 
&& n 
== nodes
[nodes_i
]->GetItem().GetID() ) 
1919             wxDataViewTreeNode 
* nd 
= nodes
[nodes_i
]; 
1922             if( Walker( nd 
, func 
) ) 
1941 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem 
& parent
, const wxDataViewItem 
& item
) 
1943     GetOwner()->InvalidateColBestWidths(); 
1945     if (IsVirtualList()) 
1947         wxDataViewVirtualListModel 
*list_model 
= 
1948             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
1949         m_count 
= list_model
->GetCount(); 
1956     wxDataViewTreeNode 
* node
; 
1957     node 
= FindNode(parent
); 
1962     node
->SetHasChildren( true ); 
1964     if( g_model
->IsContainer( item 
) ) 
1966         wxDataViewTreeNode 
* newnode 
= new wxDataViewTreeNode( node 
); 
1967         newnode
->SetItem(item
); 
1968         newnode
->SetHasChildren( true ); 
1969         node
->AddNode( newnode
); 
1972         node
->AddLeaf( item
.GetID() ); 
1974     node
->ChangeSubTreeCount(1); 
1982 static void DestroyTreeHelper( wxDataViewTreeNode 
* node
); 
1984 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem
& parent
, 
1985                                        const wxDataViewItem
& item
) 
1987     GetOwner()->InvalidateColBestWidths(); 
1989     if (IsVirtualList()) 
1991         wxDataViewVirtualListModel 
*list_model 
= 
1992             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
1993         m_count 
= list_model
->GetCount(); 
1995         if( m_currentRow 
> GetRowCount() ) 
1996             m_currentRow 
= m_count 
- 1; 
1998         // TODO: why empty the entire selection? 
1999         m_selection
.Empty(); 
2006     wxDataViewTreeNode 
* node 
= FindNode(parent
); 
2008     // Notice that it is possible that the item being deleted is not in the 
2009     // tree at all, for example we could be deleting a never shown (because 
2010     // collapsed) item in a tree model. So it's not an error if we don't know 
2011     // about this item, just return without doing anything then. 
2012     if ( !node 
|| node
->GetChildren().Index(item
.GetID()) == wxNOT_FOUND 
) 
2016     node
->GetChildren().Remove( item
.GetID() ); 
2017     // Manipolate selection 
2018     if( m_selection
.GetCount() > 1 ) 
2020         m_selection
.Empty(); 
2022     bool isContainer 
= false; 
2023     wxDataViewTreeNodes nds 
= node
->GetNodes(); 
2024     for (size_t i 
= 0; i 
< nds
.GetCount(); i 
++) 
2026         if (nds
[i
]->GetItem() == item
) 
2034         wxDataViewTreeNode 
* n 
= NULL
; 
2035         wxDataViewTreeNodes nodes 
= node
->GetNodes(); 
2036         int len 
= nodes
.GetCount(); 
2037         for( int i 
= 0; i 
< len
; i 
++) 
2039             if( nodes
[i
]->GetItem() == item 
) 
2046         wxCHECK_MSG( n 
!= NULL
, false, "item not found" ); 
2048         node
->GetNodes().Remove( n 
); 
2049         sub 
-= n
->GetSubTreeCount(); 
2050         ::DestroyTreeHelper(n
); 
2052     // Make the row number invalid and get a new valid one when user call GetRowCount 
2054     node
->ChangeSubTreeCount(sub
); 
2056     // Change the current row to the last row if the current exceed the max row number 
2057     if( m_currentRow 
> GetRowCount() ) 
2058         m_currentRow 
= m_count 
- 1; 
2065 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem 
& item
) 
2067     GetOwner()->InvalidateColBestWidths(); 
2073     wxWindow 
*parent 
= GetParent(); 
2074     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2075     le
.SetEventObject(parent
); 
2076     le
.SetModel(GetOwner()->GetModel()); 
2078     parent
->GetEventHandler()->ProcessEvent(le
); 
2083 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem 
& item
, unsigned int model_column 
) 
2085     int view_column 
= -1; 
2086     unsigned int n_col 
= m_owner
->GetColumnCount(); 
2087     for (unsigned i 
= 0; i 
< n_col
; i
++) 
2089         wxDataViewColumn 
*column 
= m_owner
->GetColumn( i 
); 
2090         if (column
->GetModelColumn() == model_column
) 
2092             view_column 
= (int) i
; 
2096     if (view_column 
== -1) 
2099     GetOwner()->InvalidateColBestWidth(view_column
); 
2101     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 
2102 /*#define MAX_VIRTUAL_WIDTH       100000 
2104     wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight ); 
2105     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); 
2106     Refresh( true, &rect ); 
2114     wxWindow 
*parent 
= GetParent(); 
2115     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2116     le
.SetEventObject(parent
); 
2117     le
.SetModel(GetOwner()->GetModel()); 
2119     le
.SetColumn(view_column
); 
2120     le
.SetDataViewColumn(GetOwner()->GetColumn(view_column
)); 
2121     parent
->GetEventHandler()->ProcessEvent(le
); 
2126 bool wxDataViewMainWindow::Cleared() 
2128     GetOwner()->InvalidateColBestWidths(); 
2131     m_selection
.Clear(); 
2134     BuildTree( GetOwner()->GetModel() ); 
2141 void wxDataViewMainWindow::UpdateDisplay() 
2144     m_underMouse 
= NULL
; 
2147 void wxDataViewMainWindow::OnInternalIdle() 
2149     wxWindow::OnInternalIdle(); 
2153         RecalculateDisplay(); 
2158 void wxDataViewMainWindow::RecalculateDisplay() 
2160     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2167     int width 
= GetEndOfLastCol(); 
2168     int height 
= GetLineStart( GetRowCount() ); 
2170     SetVirtualSize( width
, height 
); 
2171     GetOwner()->SetScrollRate( 10, m_lineHeight 
); 
2176 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
2178     m_underMouse 
= NULL
; 
2180     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
2182     if (GetOwner()->m_headerArea
) 
2183         GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 ); 
2186 void wxDataViewMainWindow::ScrollTo( int rows
, int column 
) 
2188     m_underMouse 
= NULL
; 
2191     m_owner
->GetScrollPixelsPerUnit( &x
, &y 
); 
2192     int sy 
= GetLineStart( rows 
)/y
; 
2196         wxRect rect 
= GetClientRect(); 
2200         m_owner
->CalcUnscrolledPosition( rect
.x
, rect
.y
, &xx
, &yy 
); 
2201         for (x_start 
= 0; colnum 
< column
; colnum
++) 
2203             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(colnum
); 
2204             if (col
->IsHidden()) 
2205                 continue;      // skip it! 
2207             w 
= col
->GetWidth(); 
2211         int x_end 
= x_start 
+ w
; 
2212         xe 
= xx 
+ rect
.width
; 
2215             sx 
= ( xx 
+ x_end 
- xe 
)/x
; 
2222     m_owner
->Scroll( sx
, sy 
); 
2225 int wxDataViewMainWindow::GetCountPerPage() const 
2227     wxSize size 
= GetClientSize(); 
2228     return size
.y 
/ m_lineHeight
; 
2231 int wxDataViewMainWindow::GetEndOfLastCol() const 
2235     for (i 
= 0; i 
< GetOwner()->GetColumnCount(); i
++) 
2237         const wxDataViewColumn 
*c 
= 
2238             const_cast<wxDataViewCtrl
*>(GetOwner())->GetColumnAt( i 
); 
2241             width 
+= c
->GetWidth(); 
2246 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const 
2250     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2252     return GetLineAt( y 
); 
2255 unsigned int wxDataViewMainWindow::GetLastVisibleRow() 
2257     wxSize client_size 
= GetClientSize(); 
2258     m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
, 
2259                                     &client_size
.x
, &client_size
.y 
); 
2261     // we should deal with the pixel here 
2262     unsigned int row 
= GetLineAt(client_size
.y
) - 1; 
2264     return wxMin( GetRowCount()-1, row 
); 
2267 unsigned int wxDataViewMainWindow::GetRowCount() 
2269     if ( m_count 
== -1 ) 
2271         m_count 
= RecalculateCount(); 
2277 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row 
) 
2284 void wxDataViewMainWindow::SelectAllRows( bool on 
) 
2291         m_selection
.Clear(); 
2292         for (unsigned int i 
= 0; i 
< GetRowCount(); i
++) 
2293             m_selection
.Add( i 
); 
2298         unsigned int first_visible 
= GetFirstVisibleRow(); 
2299         unsigned int last_visible 
= GetLastVisibleRow(); 
2301         for (i 
= 0; i 
< m_selection
.GetCount(); i
++) 
2303             unsigned int row 
= m_selection
[i
]; 
2304             if ((row 
>= first_visible
) && (row 
<= last_visible
)) 
2307         m_selection
.Clear(); 
2311 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on 
) 
2313     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2317             m_selection
.Add( row 
); 
2325             m_selection
.Remove( row 
); 
2331 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on 
) 
2335         unsigned int tmp 
= from
; 
2341     for (i 
= from
; i 
<= to
; i
++) 
2343         if (m_selection
.Index( i 
) == wxNOT_FOUND
) 
2346                 m_selection
.Add( i 
); 
2351                 m_selection
.Remove( i 
); 
2354     RefreshRows( from
, to 
); 
2357 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections 
) 
2359     for (size_t i
=0; i 
< aSelections
.GetCount(); i
++) 
2361         int n 
= aSelections
[i
]; 
2363         m_selection
.Add( n 
); 
2368 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row 
) 
2370     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2371         m_selection
.Add( row 
); 
2373         m_selection
.Remove( row 
); 
2377 bool wxDataViewMainWindow::IsRowSelected( unsigned int row 
) 
2379     return (m_selection
.Index( row 
) != wxNOT_FOUND
); 
2382 void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem
& item
) 
2384     wxWindow 
*parent 
= GetParent(); 
2385     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED
, parent
->GetId()); 
2387     le
.SetEventObject(parent
); 
2388     le
.SetModel(GetOwner()->GetModel()); 
2391     parent
->GetEventHandler()->ProcessEvent(le
); 
2394 void wxDataViewMainWindow::RefreshRow( unsigned int row 
) 
2396     wxRect 
rect( 0, GetLineStart( row 
), GetEndOfLastCol(), GetLineHeight( row 
) ); 
2397     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2399     wxSize client_size 
= GetClientSize(); 
2400     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2401     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2402     if (intersect_rect
.width 
> 0) 
2403         Refresh( true, &intersect_rect 
); 
2406 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to 
) 
2410         unsigned int tmp 
= to
; 
2415     wxRect 
rect( 0, GetLineStart( from 
), GetEndOfLastCol(), GetLineStart( (to
-from
+1) ) ); 
2416     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2418     wxSize client_size 
= GetClientSize(); 
2419     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2420     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2421     if (intersect_rect
.width 
> 0) 
2422         Refresh( true, &intersect_rect 
); 
2425 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow 
) 
2427     wxSize client_size 
= GetClientSize(); 
2428     int start 
= GetLineStart( firstRow 
); 
2429     m_owner
->CalcScrolledPosition( start
, 0, &start
, NULL 
); 
2430     if (start 
> client_size
.y
) return; 
2432     wxRect 
rect( 0, start
, client_size
.x
, client_size
.y 
- start 
); 
2434     Refresh( true, &rect 
); 
2437 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
) 
2439     wxCHECK_RET( newCurrent 
< GetRowCount(), 
2440                 wxT("invalid item index in OnArrowChar()") ); 
2442     // if there is no selection, we cannot move it anywhere 
2443     if (!HasCurrentRow()) 
2446     unsigned int oldCurrent 
= m_currentRow
; 
2448     // in single selection we just ignore Shift as we can't select several 
2450     if ( event
.ShiftDown() && !IsSingleSel() ) 
2452         RefreshRow( oldCurrent 
); 
2454         ChangeCurrentRow( newCurrent 
); 
2456         // select all the items between the old and the new one 
2457         if ( oldCurrent 
> newCurrent 
) 
2459             newCurrent 
= oldCurrent
; 
2460             oldCurrent 
= m_currentRow
; 
2463         SelectRows( oldCurrent
, newCurrent
, true ); 
2464         if (oldCurrent
!=newCurrent
) 
2465             SendSelectionChangedEvent(GetItemByRow(m_selection
[0])); 
2469         RefreshRow( oldCurrent 
); 
2471         // all previously selected items are unselected unless ctrl is held 
2472         if ( !event
.ControlDown() ) 
2473             SelectAllRows(false); 
2475         ChangeCurrentRow( newCurrent 
); 
2477         if ( !event
.ControlDown() ) 
2479             SelectRow( m_currentRow
, true ); 
2480             SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
2483             RefreshRow( m_currentRow 
); 
2486     GetOwner()->EnsureVisible( m_currentRow
, -1 ); 
2489 wxRect 
wxDataViewMainWindow::GetLineRect( unsigned int row 
) const 
2493     rect
.y 
= GetLineStart( row 
); 
2494     rect
.width 
= GetEndOfLastCol(); 
2495     rect
.height 
= GetLineHeight( row 
); 
2500 int wxDataViewMainWindow::GetLineStart( unsigned int row 
) const 
2502     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2504     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2506         // TODO make more efficient 
2511         for (r 
= 0; r 
< row
; r
++) 
2513             const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(r
); 
2514             if (!node
) return start
; 
2516             wxDataViewItem item 
= node
->GetItem(); 
2518             if (node 
&& !node
->HasChildren()) 
2520                 // Yes, if the node does not have any child, it must be a leaf which 
2521                 // mean that it is a temporarily created by GetTreeNodeByRow 
2525             unsigned int cols 
= GetOwner()->GetColumnCount(); 
2527             int height 
= m_lineHeight
; 
2528             for (col 
= 0; col 
< cols
; col
++) 
2530                 const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2531                 if (column
->IsHidden()) 
2532                     continue;      // skip it! 
2535                     model
->IsContainer(item
) && 
2536                     !model
->HasContainerColumns(item
)) 
2537                     continue;      // skip it! 
2539                 wxDataViewRenderer 
*renderer 
= 
2540                     const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2541                 renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2543                 height 
= wxMax( height
, renderer
->GetSize().y 
); 
2553         return row 
* m_lineHeight
; 
2557 int wxDataViewMainWindow::GetLineAt( unsigned int y 
) const 
2559     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2561     // check for the easy case first 
2562     if ( !GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT
) ) 
2563         return y 
/ m_lineHeight
; 
2565     // TODO make more efficient 
2566     unsigned int row 
= 0; 
2567     unsigned int yy 
= 0; 
2570         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2573             // not really correct... 
2574             return row 
+ ((y
-yy
) / m_lineHeight
); 
2577         wxDataViewItem item 
= node
->GetItem(); 
2579         if (node 
&& !node
->HasChildren()) 
2581             // Yes, if the node does not have any child, it must be a leaf which 
2582             // mean that it is a temporarily created by GetTreeNodeByRow 
2586         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2588         int height 
= m_lineHeight
; 
2589         for (col 
= 0; col 
< cols
; col
++) 
2591             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2592             if (column
->IsHidden()) 
2593                 continue;      // skip it! 
2596                 model
->IsContainer(item
) && 
2597                 !model
->HasContainerColumns(item
)) 
2598                 continue;      // skip it! 
2600             wxDataViewRenderer 
*renderer 
= 
2601                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2602             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2604             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2615 int wxDataViewMainWindow::GetLineHeight( unsigned int row 
) const 
2617     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2619     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2621         wxASSERT( !IsVirtualList() ); 
2623         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2624         // wxASSERT( node ); 
2625         if (!node
) return m_lineHeight
; 
2627         wxDataViewItem item 
= node
->GetItem(); 
2629         if (node 
&& !node
->HasChildren()) 
2631                 // Yes, if the node does not have any child, it must be a leaf which 
2632                 // mean that it is a temporarily created by GetTreeNodeByRow 
2636         int height 
= m_lineHeight
; 
2638         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2640         for (col 
= 0; col 
< cols
; col
++) 
2642             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2643             if (column
->IsHidden()) 
2644                 continue;      // skip it! 
2647                 model
->IsContainer(item
) && 
2648                 !model
->HasContainerColumns(item
)) 
2649                 continue;      // skip it! 
2651             wxDataViewRenderer 
*renderer 
= 
2652                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2653             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2655             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2662         return m_lineHeight
; 
2666 class RowToItemJob
: public DoJob
 
2669     RowToItemJob( unsigned int row 
, int current 
) 
2670         { this->row 
= row
; this->current 
= current
; } 
2671     virtual ~RowToItemJob() {} 
2673     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2676         if( current 
== static_cast<int>(row
)) 
2678             ret 
= node
->GetItem(); 
2682         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2684             current 
+= node
->GetSubTreeCount(); 
2689             // If the current has no child node, we can find the desired item of the row 
2691             // This if can speed up finding in some case, and will has a very good effect 
2692             // when it comes to list view 
2693             if( node
->GetNodes().GetCount() == 0) 
2695                 int index 
= static_cast<int>(row
) - current 
- 1; 
2696                 ret 
= node
->GetChildren().Item( index 
); 
2703     virtual int operator() ( void * n 
) 
2706         if( current 
== static_cast<int>(row
)) 
2708             ret 
= wxDataViewItem( n 
); 
2714     wxDataViewItem 
GetResult() const 
2723 wxDataViewItem 
wxDataViewMainWindow::GetItemByRow(unsigned int row
) const 
2725     if (IsVirtualList()) 
2727         return wxDataViewItem( wxUIntToPtr(row
+1) ); 
2731         RowToItemJob 
job( row
, -2 ); 
2732         Walker( m_root 
, job 
); 
2733         return job
.GetResult(); 
2737 class RowToTreeNodeJob
: public DoJob
 
2740     RowToTreeNodeJob( unsigned int row 
, int current
, wxDataViewTreeNode 
* node 
) 
2743         this->current 
= current
; 
2747     virtual ~RowToTreeNodeJob(){ } 
2749     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2752         if( current 
== static_cast<int>(row
)) 
2758         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2760             current 
+= node
->GetSubTreeCount(); 
2767             // If the current node has no children, we can find the desired item of the 
2768             // row number directly. 
2769             // This if can speed up finding in some case, and will have a very good 
2770             // effect for list views. 
2771             if( node
->GetNodes().GetCount() == 0) 
2773                 int index 
= static_cast<int>(row
) - current 
- 1; 
2774                 void * n 
= node
->GetChildren().Item( index 
); 
2775                 ret 
= new wxDataViewTreeNode( parent 
); 
2776                 ret
->SetItem( wxDataViewItem( n 
)); 
2777                 ret
->SetHasChildren(false); 
2784     virtual int operator() ( void * n 
) 
2787         if( current 
== static_cast<int>(row
)) 
2789             ret 
= new wxDataViewTreeNode( parent 
); 
2790             ret
->SetItem( wxDataViewItem( n 
)); 
2791             ret
->SetHasChildren(false); 
2798     wxDataViewTreeNode 
* GetResult() const 
2804     wxDataViewTreeNode 
* ret
; 
2805     wxDataViewTreeNode 
* parent
; 
2808 wxDataViewTreeNode 
* wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row
) const 
2810     wxASSERT( !IsVirtualList() ); 
2812     RowToTreeNodeJob 
job( row 
, -2, m_root 
); 
2813     Walker( m_root 
, job 
); 
2814     return job
.GetResult(); 
2817 wxDataViewEvent 
wxDataViewMainWindow::SendExpanderEvent( wxEventType type
, 
2818                                                          const wxDataViewItem 
& item 
) 
2820     wxWindow 
*parent 
= GetParent(); 
2821     wxDataViewEvent 
le(type
, parent
->GetId()); 
2823     le
.SetEventObject(parent
); 
2824     le
.SetModel(GetOwner()->GetModel()); 
2827     parent
->GetEventHandler()->ProcessEvent(le
); 
2831 bool wxDataViewMainWindow::IsExpanded( unsigned int row 
) const 
2836     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2840     if (!node
->HasChildren()) 
2846     return node
->IsOpen(); 
2849 bool wxDataViewMainWindow::HasChildren( unsigned int row 
) const 
2854     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2858     if (!node
->HasChildren()) 
2867 void wxDataViewMainWindow::Expand( unsigned int row 
) 
2872     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2876     if (!node
->HasChildren()) 
2882             if (!node
->IsOpen()) 
2885                     SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING
, node
->GetItem()); 
2887                 // Check if the user prevent expanding 
2888                 if( e
.GetSkipped() ) 
2893                 // build the children of current node 
2894                 if( node
->GetChildrenNumber() == 0 ) 
2897                     ::BuildTreeHelper(GetOwner()->GetModel(), node
->GetItem(), node
); 
2900                 // By expanding the node all row indices that are currently in the selection list 
2901                 // and are greater than our node have become invalid. So we have to correct that now. 
2902                 const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
2903                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2905                     const unsigned testRow 
= m_selection
[i
]; 
2906                     // all rows above us are not affected, so skip them 
2910                     m_selection
[i
] += rowAdjustment
; 
2913                 if(m_currentRow 
> row
) 
2914                     ChangeCurrentRow(m_currentRow 
+ rowAdjustment
); 
2918                 // Send the expanded event 
2919                 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED
,node
->GetItem()); 
2923 void wxDataViewMainWindow::Collapse(unsigned int row
) 
2928     wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
2932     if (!node
->HasChildren()) 
2941                 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING
,node
->GetItem()); 
2942             if( e
.GetSkipped() ) 
2945             // Find out if there are selected items below the current node. 
2946             bool selectCollapsingRow 
= false; 
2947             const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
2948             unsigned maxRowToBeTested 
= row 
+ rowAdjustment
; 
2949             for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2951                 const unsigned testRow 
= m_selection
[i
]; 
2952                 if(testRow 
> row 
&& testRow 
<= maxRowToBeTested
) 
2954                     selectCollapsingRow 
= true; 
2955                     // get out as soon as we have found a node that is selected 
2962             // If the node to be closed has selected items the user won't see those any longer. 
2963             // We select the collapsing node in this case. 
2964             if(selectCollapsingRow
) 
2966                 SelectAllRows(false); 
2967                 ChangeCurrentRow(row
); 
2968                 SelectRow(row
, true); 
2969                 SendSelectionChangedEvent(GetItemByRow(row
)); 
2973                 // if there were no selected items below our node we still need to "fix" the 
2974                 // selection list to adjust for the changing of the row indices. 
2975                 // We actually do the opposite of what we are doing in Expand(). 
2976                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2978                     const unsigned testRow 
= m_selection
[i
]; 
2979                     // all rows above us are not affected, so skip them 
2983                     m_selection
[i
] -= rowAdjustment
; 
2986                 // if the "current row" is being collapsed away we change it to the current row ;-) 
2987                 if(m_currentRow 
> row 
&& m_currentRow 
<= maxRowToBeTested
) 
2988                     ChangeCurrentRow(row
); 
2989                 else if(m_currentRow 
> row
) 
2990                     ChangeCurrentRow(m_currentRow 
- rowAdjustment
); 
2995             SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED
,node
->GetItem()); 
2999 wxDataViewTreeNode 
* wxDataViewMainWindow::FindNode( const wxDataViewItem 
& item 
) 
3001     const wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
3008     // Compose the parent-chain for the item we are looking for 
3009     wxVector
<wxDataViewItem
> parentChain
; 
3010     wxDataViewItem 
it( item 
); 
3013         parentChain
.push_back(it
); 
3014         it 
= model
->GetParent(it
); 
3017     // Find the item along the parent-chain. 
3018     // This algorithm is designed to speed up the node-finding method 
3019     wxDataViewTreeNode
* node 
= m_root
; 
3020     for( unsigned iter 
= parentChain
.size()-1; iter
>=0; --iter 
) 
3022         if( node
->HasChildren() ) 
3024             if( node
->GetChildrenNumber() == 0 ) 
3027                 ::BuildTreeHelper(model
, node
->GetItem(), node
); 
3030             const wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
3033             for (unsigned i 
= 0; i 
< nodes
.GetCount(); ++i
) 
3035                 wxDataViewTreeNode
* currentNode 
= nodes
[i
]; 
3036                 if (currentNode
->GetItem() == parentChain
[iter
]) 
3038                     if (currentNode
->GetItem() == item
) 
3055 void wxDataViewMainWindow::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
3056                                     wxDataViewColumn
* &column 
) 
3058     wxDataViewColumn 
*col 
= NULL
; 
3059     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3060     unsigned int colnum 
= 0; 
3062     m_owner
->CalcUnscrolledPosition( point
.x
, point
.y
, &x
, &y 
); 
3063     for (unsigned x_start 
= 0; colnum 
< cols
; colnum
++) 
3065         col 
= GetOwner()->GetColumnAt(colnum
); 
3066         if (col
->IsHidden()) 
3067             continue;      // skip it! 
3069         unsigned int w 
= col
->GetWidth(); 
3070         if (x_start
+w 
>= (unsigned int)x
) 
3077     item 
= GetItemByRow( GetLineAt( y 
) ); 
3080 wxRect 
wxDataViewMainWindow::GetItemRect( const wxDataViewItem 
& item
, 
3081                                           const wxDataViewColumn
* column 
) 
3086     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3087     // If column is null the loop will compute the combined width of all columns. 
3088     // Otherwise, it will compute the x position of the column we are looking for. 
3089     for (unsigned int i 
= 0; i 
< cols
; i
++) 
3091         wxDataViewColumn
* col 
= GetOwner()->GetColumnAt( i 
); 
3096         if (col
->IsHidden()) 
3097             continue;      // skip it! 
3099         xpos 
+= col
->GetWidth(); 
3100         width 
+= col
->GetWidth(); 
3105         // If we have a column, we need can get its width directly. 
3106         if(column
->IsHidden()) 
3109             width 
= column
->GetWidth(); 
3114         // If we have no column, we reset the x position back to zero. 
3118     // we have to take an expander column into account and compute its indentation 
3119     // to get the correct x position where the actual text is 
3121     int row 
= GetRowByItem(item
); 
3122     if (!IsList() && (column 
== 0 || GetOwner()->GetExpanderColumn() == column
) ) 
3124         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
3125         indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
3126         indent 
= indent 
+ m_lineHeight
; // use m_lineHeight as the width of the expander 
3128         if(!node
->HasChildren()) 
3132     wxRect 
itemRect( xpos 
+ indent
, 
3133                      GetLineStart( row 
), 
3135                      GetLineHeight( row 
) ); 
3137     GetOwner()->CalcScrolledPosition(  itemRect
.x
,  itemRect
.y
, 
3138                                       &itemRect
.x
, &itemRect
.y 
); 
3143 int wxDataViewMainWindow::RecalculateCount() 
3145     if (IsVirtualList()) 
3147         wxDataViewVirtualListModel 
*list_model 
= 
3148             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
3150         return list_model
->GetCount(); 
3154         return m_root
->GetSubTreeCount(); 
3158 class ItemToRowJob 
: public DoJob
 
3161     ItemToRowJob(const wxDataViewItem
& item_
, wxVector
<wxDataViewItem
>::reverse_iterator iter
) 
3168     // Maybe binary search will help to speed up this process 
3169     virtual int operator() ( wxDataViewTreeNode 
* node
) 
3172         if( node
->GetItem() == item 
) 
3177         if( node
->GetItem() == *m_iter 
) 
3184             ret 
+= node
->GetSubTreeCount(); 
3190     virtual int operator() ( void * n 
) 
3193         if( n 
== item
.GetID() ) 
3198     // the row number is begin from zero 
3199     int GetResult() const 
3203     wxVector
<wxDataViewItem
>::reverse_iterator m_iter
; 
3204     wxDataViewItem item
; 
3209 int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem 
& item
) const 
3211     const wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
3215     if (IsVirtualList()) 
3217         return wxPtrToUInt( item
.GetID() ) -1; 
3224         // Compose the parent-chain of the item we are looking for 
3225         wxVector
<wxDataViewItem
> parentChain
; 
3226         wxDataViewItem 
it( item 
); 
3229             parentChain
.push_back(it
); 
3230             it 
= model
->GetParent(it
); 
3233         // add an 'invalid' item to represent our 'invisible' root node 
3234         parentChain
.push_back(wxDataViewItem()); 
3236         // the parent chain was created by adding the deepest parent first. 
3237         // so if we want to start at the root node, we have to iterate backwards through the vector 
3238         ItemToRowJob 
job( item
, parentChain
.rbegin() ); 
3239         Walker( m_root
, job 
); 
3240         return job
.GetResult(); 
3244 static void BuildTreeHelper( const wxDataViewModel 
* model
,  const wxDataViewItem 
& item
, 
3245                              wxDataViewTreeNode 
* node
) 
3247     if( !model
->IsContainer( item 
) ) 
3250     wxDataViewItemArray children
; 
3251     unsigned int num 
= model
->GetChildren( item
, children
); 
3253     unsigned int index 
= 0; 
3254     while( index 
< num 
) 
3256         if( model
->IsContainer( children
[index
] ) ) 
3258             wxDataViewTreeNode 
* n 
= new wxDataViewTreeNode( node 
); 
3259             n
->SetItem(children
[index
]); 
3260             n
->SetHasChildren( true ); 
3265             node
->AddLeaf( children
[index
].GetID() ); 
3269     node
->SetSubTreeCount( num 
); 
3270     wxDataViewTreeNode 
* n 
= node
->GetParent(); 
3272         n
->ChangeSubTreeCount(num
); 
3276 void wxDataViewMainWindow::BuildTree(wxDataViewModel 
* model
) 
3280     if (GetOwner()->GetModel()->IsVirtualListModel()) 
3286     m_root 
= new wxDataViewTreeNode( NULL 
); 
3287     m_root
->SetHasChildren(true); 
3289     // First we define a invalid item to fetch the top-level elements 
3290     wxDataViewItem item
; 
3292     BuildTreeHelper( model
, item
, m_root
); 
3296 static void DestroyTreeHelper( wxDataViewTreeNode 
* node 
) 
3298     if( node
->GetNodeNumber() != 0 ) 
3300         int len 
= node
->GetNodeNumber(); 
3301         wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
3302         for (int i 
= 0; i 
< len
; i
++) 
3303             DestroyTreeHelper(nodes
[i
]); 
3308 void wxDataViewMainWindow::DestroyTree() 
3310     if (!IsVirtualList()) 
3312         ::DestroyTreeHelper(m_root
); 
3318 void wxDataViewMainWindow::OnChar( wxKeyEvent 
&event 
) 
3320     wxWindow 
* const parent 
= GetParent(); 
3322     // propagate the char event upwards 
3323     wxKeyEvent 
eventForParent(event
); 
3324     eventForParent
.SetEventObject(parent
); 
3325     if ( parent
->ProcessWindowEvent(eventForParent
) ) 
3328     if ( parent
->HandleAsNavigationKey(event
) ) 
3331     // no item -> nothing to do 
3332     if (!HasCurrentRow()) 
3338     // don't use m_linesPerPage directly as it might not be computed yet 
3339     const int pageSize 
= GetCountPerPage(); 
3340     wxCHECK_RET( pageSize
, wxT("should have non zero page size") ); 
3342     switch ( event
.GetKeyCode() ) 
3346                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, 
3348                 le
.SetItem( GetItemByRow(m_currentRow
) ); 
3349                 le
.SetEventObject(parent
); 
3350                 le
.SetModel(GetOwner()->GetModel()); 
3352                 parent
->GetEventHandler()->ProcessEvent(le
); 
3357             if ( m_currentRow 
> 0 ) 
3358                 OnArrowChar( m_currentRow 
- 1, event 
); 
3362             if ( m_currentRow 
< GetRowCount() - 1 ) 
3363                 OnArrowChar( m_currentRow 
+ 1, event 
); 
3365         // Add the process for tree expanding/collapsing 
3371             wxDataViewTreeNode
* node 
= GetTreeNodeByRow(m_currentRow
); 
3375             if (node
->HasChildren() && node
->IsOpen()) 
3377                 Collapse(m_currentRow
); 
3379             else    // if the node is already closed we move the selection to its parent 
3381                 wxDataViewTreeNode 
*parent_node 
= node
->GetParent(); 
3383                 if(!node
->HasChildren()) 
3388                     int parent 
= GetRowByItem( parent_node
->GetItem() ); 
3391                         unsigned int row 
= m_currentRow
; 
3392                         SelectRow( row
, false); 
3393                         SelectRow( parent
, true ); 
3394                         ChangeCurrentRow( parent 
); 
3395                         GetOwner()->EnsureVisible( parent
, -1 ); 
3396                         SendSelectionChangedEvent( parent_node
->GetItem() ); 
3404             if (!IsExpanded( m_currentRow 
)) 
3405                 Expand( m_currentRow 
); 
3408                 unsigned int row 
= m_currentRow
; 
3409                 SelectRow( row
, false ); 
3410                 SelectRow( row 
+ 1, true ); 
3411                 ChangeCurrentRow( row 
+ 1 ); 
3412                 GetOwner()->EnsureVisible( row 
+ 1, -1 ); 
3413                 SendSelectionChangedEvent( GetItemByRow(row
+1) ); 
3420                 OnArrowChar( GetRowCount() - 1, event 
); 
3425                 OnArrowChar( 0, event 
); 
3430                 int steps 
= pageSize 
- 1; 
3431                 int index 
= m_currentRow 
- steps
; 
3435                 OnArrowChar( index
, event 
); 
3441                 int steps 
= pageSize 
- 1; 
3442                 unsigned int index 
= m_currentRow 
+ steps
; 
3443                 unsigned int count 
= GetRowCount(); 
3444                 if ( index 
>= count 
) 
3447                 OnArrowChar( index
, event 
); 
3453                 if(m_selection
.size() == 1) 
3455                     // TODO: we need to revise that when we have a concept for a 'current column' 
3456                     GetOwner()->StartEditor(GetItemByRow(m_selection
[0]), 0); 
3466 void wxDataViewMainWindow::OnMouse( wxMouseEvent 
&event 
) 
3468     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
3470         // let the base handle mouse wheel events. 
3475     // set the focus to ourself if any of the mouse buttons are pressed 
3476     if(event
.ButtonDown() && !HasFocus()) 
3479     int x 
= event
.GetX(); 
3480     int y 
= event
.GetY(); 
3481     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3482     wxDataViewColumn 
*col 
= NULL
; 
3485     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3487     for (i 
= 0; i 
< cols
; i
++) 
3489         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt( i 
); 
3491             continue;      // skip it! 
3493         if (x 
< xpos 
+ c
->GetWidth()) 
3498         xpos 
+= c
->GetWidth(); 
3506     wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
3507     unsigned int current 
= GetLineAt( y 
); 
3508     if ((current 
>= GetRowCount()) || (x 
> GetEndOfLastCol())) 
3510         // Unselect all if below the last row ? 
3515     // Test whether the mouse is hovered on the tree item button 
3516     bool hoverOverExpander 
= false; 
3517     if ((!IsList()) && (GetOwner()->GetExpanderColumn() == col
)) 
3519         wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(current
); 
3520         if( node
!=NULL 
&& node
->HasChildren() ) 
3522             int indent 
= node
->GetIndentLevel(); 
3523             indent 
= GetOwner()->GetIndent()*indent
; 
3525             // we make the rectangle we are looking in a bit bigger than the actual 
3526             // visual expander so the user can hit that little thing reliably 
3527             wxRect 
rect( xpos 
+ indent
, 
3528                         GetLineStart( current 
) + (GetLineHeight(current
) - m_lineHeight
)/2, 
3529                         m_lineHeight
, m_lineHeight
); 
3530             if( rect
.Contains(x
, y
) ) 
3532                 // So the mouse is over the expander 
3533                 hoverOverExpander 
= true; 
3534                 if (m_underMouse 
&& m_underMouse 
!= node
) 
3536                     // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
3537                     RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
3539                 if (m_underMouse 
!= node
) 
3541                     // wxLogMessage("Do the row: %d", current); 
3542                     RefreshRow(current
); 
3544                 m_underMouse 
= node
; 
3547         if (node
!=NULL 
&& !node
->HasChildren()) 
3550     if (!hoverOverExpander
) 
3552         if (m_underMouse 
!= NULL
) 
3554             // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
3555             RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
3556             m_underMouse 
= NULL
; 
3560     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
3562 #if wxUSE_DRAG_AND_DROP 
3563     if (event
.Dragging()) 
3565         if (m_dragCount 
== 0) 
3567             // we have to report the raw, physical coords as we want to be 
3568             // able to call HitTest(event.m_pointDrag) from the user code to 
3569             // get the item being dragged 
3570             m_dragStart 
= event
.GetPosition(); 
3575         if (m_dragCount 
!= 3) 
3578         if (event
.LeftIsDown()) 
3580             m_owner
->CalcUnscrolledPosition( m_dragStart
.x
, m_dragStart
.y
, 
3581                                              &m_dragStart
.x
, &m_dragStart
.y 
); 
3582             unsigned int drag_item_row 
= GetLineAt( m_dragStart
.y 
); 
3583             wxDataViewItem item 
= GetItemByRow( drag_item_row 
); 
3585             // Notify cell about drag 
3586             wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG
, m_owner
->GetId() ); 
3587             event
.SetEventObject( m_owner 
); 
3588             event
.SetItem( item 
); 
3589             event
.SetModel( model 
); 
3590             if (!m_owner
->HandleWindowEvent( event 
)) 
3593             if (!event
.IsAllowed()) 
3596             wxDataObject 
*obj 
= event
.GetDataObject(); 
3600             wxDataViewDropSource 
drag( this, drag_item_row 
); 
3601             drag
.SetData( *obj 
); 
3602             /* wxDragResult res = */ drag
.DoDragDrop(); 
3611 #endif // wxUSE_DRAG_AND_DROP 
3613     bool simulateClick 
= false; 
3615     if (event
.ButtonDClick()) 
3617         m_renameTimer
->Stop(); 
3618         m_lastOnSame 
= false; 
3621     wxDataViewItem item 
= GetItemByRow(current
); 
3622     bool ignore_other_columns 
= 
3623         ((GetOwner()->GetExpanderColumn() != col
) && 
3624         (model
->IsContainer(item
)) && 
3625         (!model
->HasContainerColumns(item
))); 
3627     if (event
.LeftDClick()) 
3629         if(hoverOverExpander
) 
3631             // a double click on the expander will be converted into a "simulated" normal click 
3632             simulateClick 
= true; 
3634         else if ( current 
== m_lineLastClicked 
) 
3636             if ((!ignore_other_columns
) && (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)) 
3638                 const unsigned colIdx 
= col
->GetModelColumn(); 
3640                 cell
->PrepareForItem(model
, item
, colIdx
); 
3642                 wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3643                                 col
->GetWidth(), GetLineHeight( current 
) ); 
3644                 cell
->WXOnActivate( cell_rect
, model
, item
, colIdx 
); 
3648                 wxWindow 
*parent 
= GetParent(); 
3649                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId()); 
3651                 le
.SetColumn( col
->GetModelColumn() ); 
3652                 le
.SetDataViewColumn( col 
); 
3653                 le
.SetEventObject(parent
); 
3654                 le
.SetModel(GetOwner()->GetModel()); 
3656                 parent
->GetEventHandler()->ProcessEvent(le
); 
3662             // The first click was on another item, so don't interpret this as 
3663             // a double click, but as a simple click instead 
3664             simulateClick 
= true; 
3668     if (event
.LeftUp() && !hoverOverExpander
) 
3670         if (m_lineSelectSingleOnUp 
!= (unsigned int)-1) 
3672             // select single line 
3673             SelectAllRows( false ); 
3674             SelectRow( m_lineSelectSingleOnUp
, true ); 
3675             SendSelectionChangedEvent( GetItemByRow(m_lineSelectSingleOnUp
) ); 
3678         // If the user click the expander, we do not do editing even if the column 
3679         // with expander are editable 
3680         if (m_lastOnSame 
&& !ignore_other_columns
) 
3682             if ((col 
== m_currentCol
) && (current 
== m_currentRow
) && 
3683                 (cell
->GetMode() & wxDATAVIEW_CELL_EDITABLE
) ) 
3685                 m_renameTimer
->Start( 100, true ); 
3689         m_lastOnSame 
= false; 
3690         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3692     else if(!event
.LeftUp()) 
3694         // This is necessary, because after a DnD operation in 
3695         // from and to ourself, the up event is swallowed by the 
3696         // DnD code. So on next non-up event (which means here and 
3697         // now) m_lineSelectSingleOnUp should be reset. 
3698         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3701     if (event
.RightDown()) 
3703         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3704         m_lineLastClicked 
= current
; 
3706         // If the item is already selected, do not update the selection. 
3707         // Multi-selections should not be cleared if a selected item is clicked. 
3708         if (!IsRowSelected(current
)) 
3710             SelectAllRows(false); 
3711             ChangeCurrentRow(current
); 
3712             SelectRow(m_currentRow
,true); 
3713             SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3716     else if (event
.RightUp()) 
3719         model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3720         wxWindow 
*parent 
= GetParent(); 
3721         wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU
, parent
->GetId()); 
3723         le
.SetColumn( col
->GetModelColumn() ); 
3724         le
.SetDataViewColumn( col 
); 
3725         le
.SetEventObject(parent
); 
3726         le
.SetModel(GetOwner()->GetModel()); 
3728         parent
->GetEventHandler()->ProcessEvent(le
); 
3730     else if (event
.MiddleDown()) 
3734     if((event
.LeftDown() || simulateClick
) && hoverOverExpander
) 
3736         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(current
); 
3738         // hoverOverExpander being true tells us that our node must be 
3739         // valid and have children. 
3740         // So we don't need any extra checks. 
3741         if( node
->IsOpen() ) 
3746     else if ((event
.LeftDown() || simulateClick
) && !hoverOverExpander
) 
3748         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3749         m_lineLastClicked 
= current
; 
3751         unsigned int oldCurrentRow 
= m_currentRow
; 
3752         bool oldWasSelected 
= IsRowSelected(m_currentRow
); 
3754         bool cmdModifierDown 
= event
.CmdDown(); 
3755         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3757             if ( IsSingleSel() || !IsRowSelected(current
) ) 
3759                 SelectAllRows( false ); 
3760                 ChangeCurrentRow(current
); 
3761                 SelectRow(m_currentRow
,true); 
3762                 SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3764             else // multi sel & current is highlighted & no mod keys 
3766                 m_lineSelectSingleOnUp 
= current
; 
3767                 ChangeCurrentRow(current
); // change focus 
3770         else // multi sel & either ctrl or shift is down 
3772             if (cmdModifierDown
) 
3774                 ChangeCurrentRow(current
); 
3775                 ReverseRowSelection(m_currentRow
); 
3776                 SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
3778             else if (event
.ShiftDown()) 
3780                 ChangeCurrentRow(current
); 
3782                 unsigned int lineFrom 
= oldCurrentRow
, 
3785                 if ( lineTo 
< lineFrom 
) 
3788                     lineFrom 
= m_currentRow
; 
3791                 SelectRows(lineFrom
, lineTo
, true); 
3792                 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) ); 
3794             else // !ctrl, !shift 
3796                 // test in the enclosing if should make it impossible 
3797                 wxFAIL_MSG( wxT("how did we get here?") ); 
3801         if (m_currentRow 
!= oldCurrentRow
) 
3802             RefreshRow( oldCurrentRow 
); 
3804         wxDataViewColumn 
*oldCurrentCol 
= m_currentCol
; 
3806         // Update selection here... 
3809         m_lastOnSame 
= !simulateClick 
&& ((col 
== oldCurrentCol
) && 
3810                         (current 
== oldCurrentRow
)) && oldWasSelected
; 
3812         // Call LeftClick after everything else as under GTK+ 
3813         if (cell
->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE
) 
3815             // notify cell about click 
3816             cell
->PrepareForItem(model
, item
, col
->GetModelColumn()); 
3818             wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3819                               col
->GetWidth(), GetLineHeight( current 
) ); 
3821             // Report position relative to the cell's custom area, i.e. 
3822             // no the entire space as given by the control but the one 
3823             // used by the renderer after calculation of alignment etc. 
3825             // adjust the rectangle ourselves to account for the alignment 
3826             wxRect rectItem 
= cell_rect
; 
3827             const int align 
= cell
->GetAlignment(); 
3828             if ( align 
!= wxDVR_DEFAULT_ALIGNMENT 
) 
3830                 const wxSize size 
= cell
->GetSize(); 
3832                 if ( size
.x 
>= 0 && size
.x 
< cell_rect
.width 
) 
3834                     if ( align 
& wxALIGN_CENTER_HORIZONTAL 
) 
3835                         rectItem
.x 
+= (cell_rect
.width 
- size
.x
)/2; 
3836                     else if ( align 
& wxALIGN_RIGHT 
) 
3837                         rectItem
.x 
+= cell_rect
.width 
- size
.x
; 
3838                     // else: wxALIGN_LEFT is the default 
3841                 if ( size
.y 
>= 0 && size
.y 
< cell_rect
.height 
) 
3843                     if ( align 
& wxALIGN_CENTER_VERTICAL 
) 
3844                         rectItem
.y 
+= (cell_rect
.height 
- size
.y
)/2; 
3845                     else if ( align 
& wxALIGN_BOTTOM 
) 
3846                         rectItem
.y 
+= cell_rect
.height 
- size
.y
; 
3847                     // else: wxALIGN_TOP is the default 
3851             wxPoint 
pos( event
.GetPosition() ); 
3852             pos
.x 
-= rectItem
.x
; 
3853             pos
.y 
-= rectItem
.y
; 
3855             m_owner
->CalcUnscrolledPosition( pos
.x
, pos
.y
, &pos
.x
, &pos
.y 
); 
3857              /* ignore ret */ cell
->WXOnLeftClick( pos
, cell_rect
, 
3858                               model
, item
, col
->GetModelColumn()); 
3863 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent 
&event 
) 
3867     if (HasCurrentRow()) 
3873 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
3877     if (HasCurrentRow()) 
3883 wxDataViewItem 
wxDataViewMainWindow::GetSelection() const 
3885     if( m_selection
.GetCount() != 1 ) 
3886         return wxDataViewItem(); 
3888     return GetItemByRow( m_selection
.Item(0)); 
3891 //----------------------------------------------------------------------------- 
3893 //----------------------------------------------------------------------------- 
3895 WX_DEFINE_LIST(wxDataViewColumnList
) 
3897 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3898 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3899     EVT_SIZE(wxDataViewCtrl::OnSize
) 
3902 wxDataViewCtrl::~wxDataViewCtrl() 
3905         GetModel()->RemoveNotifier( m_notifier 
); 
3908     m_colsBestWidths
.clear(); 
3911 void wxDataViewCtrl::Init() 
3913     m_cols
.DeleteContents(true); 
3916     // No sorting column at start 
3917     m_sortingColumnIdx 
= wxNOT_FOUND
; 
3919     m_headerArea 
= NULL
; 
3922 bool wxDataViewCtrl::Create(wxWindow 
*parent
, 
3927                             const wxValidator
& validator
, 
3928                             const wxString
& name
) 
3930 //    if ( (style & wxBORDER_MASK) == 0) 
3931 //        style |= wxBORDER_SUNKEN; 
3935     if (!wxControl::Create( parent
, id
, pos
, size
, 
3936                             style 
| wxScrolledWindowStyle
, validator
, name
)) 
3939     SetInitialSize(size
); 
3942     MacSetClipChildren( true ); 
3945     m_clientArea 
= new wxDataViewMainWindow( this, wxID_ANY 
); 
3947     // We use the cursor keys for moving the selection, not scrolling, so call 
3948     // this method to ensure wxScrollHelperEvtHandler doesn't catch all 
3949     // keyboard events forwarded to us from wxListMainWindow. 
3950     DisableKeyboardScrolling(); 
3952     if (HasFlag(wxDV_NO_HEADER
)) 
3953         m_headerArea 
= NULL
; 
3955         m_headerArea 
= new wxDataViewHeaderWindow(this); 
3957     SetTargetWindow( m_clientArea 
); 
3959     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
3961         sizer
->Add( m_headerArea
, 0, wxGROW 
); 
3962     sizer
->Add( m_clientArea
, 1, wxGROW 
); 
3968 wxBorder 
wxDataViewCtrl::GetDefaultBorder() const 
3970     return wxBORDER_THEME
; 
3974 WXLRESULT 
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
, 
3978     WXLRESULT rc 
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
3981     // we need to process arrows ourselves for scrolling 
3982     if ( nMsg 
== WM_GETDLGCODE 
) 
3984         rc 
|= DLGC_WANTARROWS
; 
3992 wxSize 
wxDataViewCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
3994     wxSize newsize 
= size
; 
3995     if (!HasFlag(wxDV_NO_HEADER
) && (m_headerArea
)) 
3996     newsize
.y 
-= m_headerArea
->GetSize().y
; 
4001 void wxDataViewCtrl::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
4003     // We need to override OnSize so that our scrolled 
4004     // window a) does call Layout() to use sizers for 
4005     // positioning the controls but b) does not query 
4006     // the sizer for their size and use that for setting 
4007     // the scrollable area as set that ourselves by 
4008     // calling SetScrollbar() further down. 
4015 void wxDataViewCtrl::SetFocus() 
4018         m_clientArea
->SetFocus(); 
4021 bool wxDataViewCtrl::AssociateModel( wxDataViewModel 
*model 
) 
4023     if (!wxDataViewCtrlBase::AssociateModel( model 
)) 
4026     m_notifier 
= new wxGenericDataViewModelNotifier( m_clientArea 
); 
4028     model
->AddNotifier( m_notifier 
); 
4030     m_clientArea
->DestroyTree(); 
4032     m_clientArea
->BuildTree(model
); 
4034     m_clientArea
->UpdateDisplay(); 
4039 #if wxUSE_DRAG_AND_DROP 
4041 bool wxDataViewCtrl::EnableDragSource( const wxDataFormat 
&format 
) 
4043     return m_clientArea
->EnableDragSource( format 
); 
4046 bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat 
&format 
) 
4048     return m_clientArea
->EnableDropTarget( format 
); 
4051 #endif // wxUSE_DRAG_AND_DROP 
4053 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn 
*col 
) 
4055     if (!wxDataViewCtrlBase::AppendColumn(col
)) 
4058     m_cols
.Append( col 
); 
4059     m_colsBestWidths
.push_back(0); 
4060     OnColumnsCountChanged(); 
4064 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn 
*col 
) 
4066     if (!wxDataViewCtrlBase::PrependColumn(col
)) 
4069     m_cols
.Insert( col 
); 
4070     m_colsBestWidths
.insert(m_colsBestWidths
.begin(), 0); 
4071     OnColumnsCountChanged(); 
4075 bool wxDataViewCtrl::InsertColumn( unsigned int pos
, wxDataViewColumn 
*col 
) 
4077     if (!wxDataViewCtrlBase::InsertColumn(pos
,col
)) 
4080     m_cols
.Insert( pos
, col 
); 
4081     m_colsBestWidths
.insert(m_colsBestWidths
.begin() + pos
, 0); 
4082     OnColumnsCountChanged(); 
4086 void wxDataViewCtrl::OnColumnChange(unsigned int idx
) 
4089         m_headerArea
->UpdateColumn(idx
); 
4091     m_clientArea
->UpdateDisplay(); 
4094 void wxDataViewCtrl::OnColumnsCountChanged() 
4097         m_headerArea
->SetColumnCount(GetColumnCount()); 
4099     m_clientArea
->UpdateDisplay(); 
4102 void wxDataViewCtrl::DoSetExpanderColumn() 
4104     m_clientArea
->UpdateDisplay(); 
4107 void wxDataViewCtrl::DoSetIndent() 
4109     m_clientArea
->UpdateDisplay(); 
4112 unsigned int wxDataViewCtrl::GetColumnCount() const 
4114     return m_cols
.GetCount(); 
4117 wxDataViewColumn
* wxDataViewCtrl::GetColumn( unsigned int idx 
) const 
4122 wxDataViewColumn 
*wxDataViewCtrl::GetColumnAt(unsigned int pos
) const 
4124     // columns can't be reordered if there is no header window which allows 
4126     const unsigned idx 
= m_headerArea 
? m_headerArea
->GetColumnsOrder()[pos
] 
4129     return GetColumn(idx
); 
4132 int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn 
*column
) const 
4134     const unsigned count 
= m_cols
.size(); 
4135     for ( unsigned n 
= 0; n 
< count
; n
++ ) 
4137         if ( m_cols
[n
] == column 
) 
4144 unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx
) const 
4146     if ( m_colsBestWidths
[idx
] != 0 ) 
4147         return m_colsBestWidths
[idx
]; 
4149     const int count 
= m_clientArea
->GetRowCount(); 
4150     wxDataViewColumn 
*column 
= GetColumn(idx
); 
4151     wxDataViewRenderer 
*renderer 
= 
4152         const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
4154     class MaxWidthCalculator
 
4157         MaxWidthCalculator(wxDataViewMainWindow 
*clientArea
, 
4158                            wxDataViewRenderer 
*renderer
, 
4159                            const wxDataViewModel 
*model
, 
4162               m_clientArea(clientArea
), 
4163               m_renderer(renderer
), 
4169         void UpdateWithWidth(int width
) 
4171             m_width 
= wxMax(m_width
, width
); 
4174         void UpdateWithRow(int row
) 
4176             wxDataViewItem item 
= m_clientArea
->GetItemByRow(row
); 
4177             m_renderer
->PrepareForItem(m_model
, item
, m_column
); 
4178             m_width 
= wxMax(m_width
, m_renderer
->GetSize().x
); 
4181         int GetMaxWidth() const { return m_width
; } 
4185         wxDataViewMainWindow 
*m_clientArea
; 
4186         wxDataViewRenderer 
*m_renderer
; 
4187         const wxDataViewModel 
*m_model
; 
4191     MaxWidthCalculator 
calculator(m_clientArea
, renderer
, 
4192                                   GetModel(), column
->GetModelColumn()); 
4196         int header_width 
= m_headerArea
->GetTextExtent(column
->GetTitle()).x
; 
4197         // Labels on native MSW header are indented on both sides 
4199             wxRendererNative::Get().GetHeaderButtonMargin(m_headerArea
); 
4200         calculator
.UpdateWithWidth(header_width
); 
4203     // The code below deserves some explanation. For very large controls, we 
4204     // simply can't afford to calculate sizes for all items, it takes too 
4205     // long. So the best we can do is to check the first and the last N/2 
4206     // items in the control for some sufficiently large N and calculate best 
4207     // sizes from that. That can result in the calculated best width being too 
4208     // small for some outliers, but it's better to get slightly imperfect 
4209     // result than to wait several seconds after every update. To avoid highly 
4210     // visible miscalculations, we also include all currently visible items 
4211     // no matter what.  Finally, the value of N is determined dynamically by 
4212     // measuring how much time we spent on the determining item widths so far. 
4215     int top_part_end 
= count
; 
4216     static const long CALC_TIMEOUT 
= 20/*ms*/; 
4217     // don't call wxStopWatch::Time() too often 
4218     static const unsigned CALC_CHECK_FREQ 
= 100; 
4221     // use some hard-coded limit, that's the best we can do without timer 
4222     int top_part_end 
= wxMin(500, count
); 
4223 #endif // wxUSE_STOPWATCH/!wxUSE_STOPWATCH 
4227     for ( row 
= 0; row 
< top_part_end
; row
++ ) 
4230         if ( row 
% CALC_CHECK_FREQ 
== CALC_CHECK_FREQ
-1 && 
4231              timer
.Time() > CALC_TIMEOUT 
) 
4233 #endif // wxUSE_STOPWATCH 
4234         calculator
.UpdateWithRow(row
); 
4237     // row is the first unmeasured item now; that's our value of N/2 
4243         // add bottom N/2 items now: 
4244         const int bottom_part_start 
= wxMax(row
, count 
- row
); 
4245         for ( row 
= bottom_part_start
; row 
< count
; row
++ ) 
4247             calculator
.UpdateWithRow(row
); 
4250         // finally, include currently visible items in the calculation: 
4251         const wxPoint origin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
4252         int first_visible 
= m_clientArea
->GetLineAt(origin
.y
); 
4253         int last_visible 
= m_clientArea
->GetLineAt(origin
.y 
+ GetClientSize().y
); 
4255         first_visible 
= wxMax(first_visible
, top_part_end
); 
4256         last_visible 
= wxMin(bottom_part_start
, last_visible
); 
4258         for ( row 
= first_visible
; row 
< last_visible
; row
++ ) 
4260             calculator
.UpdateWithRow(row
); 
4263         wxLogTrace("dataview", 
4264                    "determined best size from %d top, %d bottom plus %d more visible items out of %d total", 
4266                    count 
- bottom_part_start
, 
4267                    wxMax(0, last_visible 
- first_visible
), 
4271     int max_width 
= calculator
.GetMaxWidth(); 
4272     if ( max_width 
> 0 ) 
4273         max_width 
+= 2 * PADDING_RIGHTLEFT
; 
4275     const_cast<wxDataViewCtrl
*>(this)->m_colsBestWidths
[idx
] = max_width
; 
4279 void wxDataViewCtrl::ColumnMoved(wxDataViewColumn 
* WXUNUSED(col
), 
4280                                 unsigned int WXUNUSED(new_pos
)) 
4282     // do _not_ reorder m_cols elements here, they should always be in the 
4283     // order in which columns were added, we only display the columns in 
4285     m_clientArea
->UpdateDisplay(); 
4288 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn 
*column 
) 
4290     wxDataViewColumnList::compatibility_iterator ret 
= m_cols
.Find( column 
); 
4294     m_colsBestWidths
.erase(m_colsBestWidths
.begin() + GetColumnIndex(column
)); 
4296     OnColumnsCountChanged(); 
4301 bool wxDataViewCtrl::ClearColumns() 
4304     m_colsBestWidths
.clear(); 
4305     OnColumnsCountChanged(); 
4309 void wxDataViewCtrl::InvalidateColBestWidth(int idx
) 
4311     m_colsBestWidths
[idx
] = 0; 
4314         m_headerArea
->UpdateColumn(idx
); 
4317 void wxDataViewCtrl::InvalidateColBestWidths() 
4319     m_colsBestWidths
.clear(); 
4320     m_colsBestWidths
.resize(m_cols
.size()); 
4324         const unsigned cols 
= m_headerArea
->GetColumnCount(); 
4325         for ( unsigned i 
= 0; i 
< cols
; i
++ ) 
4326             m_headerArea
->UpdateColumn(i
); 
4330 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn 
*column 
) const 
4333     unsigned int len 
= GetColumnCount(); 
4334     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
4336         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
4343     // This returns the position in pixels which is not what we want. 
4346     unsigned int len 
= GetColumnCount(); 
4347     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
4349         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
4350         if (col
->IsHidden()) 
4352         ret 
+= col
->GetWidth(); 
4355             CalcScrolledPosition( ret
, dummy
, &ret
, &dummy 
); 
4363 wxDataViewColumn 
*wxDataViewCtrl::GetSortingColumn() const 
4365     return m_sortingColumnIdx 
== wxNOT_FOUND 
? NULL
 
4366                                             : GetColumn(m_sortingColumnIdx
); 
4369 wxDataViewItem 
wxDataViewCtrl::DoGetCurrentItem() const 
4371     return GetItemByRow(m_clientArea
->GetCurrentRow()); 
4374 void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem
& item
) 
4376     const int row 
= m_clientArea
->GetRowByItem(item
); 
4378     const unsigned oldCurrent 
= m_clientArea
->GetCurrentRow(); 
4379     if ( static_cast<unsigned>(row
) != oldCurrent 
) 
4381         m_clientArea
->ChangeCurrentRow(row
); 
4382         m_clientArea
->RefreshRow(oldCurrent
); 
4383         m_clientArea
->RefreshRow(row
); 
4387 // Selection code with wxDataViewItem as parameters 
4388 wxDataViewItem 
wxDataViewCtrl::GetSelection() const 
4390     return m_clientArea
->GetSelection(); 
4393 int wxDataViewCtrl::GetSelections( wxDataViewItemArray 
& sel 
) const 
4396     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
4397     int len 
= selection
.GetCount(); 
4398     for( int i 
= 0; i 
< len
; i 
++) 
4400         unsigned int row 
= selection
[i
]; 
4401         sel
.Add( m_clientArea
->GetItemByRow( row 
) ); 
4406 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray 
& sel 
) 
4408     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
4410     wxDataViewItem last_parent
; 
4412     int len 
= sel
.GetCount(); 
4413     for( int i 
= 0; i 
< len
; i 
++ ) 
4415         wxDataViewItem item 
= sel
[i
]; 
4416         wxDataViewItem parent 
= GetModel()->GetParent( item 
); 
4419             if (parent 
!= last_parent
) 
4420                 ExpandAncestors(item
); 
4423         last_parent 
= parent
; 
4424         int row 
= m_clientArea
->GetRowByItem( item 
); 
4426             selection
.Add( static_cast<unsigned int>(row
) ); 
4429     m_clientArea
->SetSelections( selection 
); 
4432 void wxDataViewCtrl::Select( const wxDataViewItem 
& item 
) 
4434     ExpandAncestors( item 
); 
4436     int row 
= m_clientArea
->GetRowByItem( item 
); 
4439         // Unselect all rows before select another in the single select mode 
4440         if (m_clientArea
->IsSingleSel()) 
4441             m_clientArea
->SelectAllRows(false); 
4443         m_clientArea
->SelectRow(row
, true); 
4445         // Also set focus to the selected item 
4446         m_clientArea
->ChangeCurrentRow( row 
); 
4450 void wxDataViewCtrl::Unselect( const wxDataViewItem 
& item 
) 
4452     int row 
= m_clientArea
->GetRowByItem( item 
); 
4454         m_clientArea
->SelectRow(row
, false); 
4457 bool wxDataViewCtrl::IsSelected( const wxDataViewItem 
& item 
) const 
4459     int row 
= m_clientArea
->GetRowByItem( item 
); 
4462         return m_clientArea
->IsRowSelected(row
); 
4467 // Selection code with row number as parameter 
4468 int wxDataViewCtrl::GetSelections( wxArrayInt 
& sel 
) const 
4471     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
4472     int len 
= selection
.GetCount(); 
4473     for( int i 
= 0; i 
< len
; i 
++) 
4475         unsigned int row 
= selection
[i
]; 
4481 void wxDataViewCtrl::SetSelections( const wxArrayInt 
& sel 
) 
4483     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
4484     int len 
= sel
.GetCount(); 
4485     for( int i 
= 0; i 
< len
; i 
++ ) 
4489             selection
.Add( static_cast<unsigned int>(row
) ); 
4491     m_clientArea
->SetSelections( selection 
); 
4494 void wxDataViewCtrl::Select( int row 
) 
4498         if (m_clientArea
->IsSingleSel()) 
4499             m_clientArea
->SelectAllRows(false); 
4500         m_clientArea
->SelectRow( row
, true ); 
4504 void wxDataViewCtrl::Unselect( int row 
) 
4507         m_clientArea
->SelectRow(row
, false); 
4510 bool wxDataViewCtrl::IsSelected( int row 
) const 
4513         return m_clientArea
->IsRowSelected(row
); 
4517 void wxDataViewCtrl::SelectRange( int from
, int to 
) 
4520     for( int i 
= from
; i 
< to
; i 
++ ) 
4522     m_clientArea
->Select(sel
); 
4525 void wxDataViewCtrl::UnselectRange( int from
, int to 
) 
4527     wxDataViewSelection sel 
= m_clientArea
->GetSelections(); 
4528     for( int i 
= from
; i 
< to
; i 
++ ) 
4529         if( sel
.Index( i 
) != wxNOT_FOUND 
) 
4531     m_clientArea
->SetSelections(sel
); 
4534 void wxDataViewCtrl::SelectAll() 
4536     m_clientArea
->SelectAllRows(true); 
4539 void wxDataViewCtrl::UnselectAll() 
4541     m_clientArea
->SelectAllRows(false); 
4544 void wxDataViewCtrl::EnsureVisible( int row
, int column 
) 
4548     if( row 
> (int) m_clientArea
->GetRowCount() ) 
4549         row 
= m_clientArea
->GetRowCount(); 
4551     int first 
= m_clientArea
->GetFirstVisibleRow(); 
4552     int last 
= m_clientArea
->GetLastVisibleRow(); 
4554         m_clientArea
->ScrollTo( row
, column 
); 
4555     else if( row 
> last 
) 
4556         m_clientArea
->ScrollTo( row 
- last 
+ first
, column 
); 
4558         m_clientArea
->ScrollTo( first
, column 
); 
4561 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem 
& item
, const wxDataViewColumn 
* column 
) 
4563     ExpandAncestors( item 
); 
4565     m_clientArea
->RecalculateDisplay(); 
4567     int row 
= m_clientArea
->GetRowByItem(item
); 
4570         if( column 
== NULL 
) 
4571             EnsureVisible(row
, -1); 
4573             EnsureVisible( row
, GetColumnIndex(column
) ); 
4578 void wxDataViewCtrl::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
4579                               wxDataViewColumn
* &column 
) const 
4581     m_clientArea
->HitTest(point
, item
, column
); 
4584 wxRect 
wxDataViewCtrl::GetItemRect( const wxDataViewItem 
& item
, 
4585                                     const wxDataViewColumn
* column 
) const 
4587     return m_clientArea
->GetItemRect(item
, column
); 
4590 wxDataViewItem 
wxDataViewCtrl::GetItemByRow( unsigned int row 
) const 
4592     return m_clientArea
->GetItemByRow( row 
); 
4595 int wxDataViewCtrl::GetRowByItem( const wxDataViewItem 
& item 
) const 
4597     return m_clientArea
->GetRowByItem( item 
); 
4600 void wxDataViewCtrl::Expand( const wxDataViewItem 
& item 
) 
4602     ExpandAncestors( item 
); 
4604     int row 
= m_clientArea
->GetRowByItem( item 
); 
4606         m_clientArea
->Expand(row
); 
4609 void wxDataViewCtrl::Collapse( const wxDataViewItem 
& item 
) 
4611     int row 
= m_clientArea
->GetRowByItem( item 
); 
4613         m_clientArea
->Collapse(row
); 
4616 bool wxDataViewCtrl::IsExpanded( const wxDataViewItem 
& item 
) const 
4618     int row 
= m_clientArea
->GetRowByItem( item 
); 
4620         return m_clientArea
->IsExpanded(row
); 
4624 void wxDataViewCtrl::StartEditor( const wxDataViewItem 
& item
, unsigned int column 
) 
4626     wxDataViewColumn
* col 
= GetColumn( column 
); 
4630     wxRect itemRect 
= GetItemRect(item
, col
); 
4631     wxDataViewRenderer
* renderer 
= col
->GetRenderer(); 
4632     if (renderer
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) 
4633         renderer
->StartEditing(item
, itemRect
); 
4636 #endif // !wxUSE_GENERICDATAVIEWCTRL 
4638 #endif // wxUSE_DATAVIEWCTRL