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/popupwin.h" 
  42 #include "wx/renderer.h" 
  43 #include "wx/dcbuffer.h" 
  46 #include "wx/listimpl.cpp" 
  47 #include "wx/imaglist.h" 
  48 #include "wx/headerctrl.h" 
  50 #include "wx/stopwatch.h" 
  51 #include "wx/weakref.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 // ---------------------------------------------------------------------------- 
  93 // Return the expander column or, if it is not set, the first column and also 
  94 // set it as the expander one for the future. 
  95 wxDataViewColumn
* GetExpanderColumnOrFirstOne(wxDataViewCtrl
* dataview
) 
  97     wxDataViewColumn
* expander 
= dataview
->GetExpanderColumn(); 
 100         // TODO-RTL: last column for RTL support 
 101         expander 
= dataview
->GetColumnAt( 0 ); 
 102         dataview
->SetExpanderColumn(expander
); 
 108 } // anonymous namespace 
 110 //----------------------------------------------------------------------------- 
 112 //----------------------------------------------------------------------------- 
 114 void wxDataViewColumn::Init(int width
, wxAlignment align
, int flags
) 
 121     m_sortAscending 
= true; 
 124 int wxDataViewColumn::GetWidth() const 
 128         case wxCOL_WIDTH_DEFAULT
: 
 129             return wxDVC_DEFAULT_WIDTH
; 
 131         case wxCOL_WIDTH_AUTOSIZE
: 
 132             wxCHECK_MSG( m_owner
, wxDVC_DEFAULT_WIDTH
, "no owner control" ); 
 133             return m_owner
->GetBestColumnWidth(m_owner
->GetColumnIndex(this)); 
 140 void wxDataViewColumn::UpdateDisplay() 
 144         int idx 
= m_owner
->GetColumnIndex( this ); 
 145         m_owner
->OnColumnChange( idx 
); 
 149 void wxDataViewColumn::SetSortOrder(bool ascending
) 
 154     // First unset the old sort column if any. 
 155     int oldSortKey 
= m_owner
->GetSortingColumnIndex(); 
 156     if ( oldSortKey 
!= wxNOT_FOUND 
) 
 158         m_owner
->GetColumn(oldSortKey
)->UnsetAsSortKey(); 
 161     // Now set this one as the new sort column. 
 162     const int idx 
= m_owner
->GetColumnIndex(this); 
 163     m_owner
->SetSortingColumnIndex(idx
); 
 166     m_sortAscending 
= ascending
; 
 168     // Call this directly instead of using UpdateDisplay() as we already have 
 169     // the column index, no need to look it up again. 
 170     m_owner
->OnColumnChange(idx
); 
 173 //----------------------------------------------------------------------------- 
 174 // wxDataViewHeaderWindow 
 175 //----------------------------------------------------------------------------- 
 177 class wxDataViewHeaderWindow 
: public wxHeaderCtrl
 
 180     wxDataViewHeaderWindow(wxDataViewCtrl 
*parent
) 
 181         : wxHeaderCtrl(parent
) 
 185     wxDataViewCtrl 
*GetOwner() const 
 186         { return static_cast<wxDataViewCtrl 
*>(GetParent()); } 
 189     // implement/override wxHeaderCtrl functions by forwarding them to the main 
 191     virtual const wxHeaderColumn
& GetColumn(unsigned int idx
) const 
 193         return *(GetOwner()->GetColumn(idx
)); 
 196     virtual bool UpdateColumnWidthToFit(unsigned int idx
, int widthTitle
) 
 198         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 200         int widthContents 
= owner
->GetBestColumnWidth(idx
); 
 201         owner
->GetColumn(idx
)->SetWidth(wxMax(widthTitle
, widthContents
)); 
 202         owner
->OnColumnChange(idx
); 
 208     bool SendEvent(wxEventType type
, unsigned int n
) 
 210         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 211         wxDataViewEvent 
event(type
, owner
->GetId()); 
 213         event
.SetEventObject(owner
); 
 215         event
.SetDataViewColumn(owner
->GetColumn(n
)); 
 216         event
.SetModel(owner
->GetModel()); 
 218         // for events created by wxDataViewHeaderWindow the 
 219         // row / value fields are not valid 
 220         return owner
->ProcessWindowEvent(event
); 
 223     void OnClick(wxHeaderCtrlEvent
& event
) 
 225         const unsigned idx 
= event
.GetColumn(); 
 227         if ( SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
, idx
) ) 
 230         // default handling for the column click is to sort by this column or 
 231         // toggle its sort order 
 232         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 233         wxDataViewColumn 
* const col 
= owner
->GetColumn(idx
); 
 234         if ( !col
->IsSortable() ) 
 236             // no default handling for non-sortable columns 
 241         if ( col
->IsSortKey() ) 
 243             // already using this column for sorting, just change the order 
 244             col
->ToggleSortOrder(); 
 246         else // not using this column for sorting yet 
 248             col
->SetSortOrder(true); 
 251         wxDataViewModel 
* const model 
= owner
->GetModel(); 
 255         owner
->OnColumnChange(idx
); 
 257         SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED
, idx
); 
 260     void OnRClick(wxHeaderCtrlEvent
& event
) 
 262         if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
, 
 267     void OnResize(wxHeaderCtrlEvent
& event
) 
 269         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 271         const unsigned col 
= event
.GetColumn(); 
 272         owner
->GetColumn(col
)->SetWidth(event
.GetWidth()); 
 273         GetOwner()->OnColumnChange(col
); 
 276     void OnEndReorder(wxHeaderCtrlEvent
& event
) 
 278         wxDataViewCtrl 
* const owner 
= GetOwner(); 
 279         owner
->ColumnMoved(owner
->GetColumn(event
.GetColumn()), 
 280                         event
.GetNewOrder()); 
 283     DECLARE_EVENT_TABLE() 
 284     wxDECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow
); 
 287 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow
, wxHeaderCtrl
) 
 288     EVT_HEADER_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnClick
) 
 289     EVT_HEADER_RIGHT_CLICK(wxID_ANY
, wxDataViewHeaderWindow::OnRClick
) 
 291     EVT_HEADER_RESIZING(wxID_ANY
, wxDataViewHeaderWindow::OnResize
) 
 292     EVT_HEADER_END_RESIZE(wxID_ANY
, wxDataViewHeaderWindow::OnResize
) 
 294     EVT_HEADER_END_REORDER(wxID_ANY
, wxDataViewHeaderWindow::OnEndReorder
) 
 297 //----------------------------------------------------------------------------- 
 298 // wxDataViewRenameTimer 
 299 //----------------------------------------------------------------------------- 
 301 class wxDataViewRenameTimer
: public wxTimer
 
 304     wxDataViewMainWindow 
*m_owner
; 
 307     wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
); 
 311 //----------------------------------------------------------------------------- 
 312 // wxDataViewTreeNode 
 313 //----------------------------------------------------------------------------- 
 315 class wxDataViewTreeNode
; 
 316 WX_DEFINE_ARRAY( wxDataViewTreeNode 
*, wxDataViewTreeNodes 
); 
 318 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, 
 319                                            wxDataViewTreeNode 
** node2
); 
 321 class wxDataViewTreeNode
 
 324     wxDataViewTreeNode(wxDataViewTreeNode 
*parent
, const wxDataViewItem
& item
) 
 331     ~wxDataViewTreeNode() 
 335             wxDataViewTreeNodes
& nodes 
= m_branchData
->children
; 
 336             for ( wxDataViewTreeNodes::iterator i 
= nodes
.begin(); 
 347     static wxDataViewTreeNode
* CreateRootNode() 
 349         wxDataViewTreeNode 
*n 
= new wxDataViewTreeNode(NULL
, wxDataViewItem()); 
 350         n
->SetHasChildren(true); 
 351         n
->m_branchData
->open 
= true; 
 355     wxDataViewTreeNode 
* GetParent() const { return m_parent
; } 
 357     const wxDataViewTreeNodes
& GetChildNodes() const 
 359         wxASSERT( m_branchData 
!= NULL 
); 
 360         return m_branchData
->children
; 
 363     void InsertChild(wxDataViewTreeNode 
*node
, unsigned index
) 
 366             m_branchData 
= new BranchNodeData
; 
 368         m_branchData
->children
.Insert(node
, index
); 
 370         // TODO: insert into sorted array directly in O(log n) instead of resorting in O(n log n) 
 372             m_branchData
->children
.Sort( &wxGenericTreeModelNodeCmp 
); 
 375     void RemoveChild(wxDataViewTreeNode 
*node
) 
 377         wxCHECK_RET( m_branchData 
!= NULL
, "leaf node doesn't have children" ); 
 378         m_branchData
->children
.Remove(node
); 
 381     // returns position of child node for given item in children list or wxNOT_FOUND 
 382     int FindChildByItem(const wxDataViewItem
& item
) const 
 387         const wxDataViewTreeNodes
& nodes 
= m_branchData
->children
; 
 388         const int len 
= nodes
.size(); 
 389         for ( int i 
= 0; i 
< len
; i
++ ) 
 391             if ( nodes
[i
]->m_item 
== item 
) 
 397     const wxDataViewItem 
& GetItem() const { return m_item
; } 
 398     void SetItem( const wxDataViewItem 
& item 
) { m_item 
= item
; } 
 400     int GetIndentLevel() const 
 403         const wxDataViewTreeNode 
* node 
= this; 
 404         while( node
->GetParent()->GetParent() != NULL 
) 
 406             node 
= node
->GetParent(); 
 414         return m_branchData 
&& m_branchData
->open
; 
 419         wxCHECK_RET( m_branchData 
!= NULL
, "can't open leaf node" ); 
 423         const wxDataViewTreeNodes
& nodes 
= m_branchData
->children
; 
 424         const int len 
= nodes
.GetCount(); 
 425         for ( int i 
= 0;i 
< len
; i 
++) 
 426             sum 
+= 1 + nodes
[i
]->GetSubTreeCount(); 
 428         if (m_branchData
->open
) 
 430             ChangeSubTreeCount(-sum
); 
 431             m_branchData
->open 
= !m_branchData
->open
; 
 435             m_branchData
->open 
= !m_branchData
->open
; 
 436             ChangeSubTreeCount(+sum
); 
 440     // "HasChildren" property corresponds to model's IsContainer(). Note that it may be true 
 441     // even if GetChildNodes() is empty; see below. 
 442     bool HasChildren() const 
 444         return m_branchData 
!= NULL
; 
 447     void SetHasChildren(bool has
) 
 451             wxDELETE(m_branchData
); 
 453         else if ( m_branchData 
== NULL 
) 
 455             m_branchData 
= new BranchNodeData
; 
 459     int GetSubTreeCount() const 
 461         return m_branchData 
? m_branchData
->subTreeCount 
: 0; 
 464     void ChangeSubTreeCount( int num 
) 
 466         wxASSERT( m_branchData 
!= NULL 
); 
 468         if( !m_branchData
->open 
) 
 471         m_branchData
->subTreeCount 
+= num
; 
 472         wxASSERT( m_branchData
->subTreeCount 
>= 0 ); 
 475             m_parent
->ChangeSubTreeCount(num
); 
 485             wxDataViewTreeNodes
& nodes 
= m_branchData
->children
; 
 487             nodes
.Sort( &wxGenericTreeModelNodeCmp 
); 
 488             int len 
= nodes
.GetCount(); 
 489             for (int i 
= 0; i 
< len
; i 
++) 
 491                 if ( nodes
[i
]->HasChildren() ) 
 499     wxDataViewTreeNode  
*m_parent
; 
 501     // Corresponding model item. 
 502     wxDataViewItem       m_item
; 
 504     // Data specific to non-leaf (branch, inner) nodes. They are kept in a 
 505     // separate struct in order to conserve memory. 
 506     struct BranchNodeData
 
 514         // Child nodes. Note that this may be empty even if m_hasChildren in 
 515         // case this branch of the tree wasn't expanded and realized yet. 
 516         wxDataViewTreeNodes  children
; 
 518         // Is the branch node currently open (expanded)? 
 521         // Total count of expanded (i.e. visible with the help of some 
 522         // scrolling) items in the subtree, but excluding this node. I.e. it is 
 523         // 0 for leaves and is the number of rows the subtree occupies for 
 528     BranchNodeData 
*m_branchData
; 
 532 int LINKAGEMODE 
wxGenericTreeModelNodeCmp( wxDataViewTreeNode 
** node1
, 
 533                                            wxDataViewTreeNode 
** node2
) 
 535     return g_model
->Compare( (*node1
)->GetItem(), (*node2
)->GetItem(), g_column
, g_asending 
); 
 539 //----------------------------------------------------------------------------- 
 540 // wxDataViewMainWindow 
 541 //----------------------------------------------------------------------------- 
 543 WX_DEFINE_SORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
); 
 545 class wxDataViewMainWindow
: public wxWindow
 
 548     wxDataViewMainWindow( wxDataViewCtrl 
*parent
, 
 550                             const wxPoint 
&pos 
= wxDefaultPosition
, 
 551                             const wxSize 
&size 
= wxDefaultSize
, 
 552                             const wxString 
&name 
= wxT("wxdataviewctrlmainwindow") ); 
 553     virtual ~wxDataViewMainWindow(); 
 555     bool IsList() const { return GetModel()->IsListModel(); } 
 556     bool IsVirtualList() const { return m_root 
== NULL
; } 
 558     // notifications from wxDataViewModel 
 559     bool ItemAdded( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 560     bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
); 
 561     bool ItemChanged( const wxDataViewItem 
&item 
); 
 562     bool ValueChanged( const wxDataViewItem 
&item
, unsigned int model_column 
); 
 566         if (!IsVirtualList()) 
 576         g_model 
= GetModel(); 
 577         wxDataViewColumn
* col 
= GetOwner()->GetSortingColumn(); 
 580             if (g_model
->HasDefaultCompare()) 
 588         g_column 
= col
->GetModelColumn(); 
 589         g_asending 
= col
->IsSortOrderAscending(); 
 592     void SetOwner( wxDataViewCtrl
* owner 
) { m_owner 
= owner
; } 
 593     wxDataViewCtrl 
*GetOwner() { return m_owner
; } 
 594     const wxDataViewCtrl 
*GetOwner() const { return m_owner
; } 
 596     wxDataViewModel
* GetModel() { return GetOwner()->GetModel(); } 
 597     const wxDataViewModel
* GetModel() const { return GetOwner()->GetModel(); } 
 599 #if wxUSE_DRAG_AND_DROP 
 600     wxBitmap 
CreateItemBitmap( unsigned int row
, int &indent 
); 
 601 #endif // wxUSE_DRAG_AND_DROP 
 602     void OnPaint( wxPaintEvent 
&event 
); 
 603     void OnCharHook( wxKeyEvent 
&event 
); 
 604     void OnChar( wxKeyEvent 
&event 
); 
 605     void OnVerticalNavigation(unsigned int newCurrent
, const wxKeyEvent
& event
); 
 608     void OnMouse( wxMouseEvent 
&event 
); 
 609     void OnSetFocus( wxFocusEvent 
&event 
); 
 610     void OnKillFocus( wxFocusEvent 
&event 
); 
 612     void UpdateDisplay(); 
 613     void RecalculateDisplay(); 
 614     void OnInternalIdle(); 
 616     void OnRenameTimer(); 
 618     void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
= NULL 
); 
 619     void ScrollTo( int rows
, int column 
); 
 621     unsigned GetCurrentRow() const { return m_currentRow
; } 
 622     bool HasCurrentRow() { return m_currentRow 
!= (unsigned int)-1; } 
 623     void ChangeCurrentRow( unsigned int row 
); 
 624     bool TryAdvanceCurrentColumn(wxDataViewTreeNode 
*node
, bool forward
); 
 626     wxDataViewColumn 
*GetCurrentColumn() const { return m_currentCol
; } 
 627     void ClearCurrentColumn() { m_currentCol 
= NULL
; } 
 629     bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); } 
 630     bool IsEmpty() { return GetRowCount() == 0; } 
 632     int GetCountPerPage() const; 
 633     int GetEndOfLastCol() const; 
 634     unsigned int GetFirstVisibleRow() const; 
 636     // I change this method to un const because in the tree view, 
 637     // the displaying number of the tree are changing along with the 
 638     // expanding/collapsing of the tree nodes 
 639     unsigned int GetLastVisibleRow(); 
 640     unsigned int GetRowCount() const; 
 642     const wxDataViewSelection
& GetSelections() const { return m_selection
; } 
 643     void SetSelections( const wxDataViewSelection 
& sel 
) 
 644         { m_selection 
= sel
; UpdateDisplay(); } 
 645     void Select( const wxArrayInt
& aSelections 
); 
 646     void SelectAllRows( bool on 
); 
 647     void SelectRow( unsigned int row
, bool on 
); 
 648     void SelectRows( unsigned int from
, unsigned int to
, bool on 
); 
 649     void ReverseRowSelection( unsigned int row 
); 
 650     bool IsRowSelected( unsigned int row 
); 
 651     void SendSelectionChangedEvent( const wxDataViewItem
& item
); 
 653     void RefreshRow( unsigned int row 
); 
 654     void RefreshRows( unsigned int from
, unsigned int to 
); 
 655     void RefreshRowsAfter( unsigned int firstRow 
); 
 657     // returns the colour to be used for drawing the rules 
 658     wxColour 
GetRuleColour() const 
 660         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
); 
 663     wxRect 
GetLineRect( unsigned int row 
) const; 
 665     int GetLineStart( unsigned int row 
) const;  // row * m_lineHeight in fixed mode 
 666     int GetLineHeight( unsigned int row 
) const; // m_lineHeight in fixed mode 
 667     int GetLineAt( unsigned int y 
) const;       // y / m_lineHeight in fixed mode 
 669     void SetRowHeight( int lineHeight 
) { m_lineHeight 
= lineHeight
; } 
 670     int GetRowHeight() const { return m_lineHeight
; } 
 672     // Some useful functions for row and item mapping 
 673     wxDataViewItem 
