1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/datavgen.cpp
3 // Purpose: wxDataViewCtrl generic implementation
4 // Author: Robert Roebling
5 // Modified by: Francesco Montorsi, Guru Kathiresan, Bo Yang
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_DATAVIEWCTRL
20 #include "wx/dataview.h"
22 #ifdef wxUSE_GENERICDATAVIEWCTRL
26 #include "wx/msw/private.h"
27 #include "wx/msw/wrapwin.h"
28 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
32 #include "wx/dcclient.h"
34 #include "wx/settings.h"
35 #include "wx/msgdlg.h"
36 #include "wx/dcscreen.h"
39 #include "wx/stockitem.h"
40 #include "wx/calctrl.h"
41 #include "wx/popupwin.h"
42 #include "wx/renderer.h"
43 #include "wx/dcbuffer.h"
46 #include "wx/listimpl.cpp"
47 #include "wx/imaglist.h"
49 //-----------------------------------------------------------------------------
51 //-----------------------------------------------------------------------------
55 static const int SCROLL_UNIT_X
= 15;
57 // the cell padding on the left/right
58 static const int PADDING_RIGHTLEFT
= 3;
60 // the expander space margin
61 static const int EXPANDER_MARGIN
= 4;
64 static const int EXPANDER_OFFSET
= 4;
66 static const int EXPANDER_OFFSET
= 1;
69 //-----------------------------------------------------------------------------
70 // wxDataViewHeaderWindow
71 //-----------------------------------------------------------------------------
73 // on wxMSW the header window (only that part however) can be made native!
74 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
75 #define USE_NATIVE_HEADER_WINDOW
77 #include "wx/headerctrl.h"
80 //Below is the compare stuff
81 //For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed
82 static wxDataViewModel
* g_model
;
83 static int g_column
= -2;
84 static bool g_asending
= true;
86 // NB: for some reason, this class must be dllexport'ed or we get warnings from
88 class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase
: public
89 #ifdef USE_NATIVE_HEADER_WINDOW
96 wxDataViewHeaderWindowBase()
99 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
100 const wxPoint
&pos
, const wxSize
&size
,
101 const wxString
&name
)
103 return wxWindow::Create(parent
, id
, pos
, size
, wxNO_BORDER
, name
);
106 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
107 wxDataViewCtrl
*GetOwner() { return m_owner
; }
109 // called on column addition/removal
110 virtual void UpdateDisplay() { /* by default, do nothing */ }
112 // returns the n-th column
113 virtual wxDataViewColumn
*GetColumn(unsigned int n
)
116 wxDataViewColumn
*ret
= m_owner
->GetColumn(n
);
123 wxDataViewCtrl
*m_owner
;
125 // sends an event generated from the n-th wxDataViewColumn
126 void SendEvent(wxEventType type
, unsigned int n
);
129 #ifdef USE_NATIVE_HEADER_WINDOW
131 #define COLUMN_WIDTH_OFFSET 2
132 #define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
134 class wxDataViewHeaderWindowMSW
: public wxDataViewHeaderWindowBase
137 wxDataViewHeaderWindowMSW(wxDataViewCtrl
*parent
)
142 bool Create(wxDataViewCtrl
*parent
);
144 // called when any column setting is changed and/or changed
146 virtual void UpdateDisplay();
148 virtual void OnInternalIdle();
150 // called Refresh afterwards
151 virtual void ScrollWindow(int dx
, int dy
, const wxRect
*rect
= NULL
);
153 virtual wxBorder
GetDefaultBorder() const { return wxBORDER_NONE
; }
156 virtual bool MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
);
158 virtual void DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
);
160 wxSize
DoGetBestSize() const;
162 unsigned int GetColumnIdxFromHeader(NMHEADER
*nmHDR
);
164 wxDataViewColumn
*GetColumnFromHeader(NMHEADER
*nmHDR
)
165 { return GetColumn(GetColumnIdxFromHeader(nmHDR
)); }
169 bool m_vetoColumnDrag
;
170 bool m_delayedUpdate
;
173 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW
)
176 #else // !defined(__WXMSW__)
178 #define HEADER_WINDOW_HEIGHT 25
179 #define HEADER_HORIZ_BORDER 5
180 #define HEADER_VERT_BORDER 3
181 #define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
183 class wxGenericDataViewHeaderWindow
: public wxDataViewHeaderWindowBase
186 wxGenericDataViewHeaderWindow( wxDataViewCtrl
*parent
,
187 wxWindowID id
= wxID_ANY
,
188 const wxPoint
&pos
= wxDefaultPosition
,
189 const wxSize
&size
= wxDefaultSize
,
190 const wxString
&name
= wxT("wxdataviewctrlheaderwindow") )
193 Create(parent
, id
, pos
, size
, name
);
196 bool Create(wxDataViewCtrl
*parent
, wxWindowID id
,
197 const wxPoint
&pos
, const wxSize
&size
,
198 const wxString
&name
);
200 ~wxGenericDataViewHeaderWindow()
202 delete m_resizeCursor
;
205 virtual void UpdateDisplay() { Refresh(); }
209 void OnPaint( wxPaintEvent
&event
);
210 void OnMouse( wxMouseEvent
&event
);
211 void OnSetFocus( wxFocusEvent
&event
);
216 // vars used for column resizing:
218 wxCursor
*m_resizeCursor
;
219 const wxCursor
*m_currentCursor
;
222 bool m_dirty
; // needs refresh?
223 int m_hover
; // index of the column under the mouse
224 int m_column
; // index of the column being resized
225 int m_currentX
; // divider line position in logical (unscrolled) coords
226 int m_minX
; // minimal position beyond which the divider line
227 // can't be dragged in logical coords
229 // the pen used to draw the current column width drag line
230 // when resizing the columsn
234 // internal utilities:
238 m_currentCursor
= (wxCursor
*) NULL
;
239 m_resizeCursor
= new wxCursor( wxCURSOR_SIZEWE
);
241 m_isDragging
= false;
244 m_hover
= wxNOT_FOUND
;
245 m_column
= wxNOT_FOUND
;
249 wxColour col
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
250 m_penCurrent
= wxPen(col
, 1, wxSOLID
);
253 void AdjustDC(wxDC
& dc
);
256 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow
)
257 DECLARE_EVENT_TABLE()
260 #endif // defined(__WXMSW__)
262 //-----------------------------------------------------------------------------
263 // wxDataViewRenameTimer
264 //-----------------------------------------------------------------------------
266 class wxDataViewRenameTimer
: public wxTimer
269 wxDataViewMainWindow
*m_owner
;
272 wxDataViewRenameTimer( wxDataViewMainWindow
*owner
);
276 //-----------------------------------------------------------------------------
277 // wxDataViewTreeNode
278 //-----------------------------------------------------------------------------
279 class wxDataViewTreeNode
;
280 WX_DEFINE_ARRAY( wxDataViewTreeNode
*, wxDataViewTreeNodes
);
281 WX_DEFINE_ARRAY( void* , wxDataViewTreeLeaves
);
283 int LINKAGEMODE
wxGenericTreeModelNodeCmp( wxDataViewTreeNode
** node1
, wxDataViewTreeNode
** node2
);
284 int LINKAGEMODE
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
);
286 class wxDataViewTreeNode
289 wxDataViewTreeNode( wxDataViewTreeNode
* parent
= NULL
)
296 m_hasChildren
= false;
300 ~wxDataViewTreeNode()
304 wxDataViewTreeNode
* GetParent() const { return m_parent
; }
305 void SetParent( wxDataViewTreeNode
* parent
) { m_parent
= parent
; }
306 wxDataViewTreeNodes
& GetNodes() { return m_nodes
; }
307 wxDataViewTreeLeaves
& GetChildren() { return m_leaves
; }
309 void AddNode( wxDataViewTreeNode
* node
)
311 m_leaves
.Add( node
->GetItem().GetID() );
313 m_leaves
.Sort( &wxGenericTreeModelItemCmp
);
316 m_nodes
.Sort( &wxGenericTreeModelNodeCmp
);
318 void AddLeaf( void * leaf
)
320 m_leaves
.Add( leaf
);
322 m_leaves
.Sort( &wxGenericTreeModelItemCmp
);
325 wxDataViewItem
& GetItem() { return m_item
; }
326 const wxDataViewItem
& GetItem() const { return m_item
; }
327 void SetItem( const wxDataViewItem
& item
) { m_item
= item
; }
329 unsigned int GetChildrenNumber() const { return m_leaves
.GetCount(); }
330 unsigned int GetNodeNumber() const { return m_nodes
.GetCount(); }
331 int GetIndentLevel() const
334 const wxDataViewTreeNode
* node
= this;
335 while( node
->GetParent()->GetParent() != NULL
)
337 node
= node
->GetParent();
350 int len
= m_nodes
.GetCount();
352 for ( int i
= 0;i
< len
; i
++)
353 sum
+= m_nodes
[i
]->GetSubTreeCount();
355 sum
+= m_leaves
.GetCount();
358 ChangeSubTreeCount(-sum
);
364 ChangeSubTreeCount(sum
);
367 bool HasChildren() const { return m_hasChildren
; }
368 void SetHasChildren( bool has
){ m_hasChildren
= has
; }
370 void SetSubTreeCount( int num
) { m_subTreeCount
= num
; }
371 int GetSubTreeCount() const { return m_subTreeCount
; }
372 void ChangeSubTreeCount( int num
)
376 m_subTreeCount
+= num
;
378 m_parent
->ChangeSubTreeCount(num
);
385 m_nodes
.Sort( &wxGenericTreeModelNodeCmp
);
386 int len
= m_nodes
.GetCount();
387 for (int i
= 0; i
< len
; i
++)
388 m_nodes
[i
]->Resort();
389 m_leaves
.Sort( &wxGenericTreeModelItemCmp
);
394 wxDataViewTreeNode
*m_parent
;
395 wxDataViewTreeNodes m_nodes
;
396 wxDataViewTreeLeaves m_leaves
;
397 wxDataViewItem m_item
;
403 int LINKAGEMODE
wxGenericTreeModelNodeCmp( wxDataViewTreeNode
** node1
, wxDataViewTreeNode
** node2
)
405 return g_model
->Compare( (*node1
)->GetItem(), (*node2
)->GetItem(), g_column
, g_asending
);
408 int LINKAGEMODE
wxGenericTreeModelItemCmp( void ** id1
, void ** id2
)
410 return g_model
->Compare( *id1
, *id2
, g_column
, g_asending
);
415 //-----------------------------------------------------------------------------
416 // wxDataViewMainWindow
417 //-----------------------------------------------------------------------------
419 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection
,
421 WX_DECLARE_LIST(wxDataViewItem
, ItemList
);
422 WX_DEFINE_LIST(ItemList
)
424 class wxDataViewMainWindow
: public wxWindow
427 wxDataViewMainWindow( wxDataViewCtrl
*parent
,
429 const wxPoint
&pos
= wxDefaultPosition
,
430 const wxSize
&size
= wxDefaultSize
,
431 const wxString
&name
= wxT("wxdataviewctrlmainwindow") );
432 virtual ~wxDataViewMainWindow();
434 bool IsVirtualList() const { return m_root
== NULL
; }
436 // notifications from wxDataViewModel
437 bool ItemAdded( const wxDataViewItem
&parent
, const wxDataViewItem
&item
);
438 bool ItemDeleted( const wxDataViewItem
&parent
, const wxDataViewItem
&item
);
439 bool ItemChanged( const wxDataViewItem
&item
);
440 bool ValueChanged( const wxDataViewItem
&item
, unsigned int col
);
444 if (!IsVirtualList())
454 g_model
= GetOwner()->GetModel();
455 wxDataViewColumn
* col
= GetOwner()->GetSortingColumn();
458 if (g_model
->HasDefaultCompare())
466 g_column
= col
->GetModelColumn();
467 g_asending
= col
->IsSortOrderAscending();
470 void SetOwner( wxDataViewCtrl
* owner
) { m_owner
= owner
; }
471 wxDataViewCtrl
*GetOwner() { return m_owner
; }
472 const wxDataViewCtrl
*GetOwner() const { return m_owner
; }
474 void OnPaint( wxPaintEvent
&event
);
475 void OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
);
476 void OnChar( wxKeyEvent
&event
);
477 void OnMouse( wxMouseEvent
&event
);
478 void OnSetFocus( wxFocusEvent
&event
);
479 void OnKillFocus( wxFocusEvent
&event
);
481 void UpdateDisplay();
482 void RecalculateDisplay();
483 void OnInternalIdle();
485 void OnRenameTimer();
487 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
= NULL
);
488 void ScrollTo( int rows
, int column
);
490 bool HasCurrentRow() { return m_currentRow
!= (unsigned int)-1; }
491 void ChangeCurrentRow( unsigned int row
);
493 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE
); }
494 bool IsEmpty() { return GetRowCount() == 0; }
496 int GetCountPerPage() const;
497 int GetEndOfLastCol() const;
498 unsigned int GetFirstVisibleRow() const;
499 //I change this method to un const because in the tree view, the displaying number of the tree are changing along with the expanding/collapsing of the tree nodes
500 unsigned int GetLastVisibleRow();
501 unsigned int GetRowCount();
503 wxDataViewItem
GetSelection() const;
504 wxDataViewSelection
GetSelections(){ return m_selection
; }
505 void SetSelections( const wxDataViewSelection
& sel
) { m_selection
= sel
; UpdateDisplay(); }
506 void Select( const wxArrayInt
& aSelections
);
507 void SelectAllRows( bool on
);
508 void SelectRow( unsigned int row
, bool on
);
509 void SelectRows( unsigned int from
, unsigned int to
, bool on
);
510 void ReverseRowSelection( unsigned int row
);
511 bool IsRowSelected( unsigned int row
);
512 void SendSelectionChangedEvent( const wxDataViewItem
& item
);
514 void RefreshRow( unsigned int row
);
515 void RefreshRows( unsigned int from
, unsigned int to
);
516 void RefreshRowsAfter( unsigned int firstRow
);
518 // returns the colour to be used for drawing the rules
519 wxColour
GetRuleColour() const
521 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT
);
524 wxRect
GetLineRect( unsigned int row
) const;
526 int GetLineStart( unsigned int row
) const; // row * m_lineHeight in fixed mode
527 int GetLineHeight( unsigned int row
) const; // m_lineHeight in fixed mode
528 int GetLineAt( unsigned int y
) const; // y / m_lineHeight in fixed mode
530 //Some useful functions for row and item mapping
531 wxDataViewItem
GetItemByRow( unsigned int row
) const;
532 int GetRowByItem( const wxDataViewItem
& item
) const;
534 //Methods for building the mapping tree
535 void BuildTree( wxDataViewModel
* model
);
537 void HitTest( const wxPoint
& point
, wxDataViewItem
& item
, wxDataViewColumn
* &column
);
538 wxRect
GetItemRect( const wxDataViewItem
& item
, const wxDataViewColumn
* column
);
540 void Expand( unsigned int row
) { OnExpanding( row
); }
541 void Collapse( unsigned int row
) { OnCollapsing( row
); }
543 wxDataViewTreeNode
* GetTreeNodeByRow( unsigned int row
) const;
544 //We did not need this temporarily
545 //wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
547 int RecalculateCount();
549 wxDataViewEvent
SendExpanderEvent( wxEventType type
, const wxDataViewItem
& item
);
550 void OnExpanding( unsigned int row
);
551 void OnCollapsing( unsigned int row
);
553 wxDataViewTreeNode
* FindNode( const wxDataViewItem
& item
);
556 wxDataViewCtrl
*m_owner
;
560 wxDataViewColumn
*m_currentCol
;
561 unsigned int m_currentRow
;
562 wxDataViewSelection m_selection
;
564 wxDataViewRenameTimer
*m_renameTimer
;
572 // for double click logic
573 unsigned int m_lineLastClicked
,
574 m_lineBeforeLastClicked
,
575 m_lineSelectSingleOnUp
;
577 // the pen used to draw horiz/vertical rules
580 // the pen used to draw the expander and the lines
583 //This is the tree structure of the model
584 wxDataViewTreeNode
* m_root
;
586 //This is the tree node under the cursor
587 wxDataViewTreeNode
* m_underMouse
;
589 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow
)
590 DECLARE_EVENT_TABLE()
593 // ---------------------------------------------------------
594 // wxGenericDataViewModelNotifier
595 // ---------------------------------------------------------
597 class wxGenericDataViewModelNotifier
: public wxDataViewModelNotifier
600 wxGenericDataViewModelNotifier( wxDataViewMainWindow
*mainWindow
)
601 { m_mainWindow
= mainWindow
; }
603 virtual bool ItemAdded( const wxDataViewItem
& parent
, const wxDataViewItem
& item
)
604 { return m_mainWindow
->ItemAdded( parent
, item
); }
605 virtual bool ItemDeleted( const wxDataViewItem
&parent
, const wxDataViewItem
&item
)
606 { return m_mainWindow
->ItemDeleted( parent
, item
); }
607 virtual bool ItemChanged( const wxDataViewItem
& item
)
608 { return m_mainWindow
->ItemChanged(item
); }
609 virtual bool ValueChanged( const wxDataViewItem
& item
, unsigned int col
)
610 { return m_mainWindow
->ValueChanged( item
, col
); }
611 virtual bool Cleared()
612 { return m_mainWindow
->Cleared(); }
613 virtual void Resort()
614 { m_mainWindow
->Resort(); }
616 wxDataViewMainWindow
*m_mainWindow
;
619 // ---------------------------------------------------------
620 // wxDataViewRenderer
621 // ---------------------------------------------------------
623 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
)
625 wxDataViewRenderer::wxDataViewRenderer( const wxString
&varianttype
,
626 wxDataViewCellMode mode
,
628 wxDataViewRendererBase( varianttype
, mode
, align
)
637 wxDataViewRenderer::~wxDataViewRenderer()
643 wxDC
*wxDataViewRenderer::GetDC()
647 if (GetOwner() == NULL
)
649 if (GetOwner()->GetOwner() == NULL
)
651 m_dc
= new wxClientDC( GetOwner()->GetOwner() );
657 void wxDataViewRenderer::SetAlignment( int align
)
662 int wxDataViewRenderer::GetAlignment() const
667 int wxDataViewRenderer::CalculateAlignment() const
669 if (m_align
== wxDVR_DEFAULT_ALIGNMENT
)
671 if (GetOwner() == NULL
)
672 return wxALIGN_LEFT
| wxALIGN_CENTRE_VERTICAL
;
674 return GetOwner()->GetAlignment() | wxALIGN_CENTRE_VERTICAL
;
680 // ---------------------------------------------------------
681 // wxDataViewCustomRenderer
682 // ---------------------------------------------------------
684 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
)
686 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString
&varianttype
,
687 wxDataViewCellMode mode
, int align
) :
688 wxDataViewRenderer( varianttype
, mode
, align
)
692 void wxDataViewCustomRenderer::RenderText( const wxString
&text
, int xoffset
, wxRect cell
, wxDC
*dc
, int state
)
694 wxDataViewCtrl
*view
= GetOwner()->GetOwner();
695 wxColour col
= (state
& wxDATAVIEW_CELL_SELECTED
) ?
696 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
) :
697 view
->GetForegroundColour();
698 dc
->SetTextForeground(col
);
699 dc
->DrawText( text
, cell
.x
+ xoffset
, cell
.y
+ ((cell
.height
- dc
->GetCharHeight()) / 2));
702 // ---------------------------------------------------------
703 // wxDataViewTextRenderer
704 // ---------------------------------------------------------
706 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewCustomRenderer
)
708 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString
&varianttype
,
709 wxDataViewCellMode mode
, int align
) :
710 wxDataViewCustomRenderer( varianttype
, mode
, align
)
714 bool wxDataViewTextRenderer::SetValue( const wxVariant
&value
)
716 m_text
= value
.GetString();
721 bool wxDataViewTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
726 bool wxDataViewTextRenderer::HasEditorCtrl()
731 wxControl
* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow
*parent
,
732 wxRect labelRect
, const wxVariant
&value
)
734 return new wxTextCtrl( parent
, wxID_ANY
, value
,
735 wxPoint(labelRect
.x
,labelRect
.y
),
736 wxSize(labelRect
.width
,labelRect
.height
) );
739 bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl
*editor
, wxVariant
&value
)
741 wxTextCtrl
*text
= (wxTextCtrl
*) editor
;
742 value
= text
->GetValue();
746 bool wxDataViewTextRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
748 RenderText( m_text
, 0, cell
, dc
, state
);
752 wxSize
wxDataViewTextRenderer::GetSize() const
754 const wxDataViewCtrl
*view
= GetView();
758 view
->GetTextExtent( m_text
, &x
, &y
);
759 return wxSize( x
, y
);
761 return wxSize(80,20);
764 // ---------------------------------------------------------
765 // wxDataViewTextRendererAttr
766 // ---------------------------------------------------------
768 IMPLEMENT_CLASS(wxDataViewTextRendererAttr
, wxDataViewTextRenderer
)
770 wxDataViewTextRendererAttr::wxDataViewTextRendererAttr( const wxString
&varianttype
,
771 wxDataViewCellMode mode
, int align
) :
772 wxDataViewTextRenderer( varianttype
, mode
, align
)
777 bool wxDataViewTextRendererAttr::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
784 if (m_attr
.HasColour())
786 colour
= dc
->GetTextForeground();
787 dc
->SetTextForeground( m_attr
.GetColour() );
790 if (m_attr
.GetBold() || m_attr
.GetItalic())
792 font
= dc
->GetFont();
793 wxFont myfont
= font
;
794 if (m_attr
.GetBold())
795 myfont
.SetWeight( wxFONTWEIGHT_BOLD
);
796 if (m_attr
.GetItalic())
797 myfont
.SetStyle( wxFONTSTYLE_ITALIC
);
798 dc
->SetFont( myfont
);
802 dc
->DrawText( m_text
, cell
.x
, cell
.y
+ ((cell
.height
- dc
->GetCharHeight()) / 2));
807 if (m_attr
.HasColour())
808 dc
->SetTextForeground( colour
);
810 if (m_attr
.GetBold() || m_attr
.GetItalic())
818 // ---------------------------------------------------------
819 // wxDataViewBitmapRenderer
820 // ---------------------------------------------------------
822 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewCustomRenderer
)
824 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString
&varianttype
,
825 wxDataViewCellMode mode
, int align
) :
826 wxDataViewCustomRenderer( varianttype
, mode
, align
)
830 bool wxDataViewBitmapRenderer::SetValue( const wxVariant
&value
)
832 if (value
.GetType() == wxT("wxBitmap"))
834 if (value
.GetType() == wxT("wxIcon"))
840 bool wxDataViewBitmapRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
845 bool wxDataViewBitmapRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
848 dc
->DrawBitmap( m_bitmap
, cell
.x
, cell
.y
);
849 else if (m_icon
.Ok())
850 dc
->DrawIcon( m_icon
, cell
.x
, cell
.y
);
855 wxSize
wxDataViewBitmapRenderer::GetSize() const
858 return wxSize( m_bitmap
.GetWidth(), m_bitmap
.GetHeight() );
859 else if (m_icon
.Ok())
860 return wxSize( m_icon
.GetWidth(), m_icon
.GetHeight() );
862 return wxSize(16,16);
865 // ---------------------------------------------------------
866 // wxDataViewToggleRenderer
867 // ---------------------------------------------------------
869 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer
, wxDataViewCustomRenderer
)
871 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString
&varianttype
,
872 wxDataViewCellMode mode
, int align
) :
873 wxDataViewCustomRenderer( varianttype
, mode
, align
)
878 bool wxDataViewToggleRenderer::SetValue( const wxVariant
&value
)
880 m_toggle
= value
.GetBool();
885 bool wxDataViewToggleRenderer::GetValue( wxVariant
&WXUNUSED(value
) ) const
890 bool wxDataViewToggleRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
892 // User wxRenderer here
895 rect
.x
= cell
.x
+ cell
.width
/2 - 10;
897 rect
.y
= cell
.y
+ cell
.height
/2 - 10;
902 flags
|= wxCONTROL_CHECKED
;
903 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE
)
904 flags
|= wxCONTROL_DISABLED
;
906 wxRendererNative::Get().DrawCheckBox(
907 GetOwner()->GetOwner(),
915 bool wxDataViewToggleRenderer::Activate( wxRect
WXUNUSED(cell
),
916 wxDataViewModel
*model
,
917 const wxDataViewItem
& item
, unsigned int col
)
919 bool value
= !m_toggle
;
920 wxVariant variant
= value
;
921 model
->SetValue( variant
, item
, col
);
922 model
->ValueChanged( item
, col
);
926 wxSize
wxDataViewToggleRenderer::GetSize() const
928 return wxSize(20,20);
931 // ---------------------------------------------------------
932 // wxDataViewProgressRenderer
933 // ---------------------------------------------------------
935 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
)
937 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString
&label
,
938 const wxString
&varianttype
, wxDataViewCellMode mode
, int align
) :
939 wxDataViewCustomRenderer( varianttype
, mode
, align
)
945 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
949 bool wxDataViewProgressRenderer::SetValue( const wxVariant
&value
)
951 m_value
= (long) value
;
953 if (m_value
< 0) m_value
= 0;
954 if (m_value
> 100) m_value
= 100;
959 bool wxDataViewProgressRenderer::GetValue( wxVariant
&value
) const
961 value
= (long) m_value
;
965 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC
*dc
, int WXUNUSED(state
) )
967 double pct
= (double)m_value
/ 100.0;
969 bar
.width
= (int)(cell
.width
* pct
);
970 dc
->SetPen( *wxTRANSPARENT_PEN
);
971 dc
->SetBrush( *wxBLUE_BRUSH
);
972 dc
->DrawRectangle( bar
);
974 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
975 dc
->SetPen( *wxBLACK_PEN
);
976 dc
->DrawRectangle( cell
);
981 wxSize
wxDataViewProgressRenderer::GetSize() const
983 return wxSize(40,12);
986 // ---------------------------------------------------------
987 // wxDataViewDateRenderer
988 // ---------------------------------------------------------
990 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
992 #if wxUSE_DATE_RENDERER_POPUP
994 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
997 wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
998 wxDataViewModel
*model
, const wxDataViewItem
& item
, unsigned int col
) :
999 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
),
1004 m_cal
= new wxCalendarCtrl( this, wxID_ANY
, *value
);
1005 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
1006 sizer
->Add( m_cal
, 1, wxGROW
);
1011 void OnCalendar( wxCalendarEvent
&event
);
1013 wxCalendarCtrl
*m_cal
;
1014 wxDataViewModel
*m_model
;
1016 const wxDataViewItem
& m_item
;
1019 virtual void OnDismiss()
1024 DECLARE_EVENT_TABLE()
1027 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
)
1028 EVT_CALENDAR( wxID_ANY
, wxDataViewDateRendererPopupTransient::OnCalendar
)
1031 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent
&event
)
1033 wxDateTime date
= event
.GetDate();
1034 wxVariant value
= date
;
1035 m_model
->SetValue( value
, m_item
, m_col
);
1036 m_model
->ValueChanged( m_item
, m_col
);
1040 #endif // wxUSE_DATE_RENDERER_POPUP
1042 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
)
1044 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString
&varianttype
,
1045 wxDataViewCellMode mode
, int align
) :
1046 wxDataViewCustomRenderer( varianttype
, mode
, align
)
1050 bool wxDataViewDateRenderer::SetValue( const wxVariant
&value
)
1052 m_date
= value
.GetDateTime();
1057 bool wxDataViewDateRenderer::GetValue( wxVariant
&value
) const
1063 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
1065 wxString tmp
= m_date
.FormatDate();
1066 RenderText( tmp
, 0, cell
, dc
, state
);
1070 wxSize
wxDataViewDateRenderer::GetSize() const
1072 const wxDataViewCtrl
* view
= GetView();
1073 wxString tmp
= m_date
.FormatDate();
1075 view
->GetTextExtent( tmp
, &x
, &y
, &d
);
1076 return wxSize(x
,y
+d
);
1079 bool wxDataViewDateRenderer::Activate( wxRect
WXUNUSED(cell
), wxDataViewModel
*model
,
1080 const wxDataViewItem
& item
, unsigned int col
)
1083 model
->GetValue( variant
, item
, col
);
1084 wxDateTime value
= variant
.GetDateTime();
1086 #if wxUSE_DATE_RENDERER_POPUP
1087 wxDataViewDateRendererPopupTransient
*popup
= new wxDataViewDateRendererPopupTransient(
1088 GetOwner()->GetOwner()->GetParent(), &value
, model
, item
, col
);
1089 wxPoint pos
= wxGetMousePosition();
1092 popup
->Popup( popup
->m_cal
);
1093 #else // !wxUSE_DATE_RENDERER_POPUP
1094 wxMessageBox(value
.Format());
1095 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
1099 // ---------------------------------------------------------
1100 // wxDataViewIconTextRenderer
1101 // ---------------------------------------------------------
1103 IMPLEMENT_CLASS(wxDataViewIconTextRenderer
, wxDataViewCustomRenderer
)
1105 wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(
1106 const wxString
&varianttype
, wxDataViewCellMode mode
, int align
) :
1107 wxDataViewCustomRenderer( varianttype
, mode
, align
)
1110 SetAlignment(align
);
1113 wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
1117 bool wxDataViewIconTextRenderer::SetValue( const wxVariant
&value
)
1123 bool wxDataViewIconTextRenderer::GetValue( wxVariant
& WXUNUSED(value
) ) const
1128 bool wxDataViewIconTextRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
1131 const wxIcon
&icon
= m_value
.GetIcon();
1134 dc
->DrawIcon( icon
, cell
.x
, cell
.y
+ ((cell
.height
- icon
.GetHeight()) / 2));
1135 xoffset
= icon
.GetWidth()+4;
1138 RenderText( m_value
.GetText(), xoffset
, cell
, dc
, state
);
1143 wxSize
wxDataViewIconTextRenderer::GetSize() const
1145 const wxDataViewCtrl
*view
= GetView();
1146 if (!m_value
.GetText().empty())
1149 view
->GetTextExtent( m_value
.GetText(), &x
, &y
);
1151 if (m_value
.GetIcon().IsOk())
1152 x
+= m_value
.GetIcon().GetWidth() + 4;
1153 return wxSize( x
, y
);
1155 return wxSize(80,20);
1159 wxDataViewIconTextRenderer::CreateEditorCtrl(wxWindow
* WXUNUSED(parent
),
1160 wxRect
WXUNUSED(labelRect
),
1161 const wxVariant
& WXUNUSED(value
))
1167 wxDataViewIconTextRenderer::GetValueFromEditorCtrl(wxControl
* WXUNUSED(editor
),
1168 wxVariant
& WXUNUSED(value
))
1173 // ---------------------------------------------------------
1175 // ---------------------------------------------------------
1177 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
1179 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewRenderer
*cell
,
1180 unsigned int model_column
,
1181 int width
, wxAlignment align
, int flags
) :
1182 wxDataViewColumnBase( title
, cell
, model_column
, width
, align
, flags
)
1184 wxDataViewColumnBase::SetWidth(width
== wxCOL_WIDTH_DEFAULT
1185 ? wxDVC_DEFAULT_WIDTH
1188 SetAlignment(align
);
1192 wxDataViewColumn::wxDataViewColumn( const wxBitmap
&bitmap
, wxDataViewRenderer
*cell
,
1193 unsigned int model_column
,
1194 int width
, wxAlignment align
, int flags
) :
1195 wxDataViewColumnBase( bitmap
, cell
, model_column
, width
, align
, flags
)
1197 wxDataViewColumnBase::SetWidth(width
== wxCOL_WIDTH_DEFAULT
1198 ? wxDVC_DEFAULT_WIDTH
1201 SetAlignment(align
);
1205 void wxDataViewColumn::SetFlags(int flags
)
1207 if ( flags
!= GetFlags() )
1209 wxDataViewColumnBase::SetFlags(flags
);
1211 // tell our owner to e.g. update its scrollbars:
1213 GetOwner()->OnColumnChange();
1217 void wxDataViewColumn::SetSortOrder( bool ascending
)
1219 if ( ascending
== IsSortOrderAscending() )
1222 wxDataViewColumnBase::SetSortOrder(ascending
);
1224 // Update header button
1226 GetOwner()->OnColumnChange();
1229 void wxDataViewColumn::SetInternalWidth( int width
)
1231 if ( width
== GetWidth() )
1234 wxDataViewColumnBase::SetWidth(width
);
1236 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
1237 if (m_owner
&& m_owner
->m_clientArea
)
1238 m_owner
->m_clientArea
->RecalculateDisplay();
1241 void wxDataViewColumn::SetWidth( int width
)
1243 if ( width
== wxCOL_WIDTH_DEFAULT
)
1244 width
= wxDVC_DEFAULT_WIDTH
;
1246 if ( width
== GetWidth() )
1249 if (m_owner
->m_headerArea
)
1250 m_owner
->m_headerArea
->UpdateDisplay();
1252 SetInternalWidth(width
);
1255 int wxDataViewColumn::GetWidth() const
1257 int width
= wxDataViewColumnBase::GetWidth();
1258 return width
== wxCOL_WIDTH_DEFAULT
? wxDVC_DEFAULT_WIDTH
: width
;
1261 //-----------------------------------------------------------------------------
1262 // wxDataViewHeaderWindowBase
1263 //-----------------------------------------------------------------------------
1265 void wxDataViewHeaderWindowBase::SendEvent(wxEventType type
, unsigned int n
)
1267 wxWindow
*parent
= GetParent();
1268 wxDataViewEvent
le(type
, parent
->GetId());
1270 le
.SetEventObject(parent
);
1272 le
.SetDataViewColumn(GetColumn(n
));
1273 le
.SetModel(GetOwner()->GetModel());
1275 // for events created by wxDataViewHeaderWindow the
1276 // row / value fields are not valid
1278 parent
->GetEventHandler()->ProcessEvent(le
);
1281 #ifdef USE_NATIVE_HEADER_WINDOW
1283 // implemented in msw/listctrl.cpp:
1284 int WXDLLIMPEXP_CORE
wxMSWGetColumnClicked(NMHDR
*nmhdr
, POINT
*ptClick
);
1286 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW
, wxWindow
)
1288 bool wxDataViewHeaderWindowMSW::Create(wxDataViewCtrl
*parent
)
1292 m_scrollOffsetX
= 0;
1293 m_delayedUpdate
= false;
1294 m_vetoColumnDrag
= false;
1295 m_buttonHeight
= wxRendererNative::Get().GetHeaderButtonHeight( this );
1297 return wxHeaderCtrl::Create(parent
, wxID_ANY
);
1300 wxSize
wxDataViewHeaderWindowMSW::DoGetBestSize() const
1302 return wxSize( 80, m_buttonHeight
+2 );
1305 void wxDataViewHeaderWindowMSW::OnInternalIdle()
1307 if (m_delayedUpdate
)
1309 m_delayedUpdate
= false;
1314 void wxDataViewHeaderWindowMSW::UpdateDisplay()
1316 // remove old columns
1319 // add the updated array of columns to the header control
1320 const unsigned int cols
= GetOwner()->GetColumnCount();
1321 for (unsigned int i
= 0; i
< cols
; i
++)
1323 wxDataViewColumn
* const col
= GetColumn( i
);
1324 if (col
->IsHidden())
1325 continue; // don't add it!
1327 // we store the column index to use later as client data (we need to do
1328 // it since column indices in the control and the model may not be the
1329 // same if any columns have been hidden)
1330 col
->SetClientData(i
);
1334 if ( col
->IsSortable() && GetOwner()->GetSortingColumn() == col
)
1336 ShowSortIndicator(GetColumnCount() - 1, col
->IsSortOrderAscending());
1340 // the native wxMSW implementation of the header window
1341 // draws the column separator COLUMN_WIDTH_OFFSET pixels
1342 // on the right: to correct this effect we make the column
1343 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1345 hdi
.cxy
+= COLUMN_WIDTH_OFFSET
;
1350 unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER
*nmHDR
)
1354 // NOTE: we don't just return nmHDR->iItem because when there are
1355 // hidden columns, nmHDR->iItem may be different from
1356 // nmHDR->pitem->lParam
1358 if (nmHDR
->pitem
&& nmHDR
->pitem
->mask
& HDI_LPARAM
)
1360 idx
= (unsigned int)nmHDR
->pitem
->lParam
;
1365 item
.mask
= HDI_LPARAM
;
1366 Header_GetItem((HWND
)m_hWnd
, nmHDR
->iItem
, &item
);
1368 return (unsigned int)item
.lParam
;
1371 bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
1373 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
1375 // is it a message from the header?
1376 if ( nmhdr
->hwndFrom
!= (HWND
)m_hWnd
)
1377 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1379 NMHEADER
*nmHDR
= (NMHEADER
*)nmhdr
;
1380 switch ( nmhdr
->code
)
1382 case NM_RELEASEDCAPTURE
:
1384 // user has released the mouse
1385 m_vetoColumnDrag
= false;
1389 case HDN_BEGINTRACK
:
1390 // user has started to resize a column:
1391 // do we need to veto it?
1392 if (!GetColumn(nmHDR
->iItem
)->IsResizeable())
1401 if (nmHDR
->iItem
!= -1)
1403 // user has started to reorder a valid column
1404 if ((m_vetoColumnDrag
== true) || (!GetColumn(nmHDR
->iItem
)->IsReorderable()))
1408 m_vetoColumnDrag
= true;
1414 m_vetoColumnDrag
= true;
1418 case HDN_ENDDRAG
: // user has finished reordering a column
1420 wxDataViewColumn
*col
= GetColumn(nmHDR
->iItem
);
1421 unsigned int new_pos
= nmHDR
->pitem
->iOrder
;
1422 m_owner
->ColumnMoved( col
, new_pos
);
1423 m_delayedUpdate
= true;
1427 case HDN_ITEMCHANGING
:
1428 if (nmHDR
->pitem
!= NULL
&&
1429 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1431 int minWidth
= GetColumnFromHeader(nmHDR
)->GetMinWidth();
1432 if (nmHDR
->pitem
->cxy
< minWidth
)
1434 // do not allow the user to resize this column under
1435 // its minimal width:
1441 case HDN_ITEMCHANGED
: // user is resizing a column
1442 case HDN_ENDTRACK
: // user has finished resizing a column
1444 // update the width of the modified column:
1445 if (nmHDR
->pitem
!= NULL
&&
1446 (nmHDR
->pitem
->mask
& HDI_WIDTH
) != 0)
1448 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1449 unsigned int w
= nmHDR
->pitem
->cxy
;
1450 wxDataViewColumn
*col
= GetColumn(idx
);
1452 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1453 if (idx
== 0 && w
> COLUMN_WIDTH_OFFSET
)
1454 w
-= COLUMN_WIDTH_OFFSET
;
1456 if (w
>= (unsigned)col
->GetMinWidth())
1457 col
->SetInternalWidth(w
);
1463 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1464 wxDataViewModel
* model
= GetOwner()->GetModel();
1466 if(nmHDR
->iButton
== 0)
1468 wxDataViewColumn
*col
= GetColumn(idx
);
1469 if(col
->IsSortable())
1471 if(model
&& m_owner
->GetSortingColumn() == col
)
1473 bool order
= col
->IsSortOrderAscending();
1474 col
->SetSortOrder(!order
);
1478 m_owner
->SetSortingColumn(col
);
1486 wxEventType evt
= nmHDR
->iButton
== 0 ?
1487 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1488 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1489 SendEvent(evt
, idx
);
1495 // NOTE: for some reason (i.e. for a bug in Windows)
1496 // the HDN_ITEMCLICK notification is not sent on
1497 // right clicks, so we need to handle NM_RCLICK
1500 int column
= wxMSWGetColumnClicked(nmhdr
, &ptClick
);
1501 if (column
!= wxNOT_FOUND
)
1504 item
.mask
= HDI_LPARAM
;
1505 Header_GetItem((HWND
)m_hWnd
, column
, &item
);
1507 // 'idx' may be different from 'column' if there are
1508 // hidden columns...
1509 unsigned int idx
= (unsigned int)item
.lParam
;
1510 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
,
1516 case HDN_GETDISPINFOW
:
1517 // see wxListCtrl::MSWOnNotify for more info!
1520 case HDN_ITEMDBLCLICK
:
1522 unsigned int idx
= GetColumnIdxFromHeader(nmHDR
);
1523 int w
= GetOwner()->GetBestColumnWidth(idx
);
1525 // update the native control:
1527 ZeroMemory(&hd
, sizeof(hd
));
1528 hd
.mask
= HDI_WIDTH
;
1530 Header_SetItem(GetHwnd(),
1531 nmHDR
->iItem
, // NOTE: we don't want 'idx' here!
1534 // update the wxDataViewColumn class:
1535 GetColumn(idx
)->SetInternalWidth(w
);
1540 return wxWindow::MSWOnNotify(idCtrl
, lParam
, result
);
1546 void wxDataViewHeaderWindowMSW::ScrollWindow(int dx
, int WXUNUSED(dy
),
1547 const wxRect
* WXUNUSED(rect
))
1549 m_scrollOffsetX
+= dx
;
1551 GetParent()->Layout();
1554 void wxDataViewHeaderWindowMSW::DoSetSize(int x
, int y
,
1558 // TODO: why is there a border + 2px around it?
1559 wxControl::DoSetSize( x
+m_scrollOffsetX
+1, y
+1, w
-m_scrollOffsetX
-2, h
-2, f
);
1562 #else // !defined(__WXMSW__)
1564 IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow
, wxWindow
)
1565 BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow
, wxWindow
)
1566 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint
)
1567 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse
)
1568 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus
)
1571 bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl
*parent
, wxWindowID id
,
1572 const wxPoint
&pos
, const wxSize
&size
,
1573 const wxString
&name
)
1577 if (!wxDataViewHeaderWindowBase::Create(parent
, id
, pos
, size
, name
))
1580 wxVisualAttributes attr
= wxPanel::GetClassDefaultAttributes();
1581 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1582 SetOwnForegroundColour( attr
.colFg
);
1583 SetOwnBackgroundColour( attr
.colBg
);
1585 SetOwnFont( attr
.font
);
1587 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1588 // a wxBoxSizer and in order to avoid super-big header windows,
1589 // we need to set our height as fixed
1590 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1591 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT
));
1596 void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1599 GetClientSize( &w
, &h
);
1601 wxAutoBufferedPaintDC
dc( this );
1603 dc
.SetBackground(GetBackgroundColour());
1607 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1610 m_owner
->GetViewStart( &x
, NULL
);
1612 // account for the horz scrollbar offset
1613 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1615 dc
.SetFont( GetFont() );
1617 unsigned int cols
= GetOwner()->GetColumnCount();
1620 for (i
= 0; i
< cols
; i
++)
1622 wxDataViewColumn
*col
= GetColumn( i
);
1623 if (col
->IsHidden())
1624 continue; // skip it!
1626 int cw
= col
->GetWidth();
1629 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
;
1630 if (col
->IsSortable() && GetOwner()->GetSortingColumn() == col
)
1632 if (col
->IsSortOrderAscending())
1633 sortArrow
= wxHDR_SORT_ICON_UP
;
1635 sortArrow
= wxHDR_SORT_ICON_DOWN
;
1639 if (m_parent
->IsEnabled())
1641 if ((int) i
== m_hover
)
1642 state
= wxCONTROL_CURRENT
;
1646 state
= (int) wxCONTROL_DISABLED
;
1649 wxRendererNative::Get().DrawHeaderButton
1653 wxRect(xpos
, 0, cw
, ch
-1),
1658 // align as required the column title:
1660 wxSize titleSz
= dc
.GetTextExtent(col
->GetTitle());
1661 switch (col
->GetAlignment())
1664 x
+= HEADER_HORIZ_BORDER
;
1667 x
+= cw
- titleSz
.GetWidth() - HEADER_HORIZ_BORDER
;
1670 case wxALIGN_CENTER
:
1671 case wxALIGN_CENTER_HORIZONTAL
:
1672 x
+= (cw
- titleSz
.GetWidth() - 2 * HEADER_HORIZ_BORDER
)/2;
1676 // always center the title vertically:
1677 int y
= wxMax((ch
- titleSz
.GetHeight()) / 2, HEADER_VERT_BORDER
);
1679 dc
.SetClippingRegion( xpos
+HEADER_HORIZ_BORDER
,
1681 wxMax(cw
- 2 * HEADER_HORIZ_BORDER
, 1), // width
1682 wxMax(ch
- 2 * HEADER_VERT_BORDER
, 1)); // height
1683 dc
.DrawText( col
->GetTitle(), x
, y
);
1684 dc
.DestroyClippingRegion();
1690 void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent
&event
)
1692 GetParent()->SetFocus();
1696 void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent
&event
)
1698 // we want to work with logical coords
1700 m_owner
->CalcUnscrolledPosition(event
.GetX(), 0, &x
, NULL
);
1701 int y
= event
.GetY();
1705 // we don't draw the line beyond our window,
1706 // but we allow dragging it there
1708 GetClientSize( &w
, NULL
);
1709 m_owner
->CalcUnscrolledPosition(w
, 0, &w
, NULL
);
1712 if (event
.ButtonUp())
1714 m_isDragging
= false;
1720 m_currentX
= wxMax(m_minX
+ 7, x
);
1724 GetColumn(m_column
)->SetWidth(m_currentX
- m_minX
);
1726 GetOwner()->Refresh();
1730 else // not dragging
1733 m_column
= wxNOT_FOUND
;
1735 bool hit_border
= false;
1737 // end of the current column
1740 // find the column where this event occured
1741 int countCol
= m_owner
->GetColumnCount();
1742 for (int column
= 0; column
< countCol
; column
++)
1744 wxDataViewColumn
*p
= GetColumn(column
);
1747 continue; // skip if not shown
1749 xpos
+= p
->GetWidth();
1751 if ((abs(x
-xpos
) < 3) && (y
< 22))
1759 // inside the column
1766 int old_hover
= m_hover
;
1768 if (event
.Leaving())
1769 m_hover
= wxNOT_FOUND
;
1770 if (old_hover
!= m_hover
)
1773 if (m_column
== wxNOT_FOUND
)
1776 bool resizeable
= GetColumn(m_column
)->IsResizeable();
1777 if (event
.LeftDClick() && resizeable
)
1779 GetColumn(m_column
)->SetWidth(GetOwner()->GetBestColumnWidth(m_column
));
1782 else if (event
.LeftDown() || event
.RightUp())
1784 if (hit_border
&& event
.LeftDown() && resizeable
)
1786 m_isDragging
= true;
1790 else // click on a column
1792 wxDataViewModel
* model
= GetOwner()->GetModel();
1793 wxEventType evt
= event
.LeftDown() ?
1794 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
:
1795 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
;
1796 SendEvent(evt
, m_column
);
1798 //Left click the header
1799 if(event
.LeftDown())
1801 wxDataViewColumn
*col
= GetColumn(m_column
);
1802 if(col
->IsSortable())
1804 wxDataViewColumn
* sortCol
= m_owner
->GetSortingColumn();
1805 if(model
&& sortCol
== col
)
1807 bool order
= col
->IsSortOrderAscending();
1808 col
->SetSortOrder(!order
);
1812 m_owner
->SetSortingColumn(col
);
1818 //Send the column sorted event
1819 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED
, m_column
);
1823 else if (event
.Moving())
1825 if (hit_border
&& resizeable
)
1826 m_currentCursor
= m_resizeCursor
;
1828 m_currentCursor
= wxSTANDARD_CURSOR
;
1830 SetCursor(*m_currentCursor
);
1835 void wxGenericDataViewHeaderWindow::AdjustDC(wxDC
& dc
)
1839 m_owner
->GetScrollPixelsPerUnit( &xpix
, NULL
);
1840 m_owner
->GetViewStart( &x
, NULL
);
1842 // shift the DC origin to match the position of the main window horizontal
1843 // scrollbar: this allows us to always use logical coords
1844 dc
.SetDeviceOrigin( -x
* xpix
, 0 );
1847 #endif // defined(__WXMSW__)
1849 //-----------------------------------------------------------------------------
1850 // wxDataViewRenameTimer
1851 //-----------------------------------------------------------------------------
1853 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow
*owner
)
1858 void wxDataViewRenameTimer::Notify()
1860 m_owner
->OnRenameTimer();
1863 //-----------------------------------------------------------------------------
1864 // wxDataViewMainWindow
1865 //-----------------------------------------------------------------------------
1867 //The tree building helper, declared firstly
1868 static void BuildTreeHelper( wxDataViewModel
* model
, wxDataViewItem
& item
, wxDataViewTreeNode
* node
);
1870 int LINKAGEMODE
wxDataViewSelectionCmp( unsigned int row1
, unsigned int row2
)
1872 if (row1
> row2
) return 1;
1873 if (row1
== row2
) return 0;
1878 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow
, wxWindow
)
1880 BEGIN_EVENT_TABLE(wxDataViewMainWindow
,wxWindow
)
1881 EVT_PAINT (wxDataViewMainWindow::OnPaint
)
1882 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse
)
1883 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus
)
1884 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus
)
1885 EVT_CHAR (wxDataViewMainWindow::OnChar
)
1888 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl
*parent
, wxWindowID id
,
1889 const wxPoint
&pos
, const wxSize
&size
, const wxString
&name
) :
1890 wxWindow( parent
, id
, pos
, size
, wxWANTS_CHARS
|wxBORDER_NONE
, name
),
1891 m_selection( wxDataViewSelectionCmp
)
1896 m_lastOnSame
= false;
1897 m_renameTimer
= new wxDataViewRenameTimer( this );
1899 // TODO: user better initial values/nothing selected
1900 m_currentCol
= NULL
;
1903 m_lineHeight
= wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1
1906 m_dragStart
= wxPoint(0,0);
1907 m_lineLastClicked
= (unsigned int) -1;
1908 m_lineBeforeLastClicked
= (unsigned int) -1;
1909 m_lineSelectSingleOnUp
= (unsigned int) -1;
1913 SetBackgroundColour( *wxWHITE
);
1915 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
1917 m_penRule
= wxPen(GetRuleColour());
1919 //Here I compose a pen can draw black lines, maybe there are something system colour to use
1920 m_penExpander
= wxPen(wxColour(0,0,0));
1921 //Some new added code to deal with the tree structure
1922 m_root
= new wxDataViewTreeNode( NULL
);
1923 m_root
->SetHasChildren(true);
1925 //Make m_count = -1 will cause the class recaculate the real displaying number of rows.
1927 m_underMouse
= NULL
;
1931 wxDataViewMainWindow::~wxDataViewMainWindow()
1934 delete m_renameTimer
;
1937 void wxDataViewMainWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1939 wxDataViewModel
*model
= GetOwner()->GetModel();
1940 wxAutoBufferedPaintDC
dc( this );
1943 dc
.SetPen( *wxTRANSPARENT_PEN
);
1944 dc
.SetBrush( wxBrush( GetBackgroundColour()) );
1945 dc
.SetBrush( *wxWHITE_BRUSH
);
1946 wxSize
size( GetClientSize() );
1947 dc
.DrawRectangle( 0,0,size
.x
,size
.y
);
1951 GetOwner()->PrepareDC( dc
);
1952 dc
.SetFont( GetFont() );
1954 wxRect update
= GetUpdateRegion().GetBox();
1955 m_owner
->CalcUnscrolledPosition( update
.x
, update
.y
, &update
.x
, &update
.y
);
1957 // compute which items needs to be redrawn
1958 unsigned int item_start
= GetLineAt( wxMax(0,update
.y
) );
1959 unsigned int item_count
=
1960 wxMin( (int)( GetLineAt( wxMax(0,update
.y
+update
.height
) ) - item_start
+ 1),
1961 (int)(GetRowCount( ) - item_start
));
1962 unsigned int item_last
= item_start
+ item_count
;
1964 // compute which columns needs to be redrawn
1965 unsigned int cols
= GetOwner()->GetColumnCount();
1966 unsigned int col_start
= 0;
1967 unsigned int x_start
;
1968 for (x_start
= 0; col_start
< cols
; col_start
++)
1970 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_start
);
1971 if (col
->IsHidden())
1972 continue; // skip it!
1974 unsigned int w
= col
->GetWidth();
1975 if (x_start
+w
>= (unsigned int)update
.x
)
1981 unsigned int col_last
= col_start
;
1982 unsigned int x_last
= x_start
;
1983 for (; col_last
< cols
; col_last
++)
1985 wxDataViewColumn
*col
= GetOwner()->GetColumn(col_last
);
1986 if (col
->IsHidden())
1987 continue; // skip it!
1989 if (x_last
> (unsigned int)update
.GetRight())
1992 x_last
+= col
->GetWidth();
1995 // Draw horizontal rules if required
1996 if ( m_owner
->HasFlag(wxDV_HORIZ_RULES
) )
1998 dc
.SetPen(m_penRule
);
1999 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
2001 for (unsigned int i
= item_start
; i
<= item_last
+1; i
++)
2003 int y
= GetLineStart( i
);
2004 dc
.DrawLine(x_start
, y
, x_last
, y
);
2008 // Draw vertical rules if required
2009 if ( m_owner
->HasFlag(wxDV_VERT_RULES
) )
2011 dc
.SetPen(m_penRule
);
2012 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
2015 for (unsigned int i
= col_start
; i
< col_last
; i
++)
2017 wxDataViewColumn
*col
= GetOwner()->GetColumn(i
);
2018 if (col
->IsHidden())
2019 continue; // skip it
2021 dc
.DrawLine(x
, GetLineStart( item_start
),
2022 x
, GetLineStart( item_last
) );
2024 x
+= col
->GetWidth();
2027 // Draw last vertical rule
2028 dc
.DrawLine(x
, GetLineStart( item_start
),
2029 x
, GetLineStart( item_last
) );
2032 // redraw the background for the items which are selected/current
2033 for (unsigned int item
= item_start
; item
< item_last
; item
++)
2035 bool selected
= m_selection
.Index( item
) != wxNOT_FOUND
;
2036 if (selected
|| item
== m_currentRow
)
2038 int flags
= selected
? (int)wxCONTROL_SELECTED
: 0;
2039 if (item
== m_currentRow
)
2040 flags
|= wxCONTROL_CURRENT
;
2042 flags
|= wxCONTROL_FOCUSED
;
2044 wxRect
rect( x_start
, GetLineStart( item
), x_last
, GetLineHeight( item
) );
2045 wxRendererNative::Get().DrawItemSelectionRect
2055 wxDataViewColumn
*expander
= GetOwner()->GetExpanderColumn();
2058 // TODO: last column for RTL support
2059 expander
= GetOwner()->GetColumn( 0 );
2060 GetOwner()->SetExpanderColumn(expander
);
2063 // redraw all cells for all rows which must be repainted and all columns
2065 cell_rect
.x
= x_start
;
2066 for (unsigned int i
= col_start
; i
< col_last
; i
++)
2069 wxDataViewColumn
*col
= GetOwner()->GetColumn( i
);
2070 wxDataViewRenderer
*cell
= col
->GetRenderer();
2071 cell_rect
.width
= col
->GetWidth();
2073 if (col
->IsHidden())
2074 continue; // skip it!
2076 for (unsigned int item
= item_start
; item
< item_last
; item
++)
2078 // get the cell value and set it into the renderer
2080 wxDataViewTreeNode
*node
= NULL
;
2081 wxDataViewItem dataitem
;
2083 if (!IsVirtualList())
2085 node
= GetTreeNodeByRow(item
);
2089 dataitem
= node
->GetItem();
2091 if ((i
> 0) && model
->IsContainer(dataitem
) && !model
->HasContainerColumns(dataitem
))
2096 dataitem
= wxDataViewItem( wxUIntToPtr(item
) );
2099 model
->GetValue( value
, dataitem
, col
->GetModelColumn());
2100 cell
->SetValue( value
);
2102 if (cell
->GetWantsAttr())
2104 wxDataViewItemAttr attr
;
2105 bool ret
= model
->GetAttr( dataitem
, col
->GetModelColumn(), attr
);
2107 cell
->SetAttr( attr
);
2108 cell
->SetHasAttr( ret
);
2112 cell_rect
.y
= GetLineStart( item
);
2113 cell_rect
.height
= GetLineHeight( item
); // -1 is for the horizontal rules (?)
2115 //Draw the expander here.
2117 if ((!IsVirtualList()) && (col
== expander
))
2119 indent
= node
->GetIndentLevel();
2121 //Calculate the indent first
2122 indent
= cell_rect
.x
+ GetOwner()->GetIndent() * indent
;
2124 int expander_width
= m_lineHeight
- 2*EXPANDER_MARGIN
;
2125 // change the cell_rect.x to the appropriate pos
2126 int expander_x
= indent
+ EXPANDER_MARGIN
;
2127 int expander_y
= cell_rect
.y
+ EXPANDER_MARGIN
+ (GetLineHeight(item
) / 2) - (expander_width
/2) - EXPANDER_OFFSET
;
2128 indent
= indent
+ m_lineHeight
; //try to use the m_lineHeight as the expander space
2129 dc
.SetPen( m_penExpander
);
2130 dc
.SetBrush( wxNullBrush
);
2131 if( node
->HasChildren() )
2133 wxRect
rect( expander_x
, expander_y
, expander_width
, expander_width
);
2135 if (m_underMouse
== node
)
2137 flag
|= wxCONTROL_CURRENT
;
2139 if( node
->IsOpen() )
2140 wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
|wxCONTROL_EXPANDED
);
2142 wxRendererNative::Get().DrawTreeItemButton( this, dc
, rect
, flag
);
2144 //force the expander column to left-center align
2145 cell
->SetAlignment( wxALIGN_CENTER_VERTICAL
);
2147 if (node
&& !node
->HasChildren())
2149 // Yes, if the node does not have any child, it must be a leaf which
2150 // mean that it is a temporarily created by GetTreeNodeByRow
2154 // cannot be bigger than allocated space
2155 wxSize size
= cell
->GetSize();
2156 // Because of the tree structure indent, here we should minus the width of the cell for drawing
2157 size
.x
= wxMin( size
.x
+ 2*PADDING_RIGHTLEFT
, cell_rect
.width
- indent
);
2158 // size.y = wxMin( size.y, cell_rect.height );
2159 size
.y
= cell_rect
.height
;
2161 wxRect
item_rect(cell_rect
.GetTopLeft(), size
);
2162 int align
= cell
->CalculateAlignment();
2164 // horizontal alignment:
2165 item_rect
.x
= cell_rect
.x
;
2166 if (align
& wxALIGN_CENTER_HORIZONTAL
)
2167 item_rect
.x
= cell_rect
.x
+ (cell_rect
.width
/ 2) - (size
.x
/ 2);
2168 else if (align
& wxALIGN_RIGHT
)
2169 item_rect
.x
= cell_rect
.x
+ cell_rect
.width
- size
.x
;
2170 //else: wxALIGN_LEFT is the default
2172 // vertical alignment:
2173 item_rect
.y
= cell_rect
.y
;
2174 if (align
& wxALIGN_CENTER_VERTICAL
)
2175 item_rect
.y
= cell_rect
.y
+ (cell_rect
.height
/ 2) - (size
.y
/ 2);
2176 else if (align
& wxALIGN_BOTTOM
)
2177 item_rect
.y
= cell_rect
.y
+ cell_rect
.height
- size
.y
;
2178 //else: wxALIGN_TOP is the default
2181 item_rect
.x
+= PADDING_RIGHTLEFT
;
2182 item_rect
.width
= size
.x
- 2 * PADDING_RIGHTLEFT
;
2184 //Here we add the tree indent
2185 item_rect
.x
+= indent
;
2188 if (m_hasFocus
&& (m_selection
.Index(item
) != wxNOT_FOUND
))
2189 state
|= wxDATAVIEW_CELL_SELECTED
;
2191 // TODO: it would be much more efficient to create a clipping
2192 // region for the entire column being rendered (in the OnPaint
2193 // of wxDataViewMainWindow) instead of a single clip region for
2194 // each cell. However it would mean that each renderer should
2195 // respect the given wxRect's top & bottom coords, eventually
2196 // violating only the left & right coords - however the user can
2197 // make its own renderer and thus we cannot be sure of that.
2198 dc
.SetClippingRegion( item_rect
);
2199 cell
->Render( item_rect
, &dc
, state
);
2200 dc
.DestroyClippingRegion();
2203 cell_rect
.x
+= cell_rect
.width
;
2207 void wxDataViewMainWindow::OnRenameTimer()
2209 // We have to call this here because changes may just have
2210 // been made and no screen update taken place.
2215 unsigned int cols
= GetOwner()->GetColumnCount();
2217 for (i
= 0; i
< cols
; i
++)
2219 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
2221 continue; // skip it!
2223 if (c
== m_currentCol
)
2225 xpos
+= c
->GetWidth();
2227 wxRect
labelRect( xpos
,
2228 GetLineStart( m_currentRow
),
2229 m_currentCol
->GetWidth(),
2230 GetLineHeight( m_currentRow
) );
2232 GetOwner()->CalcScrolledPosition( labelRect
.x
, labelRect
.y
,
2233 &labelRect
.x
, &labelRect
.y
);
2235 wxDataViewItem item
= GetItemByRow( m_currentRow
);
2236 m_currentCol
->GetRenderer()->StartEditing( item
, labelRect
);
2240 //------------------------------------------------------------------
2241 // Helper class for do operation on the tree node
2242 //------------------------------------------------------------------
2247 virtual ~DoJob() { }
2249 //The return value control how the tree-walker tranverse the tree
2250 // 0: Job done, stop tranverse and return
2251 // 1: Ignore the current node's subtree and continue
2252 // 2: Job not done, continue
2253 enum { OK
= 0 , IGR
= 1, CONT
= 2 };
2254 virtual int operator() ( wxDataViewTreeNode
* node
) = 0;
2255 virtual int operator() ( void * n
) = 0;
2258 bool Walker( wxDataViewTreeNode
* node
, DoJob
& func
)
2263 switch( func( node
) )
2274 wxDataViewTreeNodes nodes
= node
->GetNodes();
2275 wxDataViewTreeLeaves leaves
= node
->GetChildren();
2277 int len_nodes
= nodes
.GetCount();
2278 int len
= leaves
.GetCount();
2279 int i
= 0, nodes_i
= 0;
2281 for(; i
< len
; i
++ )
2283 void * n
= leaves
[i
];
2284 if( nodes_i
< len_nodes
&& n
== nodes
[nodes_i
]->GetItem().GetID() )
2286 wxDataViewTreeNode
* nd
= nodes
[nodes_i
];
2289 if( Walker( nd
, func
) )
2308 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem
& parent
, const wxDataViewItem
& item
)
2319 wxDataViewTreeNode
* node
;
2320 node
= FindNode(parent
);
2325 node
->SetHasChildren( true );
2327 if( g_model
->IsContainer( item
) )
2329 wxDataViewTreeNode
* newnode
= new wxDataViewTreeNode( node
);
2330 newnode
->SetItem(item
);
2331 newnode
->SetHasChildren( true );
2332 node
->AddNode( newnode
);
2335 node
->AddLeaf( item
.GetID() );
2337 node
->ChangeSubTreeCount(1);
2345 static void DestroyTreeHelper( wxDataViewTreeNode
* node
);
2347 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem
& parent
,
2348 const wxDataViewItem
& item
)
2353 if( m_currentRow
> GetRowCount() )
2354 m_currentRow
= m_count
- 1;
2356 m_selection
.Empty();
2363 wxDataViewTreeNode
* node
= FindNode(parent
);
2365 wxCHECK_MSG( node
!= NULL
, false, "item not found" );
2366 wxCHECK_MSG( node
->GetChildren().Index( item
.GetID() ) != wxNOT_FOUND
, false, "item not found" );
2369 node
->GetChildren().Remove( item
.GetID() );
2370 //Manuplate selection
2371 if( m_selection
.GetCount() > 1 )
2373 m_selection
.Empty();
2375 bool isContainer
= false;
2376 wxDataViewTreeNodes nds
= node
->GetNodes();
2377 for (size_t i
= 0; i
< nds
.GetCount(); i
++)
2379 if (nds
[i
]->GetItem() == item
)
2387 wxDataViewTreeNode
* n
= NULL
;
2388 wxDataViewTreeNodes nodes
= node
->GetNodes();
2389 int len
= nodes
.GetCount();
2390 for( int i
= 0; i
< len
; i
++)
2392 if( nodes
[i
]->GetItem() == item
)
2399 wxCHECK_MSG( n
!= NULL
, false, "item not found" );
2401 node
->GetNodes().Remove( n
);
2402 sub
-= n
->GetSubTreeCount();
2403 ::DestroyTreeHelper(n
);
2405 //Make the row number invalid and get a new valid one when user call GetRowCount
2407 node
->ChangeSubTreeCount(sub
);
2409 //Change the current row to the last row if the current exceed the max row number
2410 if( m_currentRow
> GetRowCount() )
2411 m_currentRow
= m_count
- 1;
2418 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem
& item
)
2424 wxWindow
*parent
= GetParent();
2425 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId());
2426 le
.SetEventObject(parent
);
2427 le
.SetModel(GetOwner()->GetModel());
2429 parent
->GetEventHandler()->ProcessEvent(le
);
2434 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem
& item
, unsigned int col
)
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 );
2449 wxWindow
*parent
= GetParent();
2450 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED
, parent
->GetId());
2451 le
.SetEventObject(parent
);
2452 le
.SetModel(GetOwner()->GetModel());
2455 le
.SetDataViewColumn(GetOwner()->GetColumn(col
));
2456 parent
->GetEventHandler()->ProcessEvent(le
);
2461 bool wxDataViewMainWindow::Cleared()
2466 BuildTree( GetOwner()->GetModel() );
2473 void wxDataViewMainWindow::UpdateDisplay()
2478 void wxDataViewMainWindow::OnInternalIdle()
2480 wxWindow::OnInternalIdle();
2484 RecalculateDisplay();
2489 void wxDataViewMainWindow::RecalculateDisplay()
2491 wxDataViewModel
*model
= GetOwner()->GetModel();
2498 int width
= GetEndOfLastCol();
2499 int height
= GetLineStart( GetRowCount() );
2501 SetVirtualSize( width
, height
);
2502 GetOwner()->SetScrollRate( 10, m_lineHeight
);
2507 void wxDataViewMainWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
2509 wxWindow::ScrollWindow( dx
, dy
, rect
);
2511 if (GetOwner()->m_headerArea
)
2512 GetOwner()->m_headerArea
->ScrollWindow( dx
, 0 );
2515 void wxDataViewMainWindow::ScrollTo( int rows
, int column
)
2518 m_owner
->GetScrollPixelsPerUnit( &x
, &y
);
2519 int sy
= GetLineStart( rows
)/y
;
2523 wxRect rect
= GetClientRect();
2527 m_owner
->CalcUnscrolledPosition( rect
.x
, rect
.y
, &xx
, &yy
);
2528 for (x_start
= 0; colnum
< column
; colnum
++)
2530 wxDataViewColumn
*col
= GetOwner()->GetColumn(colnum
);
2531 if (col
->IsHidden())
2532 continue; // skip it!
2534 w
= col
->GetWidth();
2538 int x_end
= x_start
+ w
;
2539 xe
= xx
+ rect
.width
;
2542 sx
= ( xx
+ x_end
- xe
)/x
;
2549 m_owner
->Scroll( sx
, sy
);
2552 int wxDataViewMainWindow::GetCountPerPage() const
2554 wxSize size
= GetClientSize();
2555 return size
.y
/ m_lineHeight
;
2558 int wxDataViewMainWindow::GetEndOfLastCol() const
2562 for (i
= 0; i
< GetOwner()->GetColumnCount(); i
++)
2564 const wxDataViewColumn
*c
=
2565 const_cast<wxDataViewCtrl
*>(GetOwner())->GetColumn( i
);
2568 width
+= c
->GetWidth();
2573 unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
2577 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
2579 return GetLineAt( y
);
2582 unsigned int wxDataViewMainWindow::GetLastVisibleRow()
2584 wxSize client_size
= GetClientSize();
2585 m_owner
->CalcUnscrolledPosition( client_size
.x
, client_size
.y
,
2586 &client_size
.x
, &client_size
.y
);
2588 //we should deal with the pixel here
2589 unsigned int row
= GetLineAt(client_size
.y
) - 1;
2591 return wxMin( GetRowCount()-1, row
);
2594 unsigned int wxDataViewMainWindow::GetRowCount()
2596 if ( m_count
== -1 )
2598 m_count
= RecalculateCount();
2604 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row
)
2611 void wxDataViewMainWindow::SelectAllRows( bool on
)
2618 m_selection
.Clear();
2619 for (unsigned int i
= 0; i
< GetRowCount(); i
++)
2620 m_selection
.Add( i
);
2625 unsigned int first_visible
= GetFirstVisibleRow();
2626 unsigned int last_visible
= GetLastVisibleRow();
2628 for (i
= 0; i
< m_selection
.GetCount(); i
++)
2630 unsigned int row
= m_selection
[i
];
2631 if ((row
>= first_visible
) && (row
<= last_visible
))
2634 m_selection
.Clear();
2638 void wxDataViewMainWindow::SelectRow( unsigned int row
, bool on
)
2640 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2644 m_selection
.Add( row
);
2652 m_selection
.Remove( row
);
2658 void wxDataViewMainWindow::SelectRows( unsigned int from
, unsigned int to
, bool on
)
2662 unsigned int tmp
= from
;
2668 for (i
= from
; i
<= to
; i
++)
2670 if (m_selection
.Index( i
) == wxNOT_FOUND
)
2673 m_selection
.Add( i
);
2678 m_selection
.Remove( i
);
2681 RefreshRows( from
, to
);
2684 void wxDataViewMainWindow::Select( const wxArrayInt
& aSelections
)
2686 for (size_t i
=0; i
< aSelections
.GetCount(); i
++)
2688 int n
= aSelections
[i
];
2690 m_selection
.Add( n
);
2695 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row
)
2697 if (m_selection
.Index( row
) == wxNOT_FOUND
)
2698 m_selection
.Add( row
);
2700 m_selection
.Remove( row
);
2704 bool wxDataViewMainWindow::IsRowSelected( unsigned int row
)
2706 return (m_selection
.Index( row
) != wxNOT_FOUND
);
2709 void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem
& item
)
2711 wxWindow
*parent
= GetParent();
2712 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED
, parent
->GetId());
2714 le
.SetEventObject(parent
);
2715 le
.SetModel(GetOwner()->GetModel());
2718 parent
->GetEventHandler()->ProcessEvent(le
);
2721 void wxDataViewMainWindow::RefreshRow( unsigned int row
)
2723 wxRect
rect( 0, GetLineStart( row
), GetEndOfLastCol(), GetLineHeight( row
) );
2724 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2726 wxSize client_size
= GetClientSize();
2727 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2728 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2729 if (intersect_rect
.width
> 0)
2730 Refresh( true, &intersect_rect
);
2733 void wxDataViewMainWindow::RefreshRows( unsigned int from
, unsigned int to
)
2737 unsigned int tmp
= to
;
2742 wxRect
rect( 0, GetLineStart( from
), GetEndOfLastCol(), GetLineStart( (to
-from
+1) ) );
2743 m_owner
->CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
2745 wxSize client_size
= GetClientSize();
2746 wxRect
client_rect( 0, 0, client_size
.x
, client_size
.y
);
2747 wxRect intersect_rect
= client_rect
.Intersect( rect
);
2748 if (intersect_rect
.width
> 0)
2749 Refresh( true, &intersect_rect
);
2752 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow
)
2754 wxSize client_size
= GetClientSize();
2755 int start
= GetLineStart( firstRow
);
2756 m_owner
->CalcScrolledPosition( start
, 0, &start
, NULL
);
2757 if (start
> client_size
.y
) return;
2759 wxRect
rect( 0, start
, client_size
.x
, client_size
.y
- start
);
2761 Refresh( true, &rect
);
2764 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent
, const wxKeyEvent
& event
)
2766 wxCHECK_RET( newCurrent
< GetRowCount(),
2767 _T("invalid item index in OnArrowChar()") );
2769 // if there is no selection, we cannot move it anywhere
2770 if (!HasCurrentRow())
2773 unsigned int oldCurrent
= m_currentRow
;
2775 // in single selection we just ignore Shift as we can't select several
2777 if ( event
.ShiftDown() && !IsSingleSel() )
2779 RefreshRow( oldCurrent
);
2781 ChangeCurrentRow( newCurrent
);
2783 // select all the items between the old and the new one
2784 if ( oldCurrent
> newCurrent
)
2786 newCurrent
= oldCurrent
;
2787 oldCurrent
= m_currentRow
;
2790 SelectRows( oldCurrent
, newCurrent
, true );
2791 if (oldCurrent
!=newCurrent
)
2792 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]));
2796 RefreshRow( oldCurrent
);
2798 // all previously selected items are unselected unless ctrl is held
2799 if ( !event
.ControlDown() )
2800 SelectAllRows(false);
2802 ChangeCurrentRow( newCurrent
);
2804 if ( !event
.ControlDown() )
2806 SelectRow( m_currentRow
, true );
2807 SendSelectionChangedEvent(GetItemByRow(m_currentRow
));
2810 RefreshRow( m_currentRow
);
2813 GetOwner()->EnsureVisible( m_currentRow
, -1 );
2816 wxRect
wxDataViewMainWindow::GetLineRect( unsigned int row
) const
2820 rect
.y
= GetLineStart( row
);
2821 rect
.width
= GetEndOfLastCol();
2822 rect
.height
= GetLineHeight( row
);
2827 int wxDataViewMainWindow::GetLineStart( unsigned int row
) const
2829 const wxDataViewModel
*model
= GetOwner()->GetModel();
2831 if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
)
2833 // TODO make more efficient
2838 for (r
= 0; r
< row
; r
++)
2840 const wxDataViewTreeNode
* node
= GetTreeNodeByRow(r
);
2841 if (!node
) return start
;
2843 wxDataViewItem item
= node
->GetItem();
2845 if (node
&& !node
->HasChildren())
2847 // Yes, if the node does not have any child, it must be a leaf which
2848 // mean that it is a temporarily created by GetTreeNodeByRow
2852 unsigned int cols
= GetOwner()->GetColumnCount();
2854 int height
= m_lineHeight
;
2855 for (col
= 0; col
< cols
; col
++)
2857 const wxDataViewColumn
*column
= GetOwner()->GetColumn(col
);
2858 if (column
->IsHidden())
2859 continue; // skip it!
2861 if ((col
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
))
2862 continue; // skip it!
2864 const wxDataViewRenderer
*renderer
= column
->GetRenderer();
2866 model
->GetValue( value
, item
, column
->GetModelColumn() );
2867 wxDataViewRenderer
*renderer2
= const_cast<wxDataViewRenderer
*>(renderer
);
2868 renderer2
->SetValue( value
);
2869 height
= wxMax( height
, renderer
->GetSize().y
);
2880 return row
* m_lineHeight
;
2884 int wxDataViewMainWindow::GetLineAt( unsigned int y
) const
2886 const wxDataViewModel
*model
= GetOwner()->GetModel();
2888 // check for the easy case first
2889 if ( !GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT
) )
2890 return y
/ m_lineHeight
;
2892 // TODO make more efficient
2893 unsigned int row
= 0;
2894 unsigned int yy
= 0;
2897 const wxDataViewTreeNode
* node
= GetTreeNodeByRow(row
);
2900 // not really correct...
2901 return row
+ ((y
-yy
) / m_lineHeight
);
2904 wxDataViewItem item
= node
->GetItem();
2906 if (node
&& !node
->HasChildren())
2908 // Yes, if the node does not have any child, it must be a leaf which
2909 // mean that it is a temporarily created by GetTreeNodeByRow
2913 unsigned int cols
= GetOwner()->GetColumnCount();
2915 int height
= m_lineHeight
;
2916 for (col
= 0; col
< cols
; col
++)
2918 const wxDataViewColumn
*column
= GetOwner()->GetColumn(col
);
2919 if (column
->IsHidden())
2920 continue; // skip it!
2922 if ((col
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
))
2923 continue; // skip it!
2925 const wxDataViewRenderer
*renderer
= column
->GetRenderer();
2927 model
->GetValue( value
, item
, column
->GetModelColumn() );
2928 wxDataViewRenderer
*renderer2
= const_cast<wxDataViewRenderer
*>(renderer
);
2929 renderer2
->SetValue( value
);
2930 height
= wxMax( height
, renderer
->GetSize().y
);
2941 int wxDataViewMainWindow::GetLineHeight( unsigned int row
) const
2943 const wxDataViewModel
*model
= GetOwner()->GetModel();
2945 if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT
)
2947 wxASSERT( !IsVirtualList() );
2949 const wxDataViewTreeNode
* node
= GetTreeNodeByRow(row
);
2950 // wxASSERT( node );
2951 if (!node
) return m_lineHeight
;
2953 wxDataViewItem item
= node
->GetItem();
2955 if (node
&& !node
->HasChildren())
2957 // Yes, if the node does not have any child, it must be a leaf which
2958 // mean that it is a temporarily created by GetTreeNodeByRow
2962 int height
= m_lineHeight
;
2964 unsigned int cols
= GetOwner()->GetColumnCount();
2966 for (col
= 0; col
< cols
; col
++)
2968 const wxDataViewColumn
*column
= GetOwner()->GetColumn(col
);
2969 if (column
->IsHidden())
2970 continue; // skip it!
2972 if ((col
!= 0) && model
->IsContainer(item
) && !model
->HasContainerColumns(item
))
2973 continue; // skip it!
2975 const wxDataViewRenderer
*renderer
= column
->GetRenderer();
2977 model
->GetValue( value
, item
, column
->GetModelColumn() );
2978 wxDataViewRenderer
*renderer2
= const_cast<wxDataViewRenderer
*>(renderer
);
2979 renderer2
->SetValue( value
);
2980 height
= wxMax( height
, renderer
->GetSize().y
);
2987 return m_lineHeight
;
2991 class RowToItemJob
: public DoJob
2994 RowToItemJob( unsigned int row
, int current
) { this->row
= row
; this->current
= current
;}
2995 virtual ~RowToItemJob() { }
2997 virtual int operator() ( wxDataViewTreeNode
* node
)
3000 if( current
== static_cast<int>(row
))
3002 ret
= node
->GetItem();
3006 if( node
->GetSubTreeCount() + current
< static_cast<int>(row
) )
3008 current
+= node
->GetSubTreeCount();
3013 //If the current has no child node, we can find the desired item of the row number directly.
3014 //This if can speed up finding in some case, and will has a very good effect when it comes to list view
3015 if( node
->GetNodes().GetCount() == 0)
3017 int index
= static_cast<int>(row
) - current
- 1;
3018 ret
= node
->GetChildren().Item( index
);
3025 virtual int operator() ( void * n
)
3028 if( current
== static_cast<int>(row
))
3030 ret
= wxDataViewItem( n
);
3035 wxDataViewItem
GetResult(){ return ret
; }
3042 wxDataViewItem
wxDataViewMainWindow::GetItemByRow(unsigned int row
) const
3046 return wxDataViewItem( wxUIntToPtr(row
) );
3050 RowToItemJob
job( row
, -2 );
3051 Walker( m_root
, job
);
3052 return job
.GetResult();
3056 class RowToTreeNodeJob
: public DoJob
3059 RowToTreeNodeJob( unsigned int row
, int current
, wxDataViewTreeNode
* node
)
3062 this->current
= current
;
3066 virtual ~RowToTreeNodeJob(){ }
3068 virtual int operator() ( wxDataViewTreeNode
* node
)
3071 if( current
== static_cast<int>(row
))
3077 if( node
->GetSubTreeCount() + current
< static_cast<int>(row
) )
3079 current
+= node
->GetSubTreeCount();
3085 //If the current has no child node, we can find the desired item of the row number directly.
3086 //This if can speed up finding in some case, and will has a very good effect when it comes to list view
3087 if( node
->GetNodes().GetCount() == 0)
3089 int index
= static_cast<int>(row
) - current
- 1;
3090 void * n
= node
->GetChildren().Item( index
);
3091 ret
= new wxDataViewTreeNode( parent
);
3092 ret
->SetItem( wxDataViewItem( n
));
3093 ret
->SetHasChildren(false);
3102 virtual int operator() ( void * n
)
3105 if( current
== static_cast<int>(row
))
3107 ret
= new wxDataViewTreeNode( parent
);
3108 ret
->SetItem( wxDataViewItem( n
));
3109 ret
->SetHasChildren(false);
3115 wxDataViewTreeNode
* GetResult(){ return ret
; }
3119 wxDataViewTreeNode
* ret
;
3120 wxDataViewTreeNode
* parent
;
3124 wxDataViewTreeNode
* wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row
) const
3126 wxASSERT( !IsVirtualList() );
3128 RowToTreeNodeJob
job( row
, -2, m_root
);
3129 Walker( m_root
, job
);
3130 return job
.GetResult();
3133 wxDataViewEvent
wxDataViewMainWindow::SendExpanderEvent( wxEventType type
, const wxDataViewItem
& item
)
3135 wxWindow
*parent
= GetParent();
3136 wxDataViewEvent
le(type
, parent
->GetId());
3138 le
.SetEventObject(parent
);
3139 le
.SetModel(GetOwner()->GetModel());
3142 parent
->GetEventHandler()->ProcessEvent(le
);
3146 void wxDataViewMainWindow::OnExpanding( unsigned int row
)
3148 if (IsVirtualList())
3151 wxDataViewTreeNode
* node
= GetTreeNodeByRow(row
);
3154 if( node
->HasChildren())
3156 if( !node
->IsOpen())
3158 wxDataViewEvent e
= SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING
,node
->GetItem());
3159 //Check if the user prevent expanding
3160 if( e
.GetSkipped() )
3164 //Here I build the children of current node
3165 if( node
->GetChildrenNumber() == 0 )
3168 ::BuildTreeHelper(GetOwner()->GetModel(), node
->GetItem(), node
);
3172 //Send the expanded event
3173 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED
,node
->GetItem());
3177 SelectRow( row
, false );
3178 SelectRow( row
+ 1, true );
3179 ChangeCurrentRow( row
+ 1 );
3180 SendSelectionChangedEvent( GetItemByRow(row
+1));
3188 void wxDataViewMainWindow::OnCollapsing(unsigned int row
)
3190 if (IsVirtualList())
3193 wxDataViewTreeNode
* node
= GetTreeNodeByRow(row
);
3196 wxDataViewTreeNode
* nd
= node
;
3198 if( node
->HasChildren() && node
->IsOpen() )
3200 wxDataViewEvent e
= SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING
,node
->GetItem());
3201 if( e
.GetSkipped() )
3206 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED
,nd
->GetItem());
3210 node
= node
->GetParent();
3213 int parent
= GetRowByItem( node
->GetItem() );
3216 SelectRow( row
, false);
3217 SelectRow(parent
, true );
3218 ChangeCurrentRow( parent
);
3219 SendSelectionChangedEvent( node
->GetItem() );
3223 if( !nd
->HasChildren())
3228 wxDataViewTreeNode
* wxDataViewMainWindow::FindNode( const wxDataViewItem
& item
)
3230 wxDataViewModel
* model
= GetOwner()->GetModel();
3234 //Compose the a parent-chain of the finding item
3236 list
.DeleteContents( true );
3237 wxDataViewItem
it( item
);
3240 wxDataViewItem
* pItem
= new wxDataViewItem( it
);
3241 list
.Insert( pItem
);
3242 it
= model
->GetParent( it
);
3245 //Find the item along the parent-chain.
3246 //This algorithm is designed to speed up the node-finding method
3247 wxDataViewTreeNode
* node
= m_root
;
3248 for( ItemList::const_iterator iter
= list
.begin(); iter
!=list
.end(); iter
++ )
3250 if( node
->HasChildren() )
3252 if( node
->GetChildrenNumber() == 0 )
3255 ::BuildTreeHelper(model
, node
->GetItem(), node
);
3258 wxDataViewTreeNodes nodes
= node
->GetNodes();
3262 for (i
= 0; i
< nodes
.GetCount(); i
++)
3264 if (nodes
[i
]->GetItem() == (**iter
))
3266 if (nodes
[i
]->GetItem() == item
)
3283 void wxDataViewMainWindow::HitTest( const wxPoint
& point
, wxDataViewItem
& item
, wxDataViewColumn
* &column
)
3285 wxDataViewColumn
*col
= NULL
;
3286 unsigned int cols
= GetOwner()->GetColumnCount();
3287 unsigned int colnum
= 0;
3289 m_owner
->CalcUnscrolledPosition( point
.x
, point
.y
, &x
, &y
);
3290 for (unsigned x_start
= 0; colnum
< cols
; colnum
++)
3292 col
= GetOwner()->GetColumn(colnum
);
3293 if (col
->IsHidden())
3294 continue; // skip it!
3296 unsigned int w
= col
->GetWidth();
3297 if (x_start
+w
>= (unsigned int)x
)
3304 item
= GetItemByRow( GetLineAt( y
) );
3307 wxRect
wxDataViewMainWindow::GetItemRect( const wxDataViewItem
& item
, const wxDataViewColumn
* column
)
3309 int row
= GetRowByItem(item
);
3310 int y
= GetLineStart( row
);
3311 int h
= GetLineHeight( m_lineHeight
);
3313 wxDataViewColumn
*col
= NULL
;
3314 for( int i
= 0, cols
= GetOwner()->GetColumnCount(); i
< cols
; i
++ )
3316 col
= GetOwner()->GetColumn( i
);
3317 x
+= col
->GetWidth();
3318 if( GetOwner()->GetColumn(i
+1) == column
)
3321 int w
= col
->GetWidth();
3322 m_owner
->CalcScrolledPosition( x
, y
, &x
, &y
);
3323 return wxRect(x
, y
, w
, h
);
3326 int wxDataViewMainWindow::RecalculateCount()
3330 wxDataViewIndexListModel
*list_model
= (wxDataViewIndexListModel
*) GetOwner()->GetModel();
3332 return list_model
->GetLastIndex() + 1;
3334 return list_model
->GetLastIndex() - 1;
3339 return m_root
->GetSubTreeCount();
3343 class ItemToRowJob
: public DoJob
3346 ItemToRowJob(const wxDataViewItem
& item_
, ItemList::const_iterator iter
)
3353 //Maybe binary search will help to speed up this process
3354 virtual int operator() ( wxDataViewTreeNode
* node
)
3357 if( node
->GetItem() == item
)
3362 if( node
->GetItem() == **m_iter
)
3369 ret
+= node
->GetSubTreeCount();
3375 virtual int operator() ( void * n
)
3378 if( n
== item
.GetID() )
3382 //the row number is begin from zero
3383 int GetResult() { return ret
-1; }
3386 ItemList::const_iterator m_iter
;
3387 wxDataViewItem item
;
3392 int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem
& item
) const
3394 const wxDataViewModel
* model
= GetOwner()->GetModel();
3400 return wxPtrToUInt( item
.GetID() );
3407 //Compose the a parent-chain of the finding item
3409 wxDataViewItem
* pItem
;
3410 list
.DeleteContents( true );
3411 wxDataViewItem
it( item
);
3414 pItem
= new wxDataViewItem( it
);
3415 list
.Insert( pItem
);
3416 it
= model
->GetParent( it
);
3418 pItem
= new wxDataViewItem( );
3419 list
.Insert( pItem
);
3421 ItemToRowJob
job( item
, list
.begin() );
3422 Walker(m_root
, job
);
3423 return job
.GetResult();
3427 static void BuildTreeHelper( wxDataViewModel
* model
, wxDataViewItem
& item
, wxDataViewTreeNode
* node
)
3429 if( !model
->IsContainer( item
) )
3432 wxDataViewItemArray children
;
3433 unsigned int num
= model
->GetChildren( item
, children
);
3434 unsigned int index
= 0;
3435 while( index
< num
)
3437 if( model
->IsContainer( children
[index
] ) )
3439 wxDataViewTreeNode
* n
= new wxDataViewTreeNode( node
);
3440 n
->SetItem(children
[index
]);
3441 n
->SetHasChildren( true );
3446 node
->AddLeaf( children
[index
].GetID() );
3450 node
->SetSubTreeCount( num
);
3451 wxDataViewTreeNode
* n
= node
->GetParent();
3453 n
->ChangeSubTreeCount(num
);
3457 void wxDataViewMainWindow::BuildTree(wxDataViewModel
* model
)
3461 if (GetOwner()->GetModel()->IsVirtualListModel())
3467 m_root
= new wxDataViewTreeNode( NULL
);
3468 m_root
->SetHasChildren(true);
3470 //First we define a invalid item to fetch the top-level elements
3471 wxDataViewItem item
;
3473 BuildTreeHelper( model
, item
, m_root
);
3477 static void DestroyTreeHelper( wxDataViewTreeNode
* node
)
3479 if( node
->GetNodeNumber() != 0 )
3481 int len
= node
->GetNodeNumber();
3483 wxDataViewTreeNodes
& nodes
= node
->GetNodes();
3484 for(; i
< len
; i
++ )
3486 DestroyTreeHelper(nodes
[i
]);
3492 void wxDataViewMainWindow::DestroyTree()
3494 if (!IsVirtualList())
3496 ::DestroyTreeHelper(m_root
);
3502 void wxDataViewMainWindow::OnChar( wxKeyEvent
&event
)
3504 if ( GetParent()->HandleAsNavigationKey(event
) )
3507 // no item -> nothing to do
3508 if (!HasCurrentRow())
3514 // don't use m_linesPerPage directly as it might not be computed yet
3515 const int pageSize
= GetCountPerPage();
3516 wxCHECK_RET( pageSize
, _T("should have non zero page size") );
3518 switch ( event
.GetKeyCode() )
3522 if (m_currentRow
> 0)
3524 wxWindow
*parent
= GetParent();
3525 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId());
3526 le
.SetItem( GetItemByRow(m_currentRow
) );
3527 le
.SetEventObject(parent
);
3528 le
.SetModel(GetOwner()->GetModel());
3530 parent
->GetEventHandler()->ProcessEvent(le
);
3535 if ( m_currentRow
> 0 )
3536 OnArrowChar( m_currentRow
- 1, event
);
3540 if ( m_currentRow
< GetRowCount() - 1 )
3541 OnArrowChar( m_currentRow
+ 1, event
);
3543 //Add the process for tree expanding/collapsing
3545 OnCollapsing(m_currentRow
);
3548 OnExpanding( m_currentRow
);
3552 OnArrowChar( GetRowCount() - 1, event
);
3557 OnArrowChar( 0, event
);
3562 int steps
= pageSize
- 1;
3563 int index
= m_currentRow
- steps
;
3567 OnArrowChar( index
, event
);
3573 int steps
= pageSize
- 1;
3574 unsigned int index
= m_currentRow
+ steps
;
3575 unsigned int count
= GetRowCount();
3576 if ( index
>= count
)
3579 OnArrowChar( index
, event
);
3588 void wxDataViewMainWindow::OnMouse( wxMouseEvent
&event
)
3590 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
3592 // let the base handle mouse wheel events.
3597 int x
= event
.GetX();
3598 int y
= event
.GetY();
3599 m_owner
->CalcUnscrolledPosition( x
, y
, &x
, &y
);
3600 wxDataViewColumn
*col
= NULL
;
3603 unsigned int cols
= GetOwner()->GetColumnCount();
3605 for (i
= 0; i
< cols
; i
++)
3607 wxDataViewColumn
*c
= GetOwner()->GetColumn( i
);
3609 continue; // skip it!
3611 if (x
< xpos
+ c
->GetWidth())
3616 xpos
+= c
->GetWidth();
3621 wxDataViewRenderer
*cell
= col
->GetRenderer();
3622 unsigned int current
= GetLineAt( y
);
3623 if ((current
> GetRowCount()) || (x
> GetEndOfLastCol()))
3625 // Unselect all if below the last row ?
3629 //Test whether the mouse is hovered on the tree item button
3631 if ((!IsVirtualList()) && (GetOwner()->GetExpanderColumn() == col
))
3633 wxDataViewTreeNode
* node
= GetTreeNodeByRow(current
);
3634 if( node
!=NULL
&& node
->HasChildren() )
3636 int indent
= node
->GetIndentLevel();
3637 indent
= GetOwner()->GetIndent()*indent
;
3638 wxRect
rect( xpos
+ indent
+ EXPANDER_MARGIN
,
3639 GetLineStart( current
) + EXPANDER_MARGIN
+ (GetLineHeight(current
)/2) - (m_lineHeight
/2) - EXPANDER_OFFSET
,
3640 m_lineHeight
-2*EXPANDER_MARGIN
,
3641 m_lineHeight
-2*EXPANDER_MARGIN
+ EXPANDER_OFFSET
);
3642 if( rect
.Contains( x
, y
) )
3644 //So the mouse is over the expander
3646 if (m_underMouse
&& m_underMouse
!= node
)
3648 //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem()));
3649 RefreshRow(GetRowByItem(m_underMouse
->GetItem()));
3651 if (m_underMouse
!= node
)
3653 //wxLogMessage("Do the row: %d", current);
3654 RefreshRow(current
);
3656 m_underMouse
= node
;
3659 if (node
!=NULL
&& !node
->HasChildren())
3664 if (m_underMouse
!= NULL
)
3666 //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem()));
3667 RefreshRow(GetRowByItem(m_underMouse
->GetItem()));
3668 m_underMouse
= NULL
;
3672 wxDataViewModel
*model
= GetOwner()->GetModel();
3674 if (event
.Dragging())
3676 if (m_dragCount
== 0)
3678 // we have to report the raw, physical coords as we want to be
3679 // able to call HitTest(event.m_pointDrag) from the user code to
3680 // get the item being dragged
3681 m_dragStart
= event
.GetPosition();
3686 if (m_dragCount
!= 3)
3689 if (event
.LeftIsDown())
3691 // Notify cell about drag
3700 bool forceClick
= false;
3702 if (event
.ButtonDClick())
3704 m_renameTimer
->Stop();
3705 m_lastOnSame
= false;
3708 wxDataViewItem item
= GetItemByRow(current
);
3709 bool ignore_other_columns
=
3710 ((GetOwner()->GetExpanderColumn() != col
) &&
3711 (model
->IsContainer(item
)) &&
3712 (!model
->HasContainerColumns(item
)));
3714 if (event
.LeftDClick())
3716 if ( current
== m_lineLastClicked
)
3718 if ((!ignore_other_columns
) && (cell
->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE
))
3721 model
->GetValue( value
, item
, col
->GetModelColumn() );
3722 cell
->SetValue( value
);
3723 wxRect
cell_rect( xpos
, GetLineStart( current
),
3724 col
->GetWidth(), GetLineHeight( current
) );
3725 cell
->Activate( cell_rect
, model
, item
, col
->GetModelColumn() );
3730 wxWindow
*parent
= GetParent();
3731 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, parent
->GetId());
3733 le
.SetEventObject(parent
);
3734 le
.SetModel(GetOwner()->GetModel());
3736 parent
->GetEventHandler()->ProcessEvent(le
);
3742 // The first click was on another item, so don't interpret this as
3743 // a double click, but as a simple click instead
3750 if (m_lineSelectSingleOnUp
!= (unsigned int)-1)
3752 // select single line
3753 SelectAllRows( false );
3754 SelectRow( m_lineSelectSingleOnUp
, true );
3757 //Process the event of user clicking the expander
3758 bool expander
= false;
3759 if ((!IsVirtualList()) && (GetOwner()->GetExpanderColumn() == col
))
3761 wxDataViewTreeNode
* node
= GetTreeNodeByRow(current
);
3762 if( node
!=NULL
&& node
->HasChildren() )
3764 int indent
= node
->GetIndentLevel();
3765 indent
= GetOwner()->GetIndent()*indent
;
3766 wxRect
rect( xpos
+ indent
+ EXPANDER_MARGIN
,
3767 GetLineStart( current
) + EXPANDER_MARGIN
+ (GetLineHeight(current
)/2) - (m_lineHeight
/2) - EXPANDER_OFFSET
,
3768 m_lineHeight
-2*EXPANDER_MARGIN
,
3769 m_lineHeight
-2*EXPANDER_MARGIN
+ EXPANDER_OFFSET
);
3771 if( rect
.Contains( x
, y
) )
3774 if( node
->IsOpen() )
3775 OnCollapsing(current
);
3777 OnExpanding( current
);
3780 if (node
&& !node
->HasChildren())
3783 //If the user click the expander, we do not do editing even if the column with expander are editable
3784 if (m_lastOnSame
&& !expander
&& !ignore_other_columns
)
3786 if ((col
== m_currentCol
) && (current
== m_currentRow
) &&
3787 (cell
->GetMode() & wxDATAVIEW_CELL_EDITABLE
) )
3789 m_renameTimer
->Start( 100, true );
3793 m_lastOnSame
= false;
3794 m_lineSelectSingleOnUp
= (unsigned int)-1;
3798 // This is necessary, because after a DnD operation in
3799 // from and to ourself, the up event is swallowed by the
3800 // DnD code. So on next non-up event (which means here and
3801 // now) m_lineSelectSingleOnUp should be reset.
3802 m_lineSelectSingleOnUp
= (unsigned int)-1;
3805 if (event
.RightDown())
3807 m_lineBeforeLastClicked
= m_lineLastClicked
;
3808 m_lineLastClicked
= current
;
3810 // If the item is already selected, do not update the selection.
3811 // Multi-selections should not be cleared if a selected item is clicked.
3812 if (!IsRowSelected(current
))
3814 SelectAllRows(false);
3815 ChangeCurrentRow(current
);
3816 SelectRow(m_currentRow
,true);
3817 SendSelectionChangedEvent(GetItemByRow( m_currentRow
) );
3821 model
->GetValue( value
, item
, col
->GetModelColumn() );
3822 wxWindow
*parent
= GetParent();
3823 wxDataViewEvent
le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU
, parent
->GetId());
3825 le
.SetEventObject(parent
);
3826 le
.SetModel(GetOwner()->GetModel());
3828 parent
->GetEventHandler()->ProcessEvent(le
);
3830 else if (event
.MiddleDown())
3833 if (event
.LeftDown() || forceClick
)
3837 m_lineBeforeLastClicked
= m_lineLastClicked
;
3838 m_lineLastClicked
= current
;
3840 unsigned int oldCurrentRow
= m_currentRow
;
3841 bool oldWasSelected
= IsRowSelected(m_currentRow
);
3843 bool cmdModifierDown
= event
.CmdDown();
3844 if ( IsSingleSel() || !(cmdModifierDown
|| event
.ShiftDown()) )
3846 if ( IsSingleSel() || !IsRowSelected(current
) )
3848 SelectAllRows( false );
3849 ChangeCurrentRow(current
);
3850 SelectRow(m_currentRow
,true);
3851 SendSelectionChangedEvent(GetItemByRow( m_currentRow
) );
3853 else // multi sel & current is highlighted & no mod keys
3855 m_lineSelectSingleOnUp
= current
;
3856 ChangeCurrentRow(current
); // change focus
3859 else // multi sel & either ctrl or shift is down
3861 if (cmdModifierDown
)
3863 ChangeCurrentRow(current
);
3864 ReverseRowSelection(m_currentRow
);
3865 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) );
3867 else if (event
.ShiftDown())
3869 ChangeCurrentRow(current
);
3871 unsigned int lineFrom
= oldCurrentRow
,
3874 if ( lineTo
< lineFrom
)
3877 lineFrom
= m_currentRow
;
3880 SelectRows(lineFrom
, lineTo
, true);
3881 SendSelectionChangedEvent(GetItemByRow(m_selection
[0]) );
3883 else // !ctrl, !shift
3885 // test in the enclosing if should make it impossible
3886 wxFAIL_MSG( _T("how did we get here?") );
3890 if (m_currentRow
!= oldCurrentRow
)
3891 RefreshRow( oldCurrentRow
);
3893 wxDataViewColumn
*oldCurrentCol
= m_currentCol
;
3895 // Update selection here...
3898 m_lastOnSame
= !forceClick
&& ((col
== oldCurrentCol
) &&
3899 (current
== oldCurrentRow
)) && oldWasSelected
;
3901 // Call LeftClick after everything else as under GTK+
3902 if (cell
->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE
)
3904 // notify cell about right click
3906 model
->GetValue( value
, item
, col
->GetModelColumn() );
3907 cell
->SetValue( value
);
3908 wxRect
cell_rect( xpos
, GetLineStart( current
),
3909 col
->GetWidth(), GetLineHeight( current
) );
3910 /* ignore ret */ cell
->LeftClick( event
.GetPosition(), cell_rect
, model
, item
, col
->GetModelColumn());
3915 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent
&event
)
3919 if (HasCurrentRow())
3925 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent
&event
)
3929 if (HasCurrentRow())
3935 wxDataViewItem
wxDataViewMainWindow::GetSelection() const
3937 if( m_selection
.GetCount() != 1 )
3938 return wxDataViewItem();
3940 return GetItemByRow( m_selection
.Item(0));
3943 //-----------------------------------------------------------------------------
3945 //-----------------------------------------------------------------------------
3946 WX_DEFINE_LIST(wxDataViewColumnList
)
3948 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
3950 BEGIN_EVENT_TABLE(wxDataViewCtrl
, wxDataViewCtrlBase
)
3951 EVT_SIZE(wxDataViewCtrl::OnSize
)
3954 wxDataViewCtrl::~wxDataViewCtrl()
3957 GetModel()->RemoveNotifier( m_notifier
);
3962 void wxDataViewCtrl::Init()
3964 m_cols
.DeleteContents(true);
3967 // No sorting column at start
3968 m_sortingColumn
= NULL
;
3969 m_headerArea
= NULL
;
3972 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
3973 const wxPoint
& pos
, const wxSize
& size
,
3974 long style
, const wxValidator
& validator
)
3976 if ( (style
& wxBORDER_MASK
) == 0)
3977 style
|= wxBORDER_SUNKEN
;
3981 if (!wxControl::Create( parent
, id
, pos
, size
,
3982 style
| wxScrolledWindowStyle
, validator
))
3985 SetInitialSize(size
);
3988 MacSetClipChildren( true );
3991 m_clientArea
= new wxDataViewMainWindow( this, wxID_ANY
);
3993 if (HasFlag(wxDV_NO_HEADER
))
3994 m_headerArea
= NULL
;
3996 m_headerArea
= new wxDataViewHeaderWindow(this);
3998 SetTargetWindow( m_clientArea
);
4000 wxBoxSizer
*sizer
= new wxBoxSizer( wxVERTICAL
);
4002 sizer
->Add( m_headerArea
, 0, wxGROW
);
4003 sizer
->Add( m_clientArea
, 1, wxGROW
);
4010 WXLRESULT
wxDataViewCtrl::MSWWindowProc(WXUINT nMsg
,
4014 WXLRESULT rc
= wxDataViewCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
);
4017 // we need to process arrows ourselves for scrolling
4018 if ( nMsg
== WM_GETDLGCODE
)
4020 rc
|= DLGC_WANTARROWS
;
4028 wxSize
wxDataViewCtrl::GetSizeAvailableForScrollTarget(const wxSize
& size
)
4030 wxSize newsize
= size
;
4031 if (!HasFlag(wxDV_NO_HEADER
) && (m_headerArea
))
4032 newsize
.y
-= m_headerArea
->GetSize().y
;
4037 void wxDataViewCtrl::OnSize( wxSizeEvent
&WXUNUSED(event
) )
4039 // We need to override OnSize so that our scrolled
4040 // window a) does call Layout() to use sizers for
4041 // positioning the controls but b) does not query
4042 // the sizer for their size and use that for setting
4043 // the scrollable area as set that ourselves by
4044 // calling SetScrollbar() further down.
4051 void wxDataViewCtrl::SetFocus()
4054 m_clientArea
->SetFocus();
4057 bool wxDataViewCtrl::AssociateModel( wxDataViewModel
*model
)
4059 if (!wxDataViewCtrlBase::AssociateModel( model
))
4062 m_notifier
= new wxGenericDataViewModelNotifier( m_clientArea
);
4064 model
->AddNotifier( m_notifier
);
4066 m_clientArea
->DestroyTree();
4068 m_clientArea
->BuildTree(model
);
4070 m_clientArea
->UpdateDisplay();
4075 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
4077 if (!wxDataViewCtrlBase::AppendColumn(col
))
4080 m_cols
.Append( col
);
4085 bool wxDataViewCtrl::PrependColumn( wxDataViewColumn
*col
)
4087 if (!wxDataViewCtrlBase::PrependColumn(col
))
4090 m_cols
.Insert( col
);
4095 bool wxDataViewCtrl::InsertColumn( unsigned int pos
, wxDataViewColumn
*col
)
4097 if (!wxDataViewCtrlBase::InsertColumn(pos
,col
))
4100 m_cols
.Insert( pos
, col
);
4105 void wxDataViewCtrl::OnColumnChange()
4108 m_headerArea
->UpdateDisplay();
4110 m_clientArea
->UpdateDisplay();
4113 void wxDataViewCtrl::DoSetExpanderColumn()
4115 m_clientArea
->UpdateDisplay();
4118 void wxDataViewCtrl::DoSetIndent()
4120 m_clientArea
->UpdateDisplay();
4123 unsigned int wxDataViewCtrl::GetColumnCount() const
4125 return m_cols
.GetCount();
4128 wxDataViewColumn
* wxDataViewCtrl::GetColumn( unsigned int pos
) const
4130 wxDataViewColumnList::const_iterator iter
;
4132 for (iter
= m_cols
.begin(); iter
!=m_cols
.end(); iter
++)
4137 if ((*iter
)->IsHidden())
4144 void wxDataViewCtrl::ColumnMoved( wxDataViewColumn
* col
, unsigned int new_pos
)
4146 if (new_pos
> m_cols
.GetCount()) return;
4148 // Exchange position
4149 m_cols
.DeleteContents(false);
4150 m_cols
.DeleteObject( col
);
4151 m_cols
.Insert( new_pos
, col
);
4152 m_cols
.DeleteContents(true);
4154 m_clientArea
->UpdateDisplay();
4157 bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn
*column
)
4159 wxDataViewColumnList::compatibility_iterator ret
= m_cols
.Find( column
);
4169 bool wxDataViewCtrl::ClearColumns()
4176 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn
*column
) const
4178 int ret
= 0, dead
= 0;
4179 int len
= GetColumnCount();
4180 for (int i
=0; i
<len
; i
++)
4182 wxDataViewColumn
* col
= GetColumn(i
);
4183 if (col
->IsHidden())
4185 ret
+= col
->GetWidth();
4188 CalcScrolledPosition( ret
, dead
, &ret
, &dead
);
4195 wxDataViewColumn
*wxDataViewCtrl::GetSortingColumn() const
4200 //Selection code with wxDataViewItem as parameters
4201 wxDataViewItem
wxDataViewCtrl::GetSelection() const
4203 return m_clientArea
->GetSelection();
4206 int wxDataViewCtrl::GetSelections( wxDataViewItemArray
& sel
) const
4209 wxDataViewSelection selection
= m_clientArea
->GetSelections();
4210 int len
= selection
.GetCount();
4211 for( int i
= 0; i
< len
; i
++)
4213 unsigned int row
= selection
[i
];
4214 sel
.Add( m_clientArea
->GetItemByRow( row
) );
4219 void wxDataViewCtrl::SetSelections( const wxDataViewItemArray
& sel
)
4221 wxDataViewSelection
selection(wxDataViewSelectionCmp
);
4222 int len
= sel
.GetCount();
4223 for( int i
= 0; i
< len
; i
++ )
4225 int row
= m_clientArea
->GetRowByItem( sel
[i
] );
4227 selection
.Add( static_cast<unsigned int>(row
) );
4229 m_clientArea
->SetSelections( selection
);
4232 void wxDataViewCtrl::Select( const wxDataViewItem
& item
)
4234 int row
= m_clientArea
->GetRowByItem( item
);
4237 //Unselect all rows before select another in the single select mode
4238 if (m_clientArea
->IsSingleSel())
4239 m_clientArea
->SelectAllRows(false);
4240 m_clientArea
->SelectRow(row
, true);
4244 void wxDataViewCtrl::Unselect( const wxDataViewItem
& item
)
4246 int row
= m_clientArea
->GetRowByItem( item
);
4248 m_clientArea
->SelectRow(row
, false);
4251 bool wxDataViewCtrl::IsSelected( const wxDataViewItem
& item
) const
4253 int row
= m_clientArea
->GetRowByItem( item
);
4256 return m_clientArea
->IsRowSelected(row
);
4261 //Selection code with row number as parameter
4262 int wxDataViewCtrl::GetSelections( wxArrayInt
& sel
) const
4265 wxDataViewSelection selection
= m_clientArea
->GetSelections();
4266 int len
= selection
.GetCount();
4267 for( int i
= 0; i
< len
; i
++)
4269 unsigned int row
= selection
[i
];
4275 void wxDataViewCtrl::SetSelections( const wxArrayInt
& sel
)
4277 wxDataViewSelection
selection(wxDataViewSelectionCmp
);
4278 int len
= sel
.GetCount();
4279 for( int i
= 0; i
< len
; i
++ )
4283 selection
.Add( static_cast<unsigned int>(row
) );
4285 m_clientArea
->SetSelections( selection
);
4288 void wxDataViewCtrl::Select( int row
)
4292 if (m_clientArea
->IsSingleSel())
4293 m_clientArea
->SelectAllRows(false);
4294 m_clientArea
->SelectRow( row
, true );
4298 void wxDataViewCtrl::Unselect( int row
)
4301 m_clientArea
->SelectRow(row
, false);
4304 bool wxDataViewCtrl::IsSelected( int row
) const
4307 return m_clientArea
->IsRowSelected(row
);
4311 void wxDataViewCtrl::SelectRange( int from
, int to
)
4314 for( int i
= from
; i
< to
; i
++ )
4316 m_clientArea
->Select(sel
);
4319 void wxDataViewCtrl::UnselectRange( int from
, int to
)
4321 wxDataViewSelection sel
= m_clientArea
->GetSelections();
4322 for( int i
= from
; i
< to
; i
++ )
4323 if( sel
.Index( i
) != wxNOT_FOUND
)
4325 m_clientArea
->SetSelections(sel
);
4328 void wxDataViewCtrl::SelectAll()
4330 m_clientArea
->SelectAllRows(true);
4333 void wxDataViewCtrl::UnselectAll()
4335 m_clientArea
->SelectAllRows(false);
4338 void wxDataViewCtrl::EnsureVisible( int row
, int column
)
4342 if( row
> (int) m_clientArea
->GetRowCount() )
4343 row
= m_clientArea
->GetRowCount();
4345 int first
= m_clientArea
->GetFirstVisibleRow();
4346 int last
= m_clientArea
->GetLastVisibleRow();
4348 m_clientArea
->ScrollTo( row
, column
);
4349 else if( row
> last
)
4350 m_clientArea
->ScrollTo( row
- last
+ first
, column
);
4352 m_clientArea
->ScrollTo( first
, column
);
4355 void wxDataViewCtrl::EnsureVisible( const wxDataViewItem
& item
, const wxDataViewColumn
* column
)
4357 int row
= m_clientArea
->GetRowByItem(item
);
4360 if( column
== NULL
)
4361 EnsureVisible(row
, -1);
4365 int len
= GetColumnCount();
4366 for( int i
= 0; i
< len
; i
++ )
4367 if( GetColumn(i
) == column
)
4372 EnsureVisible( row
, col
);
4378 void wxDataViewCtrl::HitTest( const wxPoint
& point
, wxDataViewItem
& item
, wxDataViewColumn
* &column
) const
4380 m_clientArea
->HitTest(point
, item
, column
);
4383 wxRect
wxDataViewCtrl::GetItemRect( const wxDataViewItem
& item
, const wxDataViewColumn
* column
) const
4385 return m_clientArea
->GetItemRect(item
, column
);
4388 wxDataViewItem
wxDataViewCtrl::GetItemByRow( unsigned int row
) const
4390 return m_clientArea
->GetItemByRow( row
);
4393 int wxDataViewCtrl::GetRowByItem( const wxDataViewItem
& item
) const
4395 return m_clientArea
->GetRowByItem( item
);
4398 void wxDataViewCtrl::Expand( const wxDataViewItem
& item
)
4400 int row
= m_clientArea
->GetRowByItem( item
);
4402 m_clientArea
->Expand(row
);
4405 void wxDataViewCtrl::Collapse( const wxDataViewItem
& item
)
4407 int row
= m_clientArea
->GetRowByItem( item
);
4409 m_clientArea
->Collapse(row
);
4413 // !wxUSE_GENERICDATAVIEWCTRL
4416 // wxUSE_DATAVIEWCTRL