]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
use wxSTRINGIZE instead of redefining a special STRINGIZE in this file
[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
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
ed4b0fdc
WS
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
4ed7af08
RR
17#if wxUSE_DATAVIEWCTRL
18
19#include "wx/dataview.h"
20
21#ifdef wxUSE_GENERICDATAVIEWCTRL
22
f554a14b 23#ifndef WX_PRECOMP
57bd4c60
WS
24 #ifdef __WXMSW__
25 #include "wx/msw/wrapwin.h"
26 #endif
f554a14b
WS
27 #include "wx/sizer.h"
28 #include "wx/log.h"
ed4b0fdc 29 #include "wx/dcclient.h"
c0badb70 30 #include "wx/timer.h"
9eddec69 31 #include "wx/settings.h"
f554a14b
WS
32#endif
33
4ed7af08 34#include "wx/stockitem.h"
4ed7af08
RR
35#include "wx/calctrl.h"
36#include "wx/popupwin.h"
4ed7af08 37#include "wx/renderer.h"
2586d4a1 38#include "wx/icon.h"
4ed7af08 39
4ed7af08
RR
40//-----------------------------------------------------------------------------
41// classes
42//-----------------------------------------------------------------------------
43
44class wxDataViewCtrl;
45
a0f3af5f
RR
46//-----------------------------------------------------------------------------
47// wxDataViewHeaderWindow
48//-----------------------------------------------------------------------------
4ed7af08 49
a0f3af5f 50class wxDataViewHeaderWindow: public wxWindow
4ed7af08
RR
51{
52public:
a0f3af5f
RR
53 wxDataViewHeaderWindow( wxDataViewCtrl *parent,
54 wxWindowID id,
55 const wxPoint &pos = wxDefaultPosition,
56 const wxSize &size = wxDefaultSize,
57 const wxString &name = wxT("wxdataviewctrlheaderwindow") );
d3c7fc99 58 virtual ~wxDataViewHeaderWindow();
4ed7af08 59
a0f3af5f
RR
60 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
61 wxDataViewCtrl *GetOwner() { return m_owner; }
4ed7af08 62
a0f3af5f
RR
63 void OnPaint( wxPaintEvent &event );
64 void OnMouse( wxMouseEvent &event );
65 void OnSetFocus( wxFocusEvent &event );
f554a14b 66
a0f3af5f
RR
67private:
68 wxDataViewCtrl *m_owner;
69 wxCursor *m_resizeCursor;
f554a14b 70
a0f3af5f
RR
71private:
72 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow)
73 DECLARE_EVENT_TABLE()
74};
4ed7af08 75
0fcce6b9
RR
76//-----------------------------------------------------------------------------
77// wxDataViewRenameTimer
78//-----------------------------------------------------------------------------
79
80class wxDataViewRenameTimer: public wxTimer
81{
82private:
83 wxDataViewMainWindow *m_owner;
84
85public:
86 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
87 void Notify();
88};
89
90//-----------------------------------------------------------------------------
91// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
92//-----------------------------------------------------------------------------
93
94class wxDataViewTextCtrlWrapper : public wxEvtHandler
95{
96public:
97 // NB: text must be a valid object but not Create()d yet
98 wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner,
99 wxTextCtrl *text,
100 wxDataViewListModel *model,
0a71f9e9 101 unsigned int col, unsigned int row,
0fcce6b9
RR
102 wxRect cellLabel );
103
104 wxTextCtrl *GetText() const { return m_text; }
105
106 void AcceptChangesAndFinish();
107
108protected:
109 void OnChar( wxKeyEvent &event );
110 void OnKeyUp( wxKeyEvent &event );
111 void OnKillFocus( wxFocusEvent &event );
112
113 bool AcceptChanges();
114 void Finish();
115
116private:
117 wxDataViewMainWindow *m_owner;
118 wxTextCtrl *m_text;
119 wxString m_startValue;
120 wxDataViewListModel *m_model;
0a71f9e9
RR
121 unsigned int m_col;
122 unsigned int m_row;
0fcce6b9
RR
123 bool m_finished;
124 bool m_aboutToFinish;
125
126 DECLARE_EVENT_TABLE()
127};
128
a0f3af5f
RR
129//-----------------------------------------------------------------------------
130// wxDataViewMainWindow
131//-----------------------------------------------------------------------------
4ed7af08 132
0a71f9e9 133WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection, WXDLLIMPEXP_ADV);
cab07038 134
a0f3af5f 135class wxDataViewMainWindow: public wxWindow
4ed7af08 136{
a0f3af5f
RR
137public:
138 wxDataViewMainWindow( wxDataViewCtrl *parent,
139 wxWindowID id,
140 const wxPoint &pos = wxDefaultPosition,
141 const wxSize &size = wxDefaultSize,
142 const wxString &name = wxT("wxdataviewctrlmainwindow") );
d3c7fc99 143 virtual ~wxDataViewMainWindow();
4ed7af08 144
a0f3af5f
RR
145 // notifications from wxDataViewListModel
146 bool RowAppended();
147 bool RowPrepended();
0a71f9e9
RR
148 bool RowInserted( unsigned int before );
149 bool RowDeleted( unsigned int row );
150 bool RowChanged( unsigned int row );
151 bool ValueChanged( unsigned int col, unsigned int row );
152 bool RowsReordered( unsigned int *new_order );
a0f3af5f 153 bool Cleared();
4ed7af08 154
a0f3af5f
RR
155 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
156 wxDataViewCtrl *GetOwner() { return m_owner; }
4ed7af08 157
a0f3af5f 158 void OnPaint( wxPaintEvent &event );
0a71f9e9 159 void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event);
cab07038 160 void OnChar( wxKeyEvent &event );
a0f3af5f
RR
161 void OnMouse( wxMouseEvent &event );
162 void OnSetFocus( wxFocusEvent &event );
cab07038 163 void OnKillFocus( wxFocusEvent &event );
f554a14b 164
a0f3af5f
RR
165 void UpdateDisplay();
166 void RecalculateDisplay();
167 void OnInternalIdle();
f554a14b 168
0fcce6b9
RR
169 void OnRenameTimer();
170 void FinishEditing( wxTextCtrl *text );
171
a0f3af5f 172 void ScrollWindow( int dx, int dy, const wxRect *rect );
120b9b05 173
0a71f9e9
RR
174 bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; }
175 void ChangeCurrentRow( unsigned int row );
120b9b05 176
cab07038
RR
177 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); };
178 bool IsEmpty() { return GetRowCount() == 0; }
120b9b05 179
cab07038 180 int GetCountPerPage();
e21f75bd 181 int GetEndOfLastCol();
0a71f9e9
RR
182 unsigned int GetFirstVisibleRow();
183 unsigned int GetLastVisibleRow();
184 unsigned int GetRowCount();
120b9b05 185
cab07038 186 void SelectAllRows( bool on );
0a71f9e9
RR
187 void SelectRow( unsigned int row, bool on );
188 void SelectRows( unsigned int from, unsigned int to, bool on );
189 void ReverseRowSelection( unsigned int row );
190 bool IsRowSelected( unsigned int row );
120b9b05 191
0a71f9e9
RR
192 void RefreshRow( unsigned int row );
193 void RefreshRows( unsigned int from, unsigned int to );
194 void RefreshRowsAfter( unsigned int firstRow );
120b9b05 195
a0f3af5f 196private:
0fcce6b9
RR
197 wxDataViewCtrl *m_owner;
198 int m_lineHeight;
199 bool m_dirty;
120b9b05 200
0fcce6b9 201 wxDataViewColumn *m_currentCol;
0a71f9e9 202 unsigned int m_currentRow;
cab07038 203 wxDataViewSelection m_selection;
120b9b05 204
0fcce6b9
RR
205 wxDataViewRenameTimer *m_renameTimer;
206 wxDataViewTextCtrlWrapper *m_textctrlWrapper;
207 bool m_lastOnSame;
f554a14b 208
cab07038
RR
209 bool m_hasFocus;
210
e21f75bd
RR
211 int m_dragCount;
212 wxPoint m_dragStart;
213
214 // for double click logic
0a71f9e9 215 unsigned int m_lineLastClicked,
e21f75bd
RR
216 m_lineBeforeLastClicked,
217 m_lineSelectSingleOnUp;
cab07038 218
a0f3af5f
RR
219private:
220 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
221 DECLARE_EVENT_TABLE()
222};
4ed7af08 223
f554a14b 224// ---------------------------------------------------------
a0f3af5f 225// wxGenericDataViewListModelNotifier
f554a14b 226// ---------------------------------------------------------
a0f3af5f
RR
227
228class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier
4ed7af08 229{
a0f3af5f
RR
230public:
231 wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow )
232 { m_mainWindow = mainWindow; }
f554a14b 233
a0f3af5f
RR
234 virtual bool RowAppended()
235 { return m_mainWindow->RowAppended(); }
236 virtual bool RowPrepended()
237 { return m_mainWindow->RowPrepended(); }
0a71f9e9 238 virtual bool RowInserted( unsigned int before )
a0f3af5f 239 { return m_mainWindow->RowInserted( before ); }
0a71f9e9 240 virtual bool RowDeleted( unsigned int row )
a0f3af5f 241 { return m_mainWindow->RowDeleted( row ); }
0a71f9e9 242 virtual bool RowChanged( unsigned int row )
a0f3af5f 243 { return m_mainWindow->RowChanged( row ); }
0a71f9e9 244 virtual bool ValueChanged( unsigned int col, unsigned int row )
a0f3af5f 245 { return m_mainWindow->ValueChanged( col, row ); }
0a71f9e9 246 virtual bool RowsReordered( unsigned int *new_order )
a0f3af5f
RR
247 { return m_mainWindow->RowsReordered( new_order ); }
248 virtual bool Cleared()
249 { return m_mainWindow->Cleared(); }
f554a14b 250
a0f3af5f
RR
251 wxDataViewMainWindow *m_mainWindow;
252};
4ed7af08 253
f554a14b 254// ---------------------------------------------------------
baa9ebc4 255// wxDataViewRenderer
f554a14b 256// ---------------------------------------------------------
4ed7af08 257
baa9ebc4 258IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
4ed7af08 259
baa9ebc4
RR
260wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
261 wxDataViewRendererBase( varianttype, mode )
4ed7af08 262{
3d9d7cc4 263 m_dc = NULL;
4ed7af08
RR
264}
265
baa9ebc4 266wxDataViewRenderer::~wxDataViewRenderer()
3d9d7cc4
RR
267{
268 if (m_dc)
269 delete m_dc;
270}
271
baa9ebc4 272wxDC *wxDataViewRenderer::GetDC()
3d9d7cc4
RR
273{
274 if (m_dc == NULL)
275 {
276 if (GetOwner() == NULL)
277 return NULL;
278 if (GetOwner()->GetOwner() == NULL)
279 return NULL;
280 m_dc = new wxClientDC( GetOwner()->GetOwner() );
281 }
f554a14b 282
3d9d7cc4
RR
283 return m_dc;
284}
285
f554a14b 286// ---------------------------------------------------------
baa9ebc4 287// wxDataViewCustomRenderer
f554a14b 288// ---------------------------------------------------------
3d9d7cc4 289
baa9ebc4 290IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
3d9d7cc4 291
baa9ebc4 292wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
3d9d7cc4 293 wxDataViewCellMode mode ) :
baa9ebc4 294 wxDataViewRenderer( varianttype, mode )
3d9d7cc4
RR
295{
296}
297
f554a14b 298// ---------------------------------------------------------
baa9ebc4 299// wxDataViewTextRenderer
f554a14b 300// ---------------------------------------------------------
4ed7af08 301
baa9ebc4 302IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer)
4ed7af08 303
baa9ebc4
RR
304wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
305 wxDataViewCustomRenderer( varianttype, mode )
4ed7af08
RR
306{
307}
308
baa9ebc4 309bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
4ed7af08 310{
90675b95 311 m_text = value.GetString();
f554a14b 312
90675b95 313 return true;
4ed7af08
RR
314}
315
baa9ebc4 316bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) )
4ed7af08
RR
317{
318 return false;
319}
320
baa9ebc4 321bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
3d9d7cc4 322{
90675b95
RR
323 dc->DrawText( m_text, cell.x, cell.y );
324
325 return true;
3d9d7cc4
RR
326}
327
baa9ebc4 328wxSize wxDataViewTextRenderer::GetSize()
3d9d7cc4
RR
329{
330 return wxSize(80,20);
331}
332
2586d4a1 333// ---------------------------------------------------------
baa9ebc4 334// wxDataViewBitmapRenderer
2586d4a1
RR
335// ---------------------------------------------------------
336
baa9ebc4 337IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer)
2586d4a1 338
baa9ebc4
RR
339wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
340 wxDataViewCustomRenderer( varianttype, mode )
2586d4a1
RR
341{
342}
343
baa9ebc4 344bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
2586d4a1
RR
345{
346 if (value.GetType() == wxT("wxBitmap"))
347 m_bitmap << value;
348 if (value.GetType() == wxT("wxIcon"))
349 m_icon << value;
350
351 return true;
352}
353
baa9ebc4 354bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) )
2586d4a1
RR
355{
356 return false;
357}
358
baa9ebc4 359bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2586d4a1
RR
360{
361 if (m_bitmap.Ok())
362 dc->DrawBitmap( m_bitmap, cell.x, cell.y );
363 else if (m_icon.Ok())
364 dc->DrawIcon( m_icon, cell.x, cell.y );
365
366 return true;
367}
368
baa9ebc4 369wxSize wxDataViewBitmapRenderer::GetSize()
2586d4a1
RR
370{
371 if (m_bitmap.Ok())
372 return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() );
373 else if (m_icon.Ok())
374 return wxSize( m_icon.GetWidth(), m_icon.GetHeight() );
375
376 return wxSize(16,16);
377}
378
f554a14b 379// ---------------------------------------------------------
baa9ebc4 380// wxDataViewToggleRenderer
f554a14b 381// ---------------------------------------------------------
4ed7af08 382
baa9ebc4 383IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer)
4ed7af08 384
baa9ebc4 385wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
4ed7af08 386 wxDataViewCellMode mode ) :
baa9ebc4 387 wxDataViewCustomRenderer( varianttype, mode )
4ed7af08 388{
90675b95 389 m_toggle = false;
4ed7af08
RR
390}
391
baa9ebc4 392bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
4ed7af08 393{
90675b95 394 m_toggle = value.GetBool();
f554a14b 395
a8461d31 396 return true;
4ed7af08
RR
397}
398
baa9ebc4 399bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) )
4ed7af08
RR
400{
401 return false;
402}
f554a14b 403
baa9ebc4 404bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08 405{
90675b95 406 // User wxRenderer here
f554a14b 407
90675b95
RR
408 wxRect rect;
409 rect.x = cell.x + cell.width/2 - 10;
410 rect.width = 20;
411 rect.y = cell.y + cell.height/2 - 10;
412 rect.height = 20;
120b9b05 413
862d8041 414 int flags = 0;
90675b95 415 if (m_toggle)
862d8041
RR
416 flags |= wxCONTROL_CHECKED;
417 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
418 flags |= wxCONTROL_DISABLED;
419
90b903c2 420 wxRendererNative::Get().DrawCheckBox(
862d8041
RR
421 GetOwner()->GetOwner(),
422 *dc,
423 rect,
424 flags );
f554a14b 425
90675b95 426 return true;
4ed7af08
RR
427}
428
baa9ebc4 429bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row )
0fdc2321
RR
430{
431 bool value = !m_toggle;
432 wxVariant variant = value;
433 model->SetValue( variant, col, row );
f554a14b 434 model->ValueChanged( col, row );
0fdc2321
RR
435 return true;
436}
437
baa9ebc4 438wxSize wxDataViewToggleRenderer::GetSize()
4ed7af08 439{
3d9d7cc4 440 return wxSize(20,20);
4ed7af08
RR
441}
442
f554a14b 443// ---------------------------------------------------------
baa9ebc4 444// wxDataViewProgressRenderer
f554a14b 445// ---------------------------------------------------------
4ed7af08 446
baa9ebc4 447IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
4ed7af08 448
baa9ebc4 449wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
4ed7af08 450 const wxString &varianttype, wxDataViewCellMode mode ) :
baa9ebc4 451 wxDataViewCustomRenderer( varianttype, mode )
4ed7af08
RR
452{
453 m_label = label;
454 m_value = 0;
455}
456
baa9ebc4 457wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
4ed7af08
RR
458{
459}
460
baa9ebc4 461bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
462{
463 m_value = (long) value;
f554a14b 464
4ed7af08
RR
465 if (m_value < 0) m_value = 0;
466 if (m_value > 100) m_value = 100;
f554a14b 467
4ed7af08
RR
468 return true;
469}
f554a14b 470
baa9ebc4 471bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
472{
473 double pct = (double)m_value / 100.0;
474 wxRect bar = cell;
475 bar.width = (int)(cell.width * pct);
476 dc->SetPen( *wxTRANSPARENT_PEN );
477 dc->SetBrush( *wxBLUE_BRUSH );
478 dc->DrawRectangle( bar );
479
480 dc->SetBrush( *wxTRANSPARENT_BRUSH );
481 dc->SetPen( *wxBLACK_PEN );
482 dc->DrawRectangle( cell );
f554a14b 483
4ed7af08
RR
484 return true;
485}
486
baa9ebc4 487wxSize wxDataViewProgressRenderer::GetSize()
4ed7af08
RR
488{
489 return wxSize(40,12);
490}
f554a14b
WS
491
492// ---------------------------------------------------------
baa9ebc4 493// wxDataViewDateRenderer
f554a14b 494// ---------------------------------------------------------
4ed7af08 495
baa9ebc4 496class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
4ed7af08 497{
f554a14b 498public:
baa9ebc4 499 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
0a71f9e9 500 wxDataViewListModel *model, unsigned int col, unsigned int row ) :
4ed7af08
RR
501 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
502 {
503 m_model = model;
504 m_col = col;
505 m_row = row;
f554a14b 506 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
4ed7af08
RR
507 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
508 sizer->Add( m_cal, 1, wxGROW );
509 SetSizer( sizer );
510 sizer->Fit( this );
511 }
f554a14b 512
4ed7af08 513 void OnCalendar( wxCalendarEvent &event );
f554a14b 514
4ed7af08 515 wxCalendarCtrl *m_cal;
f554a14b 516 wxDataViewListModel *m_model;
0a71f9e9
RR
517 unsigned int m_col;
518 unsigned int m_row;
f554a14b 519
a8461d31
PC
520protected:
521 virtual void OnDismiss()
522 {
523 }
524
4ed7af08
RR
525private:
526 DECLARE_EVENT_TABLE()
527};
528
baa9ebc4
RR
529BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
530 EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar )
4ed7af08
RR
531END_EVENT_TABLE()
532
baa9ebc4 533void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
4ed7af08
RR
534{
535 wxDateTime date = event.GetDate();
536 wxVariant value = date;
537 m_model->SetValue( value, m_col, m_row );
538 m_model->ValueChanged( m_col, m_row );
539 DismissAndNotify();
540}
541
baa9ebc4 542IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
4ed7af08 543
baa9ebc4 544wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
4ed7af08 545 wxDataViewCellMode mode ) :
baa9ebc4 546 wxDataViewCustomRenderer( varianttype, mode )
4ed7af08
RR
547{
548}
f554a14b 549
baa9ebc4 550bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
551{
552 m_date = value.GetDateTime();
f554a14b 553
4ed7af08
RR
554 return true;
555}
556
baa9ebc4 557bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
558{
559 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
560 wxString tmp = m_date.FormatDate();
561 dc->DrawText( tmp, cell.x, cell.y );
562
563 return true;
564}
565
baa9ebc4 566wxSize wxDataViewDateRenderer::GetSize()
4ed7af08
RR
567{
568 wxDataViewCtrl* view = GetOwner()->GetOwner();
569 wxString tmp = m_date.FormatDate();
570 wxCoord x,y,d;
571 view->GetTextExtent( tmp, &x, &y, &d );
572 return wxSize(x,y+d);
573}
574
baa9ebc4 575bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row )
4ed7af08
RR
576{
577 wxVariant variant;
578 model->GetValue( variant, col, row );
579 wxDateTime value = variant.GetDateTime();
580
baa9ebc4 581 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
4ed7af08
RR
582 GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
583 wxPoint pos = wxGetMousePosition();
584 popup->Move( pos );
585 popup->Layout();
586 popup->Popup( popup->m_cal );
587
588 return true;
589}
590
f554a14b 591// ---------------------------------------------------------
4ed7af08 592// wxDataViewColumn
f554a14b 593// ---------------------------------------------------------
4ed7af08
RR
594
595IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
596
baa9ebc4 597wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell, unsigned int model_column,
008b5a66
RR
598 int width, int flags ) :
599 wxDataViewColumnBase( title, cell, model_column, width, flags )
4ed7af08 600{
008b5a66
RR
601 m_width = width;
602 if (m_width < 0)
603 m_width = 80;
4ed7af08
RR
604}
605
07a84e7b
RR
606wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column,
607 int width, int flags ) :
608 wxDataViewColumnBase( bitmap, cell, model_column, width, flags )
609{
610 m_width = width;
611 if (m_width < 0)
612 m_width = 30;
613}
614
47cef10f
RR
615void wxDataViewColumn::SetAlignment( wxAlignment WXUNUSED(align) )
616{
617 // TODO
618}
619
31fb32e1
RR
620void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) )
621{
622 // TODO
623}
624
625bool wxDataViewColumn::GetSortable()
626{
627 // TODO
628 return false;
629}
630
47cef10f
RR
631void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) )
632{
633 // TODO
634}
635
31fb32e1
RR
636bool wxDataViewColumn::IsSortOrderAscending()
637{
638 // TODO
639 return true;
640}
641
642
4ed7af08
RR
643wxDataViewColumn::~wxDataViewColumn()
644{
645}
646
647void wxDataViewColumn::SetTitle( const wxString &title )
648{
649 wxDataViewColumnBase::SetTitle( title );
f554a14b 650
4ed7af08
RR
651}
652
47cef10f
RR
653void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
654{
655 wxDataViewColumnBase::SetBitmap( bitmap );
656
657}
658
533544f2
RR
659int wxDataViewColumn::GetWidth()
660{
661 return m_width;
662}
663
4ed7af08
RR
664//-----------------------------------------------------------------------------
665// wxDataViewHeaderWindow
666//-----------------------------------------------------------------------------
667
45778c96 668IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow)
4ed7af08
RR
669
670BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow)
671 EVT_PAINT (wxDataViewHeaderWindow::OnPaint)
672 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse)
673 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus)
674END_EVENT_TABLE()
675
676wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id,
677 const wxPoint &pos, const wxSize &size, const wxString &name ) :
678 wxWindow( parent, id, pos, size, 0, name )
679{
680 SetOwner( parent );
4b3feaa7 681
4ed7af08 682 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
f554a14b 683
4ed7af08
RR
684 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
685 SetOwnForegroundColour( attr.colFg );
686 SetOwnBackgroundColour( attr.colBg );
687 if (!m_hasFont)
688 SetOwnFont( attr.font );
689}
690
691wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
692{
693 delete m_resizeCursor;
694}
695
f554a14b 696void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 697{
4b3feaa7
RR
698 int w, h;
699 GetClientSize( &w, &h );
700
701 wxPaintDC dc( this );
f554a14b 702
4ed7af08
RR
703 int xpix;
704 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
705
706 int x;
707 m_owner->GetViewStart( &x, NULL );
708
709 // account for the horz scrollbar offset
710 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 711
4ed7af08 712 dc.SetFont( GetFont() );
f554a14b 713
0a71f9e9
RR
714 unsigned int cols = GetOwner()->GetNumberOfColumns();
715 unsigned int i;
4b3feaa7
RR
716 int xpos = 0;
717 for (i = 0; i < cols; i++)
718 {
719 wxDataViewColumn *col = GetOwner()->GetColumn( i );
720 int width = col->GetWidth();
f554a14b 721
4b3feaa7
RR
722 int cw = width;
723 int ch = h;
4b3feaa7
RR
724
725 wxRendererNative::Get().DrawHeaderButton
726 (
727 this,
728 dc,
72664514 729 wxRect(xpos, 0, cw, ch-1),
4b3feaa7
RR
730 m_parent->IsEnabled() ? 0
731 : (int)wxCONTROL_DISABLED
732 );
733
f554a14b
WS
734 dc.DrawText( col->GetTitle(), xpos+3, 3 );
735
4b3feaa7
RR
736 xpos += width;
737 }
4ed7af08
RR
738}
739
f554a14b 740void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
4ed7af08
RR
741{
742}
743
744void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
745{
cab07038 746 GetParent()->SetFocus();
4ed7af08
RR
747 event.Skip();
748}
749
0fcce6b9
RR
750//-----------------------------------------------------------------------------
751// wxDataViewRenameTimer
752//-----------------------------------------------------------------------------
753
754wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
755{
756 m_owner = owner;
757}
758
759void wxDataViewRenameTimer::Notify()
760{
761 m_owner->OnRenameTimer();
762}
763
764//-----------------------------------------------------------------------------
765// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
766//-----------------------------------------------------------------------------
767
768BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler)
769 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar)
770 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp)
771 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus)
772END_EVENT_TABLE()
773
774wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
775 wxDataViewMainWindow *owner,
776 wxTextCtrl *text,
777 wxDataViewListModel *model,
0a71f9e9 778 unsigned int col, unsigned int row,
0fcce6b9
RR
779 wxRect rectLabel )
780{
781 m_owner = owner;
782 m_model = model;
783 m_row = row;
784 m_col = col;
120b9b05
WS
785 m_text = text;
786
0fcce6b9
RR
787 m_finished = false;
788 m_aboutToFinish = false;
120b9b05 789
0fcce6b9
RR
790 wxVariant value;
791 model->GetValue( value, col, row );
792 m_startValue = value.GetString();
120b9b05 793
0fcce6b9
RR
794 m_owner->GetOwner()->CalcScrolledPosition(
795 rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y );
796
797 m_text->Create( owner, wxID_ANY, m_startValue,
798 wxPoint(rectLabel.x-2,rectLabel.y-2),
799 wxSize(rectLabel.width+7,rectLabel.height+4) );
800 m_text->SetFocus();
120b9b05 801
0fcce6b9
RR
802 m_text->PushEventHandler(this);
803}
804
805void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
806{
807 m_aboutToFinish = true;
808
809 // Notify the owner about the changes
810 AcceptChanges();
811
812 // Even if vetoed, close the control (consistent with MSW)
813 Finish();
814}
815
816void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event )
817{
818 switch ( event.m_keyCode )
819 {
820 case WXK_RETURN:
821 AcceptChangesAndFinish();
822 break;
823
824 case WXK_ESCAPE:
825 // m_owner->OnRenameCancelled( m_itemEdited );
826 Finish();
827 break;
828
829 default:
830 event.Skip();
831 }
832}
833
834void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
835{
836 if (m_finished)
837 {
838 event.Skip();
839 return;
840 }
841
842 // auto-grow the textctrl
843 wxSize parentSize = m_owner->GetSize();
844 wxPoint myPos = m_text->GetPosition();
845 wxSize mySize = m_text->GetSize();
846 int sx, sy;
847 m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
848 if (myPos.x + sx > parentSize.x)
849 sx = parentSize.x - myPos.x;
850 if (mySize.x > sx)
851 sx = mySize.x;
852 m_text->SetSize(sx, wxDefaultCoord);
853
854 event.Skip();
855}
856
857void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
858{
859 if ( !m_finished && !m_aboutToFinish )
860 {
861 AcceptChanges();
862 //if ( !AcceptChanges() )
863 // m_owner->OnRenameCancelled( m_itemEdited );
120b9b05 864
0fcce6b9
RR
865 Finish();
866 }
867
868 // We must let the native text control handle focus
869 event.Skip();
870}
871
872bool wxDataViewTextCtrlWrapper::AcceptChanges()
873{
874 const wxString value = m_text->GetValue();
875
876 if ( value == m_startValue )
877 // nothing changed, always accept
878 return true;
879
880// if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
881 // vetoed by the user
882// return false;
883
884 // accepted, do rename the item
885 wxVariant variant;
886 variant = value;
887 m_model->SetValue( variant, m_col, m_row );
888 m_model->ValueChanged( m_col, m_row );
889
890 return true;
891}
892
893void wxDataViewTextCtrlWrapper::Finish()
894{
895 if ( !m_finished )
896 {
897 m_finished = true;
898
899 m_text->RemoveEventHandler(this);
900 m_owner->FinishEditing(m_text);
901
902 // delete later
903 wxPendingDelete.Append( this );
904 }
905}
906
4ed7af08
RR
907//-----------------------------------------------------------------------------
908// wxDataViewMainWindow
909//-----------------------------------------------------------------------------
910
0a71f9e9 911int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
cab07038
RR
912{
913 if (row1 > row2) return 1;
914 if (row1 == row2) return 0;
915 return -1;
916}
917
918
45778c96 919IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
920
921BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
922 EVT_PAINT (wxDataViewMainWindow::OnPaint)
923 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
924 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
cab07038
RR
925 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
926 EVT_CHAR (wxDataViewMainWindow::OnChar)
4ed7af08
RR
927END_EVENT_TABLE()
928
929wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
930 const wxPoint &pos, const wxSize &size, const wxString &name ) :
72664514 931 wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ),
cab07038 932 m_selection( wxDataViewSelectionCmp )
120b9b05 933
4ed7af08
RR
934{
935 SetOwner( parent );
f554a14b 936
0fcce6b9
RR
937 m_lastOnSame = false;
938 m_renameTimer = new wxDataViewRenameTimer( this );
939 m_textctrlWrapper = NULL;
120b9b05 940
0fcce6b9
RR
941 // TODO: user better initial values/nothing selected
942 m_currentCol = NULL;
943 m_currentRow = 0;
944
945 // TODO: we need to calculate this smartly
4b3feaa7 946 m_lineHeight = 20;
e21f75bd
RR
947
948 m_dragCount = 0;
949 m_dragStart = wxPoint(0,0);
0a71f9e9
RR
950 m_lineLastClicked = (unsigned int) -1;
951 m_lineBeforeLastClicked = (unsigned int) -1;
952 m_lineSelectSingleOnUp = (unsigned int) -1;
120b9b05 953
cab07038 954 m_hasFocus = false;
f554a14b 955
72664514
RR
956 SetBackgroundColour( *wxWHITE );
957
4b3feaa7 958 UpdateDisplay();
4ed7af08
RR
959}
960
961wxDataViewMainWindow::~wxDataViewMainWindow()
962{
0fcce6b9
RR
963 delete m_renameTimer;
964}
965
966void wxDataViewMainWindow::OnRenameTimer()
967{
968 // We have to call this here because changes may just have
969 // been made and no screen update taken place.
970 if ( m_dirty )
971 wxSafeYield();
972
973
974 int xpos = 0;
0a71f9e9
RR
975 unsigned int cols = GetOwner()->GetNumberOfColumns();
976 unsigned int i;
0fcce6b9
RR
977 for (i = 0; i < cols; i++)
978 {
979 wxDataViewColumn *c = GetOwner()->GetColumn( i );
980 if (c == m_currentCol)
981 break;
982 xpos += c->GetWidth();
983 }
984 wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight );
985
986 wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl);
987
988 wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
120b9b05 989 m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(),
0fcce6b9
RR
990 m_currentCol->GetModelColumn(), m_currentRow, labelRect );
991}
992
993void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text )
994{
995 delete text;
996 m_textctrlWrapper = NULL;
997 SetFocus();
998 // SetFocusIgnoringChildren();
4ed7af08
RR
999}
1000
a0f3af5f
RR
1001bool wxDataViewMainWindow::RowAppended()
1002{
1003 return false;
1004}
1005
1006bool wxDataViewMainWindow::RowPrepended()
1007{
1008 return false;
1009}
1010
0a71f9e9 1011bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before) )
a0f3af5f
RR
1012{
1013 return false;
1014}
1015
0a71f9e9 1016bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row) )
a0f3af5f
RR
1017{
1018 return false;
1019}
1020
0a71f9e9 1021bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) )
a0f3af5f
RR
1022{
1023 return false;
1024}
1025
0a71f9e9 1026bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row )
a0f3af5f 1027{
0fdc2321
RR
1028 wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
1029 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1030 Refresh( true, &rect );
1031
1032 return true;
a0f3af5f
RR
1033}
1034
0a71f9e9 1035bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order) )
a0f3af5f 1036{
0fcce6b9 1037 Refresh();
120b9b05 1038
0fcce6b9 1039 return true;
a0f3af5f
RR
1040}
1041
1042bool wxDataViewMainWindow::Cleared()
1043{
1044 return false;
1045}
1046
4b3feaa7
RR
1047void wxDataViewMainWindow::UpdateDisplay()
1048{
1049 m_dirty = true;
1050}
1051
1052void wxDataViewMainWindow::OnInternalIdle()
1053{
1054 wxWindow::OnInternalIdle();
f554a14b 1055
4b3feaa7
RR
1056 if (m_dirty)
1057 {
1058 RecalculateDisplay();
1059 m_dirty = false;
1060 }
1061}
1062
1063void wxDataViewMainWindow::RecalculateDisplay()
1064{
1065 wxDataViewListModel *model = GetOwner()->GetModel();
1066 if (!model)
1067 {
1068 Refresh();
1069 return;
1070 }
f554a14b 1071
4b3feaa7 1072 int width = 0;
0a71f9e9
RR
1073 unsigned int cols = GetOwner()->GetNumberOfColumns();
1074 unsigned int i;
4b3feaa7
RR
1075 for (i = 0; i < cols; i++)
1076 {
1077 wxDataViewColumn *col = GetOwner()->GetColumn( i );
1078 width += col->GetWidth();
1079 }
f554a14b 1080
4b3feaa7
RR
1081 int height = model->GetNumberOfRows() * m_lineHeight;
1082
1083 SetVirtualSize( width, height );
1084 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 1085
4b3feaa7
RR
1086 Refresh();
1087}
1088
1089void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1090{
1091 wxWindow::ScrollWindow( dx, dy, rect );
1092 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
1093}
1094
f554a14b 1095void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08
RR
1096{
1097 wxPaintDC dc( this );
1098
4b3feaa7 1099 GetOwner()->PrepareDC( dc );
4ed7af08
RR
1100
1101 dc.SetFont( GetFont() );
90675b95
RR
1102
1103 wxRect update = GetUpdateRegion().GetBox();
1104 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
f554a14b 1105
90675b95 1106 wxDataViewListModel *model = GetOwner()->GetModel();
f554a14b 1107
0a71f9e9
RR
1108 unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
1109 unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
a87594c6 1110 (int)(model->GetNumberOfRows()-item_start) );
90675b95 1111
120b9b05 1112
cab07038 1113
0a71f9e9 1114 unsigned int item;
cab07038
RR
1115 for (item = item_start; item < item_start+item_count; item++)
1116 {
1117 if (m_selection.Index( item ) != wxNOT_FOUND)
1118 {
daebb44c
RR
1119 int flags = wxCONTROL_SELECTED;
1120 if (item == m_currentRow)
1121 flags |= wxCONTROL_CURRENT;
1122 if (m_hasFocus)
1123 flags |= wxCONTROL_FOCUSED;
e21f75bd 1124 wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
daebb44c
RR
1125 wxRendererNative::Get().DrawItemSelectionRect
1126 (
1127 this,
1128 dc,
1129 rect,
1130 flags
1131 );
1132 }
1133 else
1134 {
1135 if (item == m_currentRow)
1136 {
1137 int flags = wxCONTROL_CURRENT;
1138 if (m_hasFocus)
1139 flags |= wxCONTROL_FOCUSED; // should have no effect
1140 wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
1141 wxRendererNative::Get().DrawItemSelectionRect
1142 (
1143 this,
1144 dc,
1145 rect,
1146 flags
1147 );
120b9b05 1148
daebb44c 1149 }
cab07038
RR
1150 }
1151 }
120b9b05 1152
90675b95
RR
1153 wxRect cell_rect;
1154 cell_rect.x = 0;
1155 cell_rect.height = m_lineHeight;
0a71f9e9
RR
1156 unsigned int cols = GetOwner()->GetNumberOfColumns();
1157 unsigned int i;
90675b95
RR
1158 for (i = 0; i < cols; i++)
1159 {
1160 wxDataViewColumn *col = GetOwner()->GetColumn( i );
baa9ebc4 1161 wxDataViewRenderer *cell = col->GetRenderer();
90675b95 1162 cell_rect.width = col->GetWidth();
f554a14b 1163
0fcce6b9 1164 for (item = item_start; item < item_start+item_count; item++)
90675b95
RR
1165 {
1166 cell_rect.y = item*m_lineHeight;
1167 wxVariant value;
1168 model->GetValue( value, col->GetModelColumn(), item );
1169 cell->SetValue( value );
4064f7de
RR
1170 wxSize size = cell->GetSize();
1171 // cannot be bigger than allocated space
1172 size.x = wxMin( size.x, cell_rect.width );
1173 size.y = wxMin( size.y, cell_rect.height );
1174 // TODO: check for left/right/centre alignment here
1175 wxRect item_rect;
1176 // for now: centre
1177 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
1178 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
f554a14b 1179
4064f7de
RR
1180 item_rect.width = size.x;
1181 item_rect.height= size.y;
1182 cell->Render( item_rect, &dc, 0 );
90675b95 1183 }
f554a14b 1184
90675b95
RR
1185 cell_rect.x += cell_rect.width;
1186 }
4ed7af08
RR
1187}
1188
cab07038
RR
1189int wxDataViewMainWindow::GetCountPerPage()
1190{
1191 wxSize size = GetClientSize();
1192 return size.y / m_lineHeight;
1193}
1194
e21f75bd
RR
1195int wxDataViewMainWindow::GetEndOfLastCol()
1196{
1197 int width = 0;
0a71f9e9 1198 unsigned int i;
e21f75bd
RR
1199 for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++)
1200 {
1201 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1202 width += c->GetWidth();
1203 }
1204 return width;
1205}
1206
0a71f9e9 1207unsigned int wxDataViewMainWindow::GetFirstVisibleRow()
72664514
RR
1208{
1209 int x = 0;
1210 int y = 0;
1211 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
120b9b05 1212
72664514
RR
1213 return y / m_lineHeight;
1214}
1215
0a71f9e9 1216unsigned int wxDataViewMainWindow::GetLastVisibleRow()
72664514
RR
1217{
1218 wxSize client_size = GetClientSize();
1219 m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, &client_size.x, &client_size.y );
1220
5637e131 1221 return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 );
72664514
RR
1222}
1223
0a71f9e9 1224unsigned int wxDataViewMainWindow::GetRowCount()
cab07038
RR
1225{
1226 return GetOwner()->GetModel()->GetNumberOfRows();
1227}
1228
0a71f9e9 1229void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
e21f75bd
RR
1230{
1231 m_currentRow = row;
120b9b05 1232
e21f75bd
RR
1233 // send event
1234}
1235
cab07038
RR
1236void wxDataViewMainWindow::SelectAllRows( bool on )
1237{
4a851b11
VZ
1238 if (IsEmpty())
1239 return;
120b9b05 1240
cab07038
RR
1241 if (on)
1242 {
72664514 1243 m_selection.Clear();
0a71f9e9 1244 for (unsigned int i = 0; i < GetRowCount(); i++)
cab07038 1245 m_selection.Add( i );
72664514
RR
1246 Refresh();
1247 }
1248 else
1249 {
0a71f9e9
RR
1250 unsigned int first_visible = GetFirstVisibleRow();
1251 unsigned int last_visible = GetLastVisibleRow();
1252 unsigned int i;
72664514 1253 for (i = 0; i < m_selection.GetCount(); i++)
120b9b05 1254 {
0a71f9e9 1255 unsigned int row = m_selection[i];
72664514
RR
1256 if ((row >= first_visible) && (row <= last_visible))
1257 RefreshRow( row );
1258 }
1259 m_selection.Clear();
cab07038 1260 }
cab07038
RR
1261}
1262
0a71f9e9 1263void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
cab07038
RR
1264{
1265 if (m_selection.Index( row ) == wxNOT_FOUND)
1266 {
1267 if (on)
1268 {
1269 m_selection.Add( row );
1270 RefreshRow( row );
1271 }
1272 }
1273 else
1274 {
1275 if (!on)
1276 {
1277 m_selection.Remove( row );
1278 RefreshRow( row );
1279 }
1280 }
1281}
1282
0a71f9e9 1283void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
cab07038
RR
1284{
1285 if (from > to)
1286 {
0a71f9e9 1287 unsigned int tmp = from;
cab07038
RR
1288 from = to;
1289 to = tmp;
1290 }
1291
0a71f9e9 1292 unsigned int i;
cab07038
RR
1293 for (i = from; i <= to; i++)
1294 {
1295 if (m_selection.Index( i ) == wxNOT_FOUND)
1296 {
1297 if (on)
1298 m_selection.Add( i );
1299 }
1300 else
1301 {
1302 if (!on)
1303 m_selection.Remove( i );
1304 }
1305 }
1306 RefreshRows( from, to );
1307}
1308
0a71f9e9 1309void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
cab07038
RR
1310{
1311 if (m_selection.Index( row ) == wxNOT_FOUND)
1312 m_selection.Add( row );
1313 else
1314 m_selection.Remove( row );
120b9b05 1315 RefreshRow( row );
cab07038
RR
1316}
1317
0a71f9e9 1318bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
cab07038
RR
1319{
1320 return (m_selection.Index( row ) != wxNOT_FOUND);
1321}
1322
0a71f9e9 1323void wxDataViewMainWindow::RefreshRow( unsigned int row )
cab07038 1324{
e21f75bd 1325 wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
cab07038 1326 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1327
cab07038
RR
1328 wxSize client_size = GetClientSize();
1329 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1330 wxRect intersect_rect = client_rect.Intersect( rect );
1331 if (intersect_rect.width > 0)
1332 Refresh( true, &intersect_rect );
1333}
1334
0a71f9e9 1335void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
cab07038
RR
1336{
1337 if (from > to)
1338 {
0a71f9e9 1339 unsigned int tmp = to;
cab07038
RR
1340 to = from;
1341 from = tmp;
1342 }
1343
e21f75bd 1344 wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
cab07038 1345 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1346
cab07038
RR
1347 wxSize client_size = GetClientSize();
1348 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1349 wxRect intersect_rect = client_rect.Intersect( rect );
1350 if (intersect_rect.width > 0)
1351 Refresh( true, &intersect_rect );
1352}
1353
0a71f9e9 1354void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
cab07038 1355{
0a71f9e9 1356 unsigned int count = GetRowCount();
4a851b11
VZ
1357 if (firstRow > count)
1358 return;
120b9b05 1359
e21f75bd 1360 wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
cab07038 1361 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1362
cab07038
RR
1363 wxSize client_size = GetClientSize();
1364 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1365 wxRect intersect_rect = client_rect.Intersect( rect );
1366 if (intersect_rect.width > 0)
1367 Refresh( true, &intersect_rect );
1368}
1369
0a71f9e9 1370void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
cab07038 1371{
4a851b11 1372 wxCHECK_RET( newCurrent < GetRowCount(),
cab07038
RR
1373 _T("invalid item index in OnArrowChar()") );
1374
1375 // if there is no selection, we cannot move it anywhere
1376 if (!HasCurrentRow())
1377 return;
1378
0a71f9e9 1379 unsigned int oldCurrent = m_currentRow;
cab07038
RR
1380
1381 // in single selection we just ignore Shift as we can't select several
1382 // items anyhow
e21f75bd 1383 if ( event.ShiftDown() && !IsSingleSel() )
cab07038
RR
1384 {
1385 RefreshRow( oldCurrent );
120b9b05 1386
e21f75bd 1387 ChangeCurrentRow( newCurrent );
cab07038
RR
1388
1389 // select all the items between the old and the new one
1390 if ( oldCurrent > newCurrent )
1391 {
1392 newCurrent = oldCurrent;
1393 oldCurrent = m_currentRow;
1394 }
1395
1396 SelectRows( oldCurrent, newCurrent, true );
1397 }
1398 else // !shift
1399 {
72664514 1400 RefreshRow( oldCurrent );
120b9b05 1401
cab07038
RR
1402 // all previously selected items are unselected unless ctrl is held
1403 if ( !event.ControlDown() )
1404 SelectAllRows(false);
1405
e21f75bd 1406 ChangeCurrentRow( newCurrent );
cab07038
RR
1407
1408 if ( !event.ControlDown() )
1409 SelectRow( m_currentRow, true );
72664514
RR
1410 else
1411 RefreshRow( m_currentRow );
cab07038
RR
1412 }
1413
1414 // MoveToFocus();
1415}
1416
1417void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
1418{
1419 if (event.GetKeyCode() == WXK_TAB)
1420 {
1421 wxNavigationKeyEvent nevent;
1422 nevent.SetWindowChange( event.ControlDown() );
1423 nevent.SetDirection( !event.ShiftDown() );
1424 nevent.SetEventObject( GetParent()->GetParent() );
1425 nevent.SetCurrentFocus( m_parent );
1426 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
1427 return;
1428 }
1429
1430 // no item -> nothing to do
1431 if (!HasCurrentRow())
1432 {
1433 event.Skip();
1434 return;
1435 }
120b9b05 1436
cab07038
RR
1437 // don't use m_linesPerPage directly as it might not be computed yet
1438 const int pageSize = GetCountPerPage();
1439 wxCHECK_RET( pageSize, _T("should have non zero page size") );
1440
1441 switch ( event.GetKeyCode() )
1442 {
1443 case WXK_UP:
1444 if ( m_currentRow > 0 )
1445 OnArrowChar( m_currentRow - 1, event );
1446 break;
1447
1448 case WXK_DOWN:
4a851b11 1449 if ( m_currentRow < GetRowCount() - 1 )
cab07038
RR
1450 OnArrowChar( m_currentRow + 1, event );
1451 break;
1452
1453 case WXK_END:
1454 if (!IsEmpty())
1455 OnArrowChar( GetRowCount() - 1, event );
1456 break;
1457
1458 case WXK_HOME:
1459 if (!IsEmpty())
1460 OnArrowChar( 0, event );
1461 break;
1462
1463 case WXK_PAGEUP:
1464 {
1465 int steps = pageSize - 1;
1466 int index = m_currentRow - steps;
1467 if (index < 0)
1468 index = 0;
1469
1470 OnArrowChar( index, event );
1471 }
1472 break;
1473
1474 case WXK_PAGEDOWN:
1475 {
1476 int steps = pageSize - 1;
0a71f9e9
RR
1477 unsigned int index = m_currentRow + steps;
1478 unsigned int count = GetRowCount();
cab07038
RR
1479 if ( index >= count )
1480 index = count - 1;
1481
1482 OnArrowChar( index, event );
1483 }
1484 break;
1485
1486 default:
1487 event.Skip();
1488 }
1489}
1490
4ed7af08
RR
1491void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
1492{
e21f75bd
RR
1493 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1494 {
1495 // let the base handle mouse wheel events.
1496 event.Skip();
1497 return;
1498 }
1499
0fdc2321
RR
1500 int x = event.GetX();
1501 int y = event.GetY();
1502 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1503
1504 wxDataViewColumn *col = NULL;
1505
1506 int xpos = 0;
0a71f9e9
RR
1507 unsigned int cols = GetOwner()->GetNumberOfColumns();
1508 unsigned int i;
0fdc2321
RR
1509 for (i = 0; i < cols; i++)
1510 {
1511 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1512 if (x < xpos + c->GetWidth())
1513 {
1514 col = c;
1515 break;
1516 }
1517 xpos += c->GetWidth();
1518 }
f554a14b 1519 if (!col)
0fdc2321 1520 return;
baa9ebc4 1521 wxDataViewRenderer *cell = col->GetRenderer();
f554a14b 1522
0a71f9e9 1523 unsigned int current = y / m_lineHeight;
120b9b05 1524
e21f75bd
RR
1525 if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
1526 {
1527 // Unselect all if below the last row ?
1528 return;
1529 }
f554a14b 1530
0fdc2321
RR
1531 wxDataViewListModel *model = GetOwner()->GetModel();
1532
e21f75bd
RR
1533 if (event.Dragging())
1534 {
1535 if (m_dragCount == 0)
1536 {
1537 // we have to report the raw, physical coords as we want to be
1538 // able to call HitTest(event.m_pointDrag) from the user code to
1539 // get the item being dragged
1540 m_dragStart = event.GetPosition();
1541 }
1542
1543 m_dragCount++;
1544
1545 if (m_dragCount != 3)
1546 return;
1547
1548 if (event.LeftIsDown())
1549 {
1550 // Notify cell about drag
1551 }
1552 return;
1553 }
1554 else
1555 {
1556 m_dragCount = 0;
1557 }
1558
1559 bool forceClick = false;
1560
0fcce6b9
RR
1561 if (event.ButtonDClick())
1562 {
1563 m_renameTimer->Stop();
1564 m_lastOnSame = false;
1565 }
1566
0fdc2321
RR
1567 if (event.LeftDClick())
1568 {
e21f75bd 1569 if ( current == m_lineLastClicked )
0fdc2321 1570 {
e21f75bd
RR
1571 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
1572 {
1573 wxVariant value;
1574 model->GetValue( value, col->GetModelColumn(), current );
1575 cell->SetValue( value );
1576 wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight );
1577 cell->Activate( cell_rect, model, col->GetModelColumn(), current );
1578 }
1579 return;
1580 }
1581 else
1582 {
1583 // The first click was on another item, so don't interpret this as
1584 // a double click, but as a simple click instead
1585 forceClick = true;
0fdc2321 1586 }
120b9b05 1587 }
f554a14b 1588
0fcce6b9
RR
1589 if (event.LeftUp())
1590 {
0a71f9e9 1591 if (m_lineSelectSingleOnUp != (unsigned int)-1)
e21f75bd
RR
1592 {
1593 // select single line
1594 SelectAllRows( false );
1595 SelectRow( m_lineSelectSingleOnUp, true );
1596 }
120b9b05 1597
0fcce6b9
RR
1598 if (m_lastOnSame)
1599 {
a8461d31 1600 if ((col == m_currentCol) && (current == m_currentRow) &&
0fcce6b9
RR
1601 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
1602 {
1603 m_renameTimer->Start( 100, true );
1604 }
1605 }
1606
1607 m_lastOnSame = false;
0a71f9e9 1608 m_lineSelectSingleOnUp = (unsigned int)-1;
120b9b05 1609 }
e21f75bd
RR
1610 else
1611 {
1612 // This is necessary, because after a DnD operation in
1613 // from and to ourself, the up event is swallowed by the
1614 // DnD code. So on next non-up event (which means here and
1615 // now) m_lineSelectSingleOnUp should be reset.
0a71f9e9 1616 m_lineSelectSingleOnUp = (unsigned int)-1;
e21f75bd
RR
1617 }
1618
1619 if (event.RightDown())
1620 {
1621 m_lineBeforeLastClicked = m_lineLastClicked;
1622 m_lineLastClicked = current;
1623
1624 // If the item is already selected, do not update the selection.
1625 // Multi-selections should not be cleared if a selected item is clicked.
1626 if (!IsRowSelected(current))
1627 {
1628 SelectAllRows(false);
1629 ChangeCurrentRow(current);
1630 SelectRow(m_currentRow,true);
1631 }
1632
1633 // notify cell about right click
1634 // cell->...
120b9b05 1635
e21f75bd
RR
1636 // Allow generation of context menu event
1637 event.Skip();
1638 }
1639 else if (event.MiddleDown())
1640 {
1641 // notify cell about middle click
1642 // cell->...
1643 }
1644 if (event.LeftDown() || forceClick)
0fcce6b9 1645 {
72664514
RR
1646#ifdef __WXMSW__
1647 SetFocus();
1648#endif
120b9b05 1649
e21f75bd
RR
1650 m_lineBeforeLastClicked = m_lineLastClicked;
1651 m_lineLastClicked = current;
1652
0a71f9e9 1653 unsigned int oldCurrentRow = m_currentRow;
e21f75bd
RR
1654 bool oldWasSelected = IsRowSelected(m_currentRow);
1655
1656 bool cmdModifierDown = event.CmdDown();
1657 if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
1658 {
1659 if ( IsSingleSel() || !IsRowSelected(current) )
1660 {
1661 SelectAllRows( false );
1662
1663 ChangeCurrentRow(current);
1664
1665 SelectRow(m_currentRow,true);
1666 }
1667 else // multi sel & current is highlighted & no mod keys
1668 {
1669 m_lineSelectSingleOnUp = current;
1670 ChangeCurrentRow(current); // change focus
1671 }
1672 }
1673 else // multi sel & either ctrl or shift is down
1674 {
1675 if (cmdModifierDown)
1676 {
1677 ChangeCurrentRow(current);
1678
1679 ReverseRowSelection(m_currentRow);
1680 }
1681 else if (event.ShiftDown())
1682 {
1683 ChangeCurrentRow(current);
1684
0a71f9e9 1685 unsigned int lineFrom = oldCurrentRow,
e21f75bd
RR
1686 lineTo = current;
1687
1688 if ( lineTo < lineFrom )
1689 {
1690 lineTo = lineFrom;
1691 lineFrom = m_currentRow;
1692 }
1693
1694 SelectRows(lineFrom, lineTo, true);
1695 }
1696 else // !ctrl, !shift
1697 {
1698 // test in the enclosing if should make it impossible
1699 wxFAIL_MSG( _T("how did we get here?") );
1700 }
1701 }
1702
72664514
RR
1703 if (m_currentRow != oldCurrentRow)
1704 RefreshRow( oldCurrentRow );
e21f75bd 1705
0fcce6b9 1706 wxDataViewColumn *oldCurrentCol = m_currentCol;
120b9b05 1707
0fcce6b9
RR
1708 // Update selection here...
1709 m_currentCol = col;
120b9b05 1710
e21f75bd 1711 m_lastOnSame = !forceClick && ((col == oldCurrentCol) && (current == oldCurrentRow)) && oldWasSelected;
0fdc2321 1712 }
4ed7af08
RR
1713}
1714
1715void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
1716{
cab07038 1717 m_hasFocus = true;
120b9b05 1718
cab07038
RR
1719 if (HasCurrentRow())
1720 Refresh();
120b9b05 1721
cab07038
RR
1722 event.Skip();
1723}
1724
1725void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
1726{
1727 m_hasFocus = false;
120b9b05 1728
cab07038
RR
1729 if (HasCurrentRow())
1730 Refresh();
120b9b05 1731
4ed7af08
RR
1732 event.Skip();
1733}
1734
1735//-----------------------------------------------------------------------------
1736// wxDataViewCtrl
1737//-----------------------------------------------------------------------------
1738
1739IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1740
4b3feaa7
RR
1741BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
1742 EVT_SIZE(wxDataViewCtrl::OnSize)
1743END_EVENT_TABLE()
1744
4ed7af08
RR
1745wxDataViewCtrl::~wxDataViewCtrl()
1746{
1747 if (m_notifier)
1748 GetModel()->RemoveNotifier( m_notifier );
1749}
1750
1751void wxDataViewCtrl::Init()
1752{
1753 m_notifier = NULL;
1754}
1755
1756bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 1757 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
1758 long style, const wxValidator& validator )
1759{
4b3feaa7
RR
1760 if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
1761 return false;
1762
4ed7af08 1763 Init();
f554a14b 1764
4ed7af08
RR
1765#ifdef __WXMAC__
1766 MacSetClipChildren( true ) ;
1767#endif
1768
f554a14b 1769 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
72664514
RR
1770#ifdef __WXMSW__
1771 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22) );
1772#else
f554a14b 1773 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) );
120b9b05 1774#endif
f554a14b 1775
4ed7af08 1776 SetTargetWindow( m_clientArea );
f554a14b 1777
4ed7af08
RR
1778 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1779 sizer->Add( m_headerArea, 0, wxGROW );
1780 sizer->Add( m_clientArea, 1, wxGROW );
1781 SetSizer( sizer );
1782
1783 return true;
1784}
1785
1786#ifdef __WXMSW__
1787WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
1788 WXWPARAM wParam,
1789 WXLPARAM lParam)
1790{
b910a8ad 1791 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
1792
1793#ifndef __WXWINCE__
1794 // we need to process arrows ourselves for scrolling
1795 if ( nMsg == WM_GETDLGCODE )
1796 {
1797 rc |= DLGC_WANTARROWS;
1798 }
1799#endif
1800
1801 return rc;
1802}
1803#endif
1804
f554a14b 1805void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 1806{
4b3feaa7
RR
1807 // We need to override OnSize so that our scrolled
1808 // window a) does call Layout() to use sizers for
1809 // positioning the controls but b) does not query
1810 // the sizer for their size and use that for setting
1811 // the scrollable area as set that ourselves by
1812 // calling SetScrollbar() further down.
1813
1814 Layout();
1815
1816 AdjustScrollbars();
4ed7af08
RR
1817}
1818
1819bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1820{
1821 if (!wxDataViewCtrlBase::AssociateModel( model ))
1822 return false;
1823
a0f3af5f 1824 m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea );
4ed7af08 1825
f554a14b 1826 model->AddNotifier( m_notifier );
4ed7af08 1827
4b3feaa7 1828 m_clientArea->UpdateDisplay();
f554a14b 1829
4ed7af08
RR
1830 return true;
1831}
1832
1833bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1834{
1835 if (!wxDataViewCtrlBase::AppendColumn(col))
1836 return false;
f554a14b 1837
4b3feaa7 1838 m_clientArea->UpdateDisplay();
f554a14b 1839
4ed7af08
RR
1840 return true;
1841}
1842
df387169 1843void wxDataViewCtrl::SetSelection( int WXUNUSED(row) )
6ff7eee7 1844{
df387169 1845 // FIXME - TODO
6ff7eee7
RR
1846}
1847
df387169 1848void wxDataViewCtrl::SetSelectionRange( unsigned int WXUNUSED(from), unsigned int WXUNUSED(to) )
6ff7eee7 1849{
df387169 1850 // FIXME - TODO
6ff7eee7
RR
1851}
1852
df387169 1853void wxDataViewCtrl::SetSelections( const wxArrayInt& WXUNUSED(aSelections) )
6ff7eee7 1854{
df387169 1855 // FIXME - TODO
6ff7eee7 1856}
df387169
WS
1857
1858void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) )
fc211fe5 1859{
df387169 1860 // FIXME - TODO
fc211fe5
RR
1861}
1862
df387169 1863bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const
6ff7eee7 1864{
df387169
WS
1865 // FIXME - TODO
1866
6ff7eee7
RR
1867 return false;
1868}
1869
1870int wxDataViewCtrl::GetSelection() const
1871{
df387169
WS
1872 // FIXME - TODO
1873
6ff7eee7
RR
1874 return -1;
1875}
1876
df387169 1877int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const
6ff7eee7 1878{
df387169
WS
1879 // FIXME - TODO
1880
6ff7eee7
RR
1881 return 0;
1882}
1883
f554a14b 1884#endif
4ed7af08
RR
1885 // !wxUSE_GENERICDATAVIEWCTRL
1886
f554a14b 1887#endif
4ed7af08 1888 // wxUSE_DATAVIEWCTRL