GetItemByRow( unsigned int row 
) const; 
 674     int GetRowByItem( const wxDataViewItem 
& item 
) const; 
 676     wxDataViewTreeNode 
* GetTreeNodeByRow( unsigned int row 
) const; 
 677     // We did not need this temporarily 
 678     // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item ); 
 680     // Methods for building the mapping tree 
 681     void BuildTree( wxDataViewModel  
* model 
); 
 683     void HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, wxDataViewColumn
* &column 
); 
 684     wxRect 
GetItemRect( const wxDataViewItem 
& item
, const wxDataViewColumn
* column 
); 
 686     void Expand( unsigned int row 
); 
 687     void Collapse( unsigned int row 
); 
 688     bool IsExpanded( unsigned int row 
) const; 
 689     bool HasChildren( unsigned int row 
) const; 
 691 #if wxUSE_DRAG_AND_DROP 
 692     bool EnableDragSource( const wxDataFormat 
&format 
); 
 693     bool EnableDropTarget( const wxDataFormat 
&format 
); 
 695     void RemoveDropHint(); 
 696     wxDragResult 
OnDragOver( wxDataFormat format
, wxCoord x
, wxCoord y
, wxDragResult def 
); 
 697     bool OnDrop( wxDataFormat format
, wxCoord x
, wxCoord y 
); 
 698     wxDragResult 
OnData( wxDataFormat format
, wxCoord x
, wxCoord y
, wxDragResult def 
); 
 700 #endif // wxUSE_DRAG_AND_DROP 
 702     void OnColumnsCountChanged(); 
 704     // Called by wxDataViewCtrl and our own OnRenameTimer() to start edit the 
 705     // specified item in the given column. 
 706     void StartEditing(const wxDataViewItem
& item
, const wxDataViewColumn
* col
); 
 709     int RecalculateCount() const; 
 711     // Return false only if the event was vetoed by its handler. 
 712     bool SendExpanderEvent(wxEventType type
, const wxDataViewItem
& item
); 
 714     wxDataViewTreeNode 
* FindNode( const wxDataViewItem 
& item 
); 
 716     wxDataViewColumn 
*FindColumnForEditing(const wxDataViewItem
& item
, wxDataViewCellMode mode
); 
 718     bool IsCellEditableInMode(const wxDataViewItem
& item
, const wxDataViewColumn 
*col
, wxDataViewCellMode mode
) const; 
 720     void DrawCellBackground( wxDataViewRenderer
* cell
, wxDC
& dc
, const wxRect
& rect 
); 
 723     wxDataViewCtrl             
*m_owner
; 
 727     wxDataViewColumn           
*m_currentCol
; 
 728     unsigned int                m_currentRow
; 
 729     wxDataViewSelection         m_selection
; 
 731     wxDataViewRenameTimer      
*m_renameTimer
; 
 736     bool                        m_currentColSetByKeyboard
; 
 738 #if wxUSE_DRAG_AND_DROP 
 743     wxDataFormat                m_dragFormat
; 
 746     wxDataFormat                m_dropFormat
; 
 748     unsigned int                m_dropHintLine
; 
 749 #endif // wxUSE_DRAG_AND_DROP 
 751     // for double click logic 
 752     unsigned int m_lineLastClicked
, 
 753         m_lineBeforeLastClicked
, 
 754         m_lineSelectSingleOnUp
; 
 756     // the pen used to draw horiz/vertical rules 
 759     // the pen used to draw the expander and the lines 
 762     // This is the tree structure of the model 
 763     wxDataViewTreeNode 
* m_root
; 
 766     // This is the tree node under the cursor 
 767     wxDataViewTreeNode 
* m_underMouse
; 
 769     // The control used for editing or NULL. 
 770     wxWeakRef
<wxWindow
> m_editorCtrl
; 
 772     // Id m_editorCtrl is non-NULL, pointer to the associated renderer. 
 773     wxDataViewRenderer
* m_editorRenderer
; 
 776     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
) 
 777     DECLARE_EVENT_TABLE() 
 780 // --------------------------------------------------------- 
 781 // wxGenericDataViewModelNotifier 
 782 // --------------------------------------------------------- 
 784 class wxGenericDataViewModelNotifier
: public wxDataViewModelNotifier
 
 787     wxGenericDataViewModelNotifier( wxDataViewMainWindow 
*mainWindow 
) 
 788         { m_mainWindow 
= mainWindow
; } 
 790     virtual bool ItemAdded( const wxDataViewItem 
& parent
, const wxDataViewItem 
& item 
) 
 791         { return m_mainWindow
->ItemAdded( parent 
, item 
); } 
 792     virtual bool ItemDeleted( const wxDataViewItem 
&parent
, const wxDataViewItem 
&item 
) 
 793         { return m_mainWindow
->ItemDeleted( parent
, item 
); } 
 794     virtual bool ItemChanged( const wxDataViewItem 
& item 
) 
 795         { return m_mainWindow
->ItemChanged(item
);  } 
 796     virtual bool ValueChanged( const wxDataViewItem 
& item 
, unsigned int col 
) 
 797         { return m_mainWindow
->ValueChanged( item
, col 
); } 
 798     virtual bool Cleared() 
 799         { return m_mainWindow
->Cleared(); } 
 800     virtual void Resort() 
 801         { m_mainWindow
->Resort(); } 
 803     wxDataViewMainWindow    
*m_mainWindow
; 
 806 // --------------------------------------------------------- 
 807 // wxDataViewRenderer 
 808 // --------------------------------------------------------- 
 810 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
) 
 812 wxDataViewRenderer::wxDataViewRenderer( const wxString 
&varianttype
, 
 813                                         wxDataViewCellMode mode
, 
 815     wxDataViewCustomRendererBase( varianttype
, mode
, align 
) 
 819     m_ellipsizeMode 
= wxELLIPSIZE_MIDDLE
; 
 823 wxDataViewRenderer::~wxDataViewRenderer() 
 828 wxDC 
*wxDataViewRenderer::GetDC() 
 832         if (GetOwner() == NULL
) 
 834         if (GetOwner()->GetOwner() == NULL
) 
 836         m_dc 
= new wxClientDC( GetOwner()->GetOwner() ); 
 842 void wxDataViewRenderer::SetAlignment( int align 
) 
 847 int wxDataViewRenderer::GetAlignment() const 
 852 // --------------------------------------------------------- 
 853 // wxDataViewCustomRenderer 
 854 // --------------------------------------------------------- 
 856 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
) 
 858 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString 
&varianttype
, 
 859                         wxDataViewCellMode mode
, int align 
) : 
 860     wxDataViewRenderer( varianttype
, mode
, align 
) 
 864 // --------------------------------------------------------- 
 865 // wxDataViewTextRenderer 
 866 // --------------------------------------------------------- 
 868 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewRenderer
) 
 870 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString 
&varianttype
, 
 871                                                 wxDataViewCellMode mode
, int align 
) : 
 872     wxDataViewRenderer( varianttype
, mode
, align 
) 
 876 bool wxDataViewTextRenderer::SetValue( const wxVariant 
&value 
) 
 878     m_text 
= value
.GetString(); 
 883 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 888 bool wxDataViewTextRenderer::HasEditorCtrl() const 
 893 wxWindow
* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow 
*parent
, 
 894         wxRect labelRect
, const wxVariant 
&value 
) 
 896     wxTextCtrl
* ctrl 
= new wxTextCtrl( parent
, wxID_ANY
, value
, 
 897                                        wxPoint(labelRect
.x
,labelRect
.y
), 
 898                                        wxSize(labelRect
.width
,labelRect
.height
), 
 899                                        wxTE_PROCESS_ENTER 
); 
 901     // select the text in the control an place the cursor at the end 
 902     ctrl
->SetInsertionPointEnd(); 
 908 bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxWindow 
*editor
, wxVariant 
&value 
) 
 910     wxTextCtrl 
*text 
= (wxTextCtrl
*) editor
; 
 911     value 
= text
->GetValue(); 
 915 bool wxDataViewTextRenderer::Render(wxRect rect
, wxDC 
*dc
, int state
) 
 917     RenderText(m_text
, 0, rect
, dc
, state
); 
 921 wxSize 
wxDataViewTextRenderer::GetSize() const 
 924         return GetTextExtent(m_text
); 
 926         return wxSize(wxDVC_DEFAULT_RENDERER_SIZE
,wxDVC_DEFAULT_RENDERER_SIZE
); 
 929 // --------------------------------------------------------- 
 930 // wxDataViewBitmapRenderer 
 931 // --------------------------------------------------------- 
 933 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewRenderer
) 
 935 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString 
&varianttype
, 
 936                                                     wxDataViewCellMode mode
, int align 
) : 
 937     wxDataViewRenderer( varianttype
, mode
, align 
) 
 941 bool wxDataViewBitmapRenderer::SetValue( const wxVariant 
&value 
) 
 943     if (value
.GetType() == wxT("wxBitmap")) 
 945     if (value
.GetType() == wxT("wxIcon")) 
 951 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
 956 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
 959         dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y 
); 
 960     else if (m_icon
.IsOk()) 
 961         dc
->DrawIcon( m_icon
, cell
.x
, cell
.y 
); 
 966 wxSize 
wxDataViewBitmapRenderer::GetSize() const 
 969         return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() ); 
 970     else if (m_icon
.IsOk()) 
 971         return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() ); 
 973     return wxSize(wxDVC_DEFAULT_RENDERER_SIZE
,wxDVC_DEFAULT_RENDERER_SIZE
); 
 976 // --------------------------------------------------------- 
 977 // wxDataViewToggleRenderer 
 978 // --------------------------------------------------------- 
 980 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewRenderer
) 
 982 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString 
&varianttype
, 
 983                         wxDataViewCellMode mode
, int align 
) : 
 984     wxDataViewRenderer( varianttype
, mode
, align 
) 
 989 bool wxDataViewToggleRenderer::SetValue( const wxVariant 
&value 
) 
 991     m_toggle 
