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