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
; 
1609     // Get the parent of DataViewCtrl 
1610     wxWindow 
*parent 
= GetParent()->GetParent(); 
1611     wxDataViewEvent 
cache_event(wxEVT_COMMAND_DATAVIEW_CACHE_HINT
, parent
->GetId()); 
1612     cache_event
.SetEventObject(GetParent()); 
1613     cache_event
.SetCache(item_start
, item_last 
- 1); 
1614     parent
->ProcessWindowEvent(cache_event
); 
1616     // compute which columns needs to be redrawn 
1617     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1620         // we assume that we have at least one column below and painting an 
1621         // empty control is unnecessary anyhow 
1625     unsigned int col_start 
= 0; 
1626     unsigned int x_start
; 
1627     for (x_start 
= 0; col_start 
< cols
; col_start
++) 
1629         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_start
); 
1630         if (col
->IsHidden()) 
1631             continue;      // skip it! 
1633         unsigned int w 
= col
->GetWidth(); 
1634         if (x_start
+w 
>= (unsigned int)update
.x
) 
1640     unsigned int col_last 
= col_start
; 
1641     unsigned int x_last 
= x_start
; 
1642     for (; col_last 
< cols
; col_last
++) 
1644         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_last
); 
1645         if (col
->IsHidden()) 
1646             continue;      // skip it! 
1648         if (x_last 
> (unsigned int)update
.GetRight()) 
1651         x_last 
+= col
->GetWidth(); 
1654     // Draw horizontal rules if required 
1655     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
1657         dc
.SetPen(m_penRule
); 
1658         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1660         for (unsigned int i 
= item_start
; i 
<= item_last
; i
++) 
1662             int y 
= GetLineStart( i 
); 
1663             dc
.DrawLine(x_start
, y
, x_last
, y
); 
1667     // Draw vertical rules if required 
1668     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
1670         dc
.SetPen(m_penRule
); 
1671         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1673         // NB: Vertical rules are drawn in the last pixel of a column so that 
1674         //     they align perfectly with native MSW wxHeaderCtrl as well as for 
1675         //     consistency with MSW native list control. There's no vertical 
1676         //     rule at the most-left side of the control. 
1678         int x 
= x_start 
- 1; 
1679         for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1681             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(i
); 
1682             if (col
->IsHidden()) 
1683                 continue;       // skip it 
1685             x 
+= col
->GetWidth(); 
1687             dc
.DrawLine(x
, GetLineStart( item_start 
), 
1688                         x
, GetLineStart( item_last 
) ); 
1692     // redraw the background for the items which are selected/current 
1693     for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1695         bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1696         if (selected 
|| item 
== m_currentRow
) 
1698             int flags 
= selected 
? (int)wxCONTROL_SELECTED 
: 0; 
1699             if (item 
== m_currentRow
) 
1700                 flags 
|= wxCONTROL_CURRENT
; 
1702                 flags 
|= wxCONTROL_FOCUSED
; 
1704             wxRect 
rect( x_start
, GetLineStart( item 
), 
1705                          x_last 
- x_start
, GetLineHeight( item 
) ); 
1706             wxRendererNative::Get().DrawItemSelectionRect
 