= value
.GetBool(); 
 996 bool wxDataViewToggleRenderer::GetValue( wxVariant 
&WXUNUSED(value
) ) const 
1001 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC 
*dc
, int WXUNUSED(state
) ) 
1005         flags 
|= wxCONTROL_CHECKED
; 
1006     if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE 
|| 
1007         GetEnabled() == false) 
1008         flags 
|= wxCONTROL_DISABLED
; 
1010     // Ensure that the check boxes always have at least the minimal required 
1011     // size, otherwise DrawCheckBox() doesn't really work well. If this size is 
1012     // greater than the cell size, the checkbox will be truncated but this is a 
1014     wxSize size 
= cell
.GetSize(); 
1015     size
.IncTo(GetSize()); 
1018     wxRendererNative::Get().DrawCheckBox( 
1019             GetOwner()->GetOwner(), 
1027 bool wxDataViewToggleRenderer::WXActivateCell(const wxRect
& WXUNUSED(cell
), 
1028                                               wxDataViewModel 
*model
, 
1029                                               const wxDataViewItem
& item
, 
1031                                               const wxMouseEvent 
*mouseEvent
) 
1035         // only react to clicks directly on the checkbox, not elsewhere in the same cell: 
1036         if ( !wxRect(GetSize()).Contains(mouseEvent
->GetPosition()) ) 
1040     model
->ChangeValue(!m_toggle
, item
, col
); 
1044 wxSize 
wxDataViewToggleRenderer::GetSize() const 
1046     // the window parameter is not used by GetCheckBoxSize() so it's 
1047     // safe to pass NULL 
1048     return wxRendererNative::Get().GetCheckBoxSize(NULL
); 
1051 // --------------------------------------------------------- 
1052 // wxDataViewProgressRenderer 
1053 // --------------------------------------------------------- 
1055 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewRenderer
) 
1057 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString 
&label
, 
1058     const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
1059     wxDataViewRenderer( varianttype
, mode
, align 
) 
1065 bool wxDataViewProgressRenderer::SetValue( const wxVariant 
&value 
) 
1067     m_value 
= (long) value
; 
1069     if (m_value 
< 0) m_value 
= 0; 
1070     if (m_value 
> 100) m_value 
= 100; 
1075 bool wxDataViewProgressRenderer::GetValue( wxVariant 
&value 
) const 
1077     value 
= (long) m_value
; 
1082 wxDataViewProgressRenderer::Render(wxRect rect
, wxDC 
*dc
, int WXUNUSED(state
)) 
1084     // deflate the rect to leave a small border between bars in adjacent rows 
1085     wxRect bar 
= rect
.Deflate(0, 1); 
1087     dc
->SetBrush( *wxTRANSPARENT_BRUSH 
); 
1088     dc
->SetPen( *wxBLACK_PEN 
); 
1089     dc
->DrawRectangle( bar 
); 
1091     bar
.width 
= (int)(bar
.width 
* m_value 
/ 100.); 
1092     dc
->SetPen( *wxTRANSPARENT_PEN 
); 
1094     const wxDataViewItemAttr
& attr 
= GetAttr(); 
1095     dc
->SetBrush( attr
.HasColour() ? wxBrush(attr
.GetColour()) 
1097     dc
->DrawRectangle( bar 
); 
1102 wxSize 
wxDataViewProgressRenderer::GetSize() const 
1104     return wxSize(40,12); 
1107 // --------------------------------------------------------- 
1108 // wxDataViewIconTextRenderer 
1109 // --------------------------------------------------------- 
1111 IMPLEMENT_CLASS(wxDataViewIconTextRenderer
, wxDataViewRenderer
) 
1113 wxDataViewIconTextRenderer::wxDataViewIconTextRenderer( 
1114 const wxString 
&varianttype
, wxDataViewCellMode mode
, int align 
) : 
1115     wxDataViewRenderer( varianttype
, mode
, align 
) 
1118     SetAlignment(align
); 
1121 bool wxDataViewIconTextRenderer::SetValue( const wxVariant 
&value 
) 
1127 bool wxDataViewIconTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const 
1132 bool wxDataViewIconTextRenderer::Render(wxRect rect
, wxDC 
*dc
, int state
) 
1136     const wxIcon
& icon 
= m_value
.GetIcon(); 
1139         dc
->DrawIcon(icon
, rect
.x
, rect
.y 
+ (rect
.height 
- icon
.GetHeight())/2); 
1140         xoffset 
= icon
.GetWidth()+4; 
1143     RenderText(m_value
.GetText(), xoffset
, rect
, dc
, state
); 
1148 wxSize 
wxDataViewIconTextRenderer::GetSize() const 
1150     if (!m_value
.GetText().empty()) 
1152         wxSize size 
= GetTextExtent(m_value
.GetText()); 
1154         if (m_value
.GetIcon().IsOk()) 
1155             size
.x 
+= m_value
.GetIcon().GetWidth() + 4; 
1158     return wxSize(80,20); 
1161 wxWindow
* wxDataViewIconTextRenderer::CreateEditorCtrl(wxWindow 
*parent
, wxRect labelRect
, const wxVariant
& value
) 
1163     wxDataViewIconText iconText
; 
1166     wxString text 
= iconText
.GetText(); 
1168     // adjust the label rect to take the width of the icon into account 
1169     if (iconText
.GetIcon().IsOk()) 
1171         int w 
= iconText
.GetIcon().GetWidth() + 4; 
1173         labelRect
.width 
-= w
; 
1176     wxTextCtrl
* ctrl 
= new wxTextCtrl( parent
, wxID_ANY
, text
, 
1177                                        wxPoint(labelRect
.x
,labelRect
.y
), 
1178                                        wxSize(labelRect
.width
,labelRect
.height
), 
1179                                        wxTE_PROCESS_ENTER 
); 
1181     // select the text in the control an place the cursor at the end 
1182     ctrl
->SetInsertionPointEnd(); 
1188 bool wxDataViewIconTextRenderer::GetValueFromEditorCtrl( wxWindow 
*editor
, wxVariant
& value 
) 
1190     wxTextCtrl 
*text 
= (wxTextCtrl
*) editor
; 
1192     // The icon can't be edited so get its old value and reuse it. 
1194     wxDataViewColumn
* const col 
= GetOwner(); 
1195     GetView()->GetModel()->GetValue(valueOld
, m_item
, col
->GetModelColumn()); 
1197     wxDataViewIconText iconText
; 
1198     iconText 
<< valueOld
; 
1200     // But replace the text with the value entered by user. 
1201     iconText
.SetText(text
->GetValue()); 
1207 //----------------------------------------------------------------------------- 
1208 // wxDataViewDropTarget 
1209 //----------------------------------------------------------------------------- 
1211 #if wxUSE_DRAG_AND_DROP 
1213 class wxBitmapCanvas
: public wxWindow
 
1216     wxBitmapCanvas( wxWindow 
*parent
, const wxBitmap 
&bitmap
, const wxSize 
&size 
) : 
1217     wxWindow( parent
, wxID_ANY
, wxPoint(0,0), size 
) 
1220         Connect( wxEVT_PAINT
, wxPaintEventHandler(wxBitmapCanvas::OnPaint
) ); 
1223     void OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1226         dc
.DrawBitmap( m_bitmap
, 0, 0); 
1232 class wxDataViewDropSource
: public wxDropSource
 
1235     wxDataViewDropSource( wxDataViewMainWindow 
*win
, unsigned int row 
) : 
1243     ~wxDataViewDropSource() 
1248     virtual bool GiveFeedback( wxDragResult 
WXUNUSED(effect
) ) 
1250         wxPoint pos 
= wxGetMousePosition(); 
1254             int liney 
= m_win
->GetLineStart( m_row 
); 
1256             m_win
->GetOwner()->CalcUnscrolledPosition( 0, liney
, NULL
, &liney 
); 
1257             m_win
->ClientToScreen( &linex
, &liney 
); 
1258             m_dist_x 
= pos
.x 
- linex
; 
1259             m_dist_y 
= pos
.y 
- liney
; 
1262             wxBitmap ib 
= m_win
->CreateItemBitmap( m_row
, indent 
); 
1264             m_hint 
= new wxFrame( m_win
->GetParent(), wxID_ANY
, wxEmptyString
, 
1265                                         wxPoint(pos
.x 
- m_dist_x
, pos
.y 
+ 5 ), 
1267                                         wxFRAME_TOOL_WINDOW 
| 
1268                                         wxFRAME_FLOAT_ON_PARENT 
| 
1269                                         wxFRAME_NO_TASKBAR 
| 
1271             new wxBitmapCanvas( m_hint
, ib
, ib
.GetSize() ); 
1276             m_hint
->Move( pos
.x 
- m_dist_x
, pos
.y 
+ 5  ); 
1277             m_hint
->SetTransparent( 128 ); 
1283     wxDataViewMainWindow   
*m_win
; 
1286     int m_dist_x
,m_dist_y
; 
1290 class wxDataViewDropTarget
: public wxDropTarget
 
1293     wxDataViewDropTarget( wxDataObject 
*obj
, wxDataViewMainWindow 
*win 
) : 
1299     virtual wxDragResult 
OnDragOver( wxCoord x
, wxCoord y
, wxDragResult def 
) 
1301         wxDataFormat format 
= GetMatchingPair(); 
1302         if (format 
== wxDF_INVALID
) 
1304         return m_win
->OnDragOver( format
, x
, y
, def
); 
1307     virtual bool OnDrop( wxCoord x
, wxCoord y 
) 
1309         wxDataFormat format 
= GetMatchingPair(); 
1310         if (format 
== wxDF_INVALID
) 
1312         return m_win
->OnDrop( format
, x
, y 
); 
1315     virtual wxDragResult 
OnData( wxCoord x
, wxCoord y
, wxDragResult def 
) 
1317         wxDataFormat format 
= GetMatchingPair(); 
1318         if (format 
== wxDF_INVALID
) 
1322         return m_win
->OnData( format
, x
, y
, def 
); 
1325     virtual void OnLeave() 
1326         { m_win
->OnLeave(); } 
1328     wxDataViewMainWindow   
*m_win
; 
1331 #endif // wxUSE_DRAG_AND_DROP 
1333 //----------------------------------------------------------------------------- 
1334 // wxDataViewRenameTimer 
1335 //----------------------------------------------------------------------------- 
1337 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow 
*owner 
) 
1342 void wxDataViewRenameTimer::Notify() 
1344     m_owner
->OnRenameTimer(); 
1347 //----------------------------------------------------------------------------- 
1348 // wxDataViewMainWindow 
1349 //----------------------------------------------------------------------------- 
1351 // The tree building helper, declared firstly 
1352 static void BuildTreeHelper( const wxDataViewModel 
* model
,  const wxDataViewItem 
& item
, 
1353                              wxDataViewTreeNode 
* node
); 
1355 int LINKAGEMODE 
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2 
) 
1357     if (row1 
> row2
) return 1; 
1358     if (row1 
== row2
) return 0; 
1362 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
) 
1364 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
) 
1365     EVT_PAINT         (wxDataViewMainWindow::OnPaint
) 
1366     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse
) 
1367     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus
) 
1368     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus
) 
1369     EVT_CHAR_HOOK     (wxDataViewMainWindow::OnCharHook
) 
1370     EVT_CHAR          (wxDataViewMainWindow::OnChar
) 
1373 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl 
*parent
, wxWindowID id
, 
1374     const wxPoint 
&pos
, const wxSize 
&size
, const wxString 
&name 
) : 
1375     wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
|wxBORDER_NONE
, name 
), 
1376     m_selection( wxDataViewSelectionCmp 
) 
1381     m_editorRenderer 
= NULL
; 
1383     m_lastOnSame 
= false; 
1384     m_renameTimer 
= new wxDataViewRenameTimer( this ); 
1386     // TODO: user better initial values/nothing selected 
1387     m_currentCol 
= NULL
; 
1388     m_currentColSetByKeyboard 
= false; 
1389     m_useCellFocus 
= false; 
1393     // We would like to use the same line height that Explorer uses. This is 
1394     // different from standard ListView control since Vista. 
1395     if ( wxGetWinVersion() >= wxWinVersion_Vista 
) 
1396         m_lineHeight 
= wxMax(16, GetCharHeight()) + 6; // 16 = mini icon height 
1399         m_lineHeight 
= wxMax(16, GetCharHeight()) + 1; // 16 = mini icon height 
1401 #if wxUSE_DRAG_AND_DROP 
1403     m_dragStart 
= wxPoint(0,0); 
1405     m_dragEnabled 
= false; 
1406     m_dropEnabled 
= false; 
1408     m_dropHintLine 
= (unsigned int) -1; 
1409 #endif // wxUSE_DRAG_AND_DROP 
1411     m_lineLastClicked 
= (unsigned int) -1; 
1412     m_lineBeforeLastClicked 
= (unsigned int) -1; 
1413     m_lineSelectSingleOnUp 
= (unsigned int) -1; 
1417     SetBackgroundColour( *wxWHITE 
); 
1419     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
1421     m_penRule 
= wxPen(GetRuleColour()); 
1423     // compose a pen whichcan draw black lines 
1424     // TODO: maybe there is something system colour to use 
1425     m_penExpander 
= wxPen(wxColour(0,0,0)); 
1427     m_root 
= wxDataViewTreeNode::CreateRootNode(); 
1429     // Make m_count = -1 will cause the class recaculate the real displaying number of rows. 
1431     m_underMouse 
= NULL
; 
1435 wxDataViewMainWindow::~wxDataViewMainWindow() 
1438     delete m_renameTimer
; 
1442 #if wxUSE_DRAG_AND_DROP 
1443 bool wxDataViewMainWindow::EnableDragSource( const wxDataFormat 
&format 
) 
1445     m_dragFormat 
= format
; 
1446     m_dragEnabled 
= format 
!= wxDF_INVALID
; 
1451 bool wxDataViewMainWindow::EnableDropTarget( const wxDataFormat 
&format 
) 
1453     m_dropFormat 
= format
; 
1454     m_dropEnabled 
= format 
!= wxDF_INVALID
; 
1457         SetDropTarget( new wxDataViewDropTarget( new wxCustomDataObject( format 
), this ) ); 
1462 void wxDataViewMainWindow::RemoveDropHint() 
1467             RefreshRow( m_dropHintLine 
); 
1468             m_dropHintLine 
= (unsigned int) -1; 
1472 wxDragResult 
wxDataViewMainWindow::OnDragOver( wxDataFormat format
, wxCoord x
, 
1473                                                wxCoord y
, wxDragResult def 
) 
1477     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1478     unsigned int row 
= GetLineAt( yy 
); 
1480     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1486     wxDataViewItem item 
= GetItemByRow( row 
); 
1488     wxDataViewModel 
*model 
= GetModel(); 
1490     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE
, m_owner
->GetId() ); 
1491     event
.SetEventObject( m_owner 
); 
1492     event
.SetItem( item 
); 
1493     event
.SetModel( model 
); 
1494     event
.SetDataFormat( format 
); 
1495     event
.SetDropEffect( def 
); 
1496     if (!m_owner
->HandleWindowEvent( event 
)) 
1502     if (!event
.IsAllowed()) 
1509     if (m_dropHint 
&& (row 
!= m_dropHintLine
)) 
1510         RefreshRow( m_dropHintLine 
); 
1512     m_dropHintLine 
= row
; 
1518 bool wxDataViewMainWindow::OnDrop( wxDataFormat format
, wxCoord x
, wxCoord y 
) 
1524     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1525     unsigned int row 
= GetLineAt( yy 
); 
1527     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1530     wxDataViewItem item 
= GetItemByRow( row 
); 
1532     wxDataViewModel 
*model 
= GetModel(); 
1534     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE
, m_owner
->GetId() ); 
1535     event
.SetEventObject( m_owner 
); 
1536     event
.SetItem( item 
); 
1537     event
.SetModel( model 
); 
1538     event
.SetDataFormat( format 
); 
1539     if (!m_owner
->HandleWindowEvent( event 
)) 
1542     if (!event
.IsAllowed()) 
1548 wxDragResult 
wxDataViewMainWindow::OnData( wxDataFormat format
, wxCoord x
, wxCoord y
, 
1553     m_owner
->CalcUnscrolledPosition( xx
, yy
, &xx
, &yy 
); 
1554     unsigned int row 
= GetLineAt( yy 
); 
1556     if ((row 
>= GetRowCount()) || (xx 
> GetEndOfLastCol())) 
1559     wxDataViewItem item 
= GetItemByRow( row 
); 
1561     wxDataViewModel 
*model 
= GetModel(); 
1563     wxCustomDataObject 
*obj 
= (wxCustomDataObject 
*) GetDropTarget()->GetDataObject(); 
1565     wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_DROP
, m_owner
->GetId() ); 
1566     event
.SetEventObject( m_owner 
); 
1567     event
.SetItem( item 
); 
1568     event
.SetModel( model 
); 
1569     event
.SetDataFormat( format 
); 
1570     event
.SetDataSize( obj
->GetSize() ); 
1571     event
.SetDataBuffer( obj
->GetData() ); 
1572     event
.SetDropEffect( def 
); 
1573     if (!m_owner
->HandleWindowEvent( event 
)) 
1576     if (!event
.IsAllowed()) 
1582 void wxDataViewMainWindow::OnLeave() 
1587 wxBitmap 
wxDataViewMainWindow::CreateItemBitmap( unsigned int row
, int &indent 
) 
1589     int height 
= GetLineHeight( row 
); 
1591     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1593     for (col 
= 0; col 
< cols
; col
++) 
1595         wxDataViewColumn 
*column 
= GetOwner()->GetColumnAt(col
); 
1596         if (column
->IsHidden()) 
1597             continue;      // skip it! 
1598         width 
+= column
->GetWidth(); 
1604         wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
1605         indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
1606         indent 
= indent 
+ m_lineHeight
; 
1607             // try to use the m_lineHeight as the expander space 
1611     wxBitmap 
bitmap( width
, height 
); 
1612     wxMemoryDC 
dc( bitmap 
); 
1613     dc
.SetFont( GetFont() ); 
1614     dc
.SetPen( *wxBLACK_PEN 
); 
1615     dc
.SetBrush( *wxWHITE_BRUSH 
); 
1616     dc
.DrawRectangle( 0,0,width
,height 
); 
1618     wxDataViewModel 
*model 
= m_owner
->GetModel(); 
1620     wxDataViewColumn 
* const 
1621         expander 
= GetExpanderColumnOrFirstOne(GetOwner()); 
1624     for (col 
= 0; col 
< cols
; col
++) 
1626         wxDataViewColumn 
*column 
= GetOwner()->GetColumnAt( col 
); 
1627         wxDataViewRenderer 
*cell 
= column
->GetRenderer(); 
1629         if (column
->IsHidden()) 
1630             continue;       // skip it! 
1632         width 
= column
->GetWidth(); 
1634         if (column 
== expander
) 
1637         wxDataViewItem item 
= GetItemByRow( row 
); 
1638         cell
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
1640         wxRect 
item_rect(x
, 0, width
, height
); 
1641         item_rect
.Deflate(PADDING_RIGHTLEFT
, 0); 
1643         // dc.SetClippingRegion( item_rect ); 
1644         cell
->WXCallRender(item_rect
, &dc
, 0); 
1645         // dc.DestroyClippingRegion(); 
1653 #endif // wxUSE_DRAG_AND_DROP 
1656 // Draw focus rect for individual cell. Unlike native focus rect, we render 
1657 // this in foreground text color (typically white) to enhance contrast and 
1659 static void DrawSelectedCellFocusRect(wxDC
& dc
, const wxRect
& rect
) 
1661     // (This code is based on wxRendererGeneric::DrawFocusRect and modified.) 
1663     // draw the pixels manually because the "dots" in wxPen with wxDOT style 
1664     // may be short traits and not really dots 
1666     // note that to behave in the same manner as DrawRect(), we must exclude 
1667     // the bottom and right borders from the rectangle 
1668     wxCoord x1 
= rect
.GetLeft(), 
1670             x2 
= rect
.GetRight(), 
1671             y2 
= rect
.GetBottom(); 
1673     wxDCPenChanger 
pen(dc
, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
)); 
1676     for ( z 
= x1 
+ 1; z 
< x2
; z 
+= 2 ) 
1677         dc
.DrawPoint(z
, rect
.GetTop()); 
1679     wxCoord shift 
= z 
== x2 
? 0 : 1; 
1680     for ( z 
= y1 
+ shift
; z 
< y2
; z 
+= 2 ) 
1681         dc
.DrawPoint(x2
, z
); 
1683     shift 
= z 
== y2 
? 0 : 1; 
1684     for ( z 
= x2 
- shift
; z 
> x1
; z 
-= 2 ) 
1685         dc
.DrawPoint(z
, y2
); 
1687     shift 
= z 
== x1 
? 0 : 1; 
1688     for ( z 
= y2 
- shift
; z 
> y1
; z 
-= 2 ) 
1689         dc
.DrawPoint(x1
, z
); 
1693 void wxDataViewMainWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1695     wxDataViewModel 
*model 
= GetModel(); 
1696     wxAutoBufferedPaintDC 
dc( this ); 
1699     dc
.SetBrush(GetOwner()->GetBackgroundColour()); 
1700     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1701     dc
.DrawRectangle(GetClientSize()); 
1706         // No items to draw. 
1711     GetOwner()->PrepareDC( dc 
); 
1712     dc
.SetFont( GetFont() ); 
1714     wxRect update 
= GetUpdateRegion().GetBox(); 
1715     m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y 
); 
1717     // compute which items needs to be redrawn 
1718     unsigned int item_start 
= GetLineAt( wxMax(0,update
.y
) ); 
1719     unsigned int item_count 
= 
1720         wxMin( (int)(  GetLineAt( wxMax(0,update
.y
+update
.height
) ) - item_start 
+ 1), 
1721             (int)(GetRowCount( ) - item_start
)); 
1722     unsigned int item_last 
= item_start 
+ item_count
; 
1724     // Send the event to wxDataViewCtrl itself. 
1725     wxWindow 
* const parent 
= GetParent(); 
1726     wxDataViewEvent 
cache_event(wxEVT_COMMAND_DATAVIEW_CACHE_HINT
, parent
->GetId()); 
1727     cache_event
.SetEventObject(parent
); 
1728     cache_event
.SetCache(item_start
, item_last 
- 1); 
1729     parent
->ProcessWindowEvent(cache_event
); 
1731     // compute which columns needs to be redrawn 
1732     unsigned int cols 
= GetOwner()->GetColumnCount(); 
1735         // we assume that we have at least one column below and painting an 
1736         // empty control is unnecessary anyhow 
1740     unsigned int col_start 
= 0; 
1741     unsigned int x_start
; 
1742     for (x_start 
= 0; col_start 
< cols
; col_start
++) 
1744         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_start
); 
1745         if (col
->IsHidden()) 
1746             continue;      // skip it! 
1748         unsigned int w 
= col
->GetWidth(); 
1749         if (x_start
+w 
>= (unsigned int)update
.x
) 
1755     unsigned int col_last 
= col_start
; 
1756     unsigned int x_last 
= x_start
; 
1757     for (; col_last 
< cols
; col_last
++) 
1759         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(col_last
); 
1760         if (col
->IsHidden()) 
1761             continue;      // skip it! 
1763         if (x_last 
> (unsigned int)update
.GetRight()) 
1766         x_last 
+= col
->GetWidth(); 
1769     // Draw background of alternate rows specially if required 
1770     if ( m_owner
->HasFlag(wxDV_ROW_LINES
) ) 
1772         wxColour altRowColour 
= m_owner
->m_alternateRowColour
; 
1773         if ( !altRowColour
.IsOk() ) 
1775             // Determine the alternate rows colour automatically from the 
1776             // background colour. 
1777             const wxColour bgColour 
= m_owner
->GetBackgroundColour(); 
1779             // Depending on the background, alternate row color 
1780             // will be 3% more dark or 50% brighter. 
1781             int alpha 
= bgColour
.GetRGB() > 0x808080 ? 97 : 150; 
1782             altRowColour 
= bgColour
.ChangeLightness(alpha
); 
1785         dc
.SetPen(*wxTRANSPARENT_PEN
); 
1786         dc
.SetBrush(wxBrush(altRowColour
)); 
1788         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1792                 dc
.DrawRectangle(x_start
, 
1794                                  GetClientSize().GetWidth(), 
1795                                  GetLineHeight(item
)); 
1800     // Draw horizontal rules if required 
1801     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
1803         dc
.SetPen(m_penRule
); 
1804         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1806         for (unsigned int i 
= item_start
; i 
<= item_last
; i
++) 
1808             int y 
= GetLineStart( i 
); 
1809             dc
.DrawLine(x_start
, y
, x_last
, y
); 
1813     // Draw vertical rules if required 
1814     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
1816         dc
.SetPen(m_penRule
); 
1817         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1819         // NB: Vertical rules are drawn in the last pixel of a column so that 
1820         //     they align perfectly with native MSW wxHeaderCtrl as well as for 
1821         //     consistency with MSW native list control. There's no vertical 
1822         //     rule at the most-left side of the control. 
1824         int x 
= x_start 
- 1; 
1825         for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1827             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(i
); 
1828             if (col
->IsHidden()) 
1829                 continue;       // skip it 
1831             x 
+= col
->GetWidth(); 
1833             dc
.DrawLine(x
, GetLineStart( item_start 
), 
1834                         x
, GetLineStart( item_last 
) ); 
1838     // redraw the background for the items which are selected/current 
1839     for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1841         bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1843         if (selected 
|| item 
== m_currentRow
) 
1845             wxRect 
rect( x_start
, GetLineStart( item 
), 
1846                          x_last 
- x_start
, GetLineHeight( item 
) ); 
1848             // draw selection and whole-item focus: 
1851                 int flags 
= wxCONTROL_SELECTED
; 
1853                     flags 
|= wxCONTROL_FOCUSED
; 
1855                 wxRendererNative::Get().DrawItemSelectionRect
 
