]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
[ 1560785 ] wxFileName::IsReadable/Writable/Executable
[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
606wxDataViewColumn::~wxDataViewColumn()
607{
608}
609
610void wxDataViewColumn::SetTitle( const wxString &title )
611{
612 wxDataViewColumnBase::SetTitle( title );
f554a14b 613
4ed7af08
RR
614}
615
533544f2
RR
616int wxDataViewColumn::GetWidth()
617{
618 return m_width;
619}
620
4ed7af08
RR
621//-----------------------------------------------------------------------------
622// wxDataViewHeaderWindow
623//-----------------------------------------------------------------------------
624
45778c96 625IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow)
4ed7af08
RR
626
627BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow)
628 EVT_PAINT (wxDataViewHeaderWindow::OnPaint)
629 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse)
630 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus)
631END_EVENT_TABLE()
632
633wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id,
634 const wxPoint &pos, const wxSize &size, const wxString &name ) :
635 wxWindow( parent, id, pos, size, 0, name )
636{
637 SetOwner( parent );
4b3feaa7 638
4ed7af08 639 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
f554a14b 640
4ed7af08
RR
641 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
642 SetOwnForegroundColour( attr.colFg );
643 SetOwnBackgroundColour( attr.colBg );
644 if (!m_hasFont)
645 SetOwnFont( attr.font );
646}
647
648wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
649{
650 delete m_resizeCursor;
651}
652
f554a14b 653void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 654{
4b3feaa7
RR
655 int w, h;
656 GetClientSize( &w, &h );
657
658 wxPaintDC dc( this );
f554a14b 659
4ed7af08
RR
660 int xpix;
661 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
662
663 int x;
664 m_owner->GetViewStart( &x, NULL );
665
666 // account for the horz scrollbar offset
667 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 668
4ed7af08 669 dc.SetFont( GetFont() );
f554a14b 670
0a71f9e9
RR
671 unsigned int cols = GetOwner()->GetNumberOfColumns();
672 unsigned int i;
4b3feaa7
RR
673 int xpos = 0;
674 for (i = 0; i < cols; i++)
675 {
676 wxDataViewColumn *col = GetOwner()->GetColumn( i );
677 int width = col->GetWidth();
f554a14b 678
4b3feaa7
RR
679 int cw = width;
680 int ch = h;
4b3feaa7
RR
681
682 wxRendererNative::Get().DrawHeaderButton
683 (
684 this,
685 dc,
72664514 686 wxRect(xpos, 0, cw, ch-1),
4b3feaa7
RR
687 m_parent->IsEnabled() ? 0
688 : (int)wxCONTROL_DISABLED
689 );
690
f554a14b
WS
691 dc.DrawText( col->GetTitle(), xpos+3, 3 );
692
4b3feaa7
RR
693 xpos += width;
694 }
4ed7af08
RR
695}
696
f554a14b 697void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
4ed7af08
RR
698{
699}
700
701void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
702{
cab07038 703 GetParent()->SetFocus();
4ed7af08
RR
704 event.Skip();
705}
706
0fcce6b9
RR
707//-----------------------------------------------------------------------------
708// wxDataViewRenameTimer
709//-----------------------------------------------------------------------------
710
711wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
712{
713 m_owner = owner;
714}
715
716void wxDataViewRenameTimer::Notify()
717{
718 m_owner->OnRenameTimer();
719}
720
721//-----------------------------------------------------------------------------
722// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
723//-----------------------------------------------------------------------------
724
725BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler)
726 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar)
727 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp)
728 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus)
729END_EVENT_TABLE()
730
731wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
732 wxDataViewMainWindow *owner,
733 wxTextCtrl *text,
734 wxDataViewListModel *model,
0a71f9e9 735 unsigned int col, unsigned int row,
0fcce6b9
RR
736 wxRect rectLabel )
737{
738 m_owner = owner;
739 m_model = model;
740 m_row = row;
741 m_col = col;
120b9b05
WS
742 m_text = text;
743
0fcce6b9
RR
744 m_finished = false;
745 m_aboutToFinish = false;
120b9b05 746
0fcce6b9
RR
747 wxVariant value;
748 model->GetValue( value, col, row );
749 m_startValue = value.GetString();
120b9b05 750
0fcce6b9
RR
751 m_owner->GetOwner()->CalcScrolledPosition(
752 rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y );
753
754 m_text->Create( owner, wxID_ANY, m_startValue,
755 wxPoint(rectLabel.x-2,rectLabel.y-2),
756 wxSize(rectLabel.width+7,rectLabel.height+4) );
757 m_text->SetFocus();
120b9b05 758
0fcce6b9
RR
759 m_text->PushEventHandler(this);
760}
761
762void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
763{
764 m_aboutToFinish = true;
765
766 // Notify the owner about the changes
767 AcceptChanges();
768
769 // Even if vetoed, close the control (consistent with MSW)
770 Finish();
771}
772
773void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event )
774{
775 switch ( event.m_keyCode )
776 {
777 case WXK_RETURN:
778 AcceptChangesAndFinish();
779 break;
780
781 case WXK_ESCAPE:
782 // m_owner->OnRenameCancelled( m_itemEdited );
783 Finish();
784 break;
785
786 default:
787 event.Skip();
788 }
789}
790
791void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
792{
793 if (m_finished)
794 {
795 event.Skip();
796 return;
797 }
798
799 // auto-grow the textctrl
800 wxSize parentSize = m_owner->GetSize();
801 wxPoint myPos = m_text->GetPosition();
802 wxSize mySize = m_text->GetSize();
803 int sx, sy;
804 m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
805 if (myPos.x + sx > parentSize.x)
806 sx = parentSize.x - myPos.x;
807 if (mySize.x > sx)
808 sx = mySize.x;
809 m_text->SetSize(sx, wxDefaultCoord);
810
811 event.Skip();
812}
813
814void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
815{
816 if ( !m_finished && !m_aboutToFinish )
817 {
818 AcceptChanges();
819 //if ( !AcceptChanges() )
820 // m_owner->OnRenameCancelled( m_itemEdited );
120b9b05 821
0fcce6b9
RR
822 Finish();
823 }
824
825 // We must let the native text control handle focus
826 event.Skip();
827}
828
829bool wxDataViewTextCtrlWrapper::AcceptChanges()
830{
831 const wxString value = m_text->GetValue();
832
833 if ( value == m_startValue )
834 // nothing changed, always accept
835 return true;
836
837// if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
838 // vetoed by the user
839// return false;
840
841 // accepted, do rename the item
842 wxVariant variant;
843 variant = value;
844 m_model->SetValue( variant, m_col, m_row );
845 m_model->ValueChanged( m_col, m_row );
846
847 return true;
848}
849
850void wxDataViewTextCtrlWrapper::Finish()
851{
852 if ( !m_finished )
853 {
854 m_finished = true;
855
856 m_text->RemoveEventHandler(this);
857 m_owner->FinishEditing(m_text);
858
859 // delete later
860 wxPendingDelete.Append( this );
861 }
862}
863
4ed7af08
RR
864//-----------------------------------------------------------------------------
865// wxDataViewMainWindow
866//-----------------------------------------------------------------------------
867
0a71f9e9 868int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
cab07038
RR
869{
870 if (row1 > row2) return 1;
871 if (row1 == row2) return 0;
872 return -1;
873}
874
875
45778c96 876IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
877
878BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
879 EVT_PAINT (wxDataViewMainWindow::OnPaint)
880 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
881 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
cab07038
RR
882 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
883 EVT_CHAR (wxDataViewMainWindow::OnChar)
4ed7af08
RR
884END_EVENT_TABLE()
885
886wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
887 const wxPoint &pos, const wxSize &size, const wxString &name ) :
72664514 888 wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ),
cab07038 889 m_selection( wxDataViewSelectionCmp )
120b9b05 890
4ed7af08
RR
891{
892 SetOwner( parent );
f554a14b 893
0fcce6b9
RR
894 m_lastOnSame = false;
895 m_renameTimer = new wxDataViewRenameTimer( this );
896 m_textctrlWrapper = NULL;
120b9b05 897
0fcce6b9
RR
898 // TODO: user better initial values/nothing selected
899 m_currentCol = NULL;
900 m_currentRow = 0;
901
902 // TODO: we need to calculate this smartly
4b3feaa7 903 m_lineHeight = 20;
e21f75bd
RR
904
905 m_dragCount = 0;
906 m_dragStart = wxPoint(0,0);
0a71f9e9
RR
907 m_lineLastClicked = (unsigned int) -1;
908 m_lineBeforeLastClicked = (unsigned int) -1;
909 m_lineSelectSingleOnUp = (unsigned int) -1;
120b9b05 910
cab07038 911 m_hasFocus = false;
f554a14b 912
72664514
RR
913 SetBackgroundColour( *wxWHITE );
914
4b3feaa7 915 UpdateDisplay();
4ed7af08
RR
916}
917
918wxDataViewMainWindow::~wxDataViewMainWindow()
919{
0fcce6b9
RR
920 delete m_renameTimer;
921}
922
923void wxDataViewMainWindow::OnRenameTimer()
924{
925 // We have to call this here because changes may just have
926 // been made and no screen update taken place.
927 if ( m_dirty )
928 wxSafeYield();
929
930
931 int xpos = 0;
0a71f9e9
RR
932 unsigned int cols = GetOwner()->GetNumberOfColumns();
933 unsigned int i;
0fcce6b9
RR
934 for (i = 0; i < cols; i++)
935 {
936 wxDataViewColumn *c = GetOwner()->GetColumn( i );
937 if (c == m_currentCol)
938 break;
939 xpos += c->GetWidth();
940 }
941 wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight );
942
943 wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl);
944
945 wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
120b9b05 946 m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(),
0fcce6b9
RR
947 m_currentCol->GetModelColumn(), m_currentRow, labelRect );
948}
949
950void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text )
951{
952 delete text;
953 m_textctrlWrapper = NULL;
954 SetFocus();
955 // SetFocusIgnoringChildren();
4ed7af08
RR
956}
957
a0f3af5f
RR
958bool wxDataViewMainWindow::RowAppended()
959{
960 return false;
961}
962
963bool wxDataViewMainWindow::RowPrepended()
964{
965 return false;
966}
967
0a71f9e9 968bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before) )
a0f3af5f
RR
969{
970 return false;
971}
972
0a71f9e9 973bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row) )
a0f3af5f
RR
974{
975 return false;
976}
977
0a71f9e9 978bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) )
a0f3af5f
RR
979{
980 return false;
981}
982
0a71f9e9 983bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row )
a0f3af5f 984{
0fdc2321
RR
985 wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
986 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
987 Refresh( true, &rect );
988
989 return true;
a0f3af5f
RR
990}
991
0a71f9e9 992bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order) )
a0f3af5f 993{
0fcce6b9 994 Refresh();
120b9b05 995
0fcce6b9 996 return true;
a0f3af5f
RR
997}
998
999bool wxDataViewMainWindow::Cleared()
1000{
1001 return false;
1002}
1003
4b3feaa7
RR
1004void wxDataViewMainWindow::UpdateDisplay()
1005{
1006 m_dirty = true;
1007}
1008
1009void wxDataViewMainWindow::OnInternalIdle()
1010{
1011 wxWindow::OnInternalIdle();
f554a14b 1012
4b3feaa7
RR
1013 if (m_dirty)
1014 {
1015 RecalculateDisplay();
1016 m_dirty = false;
1017 }
1018}
1019
1020void wxDataViewMainWindow::RecalculateDisplay()
1021{
1022 wxDataViewListModel *model = GetOwner()->GetModel();
1023 if (!model)
1024 {
1025 Refresh();
1026 return;
1027 }
f554a14b 1028
4b3feaa7 1029 int width = 0;
0a71f9e9
RR
1030 unsigned int cols = GetOwner()->GetNumberOfColumns();
1031 unsigned int i;
4b3feaa7
RR
1032 for (i = 0; i < cols; i++)
1033 {
1034 wxDataViewColumn *col = GetOwner()->GetColumn( i );
1035 width += col->GetWidth();
1036 }
f554a14b 1037
4b3feaa7
RR
1038 int height = model->GetNumberOfRows() * m_lineHeight;
1039
1040 SetVirtualSize( width, height );
1041 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 1042
4b3feaa7
RR
1043 Refresh();
1044}
1045
1046void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1047{
1048 wxWindow::ScrollWindow( dx, dy, rect );
1049 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
1050}
1051
f554a14b 1052void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08
RR
1053{
1054 wxPaintDC dc( this );
1055
4b3feaa7 1056 GetOwner()->PrepareDC( dc );
4ed7af08
RR
1057
1058 dc.SetFont( GetFont() );
90675b95
RR
1059
1060 wxRect update = GetUpdateRegion().GetBox();
1061 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
f554a14b 1062
90675b95 1063 wxDataViewListModel *model = GetOwner()->GetModel();
f554a14b 1064
0a71f9e9
RR
1065 unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
1066 unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
a87594c6 1067 (int)(model->GetNumberOfRows()-item_start) );
90675b95 1068
120b9b05 1069
cab07038 1070
0a71f9e9 1071 unsigned int item;
cab07038
RR
1072 for (item = item_start; item < item_start+item_count; item++)
1073 {
1074 if (m_selection.Index( item ) != wxNOT_FOUND)
1075 {
daebb44c
RR
1076 int flags = wxCONTROL_SELECTED;
1077 if (item == m_currentRow)
1078 flags |= wxCONTROL_CURRENT;
1079 if (m_hasFocus)
1080 flags |= wxCONTROL_FOCUSED;
e21f75bd 1081 wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
daebb44c
RR
1082 wxRendererNative::Get().DrawItemSelectionRect
1083 (
1084 this,
1085 dc,
1086 rect,
1087 flags
1088 );
1089 }
1090 else
1091 {
1092 if (item == m_currentRow)
1093 {
1094 int flags = wxCONTROL_CURRENT;
1095 if (m_hasFocus)
1096 flags |= wxCONTROL_FOCUSED; // should have no effect
1097 wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
1098 wxRendererNative::Get().DrawItemSelectionRect
1099 (
1100 this,
1101 dc,
1102 rect,
1103 flags
1104 );
120b9b05 1105
daebb44c 1106 }
cab07038
RR
1107 }
1108 }
120b9b05 1109
90675b95
RR
1110 wxRect cell_rect;
1111 cell_rect.x = 0;
1112 cell_rect.height = m_lineHeight;
0a71f9e9
RR
1113 unsigned int cols = GetOwner()->GetNumberOfColumns();
1114 unsigned int i;
90675b95
RR
1115 for (i = 0; i < cols; i++)
1116 {
1117 wxDataViewColumn *col = GetOwner()->GetColumn( i );
baa9ebc4 1118 wxDataViewRenderer *cell = col->GetRenderer();
90675b95 1119 cell_rect.width = col->GetWidth();
f554a14b 1120
0fcce6b9 1121 for (item = item_start; item < item_start+item_count; item++)
90675b95
RR
1122 {
1123 cell_rect.y = item*m_lineHeight;
1124 wxVariant value;
1125 model->GetValue( value, col->GetModelColumn(), item );
1126 cell->SetValue( value );
4064f7de
RR
1127 wxSize size = cell->GetSize();
1128 // cannot be bigger than allocated space
1129 size.x = wxMin( size.x, cell_rect.width );
1130 size.y = wxMin( size.y, cell_rect.height );
1131 // TODO: check for left/right/centre alignment here
1132 wxRect item_rect;
1133 // for now: centre
1134 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
1135 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
f554a14b 1136
4064f7de
RR
1137 item_rect.width = size.x;
1138 item_rect.height= size.y;
1139 cell->Render( item_rect, &dc, 0 );
90675b95 1140 }
f554a14b 1141
90675b95
RR
1142 cell_rect.x += cell_rect.width;
1143 }
4ed7af08
RR
1144}
1145
cab07038
RR
1146int wxDataViewMainWindow::GetCountPerPage()
1147{
1148 wxSize size = GetClientSize();
1149 return size.y / m_lineHeight;
1150}
1151
e21f75bd
RR
1152int wxDataViewMainWindow::GetEndOfLastCol()
1153{
1154 int width = 0;
0a71f9e9 1155 unsigned int i;
e21f75bd
RR
1156 for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++)
1157 {
1158 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1159 width += c->GetWidth();
1160 }
1161 return width;
1162}
1163
0a71f9e9 1164unsigned int wxDataViewMainWindow::GetFirstVisibleRow()
72664514
RR
1165{
1166 int x = 0;
1167 int y = 0;
1168 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
120b9b05 1169
72664514
RR
1170 return y / m_lineHeight;
1171}
1172
0a71f9e9 1173unsigned int wxDataViewMainWindow::GetLastVisibleRow()
72664514
RR
1174{
1175 wxSize client_size = GetClientSize();
1176 m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, &client_size.x, &client_size.y );
1177
5637e131 1178 return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 );
72664514
RR
1179}
1180
0a71f9e9 1181unsigned int wxDataViewMainWindow::GetRowCount()
cab07038
RR
1182{
1183 return GetOwner()->GetModel()->GetNumberOfRows();
1184}
1185
0a71f9e9 1186void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
e21f75bd
RR
1187{
1188 m_currentRow = row;
120b9b05 1189
e21f75bd
RR
1190 // send event
1191}
1192
cab07038
RR
1193void wxDataViewMainWindow::SelectAllRows( bool on )
1194{
4a851b11
VZ
1195 if (IsEmpty())
1196 return;
120b9b05 1197
cab07038
RR
1198 if (on)
1199 {
72664514 1200 m_selection.Clear();
0a71f9e9 1201 for (unsigned int i = 0; i < GetRowCount(); i++)
cab07038 1202 m_selection.Add( i );
72664514
RR
1203 Refresh();
1204 }
1205 else
1206 {
0a71f9e9
RR
1207 unsigned int first_visible = GetFirstVisibleRow();
1208 unsigned int last_visible = GetLastVisibleRow();
1209 unsigned int i;
72664514 1210 for (i = 0; i < m_selection.GetCount(); i++)
120b9b05 1211 {
0a71f9e9 1212 unsigned int row = m_selection[i];
72664514
RR
1213 if ((row >= first_visible) && (row <= last_visible))
1214 RefreshRow( row );
1215 }
1216 m_selection.Clear();
cab07038 1217 }
cab07038
RR
1218}
1219
0a71f9e9 1220void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
cab07038
RR
1221{
1222 if (m_selection.Index( row ) == wxNOT_FOUND)
1223 {
1224 if (on)
1225 {
1226 m_selection.Add( row );
1227 RefreshRow( row );
1228 }
1229 }
1230 else
1231 {
1232 if (!on)
1233 {
1234 m_selection.Remove( row );
1235 RefreshRow( row );
1236 }
1237 }
1238}
1239
0a71f9e9 1240void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
cab07038
RR
1241{
1242 if (from > to)
1243 {
0a71f9e9 1244 unsigned int tmp = from;
cab07038
RR
1245 from = to;
1246 to = tmp;
1247 }
1248
0a71f9e9 1249 unsigned int i;
cab07038
RR
1250 for (i = from; i <= to; i++)
1251 {
1252 if (m_selection.Index( i ) == wxNOT_FOUND)
1253 {
1254 if (on)
1255 m_selection.Add( i );
1256 }
1257 else
1258 {
1259 if (!on)
1260 m_selection.Remove( i );
1261 }
1262 }
1263 RefreshRows( from, to );
1264}
1265
0a71f9e9 1266void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
cab07038
RR
1267{
1268 if (m_selection.Index( row ) == wxNOT_FOUND)
1269 m_selection.Add( row );
1270 else
1271 m_selection.Remove( row );
120b9b05 1272 RefreshRow( row );
cab07038
RR
1273}
1274
0a71f9e9 1275bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
cab07038
RR
1276{
1277 return (m_selection.Index( row ) != wxNOT_FOUND);
1278}
1279
0a71f9e9 1280void wxDataViewMainWindow::RefreshRow( unsigned int row )
cab07038 1281{
e21f75bd 1282 wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
cab07038 1283 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1284
cab07038
RR
1285 wxSize client_size = GetClientSize();
1286 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1287 wxRect intersect_rect = client_rect.Intersect( rect );
1288 if (intersect_rect.width > 0)
1289 Refresh( true, &intersect_rect );
1290}
1291
0a71f9e9 1292void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
cab07038
RR
1293{
1294 if (from > to)
1295 {
0a71f9e9 1296 unsigned int tmp = to;
cab07038
RR
1297 to = from;
1298 from = tmp;
1299 }
1300
e21f75bd 1301 wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
cab07038 1302 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1303
cab07038
RR
1304 wxSize client_size = GetClientSize();
1305 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1306 wxRect intersect_rect = client_rect.Intersect( rect );
1307 if (intersect_rect.width > 0)
1308 Refresh( true, &intersect_rect );
1309}
1310
0a71f9e9 1311void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
cab07038 1312{
0a71f9e9 1313 unsigned int count = GetRowCount();
4a851b11
VZ
1314 if (firstRow > count)
1315 return;
120b9b05 1316
e21f75bd 1317 wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
cab07038 1318 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 1319
cab07038
RR
1320 wxSize client_size = GetClientSize();
1321 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1322 wxRect intersect_rect = client_rect.Intersect( rect );
1323 if (intersect_rect.width > 0)
1324 Refresh( true, &intersect_rect );
1325}
1326
0a71f9e9 1327void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
cab07038 1328{
4a851b11 1329 wxCHECK_RET( newCurrent < GetRowCount(),
cab07038
RR
1330 _T("invalid item index in OnArrowChar()") );
1331
1332 // if there is no selection, we cannot move it anywhere
1333 if (!HasCurrentRow())
1334 return;
1335
0a71f9e9 1336 unsigned int oldCurrent = m_currentRow;
cab07038
RR
1337
1338 // in single selection we just ignore Shift as we can't select several
1339 // items anyhow
e21f75bd 1340 if ( event.ShiftDown() && !IsSingleSel() )
cab07038
RR
1341 {
1342 RefreshRow( oldCurrent );
120b9b05 1343
e21f75bd 1344 ChangeCurrentRow( newCurrent );
cab07038
RR
1345
1346 // select all the items between the old and the new one
1347 if ( oldCurrent > newCurrent )
1348 {
1349 newCurrent = oldCurrent;
1350 oldCurrent = m_currentRow;
1351 }
1352
1353 SelectRows( oldCurrent, newCurrent, true );
1354 }
1355 else // !shift
1356 {
72664514 1357 RefreshRow( oldCurrent );
120b9b05 1358
cab07038
RR
1359 // all previously selected items are unselected unless ctrl is held
1360 if ( !event.ControlDown() )
1361 SelectAllRows(false);
1362
e21f75bd 1363 ChangeCurrentRow( newCurrent );
cab07038
RR
1364
1365 if ( !event.ControlDown() )
1366 SelectRow( m_currentRow, true );
72664514
RR
1367 else
1368 RefreshRow( m_currentRow );
cab07038
RR
1369 }
1370
1371 // MoveToFocus();
1372}
1373
1374void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
1375{
1376 if (event.GetKeyCode() == WXK_TAB)
1377 {
1378 wxNavigationKeyEvent nevent;
1379 nevent.SetWindowChange( event.ControlDown() );
1380 nevent.SetDirection( !event.ShiftDown() );
1381 nevent.SetEventObject( GetParent()->GetParent() );
1382 nevent.SetCurrentFocus( m_parent );
1383 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
1384 return;
1385 }
1386
1387 // no item -> nothing to do
1388 if (!HasCurrentRow())
1389 {
1390 event.Skip();
1391 return;
1392 }
120b9b05 1393
cab07038
RR
1394 // don't use m_linesPerPage directly as it might not be computed yet
1395 const int pageSize = GetCountPerPage();
1396 wxCHECK_RET( pageSize, _T("should have non zero page size") );
1397
1398 switch ( event.GetKeyCode() )
1399 {
1400 case WXK_UP:
1401 if ( m_currentRow > 0 )
1402 OnArrowChar( m_currentRow - 1, event );
1403 break;
1404
1405 case WXK_DOWN:
4a851b11 1406 if ( m_currentRow < GetRowCount() - 1 )
cab07038
RR
1407 OnArrowChar( m_currentRow + 1, event );
1408 break;
1409
1410 case WXK_END:
1411 if (!IsEmpty())
1412 OnArrowChar( GetRowCount() - 1, event );
1413 break;
1414
1415 case WXK_HOME:
1416 if (!IsEmpty())
1417 OnArrowChar( 0, event );
1418 break;
1419
1420 case WXK_PAGEUP:
1421 {
1422 int steps = pageSize - 1;
1423 int index = m_currentRow - steps;
1424 if (index < 0)
1425 index = 0;
1426
1427 OnArrowChar( index, event );
1428 }
1429 break;
1430
1431 case WXK_PAGEDOWN:
1432 {
1433 int steps = pageSize - 1;
0a71f9e9
RR
1434 unsigned int index = m_currentRow + steps;
1435 unsigned int count = GetRowCount();
cab07038
RR
1436 if ( index >= count )
1437 index = count - 1;
1438
1439 OnArrowChar( index, event );
1440 }
1441 break;
1442
1443 default:
1444 event.Skip();
1445 }
1446}
1447
4ed7af08
RR
1448void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
1449{
e21f75bd
RR
1450 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1451 {
1452 // let the base handle mouse wheel events.
1453 event.Skip();
1454 return;
1455 }
1456
0fdc2321
RR
1457 int x = event.GetX();
1458 int y = event.GetY();
1459 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1460
1461 wxDataViewColumn *col = NULL;
1462
1463 int xpos = 0;
0a71f9e9
RR
1464 unsigned int cols = GetOwner()->GetNumberOfColumns();
1465 unsigned int i;
0fdc2321
RR
1466 for (i = 0; i < cols; i++)
1467 {
1468 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1469 if (x < xpos + c->GetWidth())
1470 {
1471 col = c;
1472 break;
1473 }
1474 xpos += c->GetWidth();
1475 }
f554a14b 1476 if (!col)
0fdc2321 1477 return;
baa9ebc4 1478 wxDataViewRenderer *cell = col->GetRenderer();
f554a14b 1479
0a71f9e9 1480 unsigned int current = y / m_lineHeight;
120b9b05 1481
e21f75bd
RR
1482 if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
1483 {
1484 // Unselect all if below the last row ?
1485 return;
1486 }
f554a14b 1487
0fdc2321
RR
1488 wxDataViewListModel *model = GetOwner()->GetModel();
1489
e21f75bd
RR
1490 if (event.Dragging())
1491 {
1492 if (m_dragCount == 0)
1493 {
1494 // we have to report the raw, physical coords as we want to be
1495 // able to call HitTest(event.m_pointDrag) from the user code to
1496 // get the item being dragged
1497 m_dragStart = event.GetPosition();
1498 }
1499
1500 m_dragCount++;
1501
1502 if (m_dragCount != 3)
1503 return;
1504
1505 if (event.LeftIsDown())
1506 {
1507 // Notify cell about drag
1508 }
1509 return;
1510 }
1511 else
1512 {
1513 m_dragCount = 0;
1514 }
1515
1516 bool forceClick = false;
1517
0fcce6b9
RR
1518 if (event.ButtonDClick())
1519 {
1520 m_renameTimer->Stop();
1521 m_lastOnSame = false;
1522 }
1523
0fdc2321
RR
1524 if (event.LeftDClick())
1525 {
e21f75bd 1526 if ( current == m_lineLastClicked )
0fdc2321 1527 {
e21f75bd
RR
1528 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
1529 {
1530 wxVariant value;
1531 model->GetValue( value, col->GetModelColumn(), current );
1532 cell->SetValue( value );
1533 wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight );
1534 cell->Activate( cell_rect, model, col->GetModelColumn(), current );
1535 }
1536 return;
1537 }
1538 else
1539 {
1540 // The first click was on another item, so don't interpret this as
1541 // a double click, but as a simple click instead
1542 forceClick = true;
0fdc2321 1543 }
120b9b05 1544 }
f554a14b 1545
0fcce6b9
RR
1546 if (event.LeftUp())
1547 {
0a71f9e9 1548 if (m_lineSelectSingleOnUp != (unsigned int)-1)
e21f75bd
RR
1549 {
1550 // select single line
1551 SelectAllRows( false );
1552 SelectRow( m_lineSelectSingleOnUp, true );
1553 }
120b9b05 1554
0fcce6b9
RR
1555 if (m_lastOnSame)
1556 {
a8461d31 1557 if ((col == m_currentCol) && (current == m_currentRow) &&
0fcce6b9
RR
1558 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
1559 {
1560 m_renameTimer->Start( 100, true );
1561 }
1562 }
1563
1564 m_lastOnSame = false;
0a71f9e9 1565 m_lineSelectSingleOnUp = (unsigned int)-1;
120b9b05 1566 }
e21f75bd
RR
1567 else
1568 {
1569 // This is necessary, because after a DnD operation in
1570 // from and to ourself, the up event is swallowed by the
1571 // DnD code. So on next non-up event (which means here and
1572 // now) m_lineSelectSingleOnUp should be reset.
0a71f9e9 1573 m_lineSelectSingleOnUp = (unsigned int)-1;
e21f75bd
RR
1574 }
1575
1576 if (event.RightDown())
1577 {
1578 m_lineBeforeLastClicked = m_lineLastClicked;
1579 m_lineLastClicked = current;
1580
1581 // If the item is already selected, do not update the selection.
1582 // Multi-selections should not be cleared if a selected item is clicked.
1583 if (!IsRowSelected(current))
1584 {
1585 SelectAllRows(false);
1586 ChangeCurrentRow(current);
1587 SelectRow(m_currentRow,true);
1588 }
1589
1590 // notify cell about right click
1591 // cell->...
120b9b05 1592
e21f75bd
RR
1593 // Allow generation of context menu event
1594 event.Skip();
1595 }
1596 else if (event.MiddleDown())
1597 {
1598 // notify cell about middle click
1599 // cell->...
1600 }
1601 if (event.LeftDown() || forceClick)
0fcce6b9 1602 {
72664514
RR
1603#ifdef __WXMSW__
1604 SetFocus();
1605#endif
120b9b05 1606
e21f75bd
RR
1607 m_lineBeforeLastClicked = m_lineLastClicked;
1608 m_lineLastClicked = current;
1609
0a71f9e9 1610 unsigned int oldCurrentRow = m_currentRow;
e21f75bd
RR
1611 bool oldWasSelected = IsRowSelected(m_currentRow);
1612
1613 bool cmdModifierDown = event.CmdDown();
1614 if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
1615 {
1616 if ( IsSingleSel() || !IsRowSelected(current) )
1617 {
1618 SelectAllRows( false );
1619
1620 ChangeCurrentRow(current);
1621
1622 SelectRow(m_currentRow,true);
1623 }
1624 else // multi sel & current is highlighted & no mod keys
1625 {
1626 m_lineSelectSingleOnUp = current;
1627 ChangeCurrentRow(current); // change focus
1628 }
1629 }
1630 else // multi sel & either ctrl or shift is down
1631 {
1632 if (cmdModifierDown)
1633 {
1634 ChangeCurrentRow(current);
1635
1636 ReverseRowSelection(m_currentRow);
1637 }
1638 else if (event.ShiftDown())
1639 {
1640 ChangeCurrentRow(current);
1641
0a71f9e9 1642 unsigned int lineFrom = oldCurrentRow,
e21f75bd
RR
1643 lineTo = current;
1644
1645 if ( lineTo < lineFrom )
1646 {
1647 lineTo = lineFrom;
1648 lineFrom = m_currentRow;
1649 }
1650
1651 SelectRows(lineFrom, lineTo, true);
1652 }
1653 else // !ctrl, !shift
1654 {
1655 // test in the enclosing if should make it impossible
1656 wxFAIL_MSG( _T("how did we get here?") );
1657 }
1658 }
1659
72664514
RR
1660 if (m_currentRow != oldCurrentRow)
1661 RefreshRow( oldCurrentRow );
e21f75bd 1662
0fcce6b9 1663 wxDataViewColumn *oldCurrentCol = m_currentCol;
120b9b05 1664
0fcce6b9
RR
1665 // Update selection here...
1666 m_currentCol = col;
120b9b05 1667
e21f75bd 1668 m_lastOnSame = !forceClick && ((col == oldCurrentCol) && (current == oldCurrentRow)) && oldWasSelected;
0fdc2321 1669 }
4ed7af08
RR
1670}
1671
1672void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
1673{
cab07038 1674 m_hasFocus = true;
120b9b05 1675
cab07038
RR
1676 if (HasCurrentRow())
1677 Refresh();
120b9b05 1678
cab07038
RR
1679 event.Skip();
1680}
1681
1682void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
1683{
1684 m_hasFocus = false;
120b9b05 1685
cab07038
RR
1686 if (HasCurrentRow())
1687 Refresh();
120b9b05 1688
4ed7af08
RR
1689 event.Skip();
1690}
1691
1692//-----------------------------------------------------------------------------
1693// wxDataViewCtrl
1694//-----------------------------------------------------------------------------
1695
1696IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1697
4b3feaa7
RR
1698BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
1699 EVT_SIZE(wxDataViewCtrl::OnSize)
1700END_EVENT_TABLE()
1701
4ed7af08
RR
1702wxDataViewCtrl::~wxDataViewCtrl()
1703{
1704 if (m_notifier)
1705 GetModel()->RemoveNotifier( m_notifier );
1706}
1707
1708void wxDataViewCtrl::Init()
1709{
1710 m_notifier = NULL;
1711}
1712
1713bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 1714 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
1715 long style, const wxValidator& validator )
1716{
4b3feaa7
RR
1717 if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
1718 return false;
1719
4ed7af08 1720 Init();
f554a14b 1721
4ed7af08
RR
1722#ifdef __WXMAC__
1723 MacSetClipChildren( true ) ;
1724#endif
1725
f554a14b 1726 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
72664514
RR
1727#ifdef __WXMSW__
1728 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22) );
1729#else
f554a14b 1730 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) );
120b9b05 1731#endif
f554a14b 1732
4ed7af08 1733 SetTargetWindow( m_clientArea );
f554a14b 1734
4ed7af08
RR
1735 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1736 sizer->Add( m_headerArea, 0, wxGROW );
1737 sizer->Add( m_clientArea, 1, wxGROW );
1738 SetSizer( sizer );
1739
1740 return true;
1741}
1742
1743#ifdef __WXMSW__
1744WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
1745 WXWPARAM wParam,
1746 WXLPARAM lParam)
1747{
b910a8ad 1748 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
1749
1750#ifndef __WXWINCE__
1751 // we need to process arrows ourselves for scrolling
1752 if ( nMsg == WM_GETDLGCODE )
1753 {
1754 rc |= DLGC_WANTARROWS;
1755 }
1756#endif
1757
1758 return rc;
1759}
1760#endif
1761
f554a14b 1762void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 1763{
4b3feaa7
RR
1764 // We need to override OnSize so that our scrolled
1765 // window a) does call Layout() to use sizers for
1766 // positioning the controls but b) does not query
1767 // the sizer for their size and use that for setting
1768 // the scrollable area as set that ourselves by
1769 // calling SetScrollbar() further down.
1770
1771 Layout();
1772
1773 AdjustScrollbars();
4ed7af08
RR
1774}
1775
1776bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1777{
1778 if (!wxDataViewCtrlBase::AssociateModel( model ))
1779 return false;
1780
a0f3af5f 1781 m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea );
4ed7af08 1782
f554a14b 1783 model->AddNotifier( m_notifier );
4ed7af08 1784
4b3feaa7 1785 m_clientArea->UpdateDisplay();
f554a14b 1786
4ed7af08
RR
1787 return true;
1788}
1789
1790bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1791{
1792 if (!wxDataViewCtrlBase::AppendColumn(col))
1793 return false;
f554a14b 1794
4b3feaa7 1795 m_clientArea->UpdateDisplay();
f554a14b 1796
4ed7af08
RR
1797 return true;
1798}
1799
df387169 1800void wxDataViewCtrl::SetSelection( int WXUNUSED(row) )
6ff7eee7 1801{
df387169 1802 // FIXME - TODO
6ff7eee7
RR
1803}
1804
df387169 1805void wxDataViewCtrl::SetSelectionRange( unsigned int WXUNUSED(from), unsigned int WXUNUSED(to) )
6ff7eee7 1806{
df387169 1807 // FIXME - TODO
6ff7eee7
RR
1808}
1809
df387169 1810void wxDataViewCtrl::SetSelections( const wxArrayInt& WXUNUSED(aSelections) )
6ff7eee7 1811{
df387169 1812 // FIXME - TODO
6ff7eee7 1813}
df387169
WS
1814
1815void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) )
fc211fe5 1816{
df387169 1817 // FIXME - TODO
fc211fe5
RR
1818}
1819
df387169 1820bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const
6ff7eee7 1821{
df387169
WS
1822 // FIXME - TODO
1823
6ff7eee7
RR
1824 return false;
1825}
1826
1827int wxDataViewCtrl::GetSelection() const
1828{
df387169
WS
1829 // FIXME - TODO
1830
6ff7eee7
RR
1831 return -1;
1832}
1833
df387169 1834int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const
6ff7eee7 1835{
df387169
WS
1836 // FIXME - TODO
1837
6ff7eee7
RR
1838 return 0;
1839}
1840
f554a14b 1841#endif
4ed7af08
RR
1842 // !wxUSE_GENERICDATAVIEWCTRL
1843
f554a14b 1844#endif
4ed7af08 1845 // wxUSE_DATAVIEWCTRL