1716 #if wxUSE_DRAG_AND_DROP 
1719         wxRect 
rect( x_start
, GetLineStart( m_dropHintLine 
), 
1720                      x_last 
- x_start
, GetLineHeight( m_dropHintLine 
) ); 
1721         dc
.SetPen( *wxBLACK_PEN 
); 
1722         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1723         dc
.DrawRectangle( rect 
); 
1725 #endif // wxUSE_DRAG_AND_DROP 
1727     wxDataViewColumn 
*expander 
= GetOwner()->GetExpanderColumn(); 
1730         // TODO-RTL: last column for RTL support 
1731         expander 
= GetOwner()->GetColumnAt( 0 ); 
1732         GetOwner()->SetExpanderColumn(expander
); 
1735     // redraw all cells for all rows which must be repainted and all columns 
1737     cell_rect
.x 
= x_start
; 
1738     for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1740         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt( i 
); 
1741         wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
1742         cell_rect
.width 
= col
->GetWidth(); 
1744         if ( col
->IsHidden() || cell_rect
.width 
<= 0 ) 
1745             continue;       // skip it! 
1747         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1749             // get the cell value and set it into the renderer 
1750             wxDataViewTreeNode 
*node 
= NULL
; 
1751             wxDataViewItem dataitem
; 
1753             if (!IsVirtualList()) 
1755                 node 
= GetTreeNodeByRow(item
); 
1759                 dataitem 
= node
->GetItem(); 
1761                 if ((i 
> 0) && model
->IsContainer(dataitem
) && 
1762                     !model
->HasContainerColumns(dataitem
)) 
1767                 dataitem 
= wxDataViewItem( wxUIntToPtr(item
+1) ); 
1770             cell
->PrepareForItem(model
, dataitem
, col
->GetModelColumn()); 
1773             cell_rect
.y 
= GetLineStart( item 
); 
1774             cell_rect
.height 
= GetLineHeight( item 
); 
1776             // deal with the expander 
1778             if ((!IsList()) && (col 
== expander
)) 
1780                 // Calculate the indent first 
1781                 indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
1783                 // we reserve m_lineHeight of horizontal space for the expander 
1784                 // but leave EXPANDER_MARGIN around the expander itself 
1785                 int exp_x 
= cell_rect
.x 
+ indent 
+ EXPANDER_MARGIN
; 
1787                 indent 
+= m_lineHeight
; 
1789                 // draw expander if needed and visible 
1790                 if ( node
->HasChildren() && exp_x 
< cell_rect
.GetRight() ) 
1792                     dc
.SetPen( m_penExpander 
); 
1793                     dc
.SetBrush( wxNullBrush 
); 
1795                     int exp_size 
= m_lineHeight 
- 2*EXPANDER_MARGIN
; 
1796                     int exp_y 
= cell_rect
.y 
+ (cell_rect
.height 
- exp_size
)/2 
1797                                    + EXPANDER_MARGIN 
- EXPANDER_OFFSET
; 
1799                     const wxRect 
rect(exp_x
, exp_y
, exp_size
, exp_size
); 
1802                     if ( m_underMouse 
== node 
) 
1803                         flag 
|= wxCONTROL_CURRENT
; 
1804                     if ( node
->IsOpen() ) 
1805                         flag 
|= wxCONTROL_EXPANDED
; 
1807                     // ensure that we don't overflow the cell (which might 
1808                     // happen if the column is very narrow) 
1809                     wxDCClipper 
clip(dc
, cell_rect
); 
1811                     wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
); 
1814                 // force the expander column to left-center align 
1815                 cell
->SetAlignment( wxALIGN_CENTER_VERTICAL 
); 
1817             if (node 
&& !node
->HasChildren()) 
1819                 // Yes, if the node does not have any child, it must be a leaf which 
1820                 // mean that it is a temporarily created by GetTreeNodeByRow 
1824             wxRect item_rect 
= cell_rect
; 
1825             item_rect
.Deflate(PADDING_RIGHTLEFT
, 0); 
1827             // account for the tree indent (harmless if we're not indented) 
1828             item_rect
.x 
+= indent
; 
1829             item_rect
.width 
-= indent
; 
1831             if ( item_rect
.width 
<= 0 ) 
1835             if (m_hasFocus 
&& (m_selection
.Index(item
) != wxNOT_FOUND
)) 
1836                 state 
|= wxDATAVIEW_CELL_SELECTED
; 
1838             // TODO: it would be much more efficient to create a clipping 
1839             //       region for the entire column being rendered (in the OnPaint 
1840             //       of wxDataViewMainWindow) instead of a single clip region for 
1841             //       each cell. However it would mean that each renderer should 
1842             //       respect the given wxRect's top & bottom coords, eventually 
1843             //       violating only the left & right coords - however the user can 
1844             //       make its own renderer and thus we cannot be sure of that. 
1845             wxDCClipper 
clip(dc
, item_rect
); 
1847             cell
->WXCallRender(item_rect
, &dc
, state
); 
1850         cell_rect
.x 
+= cell_rect
.width
; 
1854 void wxDataViewMainWindow::OnRenameTimer() 
1856     // We have to call this here because changes may just have 
1857     // been made and no screen update taken place. 
1860         // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead 
1861         //       (needs to be tested!) 
1865     wxDataViewItem item 
= GetItemByRow( m_currentRow 
); 
1867     wxRect labelRect 
= GetItemRect(item
, m_currentCol
); 
1869     m_currentCol
->GetRenderer()->StartEditing( item
, labelRect 
); 
1872 //----------------------------------------------------------------------------- 
1873 // Helper class for do operation on the tree node 
1874 //----------------------------------------------------------------------------- 
1879     virtual ~DoJob() { } 
1881     // The return value control how the tree-walker tranverse the tree 
1882     // 0: Job done, stop tranverse and return 
1883     // 1: Ignore the current node's subtree and continue 
1884     // 2: Job not done, continue 
1885     enum  { OK 
= 0 , IGR 
= 1, CONT 
= 2 }; 
1886     virtual int operator() ( wxDataViewTreeNode 
* node 
) = 0; 
1887     virtual int operator() ( void * n 
) = 0; 
1890 bool Walker( wxDataViewTreeNode 
* node
, DoJob 
& func 
) 
1895     switch( func( node 
) ) 
1906     const wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
1907     const wxDataViewTreeLeaves
& leaves 
= node
->GetChildren(); 
1909     int len_nodes 
= nodes
.GetCount(); 
1910     int len 
= leaves
.GetCount(); 
1911     int i 
= 0, nodes_i 
= 0; 
1913     for(; i 
< len
; i 
++ ) 
1915         void * n 
= leaves
[i
]; 
1916         if( nodes_i 
< len_nodes 
&& n 
== nodes
[nodes_i
]->GetItem().GetID() ) 
1918             wxDataViewTreeNode 
* nd 
= nodes
[nodes_i
]; 
1921             if( Walker( nd 
, func 
) ) 
1940 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem 
& parent
, const wxDataViewItem 
& item
) 
1942     GetOwner()->InvalidateColBestWidths(); 
1944     if (IsVirtualList()) 
1946         wxDataViewVirtualListModel 
*list_model 
= 
1947             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
1948         m_count 
= list_model
->GetCount(); 
1955     wxDataViewTreeNode 
* node
; 
1956     node 
= FindNode(parent
); 
1961     node
->SetHasChildren( true ); 
1963     if( g_model
->IsContainer( item 
) ) 
1965         wxDataViewTreeNode 
* newnode 
= new wxDataViewTreeNode( node 
); 
1966         newnode
->SetItem(item
); 
1967         newnode
->SetHasChildren( true ); 
1968         node
->AddNode( newnode
); 
1971         node
->AddLeaf( item
.GetID() ); 
1973     node
->ChangeSubTreeCount(1); 
1981 static void DestroyTreeHelper( wxDataViewTreeNode 
* node
); 
1983 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem
& parent
, 
1984                                        const wxDataViewItem
& item
) 
1986     GetOwner()->InvalidateColBestWidths(); 
1988     if (IsVirtualList()) 
1990         wxDataViewVirtualListModel 
*list_model 
= 
1991             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
1992         m_count 
= list_model
->GetCount(); 
1994         if( m_currentRow 
> GetRowCount() ) 
1995             m_currentRow 
= m_count 
- 1; 
1997         // TODO: why empty the entire selection? 
1998         m_selection
.Empty(); 
2005     wxDataViewTreeNode 
* node 
= FindNode(parent
); 
2007     // Notice that it is possible that the item being deleted is not in the 
2008     // tree at all, for example we could be deleting a never shown (because 
2009     // collapsed) item in a tree model. So it's not an error if we don't know 
2010     // about this item, just return without doing anything then. 
2011     if ( !node 
|| node
->GetChildren().Index(item
.GetID()) == wxNOT_FOUND 
) 
2015     node
->GetChildren().Remove( item
.GetID() ); 
2016     // Manipolate selection 
2017     if( m_selection
.GetCount() > 1 ) 
2019         m_selection
.Empty(); 
2021     bool isContainer 
= false; 
2022     wxDataViewTreeNodes nds 
= node
->GetNodes(); 
2023     for (size_t i 
= 0; i 
< nds
.GetCount(); i 
++) 
2025         if (nds
[i
]->GetItem() == item
) 
2033         wxDataViewTreeNode 
* n 
= NULL
; 
2034         wxDataViewTreeNodes nodes 
= node
->GetNodes(); 
2035         int len 
= nodes
.GetCount(); 
2036         for( int i 
= 0; i 
< len
; i 
++) 
2038             if( nodes
[i
]->GetItem() == item 
) 
2045         wxCHECK_MSG( n 
!= NULL
, false, "item not found" ); 
2047         node
->GetNodes().Remove( n 
); 
2048         sub 
-= n
->GetSubTreeCount(); 
2049         ::DestroyTreeHelper(n
); 
2051     // Make the row number invalid and get a new valid one when user call GetRowCount 
2053     node
->ChangeSubTreeCount(sub
); 
2055     // Change the current row to the last row if the current exceed the max row number 
2056     if( m_currentRow 
> GetRowCount() ) 
2057         m_currentRow 
= m_count 
- 1; 
2064 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem 
& item
) 
2066     GetOwner()->InvalidateColBestWidths(); 
2072     wxWindow 
*parent 
= GetParent(); 
2073     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2074     le
.SetEventObject(parent
); 
2075     le
.SetModel(GetOwner()->GetModel()); 
2077     parent
->GetEventHandler()->ProcessEvent(le
); 
2082 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem 
& item
, unsigned int model_column 
) 
2084     int view_column 
= -1; 
2085     unsigned int n_col 
= m_owner
->GetColumnCount(); 
2086     for (unsigned i 
= 0; i 
< n_col
; i
++) 
2088         wxDataViewColumn 
*column 
= m_owner
->GetColumn( i 
); 
2089         if (column
->GetModelColumn() == model_column
) 
2091             view_column 
= (int) i
; 
2095     if (view_column 
== -1) 
2098     GetOwner()->InvalidateColBestWidth(view_column
); 
2100     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 
2101 /*#define MAX_VIRTUAL_WIDTH       100000 
2103     wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight ); 
2104     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); 
2105     Refresh( true, &rect ); 
2113     wxWindow 
*parent 
= GetParent(); 
2114     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2115     le
.SetEventObject(parent
); 
2116     le
.SetModel(GetOwner()->GetModel()); 
2118     le
.SetColumn(view_column
); 
2119     le
.SetDataViewColumn(GetOwner()->GetColumn(view_column
)); 
2120     parent
->GetEventHandler()->ProcessEvent(le
); 
2125 bool wxDataViewMainWindow::Cleared() 
2127     GetOwner()->InvalidateColBestWidths(); 
2130     m_selection
.Clear(); 
2133     BuildTree( GetOwner()->GetModel() ); 
2140 void wxDataViewMainWindow::UpdateDisplay() 
2143     m_underMouse 
= NULL
; 
2146 void wxDataViewMainWindow::OnInternalIdle() 
2148     wxWindow::OnInternalIdle(); 
2152         RecalculateDisplay(); 
2157 void wxDataViewMainWindow::RecalculateDisplay() 
2159     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2166     int width 
= GetEndOfLastCol(); 
2167     int height 
= GetLineStart( GetRowCount() ); 
2169     SetVirtualSize( width
, height 
); 
2170     GetOwner()->SetScrollRate( 10, m_lineHeight 
); 
2175 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
2177     m_underMouse 
= NULL
; 
2179     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
2181     if (GetOwner()->m_headerArea
) 
2182         GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 ); 
2185 void wxDataViewMainWindow::ScrollTo( int rows
, int column 
) 
2187     m_underMouse 
= NULL
; 
2190     m_owner
->GetScrollPixelsPerUnit( &x
, &y 
); 
2191     int sy 
= GetLineStart( rows 
)/y
; 
2195         wxRect rect 
= GetClientRect(); 
2199         m_owner
->CalcUnscrolledPosition( rect
.x
, rect
.y
, &xx
, &yy 
); 
2200         for (x_start 
= 0; colnum 
< column
; colnum
++) 
2202             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(colnum
); 
2203             if (col
->IsHidden()) 
2204                 continue;      // skip it! 
2206             w 
= col
->GetWidth(); 
2210         int x_end 
= x_start 
+ w
; 
2211         xe 
= xx 
+ rect
.width
; 
2214             sx 
= ( xx 
+ x_end 
- xe 
)/x
; 
2221     m_owner
->Scroll( sx
, sy 
); 
2224 int wxDataViewMainWindow::GetCountPerPage() const 
2226     wxSize size 
= GetClientSize(); 
2227     return size
.y 
/ m_lineHeight
; 
2230 int wxDataViewMainWindow::GetEndOfLastCol() const 
2234     for (i 
= 0; i 
< GetOwner()->GetColumnCount(); i
++) 
2236         const wxDataViewColumn 
*c 
= 
2237             const_cast<wxDataViewCtrl
*>(GetOwner())->GetColumnAt( i 
); 
2240             width 
+= c
->GetWidth(); 
2245 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const 
2249     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2251     return GetLineAt( y 
); 
2254 unsigned int wxDataViewMainWindow::GetLastVisibleRow() 
2256     wxSize client_size 
= GetClientSize(); 
2257     m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
, 
2258                                     &client_size
.x
, &client_size
.y 
); 
2260     // we should deal with the pixel here 
2261     unsigned int row 
= GetLineAt(client_size
.y
) - 1; 
2263     return wxMin( GetRowCount()-1, row 
); 
2266 unsigned int wxDataViewMainWindow::GetRowCount() 
2268     if ( m_count 
== -1 ) 
2270         m_count 
= RecalculateCount(); 
2276 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row 
) 
2283 void wxDataViewMainWindow::SelectAllRows( bool on 
) 
2290         m_selection
.Clear(); 
2291         for (unsigned int i 
= 0; i 
< GetRowCount(); i
++) 
2292             m_selection
.Add( i 
); 
2297         unsigned int first_visible 
= GetFirstVisibleRow(); 
2298         unsigned int last_visible 
= GetLastVisibleRow(); 
2300         for (i 
= 0; i 
< m_selection
.GetCount(); i
++) 
2302             unsigned int row 
= m_selection
[i
]; 
2303             if ((row 
>= first_visible
) && (row 
<= last_visible
)) 
2306         m_selection
.Clear(); 
2310 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on 
) 
2312     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2316             m_selection
.Add( row 
); 
2324             m_selection
.Remove( row 
); 
2330 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on 
) 
2334         unsigned int tmp 
= from
; 
2340     for (i 
= from
; i 
<= to
; i
++) 
2342         if (m_selection
.Index( i 
) == wxNOT_FOUND
) 
2345                 m_selection
.Add( i 
); 
2350                 m_selection
.Remove( i 
); 
2353     RefreshRows( from
, to 
); 
2356 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections 
) 
2358     for (size_t i
=0; i 
< aSelections
.GetCount(); i
++) 
2360         int n 
= aSelections
[i
]; 
2362         m_selection
.Add( n 
); 
2367 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row 
) 
2369     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2370         m_selection
.Add( row 
); 
2372         m_selection
.Remove( row 
); 
2376 bool wxDataViewMainWindow::IsRowSelected( unsigned int row 
) 
2378     return (m_selection
.Index( row 
) != wxNOT_FOUND
); 
2381 void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem
& item
) 
2383     wxWindow 
*parent 
= GetParent(); 
2384     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED
, parent
->GetId()); 
2386     le
.SetEventObject(parent
); 
2387     le
.SetModel(GetOwner()->GetModel()); 
2390     parent
->GetEventHandler()->ProcessEvent(le
); 
2393 void wxDataViewMainWindow::RefreshRow( unsigned int row 
) 
2395     wxRect 
rect( 0, GetLineStart( row 
), GetEndOfLastCol(), GetLineHeight( row 
) ); 
2396     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2398     wxSize client_size 
= GetClientSize(); 
2399     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2400     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2401     if (intersect_rect
.width 
> 0) 
2402         Refresh( true, &intersect_rect 
); 
2405 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to 
) 
2409         unsigned int tmp 
= to
; 
2414     wxRect 
rect( 0, GetLineStart( from 
), GetEndOfLastCol(), GetLineStart( (to
-from
+1) ) ); 
2415     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2417     wxSize client_size 
= GetClientSize(); 
2418     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2419     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2420     if (intersect_rect
.width 
> 0) 
2421         Refresh( true, &intersect_rect 
); 
2424 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow 
) 
2426     wxSize client_size 
= GetClientSize(); 
2427     int start 
= GetLineStart( firstRow 
); 
2428     m_owner
->CalcScrolledPosition( start
, 0, &start
, NULL 
); 
2429     if (start 
> client_size
.y
) return; 
2431     wxRect 
rect( 0, start
, client_size
.x
, client_size
.y 
- start 
); 
2433     Refresh( true, &rect 
); 
2436 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
) 
2438     wxCHECK_RET( newCurrent 
< GetRowCount(), 
2439                 wxT("invalid item index in OnArrowChar()") ); 
2441     // if there is no selection, we cannot move it anywhere 
2442     if (!HasCurrentRow()) 
2445     unsigned int oldCurrent 
= m_currentRow
; 
2447     // in single selection we just ignore Shift as we can't select several 
2449     if ( event
.ShiftDown() && !IsSingleSel() ) 
2451         RefreshRow( oldCurrent 
); 
2453         ChangeCurrentRow( newCurrent 
); 
2455         // select all the items between the old and the new one 
2456         if ( oldCurrent 
> newCurrent 
) 
2458             newCurrent 
= oldCurrent
; 
2459             oldCurrent 
= m_currentRow
; 
2462         SelectRows( oldCurrent
, newCurrent
, true ); 
2463         if (oldCurrent
!=newCurrent
) 
2464             SendSelectionChangedEvent(GetItemByRow(m_selection
[0])); 
2468         RefreshRow( oldCurrent 
); 
2470         // all previously selected items are unselected unless ctrl is held 
2471         if ( !event
.ControlDown() ) 
2472             SelectAllRows(false); 
2474         ChangeCurrentRow( newCurrent 
); 
2476         if ( !event
.ControlDown() ) 
2478             SelectRow( m_currentRow
, true ); 
2479             SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
2482             RefreshRow( m_currentRow 
); 
2485     GetOwner()->EnsureVisible( m_currentRow
, -1 ); 
2488 wxRect 
wxDataViewMainWindow::GetLineRect( unsigned int row 
) const 
2492     rect
.y 
= GetLineStart( row 
); 
2493     rect
.width 
= GetEndOfLastCol(); 
2494     rect
.height 
= GetLineHeight( row 
); 
2499 int wxDataViewMainWindow::GetLineStart( unsigned int row 
) const 
2501     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2503     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2505         // TODO make more efficient 
2510         for (r 
= 0; r 
< row
; r
++) 
2512             const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(r
); 
2513             if (!node
) return start
; 
2515             wxDataViewItem item 
= node
->GetItem(); 
2517             if (node 
&& !node
->HasChildren()) 
2519                 // Yes, if the node does not have any child, it must be a leaf which 
2520                 // mean that it is a temporarily created by GetTreeNodeByRow 
2524             unsigned int cols 
= GetOwner()->GetColumnCount(); 
2526             int height 
= m_lineHeight
; 
2527             for (col 
= 0; col 
< cols
; col
++) 
2529                 const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2530                 if (column
->IsHidden()) 
2531                     continue;      // skip it! 
2534                     model
->IsContainer(item
) && 
2535                     !model
->HasContainerColumns(item
)) 
2536                     continue;      // skip it! 
2538                 wxDataViewRenderer 
*renderer 
= 
2539                     const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2540                 renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2542                 height 
= wxMax( height
, renderer
->GetSize().y 
); 
2552         return row 
* m_lineHeight
; 
2556 int wxDataViewMainWindow::GetLineAt( unsigned int y 
) const 
2558     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2560     // check for the easy case first 
2561     if ( !GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT
) ) 
2562         return y 
/ m_lineHeight
; 
2564     // TODO make more efficient 
2565     unsigned int row 
= 0; 
2566     unsigned int yy 
= 0; 
2569         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2572             // not really correct... 
2573             return row 
+ ((y
-yy
) / m_lineHeight
); 
2576         wxDataViewItem item 
= node
->GetItem(); 
2578         if (node 
&& !node
->HasChildren()) 
2580             // Yes, if the node does not have any child, it must be a leaf which 
2581             // mean that it is a temporarily created by GetTreeNodeByRow 
2585         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2587         int height 
= m_lineHeight
; 
2588         for (col 
= 0; col 
< cols
; col
++) 
2590             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2591             if (column
->IsHidden()) 
2592                 continue;      // skip it! 
2595                 model
->IsContainer(item
) && 
2596                 !model
->HasContainerColumns(item
)) 
2597                 continue;      // skip it! 
2599             wxDataViewRenderer 
*renderer 
= 
2600                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2601             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2603             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2614 int wxDataViewMainWindow::GetLineHeight( unsigned int row 
) const 
2616     const wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
2618     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2620         wxASSERT( !IsVirtualList() ); 
2622         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2623         // wxASSERT( node ); 
2624         if (!node
) return m_lineHeight
; 
2626         wxDataViewItem item 
= node
->GetItem(); 
2628         if (node 
&& !node
->HasChildren()) 
2630                 // Yes, if the node does not have any child, it must be a leaf which 
2631                 // mean that it is a temporarily created by GetTreeNodeByRow 
2635         int height 
= m_lineHeight
; 
2637         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2639         for (col 
= 0; col 
< cols
; col
++) 
2641             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2642             if (column
->IsHidden()) 
2643                 continue;      // skip it! 
2646                 model
->IsContainer(item
) && 
2647                 !model
->HasContainerColumns(item
)) 
2648                 continue;      // skip it! 
2650             wxDataViewRenderer 
*renderer 
= 
2651                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2652             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2654             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2661         return m_lineHeight
; 
2665 class RowToItemJob
: public DoJob
 
2668     RowToItemJob( unsigned int row 
, int current 
) 
2669         { this->row 
= row
; this->current 
= current
; } 
2670     virtual ~RowToItemJob() {} 
2672     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2675         if( current 
== static_cast<int>(row
)) 
2677             ret 
= node
->GetItem(); 
2681         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2683             current 
+= node
->GetSubTreeCount(); 
2688             // If the current has no child node, we can find the desired item of the row 
2690             // This if can speed up finding in some case, and will has a very good effect 
2691             // when it comes to list view 
2692             if( node
->GetNodes().GetCount() == 0) 
2694                 int index 
= static_cast<int>(row
) - current 
- 1; 
2695                 ret 
= node
->GetChildren().Item( index 
); 
2702     virtual int operator() ( void * n 
) 
2705         if( current 
== static_cast<int>(row
)) 
2707             ret 
= wxDataViewItem( n 
); 
2713     wxDataViewItem 
GetResult() const 
2722 wxDataViewItem 
wxDataViewMainWindow::GetItemByRow(unsigned int row
) const 
2724     if (IsVirtualList()) 
2726         return wxDataViewItem( wxUIntToPtr(row
+1) ); 
2730         RowToItemJob 
job( row
, -2 ); 
2731         Walker( m_root 
, job 
); 
2732         return job
.GetResult(); 
2736 class RowToTreeNodeJob
: public DoJob
 
2739     RowToTreeNodeJob( unsigned int row 
, int current
, wxDataViewTreeNode 
* node 
) 
2742         this->current 
= current
; 
2746     virtual ~RowToTreeNodeJob(){ } 
2748     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2751         if( current 
== static_cast<int>(row
)) 
2757         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2759             current 
+= node
->GetSubTreeCount(); 
2766             // If the current node has no children, we can find the desired item of the 
2767             // row number directly. 
2768             // This if can speed up finding in some case, and will have a very good 
2769             // effect for list views. 
2770             if( node
->GetNodes().GetCount() == 0) 
2772                 int index 
= static_cast<int>(row
) - current 
- 1; 
2773                 void * n 
= node
->GetChildren().Item( index 
); 
2774                 ret 
= new wxDataViewTreeNode( parent 
); 
2775                 ret
->SetItem( wxDataViewItem( n 
)); 
2776                 ret
->SetHasChildren(false); 
2783     virtual int operator() ( void * n 
) 
2786         if( current 
== static_cast<int>(row
)) 
2788             ret 
= new wxDataViewTreeNode( parent 
); 
2789             ret
->SetItem( wxDataViewItem( n 
)); 
2790             ret
->SetHasChildren(false); 
2797     wxDataViewTreeNode 
* GetResult() const 
2803     wxDataViewTreeNode 
* ret
; 
2804     wxDataViewTreeNode 
* parent
; 
2807 wxDataViewTreeNode 
* wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row
) const 
2809     wxASSERT( !IsVirtualList() ); 
2811     RowToTreeNodeJob 
job( row 
, -2, m_root 
); 
2812     Walker( m_root 
, job 
); 
2813     return job
.GetResult(); 
2816 wxDataViewEvent 
wxDataViewMainWindow::SendExpanderEvent( wxEventType type
, 
2817                                                          const wxDataViewItem 
& item 
) 
2819     wxWindow 
*parent 
= GetParent(); 
2820     wxDataViewEvent 
le(type
, parent
->GetId()); 
2822     le
.SetEventObject(parent
); 
2823     le
.SetModel(GetOwner()->GetModel()); 
2826     parent
->GetEventHandler()->ProcessEvent(le
); 
2830 bool wxDataViewMainWindow::IsExpanded( unsigned int row 
) const 
2835     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2839     if (!node
->HasChildren()) 
2845     return node
->IsOpen(); 
2848 bool wxDataViewMainWindow::HasChildren( unsigned int row 
) const 
2853     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2857     if (!node
->HasChildren()) 
2866 void wxDataViewMainWindow::Expand( unsigned int row 
) 
2871     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
2875     if (!node
->HasChildren()) 
2881             if (!node
->IsOpen()) 
2884                     SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING
, node
->GetItem()); 
2886                 // Check if the user prevent expanding 
2887                 if( e
.GetSkipped() ) 
2892                 // build the children of current node 
2893                 if( node
->GetChildrenNumber() == 0 ) 
2896                     ::BuildTreeHelper(GetOwner()->GetModel(), node
->GetItem(), node
); 
2899                 // By expanding the node all row indices that are currently in the selection list 
2900                 // and are greater than our node have become invalid. So we have to correct that now. 
2901                 const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
2902                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2904                     const unsigned testRow 
= m_selection
[i
]; 
2905                     // all rows above us are not affected, so skip them 
2909                     m_selection
[i
] += rowAdjustment
; 
2912                 if(m_currentRow 
> row
) 
2913                     ChangeCurrentRow(m_currentRow 
+ rowAdjustment
); 
2917                 // Send the expanded event 
2918                 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED
,node
->GetItem()); 
2922 void wxDataViewMainWindow::Collapse(unsigned int row
) 
2927     wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
2931     if (!node
->HasChildren()) 
2940                 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING
,node
->GetItem()); 
2941             if( e
.GetSkipped() ) 
2944             // Find out if there are selected items below the current node. 
2945             bool selectCollapsingRow 
= false; 
2946             const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
2947             unsigned maxRowToBeTested 
= row 
+ rowAdjustment
; 
2948             for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2950                 const unsigned testRow 
= m_selection
[i
]; 
2951                 if(testRow 
> row 
&& testRow 
<= maxRowToBeTested
) 
2953                     selectCollapsingRow 
= true; 
2954                     // get out as soon as we have found a node that is selected 
2961             // If the node to be closed has selected items the user won't see those any longer. 
2962             // We select the collapsing node in this case. 
2963             if(selectCollapsingRow
) 
2965                 SelectAllRows(false); 
2966                 ChangeCurrentRow(row
); 
2967                 SelectRow(row
, true); 
2968                 SendSelectionChangedEvent(GetItemByRow(row
)); 
2972                 // if there were no selected items below our node we still need to "fix" the 
2973                 // selection list to adjust for the changing of the row indices. 
2974                 // We actually do the opposite of what we are doing in Expand(). 
2975                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
2977                     const unsigned testRow 
= m_selection
[i
]; 
2978                     // all rows above us are not affected, so skip them 
2982                     m_selection
[i
] -= rowAdjustment
; 
2985                 // if the "current row" is being collapsed away we change it to the current row ;-) 
2986                 if(m_currentRow 
> row 
&& m_currentRow 
<= maxRowToBeTested
) 
2987                     ChangeCurrentRow(row
); 
2988                 else if(m_currentRow 
> row
) 
2989                     ChangeCurrentRow(m_currentRow 
- rowAdjustment
); 
2994             SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED
,node
->GetItem()); 
2998 wxDataViewTreeNode 
* wxDataViewMainWindow::FindNode( const wxDataViewItem 
& item 
) 
3000     const wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
3007     // Compose the parent-chain for the item we are looking for 
3008     wxVector
<wxDataViewItem
> parentChain
; 
3009     wxDataViewItem 
it( item 
); 
3012         parentChain
.push_back(it
); 
3013         it 
= model
->GetParent(it
); 
3016     // Find the item along the parent-chain. 
3017     // This algorithm is designed to speed up the node-finding method 
3018     wxDataViewTreeNode
* node 
= m_root
; 
3019     for( unsigned iter 
= parentChain
.size()-1; iter
>=0; --iter 
) 
3021         if( node
->HasChildren() ) 
3023             if( node
->GetChildrenNumber() == 0 ) 
3026                 ::BuildTreeHelper(model
, node
->GetItem(), node
); 
3029             const wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
3032             for (unsigned i 
= 0; i 
< nodes
.GetCount(); ++i
) 
3034                 wxDataViewTreeNode
* currentNode 
= nodes
[i
]; 
3035                 if (currentNode
->GetItem() == parentChain
[iter
]) 
3037                     if (currentNode
->GetItem() == item
) 
3054 void wxDataViewMainWindow::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
3055                                     wxDataViewColumn
* &column 
) 
3057     wxDataViewColumn 
*col 
= NULL
; 
3058     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3059     unsigned int colnum 
= 0; 
3061     m_owner
->CalcUnscrolledPosition( point
.x
, point
.y
, &x
, &y 
); 
3062     for (unsigned x_start 
= 0; colnum 
< cols
; colnum
++) 
3064         col 
= GetOwner()->GetColumnAt(colnum
); 
3065         if (col
->IsHidden()) 
3066             continue;      // skip it! 
3068         unsigned int w 
= col
->GetWidth(); 
3069         if (x_start
+w 
>= (unsigned int)x
) 
3076     item 
= GetItemByRow( GetLineAt( y 
) ); 
3079 wxRect 
wxDataViewMainWindow::GetItemRect( const wxDataViewItem 
& item
, 
3080                                           const wxDataViewColumn
* column 
) 
3085     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3086     // If column is null the loop will compute the combined width of all columns. 
3087     // Otherwise, it will compute the x position of the column we are looking for. 
3088     for (unsigned int i 
= 0; i 
< cols
; i
++) 
3090         wxDataViewColumn
* col 
= GetOwner()->GetColumnAt( i 
); 
3095         if (col
->IsHidden()) 
3096             continue;      // skip it! 
3098         xpos 
+= col
->GetWidth(); 
3099         width 
+= col
->GetWidth(); 
3104         // If we have a column, we need can get its width directly. 
3105         if(column
->IsHidden()) 
3108             width 
= column
->GetWidth(); 
3113         // If we have no column, we reset the x position back to zero. 
3117     // we have to take an expander column into account and compute its indentation 
3118     // to get the correct x position where the actual text is 
3120     int row 
= GetRowByItem(item
); 
3121     if (!IsList() && (column 
== 0 || GetOwner()->GetExpanderColumn() == column
) ) 
3123         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
3124         indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
3125         indent 
= indent 
+ m_lineHeight
; // use m_lineHeight as the width of the expander 
3127         if(!node
->HasChildren()) 
3131     wxRect 
itemRect( xpos 
+ indent
, 
3132                      GetLineStart( row 
), 
3134                      GetLineHeight( row 
) ); 
3136     GetOwner()->CalcScrolledPosition(  itemRect
.x
,  itemRect
.y
, 
3137                                       &itemRect
.x
, &itemRect
.y 
); 
3142 int wxDataViewMainWindow::RecalculateCount() 
3144     if (IsVirtualList()) 
3146         wxDataViewVirtualListModel 
*list_model 
= 
3147             (wxDataViewVirtualListModel
*) GetOwner()->GetModel(); 
3149         return list_model
->GetCount(); 
3153         return m_root
->GetSubTreeCount(); 
3157 class ItemToRowJob 
: public DoJob
 
3160     ItemToRowJob(const wxDataViewItem
& item_
, wxVector
<wxDataViewItem
>::reverse_iterator iter
) 
3167     // Maybe binary search will help to speed up this process 
3168     virtual int operator() ( wxDataViewTreeNode 
* node
) 
3171         if( node
->GetItem() == item 
) 
3176         if( node
->GetItem() == *m_iter 
) 
3183             ret 
+= node
->GetSubTreeCount(); 
3189     virtual int operator() ( void * n 
) 
3192         if( n 
== item
.GetID() ) 
3197     // the row number is begin from zero 
3198     int GetResult() const 
3202     wxVector
<wxDataViewItem
>::reverse_iterator m_iter
; 
3203     wxDataViewItem item
; 
3208 int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem 
& item
) const 
3210     const wxDataViewModel 
* model 
= GetOwner()->GetModel(); 
3214     if (IsVirtualList()) 
3216         return wxPtrToUInt( item
.GetID() ) -1; 
3223         // Compose the parent-chain of the item we are looking for 
3224         wxVector
<wxDataViewItem
> parentChain
; 
3225         wxDataViewItem 
it( item 
); 
3228             parentChain
.push_back(it
); 
3229             it 
= model
->GetParent(it
); 
3232         // add an 'invalid' item to represent our 'invisible' root node 
3233         parentChain
.push_back(wxDataViewItem()); 
3235         // the parent chain was created by adding the deepest parent first. 
3236         // so if we want to start at the root node, we have to iterate backwards through the vector 
3237         ItemToRowJob 
job( item
, parentChain
.rbegin() ); 
3238         Walker( m_root
, job 
); 
3239         return job
.GetResult(); 
3243 static void BuildTreeHelper( const wxDataViewModel 
* model
,  const wxDataViewItem 
& item
, 
3244                              wxDataViewTreeNode 
* node
) 
3246     if( !model
->IsContainer( item 
) ) 
3249     wxDataViewItemArray children
; 
3250     unsigned int num 
= model
->GetChildren( item
, children
); 
3252     unsigned int index 
= 0; 
3253     while( index 
< num 
) 
3255         if( model
->IsContainer( children
[index
] ) ) 
3257             wxDataViewTreeNode 
* n 
= new wxDataViewTreeNode( node 
); 
3258             n
->SetItem(children
[index
]); 
3259             n
->SetHasChildren( true ); 
3264             node
->AddLeaf( children
[index
].GetID() ); 
3268     node
->SetSubTreeCount( num 
); 
3269     wxDataViewTreeNode 
* n 
= node
->GetParent(); 
3271         n
->ChangeSubTreeCount(num
); 
3275 void wxDataViewMainWindow::BuildTree(wxDataViewModel 
* model
) 
3279     if (GetOwner()->GetModel()->IsVirtualListModel()) 
3285     m_root 
= new wxDataViewTreeNode( NULL 
); 
3286     m_root
->SetHasChildren(true); 
3288     // First we define a invalid item to fetch the top-level elements 
3289     wxDataViewItem item
; 
3291     BuildTreeHelper( model
, item
, m_root
); 
3295 static void DestroyTreeHelper( wxDataViewTreeNode 
* node 
) 
3297     if( node
->GetNodeNumber() != 0 ) 
3299         int len 
= node
->GetNodeNumber(); 
3300         wxDataViewTreeNodes
& nodes 
= node
->GetNodes(); 
3301         for (int i 
= 0; i 
< len
; i
++) 
3302             DestroyTreeHelper(nodes
[i
]); 
3307 void wxDataViewMainWindow::DestroyTree() 
3309     if (!IsVirtualList()) 
3311         ::DestroyTreeHelper(m_root
); 
3317 void wxDataViewMainWindow::OnChar( wxKeyEvent 
&event 
) 
3319     wxWindow 
* const parent 
= GetParent(); 
3321     // propagate the char event upwards 
3322     wxKeyEvent 
eventForParent(event
); 
3323     eventForParent
.SetEventObject(parent
); 
3324     if ( parent
->ProcessWindowEvent(eventForParent
) ) 
3327     if ( parent
->HandleAsNavigationKey(event
) ) 
3330     // no item -> nothing to do 
3331     if (!HasCurrentRow()) 
3337     // don't use m_linesPerPage directly as it might not be computed yet 
3338     const int pageSize 
= GetCountPerPage(); 
3339     wxCHECK_RET( pageSize
, wxT("should have non zero page size") ); 
3341     switch ( event
.GetKeyCode() ) 
3345                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, 
3347                 le
.SetItem( GetItemByRow(m_currentRow
) ); 
3348                 le
.SetEventObject(parent
); 
3349                 le
.SetModel(GetOwner()->GetModel()); 
3351                 parent
->GetEventHandler()->ProcessEvent(le
); 
3356             if ( m_currentRow 
> 0 ) 
3357                 OnArrowChar( m_currentRow 
- 1, event 
); 
3361             if ( m_currentRow 
< GetRowCount() - 1 ) 
3362                 OnArrowChar( m_currentRow 
+ 1, event 
); 
3364         // Add the process for tree expanding/collapsing 
3370             wxDataViewTreeNode
* node 
= GetTreeNodeByRow(m_currentRow
); 
3374             if (node
->HasChildren() && node
->IsOpen()) 
3376                 Collapse(m_currentRow
); 
3378             else    // if the node is already closed we move the selection to its parent 
3380                 wxDataViewTreeNode 
*parent_node 
= node
->GetParent(); 
3382                 if(!node
->HasChildren()) 
3387                     int parent 
= GetRowByItem( parent_node
->GetItem() ); 
3390                         unsigned int row 
= m_currentRow
; 
3391                         SelectRow( row
, false); 
3392                         SelectRow( parent
, true ); 
3393                         ChangeCurrentRow( parent 
); 
3394                         GetOwner()->EnsureVisible( parent
, -1 ); 
3395                         SendSelectionChangedEvent( parent_node
->GetItem() ); 
3403             if (!IsExpanded( m_currentRow 
)) 
3404                 Expand( m_currentRow 
); 
3407                 unsigned int row 
= m_currentRow
; 
3408                 SelectRow( row
, false ); 
3409                 SelectRow( row 
+ 1, true ); 
3410                 ChangeCurrentRow( row 
+ 1 ); 
3411                 GetOwner()->EnsureVisible( row 
+ 1, -1 ); 
3412                 SendSelectionChangedEvent( GetItemByRow(row
+1) ); 
3419                 OnArrowChar( GetRowCount() - 1, event 
); 
3424                 OnArrowChar( 0, event 
); 
3429                 int steps 
= pageSize 
- 1; 
3430                 int index 
= m_currentRow 
- steps
; 
3434                 OnArrowChar( index
, event 
); 
3440                 int steps 
= pageSize 
- 1; 
3441                 unsigned int index 
= m_currentRow 
+ steps
; 
3442                 unsigned int count 
= GetRowCount(); 
3443                 if ( index 
>= count 
) 
3446                 OnArrowChar( index
, event 
); 
3452                 if(m_selection
.size() == 1) 
3454                     // TODO: we need to revise that when we have a concept for a 'current column' 
3455                     GetOwner()->StartEditor(GetItemByRow(m_selection
[0]), 0); 
3465 void wxDataViewMainWindow::OnMouse( wxMouseEvent 
&event 
) 
3467     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
3469         // let the base handle mouse wheel events. 
3474     // set the focus to ourself if any of the mouse buttons are pressed 
3475     if(event
.ButtonDown() && !HasFocus()) 
3478     int x 
= event
.GetX(); 
3479     int y 
= event
.GetY(); 
3480     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3481     wxDataViewColumn 
*col 
= NULL
; 
3484     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3486     for (i 
= 0; i 
< cols
; i
++) 
3488         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt( i 
); 
3490             continue;      // skip it! 
3492         if (x 
< xpos 
+ c
->GetWidth()) 
3497         xpos 
+= c
->GetWidth(); 
3505     wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
3506     unsigned int current 
= GetLineAt( y 
); 
3507     if ((current 
>= GetRowCount()) || (x 
> GetEndOfLastCol())) 
3509         // Unselect all if below the last row ? 
3514     // Test whether the mouse is hovered on the tree item button 
3515     bool hoverOverExpander 
= false; 
3516     if ((!IsList()) && (GetOwner()->GetExpanderColumn() == col
)) 
3518         wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(current
); 
3519         if( node
!=NULL 
&& node
->HasChildren() ) 
3521             int indent 
= node
->GetIndentLevel(); 
3522             indent 
= GetOwner()->GetIndent()*indent
; 
3524             // we make the rectangle we are looking in a bit bigger than the actual 
3525             // visual expander so the user can hit that little thing reliably 
3526             wxRect 
rect( xpos 
+ indent
, 
3527                         GetLineStart( current 
) + (GetLineHeight(current
) - m_lineHeight
)/2, 
3528                         m_lineHeight
, m_lineHeight
); 
3529             if( rect
.Contains(x
, y
) ) 
3531                 // So the mouse is over the expander 
3532                 hoverOverExpander 
= true; 
3533                 if (m_underMouse 
&& m_underMouse 
!= node
) 
3535                     // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
3536                     RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
3538                 if (m_underMouse 
!= node
) 
3540                     // wxLogMessage("Do the row: %d", current); 
3541                     RefreshRow(current
); 
3543                 m_underMouse 
= node
; 
3546         if (node
!=NULL 
&& !node
->HasChildren()) 
3549     if (!hoverOverExpander
) 
3551         if (m_underMouse 
!= NULL
) 
3553             // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
3554             RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
3555             m_underMouse 
= NULL
; 
3559     wxDataViewModel 
*model 
= GetOwner()->GetModel(); 
3561 #if wxUSE_DRAG_AND_DROP 
3562     if (event
.Dragging()) 
3564         if (m_dragCount 
== 0) 
3566             // we have to report the raw, physical coords as we want to be 
3567             // able to call HitTest(event.m_pointDrag) from the user code to 
3568             // get the item being dragged 
3569             m_dragStart 
= event
.GetPosition(); 
3574         if (m_dragCount 
!= 3) 
3577         if (event
.LeftIsDown()) 
3579             m_owner
->CalcUnscrolledPosition( m_dragStart
.x
, m_dragStart
.y
, 
3580                                              &m_dragStart
.x
, &m_dragStart
.y 
); 
3581             unsigned int drag_item_row 
= GetLineAt( m_dragStart
.y 
); 
3582             wxDataViewItem item 
= GetItemByRow( drag_item_row 
); 
3584             // Notify cell about drag 
3585             wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG
, m_owner
->GetId() ); 
3586             event
.SetEventObject( m_owner 
); 
3587             event
.SetItem( item 
); 
3588             event
.SetModel( model 
); 
3589             if (!m_owner
->HandleWindowEvent( event 
)) 
3592             if (!event
.IsAllowed()) 
3595             wxDataObject 
*obj 
= event
.GetDataObject(); 
3599             wxDataViewDropSource 
drag( this, drag_item_row 
); 
3600             drag
.SetData( *obj 
); 
3601             /* wxDragResult res = */ drag
.DoDragDrop(); 
3610 #endif // wxUSE_DRAG_AND_DROP 
3612     bool simulateClick 
= false; 
3614     if (event
.ButtonDClick()) 
3616         m_renameTimer
->Stop(); 
3617         m_lastOnSame 
= false; 
3620     wxDataViewItem item 
= GetItemByRow(current
); 
3621     bool ignore_other_columns 
= 
3622         ((GetOwner()->GetExpanderColumn() != col
) && 
3623         (model
->IsContainer(item
)) && 
3624         (!model
->HasContainerColumns(item
))); 
3626     if (event
.LeftDClick()) 
3628         if(hoverOverExpander
) 
3630             // a double click on the expander will be converted into a "simulated" normal click 
3631             simulateClick 
= true; 
3633         else if ( current 
== m_lineLastClicked 
) 
3635             if ((!ignore_other_columns
) && (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
)) 
3637                 const unsigned colIdx 
= col
->GetModelColumn(); 
3639                 cell
->PrepareForItem(model
, item
, colIdx
); 
3641                 wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3642                                 col
->GetWidth(), GetLineHeight( current 
) ); 
3643                 cell
->WXOnActivate( cell_rect
, model
, item
, colIdx 
); 
3647                 wxWindow 
*parent 
= GetParent(); 
3648                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId()); 
3650                 le
.SetColumn( col
->GetModelColumn() ); 
3651                 le
.SetDataViewColumn( col 
); 
3652                 le
.SetEventObject(parent
); 
3653                 le
.SetModel(GetOwner()->GetModel()); 
3655                 parent
->GetEventHandler()->ProcessEvent(le
); 
3661             // The first click was on another item, so don't interpret this as 
3662             // a double click, but as a simple click instead 
3663             simulateClick 
= true; 
3667     if (event
.LeftUp() && !hoverOverExpander
) 
3669         if (m_lineSelectSingleOnUp 
!= (unsigned int)-1) 
3671             // select single line 
3672             SelectAllRows( false ); 
3673             SelectRow( m_lineSelectSingleOnUp
, true ); 
3674             SendSelectionChangedEvent( GetItemByRow(m_lineSelectSingleOnUp
) ); 
3677         // If the user click the expander, we do not do editing even if the column 
3678         // with expander are editable 
3679         if (m_lastOnSame 
&& !ignore_other_columns
) 
3681             if ((col 
== m_currentCol
) && (current 
== m_currentRow
) && 
3682                 (cell
->GetMode() & wxDATAVIEW_CELL_EDITABLE
) ) 
3684                 m_renameTimer
->Start( 100, true ); 
3688         m_lastOnSame 
= false; 
3689         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3691     else if(!event
.LeftUp()) 
3693         // This is necessary, because after a DnD operation in 
3694         // from and to ourself, the up event is swallowed by the 
3695         // DnD code. So on next non-up event (which means here and 
3696         // now) m_lineSelectSingleOnUp should be reset. 
3697         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
3700     if (event
.RightDown()) 
3702         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3703         m_lineLastClicked 
= current
; 
3705         // If the item is already selected, do not update the selection. 
3706         // Multi-selections should not be cleared if a selected item is clicked. 
3707         if (!IsRowSelected(current
)) 
3709             SelectAllRows(false); 
3710             ChangeCurrentRow(current
); 
3711             SelectRow(m_currentRow
,true); 
3712             SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3715     else if (event
.RightUp()) 
3718         model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3719         wxWindow 
*parent 
= GetParent(); 
3720         wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU
, parent
->GetId()); 
3722         le
.SetColumn( col
->GetModelColumn() ); 
3723         le
.SetDataViewColumn( col 
); 
3724         le
.SetEventObject(parent
); 
3725         le
.SetModel(GetOwner()->GetModel()); 
3727         parent
->GetEventHandler()->ProcessEvent(le
); 
3729     else if (event
.MiddleDown()) 
3733     if((event
.LeftDown() || simulateClick
) && hoverOverExpander
) 
3735         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(current
); 
3737         // hoverOverExpander being true tells us that our node must be 
3738         // valid and have children. 
3739         // So we don't need any extra checks. 
3740         if( node
->IsOpen() ) 
3745     else if ((event
.LeftDown() || simulateClick
) && !hoverOverExpander
) 
3747         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
3748         m_lineLastClicked 
= current
; 
3750         unsigned int oldCurrentRow 
= m_currentRow
; 
3751         bool oldWasSelected 
= IsRowSelected(m_currentRow
); 
3753         bool cmdModifierDown 
= event
.CmdDown(); 
3754         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
3756             if ( IsSingleSel() || !IsRowSelected(current
) ) 
3758                 SelectAllRows( false ); 
3759                 ChangeCurrentRow(current
); 
3760                 SelectRow(m_currentRow
,true); 
3761                 SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
3763             else // multi sel & current is highlighted & no mod keys 
3765                 m_lineSelectSingleOnUp 
= current
; 
3766                 ChangeCurrentRow(current
); // change focus 
3769         else // multi sel & either ctrl or shift is down 
3771             if (cmdModifierDown
) 
3773                 ChangeCurrentRow(current
); 
3774                 ReverseRowSelection(m_currentRow
); 
3775                 SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
3777             else if (event
.ShiftDown()) 
3779                 ChangeCurrentRow(current
); 
3781                 unsigned int lineFrom 
= oldCurrentRow
, 
3784                 if ( lineTo 
< lineFrom 
) 
3787                     lineFrom 
= m_currentRow
; 
3790                 SelectRows(lineFrom
, lineTo
, true); 
3791                 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) ); 
3793             else // !ctrl, !shift 
3795                 // test in the enclosing if should make it impossible 
3796                 wxFAIL_MSG( wxT("how did we get here?") ); 
3800         if (m_currentRow 
!= oldCurrentRow
) 
3801             RefreshRow( oldCurrentRow 
); 
3803         wxDataViewColumn 
*oldCurrentCol 
= m_currentCol
; 
3805         // Update selection here... 
3808         m_lastOnSame 
= !simulateClick 
&& ((col 
== oldCurrentCol
) && 
3809                         (current 
== oldCurrentRow
)) && oldWasSelected
; 
3811         // Call LeftClick after everything else as under GTK+ 
3812         if (cell
->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE
) 
3814             // notify cell about click 
3815             cell
->PrepareForItem(model
, item
, col
->GetModelColumn()); 
3817             wxRect 
cell_rect( xpos
, GetLineStart( current 
), 
3818                               col
->GetWidth(), GetLineHeight( current 
) ); 
3820             // Report position relative to the cell's custom area, i.e. 
3821             // no the entire space as given by the control but the one 
3822             // used by the renderer after calculation of alignment etc. 
3824             // adjust the rectangle ourselves to account for the alignment 
3825             wxRect rectItem 
= cell_rect
; 
3826             const int align 
= cell
->GetAlignment(); 
3827             if ( align 
!= wxDVR_DEFAULT_ALIGNMENT 
) 
3829                 const wxSize size 
= cell
->GetSize(); 
3831                 if ( size
.x 
>= 0 && size
.x 
< cell_rect
.width 
) 
3833                     if ( align 
& wxALIGN_CENTER_HORIZONTAL 
) 
3834                         rectItem
.x 
+= (cell_rect
.width 
- size
.x
)/2; 
3835                     else if ( align 
& wxALIGN_RIGHT 
) 
3836                         rectItem
.x 
+= cell_rect
.width 
- size
.x
; 
3837                     // else: wxALIGN_LEFT is the default 
3840                 if ( size
.y 
>= 0 && size
.y 
< cell_rect
.height 
) 
3842                     if ( align 
& wxALIGN_CENTER_VERTICAL 
) 
3843                         rectItem
.y 
+= (cell_rect
.height 
- size
.y
)/2; 
3844                     else if ( align 
& wxALIGN_BOTTOM 
) 
3845                         rectItem
.y 
+= cell_rect
.height 
- size
.y
; 
3846                     // else: wxALIGN_TOP is the default 
3850             wxPoint 
pos( event
.GetPosition() ); 
3851             pos
.x 
-= rectItem
.x
; 
3852             pos
.y 
-= rectItem
.y
; 
3854             m_owner
->CalcUnscrolledPosition( pos
.x
, pos
.y
, &pos
.x
, &pos
.y 
); 
3856              /* ignore ret */ cell
->WXOnLeftClick( pos
, cell_rect
, 
3857                               model
, item
, col
->GetModelColumn()); 
3862 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent 
&event 
) 
3866     if (HasCurrentRow()) 
3872 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
3876     if (HasCurrentRow()) 
3882 wxDataViewItem 
wxDataViewMainWindow::GetSelection() const 
3884     if( m_selection
.GetCount() != 1 ) 
3885         return wxDataViewItem(); 
3887     return GetItemByRow( m_selection
.Item(0)); 
3890 //----------------------------------------------------------------------------- 
3892 //----------------------------------------------------------------------------- 
3894 WX_DEFINE_LIST(wxDataViewColumnList
) 
3896 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3897 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
) 
3898     EVT_SIZE(wxDataViewCtrl::OnSize
) 
3901 wxDataViewCtrl::~wxDataViewCtrl() 
3904         GetModel()->RemoveNotifier( m_notifier 
); 
3907     m_colsBestWidths
.clear(); 
3910 void wxDataViewCtrl::Init() 
3912     m_cols
.DeleteContents(true); 
3915     // No sorting column at start 
3916     m_sortingColumnIdx 
= wxNOT_FOUND
; 
3918     m_headerArea 
= NULL
; 
3921 bool wxDataViewCtrl::Create(wxWindow 
*parent
, 
3926                             const wxValidator
& validator
, 
3927                             const wxString
& name
) 
3929 //    if ( (style & wxBORDER_MASK) == 0) 
3930 //        style |= wxBORDER_SUNKEN; 
3934     if (!wxControl::Create( parent
, id
, pos
, size
, 
3935                             style 
| wxScrolledWindowStyle
, validator
, name
)) 
3938     SetInitialSize(size
); 
3941     MacSetClipChildren( true ); 
3944     m_clientArea 
= new wxDataViewMainWindow( this, wxID_ANY 
); 
3946     // We use the cursor keys for moving the selection, not scrolling, so call 
3947     // this method to ensure wxScrollHelperEvtHandler doesn't catch all 
3948     // keyboard events forwarded to us from wxListMainWindow. 
3949     DisableKeyboardScrolling(); 
3951     if (HasFlag(wxDV_NO_HEADER
)) 
3952         m_headerArea 
= NULL
; 
3954         m_headerArea 
= new wxDataViewHeaderWindow(this); 
3956     SetTargetWindow( m_clientArea 
); 
3958     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
3960         sizer
->Add( m_headerArea
, 0, wxGROW 
); 
3961     sizer
->Add( m_clientArea
, 1, wxGROW 
); 
3967 wxBorder 
wxDataViewCtrl::GetDefaultBorder() const 
3969     return wxBORDER_THEME
; 
3973 WXLRESULT 
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
, 
3977     WXLRESULT rc 
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
3980     // we need to process arrows ourselves for scrolling 
3981     if ( nMsg 
== WM_GETDLGCODE 
) 
3983         rc 
|= DLGC_WANTARROWS
; 
3991 wxSize 
wxDataViewCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
3993     wxSize newsize 
= size
; 
3994     if (!HasFlag(wxDV_NO_HEADER
) && (m_headerArea
)) 
3995     newsize
.y 
-= m_headerArea
->GetSize().y
; 
4000 void wxDataViewCtrl::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
4002     // We need to override OnSize so that our scrolled 
4003     // window a) does call Layout() to use sizers for 
4004     // positioning the controls but b) does not query 
4005     // the sizer for their size and use that for setting 
4006     // the scrollable area as set that ourselves by 
4007     // calling SetScrollbar() further down. 
4014 void wxDataViewCtrl::SetFocus() 
4017         m_clientArea
->SetFocus(); 
4020 bool wxDataViewCtrl::AssociateModel( wxDataViewModel 
*model 
) 
4022     if (!wxDataViewCtrlBase::AssociateModel( model 
)) 
4025     m_notifier 
= new wxGenericDataViewModelNotifier( m_clientArea 
); 
4027     model
->AddNotifier( m_notifier 
); 
4029     m_clientArea
->DestroyTree(); 
4031     m_clientArea
->BuildTree(model
); 
4033     m_clientArea
->UpdateDisplay(); 
4038 #if wxUSE_DRAG_AND_DROP 
4040 bool wxDataViewCtrl::EnableDragSource( const wxDataFormat 
&format 
) 
4042     return m_clientArea
->EnableDragSource( format 
); 
4045 bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat 
&format 
) 
4047     return m_clientArea
->EnableDropTarget( format 
); 
4050 #endif // wxUSE_DRAG_AND_DROP 
4052 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn 
*col 
) 
4054     if (!wxDataViewCtrlBase::AppendColumn(col
)) 
4057     m_cols
.Append( col 
); 
4058     m_colsBestWidths
.push_back(0); 
4059     OnColumnsCountChanged(); 
4063 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn 
*col 
) 
4065     if (!wxDataViewCtrlBase::PrependColumn(col
)) 
4068     m_cols
.Insert( col 
); 
4069     m_colsBestWidths
.insert(m_colsBestWidths
.begin(), 0); 
4070     OnColumnsCountChanged(); 
4074 bool wxDataViewCtrl::InsertColumn( unsigned int pos
, wxDataViewColumn 
*col 
) 
4076     if (!wxDataViewCtrlBase::InsertColumn(pos
,col
)) 
4079     m_cols
.Insert( pos
, col 
); 
4080     m_colsBestWidths
.insert(m_colsBestWidths
.begin() + pos
, 0); 
4081     OnColumnsCountChanged(); 
4085 void wxDataViewCtrl::OnColumnChange(unsigned int idx
) 
4088         m_headerArea
->UpdateColumn(idx
); 
4090     m_clientArea
->UpdateDisplay(); 
4093 void wxDataViewCtrl::OnColumnsCountChanged() 
4096         m_headerArea
->SetColumnCount(GetColumnCount()); 
4098     m_clientArea
->UpdateDisplay(); 
4101 void wxDataViewCtrl::DoSetExpanderColumn() 
4103     m_clientArea
->UpdateDisplay(); 
4106 void wxDataViewCtrl::DoSetIndent() 
4108     m_clientArea
->UpdateDisplay(); 
4111 unsigned int wxDataViewCtrl::GetColumnCount() const 
4113     return m_cols
.GetCount(); 
4116 wxDataViewColumn
* wxDataViewCtrl::GetColumn( unsigned int idx 
) const 
4121 wxDataViewColumn 
*wxDataViewCtrl::GetColumnAt(unsigned int pos
) const 
4123     // columns can't be reordered if there is no header window which allows 
4125     const unsigned idx 
= m_headerArea 
? m_headerArea
->GetColumnsOrder()[pos
] 
4128     return GetColumn(idx
); 
4131 int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn 
*column
) const 
4133     const unsigned count 
= m_cols
.size(); 
4134     for ( unsigned n 
= 0; n 
< count
; n
++ ) 
4136         if ( m_cols
[n
] == column 
) 
4143 unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx
) const 
4145     if ( m_colsBestWidths
[idx
] != 0 ) 
4146         return m_colsBestWidths
[idx
]; 
4148     const int count 
= m_clientArea
->GetRowCount(); 
4149     wxDataViewColumn 
*column 
= GetColumn(idx
); 
4150     wxDataViewRenderer 
*renderer 
= 
4151         const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
4153     class MaxWidthCalculator
 