1864             // draw keyboard focus rect if applicable 
1865             if ( item 
== m_currentRow 
&& m_hasFocus 
) 
1867                 bool renderColumnFocus 
= false; 
1869                 if ( m_useCellFocus 
&& m_currentCol 
&& m_currentColSetByKeyboard 
) 
1871                     renderColumnFocus 
= true; 
1873                     // If this is container node without columns, render full-row focus: 
1876                         wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(item
); 
1877                         if ( node
->HasChildren() && !model
->HasContainerColumns(node
->GetItem()) ) 
1878                             renderColumnFocus 
= false; 
1882                 if ( renderColumnFocus 
) 
1884                     for ( unsigned int i 
= col_start
; i 
< col_last
; i
++ ) 
1886                         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(i
); 
1887                         if ( col
->IsHidden() ) 
1890                         rect
.width 
= col
->GetWidth(); 
1892                         if ( col 
== m_currentCol 
) 
1894                             // make the rect more visible by adding a small 
1895                             // margin around it: 
1900                                 // DrawFocusRect() uses XOR and is all but 
1901                                 // invisible against dark-blue background. Use 
1902                                 // the same color used for selected text. 
1903                                 DrawSelectedCellFocusRect(dc
, rect
); 
1907                                 wxRendererNative::Get().DrawFocusRect
 
1918                         rect
.x 
+= rect
.width
; 
1923                     // render focus rectangle for the whole row 
1924                     wxRendererNative::Get().DrawFocusRect
 
