]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
wxGTK2: We don't need to check for __WXGTK20__ here
[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
4ed7af08
RR
13#if wxUSE_DATAVIEWCTRL
14
15#include "wx/dataview.h"
16
17#ifdef wxUSE_GENERICDATAVIEWCTRL
18
f554a14b
WS
19#ifndef WX_PRECOMP
20 #include "wx/sizer.h"
21 #include "wx/log.h"
22#endif
23
4ed7af08
RR
24#include "wx/stockitem.h"
25#include "wx/dcclient.h"
26#include "wx/calctrl.h"
27#include "wx/popupwin.h"
4ed7af08 28#include "wx/renderer.h"
0fcce6b9 29#include "wx/timer.h"
4ed7af08
RR
30
31#ifdef __WXMSW__
f554a14b 32 #include "wx/msw/wrapwin.h"
4ed7af08
RR
33#endif
34
35//-----------------------------------------------------------------------------
36// classes
37//-----------------------------------------------------------------------------
38
39class wxDataViewCtrl;
40
a0f3af5f
RR
41//-----------------------------------------------------------------------------
42// wxDataViewHeaderWindow
43//-----------------------------------------------------------------------------
4ed7af08 44
a0f3af5f 45class wxDataViewHeaderWindow: public wxWindow
4ed7af08
RR
46{
47public:
a0f3af5f
RR
48 wxDataViewHeaderWindow( wxDataViewCtrl *parent,
49 wxWindowID id,
50 const wxPoint &pos = wxDefaultPosition,
51 const wxSize &size = wxDefaultSize,
52 const wxString &name = wxT("wxdataviewctrlheaderwindow") );
53 ~wxDataViewHeaderWindow();
4ed7af08 54
a0f3af5f
RR
55 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
56 wxDataViewCtrl *GetOwner() { return m_owner; }
4ed7af08 57
a0f3af5f
RR
58 void OnPaint( wxPaintEvent &event );
59 void OnMouse( wxMouseEvent &event );
60 void OnSetFocus( wxFocusEvent &event );
f554a14b 61
a0f3af5f
RR
62private:
63 wxDataViewCtrl *m_owner;
64 wxCursor *m_resizeCursor;
f554a14b 65
a0f3af5f
RR
66private:
67 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow)
68 DECLARE_EVENT_TABLE()
69};
4ed7af08 70
0fcce6b9
RR
71//-----------------------------------------------------------------------------
72// wxDataViewRenameTimer
73//-----------------------------------------------------------------------------
74
75class wxDataViewRenameTimer: public wxTimer
76{
77private:
78 wxDataViewMainWindow *m_owner;
79
80public:
81 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
82 void Notify();
83};
84
85//-----------------------------------------------------------------------------
86// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
87//-----------------------------------------------------------------------------
88
89class wxDataViewTextCtrlWrapper : public wxEvtHandler
90{
91public:
92 // NB: text must be a valid object but not Create()d yet
93 wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner,
94 wxTextCtrl *text,
95 wxDataViewListModel *model,
96 size_t col, size_t row,
97 wxRect cellLabel );
98
99 wxTextCtrl *GetText() const { return m_text; }
100
101 void AcceptChangesAndFinish();
102
103protected:
104 void OnChar( wxKeyEvent &event );
105 void OnKeyUp( wxKeyEvent &event );
106 void OnKillFocus( wxFocusEvent &event );
107
108 bool AcceptChanges();
109 void Finish();
110
111private:
112 wxDataViewMainWindow *m_owner;
113 wxTextCtrl *m_text;
114 wxString m_startValue;
115 wxDataViewListModel *m_model;
116 size_t m_col;
117 size_t m_row;
118 bool m_finished;
119 bool m_aboutToFinish;
120
121 DECLARE_EVENT_TABLE()
122};
123
a0f3af5f
RR
124//-----------------------------------------------------------------------------
125// wxDataViewMainWindow
126//-----------------------------------------------------------------------------
4ed7af08 127
a0f3af5f 128class wxDataViewMainWindow: public wxWindow
4ed7af08 129{
a0f3af5f
RR
130public:
131 wxDataViewMainWindow( wxDataViewCtrl *parent,
132 wxWindowID id,
133 const wxPoint &pos = wxDefaultPosition,
134 const wxSize &size = wxDefaultSize,
135 const wxString &name = wxT("wxdataviewctrlmainwindow") );
136 ~wxDataViewMainWindow();
4ed7af08 137
a0f3af5f
RR
138 // notifications from wxDataViewListModel
139 bool RowAppended();
140 bool RowPrepended();
141 bool RowInserted( size_t before );
142 bool RowDeleted( size_t row );
143 bool RowChanged( size_t row );
144 bool ValueChanged( size_t col, size_t row );
145 bool RowsReordered( size_t *new_order );
146 bool Cleared();
4ed7af08 147
a0f3af5f
RR
148 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
149 wxDataViewCtrl *GetOwner() { return m_owner; }
4ed7af08 150
a0f3af5f
RR
151 void OnPaint( wxPaintEvent &event );
152 void OnMouse( wxMouseEvent &event );
153 void OnSetFocus( wxFocusEvent &event );
f554a14b 154
a0f3af5f
RR
155 void UpdateDisplay();
156 void RecalculateDisplay();
157 void OnInternalIdle();
f554a14b 158
0fcce6b9
RR
159 void OnRenameTimer();
160 void FinishEditing( wxTextCtrl *text );
161
a0f3af5f
RR
162 void ScrollWindow( int dx, int dy, const wxRect *rect );
163private:
0fcce6b9
RR
164 wxDataViewCtrl *m_owner;
165 int m_lineHeight;
166 bool m_dirty;
167
168 wxDataViewColumn *m_currentCol;
169 size_t m_currentRow;
170
171 wxDataViewRenameTimer *m_renameTimer;
172 wxDataViewTextCtrlWrapper *m_textctrlWrapper;
173 bool m_lastOnSame;
f554a14b 174
a0f3af5f
RR
175private:
176 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
177 DECLARE_EVENT_TABLE()
178};
4ed7af08 179
f554a14b 180// ---------------------------------------------------------
a0f3af5f 181// wxGenericDataViewListModelNotifier
f554a14b 182// ---------------------------------------------------------
a0f3af5f
RR
183
184class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier
4ed7af08 185{
a0f3af5f
RR
186public:
187 wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow )
188 { m_mainWindow = mainWindow; }
f554a14b 189
a0f3af5f
RR
190 virtual bool RowAppended()
191 { return m_mainWindow->RowAppended(); }
192 virtual bool RowPrepended()
193 { return m_mainWindow->RowPrepended(); }
194 virtual bool RowInserted( size_t before )
195 { return m_mainWindow->RowInserted( before ); }
196 virtual bool RowDeleted( size_t row )
197 { return m_mainWindow->RowDeleted( row ); }
198 virtual bool RowChanged( size_t row )
199 { return m_mainWindow->RowChanged( row ); }
200 virtual bool ValueChanged( size_t col, size_t row )
201 { return m_mainWindow->ValueChanged( col, row ); }
202 virtual bool RowsReordered( size_t *new_order )
203 { return m_mainWindow->RowsReordered( new_order ); }
204 virtual bool Cleared()
205 { return m_mainWindow->Cleared(); }
f554a14b 206
a0f3af5f
RR
207 wxDataViewMainWindow *m_mainWindow;
208};
4ed7af08 209
f554a14b 210// ---------------------------------------------------------
4ed7af08 211// wxDataViewCell
f554a14b 212// ---------------------------------------------------------
4ed7af08
RR
213
214IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell, wxDataViewCellBase)
215
216wxDataViewCell::wxDataViewCell( const wxString &varianttype, wxDataViewCellMode mode ) :
217 wxDataViewCellBase( varianttype, mode )
218{
3d9d7cc4 219 m_dc = NULL;
4ed7af08
RR
220}
221
3d9d7cc4
RR
222wxDataViewCell::~wxDataViewCell()
223{
224 if (m_dc)
225 delete m_dc;
226}
227
228wxDC *wxDataViewCell::GetDC()
229{
230 if (m_dc == NULL)
231 {
232 if (GetOwner() == NULL)
233 return NULL;
234 if (GetOwner()->GetOwner() == NULL)
235 return NULL;
236 m_dc = new wxClientDC( GetOwner()->GetOwner() );
237 }
f554a14b 238
3d9d7cc4
RR
239 return m_dc;
240}
241
f554a14b 242// ---------------------------------------------------------
3d9d7cc4 243// wxDataViewCustomCell
f554a14b 244// ---------------------------------------------------------
3d9d7cc4
RR
245
246IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell, wxDataViewCell)
247
f554a14b 248wxDataViewCustomCell::wxDataViewCustomCell( const wxString &varianttype,
3d9d7cc4
RR
249 wxDataViewCellMode mode ) :
250 wxDataViewCell( varianttype, mode )
251{
252}
253
f554a14b 254// ---------------------------------------------------------
4ed7af08 255// wxDataViewTextCell
f554a14b 256// ---------------------------------------------------------
4ed7af08 257
3d9d7cc4 258IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell, wxDataViewCustomCell)
4ed7af08
RR
259
260wxDataViewTextCell::wxDataViewTextCell( const wxString &varianttype, wxDataViewCellMode mode ) :
3d9d7cc4 261 wxDataViewCustomCell( varianttype, mode )
4ed7af08
RR
262{
263}
264
265bool wxDataViewTextCell::SetValue( const wxVariant &value )
266{
90675b95 267 m_text = value.GetString();
f554a14b 268
90675b95 269 return true;
4ed7af08
RR
270}
271
f554a14b 272bool wxDataViewTextCell::GetValue( wxVariant& WXUNUSED(value) )
4ed7af08
RR
273{
274 return false;
275}
276
f554a14b 277bool wxDataViewTextCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
3d9d7cc4 278{
90675b95
RR
279 dc->DrawText( m_text, cell.x, cell.y );
280
281 return true;
3d9d7cc4
RR
282}
283
284wxSize wxDataViewTextCell::GetSize()
285{
286 return wxSize(80,20);
287}
288
f554a14b 289// ---------------------------------------------------------
4ed7af08 290// wxDataViewToggleCell
f554a14b 291// ---------------------------------------------------------
4ed7af08 292
3d9d7cc4 293IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell, wxDataViewCustomCell)
4ed7af08 294
f554a14b 295wxDataViewToggleCell::wxDataViewToggleCell( const wxString &varianttype,
4ed7af08 296 wxDataViewCellMode mode ) :
3d9d7cc4 297 wxDataViewCustomCell( varianttype, mode )
4ed7af08 298{
90675b95 299 m_toggle = false;
4ed7af08
RR
300}
301
302bool wxDataViewToggleCell::SetValue( const wxVariant &value )
303{
90675b95 304 m_toggle = value.GetBool();
f554a14b 305
90675b95 306 return true;;
4ed7af08
RR
307}
308
f554a14b 309bool wxDataViewToggleCell::GetValue( wxVariant &WXUNUSED(value) )
4ed7af08
RR
310{
311 return false;
312}
f554a14b
WS
313
314bool wxDataViewToggleCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08 315{
90675b95 316 // User wxRenderer here
f554a14b 317
0fdc2321
RR
318 if (GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
319 dc->SetPen( *wxBLACK_PEN );
320 else
321 dc->SetPen( *wxGREY_PEN );
90675b95
RR
322 dc->SetBrush( *wxTRANSPARENT_BRUSH );
323 wxRect rect;
324 rect.x = cell.x + cell.width/2 - 10;
325 rect.width = 20;
326 rect.y = cell.y + cell.height/2 - 10;
327 rect.height = 20;
328 dc->DrawRectangle( rect );
329 if (m_toggle)
330 {
331 rect.x += 2;
332 rect.y += 2;
333 rect.width -= 4;
334 rect.height -= 4;
335 dc->DrawLine( rect.x, rect.y, rect.x+rect.width, rect.y+rect.height );
336 dc->DrawLine( rect.x+rect.width, rect.y, rect.x, rect.y+rect.height );
337 }
f554a14b 338
90675b95 339 return true;
4ed7af08
RR
340}
341
f554a14b 342bool wxDataViewToggleCell::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, size_t col, size_t row )
0fdc2321
RR
343{
344 bool value = !m_toggle;
345 wxVariant variant = value;
346 model->SetValue( variant, col, row );
f554a14b 347 model->ValueChanged( col, row );
0fdc2321
RR
348 return true;
349}
350
3d9d7cc4 351wxSize wxDataViewToggleCell::GetSize()
4ed7af08 352{
3d9d7cc4 353 return wxSize(20,20);
4ed7af08
RR
354}
355
f554a14b 356// ---------------------------------------------------------
4ed7af08 357// wxDataViewProgressCell
f554a14b 358// ---------------------------------------------------------
4ed7af08
RR
359
360IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell, wxDataViewCustomCell)
361
f554a14b 362wxDataViewProgressCell::wxDataViewProgressCell( const wxString &label,
4ed7af08 363 const wxString &varianttype, wxDataViewCellMode mode ) :
f554a14b 364 wxDataViewCustomCell( varianttype, mode )
4ed7af08
RR
365{
366 m_label = label;
367 m_value = 0;
368}
369
370wxDataViewProgressCell::~wxDataViewProgressCell()
371{
372}
373
374bool wxDataViewProgressCell::SetValue( const wxVariant &value )
375{
376 m_value = (long) value;
f554a14b 377
4ed7af08
RR
378 if (m_value < 0) m_value = 0;
379 if (m_value > 100) m_value = 100;
f554a14b 380
4ed7af08
RR
381 return true;
382}
f554a14b
WS
383
384bool wxDataViewProgressCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
385{
386 double pct = (double)m_value / 100.0;
387 wxRect bar = cell;
388 bar.width = (int)(cell.width * pct);
389 dc->SetPen( *wxTRANSPARENT_PEN );
390 dc->SetBrush( *wxBLUE_BRUSH );
391 dc->DrawRectangle( bar );
392
393 dc->SetBrush( *wxTRANSPARENT_BRUSH );
394 dc->SetPen( *wxBLACK_PEN );
395 dc->DrawRectangle( cell );
f554a14b 396
4ed7af08
RR
397 return true;
398}
399
400wxSize wxDataViewProgressCell::GetSize()
401{
402 return wxSize(40,12);
403}
f554a14b
WS
404
405// ---------------------------------------------------------
4ed7af08 406// wxDataViewDateCell
f554a14b 407// ---------------------------------------------------------
4ed7af08
RR
408
409class wxDataViewDateCellPopupTransient: public wxPopupTransientWindow
410{
f554a14b 411public:
4ed7af08
RR
412 wxDataViewDateCellPopupTransient( wxWindow* parent, wxDateTime *value,
413 wxDataViewListModel *model, size_t col, size_t row ) :
414 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
415 {
416 m_model = model;
417 m_col = col;
418 m_row = row;
f554a14b 419 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
4ed7af08
RR
420 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
421 sizer->Add( m_cal, 1, wxGROW );
422 SetSizer( sizer );
423 sizer->Fit( this );
424 }
f554a14b 425
4ed7af08
RR
426 virtual void OnDismiss()
427 {
428 }
f554a14b 429
4ed7af08 430 void OnCalendar( wxCalendarEvent &event );
f554a14b 431
4ed7af08 432 wxCalendarCtrl *m_cal;
f554a14b 433 wxDataViewListModel *m_model;
4ed7af08
RR
434 size_t m_col;
435 size_t m_row;
f554a14b 436
4ed7af08
RR
437private:
438 DECLARE_EVENT_TABLE()
439};
440
441BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient,wxPopupTransientWindow)
f554a14b 442 EVT_CALENDAR( wxID_ANY, wxDataViewDateCellPopupTransient::OnCalendar )
4ed7af08
RR
443END_EVENT_TABLE()
444
445void wxDataViewDateCellPopupTransient::OnCalendar( wxCalendarEvent &event )
446{
447 wxDateTime date = event.GetDate();
448 wxVariant value = date;
449 m_model->SetValue( value, m_col, m_row );
450 m_model->ValueChanged( m_col, m_row );
451 DismissAndNotify();
452}
453
454IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell, wxDataViewCustomCell)
455
456wxDataViewDateCell::wxDataViewDateCell( const wxString &varianttype,
457 wxDataViewCellMode mode ) :
458 wxDataViewCustomCell( varianttype, mode )
459{
460}
f554a14b 461
4ed7af08
RR
462bool wxDataViewDateCell::SetValue( const wxVariant &value )
463{
464 m_date = value.GetDateTime();
f554a14b 465
4ed7af08
RR
466 return true;
467}
468
f554a14b 469bool wxDataViewDateCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
470{
471 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
472 wxString tmp = m_date.FormatDate();
473 dc->DrawText( tmp, cell.x, cell.y );
474
475 return true;
476}
477
478wxSize wxDataViewDateCell::GetSize()
479{
480 wxDataViewCtrl* view = GetOwner()->GetOwner();
481 wxString tmp = m_date.FormatDate();
482 wxCoord x,y,d;
483 view->GetTextExtent( tmp, &x, &y, &d );
484 return wxSize(x,y+d);
485}
486
f554a14b 487bool wxDataViewDateCell::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, size_t col, size_t row )
4ed7af08
RR
488{
489 wxVariant variant;
490 model->GetValue( variant, col, row );
491 wxDateTime value = variant.GetDateTime();
492
f554a14b 493 wxDataViewDateCellPopupTransient *popup = new wxDataViewDateCellPopupTransient(
4ed7af08
RR
494 GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
495 wxPoint pos = wxGetMousePosition();
496 popup->Move( pos );
497 popup->Layout();
498 popup->Popup( popup->m_cal );
499
500 return true;
501}
502
f554a14b 503// ---------------------------------------------------------
4ed7af08 504// wxDataViewColumn
f554a14b 505// ---------------------------------------------------------
4ed7af08
RR
506
507IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
508
f554a14b 509wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewCell *cell,
4ed7af08
RR
510 size_t model_column, int flags ) :
511 wxDataViewColumnBase( title, cell, model_column, flags )
512{
4b3feaa7 513 m_width = 80;
4ed7af08
RR
514}
515
516wxDataViewColumn::~wxDataViewColumn()
517{
518}
519
520void wxDataViewColumn::SetTitle( const wxString &title )
521{
522 wxDataViewColumnBase::SetTitle( title );
f554a14b 523
4ed7af08
RR
524}
525
526//-----------------------------------------------------------------------------
527// wxDataViewHeaderWindow
528//-----------------------------------------------------------------------------
529
45778c96 530IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow)
4ed7af08
RR
531
532BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow)
533 EVT_PAINT (wxDataViewHeaderWindow::OnPaint)
534 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse)
535 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus)
536END_EVENT_TABLE()
537
538wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id,
539 const wxPoint &pos, const wxSize &size, const wxString &name ) :
540 wxWindow( parent, id, pos, size, 0, name )
541{
542 SetOwner( parent );
4b3feaa7 543
4ed7af08 544 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
f554a14b 545
4ed7af08
RR
546 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
547 SetOwnForegroundColour( attr.colFg );
548 SetOwnBackgroundColour( attr.colBg );
549 if (!m_hasFont)
550 SetOwnFont( attr.font );
551}
552
553wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
554{
555 delete m_resizeCursor;
556}
557
f554a14b 558void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 559{
4b3feaa7
RR
560 int w, h;
561 GetClientSize( &w, &h );
562
563 wxPaintDC dc( this );
f554a14b 564
4ed7af08
RR
565 int xpix;
566 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
567
568 int x;
569 m_owner->GetViewStart( &x, NULL );
570
571 // account for the horz scrollbar offset
572 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 573
4ed7af08 574 dc.SetFont( GetFont() );
f554a14b 575
4b3feaa7
RR
576 size_t cols = GetOwner()->GetNumberOfColumns();
577 size_t i;
578 int xpos = 0;
579 for (i = 0; i < cols; i++)
580 {
581 wxDataViewColumn *col = GetOwner()->GetColumn( i );
582 int width = col->GetWidth();
f554a14b 583
4b3feaa7
RR
584 // the width of the rect to draw: make it smaller to fit entirely
585 // inside the column rect
586#ifdef __WXMAC__
587 int cw = width;
588 int ch = h;
589#else
590 int cw = width - 2;
591 int ch = h - 2;
592#endif
593
594 wxRendererNative::Get().DrawHeaderButton
595 (
596 this,
597 dc,
598 wxRect(xpos, 0, cw, ch),
599 m_parent->IsEnabled() ? 0
600 : (int)wxCONTROL_DISABLED
601 );
602
f554a14b
WS
603 dc.DrawText( col->GetTitle(), xpos+3, 3 );
604
4b3feaa7
RR
605 xpos += width;
606 }
4ed7af08
RR
607}
608
f554a14b 609void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
4ed7af08
RR
610{
611}
612
613void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
614{
615 event.Skip();
616}
617
0fcce6b9
RR
618//-----------------------------------------------------------------------------
619// wxDataViewRenameTimer
620//-----------------------------------------------------------------------------
621
622wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
623{
624 m_owner = owner;
625}
626
627void wxDataViewRenameTimer::Notify()
628{
629 m_owner->OnRenameTimer();
630}
631
632//-----------------------------------------------------------------------------
633// wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
634//-----------------------------------------------------------------------------
635
636BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler)
637 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar)
638 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp)
639 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus)
640END_EVENT_TABLE()
641
642wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
643 wxDataViewMainWindow *owner,
644 wxTextCtrl *text,
645 wxDataViewListModel *model,
646 size_t col, size_t row,
647 wxRect rectLabel )
648{
649 m_owner = owner;
650 m_model = model;
651 m_row = row;
652 m_col = col;
653 m_text = text;
654
655 m_finished = false;
656 m_aboutToFinish = false;
657
658 wxVariant value;
659 model->GetValue( value, col, row );
660 m_startValue = value.GetString();
661
662 m_owner->GetOwner()->CalcScrolledPosition(
663 rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y );
664
665 m_text->Create( owner, wxID_ANY, m_startValue,
666 wxPoint(rectLabel.x-2,rectLabel.y-2),
667 wxSize(rectLabel.width+7,rectLabel.height+4) );
668 m_text->SetFocus();
669
670 m_text->PushEventHandler(this);
671}
672
673void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
674{
675 m_aboutToFinish = true;
676
677 // Notify the owner about the changes
678 AcceptChanges();
679
680 // Even if vetoed, close the control (consistent with MSW)
681 Finish();
682}
683
684void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event )
685{
686 switch ( event.m_keyCode )
687 {
688 case WXK_RETURN:
689 AcceptChangesAndFinish();
690 break;
691
692 case WXK_ESCAPE:
693 // m_owner->OnRenameCancelled( m_itemEdited );
694 Finish();
695 break;
696
697 default:
698 event.Skip();
699 }
700}
701
702void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
703{
704 if (m_finished)
705 {
706 event.Skip();
707 return;
708 }
709
710 // auto-grow the textctrl
711 wxSize parentSize = m_owner->GetSize();
712 wxPoint myPos = m_text->GetPosition();
713 wxSize mySize = m_text->GetSize();
714 int sx, sy;
715 m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
716 if (myPos.x + sx > parentSize.x)
717 sx = parentSize.x - myPos.x;
718 if (mySize.x > sx)
719 sx = mySize.x;
720 m_text->SetSize(sx, wxDefaultCoord);
721
722 event.Skip();
723}
724
725void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
726{
727 if ( !m_finished && !m_aboutToFinish )
728 {
729 AcceptChanges();
730 //if ( !AcceptChanges() )
731 // m_owner->OnRenameCancelled( m_itemEdited );
732
733 Finish();
734 }
735
736 // We must let the native text control handle focus
737 event.Skip();
738}
739
740bool wxDataViewTextCtrlWrapper::AcceptChanges()
741{
742 const wxString value = m_text->GetValue();
743
744 if ( value == m_startValue )
745 // nothing changed, always accept
746 return true;
747
748// if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
749 // vetoed by the user
750// return false;
751
752 // accepted, do rename the item
753 wxVariant variant;
754 variant = value;
755 m_model->SetValue( variant, m_col, m_row );
756 m_model->ValueChanged( m_col, m_row );
757
758 return true;
759}
760
761void wxDataViewTextCtrlWrapper::Finish()
762{
763 if ( !m_finished )
764 {
765 m_finished = true;
766
767 m_text->RemoveEventHandler(this);
768 m_owner->FinishEditing(m_text);
769
770 // delete later
771 wxPendingDelete.Append( this );
772 }
773}
774
4ed7af08
RR
775//-----------------------------------------------------------------------------
776// wxDataViewMainWindow
777//-----------------------------------------------------------------------------
778
45778c96 779IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
780
781BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
782 EVT_PAINT (wxDataViewMainWindow::OnPaint)
783 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
784 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
785END_EVENT_TABLE()
786
787wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
788 const wxPoint &pos, const wxSize &size, const wxString &name ) :
789 wxWindow( parent, id, pos, size, 0, name )
790{
791 SetOwner( parent );
f554a14b 792
0fcce6b9
RR
793 m_lastOnSame = false;
794 m_renameTimer = new wxDataViewRenameTimer( this );
795 m_textctrlWrapper = NULL;
796
797 // TODO: user better initial values/nothing selected
798 m_currentCol = NULL;
799 m_currentRow = 0;
800
801 // TODO: we need to calculate this smartly
4b3feaa7 802 m_lineHeight = 20;
f554a14b 803
4b3feaa7 804 UpdateDisplay();
4ed7af08
RR
805}
806
807wxDataViewMainWindow::~wxDataViewMainWindow()
808{
0fcce6b9
RR
809 delete m_renameTimer;
810}
811
812void wxDataViewMainWindow::OnRenameTimer()
813{
814 // We have to call this here because changes may just have
815 // been made and no screen update taken place.
816 if ( m_dirty )
817 wxSafeYield();
818
819
820 int xpos = 0;
821 size_t cols = GetOwner()->GetNumberOfColumns();
822 size_t i;
823 for (i = 0; i < cols; i++)
824 {
825 wxDataViewColumn *c = GetOwner()->GetColumn( i );
826 if (c == m_currentCol)
827 break;
828 xpos += c->GetWidth();
829 }
830 wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight );
831
832 wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl);
833
834 wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
835 m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(),
836 m_currentCol->GetModelColumn(), m_currentRow, labelRect );
837}
838
839void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text )
840{
841 delete text;
842 m_textctrlWrapper = NULL;
843 SetFocus();
844 // SetFocusIgnoringChildren();
4ed7af08
RR
845}
846
a0f3af5f
RR
847bool wxDataViewMainWindow::RowAppended()
848{
849 return false;
850}
851
852bool wxDataViewMainWindow::RowPrepended()
853{
854 return false;
855}
856
f554a14b 857bool wxDataViewMainWindow::RowInserted( size_t WXUNUSED(before) )
a0f3af5f
RR
858{
859 return false;
860}
861
f554a14b 862bool wxDataViewMainWindow::RowDeleted( size_t WXUNUSED(row) )
a0f3af5f
RR
863{
864 return false;
865}
866
f554a14b 867bool wxDataViewMainWindow::RowChanged( size_t WXUNUSED(row) )
a0f3af5f
RR
868{
869 return false;
870}
871
f554a14b 872bool wxDataViewMainWindow::ValueChanged( size_t WXUNUSED(col), size_t row )
a0f3af5f 873{
0fdc2321
RR
874 wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
875 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
876 Refresh( true, &rect );
877
878 return true;
a0f3af5f
RR
879}
880
f554a14b 881bool wxDataViewMainWindow::RowsReordered( size_t *WXUNUSED(new_order) )
a0f3af5f 882{
0fcce6b9
RR
883 Refresh();
884
885 return true;
a0f3af5f
RR
886}
887
888bool wxDataViewMainWindow::Cleared()
889{
890 return false;
891}
892
4b3feaa7
RR
893void wxDataViewMainWindow::UpdateDisplay()
894{
895 m_dirty = true;
896}
897
898void wxDataViewMainWindow::OnInternalIdle()
899{
900 wxWindow::OnInternalIdle();
f554a14b 901
4b3feaa7
RR
902 if (m_dirty)
903 {
904 RecalculateDisplay();
905 m_dirty = false;
906 }
907}
908
909void wxDataViewMainWindow::RecalculateDisplay()
910{
911 wxDataViewListModel *model = GetOwner()->GetModel();
912 if (!model)
913 {
914 Refresh();
915 return;
916 }
f554a14b 917
4b3feaa7
RR
918 int width = 0;
919 size_t cols = GetOwner()->GetNumberOfColumns();
920 size_t i;
921 for (i = 0; i < cols; i++)
922 {
923 wxDataViewColumn *col = GetOwner()->GetColumn( i );
924 width += col->GetWidth();
925 }
f554a14b 926
4b3feaa7
RR
927 int height = model->GetNumberOfRows() * m_lineHeight;
928
929 SetVirtualSize( width, height );
930 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 931
4b3feaa7
RR
932 Refresh();
933}
934
935void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
936{
937 wxWindow::ScrollWindow( dx, dy, rect );
938 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
939}
940
f554a14b 941void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08
RR
942{
943 wxPaintDC dc( this );
944
4b3feaa7 945 GetOwner()->PrepareDC( dc );
4ed7af08
RR
946
947 dc.SetFont( GetFont() );
90675b95
RR
948
949 wxRect update = GetUpdateRegion().GetBox();
950 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
f554a14b 951
90675b95 952 wxDataViewListModel *model = GetOwner()->GetModel();
f554a14b 953
0fcce6b9
RR
954 size_t item_start = wxMax( 0, update.y / m_lineHeight );
955 size_t item_count = wxMin( (update.height / m_lineHeight) + 1,
956 (int)(model->GetNumberOfRows()-item_start) );
90675b95
RR
957
958 wxRect cell_rect;
959 cell_rect.x = 0;
960 cell_rect.height = m_lineHeight;
961 size_t cols = GetOwner()->GetNumberOfColumns();
962 size_t i;
963 for (i = 0; i < cols; i++)
964 {
965 wxDataViewColumn *col = GetOwner()->GetColumn( i );
966 wxDataViewCell *cell = col->GetCell();
967 cell_rect.width = col->GetWidth();
f554a14b 968
90675b95 969 size_t item;
0fcce6b9 970 for (item = item_start; item < item_start+item_count; item++)
90675b95
RR
971 {
972 cell_rect.y = item*m_lineHeight;
973 wxVariant value;
974 model->GetValue( value, col->GetModelColumn(), item );
975 cell->SetValue( value );
4064f7de
RR
976 wxSize size = cell->GetSize();
977 // cannot be bigger than allocated space
978 size.x = wxMin( size.x, cell_rect.width );
979 size.y = wxMin( size.y, cell_rect.height );
980 // TODO: check for left/right/centre alignment here
981 wxRect item_rect;
982 // for now: centre
983 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
984 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
f554a14b 985
4064f7de
RR
986 item_rect.width = size.x;
987 item_rect.height= size.y;
988 cell->Render( item_rect, &dc, 0 );
90675b95 989 }
f554a14b 990
90675b95
RR
991 cell_rect.x += cell_rect.width;
992 }
4ed7af08
RR
993}
994
995void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
996{
0fdc2321
RR
997 int x = event.GetX();
998 int y = event.GetY();
999 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1000
1001 wxDataViewColumn *col = NULL;
1002
1003 int xpos = 0;
1004 size_t cols = GetOwner()->GetNumberOfColumns();
1005 size_t i;
1006 for (i = 0; i < cols; i++)
1007 {
1008 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1009 if (x < xpos + c->GetWidth())
1010 {
1011 col = c;
1012 break;
1013 }
1014 xpos += c->GetWidth();
1015 }
f554a14b 1016 if (!col)
0fdc2321
RR
1017 return;
1018 wxDataViewCell *cell = col->GetCell();
f554a14b 1019
0fdc2321 1020 size_t row = y / m_lineHeight;
f554a14b 1021
0fdc2321
RR
1022 wxDataViewListModel *model = GetOwner()->GetModel();
1023
0fcce6b9
RR
1024 if (event.ButtonDClick())
1025 {
1026 m_renameTimer->Stop();
1027 m_lastOnSame = false;
1028 }
1029
0fdc2321
RR
1030 if (event.LeftDClick())
1031 {
1032 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
1033 {
1034 wxVariant value;
1035 model->GetValue( value, col->GetModelColumn(), row );
1036 cell->SetValue( value );
1037 wxRect cell_rect( xpos, row * m_lineHeight, col->GetWidth(), m_lineHeight );
1038 cell->Activate( cell_rect, model, col->GetModelColumn(), row );
1039 }
f554a14b 1040
0fcce6b9
RR
1041 return;
1042 } else
1043 if (event.LeftUp())
1044 {
1045 if (m_lastOnSame)
1046 {
1047 if ((col == m_currentCol) & (row == m_currentRow) &&
1048 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
1049 {
1050 m_renameTimer->Start( 100, true );
1051 }
1052 }
1053
1054 m_lastOnSame = false;
1055 } else
1056 if (event.LeftDown())
1057 {
1058 wxDataViewColumn *oldCurrentCol = m_currentCol;
1059 size_t oldCurrentRow = m_currentRow;
1060
1061 // Update selection here...
1062 m_currentCol = col;
1063 m_currentRow = row;
1064
1065 m_lastOnSame = (col == oldCurrentCol) && (row == oldCurrentRow);
1066
0fdc2321
RR
1067 return;
1068 }
1069
4ed7af08
RR
1070 event.Skip();
1071}
1072
1073void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
1074{
1075 event.Skip();
1076}
1077
1078//-----------------------------------------------------------------------------
1079// wxDataViewCtrl
1080//-----------------------------------------------------------------------------
1081
1082IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1083
4b3feaa7
RR
1084BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
1085 EVT_SIZE(wxDataViewCtrl::OnSize)
1086END_EVENT_TABLE()
1087
4ed7af08
RR
1088wxDataViewCtrl::~wxDataViewCtrl()
1089{
1090 if (m_notifier)
1091 GetModel()->RemoveNotifier( m_notifier );
1092}
1093
1094void wxDataViewCtrl::Init()
1095{
1096 m_notifier = NULL;
1097}
1098
1099bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 1100 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
1101 long style, const wxValidator& validator )
1102{
4b3feaa7
RR
1103 if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
1104 return false;
1105
4ed7af08 1106 Init();
f554a14b 1107
4ed7af08
RR
1108#ifdef __WXMAC__
1109 MacSetClipChildren( true ) ;
1110#endif
1111
f554a14b
WS
1112 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
1113 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) );
1114
4ed7af08 1115 SetTargetWindow( m_clientArea );
f554a14b 1116
4ed7af08
RR
1117 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1118 sizer->Add( m_headerArea, 0, wxGROW );
1119 sizer->Add( m_clientArea, 1, wxGROW );
1120 SetSizer( sizer );
1121
1122 return true;
1123}
1124
1125#ifdef __WXMSW__
1126WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
1127 WXWPARAM wParam,
1128 WXLPARAM lParam)
1129{
b910a8ad 1130 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
1131
1132#ifndef __WXWINCE__
1133 // we need to process arrows ourselves for scrolling
1134 if ( nMsg == WM_GETDLGCODE )
1135 {
1136 rc |= DLGC_WANTARROWS;
1137 }
1138#endif
1139
1140 return rc;
1141}
1142#endif
1143
f554a14b 1144void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 1145{
4b3feaa7
RR
1146 // We need to override OnSize so that our scrolled
1147 // window a) does call Layout() to use sizers for
1148 // positioning the controls but b) does not query
1149 // the sizer for their size and use that for setting
1150 // the scrollable area as set that ourselves by
1151 // calling SetScrollbar() further down.
1152
1153 Layout();
1154
1155 AdjustScrollbars();
4ed7af08
RR
1156}
1157
1158bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1159{
1160 if (!wxDataViewCtrlBase::AssociateModel( model ))
1161 return false;
1162
a0f3af5f 1163 m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea );
4ed7af08 1164
f554a14b 1165 model->AddNotifier( m_notifier );
4ed7af08 1166
4b3feaa7 1167 m_clientArea->UpdateDisplay();
f554a14b 1168
4ed7af08
RR
1169 return true;
1170}
1171
1172bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1173{
1174 if (!wxDataViewCtrlBase::AppendColumn(col))
1175 return false;
f554a14b 1176
4b3feaa7 1177 m_clientArea->UpdateDisplay();
f554a14b 1178
4ed7af08
RR
1179 return true;
1180}
1181
f554a14b 1182#endif
4ed7af08
RR
1183 // !wxUSE_GENERICDATAVIEWCTRL
1184
f554a14b 1185#endif
4ed7af08
RR
1186 // wxUSE_DATAVIEWCTRL
1187