]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
use a @section instead of <b> tags
[wxWidgets.git] / src / generic / datavgen.cpp
CommitLineData
4ed7af08 1/////////////////////////////////////////////////////////////////////////////
f554a14b 2// Name: src/generic/datavgen.cpp
4ed7af08
RR
3// Purpose: wxDataViewCtrl generic implementation
4// Author: Robert Roebling
7274390f 5// Modified by: Francesco Montorsi, Guru Kathiresan, Bo Yang
4ed7af08
RR
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
ed4b0fdc
WS
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
4ed7af08
RR
18#if wxUSE_DATAVIEWCTRL
19
20#include "wx/dataview.h"
21
22#ifdef wxUSE_GENERICDATAVIEWCTRL
23
f554a14b 24#ifndef WX_PRECOMP
57bd4c60 25 #ifdef __WXMSW__
87f0efe2 26 #include "wx/msw/private.h"
57bd4c60 27 #include "wx/msw/wrapwin.h"
87f0efe2 28 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
57bd4c60 29 #endif
f554a14b
WS
30 #include "wx/sizer.h"
31 #include "wx/log.h"
ed4b0fdc 32 #include "wx/dcclient.h"
c0badb70 33 #include "wx/timer.h"
9eddec69 34 #include "wx/settings.h"
8d0ca292 35 #include "wx/msgdlg.h"
99d471a5 36 #include "wx/dcscreen.h"
f554a14b
WS
37#endif
38
4ed7af08 39#include "wx/stockitem.h"
4ed7af08
RR
40#include "wx/calctrl.h"
41#include "wx/popupwin.h"
4ed7af08 42#include "wx/renderer.h"
2e992e06 43#include "wx/dcbuffer.h"
2586d4a1 44#include "wx/icon.h"
351461fc
RR
45#include "wx/list.h"
46#include "wx/listimpl.cpp"
4ed7af08 47
4ed7af08
RR
48//-----------------------------------------------------------------------------
49// classes
50//-----------------------------------------------------------------------------
51
52class wxDataViewCtrl;
53
9861f022
RR
54static const int SCROLL_UNIT_X = 15;
55
56// the cell padding on the left/right
57static const int PADDING_RIGHTLEFT = 3;
58
3b6280be
RR
59// the expander space margin
60static const int EXPANDER_MARGIN = 4;
9861f022 61
a0f3af5f
RR
62//-----------------------------------------------------------------------------
63// wxDataViewHeaderWindow
64//-----------------------------------------------------------------------------
4ed7af08 65
626b09ec
VZ
66// on wxMSW the header window (only that part however) can be made native!
67#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
68 #define USE_NATIVE_HEADER_WINDOW
69#endif
87f0efe2 70
57f2a652
RR
71//Below is the compare stuff
72//For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed
73static wxDataViewModel * g_model;
24c4a50f
RR
74static int g_column = -2;
75static bool g_asending = true;
57f2a652 76
c741d33f
VZ
77// NB: for some reason, this class must be dllexport'ed or we get warnings from
78// MSVC in DLL build
79class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase : public wxControl
87f0efe2
RR
80{
81public:
82 wxDataViewHeaderWindowBase()
83 { m_owner = NULL; }
84
85 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 86 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
87 const wxString &name)
88 {
89 return wxWindow::Create(parent, id, pos, size, wxNO_BORDER, name);
90 }
91
92 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
93 wxDataViewCtrl *GetOwner() { return m_owner; }
94
95 // called on column addition/removal
96 virtual void UpdateDisplay() { /* by default, do nothing */ }
97
87f0efe2 98 // returns the n-th column
9861f022 99 virtual wxDataViewColumn *GetColumn(unsigned int n)
87f0efe2
RR
100 {
101 wxASSERT(m_owner);
c741d33f 102 wxDataViewColumn *ret = m_owner->GetColumn(n);
87f0efe2
RR
103 wxASSERT(ret);
104
c741d33f 105 return ret;
87f0efe2
RR
106 }
107
108protected:
109 wxDataViewCtrl *m_owner;
110
111 // sends an event generated from the n-th wxDataViewColumn
112 void SendEvent(wxEventType type, unsigned int n);
113};
114
626b09ec 115#ifdef USE_NATIVE_HEADER_WINDOW
87f0efe2 116
9861f022 117#define COLUMN_WIDTH_OFFSET 2
87f0efe2
RR
118#define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
119
120class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase
4ed7af08
RR
121{
122public:
87f0efe2
RR
123
124 wxDataViewHeaderWindowMSW( wxDataViewCtrl *parent,
9861f022
RR
125 wxWindowID id,
126 const wxPoint &pos = wxDefaultPosition,
127 const wxSize &size = wxDefaultSize,
128 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 129 {
87f0efe2
RR
130 Create(parent, id, pos, size, name);
131 }
4ed7af08 132
87f0efe2 133 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 134 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
135 const wxString &name);
136
137 ~wxDataViewHeaderWindowMSW();
138
9861f022
RR
139 // called when any column setting is changed and/or changed
140 // the column count
87f0efe2 141 virtual void UpdateDisplay();
cfa42cb8 142
fc8c1a15 143 virtual void OnInternalIdle();
87f0efe2 144
70a9e561 145 // called Refresh afterwards
87f0efe2 146 virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL);
cfa42cb8
JS
147
148 virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
87f0efe2
RR
149
150protected:
151 virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
cfa42cb8 152
9861f022
RR
153 virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags);
154
70a9e561
RR
155 wxSize DoGetBestSize() const;
156
9861f022
RR
157 unsigned int GetColumnIdxFromHeader(NMHEADER *nmHDR);
158
159 wxDataViewColumn *GetColumnFromHeader(NMHEADER *nmHDR)
160 { return GetColumn(GetColumnIdxFromHeader(nmHDR)); }
cfa42cb8 161
fc8c1a15
RR
162 int m_scrollOffsetX;
163 int m_buttonHeight;
164 bool m_delayedUpdate;
9861f022 165
87f0efe2
RR
166private:
167 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW)
168};
169
170#else // !defined(__WXMSW__)
171
172#define HEADER_WINDOW_HEIGHT 25
9861f022
RR
173#define HEADER_HORIZ_BORDER 5
174#define HEADER_VERT_BORDER 3
87f0efe2
RR
175#define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
176
177class wxGenericDataViewHeaderWindow : public wxDataViewHeaderWindowBase
178{
179public:
180 wxGenericDataViewHeaderWindow( wxDataViewCtrl *parent,
181 wxWindowID id,
182 const wxPoint &pos = wxDefaultPosition,
183 const wxSize &size = wxDefaultSize,
184 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 185 {
87f0efe2
RR
186 Init();
187 Create(parent, id, pos, size, name);
188 }
189
190 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 191 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
192 const wxString &name);
193
194 ~wxGenericDataViewHeaderWindow()
195 {
196 delete m_resizeCursor;
197 }
198
c3112d56 199 virtual void UpdateDisplay() { Refresh(); }
442c56e6 200
87f0efe2 201 // event handlers:
4ed7af08 202
a0f3af5f
RR
203 void OnPaint( wxPaintEvent &event );
204 void OnMouse( wxMouseEvent &event );
205 void OnSetFocus( wxFocusEvent &event );
f554a14b 206
87f0efe2
RR
207
208protected:
209
210 // vars used for column resizing:
211
a0f3af5f 212 wxCursor *m_resizeCursor;
87f0efe2
RR
213 const wxCursor *m_currentCursor;
214 bool m_isDragging;
215
216 bool m_dirty; // needs refresh?
cc28f5ec 217 int m_hover; // index of the column under the mouse
87f0efe2
RR
218 int m_column; // index of the column being resized
219 int m_currentX; // divider line position in logical (unscrolled) coords
c741d33f 220 int m_minX; // minimal position beyond which the divider line
87f0efe2
RR
221 // can't be dragged in logical coords
222
9861f022
RR
223 // the pen used to draw the current column width drag line
224 // when resizing the columsn
225 wxPen m_penCurrent;
226
227
87f0efe2
RR
228 // internal utilities:
229
230 void Init()
231 {
232 m_currentCursor = (wxCursor *) NULL;
233 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
234
235 m_isDragging = false;
236 m_dirty = false;
237
cc28f5ec 238 m_hover = wxNOT_FOUND;
87f0efe2
RR
239 m_column = wxNOT_FOUND;
240 m_currentX = 0;
241 m_minX = 0;
9861f022
RR
242
243 wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
244 m_penCurrent = wxPen(col, 1, wxSOLID);
87f0efe2
RR
245 }
246
87f0efe2 247 void AdjustDC(wxDC& dc);
f554a14b 248
a0f3af5f 249private:
87f0efe2 250 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow)
a0f3af5f
RR
251 DECLARE_EVENT_TABLE()
252};
4ed7af08 253
87f0efe2
RR
254#endif // defined(__WXMSW__)
255
0fcce6b9
RR
256//-----------------------------------------------------------------------------
257// wxDataViewRenameTimer
258//-----------------------------------------------------------------------------
259
260class wxDataViewRenameTimer: public wxTimer
261{
262private:
263 wxDataViewMainWindow *m_owner;
264
265public:
266 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
267 void Notify();
268};
269
aba9bfd0
RR
270//-----------------------------------------------------------------------------
271// wxDataViewTreeNode
272//-----------------------------------------------------------------------------
442c56e6 273class wxDataViewTreeNode;
57f2a652
RR
274WX_DEFINE_ARRAY( wxDataViewTreeNode *, wxDataViewTreeNodes );
275WX_DEFINE_ARRAY( void* , wxDataViewTreeLeaves);
d47db7e0 276
57f2a652
RR
277int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1, wxDataViewTreeNode ** node2);
278int LINKAGEMODE wxGenericTreeModelItemCmp( void ** id1, void ** id2);
aba9bfd0
RR
279
280class wxDataViewTreeNode
281{
282public:
b7e9f8b1 283 wxDataViewTreeNode( wxDataViewTreeNode * parent = NULL )
b5ec7dd6 284 {
438fb233
RR
285 m_parent = parent;
286 if (!parent)
287 m_open = true;
288 else
289 m_open = false;
290 m_hasChildren = false;
291 m_subTreeCount = 0;
292 }
b5ec7dd6 293
aba9bfd0 294 ~wxDataViewTreeNode()
d47db7e0 295 {
d47db7e0 296 }
aba9bfd0 297
438fb233
RR
298 wxDataViewTreeNode * GetParent() { return m_parent; }
299 void SetParent( wxDataViewTreeNode * parent ) { m_parent = parent; }
300 wxDataViewTreeNodes & GetNodes() { return m_nodes; }
301 wxDataViewTreeLeaves & GetChildren() { return m_leaves; }
442c56e6
VZ
302
303 void AddNode( wxDataViewTreeNode * node )
d47db7e0 304 {
438fb233 305 m_leaves.Add( node->GetItem().GetID() );
24c4a50f 306 if (g_column >= -1)
438fb233
RR
307 m_leaves.Sort( &wxGenericTreeModelItemCmp );
308 m_nodes.Add( node );
24c4a50f 309 if (g_column >= -1)
438fb233 310 m_nodes.Sort( &wxGenericTreeModelNodeCmp );
57f2a652 311 }
b7fe2261
VZ
312 void AddLeaf( void * leaf )
313 {
438fb233 314 m_leaves.Add( leaf );
24c4a50f 315 if (g_column >= -1)
438fb233 316 m_leaves.Sort( &wxGenericTreeModelItemCmp );
d47db7e0 317 }
aba9bfd0 318
438fb233
RR
319 wxDataViewItem & GetItem() { return m_item; }
320 void SetItem( const wxDataViewItem & item ) { m_item = item; }
aba9bfd0 321
438fb233
RR
322 unsigned int GetChildrenNumber() { return m_leaves.GetCount(); }
323 unsigned int GetNodeNumber() { return m_nodes.GetCount(); }
3b6280be
RR
324 int GetIndentLevel()
325 {
326 int ret = 0 ;
438fb233
RR
327 wxDataViewTreeNode * node = this;
328 while( node->GetParent()->GetParent() != NULL )
329 {
330 node = node->GetParent();
331 ret ++;
332 }
333 return ret;
3b6280be 334 }
aba9bfd0 335
442c56e6
VZ
336 bool IsOpen()
337 {
438fb233 338 return m_open ;
442c56e6 339 }
d47db7e0
RR
340
341 void ToggleOpen()
442c56e6 342 {
438fb233 343 int len = m_nodes.GetCount();
d47db7e0
RR
344 int sum = 0;
345 for ( int i = 0 ;i < len ; i ++)
438fb233 346 sum += m_nodes[i]->GetSubTreeCount();
d47db7e0 347
438fb233
RR
348 sum += m_leaves.GetCount();
349 if (m_open)
d47db7e0
RR
350 {
351 ChangeSubTreeCount(-sum);
438fb233 352 m_open = !m_open;
d47db7e0
RR
353 }
354 else
355 {
438fb233 356 m_open = !m_open;
d47db7e0
RR
357 ChangeSubTreeCount(sum);
358 }
359 }
438fb233
RR
360 bool HasChildren() { return m_hasChildren; }
361 void SetHasChildren( bool has ){ m_hasChildren = has; }
d47db7e0 362
438fb233
RR
363 void SetSubTreeCount( int num ) { m_subTreeCount = num; }
364 int GetSubTreeCount() { return m_subTreeCount; }
442c56e6 365 void ChangeSubTreeCount( int num )
d47db7e0 366 {
438fb233 367 if( !m_open )
d47db7e0 368 return ;
438fb233
RR
369 m_subTreeCount += num;
370 if( m_parent )
371 m_parent->ChangeSubTreeCount(num);
d47db7e0
RR
372 }
373
d3f00f59
VZ
374 void Resort()
375 {
24c4a50f 376 if (g_column >= -1)
d3f00f59 377 {
438fb233
RR
378 m_nodes.Sort( &wxGenericTreeModelNodeCmp );
379 int len = m_nodes.GetCount();
57f2a652 380 for (int i = 0; i < len; i ++)
438fb233
RR
381 m_nodes[i]->Resort();
382 m_leaves.Sort( &wxGenericTreeModelItemCmp );
d3f00f59
VZ
383 }
384 }
385
aba9bfd0 386private:
438fb233
RR
387 wxDataViewTreeNode *m_parent;
388 wxDataViewTreeNodes m_nodes;
389 wxDataViewTreeLeaves m_leaves;
390 wxDataViewItem m_item;
391 bool m_open;
392 bool m_hasChildren;
393 int m_subTreeCount;
aba9bfd0
RR
394};
395
57f2a652 396int LINKAGEMODE wxGenericTreeModelNodeCmp( wxDataViewTreeNode ** node1, wxDataViewTreeNode ** node2)
d47db7e0 397{
57f2a652 398 return g_model->Compare( (*node1)->GetItem(), (*node2)->GetItem(), g_column, g_asending );
d47db7e0
RR
399}
400
57f2a652 401int LINKAGEMODE wxGenericTreeModelItemCmp( void ** id1, void ** id2)
d47db7e0 402{
57f2a652 403 return g_model->Compare( *id1, *id2, g_column, g_asending );
d47db7e0
RR
404}
405
406
407
a0f3af5f
RR
408//-----------------------------------------------------------------------------
409// wxDataViewMainWindow
410//-----------------------------------------------------------------------------
4ed7af08 411
c741d33f 412WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection,
87f0efe2 413 WXDLLIMPEXP_ADV);
351461fc 414WX_DECLARE_LIST(wxDataViewItem, ItemList);
a76c2f37 415WX_DEFINE_LIST(ItemList)
cab07038 416
a0f3af5f 417class wxDataViewMainWindow: public wxWindow
4ed7af08 418{
a0f3af5f
RR
419public:
420 wxDataViewMainWindow( wxDataViewCtrl *parent,
421 wxWindowID id,
422 const wxPoint &pos = wxDefaultPosition,
423 const wxSize &size = wxDefaultSize,
424 const wxString &name = wxT("wxdataviewctrlmainwindow") );
d3c7fc99 425 virtual ~wxDataViewMainWindow();
4ed7af08 426
aba9bfd0
RR
427 // notifications from wxDataViewModel
428 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
32143117 429 bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item );
aba9bfd0
RR
430 bool ItemChanged( const wxDataViewItem &item );
431 bool ValueChanged( const wxDataViewItem &item, unsigned int col );
a0f3af5f 432 bool Cleared();
d3f00f59 433 void Resort()
b7fe2261 434 {
a3cc79d9
RR
435 if (m_root)
436 {
437 SortPrepare();
438 m_root->Resort();
439 }
b7fe2261 440 UpdateDisplay();
66e09788 441 }
4ed7af08 442
66e09788
RR
443 void SortPrepare()
444 {
b7fe2261 445 g_model = GetOwner()->GetModel();
57f2a652 446 wxDataViewColumn* col = GetOwner()->GetSortingColumn();
66e09788
RR
447 if( !col )
448 {
24c4a50f
RR
449 if (g_model->HasDefaultCompare())
450 g_column = -1;
451 else
452 g_column = -2;
453
66e09788
RR
454 g_asending = true;
455 return;
456 }
57f2a652 457 g_column = col->GetModelColumn();
b7fe2261 458 g_asending = col->IsSortOrderAscending();
66e09788 459 }
b7fe2261 460
a0f3af5f
RR
461 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
462 wxDataViewCtrl *GetOwner() { return m_owner; }
9861f022 463 const wxDataViewCtrl *GetOwner() const { return m_owner; }
4ed7af08 464
a0f3af5f 465 void OnPaint( wxPaintEvent &event );
0a71f9e9 466 void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event);
cab07038 467 void OnChar( wxKeyEvent &event );
a0f3af5f
RR
468 void OnMouse( wxMouseEvent &event );
469 void OnSetFocus( wxFocusEvent &event );
cab07038 470 void OnKillFocus( wxFocusEvent &event );
f554a14b 471
a0f3af5f
RR
472 void UpdateDisplay();
473 void RecalculateDisplay();
474 void OnInternalIdle();
f554a14b 475
0fcce6b9 476 void OnRenameTimer();
0fcce6b9 477
9861f022 478 void ScrollWindow( int dx, int dy, const wxRect *rect = NULL );
fbda518c 479 void ScrollTo( int rows, int column );
120b9b05 480
0a71f9e9
RR
481 bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; }
482 void ChangeCurrentRow( unsigned int row );
120b9b05 483
47b378bd 484 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }
cab07038 485 bool IsEmpty() { return GetRowCount() == 0; }
120b9b05 486
9861f022
RR
487 int GetCountPerPage() const;
488 int GetEndOfLastCol() const;
489 unsigned int GetFirstVisibleRow() const;
3b6280be
RR
490 //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
491 unsigned int GetLastVisibleRow();
492 unsigned int GetRowCount() ;
120b9b05 493
fbda518c 494 wxDataViewItem GetSelection() const;
b7e9f8b1
RR
495 wxDataViewSelection GetSelections(){ return m_selection; }
496 void SetSelections( const wxDataViewSelection & sel ) { m_selection = sel; UpdateDisplay(); }
87f0efe2 497 void Select( const wxArrayInt& aSelections );
cab07038 498 void SelectAllRows( bool on );
0a71f9e9
RR
499 void SelectRow( unsigned int row, bool on );
500 void SelectRows( unsigned int from, unsigned int to, bool on );
501 void ReverseRowSelection( unsigned int row );
502 bool IsRowSelected( unsigned int row );
526e19e2 503 void SendSelectionChangedEvent( const wxDataViewItem& item);
120b9b05 504
0a71f9e9
RR
505 void RefreshRow( unsigned int row );
506 void RefreshRows( unsigned int from, unsigned int to );
507 void RefreshRowsAfter( unsigned int firstRow );
120b9b05 508
9861f022
RR
509 // returns the colour to be used for drawing the rules
510 wxColour GetRuleColour() const
511 {
512 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
513 }
514
9861f022
RR
515 wxRect GetLineRect( unsigned int row ) const;
516
aba9bfd0 517 //Some useful functions for row and item mapping
fbda518c 518 wxDataViewItem GetItemByRow( unsigned int row ) const;
b7e9f8b1 519 int GetRowByItem( const wxDataViewItem & item );
aba9bfd0
RR
520
521 //Methods for building the mapping tree
522 void BuildTree( wxDataViewModel * model );
523 void DestroyTree();
a87b466d 524 void HitTest( const wxPoint & point, wxDataViewItem & item, wxDataViewColumn* &column );
fbda518c 525 wxRect GetItemRect( const wxDataViewItem & item, const wxDataViewColumn* column );
afebb87b
RR
526
527 void Expand( unsigned int row ) { OnExpanding( row ); }
528 void Collapse( unsigned int row ) { OnCollapsing( row ); }
3b6280be
RR
529private:
530 wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row );
704c3490
RR
531 //We did not need this temporarily
532 //wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
3b6280be
RR
533
534 int RecalculateCount() ;
535
66e09788 536 wxDataViewEvent SendExpanderEvent( wxEventType type, const wxDataViewItem & item );
3b6280be
RR
537 void OnExpanding( unsigned int row );
538 void OnCollapsing( unsigned int row );
aba9bfd0 539
442c56e6 540 wxDataViewTreeNode * FindNode( const wxDataViewItem & item );
351461fc 541
a0f3af5f 542private:
0fcce6b9
RR
543 wxDataViewCtrl *m_owner;
544 int m_lineHeight;
545 bool m_dirty;
120b9b05 546
0fcce6b9 547 wxDataViewColumn *m_currentCol;
99d471a5 548 unsigned int m_currentRow;
cab07038 549 wxDataViewSelection m_selection;
120b9b05 550
0fcce6b9 551 wxDataViewRenameTimer *m_renameTimer;
0fcce6b9 552 bool m_lastOnSame;
f554a14b 553
cab07038
RR
554 bool m_hasFocus;
555
e21f75bd
RR
556 int m_dragCount;
557 wxPoint m_dragStart;
558
559 // for double click logic
0a71f9e9 560 unsigned int m_lineLastClicked,
e21f75bd
RR
561 m_lineBeforeLastClicked,
562 m_lineSelectSingleOnUp;
cab07038 563
9861f022
RR
564 // the pen used to draw horiz/vertical rules
565 wxPen m_penRule;
566
3b6280be
RR
567 // the pen used to draw the expander and the lines
568 wxPen m_penExpander;
569
aba9bfd0 570 //This is the tree structure of the model
442c56e6 571 wxDataViewTreeNode * m_root;
3b6280be 572 int m_count;
24c4a50f
RR
573 //This is the tree node under the cursor
574 wxDataViewTreeNode * m_underMouse;
a0f3af5f
RR
575private:
576 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
577 DECLARE_EVENT_TABLE()
578};
4ed7af08 579
f554a14b 580// ---------------------------------------------------------
aba9bfd0 581// wxGenericDataViewModelNotifier
f554a14b 582// ---------------------------------------------------------
a0f3af5f 583
aba9bfd0 584class wxGenericDataViewModelNotifier: public wxDataViewModelNotifier
4ed7af08 585{
a0f3af5f 586public:
aba9bfd0 587 wxGenericDataViewModelNotifier( wxDataViewMainWindow *mainWindow )
a0f3af5f 588 { m_mainWindow = mainWindow; }
f554a14b 589
aba9bfd0
RR
590 virtual bool ItemAdded( const wxDataViewItem & parent, const wxDataViewItem & item )
591 { return m_mainWindow->ItemAdded( parent , item ); }
442c56e6 592 virtual bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
071691a0 593 { return m_mainWindow->ItemDeleted( parent, item ); }
aba9bfd0
RR
594 virtual bool ItemChanged( const wxDataViewItem & item )
595 { return m_mainWindow->ItemChanged(item); }
596 virtual bool ValueChanged( const wxDataViewItem & item , unsigned int col )
597 { return m_mainWindow->ValueChanged( item, col ); }
a0f3af5f
RR
598 virtual bool Cleared()
599 { return m_mainWindow->Cleared(); }
d3f00f59 600 virtual void Resort()
9bcc8016 601 { m_mainWindow->Resort(); }
f554a14b 602
a0f3af5f
RR
603 wxDataViewMainWindow *m_mainWindow;
604};
4ed7af08 605
f554a14b 606// ---------------------------------------------------------
baa9ebc4 607// wxDataViewRenderer
f554a14b 608// ---------------------------------------------------------
4ed7af08 609
baa9ebc4 610IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
4ed7af08 611
c741d33f 612wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype,
9861f022
RR
613 wxDataViewCellMode mode,
614 int align) :
615 wxDataViewRendererBase( varianttype, mode, align )
4ed7af08 616{
3d9d7cc4 617 m_dc = NULL;
9861f022
RR
618 m_align = align;
619 m_mode = mode;
4264606e
RR
620 m_wantsAttr = false;
621 m_hasAttr = false;
4ed7af08
RR
622}
623
baa9ebc4 624wxDataViewRenderer::~wxDataViewRenderer()
3d9d7cc4
RR
625{
626 if (m_dc)
627 delete m_dc;
628}
629
baa9ebc4 630wxDC *wxDataViewRenderer::GetDC()
3d9d7cc4
RR
631{
632 if (m_dc == NULL)
633 {
634 if (GetOwner() == NULL)
635 return NULL;
636 if (GetOwner()->GetOwner() == NULL)
637 return NULL;
638 m_dc = new wxClientDC( GetOwner()->GetOwner() );
639 }
f554a14b 640
3d9d7cc4
RR
641 return m_dc;
642}
643
e51bf699
RR
644void wxDataViewRenderer::SetAlignment( int align )
645{
646 m_align=align;
647}
648
649int wxDataViewRenderer::GetAlignment() const
650{
651 return m_align;
652}
653
654int wxDataViewRenderer::CalculateAlignment() const
655{
656 if (m_align == wxDVR_DEFAULT_ALIGNMENT)
657 {
658 if (GetOwner() == NULL)
659 return wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL;
660
661 return GetOwner()->GetAlignment() | wxALIGN_CENTRE_VERTICAL;
662 }
663
664 return m_align;
665}
666
f554a14b 667// ---------------------------------------------------------
baa9ebc4 668// wxDataViewCustomRenderer
f554a14b 669// ---------------------------------------------------------
3d9d7cc4 670
baa9ebc4 671IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
3d9d7cc4 672
baa9ebc4 673wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
9861f022
RR
674 wxDataViewCellMode mode, int align ) :
675 wxDataViewRenderer( varianttype, mode, align )
3d9d7cc4
RR
676{
677}
678
52e750fc
RR
679void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset, wxRect cell, wxDC *dc, int state )
680{
681 wxDataViewCtrl *view = GetOwner()->GetOwner();
682 wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ?
683 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) :
684 view->GetForegroundColour();
685 dc->SetTextForeground(col);
686 dc->DrawText( text, cell.x + xoffset, cell.y + ((cell.height - dc->GetCharHeight()) / 2));
687}
688
f554a14b 689// ---------------------------------------------------------
baa9ebc4 690// wxDataViewTextRenderer
f554a14b 691// ---------------------------------------------------------
4ed7af08 692
baa9ebc4 693IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer)
4ed7af08 694
c741d33f 695wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype,
9861f022
RR
696 wxDataViewCellMode mode, int align ) :
697 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
698{
699}
700
baa9ebc4 701bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
4ed7af08 702{
90675b95 703 m_text = value.GetString();
f554a14b 704
90675b95 705 return true;
4ed7af08
RR
706}
707
9861f022 708bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
4ed7af08
RR
709{
710 return false;
711}
712
99d471a5 713bool wxDataViewTextRenderer::HasEditorCtrl()
442c56e6 714{
99d471a5
RR
715 return true;
716}
717
718wxControl* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow *parent,
719 wxRect labelRect, const wxVariant &value )
720{
442c56e6 721 return new wxTextCtrl( parent, wxID_ANY, value,
99d471a5
RR
722 wxPoint(labelRect.x,labelRect.y),
723 wxSize(labelRect.width,labelRect.height) );
724}
725
726bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl *editor, wxVariant &value )
727{
728 wxTextCtrl *text = (wxTextCtrl*) editor;
729 value = text->GetValue();
730 return true;
731}
732
87f0efe2 733bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int state )
3d9d7cc4 734{
52e750fc 735 RenderText( m_text, 0, cell, dc, state );
90675b95 736 return true;
3d9d7cc4
RR
737}
738
9861f022 739wxSize wxDataViewTextRenderer::GetSize() const
3d9d7cc4 740{
9861f022 741 const wxDataViewCtrl *view = GetView();
87f0efe2
RR
742 if (!m_text.empty())
743 {
744 int x,y;
745 view->GetTextExtent( m_text, &x, &y );
746 return wxSize( x, y );
747 }
3d9d7cc4
RR
748 return wxSize(80,20);
749}
750
4264606e
RR
751// ---------------------------------------------------------
752// wxDataViewTextRendererAttr
753// ---------------------------------------------------------
754
755IMPLEMENT_CLASS(wxDataViewTextRendererAttr, wxDataViewTextRenderer)
756
757wxDataViewTextRendererAttr::wxDataViewTextRendererAttr( const wxString &varianttype,
758 wxDataViewCellMode mode, int align ) :
759 wxDataViewTextRenderer( varianttype, mode, align )
760{
761 m_wantsAttr = true;
762}
763
764bool wxDataViewTextRendererAttr::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
765{
766 wxFont font;
767 wxColour colour;
768
769 if (m_hasAttr)
770 {
771 if (m_attr.HasColour())
772 {
773 colour = dc->GetTextForeground();
774 dc->SetTextForeground( m_attr.GetColour() );
775 }
cfa42cb8 776
4264606e
RR
777 if (m_attr.GetBold() || m_attr.GetItalic())
778 {
779 font = dc->GetFont();
780 wxFont myfont = font;
781 if (m_attr.GetBold())
782 myfont.SetWeight( wxFONTWEIGHT_BOLD );
783 if (m_attr.GetItalic())
784 myfont.SetStyle( wxFONTSTYLE_ITALIC );
785 dc->SetFont( myfont );
786 }
787 }
cfa42cb8 788
4264606e 789 dc->DrawText( m_text, cell.x, cell.y + ((cell.height - dc->GetCharHeight()) / 2));
cfa42cb8 790
4264606e
RR
791 // restore dc
792 if (m_hasAttr)
793 {
794 if (m_attr.HasColour())
795 dc->SetTextForeground( colour );
cfa42cb8 796
4264606e
RR
797 if (m_attr.GetBold() || m_attr.GetItalic())
798 dc->SetFont( font );
799 }
cfa42cb8 800
4264606e
RR
801 return true;
802}
cfa42cb8 803
4264606e 804
2586d4a1 805// ---------------------------------------------------------
baa9ebc4 806// wxDataViewBitmapRenderer
2586d4a1
RR
807// ---------------------------------------------------------
808
baa9ebc4 809IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer)
2586d4a1 810
c741d33f 811wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype,
9861f022
RR
812 wxDataViewCellMode mode, int align ) :
813 wxDataViewCustomRenderer( varianttype, mode, align )
2586d4a1
RR
814{
815}
816
baa9ebc4 817bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
2586d4a1
RR
818{
819 if (value.GetType() == wxT("wxBitmap"))
820 m_bitmap << value;
821 if (value.GetType() == wxT("wxIcon"))
822 m_icon << value;
823
824 return true;
825}
826
9861f022 827bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
2586d4a1
RR
828{
829 return false;
830}
831
baa9ebc4 832bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2586d4a1
RR
833{
834 if (m_bitmap.Ok())
835 dc->DrawBitmap( m_bitmap, cell.x, cell.y );
836 else if (m_icon.Ok())
837 dc->DrawIcon( m_icon, cell.x, cell.y );
838
839 return true;
840}
841
9861f022 842wxSize wxDataViewBitmapRenderer::GetSize() const
2586d4a1
RR
843{
844 if (m_bitmap.Ok())
845 return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() );
846 else if (m_icon.Ok())
847 return wxSize( m_icon.GetWidth(), m_icon.GetHeight() );
848
849 return wxSize(16,16);
850}
851
f554a14b 852// ---------------------------------------------------------
baa9ebc4 853// wxDataViewToggleRenderer
f554a14b 854// ---------------------------------------------------------
4ed7af08 855
baa9ebc4 856IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer)
4ed7af08 857
baa9ebc4 858wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
9861f022
RR
859 wxDataViewCellMode mode, int align ) :
860 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08 861{
90675b95 862 m_toggle = false;
4ed7af08
RR
863}
864
baa9ebc4 865bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
4ed7af08 866{
90675b95 867 m_toggle = value.GetBool();
f554a14b 868
a8461d31 869 return true;
4ed7af08
RR
870}
871
9861f022 872bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
4ed7af08
RR
873{
874 return false;
875}
f554a14b 876
baa9ebc4 877bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08 878{
90675b95 879 // User wxRenderer here
f554a14b 880
90675b95
RR
881 wxRect rect;
882 rect.x = cell.x + cell.width/2 - 10;
883 rect.width = 20;
884 rect.y = cell.y + cell.height/2 - 10;
885 rect.height = 20;
120b9b05 886
862d8041 887 int flags = 0;
90675b95 888 if (m_toggle)
862d8041
RR
889 flags |= wxCONTROL_CHECKED;
890 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
891 flags |= wxCONTROL_DISABLED;
892
90b903c2 893 wxRendererNative::Get().DrawCheckBox(
862d8041
RR
894 GetOwner()->GetOwner(),
895 *dc,
896 rect,
897 flags );
f554a14b 898
90675b95 899 return true;
4ed7af08
RR
900}
901
c741d33f 902bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell),
aba9bfd0
RR
903 wxDataViewModel *model,
904 const wxDataViewItem & item, unsigned int col)
0fdc2321
RR
905{
906 bool value = !m_toggle;
907 wxVariant variant = value;
aba9bfd0
RR
908 model->SetValue( variant, item, col);
909 model->ValueChanged( item, col );
0fdc2321
RR
910 return true;
911}
912
9861f022 913wxSize wxDataViewToggleRenderer::GetSize() const
4ed7af08 914{
3d9d7cc4 915 return wxSize(20,20);
4ed7af08
RR
916}
917
f554a14b 918// ---------------------------------------------------------
baa9ebc4 919// wxDataViewProgressRenderer
f554a14b 920// ---------------------------------------------------------
4ed7af08 921
baa9ebc4 922IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
4ed7af08 923
baa9ebc4 924wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
9861f022
RR
925 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
926 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
927{
928 m_label = label;
929 m_value = 0;
930}
931
baa9ebc4 932wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
4ed7af08
RR
933{
934}
935
baa9ebc4 936bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
937{
938 m_value = (long) value;
f554a14b 939
4ed7af08
RR
940 if (m_value < 0) m_value = 0;
941 if (m_value > 100) m_value = 100;
f554a14b 942
4ed7af08
RR
943 return true;
944}
f554a14b 945
9861f022
RR
946bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
947{
948 value = (long) m_value;
949 return true;
950}
951
baa9ebc4 952bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
953{
954 double pct = (double)m_value / 100.0;
955 wxRect bar = cell;
956 bar.width = (int)(cell.width * pct);
957 dc->SetPen( *wxTRANSPARENT_PEN );
958 dc->SetBrush( *wxBLUE_BRUSH );
959 dc->DrawRectangle( bar );
960
961 dc->SetBrush( *wxTRANSPARENT_BRUSH );
962 dc->SetPen( *wxBLACK_PEN );
963 dc->DrawRectangle( cell );
f554a14b 964
4ed7af08
RR
965 return true;
966}
967
9861f022 968wxSize wxDataViewProgressRenderer::GetSize() const
4ed7af08
RR
969{
970 return wxSize(40,12);
971}
f554a14b
WS
972
973// ---------------------------------------------------------
baa9ebc4 974// wxDataViewDateRenderer
f554a14b 975// ---------------------------------------------------------
4ed7af08 976
21ead767
VZ
977#define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
978
979#if wxUSE_DATE_RENDERER_POPUP
8d0ca292 980
baa9ebc4 981class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
4ed7af08 982{
f554a14b 983public:
baa9ebc4 984 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
aba9bfd0
RR
985 wxDataViewModel *model, const wxDataViewItem & item, unsigned int col) :
986 wxPopupTransientWindow( parent, wxBORDER_SIMPLE ),
987 m_item( item )
4ed7af08
RR
988 {
989 m_model = model;
990 m_col = col;
f554a14b 991 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
4ed7af08
RR
992 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
993 sizer->Add( m_cal, 1, wxGROW );
994 SetSizer( sizer );
995 sizer->Fit( this );
996 }
f554a14b 997
4ed7af08 998 void OnCalendar( wxCalendarEvent &event );
f554a14b 999
4ed7af08 1000 wxCalendarCtrl *m_cal;
aba9bfd0 1001 wxDataViewModel *m_model;
0a71f9e9 1002 unsigned int m_col;
aba9bfd0 1003 const wxDataViewItem & m_item;
f554a14b 1004
a8461d31
PC
1005protected:
1006 virtual void OnDismiss()
1007 {
1008 }
1009
4ed7af08
RR
1010private:
1011 DECLARE_EVENT_TABLE()
1012};
1013
baa9ebc4
RR
1014BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
1015 EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar )
4ed7af08
RR
1016END_EVENT_TABLE()
1017
baa9ebc4 1018void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
4ed7af08
RR
1019{
1020 wxDateTime date = event.GetDate();
1021 wxVariant value = date;
aba9bfd0
RR
1022 m_model->SetValue( value, m_item, m_col );
1023 m_model->ValueChanged( m_item, m_col );
4ed7af08
RR
1024 DismissAndNotify();
1025}
1026
21ead767 1027#endif // wxUSE_DATE_RENDERER_POPUP
8d0ca292 1028
baa9ebc4 1029IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
4ed7af08 1030
baa9ebc4 1031wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
9861f022
RR
1032 wxDataViewCellMode mode, int align ) :
1033 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
1034{
1035}
f554a14b 1036
baa9ebc4 1037bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
1038{
1039 m_date = value.GetDateTime();
f554a14b 1040
4ed7af08
RR
1041 return true;
1042}
1043
9861f022
RR
1044bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const
1045{
1046 value = m_date;
1047 return true;
1048}
1049
52e750fc 1050bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
4ed7af08 1051{
4ed7af08 1052 wxString tmp = m_date.FormatDate();
52e750fc 1053 RenderText( tmp, 0, cell, dc, state );
4ed7af08
RR
1054 return true;
1055}
1056
9861f022 1057wxSize wxDataViewDateRenderer::GetSize() const
4ed7af08 1058{
9861f022 1059 const wxDataViewCtrl* view = GetView();
4ed7af08
RR
1060 wxString tmp = m_date.FormatDate();
1061 wxCoord x,y,d;
1062 view->GetTextExtent( tmp, &x, &y, &d );
1063 return wxSize(x,y+d);
1064}
1065
aba9bfd0
RR
1066bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model,
1067 const wxDataViewItem & item, unsigned int col )
4ed7af08
RR
1068{
1069 wxVariant variant;
aba9bfd0 1070 model->GetValue( variant, item, col );
4ed7af08
RR
1071 wxDateTime value = variant.GetDateTime();
1072
21ead767 1073#if wxUSE_DATE_RENDERER_POPUP
baa9ebc4 1074 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
aba9bfd0 1075 GetOwner()->GetOwner()->GetParent(), &value, model, item, col);
4ed7af08
RR
1076 wxPoint pos = wxGetMousePosition();
1077 popup->Move( pos );
1078 popup->Layout();
1079 popup->Popup( popup->m_cal );
21ead767 1080#else // !wxUSE_DATE_RENDERER_POPUP
8d0ca292 1081 wxMessageBox(value.Format());
21ead767 1082#endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
4ed7af08
RR
1083 return true;
1084}
1085
b7fe2261 1086// ---------------------------------------------------------
24c4a50f 1087// wxDataViewIconTextRenderer
b7fe2261 1088// ---------------------------------------------------------
24c4a50f
RR
1089
1090IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer)
1091
b7fe2261 1092wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(
24c4a50f
RR
1093 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
1094 wxDataViewCustomRenderer( varianttype, mode, align )
1095{
1096 SetMode(mode);
1097 SetAlignment(align);
1098}
1099
1100wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
1101{
1102}
b7fe2261 1103
24c4a50f
RR
1104bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
1105{
1106 m_value << value;
1107 return true;
1108}
1109
b5ec7dd6 1110bool wxDataViewIconTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
24c4a50f
RR
1111{
1112 return false;
1113}
b7fe2261 1114
24c4a50f
RR
1115bool wxDataViewIconTextRenderer::Render( wxRect cell, wxDC *dc, int state )
1116{
52e750fc 1117 int xoffset = 0;
24c4a50f
RR
1118 const wxIcon &icon = m_value.GetIcon();
1119 if (icon.IsOk())
1120 {
b5ec7dd6 1121 dc->DrawIcon( icon, cell.x, cell.y + ((cell.height - icon.GetHeight()) / 2));
52e750fc 1122 xoffset = icon.GetWidth()+4;
24c4a50f 1123 }
b5ec7dd6 1124
52e750fc 1125 RenderText( m_value.GetText(), xoffset, cell, dc, state );
24c4a50f
RR
1126
1127 return true;
1128}
1129
1130wxSize wxDataViewIconTextRenderer::GetSize() const
1131{
e44ac7bc
RR
1132 const wxDataViewCtrl *view = GetView();
1133 if (!m_value.GetText().empty())
1134 {
1135 int x,y;
1136 view->GetTextExtent( m_value.GetText(), &x, &y );
b5ec7dd6 1137
e44ac7bc
RR
1138 if (m_value.GetIcon().IsOk())
1139 x += m_value.GetIcon().GetWidth() + 4;
1140 return wxSize( x, y );
1141 }
1142 return wxSize(80,20);
24c4a50f
RR
1143}
1144
b5ec7dd6
VZ
1145wxControl *
1146wxDataViewIconTextRenderer::CreateEditorCtrl(wxWindow * WXUNUSED(parent),
1147 wxRect WXUNUSED(labelRect),
1148 const wxVariant& WXUNUSED(value))
24c4a50f
RR
1149{
1150 return NULL;
1151}
1152
b5ec7dd6
VZ
1153bool
1154wxDataViewIconTextRenderer::GetValueFromEditorCtrl(wxControl* WXUNUSED(editor),
1155 wxVariant& WXUNUSED(value))
24c4a50f
RR
1156{
1157 return false;
1158}
1159
f554a14b 1160// ---------------------------------------------------------
4ed7af08 1161// wxDataViewColumn
f554a14b 1162// ---------------------------------------------------------
4ed7af08
RR
1163
1164IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
1165
c741d33f 1166wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
87f0efe2
RR
1167 unsigned int model_column,
1168 int width, wxAlignment align, int flags ) :
1169 wxDataViewColumnBase( title, cell, model_column, width, align, flags )
4ed7af08 1170{
9861f022
RR
1171 SetAlignment(align);
1172 SetTitle(title);
1173 SetFlags(flags);
1174
ad386793 1175 m_autosize = width < 0; // TODO
f210b1b5 1176
9861f022 1177 Init(width < 0 ? wxDVC_DEFAULT_WIDTH : width);
4ed7af08
RR
1178}
1179
c741d33f 1180wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
87f0efe2
RR
1181 unsigned int model_column,
1182 int width, wxAlignment align, int flags ) :
1183 wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
07a84e7b 1184{
9861f022
RR
1185 SetAlignment(align);
1186 SetFlags(flags);
1187
1188 Init(width < 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH : width);
07a84e7b
RR
1189}
1190
9861f022
RR
1191wxDataViewColumn::~wxDataViewColumn()
1192{
1193}
1194
1195void wxDataViewColumn::Init( int width )
47cef10f 1196{
87f0efe2 1197 m_width = width;
9861f022 1198 m_minWidth = wxDVC_DEFAULT_MINWIDTH;
c3112d56 1199 m_ascending = true;
47cef10f
RR
1200}
1201
9861f022 1202void wxDataViewColumn::SetResizeable( bool resizeable )
31fb32e1 1203{
9861f022
RR
1204 if (resizeable)
1205 m_flags |= wxDATAVIEW_COL_RESIZABLE;
1206 else
1207 m_flags &= ~wxDATAVIEW_COL_RESIZABLE;
1208}
1209
1210void wxDataViewColumn::SetHidden( bool hidden )
1211{
1212 if (hidden)
1213 m_flags |= wxDATAVIEW_COL_HIDDEN;
1214 else
1215 m_flags &= ~wxDATAVIEW_COL_HIDDEN;
1216
1217 // tell our owner to e.g. update its scrollbars:
1218 if (GetOwner())
1219 GetOwner()->OnColumnChange();
1220}
1221
1222void wxDataViewColumn::SetSortable( bool sortable )
1223{
1224 if (sortable)
1225 m_flags |= wxDATAVIEW_COL_SORTABLE;
1226 else
1227 m_flags &= ~wxDATAVIEW_COL_SORTABLE;
442c56e6 1228
c3112d56
RR
1229 // Update header button
1230 if (GetOwner())
1231 GetOwner()->OnColumnChange();
31fb32e1
RR
1232}
1233
99c75ebc
RR
1234void wxDataViewColumn::SetReorderable( bool reorderable )
1235{
309bd665
RR
1236 if (reorderable)
1237 m_flags |= wxDATAVIEW_COL_REORDERABLE;
1238 else
1239 m_flags &= ~wxDATAVIEW_COL_REORDERABLE;
99c75ebc
RR
1240}
1241
c3112d56 1242void wxDataViewColumn::SetSortOrder( bool ascending )
47cef10f 1243{
c3112d56 1244 m_ascending = ascending;
442c56e6 1245
c3112d56
RR
1246 // Update header button
1247 if (GetOwner())
1248 GetOwner()->OnColumnChange();
47cef10f
RR
1249}
1250
87f0efe2 1251bool wxDataViewColumn::IsSortOrderAscending() const
31fb32e1 1252{
c3112d56 1253 return m_ascending;
31fb32e1
RR
1254}
1255
9861f022 1256void wxDataViewColumn::SetInternalWidth( int width )
4ed7af08 1257{
9861f022 1258 m_width = width;
f554a14b 1259
9861f022
RR
1260 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
1261 if (m_owner && m_owner->m_clientArea)
1262 m_owner->m_clientArea->RecalculateDisplay();
4ed7af08
RR
1263}
1264
9861f022 1265void wxDataViewColumn::SetWidth( int width )
47cef10f 1266{
63779a3d 1267 if (m_owner->m_headerArea) m_owner->m_headerArea->UpdateDisplay();
47cef10f 1268
9861f022 1269 SetInternalWidth(width);
47cef10f
RR
1270}
1271
533544f2 1272
4ed7af08 1273//-----------------------------------------------------------------------------
87f0efe2 1274// wxDataViewHeaderWindowBase
4ed7af08
RR
1275//-----------------------------------------------------------------------------
1276
87f0efe2
RR
1277void wxDataViewHeaderWindowBase::SendEvent(wxEventType type, unsigned int n)
1278{
1279 wxWindow *parent = GetParent();
1280 wxDataViewEvent le(type, parent->GetId());
1281
1282 le.SetEventObject(parent);
1283 le.SetColumn(n);
1284 le.SetDataViewColumn(GetColumn(n));
1285 le.SetModel(GetOwner()->GetModel());
1286
1287 // for events created by wxDataViewHeaderWindow the
1288 // row / value fields are not valid
1289
1290 parent->GetEventHandler()->ProcessEvent(le);
1291}
1292
626b09ec 1293#ifdef USE_NATIVE_HEADER_WINDOW
87f0efe2 1294
e61d6c0b
VZ
1295#ifndef HDS_DRAGDROP
1296 #define HDS_DRAGDROP 0x0040
1297#endif
1298#ifndef HDS_FULLDRAG
1299 #define HDS_FULLDRAG 0x0080
1300#endif
1301
87f0efe2 1302// implemented in msw/listctrl.cpp:
a68962fc 1303int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
87f0efe2 1304
5d3f234b 1305IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW, wxWindow)
87f0efe2
RR
1306
1307bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl *parent, wxWindowID id,
c741d33f 1308 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
1309 const wxString &name )
1310{
1311 m_owner = parent;
1312
d81ad1f0 1313 m_scrollOffsetX = 0;
fc8c1a15 1314 m_delayedUpdate = false;
0d1c4ede 1315 m_buttonHeight = wxRendererNative::Get().GetHeaderButtonHeight( this );
87f0efe2
RR
1316
1317 int x = pos.x == wxDefaultCoord ? 0 : pos.x,
1318 y = pos.y == wxDefaultCoord ? 0 : pos.y,
1319 w = size.x == wxDefaultCoord ? 1 : size.x,
0d1c4ede 1320 h = m_buttonHeight;
87f0efe2 1321
0d1c4ede
RR
1322 wxSize new_size(w,h);
1323
1324 if ( !CreateControl(parent, id, pos, new_size, 0, wxDefaultValidator, name) )
70a9e561
RR
1325 return false;
1326
87f0efe2
RR
1327 // create the native WC_HEADER window:
1328 WXHWND hwndParent = (HWND)parent->GetHandle();
0677c6cb 1329 WXDWORD msStyle = WS_CHILD | HDS_DRAGDROP | HDS_BUTTONS | HDS_HORZ | HDS_HOTTRACK | HDS_FULLDRAG;
cfa42cb8 1330
70a9e561
RR
1331 if ( m_isShown )
1332 msStyle |= WS_VISIBLE;
cfa42cb8 1333
c741d33f
VZ
1334 m_hWnd = CreateWindowEx(0,
1335 WC_HEADER,
1336 (LPCTSTR) NULL,
87f0efe2
RR
1337 msStyle,
1338 x, y, w, h,
c741d33f
VZ
1339 (HWND)hwndParent,
1340 (HMENU)-1,
1341 wxGetInstance(),
87f0efe2 1342 (LPVOID) NULL);
c741d33f 1343 if (m_hWnd == NULL)
87f0efe2
RR
1344 {
1345 wxLogLastError(_T("CreateWindowEx"));
1346 return false;
1347 }
1348
5d3f234b 1349 // we need to subclass the m_hWnd to force wxWindow::HandleNotify
87f0efe2 1350 // to call wxDataViewHeaderWindow::MSWOnNotify
5d3f234b 1351 SubclassWin(m_hWnd);
87f0efe2 1352
c741d33f 1353 // the following is required to get the default win's font for
9861f022
RR
1354 // header windows and must be done befor sending the HDM_LAYOUT msg
1355 SetFont(GetFont());
cfa42cb8 1356
70a9e561
RR
1357 return true;
1358}
1359
1360wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow()
1361{
1362 UnsubclassWin();
1363}
1364
1365wxSize wxDataViewHeaderWindowMSW::DoGetBestSize() const
1366{
fc8c1a15
RR
1367 return wxSize( 80, m_buttonHeight+2 );
1368}
1369
1370void wxDataViewHeaderWindowMSW::OnInternalIdle()
1371{
1372 if (m_delayedUpdate)
1373 {
1374 m_delayedUpdate = false;
1375 UpdateDisplay();
1376 }
70a9e561
RR
1377}
1378
87f0efe2
RR
1379void wxDataViewHeaderWindowMSW::UpdateDisplay()
1380{
1381 // remove old columns
914e6945 1382 for (int j=0, max=Header_GetItemCount((HWND)m_hWnd); j < max; j++)
87f0efe2 1383 Header_DeleteItem((HWND)m_hWnd, 0);
c741d33f 1384
87f0efe2 1385 // add the updated array of columns to the header control
9861f022
RR
1386 unsigned int cols = GetOwner()->GetColumnCount();
1387 unsigned int added = 0;
87f0efe2
RR
1388 for (unsigned int i = 0; i < cols; i++)
1389 {
1390 wxDataViewColumn *col = GetColumn( i );
1391 if (col->IsHidden())
1392 continue; // don't add it!
1393
1394 HDITEM hdi;
1395 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
fab3f50e 1396 hdi.pszText = (wxChar *) col->GetTitle().wx_str();
87f0efe2
RR
1397 hdi.cxy = col->GetWidth();
1398 hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]);
1399 hdi.fmt = HDF_LEFT | HDF_STRING;
b7e9f8b1
RR
1400 //hdi.fmt &= ~(HDF_SORTDOWN|HDF_SORTUP);
1401
70a9e561 1402 if (col->IsSortable() && GetOwner()->GetSortingColumn() == col)
b7e9f8b1
RR
1403 {
1404 //The Microsoft Comctrl32.dll 6.0 support SORTUP/SORTDOWN, but they are not default
1405 //see http://msdn2.microsoft.com/en-us/library/ms649534.aspx for more detail
4bae66a8
RR
1406 // VZ: works with 5.81
1407 hdi.fmt |= col->IsSortOrderAscending() ? HDF_SORTUP : HDF_SORTDOWN;
b7e9f8b1 1408 }
9861f022
RR
1409
1410 // lParam is reserved for application's use:
1411 // we store there the column index to use it later in MSWOnNotify
1412 // (since columns may have been hidden)
1413 hdi.lParam = (LPARAM)i;
1414
1415 // the native wxMSW implementation of the header window
c741d33f 1416 // draws the column separator COLUMN_WIDTH_OFFSET pixels
9861f022
RR
1417 // on the right: to correct this effect we make the column
1418 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1419 if (i == 0)
1420 hdi.cxy += COLUMN_WIDTH_OFFSET;
1421
1422 switch (col->GetAlignment())
1423 {
1424 case wxALIGN_LEFT:
1425 hdi.fmt |= HDF_LEFT;
1426 break;
1427 case wxALIGN_CENTER:
1428 case wxALIGN_CENTER_HORIZONTAL:
1429 hdi.fmt |= HDF_CENTER;
1430 break;
1431 case wxALIGN_RIGHT:
1432 hdi.fmt |= HDF_RIGHT;
1433 break;
5d3f234b
RR
1434
1435 default:
1436 // such alignment is not allowed for the column header!
0677c6cb 1437 break; // wxFAIL;
9861f022 1438 }
c741d33f
VZ
1439
1440 SendMessage((HWND)m_hWnd, HDM_INSERTITEM,
1441 (WPARAM)added, (LPARAM)&hdi);
9861f022 1442 added++;
87f0efe2
RR
1443 }
1444}
1445
9861f022
RR
1446unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR)
1447{
1448 unsigned int idx;
1449
1450 // NOTE: we don't just return nmHDR->iItem because when there are
1451 // hidden columns, nmHDR->iItem may be different from
1452 // nmHDR->pitem->lParam
1453
1454 if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM)
1455 {
1456 idx = (unsigned int)nmHDR->pitem->lParam;
1457 return idx;
1458 }
1459
1460 HDITEM item;
1461 item.mask = HDI_LPARAM;
1462 Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item);
1463
1464 return (unsigned int)item.lParam;
1465}
1466
87f0efe2
RR
1467bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
1468{
1469 NMHDR *nmhdr = (NMHDR *)lParam;
1470
1471 // is it a message from the header?
1472 if ( nmhdr->hwndFrom != (HWND)m_hWnd )
1473 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1474
1475 NMHEADER *nmHDR = (NMHEADER *)nmhdr;
1476 switch ( nmhdr->code )
1477 {
1478 case HDN_BEGINTRACK:
1479 // user has started to resize a column:
1480 // do we need to veto it?
1481 if (!GetColumn(nmHDR->iItem)->IsResizeable())
1482 {
1483 // veto it!
1484 *result = TRUE;
1485 }
1486 break;
1487
1488 case HDN_BEGINDRAG:
1489 // user has started to reorder a column
dd570ceb 1490 if ((nmHDR->iItem != -1) && (!GetColumn(nmHDR->iItem)->IsReorderable()))
309bd665
RR
1491 {
1492 // veto it!
1493 *result = TRUE;
1494 }
87f0efe2
RR
1495 break;
1496
309bd665
RR
1497 case HDN_ENDDRAG: // user has finished reordering a column
1498 {
fc8c1a15
RR
1499 wxDataViewColumn *col = GetColumn(nmHDR->iItem);
1500 unsigned int new_pos = nmHDR->pitem->iOrder;
1501 m_owner->ColumnMoved( col, new_pos );
1502 m_delayedUpdate = true;
309bd665
RR
1503 }
1504 break;
cfa42cb8 1505
9861f022 1506 case HDN_ITEMCHANGING:
c741d33f 1507 if (nmHDR->pitem != NULL &&
9861f022
RR
1508 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1509 {
1510 int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth();
1511 if (nmHDR->pitem->cxy < minWidth)
1512 {
c741d33f 1513 // do not allow the user to resize this column under
9861f022
RR
1514 // its minimal width:
1515 *result = TRUE;
1516 }
1517 }
1518 break;
1519
87f0efe2
RR
1520 case HDN_ITEMCHANGED: // user is resizing a column
1521 case HDN_ENDTRACK: // user has finished resizing a column
87f0efe2
RR
1522
1523 // update the width of the modified column:
c741d33f 1524 if (nmHDR->pitem != NULL &&
9861f022
RR
1525 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1526 {
1527 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
1528 unsigned int w = nmHDR->pitem->cxy;
1529 wxDataViewColumn *col = GetColumn(idx);
1530
1531 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1532 if (idx == 0 && w > COLUMN_WIDTH_OFFSET)
1533 w -= COLUMN_WIDTH_OFFSET;
1534
1535 if (w >= (unsigned)col->GetMinWidth())
1536 col->SetInternalWidth(w);
1537 }
87f0efe2
RR
1538 break;
1539
1540 case HDN_ITEMCLICK:
1541 {
9861f022 1542 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
d3f00f59
VZ
1543 wxDataViewModel * model = GetOwner()->GetModel();
1544
1545 if(nmHDR->iButton == 0)
1546 {
1547 wxDataViewColumn *col = GetColumn(idx);
1548 if(col->IsSortable())
1549 {
57f2a652 1550 if(model && m_owner->GetSortingColumn() == col)
d3f00f59
VZ
1551 {
1552 bool order = col->IsSortOrderAscending();
1553 col->SetSortOrder(!order);
d3f00f59
VZ
1554 }
1555 else if(model)
1556 {
57f2a652 1557 m_owner->SetSortingColumn(col);
d3f00f59
VZ
1558 }
1559 }
1560 UpdateDisplay();
1561 if(model)
1562 model->Resort();
1563 }
1564
c741d33f 1565 wxEventType evt = nmHDR->iButton == 0 ?
87f0efe2
RR
1566 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1567 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
9861f022 1568 SendEvent(evt, idx);
87f0efe2
RR
1569 }
1570 break;
1571
1572 case NM_RCLICK:
1573 {
1574 // NOTE: for some reason (i.e. for a bug in Windows)
1575 // the HDN_ITEMCLICK notification is not sent on
1576 // right clicks, so we need to handle NM_RCLICK
1577
1578 POINT ptClick;
9861f022 1579 int column = wxMSWGetColumnClicked(nmhdr, &ptClick);
87f0efe2 1580 if (column != wxNOT_FOUND)
9861f022
RR
1581 {
1582 HDITEM item;
1583 item.mask = HDI_LPARAM;
1584 Header_GetItem((HWND)m_hWnd, column, &item);
1585
1586 // 'idx' may be different from 'column' if there are
1587 // hidden columns...
1588 unsigned int idx = (unsigned int)item.lParam;
87f0efe2 1589 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
9861f022
RR
1590 idx);
1591 }
87f0efe2
RR
1592 }
1593 break;
1594
1595 case HDN_GETDISPINFOW:
1596 // see wxListCtrl::MSWOnNotify for more info!
1597 break;
1598
1599 case HDN_ITEMDBLCLICK:
1600 {
9861f022 1601 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
87f0efe2
RR
1602 int w = GetOwner()->GetBestColumnWidth(idx);
1603
1604 // update the native control:
1605 HDITEM hd;
1606 ZeroMemory(&hd, sizeof(hd));
1607 hd.mask = HDI_WIDTH;
1608 hd.cxy = w;
c741d33f 1609 Header_SetItem(GetHwnd(),
9861f022
RR
1610 nmHDR->iItem, // NOTE: we don't want 'idx' here!
1611 &hd);
87f0efe2
RR
1612
1613 // update the wxDataViewColumn class:
9861f022 1614 GetColumn(idx)->SetInternalWidth(w);
87f0efe2
RR
1615 }
1616 break;
1617
1618 default:
1619 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1620 }
1621
1622 return true;
1623}
1624
f456baf1
VZ
1625void wxDataViewHeaderWindowMSW::ScrollWindow(int dx, int WXUNUSED(dy),
1626 const wxRect * WXUNUSED(rect))
87f0efe2 1627{
70a9e561 1628 m_scrollOffsetX += dx;
cfa42cb8 1629
70a9e561 1630 GetParent()->Layout();
87f0efe2
RR
1631}
1632
70a9e561
RR
1633void wxDataViewHeaderWindowMSW::DoSetSize(int x, int y,
1634 int w, int h,
1635 int f)
9861f022 1636{
d81ad1f0 1637 // TODO: why is there a border + 2px around it?
0677c6cb 1638 wxControl::DoSetSize( x+m_scrollOffsetX+1, y+1, w-m_scrollOffsetX-2, h-2, f );
9861f022
RR
1639}
1640
87f0efe2
RR
1641#else // !defined(__WXMSW__)
1642
1643IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow, wxWindow)
1644BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow, wxWindow)
1645 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint)
1646 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse)
1647 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus)
4ed7af08
RR
1648END_EVENT_TABLE()
1649
87f0efe2 1650bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f
VZ
1651 const wxPoint &pos, const wxSize &size,
1652 const wxString &name )
4ed7af08 1653{
87f0efe2 1654 m_owner = parent;
4b3feaa7 1655
87f0efe2
RR
1656 if (!wxDataViewHeaderWindowBase::Create(parent, id, pos, size, name))
1657 return false;
f554a14b 1658
4ed7af08 1659 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
2e992e06 1660 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
4ed7af08
RR
1661 SetOwnForegroundColour( attr.colFg );
1662 SetOwnBackgroundColour( attr.colBg );
1663 if (!m_hasFont)
1664 SetOwnFont( attr.font );
4ed7af08 1665
87f0efe2
RR
1666 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1667 // a wxBoxSizer and in order to avoid super-big header windows,
1668 // we need to set our height as fixed
1669 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1670 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1671
1672 return true;
4ed7af08
RR
1673}
1674
87f0efe2 1675void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 1676{
4b3feaa7
RR
1677 int w, h;
1678 GetClientSize( &w, &h );
1679
2e992e06
VZ
1680 wxAutoBufferedPaintDC dc( this );
1681
1682 dc.SetBackground(GetBackgroundColour());
1683 dc.Clear();
f554a14b 1684
4ed7af08
RR
1685 int xpix;
1686 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1687
1688 int x;
1689 m_owner->GetViewStart( &x, NULL );
1690
1691 // account for the horz scrollbar offset
1692 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 1693
4ed7af08 1694 dc.SetFont( GetFont() );
f554a14b 1695
9861f022 1696 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 1697 unsigned int i;
4b3feaa7
RR
1698 int xpos = 0;
1699 for (i = 0; i < cols; i++)
1700 {
87f0efe2
RR
1701 wxDataViewColumn *col = GetColumn( i );
1702 if (col->IsHidden())
9861f022 1703 continue; // skip it!
f554a14b 1704
87f0efe2 1705 int cw = col->GetWidth();
4b3feaa7 1706 int ch = h;
4b3feaa7 1707
c3112d56 1708 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE;
57f2a652 1709 if (col->IsSortable() && GetOwner()->GetSortingColumn() == col)
c3112d56
RR
1710 {
1711 if (col->IsSortOrderAscending())
1712 sortArrow = wxHDR_SORT_ICON_UP;
1713 else
1714 sortArrow = wxHDR_SORT_ICON_DOWN;
1715 }
b5ec7dd6 1716
cc28f5ec
RR
1717 int state = 0;
1718 if (m_parent->IsEnabled())
1719 {
67be459b 1720 if ((int) i == m_hover)
cc28f5ec
RR
1721 state = wxCONTROL_CURRENT;
1722 }
1723 else
1724 {
1725 state = (int) wxCONTROL_DISABLED;
1726 }
c3112d56 1727
4b3feaa7
RR
1728 wxRendererNative::Get().DrawHeaderButton
1729 (
1730 this,
1731 dc,
72664514 1732 wxRect(xpos, 0, cw, ch-1),
cc28f5ec 1733 state,
c3112d56 1734 sortArrow
4b3feaa7
RR
1735 );
1736
9861f022
RR
1737 // align as required the column title:
1738 int x = xpos;
1739 wxSize titleSz = dc.GetTextExtent(col->GetTitle());
1740 switch (col->GetAlignment())
1741 {
1742 case wxALIGN_LEFT:
1743 x += HEADER_HORIZ_BORDER;
1744 break;
67be459b
RR
1745 case wxALIGN_RIGHT:
1746 x += cw - titleSz.GetWidth() - HEADER_HORIZ_BORDER;
1747 break;
1748 default:
9861f022
RR
1749 case wxALIGN_CENTER:
1750 case wxALIGN_CENTER_HORIZONTAL:
1751 x += (cw - titleSz.GetWidth() - 2 * HEADER_HORIZ_BORDER)/2;
1752 break;
9861f022
RR
1753 }
1754
1755 // always center the title vertically:
1756 int y = wxMax((ch - titleSz.GetHeight()) / 2, HEADER_VERT_BORDER);
1757
c741d33f 1758 dc.SetClippingRegion( xpos+HEADER_HORIZ_BORDER,
9861f022
RR
1759 HEADER_VERT_BORDER,
1760 wxMax(cw - 2 * HEADER_HORIZ_BORDER, 1), // width
1761 wxMax(ch - 2 * HEADER_VERT_BORDER, 1)); // height
1762 dc.DrawText( col->GetTitle(), x, y );
1763 dc.DestroyClippingRegion();
f554a14b 1764
87f0efe2 1765 xpos += cw;
4b3feaa7 1766 }
4ed7af08
RR
1767}
1768
87f0efe2 1769void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
4ed7af08 1770{
87f0efe2
RR
1771 GetParent()->SetFocus();
1772 event.Skip();
4ed7af08
RR
1773}
1774
87f0efe2 1775void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event )
4ed7af08 1776{
87f0efe2
RR
1777 // we want to work with logical coords
1778 int x;
1779 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1780 int y = event.GetY();
1781
1782 if (m_isDragging)
1783 {
c741d33f 1784 // we don't draw the line beyond our window,
87f0efe2
RR
1785 // but we allow dragging it there
1786 int w = 0;
1787 GetClientSize( &w, NULL );
1788 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1789 w -= 6;
1790
c741d33f 1791 if (event.ButtonUp())
87f0efe2
RR
1792 {
1793 m_isDragging = false;
c741d33f 1794 if (HasCapture())
87f0efe2
RR
1795 ReleaseMouse();
1796
1797 m_dirty = true;
c899416d
RR
1798 }
1799 m_currentX = wxMax(m_minX + 7, x);
87f0efe2 1800
b7fe2261 1801 if (m_currentX < w)
c899416d 1802 {
9861f022 1803 GetColumn(m_column)->SetWidth(m_currentX - m_minX);
87f0efe2
RR
1804 Refresh();
1805 GetOwner()->Refresh();
1806 }
87f0efe2
RR
1807
1808 }
1809 else // not dragging
1810 {
1811 m_minX = 0;
1812 m_column = wxNOT_FOUND;
1813
1814 bool hit_border = false;
1815
1816 // end of the current column
1817 int xpos = 0;
1818
1819 // find the column where this event occured
9861f022 1820 int countCol = m_owner->GetColumnCount();
c741d33f 1821 for (int column = 0; column < countCol; column++)
87f0efe2
RR
1822 {
1823 wxDataViewColumn *p = GetColumn(column);
1824
c741d33f 1825 if (p->IsHidden())
87f0efe2
RR
1826 continue; // skip if not shown
1827
1828 xpos += p->GetWidth();
1829 m_column = column;
c741d33f 1830 if ((abs(x-xpos) < 3) && (y < 22))
87f0efe2
RR
1831 {
1832 hit_border = true;
1833 break;
1834 }
1835
c741d33f 1836 if (x < xpos)
87f0efe2
RR
1837 {
1838 // inside the column
1839 break;
1840 }
1841
1842 m_minX = xpos;
1843 }
b5ec7dd6 1844
cc28f5ec
RR
1845 int old_hover = m_hover;
1846 m_hover = m_column;
1847 if (event.Leaving())
1848 m_hover = wxNOT_FOUND;
1849 if (old_hover != m_hover)
1850 Refresh();
87f0efe2
RR
1851
1852 if (m_column == wxNOT_FOUND)
1853 return;
1854
1855 bool resizeable = GetColumn(m_column)->IsResizeable();
1856 if (event.LeftDClick() && resizeable)
1857 {
9861f022 1858 GetColumn(m_column)->SetWidth(GetOwner()->GetBestColumnWidth(m_column));
87f0efe2
RR
1859 Refresh();
1860 }
1861 else if (event.LeftDown() || event.RightUp())
1862 {
c741d33f 1863 if (hit_border && event.LeftDown() && resizeable)
87f0efe2
RR
1864 {
1865 m_isDragging = true;
1866 CaptureMouse();
1867 m_currentX = x;
87f0efe2
RR
1868 }
1869 else // click on a column
1870 {
b7e9f8b1 1871 wxDataViewModel * model = GetOwner()->GetModel();
c741d33f 1872 wxEventType evt = event.LeftDown() ?
87f0efe2
RR
1873 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1874 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
1875 SendEvent(evt, m_column);
b7e9f8b1
RR
1876
1877 //Left click the header
1878 if(event.LeftDown())
1879 {
1880 wxDataViewColumn *col = GetColumn(m_column);
1881 if(col->IsSortable())
1882 {
57f2a652
RR
1883 wxDataViewColumn* sortCol = m_owner->GetSortingColumn();
1884 if(model && sortCol == col)
b7e9f8b1
RR
1885 {
1886 bool order = col->IsSortOrderAscending();
1887 col->SetSortOrder(!order);
b7e9f8b1
RR
1888 }
1889 else if(model)
1890 {
57f2a652 1891 m_owner->SetSortingColumn(col);
b7e9f8b1
RR
1892 }
1893 }
1894 UpdateDisplay();
1895 if(model)
1896 model->Resort();
1897 //Send the column sorted event
1898 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, m_column);
1899 }
87f0efe2
RR
1900 }
1901 }
1902 else if (event.Moving())
1903 {
c741d33f 1904 if (hit_border && resizeable)
87f0efe2
RR
1905 m_currentCursor = m_resizeCursor;
1906 else
1907 m_currentCursor = wxSTANDARD_CURSOR;
1908
1909 SetCursor(*m_currentCursor);
1910 }
1911 }
1912}
1913
87f0efe2
RR
1914void wxGenericDataViewHeaderWindow::AdjustDC(wxDC& dc)
1915{
1916 int xpix, x;
1917
1918 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1919 m_owner->GetViewStart( &x, NULL );
1920
1921 // shift the DC origin to match the position of the main window horizontal
1922 // scrollbar: this allows us to always use logical coords
1923 dc.SetDeviceOrigin( -x * xpix, 0 );
4ed7af08
RR
1924}
1925
87f0efe2
RR
1926#endif // defined(__WXMSW__)
1927
0fcce6b9
RR
1928//-----------------------------------------------------------------------------
1929// wxDataViewRenameTimer
1930//-----------------------------------------------------------------------------
1931
1932wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
1933{
1934 m_owner = owner;
1935}
1936
1937void wxDataViewRenameTimer::Notify()
1938{
1939 m_owner->OnRenameTimer();
1940}
1941
4ed7af08
RR
1942//-----------------------------------------------------------------------------
1943// wxDataViewMainWindow
1944//-----------------------------------------------------------------------------
1945
704c3490 1946//The tree building helper, declared firstly
74123073 1947static void BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node);
704c3490 1948
0a71f9e9 1949int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
cab07038
RR
1950{
1951 if (row1 > row2) return 1;
1952 if (row1 == row2) return 0;
1953 return -1;
1954}
1955
1956
45778c96 1957IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
1958
1959BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
1960 EVT_PAINT (wxDataViewMainWindow::OnPaint)
1961 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
1962 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
cab07038
RR
1963 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
1964 EVT_CHAR (wxDataViewMainWindow::OnChar)
4ed7af08
RR
1965END_EVENT_TABLE()
1966
1967wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
1968 const wxPoint &pos, const wxSize &size, const wxString &name ) :
d81ad1f0 1969 wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE, name ),
cab07038 1970 m_selection( wxDataViewSelectionCmp )
120b9b05 1971
4ed7af08
RR
1972{
1973 SetOwner( parent );
f554a14b 1974
0fcce6b9
RR
1975 m_lastOnSame = false;
1976 m_renameTimer = new wxDataViewRenameTimer( this );
120b9b05 1977
0fcce6b9
RR
1978 // TODO: user better initial values/nothing selected
1979 m_currentCol = NULL;
1980 m_currentRow = 0;
1981
e44ac7bc 1982 m_lineHeight = wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1
e21f75bd
RR
1983
1984 m_dragCount = 0;
1985 m_dragStart = wxPoint(0,0);
0a71f9e9
RR
1986 m_lineLastClicked = (unsigned int) -1;
1987 m_lineBeforeLastClicked = (unsigned int) -1;
1988 m_lineSelectSingleOnUp = (unsigned int) -1;
120b9b05 1989
cab07038 1990 m_hasFocus = false;
f554a14b 1991
72664514
RR
1992 SetBackgroundColour( *wxWHITE );
1993
cfa42cb8
JS
1994 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1995
069b2e59 1996 m_penRule = wxPen(GetRuleColour());
9861f022 1997
3b6280be 1998 //Here I compose a pen can draw black lines, maybe there are something system colour to use
069b2e59 1999 m_penExpander = wxPen(wxColour(0,0,0));
aba9bfd0
RR
2000 //Some new added code to deal with the tree structure
2001 m_root = new wxDataViewTreeNode( NULL );
704c3490
RR
2002 m_root->SetHasChildren(true);
2003
3b6280be
RR
2004 //Make m_count = -1 will cause the class recaculate the real displaying number of rows.
2005 m_count = -1 ;
24c4a50f 2006 m_underMouse = NULL;
4b3feaa7 2007 UpdateDisplay();
4ed7af08
RR
2008}
2009
2010wxDataViewMainWindow::~wxDataViewMainWindow()
2011{
aba9bfd0 2012 DestroyTree();
0fcce6b9
RR
2013 delete m_renameTimer;
2014}
2015
1117d56f 2016void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
0fcce6b9 2017{
1117d56f
RR
2018 wxDataViewModel *model = GetOwner()->GetModel();
2019 wxAutoBufferedPaintDC dc( this );
0fcce6b9 2020
1117d56f
RR
2021#ifdef __WXMSW__
2022 dc.SetPen( *wxTRANSPARENT_PEN );
2023 dc.SetBrush( wxBrush( GetBackgroundColour()) );
2024 dc.SetBrush( *wxWHITE_BRUSH );
2025 wxSize size( GetClientSize() );
2026 dc.DrawRectangle( 0,0,size.x,size.y );
2027#endif
2028
2029 // prepare the DC
2030 GetOwner()->PrepareDC( dc );
2031 dc.SetFont( GetFont() );
2032
2033 wxRect update = GetUpdateRegion().GetBox();
2034 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
2035
2036 // compute which items needs to be redrawn
2037 unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
2038 unsigned int item_count =
2039 wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
2040 (int)(GetRowCount( ) - item_start));
2041 unsigned int item_last = item_start + item_count;
2042
2043 // compute which columns needs to be redrawn
9861f022 2044 unsigned int cols = GetOwner()->GetColumnCount();
1117d56f
RR
2045 unsigned int col_start = 0;
2046 unsigned int x_start = 0;
2047 for (x_start = 0; col_start < cols; col_start++)
0fcce6b9 2048 {
1117d56f
RR
2049 wxDataViewColumn *col = GetOwner()->GetColumn(col_start);
2050 if (col->IsHidden())
9861f022
RR
2051 continue; // skip it!
2052
1117d56f
RR
2053 unsigned int w = col->GetWidth();
2054 if (x_start+w >= (unsigned int)update.x)
0fcce6b9 2055 break;
0fcce6b9 2056
1117d56f
RR
2057 x_start += w;
2058 }
1e510b1e 2059
1117d56f
RR
2060 unsigned int col_last = col_start;
2061 unsigned int x_last = x_start;
2062 for (; col_last < cols; col_last++)
2063 {
2064 wxDataViewColumn *col = GetOwner()->GetColumn(col_last);
2065 if (col->IsHidden())
2066 continue; // skip it!
afebb87b 2067
1117d56f
RR
2068 if (x_last > (unsigned int)update.GetRight())
2069 break;
4ed7af08 2070
1117d56f
RR
2071 x_last += col->GetWidth();
2072 }
d5025dc0 2073
1117d56f
RR
2074 // Draw horizontal rules if required
2075 if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
2076 {
2077 dc.SetPen(m_penRule);
2078 dc.SetBrush(*wxTRANSPARENT_BRUSH);
aba9bfd0 2079
1117d56f
RR
2080 for (unsigned int i = item_start; i <= item_last+1; i++)
2081 {
2082 int y = i * m_lineHeight;
2083 dc.DrawLine(x_start, y, x_last, y);
2084 }
2085 }
aba9bfd0 2086
1117d56f
RR
2087 // Draw vertical rules if required
2088 if ( m_owner->HasFlag(wxDV_VERT_RULES) )
b7e9f8b1 2089 {
1117d56f
RR
2090 dc.SetPen(m_penRule);
2091 dc.SetBrush(*wxTRANSPARENT_BRUSH);
b7e9f8b1 2092
1117d56f
RR
2093 int x = x_start;
2094 for (unsigned int i = col_start; i < col_last; i++)
2095 {
2096 wxDataViewColumn *col = GetOwner()->GetColumn(i);
2097 if (col->IsHidden())
2098 continue; // skip it
d47db7e0 2099
1117d56f
RR
2100 dc.DrawLine(x, item_start * m_lineHeight,
2101 x, item_last * m_lineHeight);
b7e9f8b1 2102
1117d56f
RR
2103 x += col->GetWidth();
2104 }
2105
2106 // Draw last vertical rule
2107 dc.DrawLine(x, item_start * m_lineHeight,
2108 x, item_last * m_lineHeight);
2109 }
2110
2111 // redraw the background for the items which are selected/current
2112 for (unsigned int item = item_start; item < item_last; item++)
aba9bfd0 2113 {
1117d56f
RR
2114 bool selected = m_selection.Index( item ) != wxNOT_FOUND;
2115 if (selected || item == m_currentRow)
d5025dc0 2116 {
1117d56f
RR
2117 int flags = selected ? (int)wxCONTROL_SELECTED : 0;
2118 if (item == m_currentRow)
2119 flags |= wxCONTROL_CURRENT;
2120 if (m_hasFocus)
2121 flags |= wxCONTROL_FOCUSED;
d47db7e0 2122
1117d56f
RR
2123 wxRect rect( x_start, item*m_lineHeight, x_last, m_lineHeight );
2124 wxRendererNative::Get().DrawItemSelectionRect
2125 (
2126 this,
2127 dc,
2128 rect,
2129 flags
2130 );
d47db7e0 2131 }
aba9bfd0 2132 }
a0f3af5f 2133
1117d56f
RR
2134 wxDataViewColumn *expander = GetOwner()->GetExpanderColumn();
2135 if (!expander)
8b6cf9bf 2136 {
1117d56f
RR
2137 // TODO: last column for RTL support
2138 expander = GetOwner()->GetColumn( 0 );
2139 GetOwner()->SetExpanderColumn(expander);
8b6cf9bf 2140 }
d47db7e0 2141
1117d56f
RR
2142 // redraw all cells for all rows which must be repainted and for all columns
2143 wxRect cell_rect;
2144 cell_rect.x = x_start;
2145 cell_rect.height = m_lineHeight; // -1 is for the horizontal rules
2146 for (unsigned int i = col_start; i < col_last; i++)
d47db7e0 2147 {
1117d56f
RR
2148 wxDataViewColumn *col = GetOwner()->GetColumn( i );
2149 wxDataViewRenderer *cell = col->GetRenderer();
2150 cell_rect.width = col->GetWidth();
d47db7e0 2151
1117d56f
RR
2152 if (col->IsHidden())
2153 continue; // skipt it!
d47db7e0 2154
fbda518c 2155
1117d56f
RR
2156 for (unsigned int item = item_start; item < item_last; item++)
2157 {
2158 // get the cell value and set it into the renderer
2159 wxVariant value;
2160 wxDataViewTreeNode *node = NULL;
2161 wxDataViewItem dataitem;
cfa42cb8 2162
1117d56f
RR
2163 if (m_root)
2164 {
2165 node = GetTreeNodeByRow(item);
2166 if( node == NULL )
2167 continue;
a0f3af5f 2168
1117d56f 2169 dataitem = node->GetItem();
704c3490 2170
1117d56f
RR
2171 if ((i > 0) && model->IsContainer(dataitem) && !model->HasContainerColumns(dataitem))
2172 continue;
2173 }
2174 else
2175 {
2176 dataitem = wxDataViewItem( (void*) item );
2177 }
8b6cf9bf 2178
1117d56f
RR
2179 model->GetValue( value, dataitem, col->GetModelColumn());
2180 cell->SetValue( value );
cfa42cb8 2181
1117d56f
RR
2182 if (cell->GetWantsAttr())
2183 {
2184 wxDataViewItemAttr attr;
2185 bool ret = model->GetAttr( dataitem, col->GetModelColumn(), attr );
2186 if (ret)
2187 cell->SetAttr( attr );
2188 cell->SetHasAttr( ret );
2189 }
8b6cf9bf 2190
1117d56f
RR
2191 // update the y offset
2192 cell_rect.y = item * m_lineHeight;
8b6cf9bf 2193
1117d56f
RR
2194 //Draw the expander here.
2195 int indent = 0;
2196 if ((m_root) && (col == expander))
2197 {
2198 indent = node->GetIndentLevel();
cfa42cb8 2199
1117d56f
RR
2200 //Calculate the indent first
2201 indent = cell_rect.x + GetOwner()->GetIndent() * indent;
2202
2203 int expander_width = m_lineHeight - 2*EXPANDER_MARGIN;
2204 // change the cell_rect.x to the appropriate pos
2205 int expander_x = indent + EXPANDER_MARGIN , expander_y = cell_rect.y + EXPANDER_MARGIN ;
2206 indent = indent + m_lineHeight ; //try to use the m_lineHeight as the expander space
2207 dc.SetPen( m_penExpander );
2208 dc.SetBrush( wxNullBrush );
2209 if( node->HasChildren() )
2210 {
2211 wxRect rect( expander_x , expander_y, expander_width, expander_width);
2212 int flag = 0;
2213 if (m_underMouse == node)
2214 {
2215 flag |= wxCONTROL_CURRENT;
2216 }
2217 if( node->IsOpen() )
2218 wxRendererNative::Get().DrawTreeItemButton( this, dc, rect, flag|wxCONTROL_EXPANDED );
2219 else
2220 wxRendererNative::Get().DrawTreeItemButton( this, dc, rect, flag);
2221 }
1117d56f
RR
2222 //force the expander column to left-center align
2223 cell->SetAlignment( wxALIGN_CENTER_VERTICAL );
2224 }
74123073
RR
2225 if (node && !node->HasChildren())
2226 {
2227 // Yes, if the node does not have any child, it must be a leaf which
2228 // mean that it is a temporarily created by GetTreeNodeByRow
2229 wxDELETE(node)
2230 }
1117d56f
RR
2231
2232 // cannot be bigger than allocated space
2233 wxSize size = cell->GetSize();
2234 // Because of the tree structure indent, here we should minus the width of the cell for drawing
2235 size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width - indent );
2236 // size.y = wxMin( size.y, cell_rect.height );
2237 size.y = cell_rect.height;
2238
2239 wxRect item_rect(cell_rect.GetTopLeft(), size);
e51bf699 2240 int align = cell->CalculateAlignment();
1117d56f
RR
2241
2242 // horizontal alignment:
2243 item_rect.x = cell_rect.x;
2244 if (align & wxALIGN_CENTER_HORIZONTAL)
2245 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
2246 else if (align & wxALIGN_RIGHT)
2247 item_rect.x = cell_rect.x + cell_rect.width - size.x;
2248 //else: wxALIGN_LEFT is the default
2249
2250 // vertical alignment:
2251 item_rect.y = cell_rect.y;
2252 if (align & wxALIGN_CENTER_VERTICAL)
2253 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
2254 else if (align & wxALIGN_BOTTOM)
2255 item_rect.y = cell_rect.y + cell_rect.height - size.y;
2256 //else: wxALIGN_TOP is the default
2257
2258 // add padding
2259 item_rect.x += PADDING_RIGHTLEFT;
2260 item_rect.width = size.x - 2 * PADDING_RIGHTLEFT;
2261
2262 //Here we add the tree indent
2263 item_rect.x += indent;
2264
2265 int state = 0;
2266 if (m_hasFocus && (m_selection.Index(item) != wxNOT_FOUND))
2267 state |= wxDATAVIEW_CELL_SELECTED;
2268
2269 // TODO: it would be much more efficient to create a clipping
2270 // region for the entire column being rendered (in the OnPaint
2271 // of wxDataViewMainWindow) instead of a single clip region for
2272 // each cell. However it would mean that each renderer should
2273 // respect the given wxRect's top & bottom coords, eventually
2274 // violating only the left & right coords - however the user can
2275 // make its own renderer and thus we cannot be sure of that.
2276 dc.SetClippingRegion( item_rect );
2277 cell->Render( item_rect, &dc, state );
2278 dc.DestroyClippingRegion();
2279 }
2280
2281 cell_rect.x += cell_rect.width;
2282 }
2283}
2284
2285void wxDataViewMainWindow::OnRenameTimer()
2286{
2287 // We have to call this here because changes may just have
2288 // been made and no screen update taken place.
2289 if ( m_dirty )
2290 wxSafeYield();
2291
2292 int xpos = 0;
2293 unsigned int cols = GetOwner()->GetColumnCount();
2294 unsigned int i;
2295 for (i = 0; i < cols; i++)
2296 {
2297 wxDataViewColumn *c = GetOwner()->GetColumn( i );
2298 if (c->IsHidden())
2299 continue; // skip it!
2300
2301 if (c == m_currentCol)
2302 break;
2303 xpos += c->GetWidth();
2304 }
2305 wxRect labelRect( xpos, m_currentRow * m_lineHeight,
2306 m_currentCol->GetWidth(), m_lineHeight );
2307
2308 GetOwner()->CalcScrolledPosition( labelRect.x, labelRect.y,
2309 &labelRect.x, &labelRect.y);
2310
2311 wxDataViewItem item = GetItemByRow( m_currentRow );
2312 m_currentCol->GetRenderer()->StartEditing( item, labelRect );
2313
2314}
2315
2316//------------------------------------------------------------------
2317// Helper class for do operation on the tree node
2318//------------------------------------------------------------------
2319class DoJob
2320{
2321public:
2322 DoJob(){};
2323 virtual ~DoJob(){};
2324
2325 //The return value control how the tree-walker tranverse the tree
2326 // 0: Job done, stop tranverse and return
2327 // 1: Ignore the current node's subtree and continue
2328 // 2: Job not done, continue
2329 enum { OK = 0 , IGR = 1, CONT = 2 };
2330 virtual int operator() ( wxDataViewTreeNode * node ) = 0 ;
2331 virtual int operator() ( void * n ) = 0;
2332};
2333
2334bool Walker( wxDataViewTreeNode * node, DoJob & func )
2335{
2336 if( node==NULL )
2337 return false;
2338
2339 switch( func( node ) )
2340 {
2341 case DoJob::OK :
2342 return true ;
2343 case DoJob::IGR:
2344 return false;
2345 case DoJob::CONT:
2346 default:
2347 ;
2348 }
2349
2350 wxDataViewTreeNodes nodes = node->GetNodes();
2351 wxDataViewTreeLeaves leaves = node->GetChildren();
2352
2353 int len_nodes = nodes.GetCount();
2354 int len = leaves.GetCount();
2355 int i = 0, nodes_i = 0;
2356
2357 for( ; i < len ; i ++ )
2358 {
2359 void * n = leaves[i];
2360 if( nodes_i < len_nodes && n == nodes[nodes_i]->GetItem().GetID() )
2361 {
2362 wxDataViewTreeNode * nd = nodes[nodes_i];
2363 nodes_i++;
2364
2365 if( Walker( nd , func ) )
2366 return true;
2367
2368 }
2369 else
2370 switch( func( n ) )
2371 {
2372 case DoJob::OK :
2373 return true ;
2374 case DoJob::IGR:
2375 continue;
2376 case DoJob::CONT:
2377 default:
2378 ;
2379 }
2380 }
2381 return false;
2382}
2383
2384bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
2385{
2386 if (!m_root)
2387 {
2388 m_count++;
2389 UpdateDisplay();
2390 return true;
2391 }
cfa42cb8 2392
1117d56f
RR
2393 SortPrepare();
2394
2395 wxDataViewTreeNode * node;
2396 node = FindNode(parent);
2397
2398 if( node == NULL )
2399 return false;
2400
2401 node->SetHasChildren( true );
2402
2403 if( g_model->IsContainer( item ) )
2404 {
2405 wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node );
2406 newnode->SetItem(item);
2407 newnode->SetHasChildren( true );
2408 node->AddNode( newnode);
2409 }
2410 else
2411 node->AddLeaf( item.GetID() );
2412
2413 node->ChangeSubTreeCount(1);
2414
2415 m_count = -1;
2416 UpdateDisplay();
2417
2418 return true;
2419}
2420
74123073 2421static void DestroyTreeHelper( wxDataViewTreeNode * node);
1117d56f
RR
2422
2423bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
2424 const wxDataViewItem& item)
2425{
2426 if (!m_root)
2427 {
2428 m_count--;
2429 if( m_currentRow > GetRowCount() )
2430 m_currentRow = m_count - 1;
2431
2432 m_selection.Empty();
cfa42cb8 2433
1117d56f
RR
2434 UpdateDisplay();
2435
2436 return true;
2437 }
2438
2439 wxDataViewTreeNode * node = FindNode(parent);
b7fe2261 2440
c59a09cf
RR
2441 wxCHECK_MSG( node != NULL, false, "item not found" );
2442 wxCHECK_MSG( node->GetChildren().Index( item.GetID() ) != wxNOT_FOUND, false, "item not found" );
351461fc 2443
d47db7e0
RR
2444 int sub = -1;
2445 node->GetChildren().Remove( item.GetID() );
fbda518c
RR
2446 //Manuplate selection
2447 if( m_selection.GetCount() > 1 )
2448 {
fbda518c 2449 m_selection.Empty();
fbda518c 2450 }
24c4a50f
RR
2451 bool isContainer = false;
2452 wxDataViewTreeNodes nds = node->GetNodes();
b7fe2261
VZ
2453 for (size_t i = 0; i < nds.GetCount(); i ++)
2454 {
24c4a50f
RR
2455 if (nds[i]->GetItem() == item)
2456 {
2457 isContainer = true;
2458 break;
2459 }
2460 }
2461 if( isContainer )
d47db7e0 2462 {
a8505db0 2463 wxDataViewTreeNode * n = NULL;
d47db7e0
RR
2464 wxDataViewTreeNodes nodes = node->GetNodes();
2465 int len = nodes.GetCount();
2466 for( int i = 0 ; i < len; i ++)
2467 {
2468 if( nodes[i]->GetItem() == item )
2469 {
2470 n = nodes[i];
2471 break;
2472 }
2473 }
a8505db0 2474
c59a09cf 2475 wxCHECK_MSG( n != NULL, false, "item not found" );
a8505db0 2476
d47db7e0
RR
2477 node->GetNodes().Remove( n );
2478 sub -= n->GetSubTreeCount();
74123073 2479 ::DestroyTreeHelper(n);
d47db7e0 2480 }
d47db7e0 2481 //Make the row number invalid and get a new valid one when user call GetRowCount
442c56e6 2482 m_count = -1;
d47db7e0 2483 node->ChangeSubTreeCount(sub);
24c4a50f 2484
d47db7e0
RR
2485 //Change the current row to the last row if the current exceed the max row number
2486 if( m_currentRow > GetRowCount() )
2487 m_currentRow = m_count - 1;
351461fc 2488
99d471a5 2489 UpdateDisplay();
b7fe2261 2490
99d471a5 2491 return true;
a0f3af5f
RR
2492}
2493
aba9bfd0 2494bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
a0f3af5f 2495{
66e09788 2496 SortPrepare();
b7e9f8b1
RR
2497 g_model->Resort();
2498
6608fdab
RR
2499 //Send event
2500 wxWindow *parent = GetParent();
2501 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, parent->GetId());
2502 le.SetEventObject(parent);
2503 le.SetModel(GetOwner()->GetModel());
2504 le.SetItem(item);
2505 parent->GetEventHandler()->ProcessEvent(le);
b5ec7dd6 2506
99d471a5 2507 return true;
a0f3af5f
RR
2508}
2509
b7e9f8b1 2510bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int col )
a0f3af5f 2511{
9861f022 2512 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
aba9bfd0 2513/*#define MAX_VIRTUAL_WIDTH 100000
9861f022
RR
2514
2515 wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight );
0fdc2321
RR
2516 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2517 Refresh( true, &rect );
2518
2519 return true;
aba9bfd0 2520*/
66e09788 2521 SortPrepare();
b7e9f8b1
RR
2522 g_model->Resort();
2523
2524 //Send event
2525 wxWindow *parent = GetParent();
6608fdab 2526 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, parent->GetId());
b7e9f8b1
RR
2527 le.SetEventObject(parent);
2528 le.SetModel(GetOwner()->GetModel());
2529 le.SetItem(item);
2530 le.SetColumn(col);
2531 le.SetDataViewColumn(GetOwner()->GetColumn(col));
2532 parent->GetEventHandler()->ProcessEvent(le);
d47db7e0 2533
0fcce6b9 2534 return true;
a0f3af5f
RR
2535}
2536
2537bool wxDataViewMainWindow::Cleared()
2538{
704c3490 2539 DestroyTree();
cfa42cb8 2540
33ba5a05
RR
2541 SortPrepare();
2542 BuildTree( GetOwner()->GetModel() );
cfa42cb8 2543
99d471a5 2544 UpdateDisplay();
b7e9f8b1 2545
99d471a5 2546 return true;
a0f3af5f
RR
2547}
2548
4b3feaa7
RR
2549void wxDataViewMainWindow::UpdateDisplay()
2550{
2551 m_dirty = true;
2552}
2553
2554void wxDataViewMainWindow::OnInternalIdle()
2555{
2556 wxWindow::OnInternalIdle();
f554a14b 2557
4b3feaa7
RR
2558 if (m_dirty)
2559 {
2560 RecalculateDisplay();
2561 m_dirty = false;
2562 }
2563}
2564
2565void wxDataViewMainWindow::RecalculateDisplay()
2566{
aba9bfd0 2567 wxDataViewModel *model = GetOwner()->GetModel();
4b3feaa7
RR
2568 if (!model)
2569 {
2570 Refresh();
2571 return;
2572 }
f554a14b 2573
9861f022 2574 int width = GetEndOfLastCol();
aba9bfd0 2575 int height = GetRowCount() * m_lineHeight;
4b3feaa7
RR
2576
2577 SetVirtualSize( width, height );
2578 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 2579
4b3feaa7
RR
2580 Refresh();
2581}
2582
2583void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
2584{
2585 wxWindow::ScrollWindow( dx, dy, rect );
9861f022
RR
2586
2587 if (GetOwner()->m_headerArea)
2588 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
4b3feaa7
RR
2589}
2590
fbda518c 2591void wxDataViewMainWindow::ScrollTo( int rows, int column )
b7e9f8b1
RR
2592{
2593 int x, y;
2594 m_owner->GetScrollPixelsPerUnit( &x, &y );
fbda518c
RR
2595 int sy = rows*m_lineHeight/y;
2596 int sx = 0;
2597 if( column != -1 )
2598 {
2599 wxRect rect = GetClientRect();
67be459b
RR
2600 int colnum = 0;
2601 int x_start = 0, x_end = 0, w = 0;
fbda518c
RR
2602 int xx, yy, xe;
2603 m_owner->CalcUnscrolledPosition( rect.x, rect.y, &xx, &yy );
2604 for (x_start = 0; colnum < column; colnum++)
2605 {
2606 wxDataViewColumn *col = GetOwner()->GetColumn(colnum);
2607 if (col->IsHidden())
2608 continue; // skip it!
2609
2610 w = col->GetWidth();
2611 x_start += w;
2612 }
2613
2614 x_end = x_start + w;
2615 xe = xx + rect.width;
2616 if( x_end > xe )
2617 {
2618 sx = ( xx + x_end - xe )/x;
2619 }
2620 if( x_start < xx )
2621 {
b7fe2261 2622 sx = x_start/x;
fbda518c
RR
2623 }
2624 }
2625 m_owner->Scroll( sx, sy );
b7e9f8b1
RR
2626}
2627
9861f022 2628int wxDataViewMainWindow::GetCountPerPage() const
cab07038
RR
2629{
2630 wxSize size = GetClientSize();
2631 return size.y / m_lineHeight;
2632}
2633
9861f022 2634int wxDataViewMainWindow::GetEndOfLastCol() const
e21f75bd
RR
2635{
2636 int width = 0;
0a71f9e9 2637 unsigned int i;
9861f022 2638 for (i = 0; i < GetOwner()->GetColumnCount(); i++)
e21f75bd 2639 {
c741d33f 2640 const wxDataViewColumn *c =
9861f022
RR
2641 wx_const_cast(wxDataViewCtrl*, GetOwner())->GetColumn( i );
2642
2643 if (!c->IsHidden())
2644 width += c->GetWidth();
e21f75bd
RR
2645 }
2646 return width;
2647}
2648
9861f022 2649unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
72664514
RR
2650{
2651 int x = 0;
2652 int y = 0;
2653 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
120b9b05 2654
72664514
RR
2655 return y / m_lineHeight;
2656}
2657
442c56e6 2658unsigned int wxDataViewMainWindow::GetLastVisibleRow()
72664514
RR
2659{
2660 wxSize client_size = GetClientSize();
c741d33f 2661 m_owner->CalcUnscrolledPosition( client_size.x, client_size.y,
87f0efe2 2662 &client_size.x, &client_size.y );
72664514 2663
b7fe2261 2664 //we should deal with the pixel here
49fc3b9c 2665 unsigned int row = ((client_size.y)/m_lineHeight) - 1;
b7fe2261 2666
fbda518c 2667 return wxMin( GetRowCount()-1, row );
72664514
RR
2668}
2669
442c56e6 2670unsigned int wxDataViewMainWindow::GetRowCount()
cab07038 2671{
3b6280be
RR
2672 if ( m_count == -1 )
2673 {
2674 m_count = RecalculateCount();
d5025dc0
RR
2675 int width, height;
2676 GetVirtualSize( &width, &height );
3b6280be
RR
2677 height = m_count * m_lineHeight;
2678
2679 SetVirtualSize( width, height );
2680 }
aba9bfd0 2681 return m_count;
cab07038
RR
2682}
2683
0a71f9e9 2684void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
e21f75bd
RR
2685{
2686 m_currentRow = row;
120b9b05 2687
e21f75bd
RR
2688 // send event
2689}
2690
cab07038
RR
2691void wxDataViewMainWindow::SelectAllRows( bool on )
2692{
4a851b11
VZ
2693 if (IsEmpty())
2694 return;
120b9b05 2695
cab07038
RR
2696 if (on)
2697 {
72664514 2698 m_selection.Clear();
0a71f9e9 2699 for (unsigned int i = 0; i < GetRowCount(); i++)
cab07038 2700 m_selection.Add( i );
72664514
RR
2701 Refresh();
2702 }
2703 else
2704 {
0a71f9e9
RR
2705 unsigned int first_visible = GetFirstVisibleRow();
2706 unsigned int last_visible = GetLastVisibleRow();
2707 unsigned int i;
72664514 2708 for (i = 0; i < m_selection.GetCount(); i++)
120b9b05 2709 {
0a71f9e9 2710 unsigned int row = m_selection[i];
72664514
RR
2711 if ((row >= first_visible) && (row <= last_visible))
2712 RefreshRow( row );
2713 }
2714 m_selection.Clear();
cab07038 2715 }
cab07038
RR
2716}
2717
0a71f9e9 2718void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
cab07038
RR
2719{
2720 if (m_selection.Index( row ) == wxNOT_FOUND)
2721 {
2722 if (on)
2723 {
2724 m_selection.Add( row );
2725 RefreshRow( row );
2726 }
2727 }
2728 else
2729 {
2730 if (!on)
2731 {
2732 m_selection.Remove( row );
2733 RefreshRow( row );
2734 }
2735 }
2736}
2737
0a71f9e9 2738void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
cab07038
RR
2739{
2740 if (from > to)
2741 {
0a71f9e9 2742 unsigned int tmp = from;
cab07038
RR
2743 from = to;
2744 to = tmp;
2745 }
2746
0a71f9e9 2747 unsigned int i;
cab07038
RR
2748 for (i = from; i <= to; i++)
2749 {
2750 if (m_selection.Index( i ) == wxNOT_FOUND)
2751 {
2752 if (on)
2753 m_selection.Add( i );
2754 }
2755 else
2756 {
2757 if (!on)
2758 m_selection.Remove( i );
2759 }
2760 }
2761 RefreshRows( from, to );
2762}
2763
87f0efe2
RR
2764void wxDataViewMainWindow::Select( const wxArrayInt& aSelections )
2765{
2766 for (size_t i=0; i < aSelections.GetCount(); i++)
2767 {
2768 int n = aSelections[i];
2769
2770 m_selection.Add( n );
2771 RefreshRow( n );
2772 }
2773}
2774
0a71f9e9 2775void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
cab07038
RR
2776{
2777 if (m_selection.Index( row ) == wxNOT_FOUND)
2778 m_selection.Add( row );
2779 else
2780 m_selection.Remove( row );
120b9b05 2781 RefreshRow( row );
cab07038
RR
2782}
2783
0a71f9e9 2784bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
cab07038
RR
2785{
2786 return (m_selection.Index( row ) != wxNOT_FOUND);
2787}
2788
526e19e2
RR
2789void wxDataViewMainWindow::SendSelectionChangedEvent( const wxDataViewItem& item)
2790{
2791 wxWindow *parent = GetParent();
2792 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, parent->GetId());
2793
2794 le.SetEventObject(parent);
2795 le.SetModel(GetOwner()->GetModel());
2796 le.SetItem( item );
2797
2798 parent->GetEventHandler()->ProcessEvent(le);
2799}
2800
0a71f9e9 2801void wxDataViewMainWindow::RefreshRow( unsigned int row )
cab07038 2802{
e21f75bd 2803 wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
cab07038 2804 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2805
cab07038
RR
2806 wxSize client_size = GetClientSize();
2807 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2808 wxRect intersect_rect = client_rect.Intersect( rect );
2809 if (intersect_rect.width > 0)
2810 Refresh( true, &intersect_rect );
2811}
2812
0a71f9e9 2813void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
cab07038
RR
2814{
2815 if (from > to)
2816 {
0a71f9e9 2817 unsigned int tmp = to;
cab07038
RR
2818 to = from;
2819 from = tmp;
2820 }
2821
e21f75bd 2822 wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
cab07038 2823 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2824
cab07038
RR
2825 wxSize client_size = GetClientSize();
2826 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2827 wxRect intersect_rect = client_rect.Intersect( rect );
2828 if (intersect_rect.width > 0)
2829 Refresh( true, &intersect_rect );
2830}
2831
0a71f9e9 2832void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
cab07038 2833{
0a71f9e9 2834 unsigned int count = GetRowCount();
4a851b11
VZ
2835 if (firstRow > count)
2836 return;
120b9b05 2837
e21f75bd 2838 wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
cab07038 2839 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2840
cab07038
RR
2841 wxSize client_size = GetClientSize();
2842 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2843 wxRect intersect_rect = client_rect.Intersect( rect );
2844 if (intersect_rect.width > 0)
2845 Refresh( true, &intersect_rect );
2846}
2847
0a71f9e9 2848void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
cab07038 2849{
4a851b11 2850 wxCHECK_RET( newCurrent < GetRowCount(),
cab07038
RR
2851 _T("invalid item index in OnArrowChar()") );
2852
2853 // if there is no selection, we cannot move it anywhere
2854 if (!HasCurrentRow())
2855 return;
2856
0a71f9e9 2857 unsigned int oldCurrent = m_currentRow;
cab07038
RR
2858
2859 // in single selection we just ignore Shift as we can't select several
2860 // items anyhow
e21f75bd 2861 if ( event.ShiftDown() && !IsSingleSel() )
cab07038
RR
2862 {
2863 RefreshRow( oldCurrent );
120b9b05 2864
e21f75bd 2865 ChangeCurrentRow( newCurrent );
cab07038
RR
2866
2867 // select all the items between the old and the new one
2868 if ( oldCurrent > newCurrent )
2869 {
2870 newCurrent = oldCurrent;
2871 oldCurrent = m_currentRow;
2872 }
2873
2874 SelectRows( oldCurrent, newCurrent, true );
526e19e2
RR
2875 if (oldCurrent!=newCurrent)
2876 SendSelectionChangedEvent(GetItemByRow(m_selection[0]));
cab07038
RR
2877 }
2878 else // !shift
2879 {
72664514 2880 RefreshRow( oldCurrent );
120b9b05 2881
cab07038
RR
2882 // all previously selected items are unselected unless ctrl is held
2883 if ( !event.ControlDown() )
2884 SelectAllRows(false);
2885
e21f75bd 2886 ChangeCurrentRow( newCurrent );
cab07038
RR
2887
2888 if ( !event.ControlDown() )
526e19e2 2889 {
cab07038 2890 SelectRow( m_currentRow, true );
526e19e2
RR
2891 SendSelectionChangedEvent(GetItemByRow(m_currentRow));
2892 }
72664514
RR
2893 else
2894 RefreshRow( m_currentRow );
cab07038
RR
2895 }
2896
67be459b 2897 GetOwner()->EnsureVisible( m_currentRow, -1 );
9861f022
RR
2898}
2899
2900wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const
2901{
2902 wxRect rect;
2903 rect.x = 0;
2904 rect.y = m_lineHeight * row;
2905 rect.width = GetEndOfLastCol();
2906 rect.height = m_lineHeight;
2907
2908 return rect;
cab07038
RR
2909}
2910
aba9bfd0
RR
2911class RowToItemJob: public DoJob
2912{
2913public:
2914 RowToItemJob( unsigned int row , int current ) { this->row = row; this->current = current ;}
2915 virtual ~RowToItemJob(){};
2916
d5025dc0 2917 virtual int operator() ( wxDataViewTreeNode * node )
d47db7e0
RR
2918 {
2919 current ++;
2920 if( current == static_cast<int>(row))
9bcc8016 2921 {
d47db7e0
RR
2922 ret = node->GetItem() ;
2923 return DoJob::OK;
2924 }
d5025dc0 2925
d47db7e0
RR
2926 if( node->GetSubTreeCount() + current < static_cast<int>(row) )
2927 {
2928 current += node->GetSubTreeCount();
2929 return DoJob::IGR;
2930 }
2931 else
b7e9f8b1
RR
2932 {
2933 //If the current has no child node, we can find the desired item of the row number directly.
2934 //This if can speed up finding in some case, and will has a very good effect when it comes to list view
2935 if( node->GetNodes().GetCount() == 0)
2936 {
2937 int index = static_cast<int>(row) - current - 1;
2938 ret = node->GetChildren().Item( index );
2939 return DoJob::OK;
2940 }
d47db7e0 2941 return DoJob::CONT;
b7e9f8b1 2942 }
d47db7e0
RR
2943 }
2944
2945 virtual int operator() ( void * n )
2946 {
2947 current ++;
2948 if( current == static_cast<int>(row))
9bcc8016 2949 {
d47db7e0
RR
2950 ret = wxDataViewItem( n ) ;
2951 return DoJob::OK;
2952 }
2953 return DoJob::CONT;
2954 }
d5025dc0 2955 wxDataViewItem GetResult(){ return ret; }
aba9bfd0
RR
2956private:
2957 unsigned int row;
2958 int current ;
2959 wxDataViewItem ret;
2960};
2961
fbda518c 2962wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) const
aba9bfd0 2963{
a3cc79d9
RR
2964 if (!m_root)
2965 {
2966 return wxDataViewItem( (void*) row );
2967 }
2968 else
2969 {
2970 RowToItemJob job( row, -2 );
2971 Walker( m_root , job );
2972 return job.GetResult();
2973 }
aba9bfd0
RR
2974}
2975
3b6280be
RR
2976class RowToTreeNodeJob: public DoJob
2977{
2978public:
442c56e6
VZ
2979 RowToTreeNodeJob( unsigned int row , int current, wxDataViewTreeNode * node )
2980 {
2981 this->row = row;
2982 this->current = current ;
d47db7e0
RR
2983 ret = NULL ;
2984 parent = node;
2985 }
d5025dc0 2986 virtual ~RowToTreeNodeJob(){};
3b6280be
RR
2987
2988 virtual int operator() ( wxDataViewTreeNode * node )
d5025dc0 2989 {
d47db7e0 2990 current ++;
704c3490 2991 if( current == static_cast<int>(row))
9bcc8016 2992 {
d5025dc0
RR
2993 ret = node ;
2994 return DoJob::OK;
3b6280be 2995 }
d47db7e0
RR
2996
2997 if( node->GetSubTreeCount() + current < static_cast<int>(row) )
2998 {
2999 current += node->GetSubTreeCount();
3000 return DoJob::IGR;
3001 }
d5025dc0 3002 else
d47db7e0
RR
3003 {
3004 parent = node;
b7e9f8b1
RR
3005 //If the current has no child node, we can find the desired item of the row number directly.
3006 //This if can speed up finding in some case, and will has a very good effect when it comes to list view
3007 if( node->GetNodes().GetCount() == 0)
3008 {
3009 int index = static_cast<int>(row) - current - 1;
3010 void * n = node->GetChildren().Item( index );
3011 ret = new wxDataViewTreeNode( parent ) ;
3012 ret->SetItem( wxDataViewItem( n ));
3013 ret->SetHasChildren(false);
3014 return DoJob::OK;
3015 }
d47db7e0
RR
3016 return DoJob::CONT;
3017 }
3018
b7e9f8b1 3019
d5025dc0 3020 }
3b6280be 3021
d47db7e0
RR
3022 virtual int operator() ( void * n )
3023 {
3024 current ++;
3025 if( current == static_cast<int>(row))
9bcc8016 3026 {
d47db7e0
RR
3027 ret = new wxDataViewTreeNode( parent ) ;
3028 ret->SetItem( wxDataViewItem( n ));
3029 ret->SetHasChildren(false);
3030 return DoJob::OK;
3031 }
442c56e6 3032
d47db7e0
RR
3033 return DoJob::CONT;
3034 }
3b6280be
RR
3035 wxDataViewTreeNode * GetResult(){ return ret; }
3036private:
3037 unsigned int row;
3038 int current ;
3039 wxDataViewTreeNode * ret;
d47db7e0 3040 wxDataViewTreeNode * parent ;
3b6280be
RR
3041};
3042
3043
3044wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row)
3045{
a3cc79d9
RR
3046 if (!m_root)
3047 {
3048 return NULL;
3049 }
3050 else
3051 {
3052 RowToTreeNodeJob job( row , -2, m_root );
3053 Walker( m_root , job );
3054 return job.GetResult();
3055 }
3b6280be
RR
3056}
3057
66e09788
RR
3058wxDataViewEvent wxDataViewMainWindow::SendExpanderEvent( wxEventType type, const wxDataViewItem & item )
3059{
3060 wxWindow *parent = GetParent();
3061 wxDataViewEvent le(type, parent->GetId());
3062
3063 le.SetEventObject(parent);
3064 le.SetModel(GetOwner()->GetModel());
3065 le.SetItem( item );
3066
3067 parent->GetEventHandler()->ProcessEvent(le);
3068 return le;
3069}
3070
3b6280be
RR
3071void wxDataViewMainWindow::OnExpanding( unsigned int row )
3072{
3073 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
3074 if( node != NULL )
3075 {
d5025dc0 3076 if( node->HasChildren())
66e09788 3077 {
d5025dc0 3078 if( !node->IsOpen())
3b6280be 3079 {
66e09788
RR
3080 wxDataViewEvent e = SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,node->GetItem());
3081 //Check if the user prevent expanding
3082 if( e.GetSkipped() )
3083 return;
b7fe2261 3084
d5025dc0 3085 node->ToggleOpen();
704c3490
RR
3086 //Here I build the children of current node
3087 if( node->GetChildrenNumber() == 0 )
24c4a50f
RR
3088 {
3089 SortPrepare();
74123073 3090 ::BuildTreeHelper(GetOwner()->GetModel(), node->GetItem(), node);
24c4a50f 3091 }
d5025dc0 3092 m_count = -1;
351461fc 3093 UpdateDisplay();
66e09788
RR
3094 //Send the expanded event
3095 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED,node->GetItem());
351461fc
RR
3096 }
3097 else
3098 {
3099 SelectRow( row, false );
3100 SelectRow( row + 1, true );
3101 ChangeCurrentRow( row + 1 );
526e19e2 3102 SendSelectionChangedEvent( GetItemByRow(row+1));
3b6280be 3103 }
66e09788 3104 }
d47db7e0
RR
3105 else
3106 delete node;
3b6280be
RR
3107 }
3108}
3109
3110void wxDataViewMainWindow::OnCollapsing(unsigned int row)
3111{
3112 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
d5025dc0 3113 if( node != NULL )
3b6280be 3114 {
d47db7e0
RR
3115 wxDataViewTreeNode * nd = node;
3116
3b6280be
RR
3117 if( node->HasChildren() && node->IsOpen() )
3118 {
66e09788
RR
3119 wxDataViewEvent e = SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,node->GetItem());
3120 if( e.GetSkipped() )
3121 return;
3b6280be
RR
3122 node->ToggleOpen();
3123 m_count = -1;
351461fc 3124 UpdateDisplay();
66e09788
RR
3125 SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED,nd->GetItem());
3126 }
3127 else
3128 {
3129 node = node->GetParent();
3130 if( node != NULL )
3131 {
3132 int parent = GetRowByItem( node->GetItem() ) ;
3133 if( parent >= 0 )
3134 {
3135 SelectRow( row, false);
3136 SelectRow(parent , true );
3137 ChangeCurrentRow( parent );
526e19e2 3138 SendSelectionChangedEvent( node->GetItem() );
66e09788
RR
3139 }
3140 }
3141 }
3142 if( !nd->HasChildren())
3143 delete nd;
3b6280be
RR
3144 }
3145}
3146
351461fc
RR
3147wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item )
3148{
3149 wxDataViewModel * model = GetOwner()->GetModel();
3150 if( model == NULL )
3151 return NULL;
3152
3153 //Compose the a parent-chain of the finding item
3154 ItemList list;
3155 list.DeleteContents( true );
3156 wxDataViewItem it( item );
3157 while( it.IsOk() )
3158 {
3159 wxDataViewItem * pItem = new wxDataViewItem( it );
3160 list.Insert( pItem );
3161 it = model->GetParent( it );
3162 }
3163
442c56e6 3164 //Find the item along the parent-chain.
351461fc 3165 //This algorithm is designed to speed up the node-finding method
351461fc 3166 wxDataViewTreeNode * node = m_root;
c899416d 3167 for( ItemList::const_iterator iter = list.begin(); iter !=list.end() ; iter++ )
351461fc
RR
3168 {
3169 if( node->HasChildren() )
3170 {
3171 if( node->GetChildrenNumber() == 0 )
24c4a50f
RR
3172 {
3173 SortPrepare();
74123073 3174 ::BuildTreeHelper(model, node->GetItem(), node);
24c4a50f 3175 }
351461fc 3176
d47db7e0 3177 wxDataViewTreeNodes nodes = node->GetNodes();
d2c1ee8a
RR
3178 unsigned int i;
3179 bool found = false;
3180
3181 for (i = 0; i < nodes.GetCount(); i ++)
d92cb015 3182 {
c899416d 3183 if (nodes[i]->GetItem() == (**iter))
b7fe2261 3184 {
d2c1ee8a
RR
3185 if (nodes[i]->GetItem() == item)
3186 return nodes[i];
3187
d92cb015 3188 node = nodes[i];
d2c1ee8a 3189 found = true;
d92cb015
RR
3190 break;
3191 }
3192 }
d2c1ee8a 3193 if (!found)
351461fc 3194 return NULL;
351461fc
RR
3195 }
3196 else
3197 return NULL;
3198 }
d2c1ee8a 3199 return NULL;
351461fc
RR
3200}
3201
a87b466d 3202void wxDataViewMainWindow::HitTest( const wxPoint & point, wxDataViewItem & item, wxDataViewColumn* &column )
66e09788 3203{
fbda518c 3204 wxDataViewColumn *col = NULL;
66e09788
RR
3205 unsigned int cols = GetOwner()->GetColumnCount();
3206 unsigned int colnum = 0;
3207 unsigned int x_start = 0;
3208 int x, y;
3209 m_owner->CalcUnscrolledPosition( point.x, point.y, &x, &y );
3210 for (x_start = 0; colnum < cols; colnum++)
3211 {
fbda518c 3212 col = GetOwner()->GetColumn(colnum);
66e09788
RR
3213 if (col->IsHidden())
3214 continue; // skip it!
3215
3216 unsigned int w = col->GetWidth();
3217 if (x_start+w >= (unsigned int)x)
3218 break;
3219
3220 x_start += w;
3221 }
3222
fbda518c 3223 column = col;
66e09788
RR
3224 item = GetItemByRow( y/m_lineHeight );
3225}
3226
fbda518c 3227wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item, const wxDataViewColumn* column )
66e09788
RR
3228{
3229 int row = GetRowByItem(item);
3230 int y = row*m_lineHeight;
3231 int h = m_lineHeight;
3232 int x = 0;
3233 wxDataViewColumn *col = NULL;
3234 for( int i = 0, cols = GetOwner()->GetColumnCount(); i < cols; i ++ )
3235 {
3236 col = GetOwner()->GetColumn( i );
3237 x += col->GetWidth();
fbda518c 3238 if( GetOwner()->GetColumn(i+1) == column )
66e09788
RR
3239 break;
3240 }
3241 int w = col->GetWidth();
3242 m_owner->CalcScrolledPosition( x, y, &x, &y );
3243 return wxRect(x, y, w, h);
3244}
3245
442c56e6 3246int wxDataViewMainWindow::RecalculateCount()
3b6280be 3247{
a3cc79d9
RR
3248 if (!m_root)
3249 {
3250 wxDataViewIndexListModel *list_model = (wxDataViewIndexListModel*) GetOwner()->GetModel();
f52984b8
RR
3251#ifndef __WXMAC__
3252 return list_model->GetLastIndex() + 1;
3253#else
3254 return list_model->GetLastIndex() - 1;
3255#endif
a3cc79d9
RR
3256 }
3257 else
3258 {
3259 return m_root->GetSubTreeCount();
3260 }
3b6280be
RR
3261}
3262
aba9bfd0
RR
3263class ItemToRowJob : public DoJob
3264{
3265public:
c899416d
RR
3266 ItemToRowJob(const wxDataViewItem & item, ItemList::const_iterator iter )
3267 { this->item = item ; ret = -1 ; m_iter = iter ; }
aba9bfd0
RR
3268 virtual ~ItemToRowJob(){};
3269
b7e9f8b1 3270 //Maybe binary search will help to speed up this process
d5025dc0
RR
3271 virtual int operator() ( wxDataViewTreeNode * node)
3272 {
3273 ret ++;
3274 if( node->GetItem() == item )
d47db7e0 3275 {
d5025dc0 3276 return DoJob::OK;
d47db7e0 3277 }
d5025dc0 3278
c899416d 3279 if( node->GetItem() == **m_iter )
d47db7e0 3280 {
c899416d 3281 m_iter++ ;
d5025dc0 3282 return DoJob::CONT;
d47db7e0 3283 }
d5025dc0 3284 else
d47db7e0
RR
3285 {
3286 ret += node->GetSubTreeCount();
d5025dc0 3287 return DoJob::IGR;
d47db7e0 3288 }
442c56e6 3289
d5025dc0 3290 }
aba9bfd0 3291
d47db7e0
RR
3292 virtual int operator() ( void * n )
3293 {
3294 ret ++;
3295 if( n == item.GetID() )
3296 return DoJob::OK;
3297 return DoJob::CONT;
3298 }
3b6280be
RR
3299 //the row number is begin from zero
3300 int GetResult(){ return ret -1 ; }
aba9bfd0 3301private:
c899416d 3302 ItemList::const_iterator m_iter;
aba9bfd0
RR
3303 wxDataViewItem item;
3304 int ret;
442c56e6 3305
aba9bfd0
RR
3306};
3307
b7e9f8b1 3308int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item)
aba9bfd0 3309{
d47db7e0
RR
3310 wxDataViewModel * model = GetOwner()->GetModel();
3311 if( model == NULL )
fbda518c 3312 return -1;
d47db7e0 3313
a3cc79d9 3314 if (!m_root)
d47db7e0 3315 {
a3cc79d9 3316 return wxPtrToUInt( item.GetID() );
d47db7e0 3317 }
a3cc79d9
RR
3318 else
3319 {
3320 if( !item.IsOk() )
3321 return -1;
3322
3323 //Compose the a parent-chain of the finding item
3324 ItemList list;
3325 wxDataViewItem * pItem = NULL;
3326 list.DeleteContents( true );
3327 wxDataViewItem it( item );
3328 while( it.IsOk() )
3329 {
3330 pItem = new wxDataViewItem( it );
3331 list.Insert( pItem );
3332 it = model->GetParent( it );
3333 }
3334 pItem = new wxDataViewItem( );
3335 list.Insert( pItem );
d47db7e0 3336
a3cc79d9
RR
3337 ItemToRowJob job( item, list.begin() );
3338 Walker(m_root , job );
3339 return job.GetResult();
3340 }
aba9bfd0
RR
3341}
3342
74123073 3343static void BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node)
aba9bfd0 3344{
351461fc 3345 if( !model->IsContainer( item ) )
704c3490 3346 return ;
442c56e6 3347
c899416d
RR
3348 wxDataViewItemArray children;
3349 unsigned int num = model->GetChildren( item, children);
67be459b 3350 unsigned int index = 0;
c899416d 3351 while( index < num )
aba9bfd0 3352 {
c899416d 3353 if( model->IsContainer( children[index] ) )
d47db7e0
RR
3354 {
3355 wxDataViewTreeNode * n = new wxDataViewTreeNode( node );
c899416d 3356 n->SetItem(children[index]);
d47db7e0
RR
3357 n->SetHasChildren( true ) ;
3358 node->AddNode( n );
3359 }
3360 else
3361 {
c899416d 3362 node->AddLeaf( children[index].GetID() );
d47db7e0 3363 }
c899416d 3364 index ++;
aba9bfd0 3365 }
d47db7e0
RR
3366 node->SetSubTreeCount( num );
3367 wxDataViewTreeNode * n = node->GetParent();
3368 if( n != NULL)
3369 n->ChangeSubTreeCount(num);
3370
aba9bfd0
RR
3371}
3372
3373void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
3374{
51bdecff
RR
3375 DestroyTree();
3376
e39de702 3377 if (GetOwner()->GetModel()->IsVirtualListModel())
a3cc79d9
RR
3378 {
3379 m_count = -1 ;
3380 return;
3381 }
3382
51bdecff
RR
3383 m_root = new wxDataViewTreeNode( NULL );
3384 m_root->SetHasChildren(true);
3385
aba9bfd0
RR
3386 //First we define a invalid item to fetch the top-level elements
3387 wxDataViewItem item;
66e09788 3388 SortPrepare();
3b6280be
RR
3389 BuildTreeHelper( model, item, m_root);
3390 m_count = -1 ;
aba9bfd0
RR
3391}
3392
74123073 3393static void DestroyTreeHelper( wxDataViewTreeNode * node )
aba9bfd0 3394{
d47db7e0 3395 if( node->GetNodeNumber() != 0 )
aba9bfd0 3396 {
d47db7e0 3397 int len = node->GetNodeNumber();
3b6280be 3398 int i = 0 ;
74123073 3399 wxDataViewTreeNodes& nodes = node->GetNodes();
3b6280be 3400 for( ; i < len; i ++ )
aba9bfd0
RR
3401 {
3402 DestroyTreeHelper(nodes[i]);
3403 }
3404 }
3405 delete node;
3406}
3407
3408void wxDataViewMainWindow::DestroyTree()
3409{
51bdecff
RR
3410 if (m_root)
3411 {
74123073 3412 ::DestroyTreeHelper(m_root);
51bdecff
RR
3413 m_count = 0;
3414 m_root = NULL;
3415 }
aba9bfd0
RR
3416}
3417
cab07038
RR
3418void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
3419{
f029f1d1
VS
3420 if ( HandleAsNavigationKey(event) )
3421 return;
cab07038
RR
3422
3423 // no item -> nothing to do
3424 if (!HasCurrentRow())
3425 {
3426 event.Skip();
3427 return;
3428 }
120b9b05 3429
cab07038
RR
3430 // don't use m_linesPerPage directly as it might not be computed yet
3431 const int pageSize = GetCountPerPage();
3432 wxCHECK_RET( pageSize, _T("should have non zero page size") );
3433
3434 switch ( event.GetKeyCode() )
3435 {
d37b709c
RR
3436 case WXK_RETURN:
3437 {
3438 if (m_currentRow > 0)
3439 {
3440 wxWindow *parent = GetParent();
3441 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId());
3442 le.SetItem( GetItemByRow(m_currentRow) );
3443 le.SetEventObject(parent);
3444 le.SetModel(GetOwner()->GetModel());
3445
3446 parent->GetEventHandler()->ProcessEvent(le);
3447 }
3448 break;
3449 }
cab07038
RR
3450 case WXK_UP:
3451 if ( m_currentRow > 0 )
3452 OnArrowChar( m_currentRow - 1, event );
3453 break;
3454
3455 case WXK_DOWN:
4a851b11 3456 if ( m_currentRow < GetRowCount() - 1 )
cab07038
RR
3457 OnArrowChar( m_currentRow + 1, event );
3458 break;
3b6280be
RR
3459 //Add the process for tree expanding/collapsing
3460 case WXK_LEFT:
9bcc8016
JS
3461 OnCollapsing(m_currentRow);
3462 break;
3463 case WXK_RIGHT:
3464 OnExpanding( m_currentRow);
3465 break;
cab07038
RR
3466 case WXK_END:
3467 if (!IsEmpty())
3468 OnArrowChar( GetRowCount() - 1, event );
3469 break;
3470
3471 case WXK_HOME:
3472 if (!IsEmpty())
3473 OnArrowChar( 0, event );
3474 break;
3475
3476 case WXK_PAGEUP:
3477 {
3478 int steps = pageSize - 1;
3479 int index = m_currentRow - steps;
3480 if (index < 0)
3481 index = 0;
3482
3483 OnArrowChar( index, event );
3484 }
3485 break;
3486
3487 case WXK_PAGEDOWN:
3488 {
3489 int steps = pageSize - 1;
0a71f9e9
RR
3490 unsigned int index = m_currentRow + steps;
3491 unsigned int count = GetRowCount();
cab07038
RR
3492 if ( index >= count )
3493 index = count - 1;
3494
3495 OnArrowChar( index, event );
3496 }
3497 break;
3498
3499 default:
3500 event.Skip();
3501 }
3502}
3503
4ed7af08
RR
3504void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
3505{
e21f75bd
RR
3506 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
3507 {
3508 // let the base handle mouse wheel events.
3509 event.Skip();
3510 return;
3511 }
3512
0fdc2321
RR
3513 int x = event.GetX();
3514 int y = event.GetY();
3515 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
0fdc2321 3516 wxDataViewColumn *col = NULL;
b7fe2261 3517
0fdc2321 3518 int xpos = 0;
9861f022 3519 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 3520 unsigned int i;
0fdc2321
RR
3521 for (i = 0; i < cols; i++)
3522 {
3523 wxDataViewColumn *c = GetOwner()->GetColumn( i );
9861f022
RR
3524 if (c->IsHidden())
3525 continue; // skip it!
3526
0fdc2321
RR
3527 if (x < xpos + c->GetWidth())
3528 {
3529 col = c;
3530 break;
3531 }
3532 xpos += c->GetWidth();
3533 }
f554a14b 3534 if (!col)
0fdc2321 3535 return;
f554a14b 3536
24c4a50f 3537 wxDataViewRenderer *cell = col->GetRenderer();
0a71f9e9 3538 unsigned int current = y / m_lineHeight;
e21f75bd
RR
3539 if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
3540 {
3541 // Unselect all if below the last row ?
3542 return;
3543 }
f554a14b 3544
24c4a50f
RR
3545 //Test whether the mouse is hovered on the tree item button
3546 bool hover = false;
a3cc79d9 3547 if ((m_root) && (GetOwner()->GetExpanderColumn() == col))
24c4a50f
RR
3548 {
3549 wxDataViewTreeNode * node = GetTreeNodeByRow(current);
3550 if( node!=NULL && node->HasChildren() )
3551 {
3552 int indent = node->GetIndentLevel();
3553 indent = GetOwner()->GetIndent()*indent;
3554 wxRect rect( xpos + indent + EXPANDER_MARGIN, current * m_lineHeight + EXPANDER_MARGIN, m_lineHeight-2*EXPANDER_MARGIN,m_lineHeight-2*EXPANDER_MARGIN);
3555 if( rect.Contains( x, y) )
3556 {
3557 //So the mouse is over the expander
3558 hover = true;
3559 if (m_underMouse && m_underMouse != node)
3560 {
3561 //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem()));
df2c23e7 3562 RefreshRow(GetRowByItem(m_underMouse->GetItem()));
24c4a50f
RR
3563 }
3564 if (m_underMouse != node)
3565 {
3566 //wxLogMessage("Do the row: %d", current);
df2c23e7 3567 RefreshRow(current);
24c4a50f
RR
3568 }
3569 m_underMouse = node;
3570 }
3571 }
438fb233 3572 if (node!=NULL && !node->HasChildren())
24c4a50f
RR
3573 delete node;
3574 }
3575 if (!hover)
3576 {
3577 if (m_underMouse != NULL)
3578 {
526e19e2 3579 //wxLogMessage("Undo the row: %d", GetRowByItem(m_underMouse->GetItem()));
df2c23e7 3580 RefreshRow(GetRowByItem(m_underMouse->GetItem()));
24c4a50f
RR
3581 m_underMouse = NULL;
3582 }
3583 }
3584
aba9bfd0 3585 wxDataViewModel *model = GetOwner()->GetModel();
0fdc2321 3586
e21f75bd
RR
3587 if (event.Dragging())
3588 {
3589 if (m_dragCount == 0)
3590 {
3591 // we have to report the raw, physical coords as we want to be
3592 // able to call HitTest(event.m_pointDrag) from the user code to
3593 // get the item being dragged
3594 m_dragStart = event.GetPosition();
3595 }
3596
3597 m_dragCount++;
3598
3599 if (m_dragCount != 3)
3600 return;
3601
3602 if (event.LeftIsDown())
3603 {
3604 // Notify cell about drag
3605 }
3606 return;
3607 }
3608 else
3609 {
3610 m_dragCount = 0;
3611 }
3612
3613 bool forceClick = false;
3614
0fcce6b9
RR
3615 if (event.ButtonDClick())
3616 {
3617 m_renameTimer->Stop();
3618 m_lastOnSame = false;
3619 }
3620
438fb233
RR
3621 wxDataViewItem item = GetItemByRow(current);
3622 bool ignore_other_columns =
3623 ((GetOwner()->GetExpanderColumn() != col) &&
3624 (model->IsContainer(item)) &&
3625 (!model->HasContainerColumns(item)));
b5ec7dd6 3626
0fdc2321
RR
3627 if (event.LeftDClick())
3628 {
e21f75bd 3629 if ( current == m_lineLastClicked )
0fdc2321 3630 {
438fb233 3631 if ((!ignore_other_columns) && (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE))
e21f75bd
RR
3632 {
3633 wxVariant value;
6cdcbce3 3634 model->GetValue( value, item, col->GetModelColumn() );
e21f75bd 3635 cell->SetValue( value );
c741d33f 3636 wxRect cell_rect( xpos, current * m_lineHeight,
87f0efe2 3637 col->GetWidth(), m_lineHeight );
6cdcbce3 3638 cell->Activate( cell_rect, model, item, col->GetModelColumn() );
b7e9f8b1 3639
2c3f6edd
RR
3640 }
3641 else
3642 {
b7e9f8b1
RR
3643 wxWindow *parent = GetParent();
3644 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId());
45c156e0 3645 le.SetItem( item );
b7e9f8b1 3646 le.SetEventObject(parent);
b7e9f8b1
RR
3647 le.SetModel(GetOwner()->GetModel());
3648
3649 parent->GetEventHandler()->ProcessEvent(le);
e21f75bd
RR
3650 }
3651 return;
3652 }
3653 else
3654 {
3655 // The first click was on another item, so don't interpret this as
3656 // a double click, but as a simple click instead
3657 forceClick = true;
0fdc2321 3658 }
120b9b05 3659 }
f554a14b 3660
0fcce6b9
RR
3661 if (event.LeftUp())
3662 {
0a71f9e9 3663 if (m_lineSelectSingleOnUp != (unsigned int)-1)
e21f75bd
RR
3664 {
3665 // select single line
3666 SelectAllRows( false );
3667 SelectRow( m_lineSelectSingleOnUp, true );
3668 }
120b9b05 3669
3b6280be 3670 //Process the event of user clicking the expander
d5025dc0 3671 bool expander = false;
a3cc79d9 3672 if ((m_root) && (GetOwner()->GetExpanderColumn() == col))
d5025dc0 3673 {
9bcc8016
JS
3674 wxDataViewTreeNode * node = GetTreeNodeByRow(current);
3675 if( node!=NULL && node->HasChildren() )
3676 {
3677 int indent = node->GetIndentLevel();
3678 indent = GetOwner()->GetIndent()*indent;
3679 wxRect rect( xpos + indent + EXPANDER_MARGIN, current * m_lineHeight + EXPANDER_MARGIN, m_lineHeight-2*EXPANDER_MARGIN,m_lineHeight-2*EXPANDER_MARGIN);
3680 if( rect.Contains( x, y) )
3681 {
3682 expander = true;
3683 if( node->IsOpen() )
3684 OnCollapsing(current);
3685 else
3686 OnExpanding( current );
3687 }
3688 }
74123073
RR
3689 if (node && !node->HasChildren())
3690 delete node;
d5025dc0 3691 }
3b6280be 3692 //If the user click the expander, we do not do editing even if the column with expander are editable
438fb233 3693 if (m_lastOnSame && !expander && !ignore_other_columns)
0fcce6b9 3694 {
a8461d31 3695 if ((col == m_currentCol) && (current == m_currentRow) &&
0bdfa388 3696 (cell->GetMode() & wxDATAVIEW_CELL_EDITABLE) )
0fcce6b9
RR
3697 {
3698 m_renameTimer->Start( 100, true );
3699 }
3700 }
3701
3702 m_lastOnSame = false;
0a71f9e9 3703 m_lineSelectSingleOnUp = (unsigned int)-1;
120b9b05 3704 }
e21f75bd
RR
3705 else
3706 {
3707 // This is necessary, because after a DnD operation in
3708 // from and to ourself, the up event is swallowed by the
3709 // DnD code. So on next non-up event (which means here and
3710 // now) m_lineSelectSingleOnUp should be reset.
0a71f9e9 3711 m_lineSelectSingleOnUp = (unsigned int)-1;
e21f75bd
RR
3712 }
3713
3714 if (event.RightDown())
3715 {
3716 m_lineBeforeLastClicked = m_lineLastClicked;
3717 m_lineLastClicked = current;
3718
3719 // If the item is already selected, do not update the selection.
3720 // Multi-selections should not be cleared if a selected item is clicked.
3721 if (!IsRowSelected(current))
3722 {
3723 SelectAllRows(false);
3724 ChangeCurrentRow(current);
3725 SelectRow(m_currentRow,true);
526e19e2 3726 SendSelectionChangedEvent(GetItemByRow( m_currentRow ) );
e21f75bd
RR
3727 }
3728
f210b1b5
RR
3729 wxVariant value;
3730 model->GetValue( value, item, col->GetModelColumn() );
0bdfa388
RR
3731 wxWindow *parent = GetParent();
3732 wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, parent->GetId());
3733 le.SetItem( item );
3734 le.SetEventObject(parent);
3735 le.SetModel(GetOwner()->GetModel());
3736 le.SetValue(value);
3737 parent->GetEventHandler()->ProcessEvent(le);
e21f75bd
RR
3738 }
3739 else if (event.MiddleDown())
3740 {
e21f75bd
RR
3741 }
3742 if (event.LeftDown() || forceClick)
0fcce6b9 3743 {
72664514 3744 SetFocus();
120b9b05 3745
e21f75bd
RR
3746 m_lineBeforeLastClicked = m_lineLastClicked;
3747 m_lineLastClicked = current;
3748
0a71f9e9 3749 unsigned int oldCurrentRow = m_currentRow;
e21f75bd
RR
3750 bool oldWasSelected = IsRowSelected(m_currentRow);
3751
3752 bool cmdModifierDown = event.CmdDown();
3753 if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
3754 {
3755 if ( IsSingleSel() || !IsRowSelected(current) )
3756 {
3757 SelectAllRows( false );
e21f75bd 3758 ChangeCurrentRow(current);
e21f75bd 3759 SelectRow(m_currentRow,true);
526e19e2 3760 SendSelectionChangedEvent(GetItemByRow( m_currentRow ) );
e21f75bd
RR
3761 }
3762 else // multi sel & current is highlighted & no mod keys
3763 {
3764 m_lineSelectSingleOnUp = current;
3765 ChangeCurrentRow(current); // change focus
3766 }
3767 }
3768 else // multi sel & either ctrl or shift is down
3769 {
3770 if (cmdModifierDown)
3771 {
3772 ChangeCurrentRow(current);
e21f75bd 3773 ReverseRowSelection(m_currentRow);
526e19e2 3774 SendSelectionChangedEvent(GetItemByRow(m_selection[0]) );
e21f75bd
RR
3775 }
3776 else if (event.ShiftDown())
3777 {
3778 ChangeCurrentRow(current);
3779
0a71f9e9 3780 unsigned int lineFrom = oldCurrentRow,
e21f75bd
RR
3781 lineTo = current;
3782
3783 if ( lineTo < lineFrom )
3784 {
3785 lineTo = lineFrom;
3786 lineFrom = m_currentRow;
3787 }
3788
3789 SelectRows(lineFrom, lineTo, true);
526e19e2 3790 SendSelectionChangedEvent(GetItemByRow(m_selection[0]) );
e21f75bd
RR
3791 }
3792 else // !ctrl, !shift
3793 {
3794 // test in the enclosing if should make it impossible
3795 wxFAIL_MSG( _T("how did we get here?") );
3796 }
3797 }
0bdfa388 3798
72664514
RR
3799 if (m_currentRow != oldCurrentRow)
3800 RefreshRow( oldCurrentRow );
e21f75bd 3801
0fcce6b9 3802 wxDataViewColumn *oldCurrentCol = m_currentCol;
120b9b05 3803
0fcce6b9
RR
3804 // Update selection here...
3805 m_currentCol = col;
120b9b05 3806
c741d33f 3807 m_lastOnSame = !forceClick && ((col == oldCurrentCol) &&
87f0efe2 3808 (current == oldCurrentRow)) && oldWasSelected;
0bdfa388
RR
3809
3810 // Call LeftClick after everything else as under GTK+
3811 if (cell->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE)
3812 {
3813 // notify cell about right click
3814 wxVariant value;
3815 model->GetValue( value, item, col->GetModelColumn() );
3816 cell->SetValue( value );
3817 wxRect cell_rect( xpos, current * m_lineHeight,
3818 col->GetWidth(), m_lineHeight );
3819 /* ignore ret */ cell->LeftClick( event.GetPosition(), cell_rect, model, item, col->GetModelColumn());
3820 }
0fdc2321 3821 }
4ed7af08
RR
3822}
3823
3824void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
3825{
cab07038 3826 m_hasFocus = true;
120b9b05 3827
cab07038
RR
3828 if (HasCurrentRow())
3829 Refresh();
120b9b05 3830
cab07038
RR
3831 event.Skip();
3832}
3833
3834void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
3835{
3836 m_hasFocus = false;
120b9b05 3837
cab07038
RR
3838 if (HasCurrentRow())
3839 Refresh();
120b9b05 3840
4ed7af08
RR
3841 event.Skip();
3842}
3843
fbda518c 3844wxDataViewItem wxDataViewMainWindow::GetSelection() const
704c3490
RR
3845{
3846 if( m_selection.GetCount() != 1 )
3847 return wxDataViewItem();
d47db7e0
RR
3848
3849 return GetItemByRow( m_selection.Item(0));
704c3490
RR
3850}
3851
4ed7af08
RR
3852//-----------------------------------------------------------------------------
3853// wxDataViewCtrl
3854//-----------------------------------------------------------------------------
a76c2f37 3855WX_DEFINE_LIST(wxDataViewColumnList)
4ed7af08
RR
3856
3857IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
3858
4b3feaa7
RR
3859BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
3860 EVT_SIZE(wxDataViewCtrl::OnSize)
3861END_EVENT_TABLE()
3862
4ed7af08
RR
3863wxDataViewCtrl::~wxDataViewCtrl()
3864{
3865 if (m_notifier)
3866 GetModel()->RemoveNotifier( m_notifier );
74123073
RR
3867
3868 wxDataViewColumnList::const_iterator iter;
3869 for (iter = m_cols.begin(); iter!=m_cols.end(); iter++)
3870 {
3871 delete *iter;
3872 }
4ed7af08
RR
3873}
3874
3875void wxDataViewCtrl::Init()
3876{
3877 m_notifier = NULL;
3878}
3879
3880bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 3881 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
3882 long style, const wxValidator& validator )
3883{
008e999e
RD
3884 if ( (style & wxBORDER_MASK) == 0)
3885 style |= wxBORDER_SUNKEN;
3886
c741d33f 3887 if (!wxControl::Create( parent, id, pos, size,
008e999e 3888 style | wxScrolledWindowStyle, validator))
4b3feaa7
RR
3889 return false;
3890
b89cac3f 3891 SetInitialSize(size);
b5ec7dd6 3892
4ed7af08 3893 Init();
f554a14b 3894
4ed7af08
RR
3895#ifdef __WXMAC__
3896 MacSetClipChildren( true ) ;
3897#endif
3898
f554a14b 3899 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
9861f022
RR
3900
3901 if (HasFlag(wxDV_NO_HEADER))
3902 m_headerArea = NULL;
3903 else
3904 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY );
f554a14b 3905
4ed7af08 3906 SetTargetWindow( m_clientArea );
f554a14b 3907
4ed7af08 3908 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
9861f022
RR
3909 if (m_headerArea)
3910 sizer->Add( m_headerArea, 0, wxGROW );
4ed7af08
RR
3911 sizer->Add( m_clientArea, 1, wxGROW );
3912 SetSizer( sizer );
b5ec7dd6 3913
4ed7af08
RR
3914 return true;
3915}
3916
3917#ifdef __WXMSW__
3918WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
3919 WXWPARAM wParam,
3920 WXLPARAM lParam)
3921{
b910a8ad 3922 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
3923
3924#ifndef __WXWINCE__
3925 // we need to process arrows ourselves for scrolling
3926 if ( nMsg == WM_GETDLGCODE )
3927 {
3928 rc |= DLGC_WANTARROWS;
3929 }
3930#endif
3931
3932 return rc;
3933}
3934#endif
3935
f554a14b 3936void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 3937{
4b3feaa7
RR
3938 // We need to override OnSize so that our scrolled
3939 // window a) does call Layout() to use sizers for
3940 // positioning the controls but b) does not query
3941 // the sizer for their size and use that for setting
3942 // the scrollable area as set that ourselves by
3943 // calling SetScrollbar() further down.
3944
3945 Layout();
3946
3947 AdjustScrollbars();
4ed7af08
RR
3948}
3949
aba9bfd0 3950bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
4ed7af08
RR
3951{
3952 if (!wxDataViewCtrlBase::AssociateModel( model ))
3953 return false;
3954
aba9bfd0 3955 m_notifier = new wxGenericDataViewModelNotifier( m_clientArea );
4ed7af08 3956
f554a14b 3957 model->AddNotifier( m_notifier );
4ed7af08 3958
51bdecff 3959 m_clientArea->DestroyTree();
cfa42cb8 3960
aba9bfd0
RR
3961 m_clientArea->BuildTree(model);
3962
4b3feaa7 3963 m_clientArea->UpdateDisplay();
f554a14b 3964
4ed7af08
RR
3965 return true;
3966}
3967
3968bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
3969{
3970 if (!wxDataViewCtrlBase::AppendColumn(col))
3971 return false;
f554a14b 3972
afebb87b 3973 m_cols.Append( col );
9861f022 3974 OnColumnChange();
736fe67c
RR
3975 return true;
3976}
3977
3978bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
3979{
3980 if (!wxDataViewCtrlBase::PrependColumn(col))
3981 return false;
3982
3983 m_cols.Insert( col );
3984 OnColumnChange();
4ed7af08
RR
3985 return true;
3986}
3987
9861f022
RR
3988void wxDataViewCtrl::OnColumnChange()
3989{
3990 if (m_headerArea)
3991 m_headerArea->UpdateDisplay();
3992
3993 m_clientArea->UpdateDisplay();
3994}
3b6280be
RR
3995
3996void wxDataViewCtrl::DoSetExpanderColumn()
3997{
3998 m_clientArea->UpdateDisplay();
3999}
4000
4001void wxDataViewCtrl::DoSetIndent()
4002{
4003 m_clientArea->UpdateDisplay();
4004}
4005
afebb87b
RR
4006unsigned int wxDataViewCtrl::GetColumnCount() const
4007{
4008 return m_cols.GetCount();
4009}
4010
4011wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const
4012{
4013 wxDataViewColumnList::const_iterator iter;
67be459b 4014 unsigned int i = 0;
afebb87b
RR
4015 for (iter = m_cols.begin(); iter!=m_cols.end(); iter++)
4016 {
4017 if (i == pos)
4018 return *iter;
4019
4020 if ((*iter)->IsHidden())
4021 continue;
4022 i ++;
4023 }
4024 return NULL;
4025}
4026
fc8c1a15
RR
4027void wxDataViewCtrl::ColumnMoved( wxDataViewColumn* col, unsigned int new_pos )
4028{
4029 if (new_pos > m_cols.GetCount()) return;
4030 m_cols.DeleteObject( col );
4031 m_cols.Insert( new_pos, col );
cfa42cb8 4032
fc8c1a15
RR
4033 m_clientArea->UpdateDisplay();
4034}
4035
afebb87b
RR
4036bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
4037{
c899416d 4038 wxDataViewColumnList::compatibility_iterator ret = m_cols.Find( column );
4264606e 4039 if (!ret)
afebb87b
RR
4040 return false;
4041
b7fe2261 4042 m_cols.Erase(ret);
afebb87b
RR
4043 delete column;
4044 OnColumnChange();
4045
4046 return true;
4047}
4048
4049bool wxDataViewCtrl::ClearColumns()
4050{
4051 m_cols.clear();
4052 OnColumnChange();
4053 return true;
4054}
4055
453091c2
RR
4056int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
4057{
526e19e2
RR
4058 int ret = 0, dead = 0;
4059 int len = GetColumnCount();
4060 for (int i=0; i<len; i++)
4061 {
4062 wxDataViewColumn * col = GetColumn(i);
4063 if (col->IsHidden())
4064 continue;
4065 ret += col->GetWidth();
4066 if (column==col)
4067 {
4068 CalcScrolledPosition( ret, dead, &ret, &dead );
4069 break;
4070 }
4071 }
4072 return ret;
453091c2
RR
4073}
4074
21f47fb9
RR
4075wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
4076{
4077 return NULL;
4078}
4079
b7e9f8b1 4080//Selection code with wxDataViewItem as parameters
fbda518c 4081wxDataViewItem wxDataViewCtrl::GetSelection() const
66e09788
RR
4082{
4083 return m_clientArea->GetSelection();
4084}
4085
b7e9f8b1
RR
4086int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const
4087{
4088 sel.Empty();
4089 wxDataViewSelection selection = m_clientArea->GetSelections();
4090 int len = selection.GetCount();
4091 for( int i = 0; i < len; i ++)
4092 {
4093 unsigned int row = selection[i];
4094 sel.Add( m_clientArea->GetItemByRow( row ) );
4095 }
4096 return len;
4097}
4098
4099void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel )
4100{
4101 wxDataViewSelection selection(wxDataViewSelectionCmp) ;
4102 int len = sel.GetCount();
4103 for( int i = 0; i < len; i ++ )
4104 {
4105 int row = m_clientArea->GetRowByItem( sel[i] );
4106 if( row >= 0 )
4107 selection.Add( static_cast<unsigned int>(row) );
4108 }
4109 m_clientArea->SetSelections( selection );
4110}
4111
4112void wxDataViewCtrl::Select( const wxDataViewItem & item )
704c3490 4113{
b7e9f8b1
RR
4114 int row = m_clientArea->GetRowByItem( item );
4115 if( row >= 0 )
57f2a652
RR
4116 {
4117 //Unselect all rows before select another in the single select mode
4118 if (m_clientArea->IsSingleSel())
4119 m_clientArea->SelectAllRows(false);
b7e9f8b1 4120 m_clientArea->SelectRow(row, true);
57f2a652 4121 }
704c3490 4122}
3b6280be 4123
b7e9f8b1 4124void wxDataViewCtrl::Unselect( const wxDataViewItem & item )
6ff7eee7 4125{
b7e9f8b1
RR
4126 int row = m_clientArea->GetRowByItem( item );
4127 if( row >= 0 )
4128 m_clientArea->SelectRow(row, false);
6ff7eee7
RR
4129}
4130
b7e9f8b1 4131bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const
6ff7eee7 4132{
b7e9f8b1
RR
4133 int row = m_clientArea->GetRowByItem( item );
4134 if( row >= 0 )
4135 {
4136 return m_clientArea->IsRowSelected(row);
4137 }
4138 return false;
6ff7eee7
RR
4139}
4140
b7e9f8b1
RR
4141//Selection code with row number as parameter
4142int wxDataViewCtrl::GetSelections( wxArrayInt & sel ) const
6ff7eee7 4143{
b7e9f8b1
RR
4144 sel.Empty();
4145 wxDataViewSelection selection = m_clientArea->GetSelections();
4146 int len = selection.GetCount();
4147 for( int i = 0; i < len; i ++)
4148 {
4149 unsigned int row = selection[i];
4150 sel.Add( row );
4151 }
4152 return len;
6ff7eee7 4153}
df387169 4154
b7e9f8b1 4155void wxDataViewCtrl::SetSelections( const wxArrayInt & sel )
fc211fe5 4156{
b7e9f8b1
RR
4157 wxDataViewSelection selection(wxDataViewSelectionCmp) ;
4158 int len = sel.GetCount();
4159 for( int i = 0; i < len; i ++ )
4160 {
4161 int row = sel[i];
4162 if( row >= 0 )
4163 selection.Add( static_cast<unsigned int>(row) );
4164 }
4165 m_clientArea->SetSelections( selection );
fc211fe5
RR
4166}
4167
b7e9f8b1 4168void wxDataViewCtrl::Select( int row )
6ff7eee7 4169{
b7e9f8b1 4170 if( row >= 0 )
57f2a652
RR
4171 {
4172 if (m_clientArea->IsSingleSel())
4173 m_clientArea->SelectAllRows(false);
b7e9f8b1 4174 m_clientArea->SelectRow( row, true );
57f2a652 4175 }
b7e9f8b1 4176}
df387169 4177
b7e9f8b1
RR
4178void wxDataViewCtrl::Unselect( int row )
4179{
4180 if( row >= 0 )
4181 m_clientArea->SelectRow(row, false);
4182}
4183
4184bool wxDataViewCtrl::IsSelected( int row ) const
4185{
4186 if( row >= 0 )
4187 return m_clientArea->IsRowSelected(row);
6ff7eee7
RR
4188 return false;
4189}
4190
b7e9f8b1 4191void wxDataViewCtrl::SelectRange( int from, int to )
6ff7eee7 4192{
b7fe2261 4193 wxArrayInt sel;
b7e9f8b1
RR
4194 for( int i = from; i < to; i ++ )
4195 sel.Add( i );
4196 m_clientArea->Select(sel);
4197}
df387169 4198
b7e9f8b1
RR
4199void wxDataViewCtrl::UnselectRange( int from, int to )
4200{
4201 wxDataViewSelection sel = m_clientArea->GetSelections();
4202 for( int i = from; i < to; i ++ )
4203 if( sel.Index( i ) != wxNOT_FOUND )
4204 sel.Remove( i );
4205 m_clientArea->SetSelections(sel);
6ff7eee7
RR
4206}
4207
b7e9f8b1 4208void wxDataViewCtrl::SelectAll()
6ff7eee7 4209{
b7e9f8b1
RR
4210 m_clientArea->SelectAllRows(true);
4211}
df387169 4212
b7e9f8b1
RR
4213void wxDataViewCtrl::UnselectAll()
4214{
4215 m_clientArea->SelectAllRows(false);
6ff7eee7 4216}
b7e9f8b1 4217
fbda518c 4218void wxDataViewCtrl::EnsureVisible( int row, int column )
b7e9f8b1 4219{
fbda518c
RR
4220 if( row < 0 )
4221 row = 0;
67be459b 4222 if( row > (int) m_clientArea->GetRowCount() )
fbda518c
RR
4223 row = m_clientArea->GetRowCount();
4224
4225 int first = m_clientArea->GetFirstVisibleRow();
4226 int last = m_clientArea->GetLastVisibleRow();
4227 if( row < first )
4228 m_clientArea->ScrollTo( row, column );
4229 else if( row > last )
4230 m_clientArea->ScrollTo( row - last + first, column );
4231 else
4232 m_clientArea->ScrollTo( first, column );
b7e9f8b1
RR
4233}
4234
fbda518c 4235void wxDataViewCtrl::EnsureVisible( const wxDataViewItem & item, const wxDataViewColumn * column )
b7e9f8b1
RR
4236{
4237 int row = m_clientArea->GetRowByItem(item);
4238 if( row >= 0 )
fbda518c
RR
4239 {
4240 if( column == NULL )
9bcc8016 4241 EnsureVisible(row, -1);
fbda518c 4242 else
b7fe2261 4243 {
fbda518c
RR
4244 int col = 0;
4245 int len = GetColumnCount();
4246 for( int i = 0; i < len; i ++ )
4247 if( GetColumn(i) == column )
4248 {
4249 col = i;
4250 break;
4251 }
4252 EnsureVisible( row, col );
4253 }
4254 }
b7fe2261 4255
b7e9f8b1
RR
4256}
4257
a87b466d 4258void wxDataViewCtrl::HitTest( const wxPoint & point, wxDataViewItem & item, wxDataViewColumn* &column ) const
66e09788
RR
4259{
4260 m_clientArea->HitTest(point, item, column);
4261}
4262
fbda518c 4263wxRect wxDataViewCtrl::GetItemRect( const wxDataViewItem & item, const wxDataViewColumn* column ) const
66e09788
RR
4264{
4265 return m_clientArea->GetItemRect(item, column);
4266}
4267
b7e9f8b1
RR
4268wxDataViewItem wxDataViewCtrl::GetItemByRow( unsigned int row ) const
4269{
4270 return m_clientArea->GetItemByRow( row );
4271}
4272
4273int wxDataViewCtrl::GetRowByItem( const wxDataViewItem & item ) const
4274{
4275 return m_clientArea->GetRowByItem( item );
4276}
4277
afebb87b
RR
4278void wxDataViewCtrl::Expand( const wxDataViewItem & item )
4279{
4280 int row = m_clientArea->GetRowByItem( item );
4281 if (row != -1)
4282 m_clientArea->Expand(row);
4283}
4284
4285void wxDataViewCtrl::Collapse( const wxDataViewItem & item )
4286{
4287 int row = m_clientArea->GetRowByItem( item );
4288 if (row != -1)
b7fe2261 4289 m_clientArea->Collapse(row);
afebb87b
RR
4290}
4291
b7e9f8b1 4292 #endif
4ed7af08
RR
4293 // !wxUSE_GENERICDATAVIEWCTRL
4294
f554a14b 4295#endif
4ed7af08 4296 // wxUSE_DATAVIEWCTRL