1929                                             selected 
? (int)wxCONTROL_SELECTED 
: 0 
1936 #if wxUSE_DRAG_AND_DROP 
1939         wxRect 
rect( x_start
, GetLineStart( m_dropHintLine 
), 
1940                      x_last 
- x_start
, GetLineHeight( m_dropHintLine 
) ); 
1941         dc
.SetPen( *wxBLACK_PEN 
); 
1942         dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
1943         dc
.DrawRectangle( rect 
); 
1945 #endif // wxUSE_DRAG_AND_DROP 
1947     wxDataViewColumn 
* const 
1948         expander 
= GetExpanderColumnOrFirstOne(GetOwner()); 
1950     // redraw all cells for all rows which must be repainted and all columns 
1952     cell_rect
.x 
= x_start
; 
1953     for (unsigned int i 
= col_start
; i 
< col_last
; i
++) 
1955         wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt( i 
); 
1956         wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
1957         cell_rect
.width 
= col
->GetWidth(); 
1959         if ( col
->IsHidden() || cell_rect
.width 
<= 0 ) 
1960             continue;       // skip it! 
1962         for (unsigned int item 
= item_start
; item 
< item_last
; item
++) 
1964             // get the cell value and set it into the renderer 
1965             wxDataViewTreeNode 
*node 
= NULL
; 
1966             wxDataViewItem dataitem
; 
1968             if (!IsVirtualList()) 
1970                 node 
= GetTreeNodeByRow(item
); 
1974                 dataitem 
= node
->GetItem(); 
1976                 // Skip all columns of "container" rows except the expander 
1977                 // column itself unless HasContainerColumns() overrides this. 
1978                 if ( col 
!= expander 
&& 
1979                         model
->IsContainer(dataitem
) && 
1980                             !model
->HasContainerColumns(dataitem
) ) 
1985                 dataitem 
= wxDataViewItem( wxUIntToPtr(item
+1) ); 
1988             cell
->PrepareForItem(model
, dataitem
, col
->GetModelColumn()); 
1991             cell_rect
.y 
= GetLineStart( item 
); 
1992             cell_rect
.height 
= GetLineHeight( item 
); 
1994             // draw the background 
1995             bool selected 
= m_selection
.Index( item 
) != wxNOT_FOUND
; 
1997                 DrawCellBackground( cell
, dc
, cell_rect 
); 
1999             // deal with the expander 
2001             if ((!IsList()) && (col 
== expander
)) 
2003                 // Calculate the indent first 
2004                 indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
2006                 // we reserve m_lineHeight of horizontal space for the expander 
2007                 // but leave EXPANDER_MARGIN around the expander itself 
2008                 int exp_x 
= cell_rect
.x 
+ indent 
+ EXPANDER_MARGIN
; 
2010                 indent 
+= m_lineHeight
; 
2012                 // draw expander if needed and visible 
2013                 if ( node
->HasChildren() && exp_x 
< cell_rect
.GetRight() ) 
2015                     dc
.SetPen( m_penExpander 
); 
2016                     dc
.SetBrush( wxNullBrush 
); 
2018                     int exp_size 
= m_lineHeight 
- 2*EXPANDER_MARGIN
; 
2019                     int exp_y 
= cell_rect
.y 
+ (cell_rect
.height 
- exp_size
)/2 
2020                                    + EXPANDER_MARGIN 
- EXPANDER_OFFSET
; 
2022                     const wxRect 
rect(exp_x
, exp_y
, exp_size
, exp_size
); 
2025                     if ( m_underMouse 
== node 
) 
2026                         flag 
|= wxCONTROL_CURRENT
; 
2027                     if ( node
->IsOpen() ) 
2028                         flag 
|= wxCONTROL_EXPANDED
; 
2030                     // ensure that we don't overflow the cell (which might 
2031                     // happen if the column is very narrow) 
2032                     wxDCClipper 
clip(dc
, cell_rect
); 
2034                     wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
); 
2037                 // force the expander column to left-center align 
2038                 cell
->SetAlignment( wxALIGN_CENTER_VERTICAL 
); 
2041             wxRect item_rect 
= cell_rect
; 
2042             item_rect
.Deflate(PADDING_RIGHTLEFT
, 0); 
2044             // account for the tree indent (harmless if we're not indented) 
2045             item_rect
.x 
+= indent
; 
2046             item_rect
.width 
-= indent
; 
2048             if ( item_rect
.width 
<= 0 ) 
2052             if (m_hasFocus 
&& selected
) 
2053                 state 
|= wxDATAVIEW_CELL_SELECTED
; 
2055             // TODO: it would be much more efficient to create a clipping 
2056             //       region for the entire column being rendered (in the OnPaint 
2057             //       of wxDataViewMainWindow) instead of a single clip region for 
2058             //       each cell. However it would mean that each renderer should 
2059             //       respect the given wxRect's top & bottom coords, eventually 
2060             //       violating only the left & right coords - however the user can 
2061             //       make its own renderer and thus we cannot be sure of that. 
2062             wxDCClipper 
clip(dc
, item_rect
); 
2064             cell
->WXCallRender(item_rect
, &dc
, state
); 
2067         cell_rect
.x 
+= cell_rect
.width
; 
2072 void wxDataViewMainWindow::DrawCellBackground( wxDataViewRenderer
* cell
, wxDC
& dc
, const wxRect
& rect 
) 
2074     wxRect 
rectBg( rect 
); 
2076     // don't overlap the horizontal rules 
2077     if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) ) 
2083     // don't overlap the vertical rules 
2084     if ( m_owner
->HasFlag(wxDV_VERT_RULES
) ) 
2090     cell
->RenderBackground(&dc
, rectBg
); 
2093 void wxDataViewMainWindow::OnRenameTimer() 
2095     // We have to call this here because changes may just have 
2096     // been made and no screen update taken place. 
2099         // TODO: use wxTheApp->SafeYieldFor(NULL, wxEVT_CATEGORY_UI) instead 
2100         //       (needs to be tested!) 
2104     wxDataViewItem item 
= GetItemByRow( m_currentRow 
); 
2106     StartEditing( item
, m_currentCol 
); 
2110 wxDataViewMainWindow::StartEditing(const wxDataViewItem
& item
, 
2111                                    const wxDataViewColumn
* col
) 
2113     wxDataViewRenderer
* renderer 
= col
->GetRenderer(); 
2114     if ( !IsCellEditableInMode(item
, col
, wxDATAVIEW_CELL_EDITABLE
) ) 
2117     const wxRect itemRect 
= GetItemRect(item
, col
); 
2118     if ( renderer
->StartEditing(item
, itemRect
) ) 
2120         // Save the renderer to be able to finish/cancel editing it later and 
2121         // save the control to be able to detect if we're still editing it. 
2122         m_editorRenderer 
= renderer
; 
2123         m_editorCtrl 
= renderer
->GetEditorCtrl(); 
2127 //----------------------------------------------------------------------------- 
2128 // Helper class for do operation on the tree node 
2129 //----------------------------------------------------------------------------- 
2134     virtual ~DoJob() { } 
2136     // The return value control how the tree-walker tranverse the tree 
2139         DONE
,          // Job done, stop traversing and return 
2140         SKIP_SUBTREE
,  // Ignore the current node's subtree and continue 
2141         CONTINUE       
// Job not done, continue 
2144     virtual int operator() ( wxDataViewTreeNode 
* node 
) = 0; 
2147 bool Walker( wxDataViewTreeNode 
* node
, DoJob 
& func 
) 
2149     wxCHECK_MSG( node
, false, "can't walk NULL node" ); 
2151     switch( func( node 
) ) 
2155         case DoJob::SKIP_SUBTREE
: 
2157         case DoJob::CONTINUE
: 
2161     if ( node
->HasChildren() ) 
2163         const wxDataViewTreeNodes
& nodes 
= node
->GetChildNodes(); 
2165         for ( wxDataViewTreeNodes::const_iterator i 
= nodes
.begin(); 
2169             if ( Walker(*i
, func
) ) 
2177 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem 
& parent
, const wxDataViewItem 
& item
) 
2179     if (IsVirtualList()) 
2181         wxDataViewVirtualListModel 
*list_model 
= 
2182             (wxDataViewVirtualListModel
*) GetModel(); 
2183         m_count 
= list_model
->GetCount(); 
2189         wxDataViewTreeNode 
*parentNode 
= FindNode(parent
); 
2194         wxDataViewItemArray modelSiblings
; 
2195         GetModel()->GetChildren(parent
, modelSiblings
); 
2196         const int modelSiblingsSize 
= modelSiblings
.size(); 
2198         int posInModel 
= modelSiblings
.Index(item
, /*fromEnd=*/true); 
2199         wxCHECK_MSG( posInModel 
!= wxNOT_FOUND
, false, "adding non-existent item?" ); 
2201         wxDataViewTreeNode 
*itemNode 
= new wxDataViewTreeNode(parentNode
, item
); 
2202         itemNode
->SetHasChildren(GetModel()->IsContainer(item
)); 
2204         parentNode
->SetHasChildren(true); 
2206         const wxDataViewTreeNodes
& nodeSiblings 
= parentNode
->GetChildNodes(); 
2207         const int nodeSiblingsSize 
= nodeSiblings
.size(); 
2211         if ( posInModel 
== modelSiblingsSize 
- 1 ) 
2213             nodePos 
= nodeSiblingsSize
; 
2215         else if ( modelSiblingsSize 
== nodeSiblingsSize 
+ 1 ) 
2217             // This is the simple case when our node tree already matches the 
2218             // model and only this one item is missing. 
2219             nodePos 
= posInModel
; 
2223             // It's possible that a larger discrepancy between the model and 
2224             // our realization exists. This can happen e.g. when adding a bunch 
2225             // of items to the model and then calling ItemsAdded() just once 
2226             // afterwards. In this case, we must find the right position by 
2227             // looking at sibling items. 
2229             // append to the end if we won't find a better position: 
2230             nodePos 
= nodeSiblingsSize
; 
2232             for ( int nextItemPos 
= posInModel 
+ 1; 
2233                   nextItemPos 
< modelSiblingsSize
; 
2236                 int nextNodePos 
= parentNode
->FindChildByItem(modelSiblings
[nextItemPos
]); 
2237                 if ( nextNodePos 
!= wxNOT_FOUND 
) 
2239                     nodePos 
= nextNodePos
; 
2245         parentNode
->ChangeSubTreeCount(+1); 
2246         parentNode
->InsertChild(itemNode
, nodePos
); 
2251     GetOwner()->InvalidateColBestWidths(); 
2257 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem
& parent
, 
2258                                        const wxDataViewItem
& item
) 
2260     if (IsVirtualList()) 
2262         wxDataViewVirtualListModel 
*list_model 
= 
2263             (wxDataViewVirtualListModel
*) GetModel(); 
2264         m_count 
= list_model
->GetCount(); 
2266         if ( !m_selection
.empty() ) 
2268             const int row 
= GetRowByItem(item
); 
2270             int rowIndexInSelection 
= wxNOT_FOUND
; 
2272             const size_t selCount 
= m_selection
.size(); 
2273             for ( size_t i 
= 0; i 
< selCount
; i
++ ) 
2275                 if ( m_selection
[i
] == (unsigned)row 
) 
2276                     rowIndexInSelection 
= i
; 
2277                 else if ( m_selection
[i
] > (unsigned)row 
) 
2281             if ( rowIndexInSelection 
!= wxNOT_FOUND 
) 
2282                 m_selection
.RemoveAt(rowIndexInSelection
); 
2286     else // general case 
2288         wxDataViewTreeNode 
*parentNode 
= FindNode(parent
); 
2290         // Notice that it is possible that the item being deleted is not in the 
2291         // tree at all, for example we could be deleting a never shown (because 
2292         // collapsed) item in a tree model. So it's not an error if we don't know 
2293         // about this item, just return without doing anything then. 
2297         wxCHECK_MSG( parentNode
->HasChildren(), false, "parent node doesn't have children?" ); 
2298         const wxDataViewTreeNodes
& parentsChildren 
= parentNode
->GetChildNodes(); 
2300         // We can't use FindNode() to find 'item', because it was already 
2301         // removed from the model by the time ItemDeleted() is called, so we 
2302         // have to do it manually. We keep track of its position as well for 
2304         int itemPosInNode 
= 0; 
2305         wxDataViewTreeNode 
*itemNode 
= NULL
; 
2306         for ( wxDataViewTreeNodes::const_iterator i 
= parentsChildren
.begin(); 
2307               i 
!= parentsChildren
.end(); 
2308               ++i
, ++itemPosInNode 
) 
2310             if( (*i
)->GetItem() == item 
) 
2317         // If the parent wasn't expanded, it's possible that we didn't have a 
2318         // node corresponding to 'item' and so there's nothing left to do. 
2321             // If this was the last child to be removed, it's possible the parent 
2322             // node became a leaf. Let's ask the model about it. 
2323             if ( parentNode
->GetChildNodes().empty() ) 
2324                 parentNode
->SetHasChildren(GetModel()->IsContainer(parent
)); 
2329         // Delete the item from wxDataViewTreeNode representation: 
2330         const int itemsDeleted 
= 1 + itemNode
->GetSubTreeCount(); 
2332         parentNode
->RemoveChild(itemNode
); 
2334         parentNode
->ChangeSubTreeCount(-itemsDeleted
); 
2336         // Make the row number invalid and get a new valid one when user call GetRowCount 
2339         // If this was the last child to be removed, it's possible the parent 
2340         // node became a leaf. Let's ask the model about it. 
2341         if ( parentNode
->GetChildNodes().empty() ) 
2343             bool isContainer 
= GetModel()->IsContainer(parent
); 
2344             parentNode
->SetHasChildren(isContainer
); 
2347                 // If it's still a container, make sure we show "+" icon for it 
2348                 // and not "-" one as there is nothing to collapse any more. 
2349                 if ( parentNode
->IsOpen() ) 
2350                     parentNode
->ToggleOpen(); 
2354         // Update selection by removing 'item' and its entire children tree from the selection. 
2355         if ( !m_selection
.empty() ) 
2357             // we can't call GetRowByItem() on 'item', as it's already deleted, so compute it from 
2358             // the parent ('parentNode') and position in its list of children 
2360             if ( itemPosInNode 
== 0 ) 
2362                 // 1st child, row number is that of the parent parentNode + 1 
2363                 itemRow 
= GetRowByItem(parentNode
->GetItem()) + 1; 
2367                 // row number is that of the sibling above 'item' + its subtree if any + 1 
2368                 const wxDataViewTreeNode 
*siblingNode 
= parentNode
->GetChildNodes()[itemPosInNode 
- 1]; 
2370                 itemRow 
= GetRowByItem(siblingNode
->GetItem()) + 
2371                           siblingNode
->GetSubTreeCount() + 
2375             wxDataViewSelection 
newsel(wxDataViewSelectionCmp
); 
2377             const size_t numSelections 
= m_selection
.size(); 
2378             for ( size_t i 
= 0; i 
< numSelections
; ++i 
) 
2380                 const int s 
= m_selection
[i
]; 
2382                     newsel
.push_back(s
); 
2383                 else if ( s 
>= itemRow 
+ itemsDeleted 
) 
2384                     newsel
.push_back(s 
- itemsDeleted
); 
2385                 // else: deleted item, remove from selection 
2388             m_selection 
= newsel
; 
2392     // Change the current row to the last row if the current exceed the max row number 
2393     if( m_currentRow 
> GetRowCount() ) 
2394         ChangeCurrentRow(m_count 
- 1); 
2396     GetOwner()->InvalidateColBestWidths(); 
2402 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem 
& item
) 
2407     GetOwner()->InvalidateColBestWidths(); 
2410     wxWindow 
*parent 
= GetParent(); 
2411     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2412     le
.SetEventObject(parent
); 
2413     le
.SetModel(GetModel()); 
2415     parent
->ProcessWindowEvent(le
); 
2420 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem 
& item
, unsigned int model_column 
) 
2422     int view_column 
= -1; 
2423     unsigned int n_col 
= m_owner
->GetColumnCount(); 
2424     for (unsigned i 
= 0; i 
< n_col
; i
++) 
2426         wxDataViewColumn 
*column 
= m_owner
->GetColumn( i 
); 
2427         if (column
->GetModelColumn() == model_column
) 
2429             view_column 
= (int) i
; 
2433     if (view_column 
== -1) 
2436     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 
2437 /*#define MAX_VIRTUAL_WIDTH       100000 
2439     wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight ); 
2440     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); 
2441     Refresh( true, &rect ); 
2448     GetOwner()->InvalidateColBestWidth(view_column
); 
2451     wxWindow 
*parent 
= GetParent(); 
2452     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId()); 
2453     le
.SetEventObject(parent
); 
2454     le
.SetModel(GetModel()); 
2456     le
.SetColumn(view_column
); 
2457     le
.SetDataViewColumn(GetOwner()->GetColumn(view_column
)); 
2458     parent
->ProcessWindowEvent(le
); 
2463 bool wxDataViewMainWindow::Cleared() 
2466     m_selection
.Clear(); 
2471         BuildTree( GetModel() ); 
2478     GetOwner()->InvalidateColBestWidths(); 
2484 void wxDataViewMainWindow::UpdateDisplay() 
2487     m_underMouse 
= NULL
; 
2490 void wxDataViewMainWindow::OnInternalIdle() 
2492     wxWindow::OnInternalIdle(); 
2496         RecalculateDisplay(); 
2501 void wxDataViewMainWindow::RecalculateDisplay() 
2503     wxDataViewModel 
*model 
= GetModel(); 
2510     int width 
= GetEndOfLastCol(); 
2511     int height 
= GetLineStart( GetRowCount() ); 
2513     SetVirtualSize( width
, height 
); 
2514     GetOwner()->SetScrollRate( 10, m_lineHeight 
); 
2519 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
2521     m_underMouse 
= NULL
; 
2523     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
2525     if (GetOwner()->m_headerArea
) 
2526         GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 ); 
2529 void wxDataViewMainWindow::ScrollTo( int rows
, int column 
) 
2531     m_underMouse 
= NULL
; 
2534     m_owner
->GetScrollPixelsPerUnit( &x
, &y 
); 
2535     int sy 
= GetLineStart( rows 
)/y
; 
2539         wxRect rect 
= GetClientRect(); 
2543         m_owner
->CalcUnscrolledPosition( rect
.x
, rect
.y
, &xx
, &yy 
); 
2544         for (x_start 
= 0; colnum 
< column
; colnum
++) 
2546             wxDataViewColumn 
*col 
= GetOwner()->GetColumnAt(colnum
); 
2547             if (col
->IsHidden()) 
2548                 continue;      // skip it! 
2550             w 
= col
->GetWidth(); 
2554         int x_end 
= x_start 
+ w
; 
2555         xe 
= xx 
+ rect
.width
; 
2558             sx 
= ( xx 
+ x_end 
- xe 
)/x
; 
2565     m_owner
->Scroll( sx
, sy 
); 
2568 int wxDataViewMainWindow::GetCountPerPage() const 
2570     wxSize size 
= GetClientSize(); 
2571     return size
.y 
/ m_lineHeight
; 
2574 int wxDataViewMainWindow::GetEndOfLastCol() const 
2578     for (i 
= 0; i 
< GetOwner()->GetColumnCount(); i
++) 
2580         const wxDataViewColumn 
*c 
= 
2581             const_cast<wxDataViewCtrl
*>(GetOwner())->GetColumnAt( i 
); 
2584             width 
+= c
->GetWidth(); 
2589 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const 
2593     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
2595     return GetLineAt( y 
); 
2598 unsigned int wxDataViewMainWindow::GetLastVisibleRow() 
2600     wxSize client_size 
= GetClientSize(); 
2601     m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
, 
2602                                     &client_size
.x
, &client_size
.y 
); 
2604     // we should deal with the pixel here 
2605     unsigned int row 
= GetLineAt(client_size
.y
) - 1; 
2607     return wxMin( GetRowCount()-1, row 
); 
2610 unsigned int wxDataViewMainWindow::GetRowCount() const 
2612     if ( m_count 
== -1 ) 
2614         wxDataViewMainWindow
* const 
2615             self 
= const_cast<wxDataViewMainWindow
*>(this); 
2616         self
->m_count 
= RecalculateCount(); 
2617         self
->UpdateDisplay(); 
2622 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row 
) 
2629 void wxDataViewMainWindow::SelectAllRows( bool on 
) 
2636         m_selection
.Clear(); 
2637         for (unsigned int i 
= 0; i 
< GetRowCount(); i
++) 
2638             m_selection
.Add( i 
); 
2643         unsigned int first_visible 
= GetFirstVisibleRow(); 
2644         unsigned int last_visible 
= GetLastVisibleRow(); 
2646         for (i 
= 0; i 
< m_selection
.GetCount(); i
++) 
2648             unsigned int row 
= m_selection
[i
]; 
2649             if ((row 
>= first_visible
) && (row 
<= last_visible
)) 
2652         m_selection
.Clear(); 
2656 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on 
) 
2658     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2662             m_selection
.Add( row 
); 
2670             m_selection
.Remove( row 
); 
2676 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on 
) 
2680         unsigned int tmp 
= from
; 
2686     for (i 
= from
; i 
<= to
; i
++) 
2688         if (m_selection
.Index( i 
) == wxNOT_FOUND
) 
2691                 m_selection
.Add( i 
); 
2696                 m_selection
.Remove( i 
); 
2699     RefreshRows( from
, to 
); 
2702 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections 
) 
2704     for (size_t i
=0; i 
< aSelections
.GetCount(); i
++) 
2706         int n 
= aSelections
[i
]; 
2708         m_selection
.Add( n 
); 
2713 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row 
) 
2715     if (m_selection
.Index( row 
) == wxNOT_FOUND
) 
2716         m_selection
.Add( row 
); 
2718         m_selection
.Remove( row 
); 
2722 bool wxDataViewMainWindow::IsRowSelected( unsigned int row 
) 
2724     return (m_selection
.Index( row 
) != wxNOT_FOUND
); 
2727 void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem
& item
) 
2729     wxWindow 
*parent 
= GetParent(); 
2730     wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED
, parent
->GetId()); 
2732     le
.SetEventObject(parent
); 
2733     le
.SetModel(GetModel()); 
2736     parent
->ProcessWindowEvent(le
); 
2739 void wxDataViewMainWindow::RefreshRow( unsigned int row 
) 
2741     wxRect 
rect( 0, GetLineStart( row 
), GetEndOfLastCol(), GetLineHeight( row 
) ); 
2742     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2744     wxSize client_size 
= GetClientSize(); 
2745     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2746     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2747     if (intersect_rect
.width 
> 0) 
2748         Refresh( true, &intersect_rect 
); 
2751 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to 
) 
2755         unsigned int tmp 
= to
; 
2760     wxRect 
rect( 0, GetLineStart( from 
), GetEndOfLastCol(), GetLineStart( (to
-from
+1) ) ); 
2761     m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
2763     wxSize client_size 
= GetClientSize(); 
2764     wxRect 
client_rect( 0, 0, client_size
.x
, client_size
.y 
); 
2765     wxRect intersect_rect 
= client_rect
.Intersect( rect 
); 
2766     if (intersect_rect
.width 
> 0) 
2767         Refresh( true, &intersect_rect 
); 
2770 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow 
) 
2772     wxSize client_size 
= GetClientSize(); 
2773     int start 
= GetLineStart( firstRow 
); 
2774     m_owner
->CalcScrolledPosition( start
, 0, &start
, NULL 
); 
2775     if (start 
> client_size
.y
) return; 
2777     wxRect 
rect( 0, start
, client_size
.x
, client_size
.y 
- start 
); 
2779     Refresh( true, &rect 
); 
2782 wxRect 
wxDataViewMainWindow::GetLineRect( unsigned int row 
) const 
2786     rect
.y 
= GetLineStart( row 
); 
2787     rect
.width 
= GetEndOfLastCol(); 
2788     rect
.height 
= GetLineHeight( row 
); 
2793 int wxDataViewMainWindow::GetLineStart( unsigned int row 
) const 
2795     const wxDataViewModel 
*model 
= GetModel(); 
2797     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2799         // TODO make more efficient 
2804         for (r 
= 0; r 
< row
; r
++) 
2806             const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(r
); 
2807             if (!node
) return start
; 
2809             wxDataViewItem item 
= node
->GetItem(); 
2811             unsigned int cols 
= GetOwner()->GetColumnCount(); 
2813             int height 
= m_lineHeight
; 
2814             for (col 
= 0; col 
< cols
; col
++) 
2816                 const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2817                 if (column
->IsHidden()) 
2818                     continue;      // skip it! 
2821                     model
->IsContainer(item
) && 
2822                     !model
->HasContainerColumns(item
)) 
2823                     continue;      // skip it! 
2825                 wxDataViewRenderer 
*renderer 
= 
2826                     const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2827                 renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2829                 height 
= wxMax( height
, renderer
->GetSize().y 
); 
2839         return row 
* m_lineHeight
; 
2843 int wxDataViewMainWindow::GetLineAt( unsigned int y 
) const 
2845     const wxDataViewModel 
*model 
= GetModel(); 
2847     // check for the easy case first 
2848     if ( !GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT
) ) 
2849         return y 
/ m_lineHeight
; 
2851     // TODO make more efficient 
2852     unsigned int row 
= 0; 
2853     unsigned int yy 
= 0; 
2856         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2859             // not really correct... 
2860             return row 
+ ((y
-yy
) / m_lineHeight
); 
2863         wxDataViewItem item 
= node
->GetItem(); 
2865         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2867         int height 
= m_lineHeight
; 
2868         for (col 
= 0; col 
< cols
; col
++) 
2870             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2871             if (column
->IsHidden()) 
2872                 continue;      // skip it! 
2875                 model
->IsContainer(item
) && 
2876                 !model
->HasContainerColumns(item
)) 
2877                 continue;      // skip it! 
2879             wxDataViewRenderer 
*renderer 
= 
2880                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2881             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2883             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2894 int wxDataViewMainWindow::GetLineHeight( unsigned int row 
) const 
2896     const wxDataViewModel 
*model 
= GetModel(); 
2898     if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
) 
2900         wxASSERT( !IsVirtualList() ); 
2902         const wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
2903         // wxASSERT( node ); 
2904         if (!node
) return m_lineHeight
; 
2906         wxDataViewItem item 
= node
->GetItem(); 
2908         int height 
= m_lineHeight
; 
2910         unsigned int cols 
= GetOwner()->GetColumnCount(); 
2912         for (col 
= 0; col 
< cols
; col
++) 
2914             const wxDataViewColumn 
*column 
= GetOwner()->GetColumn(col
); 
2915             if (column
->IsHidden()) 
2916                 continue;      // skip it! 
2919                 model
->IsContainer(item
) && 
2920                 !model
->HasContainerColumns(item
)) 
2921                 continue;      // skip it! 
2923             wxDataViewRenderer 
*renderer 
= 
2924                 const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
2925             renderer
->PrepareForItem(model
, item
, column
->GetModelColumn()); 
2927             height 
= wxMax( height
, renderer
->GetSize().y 
); 
2934         return m_lineHeight
; 
2939 class RowToTreeNodeJob
: public DoJob
 
2942     RowToTreeNodeJob( unsigned int row 
, int current
, wxDataViewTreeNode 
* node 
) 
2945         this->current 
= current
; 
2950     virtual int operator() ( wxDataViewTreeNode 
* node 
) 
2953         if( current 
== static_cast<int>(row
)) 
2959         if( node
->GetSubTreeCount() + current 
< static_cast<int>(row
) ) 
2961             current 
+= node
->GetSubTreeCount(); 
2962             return  DoJob::SKIP_SUBTREE
; 
2968             // If the current node has only leaf children, we can find the 
2969             // desired node directly. This can speed up finding the node 
2970             // in some cases, and will have a very good effect for list views. 
2971             if ( node
->HasChildren() && 
2972                  (int)node
->GetChildNodes().size() == node
->GetSubTreeCount() ) 
2974                 const int index 
= static_cast<int>(row
) - current 
- 1; 
2975                 ret 
= node
->GetChildNodes()[index
]; 
2979             return DoJob::CONTINUE
; 
2983     wxDataViewTreeNode 
* GetResult() const 
2989     wxDataViewTreeNode 
* ret
; 
2990     wxDataViewTreeNode 
* parent
; 
2993 wxDataViewTreeNode 
* wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row
) const 
2995     wxASSERT( !IsVirtualList() ); 
2997     RowToTreeNodeJob 
job( row 
, -2, m_root 
); 
2998     Walker( m_root 
, job 
); 
2999     return job
.GetResult(); 
3002 wxDataViewItem 
wxDataViewMainWindow::GetItemByRow(unsigned int row
) const 
3004     wxDataViewItem item
; 
3005     if (IsVirtualList()) 
3007         if ( row 
< GetRowCount() ) 
3008             item 
= wxDataViewItem(wxUIntToPtr(row
+1)); 
3012         wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
3014             item 
= node
->GetItem(); 
3021 wxDataViewMainWindow::SendExpanderEvent(wxEventType type
, 
3022                                         const wxDataViewItem
& item
) 
3024     wxWindow 
*parent 
= GetParent(); 
3025     wxDataViewEvent 
le(type
, parent
->GetId()); 
3027     le
.SetEventObject(parent
); 
3028     le
.SetModel(GetModel()); 
3031     return !parent
->ProcessWindowEvent(le
) || le
.IsAllowed(); 
3034 bool wxDataViewMainWindow::IsExpanded( unsigned int row 
) const 
3039     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
3043     if (!node
->HasChildren()) 
3046     return node
->IsOpen(); 
3049 bool wxDataViewMainWindow::HasChildren( unsigned int row 
) const 
3054     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
3058     if (!node
->HasChildren()) 
3064 void wxDataViewMainWindow::Expand( unsigned int row 
) 
3069     wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(row
); 
3073     if (!node
->HasChildren()) 
3076             if (!node
->IsOpen()) 
3078                 if ( !SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING
, node
->GetItem()) ) 
3080                     // Vetoed by the event handler. 
3086                 // build the children of current node 
3087                 if( node
->GetChildNodes().empty() ) 
3090                     ::BuildTreeHelper(GetModel(), node
->GetItem(), node
); 
3093                 // By expanding the node all row indices that are currently in the selection list 
3094                 // and are greater than our node have become invalid. So we have to correct that now. 
3095                 const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
3096                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
3098                     const unsigned testRow 
= m_selection
[i
]; 
3099                     // all rows above us are not affected, so skip them 
3103                     m_selection
[i
] += rowAdjustment
; 
3106                 if(m_currentRow 
> row
) 
3107                     ChangeCurrentRow(m_currentRow 
+ rowAdjustment
); 
3111                 // Send the expanded event 
3112                 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED
,node
->GetItem()); 
3116 void wxDataViewMainWindow::Collapse(unsigned int row
) 
3121     wxDataViewTreeNode 
*node 
= GetTreeNodeByRow(row
); 
3125     if (!node
->HasChildren()) 
3130             if ( !SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING
,node
->GetItem()) ) 
3132                 // Vetoed by the event handler. 
3136             // Find out if there are selected items below the current node. 
3137             bool selectCollapsingRow 
= false; 
3138             const unsigned rowAdjustment 
= node
->GetSubTreeCount(); 
3139             unsigned maxRowToBeTested 
= row 
+ rowAdjustment
; 
3140             for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
3142                 const unsigned testRow 
= m_selection
[i
]; 
3143                 if(testRow 
> row 
&& testRow 
<= maxRowToBeTested
) 
3145                     selectCollapsingRow 
= true; 
3146                     // get out as soon as we have found a node that is selected 
3153             // If the node to be closed has selected items the user won't see those any longer. 
3154             // We select the collapsing node in this case. 
3155             if(selectCollapsingRow
) 
3157                 SelectAllRows(false); 
3158                 ChangeCurrentRow(row
); 
3159                 SelectRow(row
, true); 
3160                 SendSelectionChangedEvent(GetItemByRow(row
)); 
3164                 // if there were no selected items below our node we still need to "fix" the 
3165                 // selection list to adjust for the changing of the row indices. 
3166                 // We actually do the opposite of what we are doing in Expand(). 
3167                 for(unsigned i
=0; i
<m_selection
.size(); ++i
) 
3169                     const unsigned testRow 
= m_selection
[i
]; 
3170                     // all rows above us are not affected, so skip them 
3174                     m_selection
[i
] -= rowAdjustment
; 
3177                 // if the "current row" is being collapsed away we change it to the current row ;-) 
3178                 if(m_currentRow 
> row 
&& m_currentRow 
<= maxRowToBeTested
) 
3179                     ChangeCurrentRow(row
); 
3180                 else if(m_currentRow 
> row
) 
3181                     ChangeCurrentRow(m_currentRow 
- rowAdjustment
); 
3186             SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED
,node
->GetItem()); 
3190 wxDataViewTreeNode 
* wxDataViewMainWindow::FindNode( const wxDataViewItem 
& item 
) 
3192     const wxDataViewModel 
* model 
= GetModel(); 
3199     // Compose the parent-chain for the item we are looking for 
3200     wxVector
<wxDataViewItem
> parentChain
; 
3201     wxDataViewItem 
it( item 
); 
3204         parentChain
.push_back(it
); 
3205         it 
= model
->GetParent(it
); 
3208     // Find the item along the parent-chain. 
3209     // This algorithm is designed to speed up the node-finding method 
3210     wxDataViewTreeNode
* node 
= m_root
; 
3211     for( unsigned iter 
= parentChain
.size()-1; ; --iter 
) 
3213         if( node
->HasChildren() ) 
3215             if( node
->GetChildNodes().empty() ) 
3217                 // Even though the item is a container, it doesn't have any 
3218                 // child nodes in the control's representation yet. We have 
3219                 // to realize its subtree now. 
3221                 ::BuildTreeHelper(model
, node
->GetItem(), node
); 
3224             const wxDataViewTreeNodes
& nodes 
= node
->GetChildNodes(); 
3227             for (unsigned i 
= 0; i 
< nodes
.GetCount(); ++i
) 
3229                 wxDataViewTreeNode
* currentNode 
= nodes
[i
]; 
3230                 if (currentNode
->GetItem() == parentChain
[iter
]) 
3232                     if (currentNode
->GetItem() == item
) 
3252 void wxDataViewMainWindow::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
3253                                     wxDataViewColumn
* &column 
) 
3255     wxDataViewColumn 
*col 
= NULL
; 
3256     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3257     unsigned int colnum 
= 0; 
3259     m_owner
->CalcUnscrolledPosition( point
.x
, point
.y
, &x
, &y 
); 
3260     for (unsigned x_start 
= 0; colnum 
< cols
; colnum
++) 
3262         col 
= GetOwner()->GetColumnAt(colnum
); 
3263         if (col
->IsHidden()) 
3264             continue;      // skip it! 
3266         unsigned int w 
= col
->GetWidth(); 
3267         if (x_start
+w 
>= (unsigned int)x
) 
3274     item 
= GetItemByRow( GetLineAt( y 
) ); 
3277 wxRect 
wxDataViewMainWindow::GetItemRect( const wxDataViewItem 
& item
, 
3278                                           const wxDataViewColumn
* column 
) 
3283     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3284     // If column is null the loop will compute the combined width of all columns. 
3285     // Otherwise, it will compute the x position of the column we are looking for. 
3286     for (unsigned int i 
= 0; i 
< cols
; i
++) 
3288         wxDataViewColumn
* col 
= GetOwner()->GetColumnAt( i 
); 
3293         if (col
->IsHidden()) 
3294             continue;      // skip it! 
3296         xpos 
+= col
->GetWidth(); 
3297         width 
+= col
->GetWidth(); 
3302         // If we have a column, we need can get its width directly. 
3303         if(column
->IsHidden()) 
3306             width 
= column
->GetWidth(); 
3311         // If we have no column, we reset the x position back to zero. 
3315     // we have to take an expander column into account and compute its indentation 
3316     // to get the correct x position where the actual text is 
3318     int row 
= GetRowByItem(item
); 
3320             (column 
== 0 || GetExpanderColumnOrFirstOne(GetOwner()) == column
) ) 
3322         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(row
); 
3323         indent 
= GetOwner()->GetIndent() * node
->GetIndentLevel(); 
3324         indent 
= indent 
+ m_lineHeight
; // use m_lineHeight as the width of the expander 
3327     wxRect 
itemRect( xpos 
+ indent
, 
3328                      GetLineStart( row 
), 
3330                      GetLineHeight( row 
) ); 
3332     GetOwner()->CalcScrolledPosition(  itemRect
.x
,  itemRect
.y
, 
3333                                       &itemRect
.x
, &itemRect
.y 
); 
3338 int wxDataViewMainWindow::RecalculateCount() const 
3340     if (IsVirtualList()) 
3342         wxDataViewVirtualListModel 
*list_model 
= 
3343             (wxDataViewVirtualListModel
*) GetModel(); 
3345         return list_model
->GetCount(); 
3349         return m_root
->GetSubTreeCount(); 
3353 class ItemToRowJob 
: public DoJob
 
3356     ItemToRowJob(const wxDataViewItem
& item_
, wxVector
<wxDataViewItem
>::reverse_iterator iter
) 
3363     // Maybe binary search will help to speed up this process 
3364     virtual int operator() ( wxDataViewTreeNode 
* node
) 
3367         if( node
->GetItem() == item 
) 
3372         if( node
->GetItem() == *m_iter 
) 
3375             return DoJob::CONTINUE
; 
3379             ret 
+= node
->GetSubTreeCount(); 
3380             return DoJob::SKIP_SUBTREE
; 
3385     // the row number is begin from zero 
3386     int GetResult() const 
3390     wxVector
<wxDataViewItem
>::reverse_iterator m_iter
; 
3391     wxDataViewItem item
; 
3396 int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem 
& item
) const 
3398     const wxDataViewModel 
* model 
= GetModel(); 
3402     if (IsVirtualList()) 
3404         return wxPtrToUInt( item
.GetID() ) -1; 
3411         // Compose the parent-chain of the item we are looking for 
3412         wxVector
<wxDataViewItem
> parentChain
; 
3413         wxDataViewItem 
it( item 
); 
3416             parentChain
.push_back(it
); 
3417             it 
= model
->GetParent(it
); 
3420         // add an 'invalid' item to represent our 'invisible' root node 
3421         parentChain
.push_back(wxDataViewItem()); 
3423         // the parent chain was created by adding the deepest parent first. 
3424         // so if we want to start at the root node, we have to iterate backwards through the vector 
3425         ItemToRowJob 
job( item
, parentChain
.rbegin() ); 
3426         Walker( m_root
, job 
); 
3427         return job
.GetResult(); 
3431 static void BuildTreeHelper( const wxDataViewModel 
* model
,  const wxDataViewItem 
& item
, 
3432                              wxDataViewTreeNode 
* node
) 
3434     if( !model
->IsContainer( item 
) ) 
3437     wxDataViewItemArray children
; 
3438     unsigned int num 
= model
->GetChildren( item
, children
); 
3440     for ( unsigned int index 
= 0; index 
< num
; index
++ ) 
3442         wxDataViewTreeNode 
*n 
= new wxDataViewTreeNode(node
, children
[index
]); 
3444         if( model
->IsContainer(children
[index
]) ) 
3445             n
->SetHasChildren( true ); 
3447         node
->InsertChild(n
, index
); 
3450     wxASSERT( node
->IsOpen() ); 
3451     node
->ChangeSubTreeCount(+num
); 
3454 void wxDataViewMainWindow::BuildTree(wxDataViewModel 
* model
) 
3458     if (GetModel()->IsVirtualListModel()) 
3464     m_root 
= wxDataViewTreeNode::CreateRootNode(); 
3466     // First we define a invalid item to fetch the top-level elements 
3467     wxDataViewItem item
; 
3469     BuildTreeHelper( model
, item
, m_root
); 
3473 void wxDataViewMainWindow::DestroyTree() 
3475     if (!IsVirtualList()) 
3483 wxDataViewMainWindow::FindColumnForEditing(const wxDataViewItem
& item
, wxDataViewCellMode mode
) 
3485     // Edit the current column editable in 'mode'. If no column is focused 
3486     // (typically because the user has full row selected), try to find the 
3487     // first editable column (this would typically be a checkbox for 
3488     // wxDATAVIEW_CELL_ACTIVATABLE and we don't want to force the user to set 
3489     // focus on the checkbox column; or on the only editable text column). 
3491     wxDataViewColumn 
*candidate 
= m_currentCol
; 
3494          !IsCellEditableInMode(item
, candidate
, mode
) && 
3495          !m_currentColSetByKeyboard 
) 
3497         // If current column was set by mouse to something not editable (in 
3498         // 'mode') and the user pressed Space/F2 to edit it, treat the 
3499         // situation as if there was whole-row focus, because that's what is 
3500         // visually indicated and the mouse click could very well be targeted 
3501         // on the row rather than on an individual cell. 
3503         // But if it was done by keyboard, respect that even if the column 
3504         // isn't editable, because focus is visually on that column and editing 
3505         // something else would be surprising. 
3511         const unsigned cols 
= GetOwner()->GetColumnCount(); 
3512         for ( unsigned i 
= 0; i 
< cols
; i
++ ) 
3514             wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt(i
); 
3515             if ( c
->IsHidden() ) 
3518             if ( IsCellEditableInMode(item
, c
, mode
) ) 
3526     // If on container item without columns, only the expander column 
3527     // may be directly editable: 
3529          GetOwner()->GetExpanderColumn() != candidate 
&& 
3530          GetModel()->IsContainer(item
) && 
3531          !GetModel()->HasContainerColumns(item
) ) 
3533         candidate 
= GetOwner()->GetExpanderColumn(); 
3539    if ( !IsCellEditableInMode(item
, candidate
, mode
) ) 
3545 bool wxDataViewMainWindow::IsCellEditableInMode(const wxDataViewItem
& item
, 
3546                                                 const wxDataViewColumn 
*col
, 
3547                                                 wxDataViewCellMode mode
) const 
3549     if ( col
->GetRenderer()->GetMode() != mode 
) 
3552     if ( !GetModel()->IsEnabled(item
, col
->GetModelColumn()) ) 
3558 void wxDataViewMainWindow::OnCharHook(wxKeyEvent
& event
) 
3562         // Handle any keys special for the in-place editor and return without 
3563         // calling Skip() below. 
3564         switch ( event
.GetKeyCode() ) 
3567                 m_editorRenderer
->CancelEditing(); 
3571                 m_editorRenderer
->FinishEditing(); 
3579 void wxDataViewMainWindow::OnChar( wxKeyEvent 
&event 
) 
3581     wxWindow 
* const parent 
= GetParent(); 
3583     // propagate the char event upwards 
3584     wxKeyEvent 
eventForParent(event
); 
3585     eventForParent
.SetEventObject(parent
); 
3586     if ( parent
->ProcessWindowEvent(eventForParent
) ) 
3589     if ( parent
->HandleAsNavigationKey(event
) ) 
3592     // no item -> nothing to do 
3593     if (!HasCurrentRow()) 
3599     // don't use m_linesPerPage directly as it might not be computed yet 
3600     const int pageSize 
= GetCountPerPage(); 
3601     wxCHECK_RET( pageSize
, wxT("should have non zero page size") ); 
3603     switch ( event
.GetKeyCode() ) 
3606             if ( event
.HasModifiers() ) 
3613                 // Enter activates the item, i.e. sends wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED to 
3614                 // it. Only if that event is not handled do we activate column renderer (which 
3615                 // is normally done by Space) or even inline editing. 
3617                 const wxDataViewItem item 
= GetItemByRow(m_currentRow
); 
3619                 wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, 
3622                 le
.SetEventObject(parent
); 
3623                 le
.SetModel(GetModel()); 
3625                 if ( parent
->ProcessWindowEvent(le
) ) 
3627                 // else: fall through to WXK_SPACE handling 
3631             if ( event
.HasModifiers() ) 
3638                 // Space toggles activatable items or -- if not activatable -- 
3639                 // starts inline editing (this is normally done using F2 on 
3640                 // Windows, but Space is common everywhere else, so use it too 
3641                 // for greater cross-platform compatibility). 
3643                 const wxDataViewItem item 
= GetItemByRow(m_currentRow
); 
3645                 // Activate the current activatable column. If not column is focused (typically 
3646                 // because the user has full row selected), try to find the first activatable 
3647                 // column (this would typically be a checkbox and we don't want to force the user 
3648                 // to set focus on the checkbox column). 
3649                 wxDataViewColumn 
*activatableCol 
= FindColumnForEditing(item
, wxDATAVIEW_CELL_ACTIVATABLE
); 
3651                 if ( activatableCol 
) 
3653                     const unsigned colIdx 
= activatableCol
->GetModelColumn(); 
3654                     const wxRect cell_rect 
= GetOwner()->GetItemRect(item
, activatableCol
); 
3656                     wxDataViewRenderer 
*cell 
= activatableCol
->GetRenderer(); 
3657                     cell
->PrepareForItem(GetModel(), item
, colIdx
); 
3658                     cell
->WXActivateCell(cell_rect
, GetModel(), item
, colIdx
, NULL
); 
3662                 // else: fall through to WXK_F2 handling 
3666             if ( event
.HasModifiers() ) 
3673                 if( !m_selection
.empty() ) 
3675                     // Mimic Windows 7 behavior: edit the item that has focus 
3676                     // if it is selected and the first selected item if focus 
3677                     // is out of selection. 
3679                     if ( m_selection
.Index(m_currentRow
) != wxNOT_FOUND 
) 
3682                         sel 
= m_selection
[0]; 
3685                     const wxDataViewItem item 
= GetItemByRow(sel
); 
3687                     // Edit the current column. If no column is focused 
3688                     // (typically because the user has full row selected), try 
3689                     // to find the first editable column. 
3690                     wxDataViewColumn 
*editableCol 
= FindColumnForEditing(item
, wxDATAVIEW_CELL_EDITABLE
); 
3693                         GetOwner()->EditItem(item
, editableCol
); 
3699             if ( m_currentRow 
> 0 ) 
3700                 OnVerticalNavigation( m_currentRow 
- 1, event 
); 
3704             if ( m_currentRow 
+ 1 < GetRowCount() ) 
3705                 OnVerticalNavigation( m_currentRow 
+ 1, event 
); 
3707         // Add the process for tree expanding/collapsing 
3719                 OnVerticalNavigation( GetRowCount() - 1, event 
); 
3724                 OnVerticalNavigation( 0, event 
); 
3729                 int steps 
= pageSize 
- 1; 
3730                 int index 
= m_currentRow 
- steps
; 
3734                 OnVerticalNavigation( index
, event 
); 
3740                 int steps 
= pageSize 
- 1; 
3741                 unsigned int index 
= m_currentRow 
+ steps
; 
3742                 unsigned int count 
= GetRowCount(); 
3743                 if ( index 
>= count 
) 
3746                 OnVerticalNavigation( index
, event 
); 
3755 void wxDataViewMainWindow::OnVerticalNavigation(unsigned int newCurrent
, const wxKeyEvent
& event
) 
3757     wxCHECK_RET( newCurrent 
< GetRowCount(), 
3758                 wxT("invalid item index in OnVerticalNavigation()") ); 
3760     // if there is no selection, we cannot move it anywhere 
3761     if (!HasCurrentRow()) 
3764     unsigned int oldCurrent 
= m_currentRow
; 
3766     // in single selection we just ignore Shift as we can't select several 
3768     if ( event
.ShiftDown() && !IsSingleSel() ) 
3770         RefreshRow( oldCurrent 
); 
3772         ChangeCurrentRow( newCurrent 
); 
3774         // select all the items between the old and the new one 
3775         if ( oldCurrent 
> newCurrent 
) 
3777             newCurrent 
= oldCurrent
; 
3778             oldCurrent 
= m_currentRow
; 
3781         SelectRows( oldCurrent
, newCurrent
, true ); 
3782         if (oldCurrent
!=newCurrent
) 
3783             SendSelectionChangedEvent(GetItemByRow(m_selection
[0])); 
3787         RefreshRow( oldCurrent 
); 
3789         // all previously selected items are unselected unless ctrl is held 
3790         if ( !event
.ControlDown() ) 
3791             SelectAllRows(false); 
3793         ChangeCurrentRow( newCurrent 
); 
3795         if ( !event
.ControlDown() ) 
3797             SelectRow( m_currentRow
, true ); 
3798             SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
3801             RefreshRow( m_currentRow 
); 
3804     GetOwner()->EnsureVisible( m_currentRow
, -1 ); 
3807 void wxDataViewMainWindow::OnLeftKey() 
3811         TryAdvanceCurrentColumn(NULL
, /*forward=*/false); 
3815         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(m_currentRow
); 
3817         if ( TryAdvanceCurrentColumn(node
, /*forward=*/false) ) 
3820         // Because TryAdvanceCurrentColumn() return false, we are at the first 
3821         // column or using whole-row selection. In this situation, we can use 
3822         // the standard TreeView handling of the left key. 
3823         if (node
->HasChildren() && node
->IsOpen()) 
3825             Collapse(m_currentRow
); 
3829             // if the node is already closed, we move the selection to its parent 
3830             wxDataViewTreeNode 
*parent_node 
= node
->GetParent(); 
3834                 int parent 
= GetRowByItem( parent_node
->GetItem() ); 
3837                     unsigned int row 
= m_currentRow
; 
3838                     SelectRow( row
, false); 
3839                     SelectRow( parent
, true ); 
3840                     ChangeCurrentRow( parent 
); 
3841                     GetOwner()->EnsureVisible( parent
, -1 ); 
3842                     SendSelectionChangedEvent( parent_node
->GetItem() ); 
3849 void wxDataViewMainWindow::OnRightKey() 
3853         TryAdvanceCurrentColumn(NULL
, /*forward=*/true); 
3857         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(m_currentRow
); 
3859         if ( node
->HasChildren() ) 
3861             if ( !node
->IsOpen() ) 
3863                 Expand( m_currentRow 
); 
3867                 // if the node is already open, we move the selection to the first child 
3868                 unsigned int row 
= m_currentRow
; 
3869                 SelectRow( row
, false ); 
3870                 SelectRow( row 
+ 1, true ); 
3871                 ChangeCurrentRow( row 
+ 1 ); 
3872                 GetOwner()->EnsureVisible( row 
+ 1, -1 ); 
3873                 SendSelectionChangedEvent( GetItemByRow(row
+1) ); 
3878             TryAdvanceCurrentColumn(node
, /*forward=*/true); 
3883 bool wxDataViewMainWindow::TryAdvanceCurrentColumn(wxDataViewTreeNode 
*node
, bool forward
) 
3885     if ( GetOwner()->GetColumnCount() == 0 ) 
3888     if ( !m_useCellFocus 
) 
3893         // navigation shouldn't work in branch nodes without other columns: 
3894         if ( node
->HasChildren() && !GetModel()->HasContainerColumns(node
->GetItem()) ) 
3898     if ( m_currentCol 
== NULL 
|| !m_currentColSetByKeyboard 
) 
3902             m_currentCol 
= GetOwner()->GetColumnAt(1); 
3903             m_currentColSetByKeyboard 
= true; 
3904             RefreshRow(m_currentRow
); 
3911     int idx 
= GetOwner()->GetColumnIndex(m_currentCol
) + (forward 
? +1 : -1); 
3913     if ( idx 
>= (int)GetOwner()->GetColumnCount() ) 
3916     GetOwner()->EnsureVisible(m_currentRow
, idx
); 
3920         // We are going to the left of the second column. Reset to whole-row 
3921         // focus (which means first column would be edited). 
3922         m_currentCol 
= NULL
; 
3923         RefreshRow(m_currentRow
); 
3927     m_currentCol 
= GetOwner()->GetColumnAt(idx
); 
3928     m_currentColSetByKeyboard 
= true; 
3929     RefreshRow(m_currentRow
); 
3933 void wxDataViewMainWindow::OnMouse( wxMouseEvent 
&event 
) 
3935     if (event
.GetEventType() == wxEVT_MOUSEWHEEL
) 
3937         // let the base handle mouse wheel events. 
3942     if(event
.LeftDown()) 
3944         // Not skipping this event would prevent the system from setting focus 
3949     int x 
= event
.GetX(); 
3950     int y 
= event
.GetY(); 
3951     m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y 
); 
3952     wxDataViewColumn 
*col 
= NULL
; 
3955     unsigned int cols 
= GetOwner()->GetColumnCount(); 
3957     for (i 
= 0; i 
< cols
; i
++) 
3959         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt( i 
); 
3961             continue;      // skip it! 
3963         if (x 
< xpos 
+ c
->GetWidth()) 
3968         xpos 
+= c
->GetWidth(); 
3971     wxDataViewModel
* const model 
= GetModel(); 
3973     const unsigned int current 
= GetLineAt( y 
); 
3974     const wxDataViewItem item 
= GetItemByRow(current
); 
3976     // Handle right clicking here, before everything else as context menu 
3977     // events should be sent even when we click outside of any item, unlike all 
3979     if (event
.RightUp()) 
3981         wxWindow 
*parent 
= GetParent(); 
3982         wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU
, parent
->GetId()); 
3983         le
.SetEventObject(parent
); 
3986         if ( item
.IsOk() && col 
) 
3989             le
.SetColumn( col
->GetModelColumn() ); 
3990             le
.SetDataViewColumn( col 
); 
3993             model
->GetValue( value
, item
, col
->GetModelColumn() ); 
3997         parent
->ProcessWindowEvent(le
); 
4007     wxDataViewRenderer 
*cell 
= col
->GetRenderer(); 
4008     if ((current 
>= GetRowCount()) || (x 
> GetEndOfLastCol())) 
4010         // Unselect all if below the last row ? 
4015     wxDataViewColumn
* const 
4016         expander 
= GetExpanderColumnOrFirstOne(GetOwner()); 
4018     // Test whether the mouse is hovering over the expander (a.k.a tree "+" 
4019     // button) and also determine the offset of the real cell start, skipping 
4020     // the indentation and the expander itself. 
4021     bool hoverOverExpander 
= false; 
4023     if ((!IsList()) && (expander 
== col
)) 
4025         wxDataViewTreeNode 
* node 
= GetTreeNodeByRow(current
); 
4027         int indent 
= node
->GetIndentLevel(); 
4028         itemOffset 
= GetOwner()->GetIndent()*indent
; 
4030         if ( node
->HasChildren() ) 
4032             // we make the rectangle we are looking in a bit bigger than the actual 
4033             // visual expander so the user can hit that little thing reliably 
4034             wxRect 
rect(itemOffset
, 
4035                         GetLineStart( current 
) + (GetLineHeight(current
) - m_lineHeight
)/2, 
4036                         m_lineHeight
, m_lineHeight
); 
4038             if( rect
.Contains(x
, y
) ) 
4040                 // So the mouse is over the expander 
4041                 hoverOverExpander 
= true; 
4042                 if (m_underMouse 
&& m_underMouse 
!= node
) 
4044                     // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
4045                     RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
4047                 if (m_underMouse 
!= node
) 
4049                     // wxLogMessage("Do the row: %d", current); 
4050                     RefreshRow(current
); 
4052                 m_underMouse 
= node
; 
4056         // Account for the expander as well, even if this item doesn't have it, 
4057         // its parent does so it still counts for the offset. 
4058         itemOffset 
+= m_lineHeight
; 
4060     if (!hoverOverExpander
) 
4062         if (m_underMouse 
!= NULL
) 
4064             // wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem())); 
4065             RefreshRow(GetRowByItem(m_underMouse
->GetItem())); 
4066             m_underMouse 
= NULL
; 
4070 #if wxUSE_DRAG_AND_DROP 
4071     if (event
.Dragging()) 
4073         if (m_dragCount 
== 0) 
4075             // we have to report the raw, physical coords as we want to be 
4076             // able to call HitTest(event.m_pointDrag) from the user code to 
4077             // get the item being dragged 
4078             m_dragStart 
= event
.GetPosition(); 
4083         if (m_dragCount 
!= 3) 
4086         if (event
.LeftIsDown()) 
4088             m_owner
->CalcUnscrolledPosition( m_dragStart
.x
, m_dragStart
.y
, 
4089                                              &m_dragStart
.x
, &m_dragStart
.y 
); 
4090             unsigned int drag_item_row 
= GetLineAt( m_dragStart
.y 
); 
4091             wxDataViewItem itemDragged 
= GetItemByRow( drag_item_row 
); 
4093             // Notify cell about drag 
4094             wxDataViewEvent 
event( wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG
, m_owner
->GetId() ); 
4095             event
.SetEventObject( m_owner 
); 
4096             event
.SetItem( itemDragged 
); 
4097             event
.SetModel( model 
); 
4098             if (!m_owner
->HandleWindowEvent( event 
)) 
4101             if (!event
.IsAllowed()) 
4104             wxDataObject 
*obj 
= event
.GetDataObject(); 
4108             wxDataViewDropSource 
drag( this, drag_item_row 
); 
4109             drag
.SetData( *obj 
); 
4110             /* wxDragResult res = */ drag
.DoDragDrop(event
.GetDragFlags()); 
4119 #endif // wxUSE_DRAG_AND_DROP 
4121     bool simulateClick 
= false; 
4123     if (event
.ButtonDClick()) 
4125         m_renameTimer
->Stop(); 
4126         m_lastOnSame 
= false; 
4129     bool ignore_other_columns 
= 
4130         ((expander 
!= col
) && 
4131         (model
->IsContainer(item
)) && 
4132         (!model
->HasContainerColumns(item
))); 
4134     if (event
.LeftDClick()) 
4136         if(hoverOverExpander
) 
4138             // a double click on the expander will be converted into a "simulated" normal click 
4139             simulateClick 
= true; 
4141         else if ( current 
== m_lineLastClicked 
) 
4143             wxWindow 
*parent 
= GetParent(); 
4144             wxDataViewEvent 
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId()); 
4146             le
.SetColumn( col
->GetModelColumn() ); 
4147             le
.SetDataViewColumn( col 
); 
4148             le
.SetEventObject(parent
); 
4149             le
.SetModel(GetModel()); 
4151             parent
->ProcessWindowEvent(le
); 
4156             // The first click was on another item, so don't interpret this as 
4157             // a double click, but as a simple click instead 
4158             simulateClick 
= true; 
4162     if (event
.LeftUp() && !hoverOverExpander
) 
4164         if (m_lineSelectSingleOnUp 
!= (unsigned int)-1) 
4166             // select single line 
4167             SelectAllRows( false ); 
4168             SelectRow( m_lineSelectSingleOnUp
, true ); 
4169             SendSelectionChangedEvent( GetItemByRow(m_lineSelectSingleOnUp
) ); 
4172         // If the user click the expander, we do not do editing even if the column 
4173         // with expander are editable 
4174         if (m_lastOnSame 
&& !ignore_other_columns
) 
4176             if ((col 
== m_currentCol
) && (current 
== m_currentRow
) && 
4177                 IsCellEditableInMode(item
, col
, wxDATAVIEW_CELL_EDITABLE
) ) 
4179                 m_renameTimer
->Start( 100, true ); 
4183         m_lastOnSame 
= false; 
4184         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
4186     else if(!event
.LeftUp()) 
4188         // This is necessary, because after a DnD operation in 
4189         // from and to ourself, the up event is swallowed by the 
4190         // DnD code. So on next non-up event (which means here and 
4191         // now) m_lineSelectSingleOnUp should be reset. 
4192         m_lineSelectSingleOnUp 
= (unsigned int)-1; 
4195     if (event
.RightDown()) 
4197         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
4198         m_lineLastClicked 
= current
; 
4200         // If the item is already selected, do not update the selection. 
4201         // Multi-selections should not be cleared if a selected item is clicked. 
4202         if (!IsRowSelected(current
)) 
4204             SelectAllRows(false); 
4205             const unsigned oldCurrent 
= m_currentRow
; 
4206             ChangeCurrentRow(current
); 
4207             SelectRow(m_currentRow
,true); 
4208             RefreshRow(oldCurrent
); 
4209             SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
4212     else if (event
.MiddleDown()) 
4216     if((event
.LeftDown() || simulateClick
) && hoverOverExpander
) 
4218         wxDataViewTreeNode
* node 
= GetTreeNodeByRow(current
); 
4220         // hoverOverExpander being true tells us that our node must be 
4221         // valid and have children. 
4222         // So we don't need any extra checks. 
4223         if( node
->IsOpen() ) 
4228     else if ((event
.LeftDown() || simulateClick
) && !hoverOverExpander
) 
4230         m_lineBeforeLastClicked 
= m_lineLastClicked
; 
4231         m_lineLastClicked 
= current
; 
4233         unsigned int oldCurrentRow 
= m_currentRow
; 
4234         bool oldWasSelected 
= IsRowSelected(m_currentRow
); 
4236         bool cmdModifierDown 
= event
.CmdDown(); 
4237         if ( IsSingleSel() || !(cmdModifierDown 
|| event
.ShiftDown()) ) 
4239             if ( IsSingleSel() || !IsRowSelected(current
) ) 
4241                 SelectAllRows( false ); 
4242                 ChangeCurrentRow(current
); 
4243                 SelectRow(m_currentRow
,true); 
4244                 SendSelectionChangedEvent(GetItemByRow( m_currentRow 
) ); 
4246             else // multi sel & current is highlighted & no mod keys 
4248                 m_lineSelectSingleOnUp 
= current
; 
4249                 ChangeCurrentRow(current
); // change focus 
4252         else // multi sel & either ctrl or shift is down 
4254             if (cmdModifierDown
) 
4256                 ChangeCurrentRow(current
); 
4257                 ReverseRowSelection(m_currentRow
); 
4258                 SendSelectionChangedEvent(GetItemByRow(m_currentRow
)); 
4260             else if (event
.ShiftDown()) 
4262                 ChangeCurrentRow(current
); 
4264                 unsigned int lineFrom 
= oldCurrentRow
, 
4267                 if ( lineTo 
< lineFrom 
) 
4270                     lineFrom 
= m_currentRow
; 
4273                 SelectRows(lineFrom
, lineTo
, true); 
4274                 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) ); 
4276             else // !ctrl, !shift 
4278                 // test in the enclosing if should make it impossible 
4279                 wxFAIL_MSG( wxT("how did we get here?") ); 
4283         if (m_currentRow 
!= oldCurrentRow
) 
4284             RefreshRow( oldCurrentRow 
); 
4286         wxDataViewColumn 
*oldCurrentCol 
= m_currentCol
; 
4288         // Update selection here... 
4290         m_currentColSetByKeyboard 
= false; 
4292         m_lastOnSame 
= !simulateClick 
&& ((col 
== oldCurrentCol
) && 
4293                         (current 
== oldCurrentRow
)) && oldWasSelected
; 
4295         // Call ActivateCell() after everything else as under GTK+ 
4296         if ( IsCellEditableInMode(item
, col
, wxDATAVIEW_CELL_ACTIVATABLE
) ) 
4298             // notify cell about click 
4299             cell
->PrepareForItem(model
, item
, col
->GetModelColumn()); 
4301             wxRect 
cell_rect( xpos 
+ itemOffset
, 
4302                               GetLineStart( current 
), 
4303                               col
->GetWidth() - itemOffset
, 
4304                               GetLineHeight( current 
) ); 
4306             // Report position relative to the cell's custom area, i.e. 
4307             // no the entire space as given by the control but the one 
4308             // used by the renderer after calculation of alignment etc. 
4310             // adjust the rectangle ourselves to account for the alignment 
4311             wxRect rectItem 
= cell_rect
; 
4312             const int align 
= cell
->GetAlignment(); 
4313             if ( align 
!= wxDVR_DEFAULT_ALIGNMENT 
) 
4315                 const wxSize size 
= cell
->GetSize(); 
4317                 if ( size
.x 
>= 0 && size
.x 
< cell_rect
.width 
) 
4319                     if ( align 
& wxALIGN_CENTER_HORIZONTAL 
) 
4320                         rectItem
.x 
+= (cell_rect
.width 
- size
.x
)/2; 
4321                     else if ( align 
& wxALIGN_RIGHT 
) 
4322                         rectItem
.x 
+= cell_rect
.width 
- size
.x
; 
4323                     // else: wxALIGN_LEFT is the default 
4326                 if ( size
.y 
>= 0 && size
.y 
< cell_rect
.height 
) 
4328                     if ( align 
& wxALIGN_CENTER_VERTICAL 
) 
4329                         rectItem
.y 
+= (cell_rect
.height 
- size
.y
)/2; 
4330                     else if ( align 
& wxALIGN_BOTTOM 
) 
4331                         rectItem
.y 
+= cell_rect
.height 
- size
.y
; 
4332                     // else: wxALIGN_TOP is the default 
4336             wxMouseEvent 
event2(event
); 
4337             event2
.m_x 
-= rectItem
.x
; 
4338             event2
.m_y 
-= rectItem
.y
; 
4339             m_owner
->CalcUnscrolledPosition(event2
.m_x
, event2
.m_y
, &event2
.m_x
, &event2
.m_y
); 
4341              /* ignore ret */ cell
->WXActivateCell
 