4156         MaxWidthCalculator(wxDataViewMainWindow 
*clientArea
, 
4157                            wxDataViewRenderer 
*renderer
, 
4158                            const wxDataViewModel 
*model
, 
4161               m_clientArea(clientArea
), 
4162               m_renderer(renderer
), 
4168         void UpdateWithWidth(int width
) 
4170             m_width 
= wxMax(m_width
, width
); 
4173         void UpdateWithRow(int row
) 
4175             wxDataViewItem item 
= m_clientArea
->GetItemByRow(row
); 
4176             m_renderer
->PrepareForItem(m_model
, item
, m_column
); 
4177             m_width 
= wxMax(m_width
, m_renderer
->GetSize().x
); 
4180         int GetMaxWidth() const { return m_width
; } 
4184         wxDataViewMainWindow 
*m_clientArea
; 
4185         wxDataViewRenderer 
*m_renderer
; 
4186         const wxDataViewModel 
*m_model
; 
4190     MaxWidthCalculator 
calculator(m_clientArea
, renderer
, 
4191                                   GetModel(), column
->GetModelColumn()); 
4195         int header_width 
= m_headerArea
->GetTextExtent(column
->GetTitle()).x
; 
4196         // Labels on native MSW header are indented on both sides 
4198             wxRendererNative::Get().GetHeaderButtonMargin(m_headerArea
); 
4199         calculator
.UpdateWithWidth(header_width
); 
4202     // The code below deserves some explanation. For very large controls, we 
4203     // simply can't afford to calculate sizes for all items, it takes too 
4204     // long. So the best we can do is to check the first and the last N/2 
4205     // items in the control for some sufficiently large N and calculate best 
4206     // sizes from that. That can result in the calculated best width being too 
4207     // small for some outliers, but it's better to get slightly imperfect 
4208     // result than to wait several seconds after every update. To avoid highly 
4209     // visible miscalculations, we also include all currently visible items 
4210     // no matter what.  Finally, the value of N is determined dynamically by 
4211     // measuring how much time we spent on the determining item widths so far. 
4214     int top_part_end 
= count
; 
4215     static const long CALC_TIMEOUT 
= 20/*ms*/; 
4216     // don't call wxStopWatch::Time() too often 
4217     static const unsigned CALC_CHECK_FREQ 
= 100; 
4220     // use some hard-coded limit, that's the best we can do without timer 
4221     int top_part_end 
= wxMin(500, count
); 
4222 #endif // wxUSE_STOPWATCH/!wxUSE_STOPWATCH 
4226     for ( row 
= 0; row 
< top_part_end
; row
++ ) 
4229         if ( row 
% CALC_CHECK_FREQ 
== CALC_CHECK_FREQ
-1 && 
4230              timer
.Time() > CALC_TIMEOUT 
) 
4232 #endif // wxUSE_STOPWATCH 
4233         calculator
.UpdateWithRow(row
); 
4236     // row is the first unmeasured item now; that's our value of N/2 
4242         // add bottom N/2 items now: 
4243         const int bottom_part_start 
= wxMax(row
, count 
- row
); 
4244         for ( row 
= bottom_part_start
; row 
< count
; row
++ ) 
4246             calculator
.UpdateWithRow(row
); 
4249         // finally, include currently visible items in the calculation: 
4250         const wxPoint origin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
4251         int first_visible 
= m_clientArea
->GetLineAt(origin
.y
); 
4252         int last_visible 
= m_clientArea
->GetLineAt(origin
.y 
+ GetClientSize().y
); 
4254         first_visible 
= wxMax(first_visible
, top_part_end
); 
4255         last_visible 
= wxMin(bottom_part_start
, last_visible
); 
4257         for ( row 
= first_visible
; row 
< last_visible
; row
++ ) 
4259             calculator
.UpdateWithRow(row
); 
4262         wxLogTrace("dataview", 
4263                    "determined best size from %d top, %d bottom plus %d more visible items out of %d total", 
4265                    count 
- bottom_part_start
, 
4266                    wxMax(0, last_visible 
- first_visible
), 
4270     int max_width 
= calculator
.GetMaxWidth(); 
4271     if ( max_width 
> 0 ) 
4272         max_width 
+= 2 * PADDING_RIGHTLEFT
; 
4274     const_cast<wxDataViewCtrl
*>(this)->m_colsBestWidths
[idx
] = max_width
; 
4278 void wxDataViewCtrl::ColumnMoved(wxDataViewColumn 
* WXUNUSED(col
), 
4279                                 unsigned int WXUNUSED(new_pos
)) 
4281     // do _not_ reorder m_cols elements here, they should always be in the 
4282     // order in which columns were added, we only display the columns in 
4284     m_clientArea
->UpdateDisplay(); 
4287 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn 
*column 
) 
4289     wxDataViewColumnList::compatibility_iterator ret 
= m_cols
.Find( column 
); 
4293     m_colsBestWidths
.erase(m_colsBestWidths
.begin() + GetColumnIndex(column
)); 
4295     OnColumnsCountChanged(); 
4300 bool wxDataViewCtrl::ClearColumns() 
4303     m_colsBestWidths
.clear(); 
4304     OnColumnsCountChanged(); 
4308 void wxDataViewCtrl::InvalidateColBestWidth(int idx
) 
4310     m_colsBestWidths
[idx
] = 0; 
4313         m_headerArea
->UpdateColumn(idx
); 
4316 void wxDataViewCtrl::InvalidateColBestWidths() 
4318     m_colsBestWidths
.clear(); 
4319     m_colsBestWidths
.resize(m_cols
.size()); 
4323         const unsigned cols 
= m_headerArea
->GetColumnCount(); 
4324         for ( unsigned i 
= 0; i 
< cols
; i
++ ) 
4325             m_headerArea
->UpdateColumn(i
); 
4329 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn 
*column 
) const 
4332     unsigned int len 
= GetColumnCount(); 
4333     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
4335         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
4342     // This returns the position in pixels which is not what we want. 
4345     unsigned int len 
= GetColumnCount(); 
4346     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
4348         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
4349         if (col
->IsHidden()) 
4351         ret 
+= col
->GetWidth(); 
4354             CalcScrolledPosition( ret
, dummy
, &ret
, &dummy 
); 
4362 wxDataViewColumn 
*wxDataViewCtrl::GetSortingColumn() const 
4364     return m_sortingColumnIdx 
== wxNOT_FOUND 
? NULL
 
