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