4346                                         col
->GetModelColumn(), 
4353 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent 
&event 
) 
4357     if (HasCurrentRow()) 
4363 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent 
&event 
) 
4367     if (HasCurrentRow()) 
4373 void wxDataViewMainWindow::OnColumnsCountChanged() 
4375     int editableCount 
= 0; 
4377     const unsigned cols 
= GetOwner()->GetColumnCount(); 
4378     for ( unsigned i 
= 0; i 
< cols
; i
++ ) 
4380         wxDataViewColumn 
*c 
= GetOwner()->GetColumnAt(i
); 
4381         if ( c
->IsHidden() ) 
4383         if ( c
->GetRenderer()->GetMode() != wxDATAVIEW_CELL_INERT 
) 
4387     m_useCellFocus 
= (editableCount 
> 1); 
4392 //----------------------------------------------------------------------------- 
4394 //----------------------------------------------------------------------------- 
4396 WX_DEFINE_LIST(wxDataViewColumnList
) 
4398 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
) 
4399 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
) 
4400     EVT_SIZE(wxDataViewCtrl::OnSize
) 
4403 wxDataViewCtrl::~wxDataViewCtrl() 
4406         GetModel()->RemoveNotifier( m_notifier 
); 
4409     m_colsBestWidths
.clear(); 
4412 void wxDataViewCtrl::Init() 
4414     m_cols
.DeleteContents(true); 
4417     // No sorting column at start 
4418     m_sortingColumnIdx 
= wxNOT_FOUND
; 
4420     m_headerArea 
= NULL
; 
4422     m_colsDirty 
= false; 
4425 bool wxDataViewCtrl::Create(wxWindow 
*parent
, 
4430                             const wxValidator
& validator
, 
4431                             const wxString
& name
) 
4433 //    if ( (style & wxBORDER_MASK) == 0) 
4434 //        style |= wxBORDER_SUNKEN; 
4438     if (!wxControl::Create( parent
, id
, pos
, size
, 
4439                             style 
| wxScrolledWindowStyle
, validator
, name
)) 
4442     SetInitialSize(size
); 
4445     MacSetClipChildren( true ); 
4448     m_clientArea 
= new wxDataViewMainWindow( this, wxID_ANY 
); 
4450     // We use the cursor keys for moving the selection, not scrolling, so call 
4451     // this method to ensure wxScrollHelperEvtHandler doesn't catch all 
4452     // keyboard events forwarded to us from wxListMainWindow. 
4453     DisableKeyboardScrolling(); 
4455     if (HasFlag(wxDV_NO_HEADER
)) 
4456         m_headerArea 
= NULL
; 
4458         m_headerArea 
= new wxDataViewHeaderWindow(this); 
4460     SetTargetWindow( m_clientArea 
); 
4462     wxBoxSizer 
*sizer 
= new wxBoxSizer( wxVERTICAL 
); 
4464         sizer
->Add( m_headerArea
, 0, wxGROW 
); 
4465     sizer
->Add( m_clientArea
, 1, wxGROW 
); 
4471 wxBorder 
wxDataViewCtrl::GetDefaultBorder() const 
4473     return wxBORDER_THEME
; 
4477 WXLRESULT 
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
, 
4481     WXLRESULT rc 
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
); 
4484     // we need to process arrows ourselves for scrolling 
4485     if ( nMsg 
== WM_GETDLGCODE 
) 
4487         rc 
|= DLGC_WANTARROWS
; 
4495 wxSize 
wxDataViewCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
4497     wxSize newsize 
= size
; 
4498     if (!HasFlag(wxDV_NO_HEADER
) && (m_headerArea
)) 
4499     newsize
.y 
-= m_headerArea
->GetSize().y
; 
4504 void wxDataViewCtrl::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
4506     // We need to override OnSize so that our scrolled 
4507     // window a) does call Layout() to use sizers for 
4508     // positioning the controls but b) does not query 
4509     // the sizer for their size and use that for setting 
4510     // the scrollable area as set that ourselves by 
4511     // calling SetScrollbar() further down. 
4517     // We must redraw the headers if their height changed. Normally this 
4518     // shouldn't happen as the control shouldn't let itself be resized beneath 
4519     // its minimal height but avoid the display artefacts that appear if it 
4520     // does happen, e.g. because there is really not enough vertical space. 
4521     if ( !HasFlag(wxDV_NO_HEADER
) && m_headerArea 
&& 
4522             m_headerArea
->GetSize().y 
<= m_headerArea
->GetBestSize(). y 
) 
4524         m_headerArea
->Refresh(); 
4528 void wxDataViewCtrl::SetFocus() 
4531         m_clientArea
->SetFocus(); 
4534 bool wxDataViewCtrl::AssociateModel( wxDataViewModel 
*model 
) 
4536     if (!wxDataViewCtrlBase::AssociateModel( model 
)) 
4541         m_notifier 
= new wxGenericDataViewModelNotifier( m_clientArea 
); 
4542         model
->AddNotifier( m_notifier 
); 
4544     else if (m_notifier
) 
4546         m_notifier
->Cleared(); 
4550     m_clientArea
->DestroyTree(); 
4554         m_clientArea
->BuildTree(model
); 
4557     m_clientArea
->UpdateDisplay(); 
4562 #if wxUSE_DRAG_AND_DROP 
4564 bool wxDataViewCtrl::EnableDragSource( const wxDataFormat 
&format 
) 
4566     return m_clientArea
->EnableDragSource( format 
); 
4569 bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat 
&format 
) 
4571     return m_clientArea
->EnableDropTarget( format 
); 
4574 #endif // wxUSE_DRAG_AND_DROP 
4576 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn 
*col 
) 
4578     if (!wxDataViewCtrlBase::AppendColumn(col
)) 
4581     m_cols
.Append( col 
); 
4582     m_colsBestWidths
.push_back(CachedColWidthInfo()); 
4583     OnColumnsCountChanged(); 
4587 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn 
*col 
) 
4589     if (!wxDataViewCtrlBase::PrependColumn(col
)) 
4592     m_cols
.Insert( col 
); 
4593     m_colsBestWidths
.insert(m_colsBestWidths
.begin(), CachedColWidthInfo()); 
4594     OnColumnsCountChanged(); 
4598 bool wxDataViewCtrl::InsertColumn( unsigned int pos
, wxDataViewColumn 
*col 
) 
4600     if (!wxDataViewCtrlBase::InsertColumn(pos
,col
)) 
4603     m_cols
.Insert( pos
, col 
); 
4604     m_colsBestWidths
.insert(m_colsBestWidths
.begin() + pos
, CachedColWidthInfo()); 
4605     OnColumnsCountChanged(); 
4609 void wxDataViewCtrl::OnColumnChange(unsigned int idx
) 
4612         m_headerArea
->UpdateColumn(idx
); 
4614     m_clientArea
->UpdateDisplay(); 
4617 void wxDataViewCtrl::OnColumnsCountChanged() 
4620         m_headerArea
->SetColumnCount(GetColumnCount()); 
4622     m_clientArea
->OnColumnsCountChanged(); 
4625 void wxDataViewCtrl::DoSetExpanderColumn() 
4627     m_clientArea
->UpdateDisplay(); 
4630 void wxDataViewCtrl::DoSetIndent() 
4632     m_clientArea
->UpdateDisplay(); 
4635 unsigned int wxDataViewCtrl::GetColumnCount() const 
4637     return m_cols
.GetCount(); 
4640 bool wxDataViewCtrl::SetRowHeight( int lineHeight 
) 
4642     if ( !m_clientArea 
) 
4645     m_clientArea
->SetRowHeight(lineHeight
); 
4650 wxDataViewColumn
* wxDataViewCtrl::GetColumn( unsigned int idx 
) const 
4655 wxDataViewColumn 
*wxDataViewCtrl::GetColumnAt(unsigned int pos
) const 
4657     // columns can't be reordered if there is no header window which allows 
4659     const unsigned idx 
= m_headerArea 
? m_headerArea
->GetColumnsOrder()[pos
] 
4662     return GetColumn(idx
); 
4665 int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn 
*column
) const 
4667     const unsigned count 
= m_cols
.size(); 
4668     for ( unsigned n 
= 0; n 
< count
; n
++ ) 
4670         if ( m_cols
[n
] == column 
) 
4677 unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx
) const 
4679     if ( m_colsBestWidths
[idx
].width 
!= 0 ) 
4680         return m_colsBestWidths
[idx
].width
; 
4682     const int count 
= m_clientArea
->GetRowCount(); 
4683     wxDataViewColumn 
*column 
= GetColumn(idx
); 
4684     wxDataViewRenderer 
*renderer 
= 
4685         const_cast<wxDataViewRenderer
*>(column
->GetRenderer()); 
4687     class MaxWidthCalculator
 
