]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
fix unused parameter warning in OnIdle()
[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
87f0efe2 5// Modified by: Francesco Montorsi, Guru Kathiresan, Otto Wyss
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"
4ed7af08 45
4ed7af08
RR
46//-----------------------------------------------------------------------------
47// classes
48//-----------------------------------------------------------------------------
49
50class wxDataViewCtrl;
51
9861f022
RR
52static const int SCROLL_UNIT_X = 15;
53
54// the cell padding on the left/right
55static const int PADDING_RIGHTLEFT = 3;
56
57// the cell padding on the top/bottom
58static const int PADDING_TOPBOTTOM = 1;
59
3b6280be
RR
60// the expander space margin
61static const int EXPANDER_MARGIN = 4;
9861f022 62
aba9bfd0
RR
63bool operator == ( const wxDataViewItem & left, const wxDataViewItem & right )
64{
65 return left.GetID() == right.GetID();
66}
67
a0f3af5f
RR
68//-----------------------------------------------------------------------------
69// wxDataViewHeaderWindow
70//-----------------------------------------------------------------------------
4ed7af08 71
87f0efe2
RR
72#define USE_NATIVE_HEADER_WINDOW 1
73
c741d33f
VZ
74// NB: for some reason, this class must be dllexport'ed or we get warnings from
75// MSVC in DLL build
76class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase : public wxControl
87f0efe2
RR
77{
78public:
79 wxDataViewHeaderWindowBase()
80 { m_owner = NULL; }
81
82 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 83 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
84 const wxString &name)
85 {
86 return wxWindow::Create(parent, id, pos, size, wxNO_BORDER, name);
87 }
88
89 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
90 wxDataViewCtrl *GetOwner() { return m_owner; }
91
92 // called on column addition/removal
93 virtual void UpdateDisplay() { /* by default, do nothing */ }
94
87f0efe2 95 // returns the n-th column
9861f022 96 virtual wxDataViewColumn *GetColumn(unsigned int n)
87f0efe2
RR
97 {
98 wxASSERT(m_owner);
c741d33f 99 wxDataViewColumn *ret = m_owner->GetColumn(n);
87f0efe2
RR
100 wxASSERT(ret);
101
c741d33f 102 return ret;
87f0efe2
RR
103 }
104
105protected:
106 wxDataViewCtrl *m_owner;
107
108 // sends an event generated from the n-th wxDataViewColumn
109 void SendEvent(wxEventType type, unsigned int n);
110};
111
112// on wxMSW the header window (only that part however) can be made native!
113#if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
114
9861f022 115#define COLUMN_WIDTH_OFFSET 2
87f0efe2
RR
116#define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
117
118class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase
4ed7af08
RR
119{
120public:
87f0efe2
RR
121
122 wxDataViewHeaderWindowMSW( wxDataViewCtrl *parent,
9861f022
RR
123 wxWindowID id,
124 const wxPoint &pos = wxDefaultPosition,
125 const wxSize &size = wxDefaultSize,
126 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 127 {
87f0efe2
RR
128 Create(parent, id, pos, size, name);
129 }
4ed7af08 130
87f0efe2 131 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 132 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
133 const wxString &name);
134
135 ~wxDataViewHeaderWindowMSW();
136
9861f022
RR
137 // called when any column setting is changed and/or changed
138 // the column count
87f0efe2
RR
139 virtual void UpdateDisplay();
140
141 // called when the main window gets scrolled
142 virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL);
143
144protected:
145 virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
9861f022
RR
146 virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags);
147
148 unsigned int GetColumnIdxFromHeader(NMHEADER *nmHDR);
149
150 wxDataViewColumn *GetColumnFromHeader(NMHEADER *nmHDR)
151 { return GetColumn(GetColumnIdxFromHeader(nmHDR)); }
152
87f0efe2
RR
153private:
154 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW)
155};
156
157#else // !defined(__WXMSW__)
158
159#define HEADER_WINDOW_HEIGHT 25
9861f022
RR
160#define HEADER_HORIZ_BORDER 5
161#define HEADER_VERT_BORDER 3
87f0efe2
RR
162#define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
163
164class wxGenericDataViewHeaderWindow : public wxDataViewHeaderWindowBase
165{
166public:
167 wxGenericDataViewHeaderWindow( wxDataViewCtrl *parent,
168 wxWindowID id,
169 const wxPoint &pos = wxDefaultPosition,
170 const wxSize &size = wxDefaultSize,
171 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 172 {
87f0efe2
RR
173 Init();
174 Create(parent, id, pos, size, name);
175 }
176
177 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 178 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
179 const wxString &name);
180
181 ~wxGenericDataViewHeaderWindow()
182 {
183 delete m_resizeCursor;
184 }
185
c3112d56
RR
186 virtual void UpdateDisplay() { Refresh(); }
187
87f0efe2 188 // event handlers:
4ed7af08 189
a0f3af5f
RR
190 void OnPaint( wxPaintEvent &event );
191 void OnMouse( wxMouseEvent &event );
192 void OnSetFocus( wxFocusEvent &event );
f554a14b 193
87f0efe2
RR
194
195protected:
196
197 // vars used for column resizing:
198
a0f3af5f 199 wxCursor *m_resizeCursor;
87f0efe2
RR
200 const wxCursor *m_currentCursor;
201 bool m_isDragging;
202
203 bool m_dirty; // needs refresh?
204 int m_column; // index of the column being resized
205 int m_currentX; // divider line position in logical (unscrolled) coords
c741d33f 206 int m_minX; // minimal position beyond which the divider line
87f0efe2
RR
207 // can't be dragged in logical coords
208
9861f022
RR
209 // the pen used to draw the current column width drag line
210 // when resizing the columsn
211 wxPen m_penCurrent;
212
213
87f0efe2
RR
214 // internal utilities:
215
216 void Init()
217 {
218 m_currentCursor = (wxCursor *) NULL;
219 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
220
221 m_isDragging = false;
222 m_dirty = false;
223
224 m_column = wxNOT_FOUND;
225 m_currentX = 0;
226 m_minX = 0;
9861f022
RR
227
228 wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
229 m_penCurrent = wxPen(col, 1, wxSOLID);
87f0efe2
RR
230 }
231
232 void DrawCurrent();
233 void AdjustDC(wxDC& dc);
f554a14b 234
a0f3af5f 235private:
87f0efe2 236 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow)
a0f3af5f
RR
237 DECLARE_EVENT_TABLE()
238};
4ed7af08 239
87f0efe2
RR
240#endif // defined(__WXMSW__)
241
0fcce6b9
RR
242//-----------------------------------------------------------------------------
243// wxDataViewRenameTimer
244//-----------------------------------------------------------------------------
245
246class wxDataViewRenameTimer: public wxTimer
247{
248private:
249 wxDataViewMainWindow *m_owner;
250
251public:
252 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
253 void Notify();
254};
255
aba9bfd0
RR
256//-----------------------------------------------------------------------------
257// wxDataViewTreeNode
258//-----------------------------------------------------------------------------
259class wxDataViewTreeNode;
260WX_DEFINE_ARRAY_PTR( wxDataViewTreeNode *, wxDataViewTreeNodes );
261
262class wxDataViewTreeNode
263{
264public:
265 wxDataViewTreeNode( wxDataViewTreeNode * parent )
266 { this->parent = parent;
267 if( parent == NULL )
268 open = true;
269 else
270 open = false;
271 }
272 //I don't know what I need to do in the destructure
273 ~wxDataViewTreeNode()
274 { }
275
276 wxDataViewTreeNode * GetParent() { return parent; }
277 void SetParent( wxDataViewTreeNode * parent ) { this->parent = parent; }
278 wxDataViewTreeNodes GetChildren() { return children; }
279 void SetChildren( wxDataViewTreeNodes children ) { this->children = children; }
280
281 wxDataViewTreeNode * GetChild( unsigned int n ) { return children.Item( n ); }
282 void InsertChild( wxDataViewTreeNode * child, unsigned int n) { children.Insert( child, n); }
283 void AppendChild( wxDataViewTreeNode * child ) { children.Add( child ); }
284
285 wxDataViewItem & GetItem() { return item; }
286 void SetItem( wxDataViewItem & item ) { this->item = item; }
287
288 unsigned int GetChildrenNumber() { return children.GetCount(); }
3b6280be
RR
289 int GetIndentLevel()
290 {
291 int ret = 0 ;
292 wxDataViewTreeNode * node = this;
293 while( node->GetParent()->GetParent() != NULL )
294 {
295 node = node->GetParent();
296 ret ++;
297 }
298 return ret;
299 }
aba9bfd0
RR
300
301 bool IsOpen() { return open; }
3b6280be 302 void ToggleOpen(){ open = !open; }
aba9bfd0
RR
303 bool HasChildren() { return children.GetCount() != 0; }
304private:
305 wxDataViewTreeNode * parent;
306 wxDataViewTreeNodes children;
307 wxDataViewItem item;
308 bool open;
309};
310
a0f3af5f
RR
311//-----------------------------------------------------------------------------
312// wxDataViewMainWindow
313//-----------------------------------------------------------------------------
4ed7af08 314
c741d33f 315WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection,
87f0efe2 316 WXDLLIMPEXP_ADV);
cab07038 317
a0f3af5f 318class wxDataViewMainWindow: public wxWindow
4ed7af08 319{
a0f3af5f
RR
320public:
321 wxDataViewMainWindow( wxDataViewCtrl *parent,
322 wxWindowID id,
323 const wxPoint &pos = wxDefaultPosition,
324 const wxSize &size = wxDefaultSize,
325 const wxString &name = wxT("wxdataviewctrlmainwindow") );
d3c7fc99 326 virtual ~wxDataViewMainWindow();
4ed7af08 327
aba9bfd0
RR
328 // notifications from wxDataViewModel
329 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
330 bool ItemDeleted( const wxDataViewItem &item );
331 bool ItemChanged( const wxDataViewItem &item );
332 bool ValueChanged( const wxDataViewItem &item, unsigned int col );
a0f3af5f 333 bool Cleared();
4ed7af08 334
a0f3af5f
RR
335 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
336 wxDataViewCtrl *GetOwner() { return m_owner; }
9861f022 337 const wxDataViewCtrl *GetOwner() const { return m_owner; }
4ed7af08 338
a0f3af5f 339 void OnPaint( wxPaintEvent &event );
0a71f9e9 340 void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event);
cab07038 341 void OnChar( wxKeyEvent &event );
a0f3af5f
RR
342 void OnMouse( wxMouseEvent &event );
343 void OnSetFocus( wxFocusEvent &event );
cab07038 344 void OnKillFocus( wxFocusEvent &event );
f554a14b 345
a0f3af5f
RR
346 void UpdateDisplay();
347 void RecalculateDisplay();
348 void OnInternalIdle();
f554a14b 349
0fcce6b9 350 void OnRenameTimer();
0fcce6b9 351
9861f022 352 void ScrollWindow( int dx, int dy, const wxRect *rect = NULL );
120b9b05 353
0a71f9e9
RR
354 bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; }
355 void ChangeCurrentRow( unsigned int row );
120b9b05 356
47b378bd 357 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }
cab07038 358 bool IsEmpty() { return GetRowCount() == 0; }
120b9b05 359
9861f022
RR
360 int GetCountPerPage() const;
361 int GetEndOfLastCol() const;
362 unsigned int GetFirstVisibleRow() const;
3b6280be
RR
363 //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
364 unsigned int GetLastVisibleRow();
365 unsigned int GetRowCount() ;
120b9b05 366
87f0efe2 367 void Select( const wxArrayInt& aSelections );
cab07038 368 void SelectAllRows( bool on );
0a71f9e9
RR
369 void SelectRow( unsigned int row, bool on );
370 void SelectRows( unsigned int from, unsigned int to, bool on );
371 void ReverseRowSelection( unsigned int row );
372 bool IsRowSelected( unsigned int row );
120b9b05 373
0a71f9e9
RR
374 void RefreshRow( unsigned int row );
375 void RefreshRows( unsigned int from, unsigned int to );
376 void RefreshRowsAfter( unsigned int firstRow );
120b9b05 377
9861f022
RR
378 // returns the colour to be used for drawing the rules
379 wxColour GetRuleColour() const
380 {
381 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
382 }
383
384 //void EnsureVisible( unsigned int row );
385 wxRect GetLineRect( unsigned int row ) const;
386
aba9bfd0
RR
387 //Some useful functions for row and item mapping
388 wxDataViewItem GetItemByRow( unsigned int row );
389 unsigned int GetRowByItem( const wxDataViewItem & item );
390
391 //Methods for building the mapping tree
392 void BuildTree( wxDataViewModel * model );
393 void DestroyTree();
3b6280be
RR
394private:
395 wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row );
396 wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item ) { return NULL; }
397
398 int RecalculateCount() ;
399
400 void OnExpanding( unsigned int row );
401 void OnCollapsing( unsigned int row );
aba9bfd0 402
a0f3af5f 403private:
0fcce6b9
RR
404 wxDataViewCtrl *m_owner;
405 int m_lineHeight;
406 bool m_dirty;
120b9b05 407
0fcce6b9 408 wxDataViewColumn *m_currentCol;
99d471a5 409 unsigned int m_currentRow;
cab07038 410 wxDataViewSelection m_selection;
120b9b05 411
0fcce6b9 412 wxDataViewRenameTimer *m_renameTimer;
0fcce6b9 413 bool m_lastOnSame;
f554a14b 414
cab07038
RR
415 bool m_hasFocus;
416
e21f75bd
RR
417 int m_dragCount;
418 wxPoint m_dragStart;
419
420 // for double click logic
0a71f9e9 421 unsigned int m_lineLastClicked,
e21f75bd
RR
422 m_lineBeforeLastClicked,
423 m_lineSelectSingleOnUp;
cab07038 424
9861f022
RR
425 // the pen used to draw horiz/vertical rules
426 wxPen m_penRule;
427
3b6280be
RR
428 // the pen used to draw the expander and the lines
429 wxPen m_penExpander;
430
aba9bfd0
RR
431 //This is the tree structure of the model
432 wxDataViewTreeNode * m_root;
3b6280be 433 int m_count;
a0f3af5f
RR
434private:
435 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
436 DECLARE_EVENT_TABLE()
437};
4ed7af08 438
f554a14b 439// ---------------------------------------------------------
aba9bfd0 440// wxGenericDataViewModelNotifier
f554a14b 441// ---------------------------------------------------------
a0f3af5f 442
aba9bfd0 443class wxGenericDataViewModelNotifier: public wxDataViewModelNotifier
4ed7af08 444{
a0f3af5f 445public:
aba9bfd0 446 wxGenericDataViewModelNotifier( wxDataViewMainWindow *mainWindow )
a0f3af5f 447 { m_mainWindow = mainWindow; }
f554a14b 448
aba9bfd0
RR
449 virtual bool ItemAdded( const wxDataViewItem & parent, const wxDataViewItem & item )
450 { return m_mainWindow->ItemAdded( parent , item ); }
451 virtual bool ItemDeleted( const wxDataViewItem & item )
452 { return m_mainWindow->ItemDeleted( item ); }
453 virtual bool ItemChanged( const wxDataViewItem & item )
454 { return m_mainWindow->ItemChanged(item); }
455 virtual bool ValueChanged( const wxDataViewItem & item , unsigned int col )
456 { return m_mainWindow->ValueChanged( item, col ); }
a0f3af5f
RR
457 virtual bool Cleared()
458 { return m_mainWindow->Cleared(); }
f554a14b 459
a0f3af5f
RR
460 wxDataViewMainWindow *m_mainWindow;
461};
4ed7af08 462
f554a14b 463// ---------------------------------------------------------
baa9ebc4 464// wxDataViewRenderer
f554a14b 465// ---------------------------------------------------------
4ed7af08 466
baa9ebc4 467IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
4ed7af08 468
c741d33f 469wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype,
9861f022
RR
470 wxDataViewCellMode mode,
471 int align) :
472 wxDataViewRendererBase( varianttype, mode, align )
4ed7af08 473{
3d9d7cc4 474 m_dc = NULL;
9861f022
RR
475 m_align = align;
476 m_mode = mode;
4ed7af08
RR
477}
478
baa9ebc4 479wxDataViewRenderer::~wxDataViewRenderer()
3d9d7cc4
RR
480{
481 if (m_dc)
482 delete m_dc;
483}
484
baa9ebc4 485wxDC *wxDataViewRenderer::GetDC()
3d9d7cc4
RR
486{
487 if (m_dc == NULL)
488 {
489 if (GetOwner() == NULL)
490 return NULL;
491 if (GetOwner()->GetOwner() == NULL)
492 return NULL;
493 m_dc = new wxClientDC( GetOwner()->GetOwner() );
494 }
f554a14b 495
3d9d7cc4
RR
496 return m_dc;
497}
498
f554a14b 499// ---------------------------------------------------------
baa9ebc4 500// wxDataViewCustomRenderer
f554a14b 501// ---------------------------------------------------------
3d9d7cc4 502
baa9ebc4 503IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
3d9d7cc4 504
baa9ebc4 505wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
9861f022
RR
506 wxDataViewCellMode mode, int align ) :
507 wxDataViewRenderer( varianttype, mode, align )
3d9d7cc4
RR
508{
509}
510
f554a14b 511// ---------------------------------------------------------
baa9ebc4 512// wxDataViewTextRenderer
f554a14b 513// ---------------------------------------------------------
4ed7af08 514
baa9ebc4 515IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer)
4ed7af08 516
c741d33f 517wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype,
9861f022
RR
518 wxDataViewCellMode mode, int align ) :
519 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
520{
521}
522
baa9ebc4 523bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
4ed7af08 524{
90675b95 525 m_text = value.GetString();
f554a14b 526
90675b95 527 return true;
4ed7af08
RR
528}
529
9861f022 530bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
4ed7af08
RR
531{
532 return false;
533}
534
99d471a5
RR
535bool wxDataViewTextRenderer::HasEditorCtrl()
536{
537 return true;
538}
539
540wxControl* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow *parent,
541 wxRect labelRect, const wxVariant &value )
542{
543 return new wxTextCtrl( parent, wxID_ANY, value,
544 wxPoint(labelRect.x,labelRect.y),
545 wxSize(labelRect.width,labelRect.height) );
546}
547
548bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl *editor, wxVariant &value )
549{
550 wxTextCtrl *text = (wxTextCtrl*) editor;
551 value = text->GetValue();
552 return true;
553}
554
87f0efe2 555bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int state )
3d9d7cc4 556{
87f0efe2
RR
557 wxDataViewCtrl *view = GetOwner()->GetOwner();
558 wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ?
559 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) :
560 view->GetForegroundColour();
561
562 dc->SetTextForeground(col);
90675b95
RR
563 dc->DrawText( m_text, cell.x, cell.y );
564
565 return true;
3d9d7cc4
RR
566}
567
9861f022 568wxSize wxDataViewTextRenderer::GetSize() const
3d9d7cc4 569{
9861f022 570 const wxDataViewCtrl *view = GetView();
87f0efe2
RR
571 if (!m_text.empty())
572 {
573 int x,y;
574 view->GetTextExtent( m_text, &x, &y );
575 return wxSize( x, y );
576 }
3d9d7cc4
RR
577 return wxSize(80,20);
578}
579
2586d4a1 580// ---------------------------------------------------------
baa9ebc4 581// wxDataViewBitmapRenderer
2586d4a1
RR
582// ---------------------------------------------------------
583
baa9ebc4 584IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer)
2586d4a1 585
c741d33f 586wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype,
9861f022
RR
587 wxDataViewCellMode mode, int align ) :
588 wxDataViewCustomRenderer( varianttype, mode, align )
2586d4a1
RR
589{
590}
591
baa9ebc4 592bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
2586d4a1
RR
593{
594 if (value.GetType() == wxT("wxBitmap"))
595 m_bitmap << value;
596 if (value.GetType() == wxT("wxIcon"))
597 m_icon << value;
598
599 return true;
600}
601
9861f022 602bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
2586d4a1
RR
603{
604 return false;
605}
606
baa9ebc4 607bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2586d4a1
RR
608{
609 if (m_bitmap.Ok())
610 dc->DrawBitmap( m_bitmap, cell.x, cell.y );
611 else if (m_icon.Ok())
612 dc->DrawIcon( m_icon, cell.x, cell.y );
613
614 return true;
615}
616
9861f022 617wxSize wxDataViewBitmapRenderer::GetSize() const
2586d4a1
RR
618{
619 if (m_bitmap.Ok())
620 return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() );
621 else if (m_icon.Ok())
622 return wxSize( m_icon.GetWidth(), m_icon.GetHeight() );
623
624 return wxSize(16,16);
625}
626
f554a14b 627// ---------------------------------------------------------
baa9ebc4 628// wxDataViewToggleRenderer
f554a14b 629// ---------------------------------------------------------
4ed7af08 630
baa9ebc4 631IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer)
4ed7af08 632
baa9ebc4 633wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
9861f022
RR
634 wxDataViewCellMode mode, int align ) :
635 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08 636{
90675b95 637 m_toggle = false;
4ed7af08
RR
638}
639
baa9ebc4 640bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
4ed7af08 641{
90675b95 642 m_toggle = value.GetBool();
f554a14b 643
a8461d31 644 return true;
4ed7af08
RR
645}
646
9861f022 647bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
4ed7af08
RR
648{
649 return false;
650}
f554a14b 651
baa9ebc4 652bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08 653{
90675b95 654 // User wxRenderer here
f554a14b 655
90675b95
RR
656 wxRect rect;
657 rect.x = cell.x + cell.width/2 - 10;
658 rect.width = 20;
659 rect.y = cell.y + cell.height/2 - 10;
660 rect.height = 20;
120b9b05 661
862d8041 662 int flags = 0;
90675b95 663 if (m_toggle)
862d8041
RR
664 flags |= wxCONTROL_CHECKED;
665 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
666 flags |= wxCONTROL_DISABLED;
667
90b903c2 668 wxRendererNative::Get().DrawCheckBox(
862d8041
RR
669 GetOwner()->GetOwner(),
670 *dc,
671 rect,
672 flags );
f554a14b 673
90675b95 674 return true;
4ed7af08
RR
675}
676
c741d33f 677bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell),
aba9bfd0
RR
678 wxDataViewModel *model,
679 const wxDataViewItem & item, unsigned int col)
0fdc2321
RR
680{
681 bool value = !m_toggle;
682 wxVariant variant = value;
aba9bfd0
RR
683 model->SetValue( variant, item, col);
684 model->ValueChanged( item, col );
0fdc2321
RR
685 return true;
686}
687
9861f022 688wxSize wxDataViewToggleRenderer::GetSize() const
4ed7af08 689{
3d9d7cc4 690 return wxSize(20,20);
4ed7af08
RR
691}
692
f554a14b 693// ---------------------------------------------------------
baa9ebc4 694// wxDataViewProgressRenderer
f554a14b 695// ---------------------------------------------------------
4ed7af08 696
baa9ebc4 697IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
4ed7af08 698
baa9ebc4 699wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
9861f022
RR
700 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
701 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
702{
703 m_label = label;
704 m_value = 0;
705}
706
baa9ebc4 707wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
4ed7af08
RR
708{
709}
710
baa9ebc4 711bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
712{
713 m_value = (long) value;
f554a14b 714
4ed7af08
RR
715 if (m_value < 0) m_value = 0;
716 if (m_value > 100) m_value = 100;
f554a14b 717
4ed7af08
RR
718 return true;
719}
f554a14b 720
9861f022
RR
721bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
722{
723 value = (long) m_value;
724 return true;
725}
726
baa9ebc4 727bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
728{
729 double pct = (double)m_value / 100.0;
730 wxRect bar = cell;
731 bar.width = (int)(cell.width * pct);
732 dc->SetPen( *wxTRANSPARENT_PEN );
733 dc->SetBrush( *wxBLUE_BRUSH );
734 dc->DrawRectangle( bar );
735
736 dc->SetBrush( *wxTRANSPARENT_BRUSH );
737 dc->SetPen( *wxBLACK_PEN );
738 dc->DrawRectangle( cell );
f554a14b 739
4ed7af08
RR
740 return true;
741}
742
9861f022 743wxSize wxDataViewProgressRenderer::GetSize() const
4ed7af08
RR
744{
745 return wxSize(40,12);
746}
f554a14b
WS
747
748// ---------------------------------------------------------
baa9ebc4 749// wxDataViewDateRenderer
f554a14b 750// ---------------------------------------------------------
4ed7af08 751
21ead767
VZ
752#define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
753
754#if wxUSE_DATE_RENDERER_POPUP
8d0ca292 755
baa9ebc4 756class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
4ed7af08 757{
f554a14b 758public:
baa9ebc4 759 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
aba9bfd0
RR
760 wxDataViewModel *model, const wxDataViewItem & item, unsigned int col) :
761 wxPopupTransientWindow( parent, wxBORDER_SIMPLE ),
762 m_item( item )
4ed7af08
RR
763 {
764 m_model = model;
765 m_col = col;
f554a14b 766 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
4ed7af08
RR
767 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
768 sizer->Add( m_cal, 1, wxGROW );
769 SetSizer( sizer );
770 sizer->Fit( this );
771 }
f554a14b 772
4ed7af08 773 void OnCalendar( wxCalendarEvent &event );
f554a14b 774
4ed7af08 775 wxCalendarCtrl *m_cal;
aba9bfd0 776 wxDataViewModel *m_model;
0a71f9e9 777 unsigned int m_col;
aba9bfd0 778 const wxDataViewItem & m_item;
f554a14b 779
a8461d31
PC
780protected:
781 virtual void OnDismiss()
782 {
783 }
784
4ed7af08
RR
785private:
786 DECLARE_EVENT_TABLE()
787};
788
baa9ebc4
RR
789BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
790 EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar )
4ed7af08
RR
791END_EVENT_TABLE()
792
baa9ebc4 793void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
4ed7af08
RR
794{
795 wxDateTime date = event.GetDate();
796 wxVariant value = date;
aba9bfd0
RR
797 m_model->SetValue( value, m_item, m_col );
798 m_model->ValueChanged( m_item, m_col );
4ed7af08
RR
799 DismissAndNotify();
800}
801
21ead767 802#endif // wxUSE_DATE_RENDERER_POPUP
8d0ca292 803
baa9ebc4 804IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
4ed7af08 805
baa9ebc4 806wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
9861f022
RR
807 wxDataViewCellMode mode, int align ) :
808 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
809{
810}
f554a14b 811
baa9ebc4 812bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
813{
814 m_date = value.GetDateTime();
f554a14b 815
4ed7af08
RR
816 return true;
817}
818
9861f022
RR
819bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const
820{
821 value = m_date;
822 return true;
823}
824
baa9ebc4 825bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
826{
827 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
828 wxString tmp = m_date.FormatDate();
829 dc->DrawText( tmp, cell.x, cell.y );
830
831 return true;
832}
833
9861f022 834wxSize wxDataViewDateRenderer::GetSize() const
4ed7af08 835{
9861f022 836 const wxDataViewCtrl* view = GetView();
4ed7af08
RR
837 wxString tmp = m_date.FormatDate();
838 wxCoord x,y,d;
839 view->GetTextExtent( tmp, &x, &y, &d );
840 return wxSize(x,y+d);
841}
842
aba9bfd0
RR
843bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model,
844 const wxDataViewItem & item, unsigned int col )
4ed7af08
RR
845{
846 wxVariant variant;
aba9bfd0 847 model->GetValue( variant, item, col );
4ed7af08
RR
848 wxDateTime value = variant.GetDateTime();
849
21ead767 850#if wxUSE_DATE_RENDERER_POPUP
baa9ebc4 851 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
aba9bfd0 852 GetOwner()->GetOwner()->GetParent(), &value, model, item, col);
4ed7af08
RR
853 wxPoint pos = wxGetMousePosition();
854 popup->Move( pos );
855 popup->Layout();
856 popup->Popup( popup->m_cal );
21ead767 857#else // !wxUSE_DATE_RENDERER_POPUP
8d0ca292 858 wxMessageBox(value.Format());
21ead767 859#endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
4ed7af08
RR
860 return true;
861}
862
f554a14b 863// ---------------------------------------------------------
4ed7af08 864// wxDataViewColumn
f554a14b 865// ---------------------------------------------------------
4ed7af08
RR
866
867IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
868
c741d33f 869wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
87f0efe2
RR
870 unsigned int model_column,
871 int width, wxAlignment align, int flags ) :
872 wxDataViewColumnBase( title, cell, model_column, width, align, flags )
4ed7af08 873{
9861f022
RR
874 SetAlignment(align);
875 SetTitle(title);
876 SetFlags(flags);
877
878 Init(width < 0 ? wxDVC_DEFAULT_WIDTH : width);
4ed7af08
RR
879}
880
c741d33f 881wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
87f0efe2
RR
882 unsigned int model_column,
883 int width, wxAlignment align, int flags ) :
884 wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
07a84e7b 885{
9861f022
RR
886 SetAlignment(align);
887 SetFlags(flags);
888
889 Init(width < 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH : width);
07a84e7b
RR
890}
891
9861f022
RR
892wxDataViewColumn::~wxDataViewColumn()
893{
894}
895
896void wxDataViewColumn::Init( int width )
47cef10f 897{
87f0efe2 898 m_width = width;
9861f022 899 m_minWidth = wxDVC_DEFAULT_MINWIDTH;
c3112d56 900 m_ascending = true;
47cef10f
RR
901}
902
9861f022 903void wxDataViewColumn::SetResizeable( bool resizeable )
31fb32e1 904{
9861f022
RR
905 if (resizeable)
906 m_flags |= wxDATAVIEW_COL_RESIZABLE;
907 else
908 m_flags &= ~wxDATAVIEW_COL_RESIZABLE;
909}
910
911void wxDataViewColumn::SetHidden( bool hidden )
912{
913 if (hidden)
914 m_flags |= wxDATAVIEW_COL_HIDDEN;
915 else
916 m_flags &= ~wxDATAVIEW_COL_HIDDEN;
917
918 // tell our owner to e.g. update its scrollbars:
919 if (GetOwner())
920 GetOwner()->OnColumnChange();
921}
922
923void wxDataViewColumn::SetSortable( bool sortable )
924{
925 if (sortable)
926 m_flags |= wxDATAVIEW_COL_SORTABLE;
927 else
928 m_flags &= ~wxDATAVIEW_COL_SORTABLE;
c3112d56
RR
929
930 // Update header button
931 if (GetOwner())
932 GetOwner()->OnColumnChange();
31fb32e1
RR
933}
934
c3112d56 935void wxDataViewColumn::SetSortOrder( bool ascending )
47cef10f 936{
c3112d56
RR
937 m_ascending = ascending;
938
939 // Update header button
940 if (GetOwner())
941 GetOwner()->OnColumnChange();
47cef10f
RR
942}
943
87f0efe2 944bool wxDataViewColumn::IsSortOrderAscending() const
31fb32e1 945{
c3112d56 946 return m_ascending;
31fb32e1
RR
947}
948
9861f022 949void wxDataViewColumn::SetInternalWidth( int width )
4ed7af08 950{
9861f022 951 m_width = width;
f554a14b 952
9861f022
RR
953 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
954 if (m_owner && m_owner->m_clientArea)
955 m_owner->m_clientArea->RecalculateDisplay();
4ed7af08
RR
956}
957
9861f022 958void wxDataViewColumn::SetWidth( int width )
47cef10f 959{
9861f022 960 m_owner->m_headerArea->UpdateDisplay();
47cef10f 961
9861f022 962 SetInternalWidth(width);
47cef10f
RR
963}
964
533544f2 965
4ed7af08 966//-----------------------------------------------------------------------------
87f0efe2 967// wxDataViewHeaderWindowBase
4ed7af08
RR
968//-----------------------------------------------------------------------------
969
87f0efe2
RR
970void wxDataViewHeaderWindowBase::SendEvent(wxEventType type, unsigned int n)
971{
972 wxWindow *parent = GetParent();
973 wxDataViewEvent le(type, parent->GetId());
974
975 le.SetEventObject(parent);
976 le.SetColumn(n);
977 le.SetDataViewColumn(GetColumn(n));
978 le.SetModel(GetOwner()->GetModel());
979
980 // for events created by wxDataViewHeaderWindow the
981 // row / value fields are not valid
982
983 parent->GetEventHandler()->ProcessEvent(le);
984}
985
986#if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
987
87f0efe2 988// implemented in msw/listctrl.cpp:
a68962fc 989int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
87f0efe2 990
5d3f234b 991IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW, wxWindow)
87f0efe2
RR
992
993bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl *parent, wxWindowID id,
c741d33f 994 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
995 const wxString &name )
996{
997 m_owner = parent;
998
999 if ( !CreateControl(parent, id, pos, size, 0, wxDefaultValidator, name) )
1000 return false;
1001
1002 int x = pos.x == wxDefaultCoord ? 0 : pos.x,
1003 y = pos.y == wxDefaultCoord ? 0 : pos.y,
1004 w = size.x == wxDefaultCoord ? 1 : size.x,
1005 h = size.y == wxDefaultCoord ? 22 : size.y;
1006
1007 // create the native WC_HEADER window:
1008 WXHWND hwndParent = (HWND)parent->GetHandle();
1009 WXDWORD msStyle = WS_CHILD | HDS_BUTTONS | HDS_HORZ | HDS_HOTTRACK | HDS_FULLDRAG;
c741d33f
VZ
1010 m_hWnd = CreateWindowEx(0,
1011 WC_HEADER,
1012 (LPCTSTR) NULL,
87f0efe2
RR
1013 msStyle,
1014 x, y, w, h,
c741d33f
VZ
1015 (HWND)hwndParent,
1016 (HMENU)-1,
1017 wxGetInstance(),
87f0efe2 1018 (LPVOID) NULL);
c741d33f 1019 if (m_hWnd == NULL)
87f0efe2
RR
1020 {
1021 wxLogLastError(_T("CreateWindowEx"));
1022 return false;
1023 }
1024
5d3f234b 1025 // we need to subclass the m_hWnd to force wxWindow::HandleNotify
87f0efe2 1026 // to call wxDataViewHeaderWindow::MSWOnNotify
5d3f234b 1027 SubclassWin(m_hWnd);
87f0efe2 1028
c741d33f 1029 // the following is required to get the default win's font for
9861f022
RR
1030 // header windows and must be done befor sending the HDM_LAYOUT msg
1031 SetFont(GetFont());
87f0efe2 1032
9861f022
RR
1033 RECT rcParent;
1034 HDLAYOUT hdl;
1035 WINDOWPOS wp;
87f0efe2 1036
c741d33f
VZ
1037 // Retrieve the bounding rectangle of the parent window's
1038 // client area, and then request size and position values
1039 // from the header control.
1040 ::GetClientRect((HWND)hwndParent, &rcParent);
1041
1042 hdl.prc = &rcParent;
1043 hdl.pwpos = &wp;
1044 if (!SendMessage((HWND)m_hWnd, HDM_LAYOUT, 0, (LPARAM) &hdl))
87f0efe2
RR
1045 {
1046 wxLogLastError(_T("SendMessage"));
1047 return false;
1048 }
c741d33f
VZ
1049
1050 // Set the size, position, and visibility of the header control.
1051 SetWindowPos((HWND)m_hWnd,
1052 wp.hwndInsertAfter,
1053 wp.x, wp.y,
1054 wp.cx, wp.cy,
87f0efe2
RR
1055 wp.flags | SWP_SHOWWINDOW);
1056
1057 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1058 // a wxBoxSizer and in order to avoid super-big header windows,
1059 // we need to set our height as fixed
1060 SetMinSize(wxSize(-1, wp.cy));
1061 SetMaxSize(wxSize(-1, wp.cy));
1062
87f0efe2
RR
1063 return true;
1064}
1065
1066wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow()
1067{
5d3f234b 1068 UnsubclassWin();
87f0efe2
RR
1069}
1070
1071void wxDataViewHeaderWindowMSW::UpdateDisplay()
1072{
1073 // remove old columns
914e6945 1074 for (int j=0, max=Header_GetItemCount((HWND)m_hWnd); j < max; j++)
87f0efe2 1075 Header_DeleteItem((HWND)m_hWnd, 0);
c741d33f 1076
87f0efe2 1077 // add the updated array of columns to the header control
9861f022
RR
1078 unsigned int cols = GetOwner()->GetColumnCount();
1079 unsigned int added = 0;
87f0efe2
RR
1080 for (unsigned int i = 0; i < cols; i++)
1081 {
1082 wxDataViewColumn *col = GetColumn( i );
1083 if (col->IsHidden())
1084 continue; // don't add it!
1085
1086 HDITEM hdi;
1087 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
fab3f50e 1088 hdi.pszText = (wxChar *) col->GetTitle().wx_str();
87f0efe2
RR
1089 hdi.cxy = col->GetWidth();
1090 hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]);
1091 hdi.fmt = HDF_LEFT | HDF_STRING;
9861f022
RR
1092
1093 // lParam is reserved for application's use:
1094 // we store there the column index to use it later in MSWOnNotify
1095 // (since columns may have been hidden)
1096 hdi.lParam = (LPARAM)i;
1097
1098 // the native wxMSW implementation of the header window
c741d33f 1099 // draws the column separator COLUMN_WIDTH_OFFSET pixels
9861f022
RR
1100 // on the right: to correct this effect we make the column
1101 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1102 if (i == 0)
1103 hdi.cxy += COLUMN_WIDTH_OFFSET;
1104
1105 switch (col->GetAlignment())
1106 {
1107 case wxALIGN_LEFT:
1108 hdi.fmt |= HDF_LEFT;
1109 break;
1110 case wxALIGN_CENTER:
1111 case wxALIGN_CENTER_HORIZONTAL:
1112 hdi.fmt |= HDF_CENTER;
1113 break;
1114 case wxALIGN_RIGHT:
1115 hdi.fmt |= HDF_RIGHT;
1116 break;
5d3f234b
RR
1117
1118 default:
1119 // such alignment is not allowed for the column header!
1120 wxFAIL;
9861f022 1121 }
c741d33f
VZ
1122
1123 SendMessage((HWND)m_hWnd, HDM_INSERTITEM,
1124 (WPARAM)added, (LPARAM)&hdi);
9861f022 1125 added++;
87f0efe2
RR
1126 }
1127}
1128
9861f022
RR
1129unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR)
1130{
1131 unsigned int idx;
1132
1133 // NOTE: we don't just return nmHDR->iItem because when there are
1134 // hidden columns, nmHDR->iItem may be different from
1135 // nmHDR->pitem->lParam
1136
1137 if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM)
1138 {
1139 idx = (unsigned int)nmHDR->pitem->lParam;
1140 return idx;
1141 }
1142
1143 HDITEM item;
1144 item.mask = HDI_LPARAM;
1145 Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item);
1146
1147 return (unsigned int)item.lParam;
1148}
1149
87f0efe2
RR
1150bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
1151{
1152 NMHDR *nmhdr = (NMHDR *)lParam;
1153
1154 // is it a message from the header?
1155 if ( nmhdr->hwndFrom != (HWND)m_hWnd )
1156 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1157
1158 NMHEADER *nmHDR = (NMHEADER *)nmhdr;
1159 switch ( nmhdr->code )
1160 {
1161 case HDN_BEGINTRACK:
1162 // user has started to resize a column:
1163 // do we need to veto it?
1164 if (!GetColumn(nmHDR->iItem)->IsResizeable())
1165 {
1166 // veto it!
1167 *result = TRUE;
1168 }
1169 break;
1170
1171 case HDN_BEGINDRAG:
1172 // user has started to reorder a column
1173 break;
1174
9861f022 1175 case HDN_ITEMCHANGING:
c741d33f 1176 if (nmHDR->pitem != NULL &&
9861f022
RR
1177 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1178 {
1179 int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth();
1180 if (nmHDR->pitem->cxy < minWidth)
1181 {
c741d33f 1182 // do not allow the user to resize this column under
9861f022
RR
1183 // its minimal width:
1184 *result = TRUE;
1185 }
1186 }
1187 break;
1188
87f0efe2
RR
1189 case HDN_ITEMCHANGED: // user is resizing a column
1190 case HDN_ENDTRACK: // user has finished resizing a column
1191 case HDN_ENDDRAG: // user has finished reordering a column
1192
1193 // update the width of the modified column:
c741d33f 1194 if (nmHDR->pitem != NULL &&
9861f022
RR
1195 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1196 {
1197 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
1198 unsigned int w = nmHDR->pitem->cxy;
1199 wxDataViewColumn *col = GetColumn(idx);
1200
1201 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1202 if (idx == 0 && w > COLUMN_WIDTH_OFFSET)
1203 w -= COLUMN_WIDTH_OFFSET;
1204
1205 if (w >= (unsigned)col->GetMinWidth())
1206 col->SetInternalWidth(w);
1207 }
87f0efe2
RR
1208 break;
1209
1210 case HDN_ITEMCLICK:
1211 {
9861f022 1212 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
c741d33f 1213 wxEventType evt = nmHDR->iButton == 0 ?
87f0efe2
RR
1214 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1215 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
9861f022 1216 SendEvent(evt, idx);
87f0efe2
RR
1217 }
1218 break;
1219
1220 case NM_RCLICK:
1221 {
1222 // NOTE: for some reason (i.e. for a bug in Windows)
1223 // the HDN_ITEMCLICK notification is not sent on
1224 // right clicks, so we need to handle NM_RCLICK
1225
1226 POINT ptClick;
9861f022 1227 int column = wxMSWGetColumnClicked(nmhdr, &ptClick);
87f0efe2 1228 if (column != wxNOT_FOUND)
9861f022
RR
1229 {
1230 HDITEM item;
1231 item.mask = HDI_LPARAM;
1232 Header_GetItem((HWND)m_hWnd, column, &item);
1233
1234 // 'idx' may be different from 'column' if there are
1235 // hidden columns...
1236 unsigned int idx = (unsigned int)item.lParam;
87f0efe2 1237 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
9861f022
RR
1238 idx);
1239 }
87f0efe2
RR
1240 }
1241 break;
1242
1243 case HDN_GETDISPINFOW:
1244 // see wxListCtrl::MSWOnNotify for more info!
1245 break;
1246
1247 case HDN_ITEMDBLCLICK:
1248 {
9861f022 1249 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
87f0efe2
RR
1250 int w = GetOwner()->GetBestColumnWidth(idx);
1251
1252 // update the native control:
1253 HDITEM hd;
1254 ZeroMemory(&hd, sizeof(hd));
1255 hd.mask = HDI_WIDTH;
1256 hd.cxy = w;
c741d33f 1257 Header_SetItem(GetHwnd(),
9861f022
RR
1258 nmHDR->iItem, // NOTE: we don't want 'idx' here!
1259 &hd);
87f0efe2
RR
1260
1261 // update the wxDataViewColumn class:
9861f022 1262 GetColumn(idx)->SetInternalWidth(w);
87f0efe2
RR
1263 }
1264 break;
1265
1266 default:
1267 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1268 }
1269
1270 return true;
1271}
1272
c741d33f 1273void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx), int WXUNUSED(dy),
87f0efe2
RR
1274 const wxRect *WXUNUSED(rect))
1275{
1276 wxSize ourSz = GetClientSize();
1277 wxSize ownerSz = m_owner->GetClientSize();
1278
1279 // where should the (logical) origin of this window be placed?
1280 int x1 = 0, y1 = 0;
1281 m_owner->CalcUnscrolledPosition(0, 0, &x1, &y1);
4ed7af08 1282
c741d33f
VZ
1283 // put this window on top of our parent and
1284 SetWindowPos((HWND)m_hWnd, HWND_TOP, -x1, 0,
1285 ownerSz.GetWidth() + x1, ourSz.GetHeight(),
87f0efe2
RR
1286 SWP_SHOWWINDOW);
1287}
1288
c741d33f
VZ
1289void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
1290 int WXUNUSED(w), int WXUNUSED(h),
9861f022
RR
1291 int WXUNUSED(f))
1292{
1293 // the wxDataViewCtrl's internal wxBoxSizer will call this function when
1294 // the wxDataViewCtrl window gets resized: the following dummy call
1295 // to ScrollWindow() is required in order to get this header window
1296 // correctly repainted when it's (horizontally) scrolled:
1297
1298 ScrollWindow(0, 0);
1299}
1300
87f0efe2
RR
1301#else // !defined(__WXMSW__)
1302
1303IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow, wxWindow)
1304BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow, wxWindow)
1305 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint)
1306 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse)
1307 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus)
4ed7af08
RR
1308END_EVENT_TABLE()
1309
87f0efe2 1310bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f
VZ
1311 const wxPoint &pos, const wxSize &size,
1312 const wxString &name )
4ed7af08 1313{
87f0efe2 1314 m_owner = parent;
4b3feaa7 1315
87f0efe2
RR
1316 if (!wxDataViewHeaderWindowBase::Create(parent, id, pos, size, name))
1317 return false;
f554a14b 1318
4ed7af08 1319 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
2e992e06 1320 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
4ed7af08
RR
1321 SetOwnForegroundColour( attr.colFg );
1322 SetOwnBackgroundColour( attr.colBg );
1323 if (!m_hasFont)
1324 SetOwnFont( attr.font );
4ed7af08 1325
87f0efe2
RR
1326 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1327 // a wxBoxSizer and in order to avoid super-big header windows,
1328 // we need to set our height as fixed
1329 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1330 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1331
1332 return true;
4ed7af08
RR
1333}
1334
87f0efe2 1335void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 1336{
4b3feaa7
RR
1337 int w, h;
1338 GetClientSize( &w, &h );
1339
2e992e06
VZ
1340 wxAutoBufferedPaintDC dc( this );
1341
1342 dc.SetBackground(GetBackgroundColour());
1343 dc.Clear();
f554a14b 1344
4ed7af08
RR
1345 int xpix;
1346 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1347
1348 int x;
1349 m_owner->GetViewStart( &x, NULL );
1350
1351 // account for the horz scrollbar offset
1352 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 1353
4ed7af08 1354 dc.SetFont( GetFont() );
f554a14b 1355
9861f022 1356 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 1357 unsigned int i;
4b3feaa7
RR
1358 int xpos = 0;
1359 for (i = 0; i < cols; i++)
1360 {
87f0efe2
RR
1361 wxDataViewColumn *col = GetColumn( i );
1362 if (col->IsHidden())
9861f022 1363 continue; // skip it!
f554a14b 1364
87f0efe2 1365 int cw = col->GetWidth();
4b3feaa7 1366 int ch = h;
4b3feaa7 1367
c3112d56
RR
1368 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE;
1369 if (col->IsSortable())
1370 {
1371 if (col->IsSortOrderAscending())
1372 sortArrow = wxHDR_SORT_ICON_UP;
1373 else
1374 sortArrow = wxHDR_SORT_ICON_DOWN;
1375 }
1376
4b3feaa7
RR
1377 wxRendererNative::Get().DrawHeaderButton
1378 (
1379 this,
1380 dc,
72664514 1381 wxRect(xpos, 0, cw, ch-1),
4b3feaa7 1382 m_parent->IsEnabled() ? 0
c3112d56
RR
1383 : (int)wxCONTROL_DISABLED,
1384 sortArrow
4b3feaa7
RR
1385 );
1386
9861f022
RR
1387 // align as required the column title:
1388 int x = xpos;
1389 wxSize titleSz = dc.GetTextExtent(col->GetTitle());
1390 switch (col->GetAlignment())
1391 {
1392 case wxALIGN_LEFT:
1393 x += HEADER_HORIZ_BORDER;
1394 break;
1395 case wxALIGN_CENTER:
1396 case wxALIGN_CENTER_HORIZONTAL:
1397 x += (cw - titleSz.GetWidth() - 2 * HEADER_HORIZ_BORDER)/2;
1398 break;
1399 case wxALIGN_RIGHT:
1400 x += cw - titleSz.GetWidth() - HEADER_HORIZ_BORDER;
1401 break;
1402 }
1403
1404 // always center the title vertically:
1405 int y = wxMax((ch - titleSz.GetHeight()) / 2, HEADER_VERT_BORDER);
1406
c741d33f 1407 dc.SetClippingRegion( xpos+HEADER_HORIZ_BORDER,
9861f022
RR
1408 HEADER_VERT_BORDER,
1409 wxMax(cw - 2 * HEADER_HORIZ_BORDER, 1), // width
1410 wxMax(ch - 2 * HEADER_VERT_BORDER, 1)); // height
1411 dc.DrawText( col->GetTitle(), x, y );
1412 dc.DestroyClippingRegion();
f554a14b 1413
87f0efe2 1414 xpos += cw;
4b3feaa7 1415 }
4ed7af08
RR
1416}
1417
87f0efe2 1418void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
4ed7af08 1419{
87f0efe2
RR
1420 GetParent()->SetFocus();
1421 event.Skip();
4ed7af08
RR
1422}
1423
87f0efe2 1424void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event )
4ed7af08 1425{
87f0efe2
RR
1426 // we want to work with logical coords
1427 int x;
1428 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1429 int y = event.GetY();
1430
1431 if (m_isDragging)
1432 {
c741d33f 1433 // we don't draw the line beyond our window,
87f0efe2
RR
1434 // but we allow dragging it there
1435 int w = 0;
1436 GetClientSize( &w, NULL );
1437 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1438 w -= 6;
1439
1440 // erase the line if it was drawn
c741d33f 1441 if (m_currentX < w)
87f0efe2
RR
1442 DrawCurrent();
1443
c741d33f 1444 if (event.ButtonUp())
87f0efe2
RR
1445 {
1446 m_isDragging = false;
c741d33f 1447 if (HasCapture())
87f0efe2
RR
1448 ReleaseMouse();
1449
1450 m_dirty = true;
1451
9861f022 1452 GetColumn(m_column)->SetWidth(m_currentX - m_minX);
87f0efe2
RR
1453
1454 Refresh();
1455 GetOwner()->Refresh();
1456 }
1457 else
1458 {
1459 m_currentX = wxMax(m_minX + 7, x);
1460
1461 // draw in the new location
1462 if (m_currentX < w) DrawCurrent();
1463 }
1464
1465 }
1466 else // not dragging
1467 {
1468 m_minX = 0;
1469 m_column = wxNOT_FOUND;
1470
1471 bool hit_border = false;
1472
1473 // end of the current column
1474 int xpos = 0;
1475
1476 // find the column where this event occured
9861f022 1477 int countCol = m_owner->GetColumnCount();
c741d33f 1478 for (int column = 0; column < countCol; column++)
87f0efe2
RR
1479 {
1480 wxDataViewColumn *p = GetColumn(column);
1481
c741d33f 1482 if (p->IsHidden())
87f0efe2
RR
1483 continue; // skip if not shown
1484
1485 xpos += p->GetWidth();
1486 m_column = column;
c741d33f 1487 if ((abs(x-xpos) < 3) && (y < 22))
87f0efe2
RR
1488 {
1489 hit_border = true;
1490 break;
1491 }
1492
c741d33f 1493 if (x < xpos)
87f0efe2
RR
1494 {
1495 // inside the column
1496 break;
1497 }
1498
1499 m_minX = xpos;
1500 }
1501
1502 if (m_column == wxNOT_FOUND)
1503 return;
1504
1505 bool resizeable = GetColumn(m_column)->IsResizeable();
1506 if (event.LeftDClick() && resizeable)
1507 {
9861f022 1508 GetColumn(m_column)->SetWidth(GetOwner()->GetBestColumnWidth(m_column));
87f0efe2
RR
1509 Refresh();
1510 }
1511 else if (event.LeftDown() || event.RightUp())
1512 {
c741d33f 1513 if (hit_border && event.LeftDown() && resizeable)
87f0efe2
RR
1514 {
1515 m_isDragging = true;
1516 CaptureMouse();
1517 m_currentX = x;
1518 DrawCurrent();
1519 }
1520 else // click on a column
1521 {
c741d33f 1522 wxEventType evt = event.LeftDown() ?
87f0efe2
RR
1523 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1524 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
1525 SendEvent(evt, m_column);
1526 }
1527 }
1528 else if (event.Moving())
1529 {
c741d33f 1530 if (hit_border && resizeable)
87f0efe2
RR
1531 m_currentCursor = m_resizeCursor;
1532 else
1533 m_currentCursor = wxSTANDARD_CURSOR;
1534
1535 SetCursor(*m_currentCursor);
1536 }
1537 }
1538}
1539
1540void wxGenericDataViewHeaderWindow::DrawCurrent()
1541{
1542 int x1 = m_currentX;
1543 int y1 = 0;
1544 ClientToScreen (&x1, &y1);
1545
1546 int x2 = m_currentX-1;
1547#ifdef __WXMSW__
1548 ++x2; // but why ????
1549#endif
1550 int y2 = 0;
1551 m_owner->GetClientSize( NULL, &y2 );
1552 m_owner->ClientToScreen( &x2, &y2 );
1553
1554 wxScreenDC dc;
9861f022
RR
1555 dc.SetLogicalFunction(wxINVERT);
1556 dc.SetPen(m_penCurrent);
1557 dc.SetBrush(*wxTRANSPARENT_BRUSH);
87f0efe2 1558 AdjustDC(dc);
9861f022 1559 dc.DrawLine(x1, y1, x2, y2);
87f0efe2
RR
1560}
1561
1562void wxGenericDataViewHeaderWindow::AdjustDC(wxDC& dc)
1563{
1564 int xpix, x;
1565
1566 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1567 m_owner->GetViewStart( &x, NULL );
1568
1569 // shift the DC origin to match the position of the main window horizontal
1570 // scrollbar: this allows us to always use logical coords
1571 dc.SetDeviceOrigin( -x * xpix, 0 );
4ed7af08
RR
1572}
1573
87f0efe2
RR
1574#endif // defined(__WXMSW__)
1575
0fcce6b9
RR
1576//-----------------------------------------------------------------------------
1577// wxDataViewRenameTimer
1578//-----------------------------------------------------------------------------
1579
1580wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
1581{
1582 m_owner = owner;
1583}
1584
1585void wxDataViewRenameTimer::Notify()
1586{
1587 m_owner->OnRenameTimer();
1588}
1589
4ed7af08
RR
1590//-----------------------------------------------------------------------------
1591// wxDataViewMainWindow
1592//-----------------------------------------------------------------------------
1593
0a71f9e9 1594int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
cab07038
RR
1595{
1596 if (row1 > row2) return 1;
1597 if (row1 == row2) return 0;
1598 return -1;
1599}
1600
1601
45778c96 1602IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
1603
1604BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
1605 EVT_PAINT (wxDataViewMainWindow::OnPaint)
1606 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
1607 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
cab07038
RR
1608 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
1609 EVT_CHAR (wxDataViewMainWindow::OnChar)
4ed7af08
RR
1610END_EVENT_TABLE()
1611
1612wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
1613 const wxPoint &pos, const wxSize &size, const wxString &name ) :
72664514 1614 wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ),
cab07038 1615 m_selection( wxDataViewSelectionCmp )
120b9b05 1616
4ed7af08
RR
1617{
1618 SetOwner( parent );
f554a14b 1619
0fcce6b9
RR
1620 m_lastOnSame = false;
1621 m_renameTimer = new wxDataViewRenameTimer( this );
120b9b05 1622
0fcce6b9
RR
1623 // TODO: user better initial values/nothing selected
1624 m_currentCol = NULL;
1625 m_currentRow = 0;
1626
1627 // TODO: we need to calculate this smartly
c741d33f 1628 m_lineHeight =
87f0efe2
RR
1629#ifdef __WXMSW__
1630 17;
1631#else
1632 20;
1633#endif
9861f022 1634 wxASSERT(m_lineHeight > 2*PADDING_TOPBOTTOM);
e21f75bd
RR
1635
1636 m_dragCount = 0;
1637 m_dragStart = wxPoint(0,0);
0a71f9e9
RR
1638 m_lineLastClicked = (unsigned int) -1;
1639 m_lineBeforeLastClicked = (unsigned int) -1;
1640 m_lineSelectSingleOnUp = (unsigned int) -1;
120b9b05 1641
cab07038 1642 m_hasFocus = false;
f554a14b 1643
2e992e06 1644 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
72664514
RR
1645 SetBackgroundColour( *wxWHITE );
1646
9861f022
RR
1647 m_penRule = wxPen(GetRuleColour(), 1, wxSOLID);
1648
3b6280be
RR
1649 //Here I compose a pen can draw black lines, maybe there are something system colour to use
1650 m_penExpander = wxPen( wxColour(0,0,0), 1, wxSOLID );
aba9bfd0
RR
1651 //Some new added code to deal with the tree structure
1652 m_root = new wxDataViewTreeNode( NULL );
3b6280be
RR
1653 //Make m_count = -1 will cause the class recaculate the real displaying number of rows.
1654 m_count = -1 ;
4b3feaa7 1655 UpdateDisplay();
4ed7af08
RR
1656}
1657
1658wxDataViewMainWindow::~wxDataViewMainWindow()
1659{
aba9bfd0 1660 DestroyTree();
0fcce6b9
RR
1661 delete m_renameTimer;
1662}
1663
1664void wxDataViewMainWindow::OnRenameTimer()
1665{
1666 // We have to call this here because changes may just have
1667 // been made and no screen update taken place.
1668 if ( m_dirty )
1669 wxSafeYield();
1670
0fcce6b9 1671 int xpos = 0;
9861f022 1672 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 1673 unsigned int i;
0fcce6b9
RR
1674 for (i = 0; i < cols; i++)
1675 {
1676 wxDataViewColumn *c = GetOwner()->GetColumn( i );
9861f022
RR
1677 if (c->IsHidden())
1678 continue; // skip it!
1679
0fcce6b9
RR
1680 if (c == m_currentCol)
1681 break;
1682 xpos += c->GetWidth();
1683 }
c741d33f 1684 wxRect labelRect( xpos, m_currentRow * m_lineHeight,
87f0efe2 1685 m_currentCol->GetWidth(), m_lineHeight );
0fcce6b9 1686
1e510b1e
RR
1687 GetOwner()->CalcScrolledPosition( labelRect.x, labelRect.y,
1688 &labelRect.x, &labelRect.y);
1689
99d471a5 1690 m_currentCol->GetRenderer()->StartEditing( m_currentRow, labelRect );
4ed7af08
RR
1691}
1692
aba9bfd0 1693class DoJob
a0f3af5f 1694{
aba9bfd0
RR
1695public:
1696 DoJob(){};
3b6280be 1697 virtual ~DoJob() { }
a0f3af5f 1698
aba9bfd0
RR
1699 virtual bool operator() ( wxDataViewTreeNode * node ) = 0 ;
1700};
1701
1702class ItemAddJob: public DoJob
a0f3af5f 1703{
aba9bfd0
RR
1704public:
1705 ItemAddJob( const wxDataViewItem & parent, const wxDataViewItem & item )
3b6280be
RR
1706 { this->parent = parent ; this->item = item; }
1707 virtual ~ItemAddJob() { }
aba9bfd0
RR
1708
1709 virtual bool operator() ( wxDataViewTreeNode * node )
1710 {
1711 if( node->GetItem() == parent )
1712 {
1713 wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node );
3b6280be
RR
1714 newnode->SetItem(item);
1715 node->AppendChild( newnode);
1716 return true;
aba9bfd0 1717 }
3b6280be 1718 return false;
aba9bfd0 1719 }
3b6280be 1720
aba9bfd0
RR
1721private:
1722 wxDataViewItem parent, item;
1723};
1724
1725bool Walker( wxDataViewTreeNode * node, DoJob & func )
1726{
3b6280be 1727 if( node==NULL || !node->HasChildren())
aba9bfd0
RR
1728 return false;
1729
1730 wxDataViewTreeNodes nodes = node->GetChildren();
1731 int len = node->GetChildrenNumber();
1732 int i = 0 ;
1733 for( ; i < len ; i ++ )
1734 {
1735 wxDataViewTreeNode * n = nodes[i];
1736 if( func( n ) )
1737 return true;
1738 if( Walker( n , func ) )
1739 return true;
1740 }
1741 return false;
a0f3af5f
RR
1742}
1743
aba9bfd0 1744
aba9bfd0 1745bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
a0f3af5f 1746{
aba9bfd0
RR
1747 ItemAddJob job( parent, item);
1748 Walker( m_root , job);
99d471a5
RR
1749 UpdateDisplay();
1750 return true;
a0f3af5f
RR
1751}
1752
aba9bfd0 1753bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem & item)
a0f3af5f 1754{
99d471a5
RR
1755 UpdateDisplay();
1756 return true;
a0f3af5f
RR
1757}
1758
aba9bfd0 1759bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
a0f3af5f 1760{
99d471a5
RR
1761 UpdateDisplay();
1762 return true;
a0f3af5f
RR
1763}
1764
aba9bfd0 1765bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int WXUNUSED(col) )
a0f3af5f 1766{
9861f022 1767 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
aba9bfd0 1768/*#define MAX_VIRTUAL_WIDTH 100000
9861f022
RR
1769
1770 wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight );
0fdc2321
RR
1771 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1772 Refresh( true, &rect );
1773
1774 return true;
aba9bfd0 1775*/
99d471a5 1776 UpdateDisplay();
0fcce6b9 1777 return true;
a0f3af5f
RR
1778}
1779
1780bool wxDataViewMainWindow::Cleared()
1781{
99d471a5
RR
1782 UpdateDisplay();
1783 return true;
a0f3af5f
RR
1784}
1785
4b3feaa7
RR
1786void wxDataViewMainWindow::UpdateDisplay()
1787{
1788 m_dirty = true;
1789}
1790
1791void wxDataViewMainWindow::OnInternalIdle()
1792{
1793 wxWindow::OnInternalIdle();
f554a14b 1794
4b3feaa7
RR
1795 if (m_dirty)
1796 {
1797 RecalculateDisplay();
1798 m_dirty = false;
1799 }
1800}
1801
1802void wxDataViewMainWindow::RecalculateDisplay()
1803{
aba9bfd0 1804 wxDataViewModel *model = GetOwner()->GetModel();
4b3feaa7
RR
1805 if (!model)
1806 {
1807 Refresh();
1808 return;
1809 }
f554a14b 1810
9861f022 1811 int width = GetEndOfLastCol();
aba9bfd0 1812 int height = GetRowCount() * m_lineHeight;
4b3feaa7
RR
1813
1814 SetVirtualSize( width, height );
1815 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 1816
4b3feaa7
RR
1817 Refresh();
1818}
1819
1820void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1821{
1822 wxWindow::ScrollWindow( dx, dy, rect );
9861f022
RR
1823
1824 if (GetOwner()->m_headerArea)
1825 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
4b3feaa7
RR
1826}
1827
f554a14b 1828void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 1829{
aba9bfd0 1830 wxDataViewModel *model = GetOwner()->GetModel();
2e992e06
VZ
1831 wxAutoBufferedPaintDC dc( this );
1832
9861f022 1833 // prepare the DC
2e992e06
VZ
1834 dc.SetBackground(GetBackgroundColour());
1835 dc.Clear();
4b3feaa7 1836 GetOwner()->PrepareDC( dc );
4ed7af08 1837 dc.SetFont( GetFont() );
90675b95
RR
1838
1839 wxRect update = GetUpdateRegion().GetBox();
1840 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
f554a14b 1841
9861f022 1842 // compute which items needs to be redrawn
0a71f9e9 1843 unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
c741d33f 1844 unsigned int item_count =
87f0efe2 1845 wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
3b6280be 1846 (int)(GetRowCount( )- item_start) );
9861f022
RR
1847 unsigned int item_last = item_start + item_count;
1848
1849 // compute which columns needs to be redrawn
1850 unsigned int cols = GetOwner()->GetColumnCount();
1851 unsigned int col_start = 0;
1852 unsigned int x_start = 0;
1853 for (x_start = 0; col_start < cols; col_start++)
1854 {
1855 wxDataViewColumn *col = GetOwner()->GetColumn(col_start);
1856 if (col->IsHidden())
1857 continue; // skip it!
1858
1859 unsigned int w = col->GetWidth();
1860 if (x_start+w >= (unsigned int)update.x)
1861 break;
1862
1863 x_start += w;
1864 }
90675b95 1865
9861f022
RR
1866 unsigned int col_last = col_start;
1867 unsigned int x_last = x_start;
1868 for (; col_last < cols; col_last++)
1869 {
1870 wxDataViewColumn *col = GetOwner()->GetColumn(col_last);
1871 if (col->IsHidden())
1872 continue; // skip it!
1873
1874 if (x_last > (unsigned int)update.GetRight())
1875 break;
1876
1877 x_last += col->GetWidth();
1878 }
1879
1880 // Draw horizontal rules if required
1881 if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
1882 {
1883 dc.SetPen(m_penRule);
1884 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1885
1886 for (unsigned int i = item_start; i <= item_last+1; i++)
1887 {
1888 int y = i * m_lineHeight;
1889 dc.DrawLine(x_start, y, x_last, y);
1890 }
1891 }
1892
1893 // Draw vertical rules if required
1894 if ( m_owner->HasFlag(wxDV_VERT_RULES) )
1895 {
1896 dc.SetPen(m_penRule);
1897 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1898
1899 int x = x_start;
1900 for (unsigned int i = col_start; i < col_last; i++)
1901 {
1902 wxDataViewColumn *col = GetOwner()->GetColumn(i);
1903 if (col->IsHidden())
1904 continue; // skip it
1905
1906 dc.DrawLine(x, item_start * m_lineHeight,
1907 x, item_last * m_lineHeight);
1908
1909 x += col->GetWidth();
1910 }
1911
1912 // Draw last vertical rule
c741d33f 1913 dc.DrawLine(x, item_start * m_lineHeight,
9861f022
RR
1914 x, item_last * m_lineHeight);
1915 }
1916
1917 // redraw the background for the items which are selected/current
1918 for (unsigned int item = item_start; item < item_last; item++)
cab07038 1919 {
87f0efe2
RR
1920 bool selected = m_selection.Index( item ) != wxNOT_FOUND;
1921 if (selected || item == m_currentRow)
cab07038 1922 {
5d3f234b 1923 int flags = selected ? (int)wxCONTROL_SELECTED : 0;
daebb44c
RR
1924 if (item == m_currentRow)
1925 flags |= wxCONTROL_CURRENT;
1926 if (m_hasFocus)
1927 flags |= wxCONTROL_FOCUSED;
9861f022
RR
1928
1929 wxRect rect( x_start, item*m_lineHeight, x_last, m_lineHeight );
daebb44c
RR
1930 wxRendererNative::Get().DrawItemSelectionRect
1931 (
1932 this,
1933 dc,
1934 rect,
1935 flags
1936 );
1937 }
cab07038 1938 }
120b9b05 1939
9861f022 1940 // redraw all cells for all rows which must be repainted and for all columns
90675b95 1941 wxRect cell_rect;
9861f022
RR
1942 cell_rect.x = x_start;
1943 cell_rect.height = m_lineHeight; // -1 is for the horizontal rules
1944 for (unsigned int i = col_start; i < col_last; i++)
90675b95
RR
1945 {
1946 wxDataViewColumn *col = GetOwner()->GetColumn( i );
baa9ebc4 1947 wxDataViewRenderer *cell = col->GetRenderer();
90675b95 1948 cell_rect.width = col->GetWidth();
f554a14b 1949
87f0efe2
RR
1950 if (col->IsHidden())
1951 continue; // skipt it!
1952
9861f022 1953 for (unsigned int item = item_start; item < item_last; item++)
90675b95 1954 {
87f0efe2 1955 // get the cell value and set it into the renderer
90675b95 1956 wxVariant value;
3b6280be
RR
1957 wxDataViewTreeNode * node = GetTreeNodeByRow(item);
1958 if( node == NULL )
1959 continue;
1960
1961 wxDataViewItem dataitem = node->GetItem();
1962 model->GetValue( value, dataitem, col->GetModelColumn());
90675b95 1963 cell->SetValue( value );
87f0efe2
RR
1964
1965 // update the y offset
9861f022 1966 cell_rect.y = item * m_lineHeight;
87f0efe2 1967
3b6280be
RR
1968 //Draw the expander here. Please notice that I use const number for all pixel data. When the final API are determined
1969 //I will change this to the data member of the class wxDataViewCtrl
1970 int indent = node->GetIndentLevel();
1971 if( col->GetModelColumn() == GetOwner()->GetExpanderColumn() )
1972 {
1973 //Calculate the indent first
1974 indent = cell_rect.x + GetOwner()->GetIndent() * indent;
1975
1976 int expander_width = m_lineHeight - 2*EXPANDER_MARGIN;
1977 // change the cell_rect.x to the appropriate pos
1978 int expander_x = indent + EXPANDER_MARGIN , expander_y = cell_rect.y + EXPANDER_MARGIN ;
1979 indent = indent + m_lineHeight ; //try to use the m_lineHeight as the expander space
1980 dc.SetPen( m_penExpander );
1981 dc.SetBrush( wxNullBrush );
1982 if( node->HasChildren() )
1983 {
1984 dc.DrawRoundedRectangle( expander_x,expander_y,expander_width,expander_width, 1.0);
1985 dc.DrawLine( expander_x + 2 , expander_y + expander_width/2, expander_x + expander_width - 2, expander_y + expander_width/2 );
1986
1987 if( !node->IsOpen() )
1988 dc.DrawLine( expander_x + expander_width/2, expander_y + 2, expander_x + expander_width/2, expander_y + expander_width -2 );
1989 }
1990 else
1991 {
1992 // I am wandering whether we should draw dot lines between tree nodes
1993 }
1994
1995 //force the expander column to left-center align
1996 cell->SetAlignment( wxALIGN_CENTER_VERTICAL );
1997 }
1998
1999
2000 // cannot be bigger than allocated space
87f0efe2 2001 wxSize size = cell->GetSize();
3b6280be
RR
2002 // Because of the tree structure indent, here we should minus the width of the cell for drawing
2003 size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width - indent );
9861f022 2004 size.y = wxMin( size.y + 2*PADDING_TOPBOTTOM, cell_rect.height );
87f0efe2
RR
2005
2006 wxRect item_rect(cell_rect.GetTopLeft(), size);
9861f022 2007 int align = cell->GetAlignment();
87f0efe2
RR
2008
2009 // horizontal alignment:
9861f022
RR
2010 item_rect.x = cell_rect.x;
2011 if (align & wxALIGN_CENTER_HORIZONTAL)
2012 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
2013 else if (align & wxALIGN_RIGHT)
87f0efe2
RR
2014 item_rect.x = cell_rect.x + cell_rect.width - size.x;
2015 //else: wxALIGN_LEFT is the default
2016
2017 // vertical alignment:
9861f022
RR
2018 item_rect.y = cell_rect.y;
2019 if (align & wxALIGN_CENTER_VERTICAL)
87f0efe2 2020 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
9861f022 2021 else if (align & wxALIGN_BOTTOM)
87f0efe2
RR
2022 item_rect.y = cell_rect.y + cell_rect.height - size.y;
2023 //else: wxALIGN_TOP is the default
2024
9861f022
RR
2025 // add padding
2026 item_rect.x += PADDING_RIGHTLEFT;
2027 item_rect.y += PADDING_TOPBOTTOM;
2028 item_rect.width = size.x - 2 * PADDING_RIGHTLEFT;
2029 item_rect.height = size.y - 2 * PADDING_TOPBOTTOM;
64b3c262 2030
3b6280be
RR
2031 //Here we add the tree indent
2032 item_rect.x += indent;
2033
64b3c262 2034 int state = 0;
87f0efe2 2035 if (m_selection.Index(item) != wxNOT_FOUND)
64b3c262 2036 state |= wxDATAVIEW_CELL_SELECTED;
87f0efe2 2037
9861f022
RR
2038 // TODO: it would be much more efficient to create a clipping
2039 // region for the entire column being rendered (in the OnPaint
2040 // of wxDataViewMainWindow) instead of a single clip region for
2041 // each cell. However it would mean that each renderer should
2042 // respect the given wxRect's top & bottom coords, eventually
2043 // violating only the left & right coords - however the user can
2044 // make its own renderer and thus we cannot be sure of that.
2045 dc.SetClippingRegion( item_rect );
64b3c262 2046 cell->Render( item_rect, &dc, state );
9861f022 2047 dc.DestroyClippingRegion();
90675b95 2048 }
f554a14b 2049
90675b95
RR
2050 cell_rect.x += cell_rect.width;
2051 }
4ed7af08
RR
2052}
2053
9861f022 2054int wxDataViewMainWindow::GetCountPerPage() const
cab07038
RR
2055{
2056 wxSize size = GetClientSize();
2057 return size.y / m_lineHeight;
2058}
2059
9861f022 2060int wxDataViewMainWindow::GetEndOfLastCol() const
e21f75bd
RR
2061{
2062 int width = 0;
0a71f9e9 2063 unsigned int i;
9861f022 2064 for (i = 0; i < GetOwner()->GetColumnCount(); i++)
e21f75bd 2065 {
c741d33f 2066 const wxDataViewColumn *c =
9861f022
RR
2067 wx_const_cast(wxDataViewCtrl*, GetOwner())->GetColumn( i );
2068
2069 if (!c->IsHidden())
2070 width += c->GetWidth();
e21f75bd
RR
2071 }
2072 return width;
2073}
2074
9861f022 2075unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
72664514
RR
2076{
2077 int x = 0;
2078 int y = 0;
2079 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
120b9b05 2080
72664514
RR
2081 return y / m_lineHeight;
2082}
2083
3b6280be 2084unsigned int wxDataViewMainWindow::GetLastVisibleRow()
72664514
RR
2085{
2086 wxSize client_size = GetClientSize();
c741d33f 2087 m_owner->CalcUnscrolledPosition( client_size.x, client_size.y,
87f0efe2 2088 &client_size.x, &client_size.y );
72664514 2089
5637e131 2090 return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 );
72664514
RR
2091}
2092
3b6280be 2093unsigned int wxDataViewMainWindow::GetRowCount()
cab07038 2094{
3b6280be
RR
2095 if ( m_count == -1 )
2096 {
2097 m_count = RecalculateCount();
2098 int width, height;
2099 GetVirtualSize( &width, &height );
2100 height = m_count * m_lineHeight;
2101
2102 SetVirtualSize( width, height );
2103 }
aba9bfd0 2104 return m_count;
cab07038
RR
2105}
2106
0a71f9e9 2107void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
e21f75bd
RR
2108{
2109 m_currentRow = row;
120b9b05 2110
e21f75bd
RR
2111 // send event
2112}
2113
cab07038
RR
2114void wxDataViewMainWindow::SelectAllRows( bool on )
2115{
4a851b11
VZ
2116 if (IsEmpty())
2117 return;
120b9b05 2118
cab07038
RR
2119 if (on)
2120 {
72664514 2121 m_selection.Clear();
0a71f9e9 2122 for (unsigned int i = 0; i < GetRowCount(); i++)
cab07038 2123 m_selection.Add( i );
72664514
RR
2124 Refresh();
2125 }
2126 else
2127 {
0a71f9e9
RR
2128 unsigned int first_visible = GetFirstVisibleRow();
2129 unsigned int last_visible = GetLastVisibleRow();
2130 unsigned int i;
72664514 2131 for (i = 0; i < m_selection.GetCount(); i++)
120b9b05 2132 {
0a71f9e9 2133 unsigned int row = m_selection[i];
72664514
RR
2134 if ((row >= first_visible) && (row <= last_visible))
2135 RefreshRow( row );
2136 }
2137 m_selection.Clear();
cab07038 2138 }
cab07038
RR
2139}
2140
0a71f9e9 2141void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
cab07038
RR
2142{
2143 if (m_selection.Index( row ) == wxNOT_FOUND)
2144 {
2145 if (on)
2146 {
2147 m_selection.Add( row );
2148 RefreshRow( row );
2149 }
2150 }
2151 else
2152 {
2153 if (!on)
2154 {
2155 m_selection.Remove( row );
2156 RefreshRow( row );
2157 }
2158 }
2159}
2160
0a71f9e9 2161void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
cab07038
RR
2162{
2163 if (from > to)
2164 {
0a71f9e9 2165 unsigned int tmp = from;
cab07038
RR
2166 from = to;
2167 to = tmp;
2168 }
2169
0a71f9e9 2170 unsigned int i;
cab07038
RR
2171 for (i = from; i <= to; i++)
2172 {
2173 if (m_selection.Index( i ) == wxNOT_FOUND)
2174 {
2175 if (on)
2176 m_selection.Add( i );
2177 }
2178 else
2179 {
2180 if (!on)
2181 m_selection.Remove( i );
2182 }
2183 }
2184 RefreshRows( from, to );
2185}
2186
87f0efe2
RR
2187void wxDataViewMainWindow::Select( const wxArrayInt& aSelections )
2188{
2189 for (size_t i=0; i < aSelections.GetCount(); i++)
2190 {
2191 int n = aSelections[i];
2192
2193 m_selection.Add( n );
2194 RefreshRow( n );
2195 }
2196}
2197
0a71f9e9 2198void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
cab07038
RR
2199{
2200 if (m_selection.Index( row ) == wxNOT_FOUND)
2201 m_selection.Add( row );
2202 else
2203 m_selection.Remove( row );
120b9b05 2204 RefreshRow( row );
cab07038
RR
2205}
2206
0a71f9e9 2207bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
cab07038
RR
2208{
2209 return (m_selection.Index( row ) != wxNOT_FOUND);
2210}
2211
0a71f9e9 2212void wxDataViewMainWindow::RefreshRow( unsigned int row )
cab07038 2213{
e21f75bd 2214 wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
cab07038 2215 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2216
cab07038
RR
2217 wxSize client_size = GetClientSize();
2218 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2219 wxRect intersect_rect = client_rect.Intersect( rect );
2220 if (intersect_rect.width > 0)
2221 Refresh( true, &intersect_rect );
2222}
2223
0a71f9e9 2224void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
cab07038
RR
2225{
2226 if (from > to)
2227 {
0a71f9e9 2228 unsigned int tmp = to;
cab07038
RR
2229 to = from;
2230 from = tmp;
2231 }
2232
e21f75bd 2233 wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
cab07038 2234 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2235
cab07038
RR
2236 wxSize client_size = GetClientSize();
2237 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2238 wxRect intersect_rect = client_rect.Intersect( rect );
2239 if (intersect_rect.width > 0)
2240 Refresh( true, &intersect_rect );
2241}
2242
0a71f9e9 2243void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
cab07038 2244{
0a71f9e9 2245 unsigned int count = GetRowCount();
4a851b11
VZ
2246 if (firstRow > count)
2247 return;
120b9b05 2248
e21f75bd 2249 wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
cab07038 2250 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2251
cab07038
RR
2252 wxSize client_size = GetClientSize();
2253 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2254 wxRect intersect_rect = client_rect.Intersect( rect );
2255 if (intersect_rect.width > 0)
2256 Refresh( true, &intersect_rect );
2257}
2258
0a71f9e9 2259void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
cab07038 2260{
4a851b11 2261 wxCHECK_RET( newCurrent < GetRowCount(),
cab07038
RR
2262 _T("invalid item index in OnArrowChar()") );
2263
2264 // if there is no selection, we cannot move it anywhere
2265 if (!HasCurrentRow())
2266 return;
2267
0a71f9e9 2268 unsigned int oldCurrent = m_currentRow;
cab07038
RR
2269
2270 // in single selection we just ignore Shift as we can't select several
2271 // items anyhow
e21f75bd 2272 if ( event.ShiftDown() && !IsSingleSel() )
cab07038
RR
2273 {
2274 RefreshRow( oldCurrent );
120b9b05 2275
e21f75bd 2276 ChangeCurrentRow( newCurrent );
cab07038
RR
2277
2278 // select all the items between the old and the new one
2279 if ( oldCurrent > newCurrent )
2280 {
2281 newCurrent = oldCurrent;
2282 oldCurrent = m_currentRow;
2283 }
2284
2285 SelectRows( oldCurrent, newCurrent, true );
2286 }
2287 else // !shift
2288 {
72664514 2289 RefreshRow( oldCurrent );
120b9b05 2290
cab07038
RR
2291 // all previously selected items are unselected unless ctrl is held
2292 if ( !event.ControlDown() )
2293 SelectAllRows(false);
2294
e21f75bd 2295 ChangeCurrentRow( newCurrent );
cab07038
RR
2296
2297 if ( !event.ControlDown() )
2298 SelectRow( m_currentRow, true );
72664514
RR
2299 else
2300 RefreshRow( m_currentRow );
cab07038
RR
2301 }
2302
9861f022
RR
2303 //EnsureVisible( m_currentRow );
2304}
2305
2306wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const
2307{
2308 wxRect rect;
2309 rect.x = 0;
2310 rect.y = m_lineHeight * row;
2311 rect.width = GetEndOfLastCol();
2312 rect.height = m_lineHeight;
2313
2314 return rect;
cab07038
RR
2315}
2316
aba9bfd0
RR
2317class RowToItemJob: public DoJob
2318{
2319public:
2320 RowToItemJob( unsigned int row , int current ) { this->row = row; this->current = current ;}
2321 virtual ~RowToItemJob(){};
2322
2323 virtual bool operator() ( wxDataViewTreeNode * node )
2324 {
3b6280be
RR
2325 if ( current == row)
2326 {
2327 ret = node->GetItem() ;
2328 return true;
2329 }
2330 current ++;
2331 return false;
2332 }
2333
2334 wxDataViewItem GetResult() { return ret; }
2335
aba9bfd0
RR
2336private:
2337 unsigned int row;
2338 int current ;
2339 wxDataViewItem ret;
2340};
2341
2342wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row)
2343{
2344 RowToItemJob job( row, 0 );
2345 Walker( m_root , job );
2346 return job.GetResult();
2347}
2348
3b6280be
RR
2349class RowToTreeNodeJob: public DoJob
2350{
2351public:
2352 RowToTreeNodeJob( unsigned int row , int current )
2353 { this->row = row; this->current = current ; ret = NULL ; }
2354 virtual ~RowToTreeNodeJob() { }
2355
2356 virtual int operator() ( wxDataViewTreeNode * node )
2357 {
2358 if( current == row)
2359 {
2360 ret = node ;
2361 return DoJob::OK;
2362 }
2363 current ++;
2364 if ( node->IsOpen())
2365 return DoJob::CONT;
2366 else
2367 return DoJob::IGR;
2368 }
2369
2370 wxDataViewTreeNode * GetResult(){ return ret; }
2371private:
2372 unsigned int row;
2373 int current ;
2374 wxDataViewTreeNode * ret;
2375};
2376
2377
2378wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row)
2379{
2380 RowToTreeNodeJob job( row , 0 );
2381 Walker( m_root , job );
2382 return job.GetResult();
2383}
2384
2385class CountJob : public DoJob
2386{
2387public:
2388 CountJob(){ count = 0 ; }
2389 virtual ~CountJob() { }
2390
2391 virtual int operator () ( wxDataViewTreeNode * node )
2392 {
2393 count ++;
2394 if (node->IsOpen())
2395 return DoJob::CONT;
2396 else
2397 return DoJob::IGR;
2398 }
2399
2400 unsigned int GetResult()
2401 {
2402 return count ;
2403 }
2404private:
2405 unsigned int count;
2406};
2407
2408void wxDataViewMainWindow::OnExpanding( unsigned int row )
2409{
2410 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
2411 if( node != NULL )
2412 {
2413 if (node->HasChildren())
2414 if (!node->IsOpen())
2415 {
2416 node->ToggleOpen();
2417 m_count = -1;
2418 Refresh();
2419 // RefreshRows(row,GetLastVisibleRow());
2420 }
2421 }
2422}
2423
2424void wxDataViewMainWindow::OnCollapsing(unsigned int row)
2425{
2426 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
2427 if (node != NULL)
2428 {
2429 if( node->HasChildren() && node->IsOpen() )
2430 {
2431 node->ToggleOpen();
2432 m_count = -1;
2433 Refresh();
2434 //RefreshRows(row,GetLastVisibleRow());
2435 }
2436 else
2437 {
2438 node = node->GetParent();
2439 if( node != NULL )
2440 {
2441 int parent = GetRowByItem( node->GetItem()) ;
2442 SelectRow( row, false);
2443 SelectRow(parent , true );
2444 ChangeCurrentRow( parent );
2445 }
2446 }
2447 }
2448}
2449
2450int wxDataViewMainWindow::RecalculateCount()
2451{
2452 CountJob job;
2453 Walker( m_root, job );
2454 return job.GetResult();
2455}
2456
aba9bfd0
RR
2457class ItemToRowJob : public DoJob
2458{
2459public:
3b6280be 2460 ItemToRowJob(const wxDataViewItem & item){ this->item = item ; ret = 0 ; }
aba9bfd0
RR
2461 virtual ~ItemToRowJob(){};
2462
2463 virtual bool operator() ( wxDataViewTreeNode * node)
2464 {
2465 ret ++;
2466 if( node->GetItem() == item )
3b6280be
RR
2467 return true;
2468 return false;
aba9bfd0
RR
2469 }
2470
3b6280be
RR
2471 //the row number is begin from zero
2472 int GetResult(){ return ret -1 ; }
aba9bfd0
RR
2473private:
2474 wxDataViewItem item;
2475 int ret;
2476};
2477
2478unsigned int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item)
2479{
2480 ItemToRowJob job( item );
2481 Walker(m_root , job );
2482 return job.GetResult();
2483}
2484
2485unsigned int BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node)
2486{
2487 int sum = 0 ;
2488 if( !model->HasChildren( item ) )
2489 return 0;
2490
2491 wxDataViewItem i = model->GetFirstChild( item );
2492 while( i.IsOk() )
2493 {
2494 wxDataViewTreeNode * n = new wxDataViewTreeNode( node );
3b6280be
RR
2495 n->SetItem(i);
2496 node->AppendChild(n);
2497 int num = BuildTreeHelper( model, i, n) + 1;
2498 sum += num ;
2499 i = model->GetNextSibling( i );
aba9bfd0
RR
2500 }
2501 return sum;
2502}
2503
2504void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
2505{
2506 //First we define a invalid item to fetch the top-level elements
2507 wxDataViewItem item;
3b6280be
RR
2508 BuildTreeHelper( model, item, m_root);
2509 m_count = -1 ;
aba9bfd0
RR
2510}
2511
2512void DestroyTreeHelper( wxDataViewTreeNode * node )
2513{
2514 if( node->HasChildren() )
2515 {
2516 int len = node->GetChildrenNumber();
3b6280be
RR
2517 int i = 0 ;
2518 wxDataViewTreeNodes nodes = node->GetChildren();
2519 for( ; i < len; i ++ )
aba9bfd0
RR
2520 {
2521 DestroyTreeHelper(nodes[i]);
2522 }
2523 }
2524 delete node;
2525}
2526
2527void wxDataViewMainWindow::DestroyTree()
2528{
2529 DestroyTreeHelper(m_root);
2530 m_count = 0 ;
2531}
2532
cab07038
RR
2533void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
2534{
2535 if (event.GetKeyCode() == WXK_TAB)
2536 {
2537 wxNavigationKeyEvent nevent;
2538 nevent.SetWindowChange( event.ControlDown() );
2539 nevent.SetDirection( !event.ShiftDown() );
2540 nevent.SetEventObject( GetParent()->GetParent() );
2541 nevent.SetCurrentFocus( m_parent );
2542 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
2543 return;
2544 }
2545
2546 // no item -> nothing to do
2547 if (!HasCurrentRow())
2548 {
2549 event.Skip();
2550 return;
2551 }
120b9b05 2552
cab07038
RR
2553 // don't use m_linesPerPage directly as it might not be computed yet
2554 const int pageSize = GetCountPerPage();
2555 wxCHECK_RET( pageSize, _T("should have non zero page size") );
2556
2557 switch ( event.GetKeyCode() )
2558 {
2559 case WXK_UP:
2560 if ( m_currentRow > 0 )
2561 OnArrowChar( m_currentRow - 1, event );
2562 break;
2563
2564 case WXK_DOWN:
4a851b11 2565 if ( m_currentRow < GetRowCount() - 1 )
cab07038
RR
2566 OnArrowChar( m_currentRow + 1, event );
2567 break;
3b6280be
RR
2568 //Add the process for tree expanding/collapsing
2569 case WXK_LEFT:
2570 OnCollapsing(m_currentRow);
2571 break;
2572 case WXK_RIGHT:
2573 OnExpanding( m_currentRow);
2574 break;
cab07038
RR
2575 case WXK_END:
2576 if (!IsEmpty())
2577 OnArrowChar( GetRowCount() - 1, event );
2578 break;
2579
2580 case WXK_HOME:
2581 if (!IsEmpty())
2582 OnArrowChar( 0, event );
2583 break;
2584
2585 case WXK_PAGEUP:
2586 {
2587 int steps = pageSize - 1;
2588 int index = m_currentRow - steps;
2589 if (index < 0)
2590 index = 0;
2591
2592 OnArrowChar( index, event );
2593 }
2594 break;
2595
2596 case WXK_PAGEDOWN:
2597 {
2598 int steps = pageSize - 1;
0a71f9e9
RR
2599 unsigned int index = m_currentRow + steps;
2600 unsigned int count = GetRowCount();
cab07038
RR
2601 if ( index >= count )
2602 index = count - 1;
2603
2604 OnArrowChar( index, event );
2605 }
2606 break;
2607
2608 default:
2609 event.Skip();
2610 }
2611}
2612
4ed7af08
RR
2613void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
2614{
e21f75bd
RR
2615 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
2616 {
2617 // let the base handle mouse wheel events.
2618 event.Skip();
2619 return;
2620 }
2621
0fdc2321
RR
2622 int x = event.GetX();
2623 int y = event.GetY();
2624 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
2625
2626 wxDataViewColumn *col = NULL;
2627
2628 int xpos = 0;
9861f022 2629 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 2630 unsigned int i;
0fdc2321
RR
2631 for (i = 0; i < cols; i++)
2632 {
2633 wxDataViewColumn *c = GetOwner()->GetColumn( i );
9861f022
RR
2634 if (c->IsHidden())
2635 continue; // skip it!
2636
0fdc2321
RR
2637 if (x < xpos + c->GetWidth())
2638 {
2639 col = c;
2640 break;
2641 }
2642 xpos += c->GetWidth();
2643 }
f554a14b 2644 if (!col)
0fdc2321 2645 return;
baa9ebc4 2646 wxDataViewRenderer *cell = col->GetRenderer();
f554a14b 2647
0a71f9e9 2648 unsigned int current = y / m_lineHeight;
120b9b05 2649
e21f75bd
RR
2650 if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
2651 {
2652 // Unselect all if below the last row ?
2653 return;
2654 }
f554a14b 2655
aba9bfd0 2656 wxDataViewModel *model = GetOwner()->GetModel();
0fdc2321 2657
e21f75bd
RR
2658 if (event.Dragging())
2659 {
2660 if (m_dragCount == 0)
2661 {
2662 // we have to report the raw, physical coords as we want to be
2663 // able to call HitTest(event.m_pointDrag) from the user code to
2664 // get the item being dragged
2665 m_dragStart = event.GetPosition();
2666 }
2667
2668 m_dragCount++;
2669
2670 if (m_dragCount != 3)
2671 return;
2672
2673 if (event.LeftIsDown())
2674 {
2675 // Notify cell about drag
2676 }
2677 return;
2678 }
2679 else
2680 {
2681 m_dragCount = 0;
2682 }
2683
2684 bool forceClick = false;
2685
0fcce6b9
RR
2686 if (event.ButtonDClick())
2687 {
2688 m_renameTimer->Stop();
2689 m_lastOnSame = false;
2690 }
2691
0fdc2321
RR
2692 if (event.LeftDClick())
2693 {
e21f75bd 2694 if ( current == m_lineLastClicked )
0fdc2321 2695 {
e21f75bd
RR
2696 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
2697 {
2698 wxVariant value;
2699 model->GetValue( value, col->GetModelColumn(), current );
2700 cell->SetValue( value );
c741d33f 2701 wxRect cell_rect( xpos, current * m_lineHeight,
87f0efe2 2702 col->GetWidth(), m_lineHeight );
aba9bfd0
RR
2703 wxDataViewItem dataitem = GetItemByRow(current);
2704 cell->Activate( cell_rect, model, dataitem, col->GetModelColumn() );
e21f75bd
RR
2705 }
2706 return;
2707 }
2708 else
2709 {
2710 // The first click was on another item, so don't interpret this as
2711 // a double click, but as a simple click instead
2712 forceClick = true;
0fdc2321 2713 }
120b9b05 2714 }
f554a14b 2715
0fcce6b9
RR
2716 if (event.LeftUp())
2717 {
0a71f9e9 2718 if (m_lineSelectSingleOnUp != (unsigned int)-1)
e21f75bd
RR
2719 {
2720 // select single line
2721 SelectAllRows( false );
2722 SelectRow( m_lineSelectSingleOnUp, true );
2723 }
120b9b05 2724
3b6280be
RR
2725 //Process the event of user clicking the expander
2726 bool expander = false;
2727 wxDataViewTreeNode * node = GetTreeNodeByRow(current);
2728 if( node!=NULL && node->HasChildren() )
2729 {
2730 int indent = node->GetIndentLevel();
2731 indent = GetOwner()->GetIndent()*indent;
2732 wxRect rect( xpos + indent + EXPANDER_MARGIN, current * m_lineHeight + EXPANDER_MARGIN, m_lineHeight-2*EXPANDER_MARGIN,m_lineHeight-2*EXPANDER_MARGIN);
2733 if( rect.Contains( x, y) )
2734 {
2735 expander = true;
2736 node->ToggleOpen();
2737 m_count = -1; //make the current row number fail
2738
2739 Refresh();
2740 //int last_row = GetLastVisibleRow();
2741 //RefreshRows( current, last_row );
2742 }
2743 }
2744
2745 //If the user click the expander, we do not do editing even if the column with expander are editable
2746 if (m_lastOnSame && !expander )
0fcce6b9 2747 {
a8461d31 2748 if ((col == m_currentCol) && (current == m_currentRow) &&
0fcce6b9
RR
2749 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
2750 {
2751 m_renameTimer->Start( 100, true );
2752 }
2753 }
2754
2755 m_lastOnSame = false;
0a71f9e9 2756 m_lineSelectSingleOnUp = (unsigned int)-1;
120b9b05 2757 }
e21f75bd
RR
2758 else
2759 {
2760 // This is necessary, because after a DnD operation in
2761 // from and to ourself, the up event is swallowed by the
2762 // DnD code. So on next non-up event (which means here and
2763 // now) m_lineSelectSingleOnUp should be reset.
0a71f9e9 2764 m_lineSelectSingleOnUp = (unsigned int)-1;
e21f75bd
RR
2765 }
2766
2767 if (event.RightDown())
2768 {
2769 m_lineBeforeLastClicked = m_lineLastClicked;
2770 m_lineLastClicked = current;
2771
2772 // If the item is already selected, do not update the selection.
2773 // Multi-selections should not be cleared if a selected item is clicked.
2774 if (!IsRowSelected(current))
2775 {
2776 SelectAllRows(false);
2777 ChangeCurrentRow(current);
2778 SelectRow(m_currentRow,true);
2779 }
2780
2781 // notify cell about right click
2782 // cell->...
120b9b05 2783
e21f75bd
RR
2784 // Allow generation of context menu event
2785 event.Skip();
2786 }
2787 else if (event.MiddleDown())
2788 {
2789 // notify cell about middle click
2790 // cell->...
2791 }
2792 if (event.LeftDown() || forceClick)
0fcce6b9 2793 {
72664514
RR
2794#ifdef __WXMSW__
2795 SetFocus();
2796#endif
120b9b05 2797
e21f75bd
RR
2798 m_lineBeforeLastClicked = m_lineLastClicked;
2799 m_lineLastClicked = current;
2800
0a71f9e9 2801 unsigned int oldCurrentRow = m_currentRow;
e21f75bd
RR
2802 bool oldWasSelected = IsRowSelected(m_currentRow);
2803
2804 bool cmdModifierDown = event.CmdDown();
2805 if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
2806 {
2807 if ( IsSingleSel() || !IsRowSelected(current) )
2808 {
2809 SelectAllRows( false );
2810
2811 ChangeCurrentRow(current);
2812
2813 SelectRow(m_currentRow,true);
2814 }
2815 else // multi sel & current is highlighted & no mod keys
2816 {
2817 m_lineSelectSingleOnUp = current;
2818 ChangeCurrentRow(current); // change focus
2819 }
2820 }
2821 else // multi sel & either ctrl or shift is down
2822 {
2823 if (cmdModifierDown)
2824 {
2825 ChangeCurrentRow(current);
2826
2827 ReverseRowSelection(m_currentRow);
2828 }
2829 else if (event.ShiftDown())
2830 {
2831 ChangeCurrentRow(current);
2832
0a71f9e9 2833 unsigned int lineFrom = oldCurrentRow,
e21f75bd
RR
2834 lineTo = current;
2835
2836 if ( lineTo < lineFrom )
2837 {
2838 lineTo = lineFrom;
2839 lineFrom = m_currentRow;
2840 }
2841
2842 SelectRows(lineFrom, lineTo, true);
2843 }
2844 else // !ctrl, !shift
2845 {
2846 // test in the enclosing if should make it impossible
2847 wxFAIL_MSG( _T("how did we get here?") );
2848 }
2849 }
2850
72664514
RR
2851 if (m_currentRow != oldCurrentRow)
2852 RefreshRow( oldCurrentRow );
e21f75bd 2853
0fcce6b9 2854 wxDataViewColumn *oldCurrentCol = m_currentCol;
120b9b05 2855
0fcce6b9
RR
2856 // Update selection here...
2857 m_currentCol = col;
120b9b05 2858
c741d33f 2859 m_lastOnSame = !forceClick && ((col == oldCurrentCol) &&
87f0efe2 2860 (current == oldCurrentRow)) && oldWasSelected;
0fdc2321 2861 }
4ed7af08
RR
2862}
2863
2864void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
2865{
cab07038 2866 m_hasFocus = true;
120b9b05 2867
cab07038
RR
2868 if (HasCurrentRow())
2869 Refresh();
120b9b05 2870
cab07038
RR
2871 event.Skip();
2872}
2873
2874void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
2875{
2876 m_hasFocus = false;
120b9b05 2877
cab07038
RR
2878 if (HasCurrentRow())
2879 Refresh();
120b9b05 2880
4ed7af08
RR
2881 event.Skip();
2882}
2883
2884//-----------------------------------------------------------------------------
2885// wxDataViewCtrl
2886//-----------------------------------------------------------------------------
2887
2888IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
2889
4b3feaa7
RR
2890BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
2891 EVT_SIZE(wxDataViewCtrl::OnSize)
2892END_EVENT_TABLE()
2893
4ed7af08
RR
2894wxDataViewCtrl::~wxDataViewCtrl()
2895{
2896 if (m_notifier)
2897 GetModel()->RemoveNotifier( m_notifier );
2898}
2899
2900void wxDataViewCtrl::Init()
2901{
2902 m_notifier = NULL;
2903}
2904
2905bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 2906 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
2907 long style, const wxValidator& validator )
2908{
c741d33f 2909 if (!wxControl::Create( parent, id, pos, size,
87f0efe2 2910 style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
4b3feaa7
RR
2911 return false;
2912
4ed7af08 2913 Init();
f554a14b 2914
4ed7af08
RR
2915#ifdef __WXMAC__
2916 MacSetClipChildren( true ) ;
2917#endif
2918
f554a14b 2919 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
9861f022
RR
2920
2921 if (HasFlag(wxDV_NO_HEADER))
2922 m_headerArea = NULL;
2923 else
2924 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY );
f554a14b 2925
4ed7af08 2926 SetTargetWindow( m_clientArea );
f554a14b 2927
4ed7af08 2928 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
9861f022
RR
2929 if (m_headerArea)
2930 sizer->Add( m_headerArea, 0, wxGROW );
4ed7af08
RR
2931 sizer->Add( m_clientArea, 1, wxGROW );
2932 SetSizer( sizer );
2933
2934 return true;
2935}
2936
2937#ifdef __WXMSW__
2938WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
2939 WXWPARAM wParam,
2940 WXLPARAM lParam)
2941{
b910a8ad 2942 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
2943
2944#ifndef __WXWINCE__
2945 // we need to process arrows ourselves for scrolling
2946 if ( nMsg == WM_GETDLGCODE )
2947 {
2948 rc |= DLGC_WANTARROWS;
2949 }
2950#endif
2951
2952 return rc;
2953}
2954#endif
2955
f554a14b 2956void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 2957{
4b3feaa7
RR
2958 // We need to override OnSize so that our scrolled
2959 // window a) does call Layout() to use sizers for
2960 // positioning the controls but b) does not query
2961 // the sizer for their size and use that for setting
2962 // the scrollable area as set that ourselves by
2963 // calling SetScrollbar() further down.
2964
2965 Layout();
2966
2967 AdjustScrollbars();
4ed7af08
RR
2968}
2969
aba9bfd0 2970bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
4ed7af08
RR
2971{
2972 if (!wxDataViewCtrlBase::AssociateModel( model ))
2973 return false;
2974
aba9bfd0 2975 m_notifier = new wxGenericDataViewModelNotifier( m_clientArea );
4ed7af08 2976
f554a14b 2977 model->AddNotifier( m_notifier );
4ed7af08 2978
aba9bfd0
RR
2979 m_clientArea->BuildTree(model);
2980
4b3feaa7 2981 m_clientArea->UpdateDisplay();
f554a14b 2982
4ed7af08
RR
2983 return true;
2984}
2985
2986bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
2987{
2988 if (!wxDataViewCtrlBase::AppendColumn(col))
2989 return false;
f554a14b 2990
9861f022 2991 OnColumnChange();
4ed7af08
RR
2992 return true;
2993}
2994
9861f022
RR
2995void wxDataViewCtrl::OnColumnChange()
2996{
2997 if (m_headerArea)
2998 m_headerArea->UpdateDisplay();
2999
3000 m_clientArea->UpdateDisplay();
3001}
3b6280be
RR
3002
3003void wxDataViewCtrl::DoSetExpanderColumn()
3004{
3005 m_clientArea->UpdateDisplay();
3006}
3007
3008void wxDataViewCtrl::DoSetIndent()
3009{
3010 m_clientArea->UpdateDisplay();
3011}
3012
3013
aba9bfd0 3014/********************************************************************
87f0efe2 3015void wxDataViewCtrl::SetSelection( int row )
6ff7eee7 3016{
87f0efe2 3017 m_clientArea->SelectRow(row, true);
6ff7eee7
RR
3018}
3019
87f0efe2 3020void wxDataViewCtrl::SetSelectionRange( unsigned int from, unsigned int to )
6ff7eee7 3021{
87f0efe2 3022 m_clientArea->SelectRows(from, to, true);
6ff7eee7
RR
3023}
3024
87f0efe2 3025void wxDataViewCtrl::SetSelections( const wxArrayInt& aSelections )
6ff7eee7 3026{
87f0efe2 3027 m_clientArea->Select(aSelections);
6ff7eee7 3028}
df387169
WS
3029
3030void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) )
fc211fe5 3031{
df387169 3032 // FIXME - TODO
fc211fe5
RR
3033}
3034
df387169 3035bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const
6ff7eee7 3036{
df387169
WS
3037 // FIXME - TODO
3038
6ff7eee7
RR
3039 return false;
3040}
3041
3042int wxDataViewCtrl::GetSelection() const
3043{
df387169
WS
3044 // FIXME - TODO
3045
6ff7eee7
RR
3046 return -1;
3047}
3048
df387169 3049int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const
6ff7eee7 3050{
df387169
WS
3051 // FIXME - TODO
3052
6ff7eee7
RR
3053 return 0;
3054}
aba9bfd0 3055*********************************************************************/
f554a14b 3056#endif
4ed7af08
RR
3057 // !wxUSE_GENERICDATAVIEWCTRL
3058
f554a14b 3059#endif
4ed7af08 3060 // wxUSE_DATAVIEWCTRL