4365                                             : GetColumn(m_sortingColumnIdx
); 
4368 wxDataViewItem 
wxDataViewCtrl::DoGetCurrentItem() const 
4370     return GetItemByRow(m_clientArea
->GetCurrentRow()); 
4373 void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem
& item
) 
4375     const int row 
= m_clientArea
->GetRowByItem(item
); 
4377     const unsigned oldCurrent 
= m_clientArea
->GetCurrentRow(); 
4378     if ( static_cast<unsigned>(row
) != oldCurrent 
) 
4380         m_clientArea
->ChangeCurrentRow(row
); 
4381         m_clientArea
->RefreshRow(oldCurrent
); 
4382         m_clientArea
->RefreshRow(row
); 
4386 // Selection code with wxDataViewItem as parameters 
4387 wxDataViewItem 
wxDataViewCtrl::GetSelection() const 
4389     return m_clientArea
->GetSelection(); 
4392 int wxDataViewCtrl::GetSelections( wxDataViewItemArray 
& sel 
) const 
4395     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
4396     int len 
= selection
.GetCount(); 
4397     for( int i 
= 0; i 
< len
; i 
++) 
4399         unsigned int row 
= selection
[i
]; 
4400         sel
.Add( m_clientArea
->GetItemByRow( row 
) ); 
4405 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray 
& sel 
) 
4407     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
4409     wxDataViewItem last_parent
; 
4411     int len 
= sel
.GetCount(); 
4412     for( int i 
= 0; i 
< len
; i 
++ ) 
4414         wxDataViewItem item 
= sel
[i
]; 
4415         wxDataViewItem parent 
= GetModel()->GetParent( item 
); 
4418             if (parent 
!= last_parent
) 
4419                 ExpandAncestors(item
); 
4422         last_parent 
= parent
; 
4423         int row 
= m_clientArea
->GetRowByItem( item 
); 
4425             selection
.Add( static_cast<unsigned int>(row
) ); 
4428     m_clientArea
->SetSelections( selection 
); 
4431 void wxDataViewCtrl::Select( const wxDataViewItem 
& item 
) 
4433     ExpandAncestors( item 
); 
4435     int row 
= m_clientArea
->GetRowByItem( item 
); 
4438         // Unselect all rows before select another in the single select mode 
4439         if (m_clientArea
->IsSingleSel()) 
4440             m_clientArea
->SelectAllRows(false); 
4442         m_clientArea
->SelectRow(row
, true); 
4444         // Also set focus to the selected item 
4445         m_clientArea
->ChangeCurrentRow( row 
); 
4449 void wxDataViewCtrl::Unselect( const wxDataViewItem 
& item 
) 
4451     int row 
= m_clientArea
->GetRowByItem( item 
); 
4453         m_clientArea
->SelectRow(row
, false); 
4456 bool wxDataViewCtrl::IsSelected( const wxDataViewItem 
& item 
) const 
4458     int row 
= m_clientArea
->GetRowByItem( item 
); 
4461         return m_clientArea
->IsRowSelected(row
); 
4466 // Selection code with row number as parameter 
4467 int wxDataViewCtrl::GetSelections( wxArrayInt 
& sel 
) const 
4470     wxDataViewSelection selection 
= m_clientArea
->GetSelections(); 
4471     int len 
= selection
.GetCount(); 
4472     for( int i 
= 0; i 
< len
; i 
++) 
4474         unsigned int row 
= selection
[i
]; 
4480 void wxDataViewCtrl::SetSelections( const wxArrayInt 
& sel 
) 
4482     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
4483     int len 
= sel
.GetCount(); 
4484     for( int i 
= 0; i 
< len
; i 
++ ) 
4488             selection
.Add( static_cast<unsigned int>(row
) ); 
4490     m_clientArea
->SetSelections( selection 
); 
4493 void wxDataViewCtrl::Select( int row 
) 
4497         if (m_clientArea
->IsSingleSel()) 
4498             m_clientArea
->SelectAllRows(false); 
4499         m_clientArea
->SelectRow( row
, true ); 
4503 void wxDataViewCtrl::Unselect( int row 
) 
4506         m_clientArea
->SelectRow(row
, false); 
4509 bool wxDataViewCtrl::IsSelected( int row 
) const 
4512         return m_clientArea
->IsRowSelected(row
); 
4516 void wxDataViewCtrl::SelectRange( int from
, int to 
) 
4519     for( int i 
= from
; i 
< to
; i 
++ ) 
4521     m_clientArea
->Select(sel
); 
4524 void wxDataViewCtrl::UnselectRange( int from
, int to 
) 
4526     wxDataViewSelection sel 
= m_clientArea
->GetSelections(); 
4527     for( int i 
= from
; i 
< to
; i 
++ ) 
4528         if( sel
.Index( i 
) != wxNOT_FOUND 
) 
4530     m_clientArea
->SetSelections(sel
); 
4533 void wxDataViewCtrl::SelectAll() 
4535     m_clientArea
->SelectAllRows(true); 
4538 void wxDataViewCtrl::UnselectAll() 
4540     m_clientArea
->SelectAllRows(false); 
4543 void wxDataViewCtrl::EnsureVisible( int row
, int column 
) 
4547     if( row 
> (int) m_clientArea
->GetRowCount() ) 
4548         row 
= m_clientArea
->GetRowCount(); 
4550     int first 
= m_clientArea
->GetFirstVisibleRow(); 
4551     int last 
= m_clientArea
->GetLastVisibleRow(); 
4553         m_clientArea
->ScrollTo( row
, column 
); 
4554     else if( row 
> last 
) 
4555         m_clientArea
->ScrollTo( row 
- last 
+ first
, column 
); 
4557         m_clientArea
->ScrollTo( first
, column 
); 
4560 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem 
& item
, const wxDataViewColumn 
* column 
) 
4562     ExpandAncestors( item 
); 
4564     m_clientArea
->RecalculateDisplay(); 
4566     int row 
= m_clientArea
->GetRowByItem(item
); 
4569         if( column 
== NULL 
) 
4570             EnsureVisible(row
, -1); 
4572             EnsureVisible( row
, GetColumnIndex(column
) ); 
4577 void wxDataViewCtrl::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
4578                               wxDataViewColumn
* &column 
) const 
4580     m_clientArea
->HitTest(point
, item
, column
); 
4583 wxRect 
wxDataViewCtrl::GetItemRect( const wxDataViewItem 
& item
, 
4584                                     const wxDataViewColumn
* column 
) const 
4586     return m_clientArea
->GetItemRect(item
, column
); 
4589 wxDataViewItem 
wxDataViewCtrl::GetItemByRow( unsigned int row 
) const 
4591     return m_clientArea
->GetItemByRow( row 
); 
4594 int wxDataViewCtrl::GetRowByItem( const wxDataViewItem 
& item 
) const 
4596     return m_clientArea
->GetRowByItem( item 
); 
4599 void wxDataViewCtrl::Expand( const wxDataViewItem 
& item 
) 
4601     ExpandAncestors( item 
); 
4603     int row 
= m_clientArea
->GetRowByItem( item 
); 
4605         m_clientArea
->Expand(row
); 
4608 void wxDataViewCtrl::Collapse( const wxDataViewItem 
& item 
) 
4610     int row 
= m_clientArea
->GetRowByItem( item 
); 
4612         m_clientArea
->Collapse(row
); 
4615 bool wxDataViewCtrl::IsExpanded( const wxDataViewItem 
& item 
) const 
4617     int row 
= m_clientArea
->GetRowByItem( item 
); 
4619         return m_clientArea
->IsExpanded(row
); 
4623 void wxDataViewCtrl::StartEditor( const wxDataViewItem 
& item
, unsigned int column 
) 
4625     wxDataViewColumn
* col 
= GetColumn( column 
); 
4629     wxRect itemRect 
= GetItemRect(item
, col
); 
4630     wxDataViewRenderer
* renderer 
= col
->GetRenderer(); 
4631     if (renderer
->GetMode() == wxDATAVIEW_CELL_EDITABLE
) 
4632         renderer
->StartEditing(item
, itemRect
); 
4635 #endif // !wxUSE_GENERICDATAVIEWCTRL 
4637 #endif // wxUSE_DATAVIEWCTRL