4690         MaxWidthCalculator(const wxDataViewCtrl 
*dvc
, 
4691                            wxDataViewMainWindow 
*clientArea
, 
4692                            wxDataViewRenderer 
*renderer
, 
4693                            const wxDataViewModel 
*model
, 
4698               m_clientArea(clientArea
), 
4699               m_renderer(renderer
), 
4702               m_expanderSize(expanderSize
) 
4706                 !clientArea
->IsList() && 
4708                  GetExpanderColumnOrFirstOne(const_cast<wxDataViewCtrl
*>(dvc
)) == dvc
->GetColumnAt(column
)); 
4711         void UpdateWithWidth(int width
) 
4713             m_width 
= wxMax(m_width
, width
); 
4716         void UpdateWithRow(int row
) 
4719             wxDataViewItem item
; 
4721             if ( m_isExpanderCol 
) 
4723                 wxDataViewTreeNode 
*node 
= m_clientArea
->GetTreeNodeByRow(row
); 
4724                 item 
= node
->GetItem(); 
4725                 indent 
= m_dvc
->GetIndent() * node
->GetIndentLevel() + m_expanderSize
; 
4729                 item 
= m_clientArea
->GetItemByRow(row
); 
4732             m_renderer
->PrepareForItem(m_model
, item
, m_column
); 
4733             m_width 
= wxMax(m_width
, m_renderer
->GetSize().x 
+ indent
); 
4736         int GetMaxWidth() const { return m_width
; } 
4740         const wxDataViewCtrl 
*m_dvc
; 
4741         wxDataViewMainWindow 
*m_clientArea
; 
4742         wxDataViewRenderer 
*m_renderer
; 
4743         const wxDataViewModel 
*m_model
; 
4745         bool m_isExpanderCol
; 
4749     MaxWidthCalculator 
calculator(this, m_clientArea
, renderer
, 
4750                                   GetModel(), column
->GetModelColumn(), 
4751                                   m_clientArea
->GetRowHeight()); 
4753     calculator
.UpdateWithWidth(column
->GetMinWidth()); 
4756         calculator
.UpdateWithWidth(m_headerArea
->GetColumnTitleWidth(*column
)); 
4758     // The code below deserves some explanation. For very large controls, we 
4759     // simply can't afford to calculate sizes for all items, it takes too 
4760     // long. So the best we can do is to check the first and the last N/2 
4761     // items in the control for some sufficiently large N and calculate best 
4762     // sizes from that. That can result in the calculated best width being too 
4763     // small for some outliers, but it's better to get slightly imperfect 
4764     // result than to wait several seconds after every update. To avoid highly 
4765     // visible miscalculations, we also include all currently visible items 
4766     // no matter what.  Finally, the value of N is determined dynamically by 
4767     // measuring how much time we spent on the determining item widths so far. 
4770     int top_part_end 
= count
; 
4771     static const long CALC_TIMEOUT 
= 20/*ms*/; 
4772     // don't call wxStopWatch::Time() too often 
4773     static const unsigned CALC_CHECK_FREQ 
= 100; 
4776     // use some hard-coded limit, that's the best we can do without timer 
4777     int top_part_end 
= wxMin(500, count
); 
4778 #endif // wxUSE_STOPWATCH/!wxUSE_STOPWATCH 
4782     for ( row 
= 0; row 
< top_part_end
; row
++ ) 
4785         if ( row 
% CALC_CHECK_FREQ 
== CALC_CHECK_FREQ
-1 && 
4786              timer
.Time() > CALC_TIMEOUT 
) 
4788 #endif // wxUSE_STOPWATCH 
4789         calculator
.UpdateWithRow(row
); 
4792     // row is the first unmeasured item now; that's our value of N/2 
4798         // add bottom N/2 items now: 
4799         const int bottom_part_start 
= wxMax(row
, count 
- row
); 
4800         for ( row 
= bottom_part_start
; row 
< count
; row
++ ) 
4802             calculator
.UpdateWithRow(row
); 
4805         // finally, include currently visible items in the calculation: 
4806         const wxPoint origin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
4807         int first_visible 
= m_clientArea
->GetLineAt(origin
.y
); 
4808         int last_visible 
= m_clientArea
->GetLineAt(origin
.y 
+ GetClientSize().y
); 
4810         first_visible 
= wxMax(first_visible
, top_part_end
); 
4811         last_visible 
= wxMin(bottom_part_start
, last_visible
); 
4813         for ( row 
= first_visible
; row 
< last_visible
; row
++ ) 
4815             calculator
.UpdateWithRow(row
); 
4818         wxLogTrace("dataview", 
4819                    "determined best size from %d top, %d bottom plus %d more visible items out of %d total", 
4821                    count 
- bottom_part_start
, 
4822                    wxMax(0, last_visible 
- first_visible
), 
4826     int max_width 
= calculator
.GetMaxWidth(); 
4827     if ( max_width 
> 0 ) 
4828         max_width 
+= 2 * PADDING_RIGHTLEFT
; 
4830     const_cast<wxDataViewCtrl
*>(this)->m_colsBestWidths
[idx
].width 
= max_width
; 
4834 void wxDataViewCtrl::ColumnMoved(wxDataViewColumn 
* WXUNUSED(col
), 
4835                                 unsigned int WXUNUSED(new_pos
)) 
4837     // do _not_ reorder m_cols elements here, they should always be in the 
4838     // order in which columns were added, we only display the columns in 
4840     m_clientArea
->UpdateDisplay(); 
4843 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn 
*column 
) 
4845     wxDataViewColumnList::compatibility_iterator ret 
= m_cols
.Find( column 
); 
4849     m_colsBestWidths
.erase(m_colsBestWidths
.begin() + GetColumnIndex(column
)); 
4852     if ( m_clientArea
->GetCurrentColumn() == column 
) 
4853         m_clientArea
->ClearCurrentColumn(); 
4855     OnColumnsCountChanged(); 
4860 bool wxDataViewCtrl::ClearColumns() 
4862     SetExpanderColumn(NULL
); 
4864     m_colsBestWidths
.clear(); 
4866     m_clientArea
->ClearCurrentColumn(); 
4868     OnColumnsCountChanged(); 
4873 void wxDataViewCtrl::InvalidateColBestWidth(int idx
) 
4875     m_colsBestWidths
[idx
].width 
= 0; 
4876     m_colsBestWidths
[idx
].dirty 
= true; 
4880 void wxDataViewCtrl::InvalidateColBestWidths() 
4882     // mark all columns as dirty: 
4883     m_colsBestWidths
.clear(); 
4884     m_colsBestWidths
.resize(m_cols
.size()); 
4888 void wxDataViewCtrl::UpdateColWidths() 
4890     m_colsDirty 
= false; 
4892     if ( !m_headerArea 
) 
4895     const unsigned len 
= m_colsBestWidths
.size(); 
4896     for ( unsigned i 
= 0; i 
< len
; i
++ ) 
4898         // Note that we have to have an explicit 'dirty' flag here instead of 
4899         // checking if the width==0, as is done in GetBestColumnWidth(). 
4901         // Testing width==0 wouldn't work correctly if some code called 
4902         // GetWidth() after col. width invalidation but before 
4903         // wxDataViewCtrl::UpdateColWidths() was called at idle time. This 
4904         // would result in the header's column width getting out of sync with 
4905         // the control itself. 
4906         if ( m_colsBestWidths
[i
].dirty 
) 
4908             m_headerArea
->UpdateColumn(i
); 
4909             m_colsBestWidths
[i
].dirty 
= false; 
4914 void wxDataViewCtrl::OnInternalIdle() 
4916     wxDataViewCtrlBase::OnInternalIdle(); 
4922 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn 
*column 
) const 
4924     unsigned int len 
= GetColumnCount(); 
4925     for ( unsigned int i 
= 0; i 
< len
; i
++ ) 
4927         wxDataViewColumn 
* col 
= GetColumnAt(i
); 
4935 wxDataViewColumn 
*wxDataViewCtrl::GetSortingColumn() const 
4937     return m_sortingColumnIdx 
== wxNOT_FOUND 
? NULL
 
4938                                             : GetColumn(m_sortingColumnIdx
); 
4941 wxDataViewItem 
wxDataViewCtrl::DoGetCurrentItem() const 
4943     return GetItemByRow(m_clientArea
->GetCurrentRow()); 
4946 void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem
& item
) 
4948     const int row 
= m_clientArea
->GetRowByItem(item
); 
4950     const unsigned oldCurrent 
= m_clientArea
->GetCurrentRow(); 
4951     if ( static_cast<unsigned>(row
) != oldCurrent 
) 
4953         m_clientArea
->ChangeCurrentRow(row
); 
4954         m_clientArea
->RefreshRow(oldCurrent
); 
4955         m_clientArea
->RefreshRow(row
); 
4959 wxDataViewColumn 
*wxDataViewCtrl::GetCurrentColumn() const 
4961     return m_clientArea
->GetCurrentColumn(); 
4964 int wxDataViewCtrl::GetSelectedItemsCount() const 
4966     return m_clientArea
->GetSelections().size(); 
4969 int wxDataViewCtrl::GetSelections( wxDataViewItemArray 
& sel 
) const 
4972     const wxDataViewSelection
& selections 
= m_clientArea
->GetSelections(); 
4974     const size_t len 
= selections
.size(); 
4975     for ( size_t i 
= 0; i 
< len
; i
++ ) 
4977         wxDataViewItem item 
= m_clientArea
->GetItemByRow(selections
[i
]); 
4984             wxFAIL_MSG( "invalid item in selection - bad internal state" ); 
4991 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray 
& sel 
) 
4993     wxDataViewSelection 
selection(wxDataViewSelectionCmp
); 
4995     wxDataViewItem last_parent
; 
4997     int len 
= sel
.GetCount(); 
4998     for( int i 
= 0; i 
< len
; i 
++ ) 
5000         wxDataViewItem item 
= sel
[i
]; 
5001         wxDataViewItem parent 
= GetModel()->GetParent( item 
); 
5004             if (parent 
!= last_parent
) 
5005                 ExpandAncestors(item
); 
5008         last_parent 
= parent
; 
5009         int row 
= m_clientArea
->GetRowByItem( item 
); 
5011             selection
.Add( static_cast<unsigned int>(row
) ); 
5014     m_clientArea
->SetSelections( selection 
); 
5017 void wxDataViewCtrl::Select( const wxDataViewItem 
& item 
) 
5019     ExpandAncestors( item 
); 
5021     int row 
= m_clientArea
->GetRowByItem( item 
); 
5024         // Unselect all rows before select another in the single select mode 
5025         if (m_clientArea
->IsSingleSel()) 
5026             m_clientArea
->SelectAllRows(false); 
5028         m_clientArea
->SelectRow(row
, true); 
5030         // Also set focus to the selected item 
5031         m_clientArea
->ChangeCurrentRow( row 
); 
5035 void wxDataViewCtrl::Unselect( const wxDataViewItem 
& item 
) 
5037     int row 
= m_clientArea
->GetRowByItem( item 
); 
5039         m_clientArea
->SelectRow(row
, false); 
5042 bool wxDataViewCtrl::IsSelected( const wxDataViewItem 
& item 
) const 
5044     int row 
= m_clientArea
->GetRowByItem( item 
); 
5047         return m_clientArea
->IsRowSelected(row
); 
5052 void wxDataViewCtrl::SetAlternateRowColour(const wxColour
& colour
) 
5054     m_alternateRowColour 
= colour
; 
5057 void wxDataViewCtrl::SelectAll() 
5059     m_clientArea
->SelectAllRows(true); 
5062 void wxDataViewCtrl::UnselectAll() 
5064     m_clientArea
->SelectAllRows(false); 
5067 void wxDataViewCtrl::EnsureVisible( int row
, int column 
) 
5071     if( row 
> (int) m_clientArea
->GetRowCount() ) 
5072         row 
= m_clientArea
->GetRowCount(); 
5074     int first 
= m_clientArea
->GetFirstVisibleRow(); 
5075     int last 
= m_clientArea
->GetLastVisibleRow(); 
5077         m_clientArea
->ScrollTo( row
, column 
); 
5078     else if( row 
> last 
) 
5079         m_clientArea
->ScrollTo( row 
- last 
+ first
, column 
); 
5081         m_clientArea
->ScrollTo( first
, column 
); 
5084 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem 
& item
, const wxDataViewColumn 
* column 
) 
5086     ExpandAncestors( item 
); 
5088     m_clientArea
->RecalculateDisplay(); 
5090     int row 
= m_clientArea
->GetRowByItem(item
); 
5093         if( column 
== NULL 
) 
5094             EnsureVisible(row
, -1); 
5096             EnsureVisible( row
, GetColumnIndex(column
) ); 
5101 void wxDataViewCtrl::HitTest( const wxPoint 
& point
, wxDataViewItem 
& item
, 
5102                               wxDataViewColumn
* &column 
) const 
5104     m_clientArea
->HitTest(point
, item
, column
); 
5107 wxRect 
wxDataViewCtrl::GetItemRect( const wxDataViewItem 
& item
, 
5108                                     const wxDataViewColumn
* column 
) const 
5110     return m_clientArea
->GetItemRect(item
, column
); 
5113 wxDataViewItem 
wxDataViewCtrl::GetItemByRow( unsigned int row 
) const 
5115     return m_clientArea
->GetItemByRow( row 
); 
5118 int wxDataViewCtrl::GetRowByItem( const wxDataViewItem 
& item 
) const 
5120     return m_clientArea
->GetRowByItem( item 
); 
5123 void wxDataViewCtrl::Expand( const wxDataViewItem 
& item 
) 
5125     ExpandAncestors( item 
); 
5127     int row 
= m_clientArea
->GetRowByItem( item 
); 
5130         m_clientArea
->Expand(row
); 
5131         InvalidateColBestWidths(); 
5135 void wxDataViewCtrl::Collapse( const wxDataViewItem 
& item 
) 
5137     int row 
= m_clientArea
->GetRowByItem( item 
); 
5140         m_clientArea
->Collapse(row
); 
5141         InvalidateColBestWidths(); 
5145 bool wxDataViewCtrl::IsExpanded( const wxDataViewItem 
& item 
) const 
5147     int row 
= m_clientArea
->GetRowByItem( item 
); 
5149         return m_clientArea
->IsExpanded(row
); 
5153 void wxDataViewCtrl::EditItem(const wxDataViewItem
& item
, const wxDataViewColumn 
*column
) 
5155     wxCHECK_RET( item
.IsOk(), "invalid item" ); 
5156     wxCHECK_RET( column
, "no column provided" ); 
5158     m_clientArea
->StartEditing(item
, column
); 
5161 #endif // !wxUSE_GENERICDATAVIEWCTRL 
5163 #endif // wxUSE_DATAVIEWCTRL