Lots of selection and focus code.
[wxWidgets.git] / src / generic / datavgen.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/datavgen.cpp
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
13 #if wxUSE_DATAVIEWCTRL
14
15 #include "wx/dataview.h"
16
17 #ifdef wxUSE_GENERICDATAVIEWCTRL
18
19 #ifndef WX_PRECOMP
20 #include "wx/sizer.h"
21 #include "wx/log.h"
22 #endif
23
24 #include "wx/stockitem.h"
25 #include "wx/dcclient.h"
26 #include "wx/calctrl.h"
27 #include "wx/popupwin.h"
28 #include "wx/renderer.h"
29 #include "wx/timer.h"
30 #include "wx/settings.h"
31
32 #ifdef __WXMSW__
33 #include "wx/msw/wrapwin.h"
34 #endif
35
36 //-----------------------------------------------------------------------------
37 // classes
38 //-----------------------------------------------------------------------------
39
40 class wxDataViewCtrl;
41
42 //-----------------------------------------------------------------------------
43 // wxDataViewHeaderWindow
44 //-----------------------------------------------------------------------------
45
46 class wxDataViewHeaderWindow: public wxWindow
47 {
48 public:
49 wxDataViewHeaderWindow( wxDataViewCtrl *parent,
50 wxWindowID id,
51 const wxPoint &pos = wxDefaultPosition,
52 const wxSize &size = wxDefaultSize,
53 const wxString &name = wxT("wxdataviewctrlheaderwindow") );
54 ~wxDataViewHeaderWindow();
55
56 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
57 wxDataViewCtrl *GetOwner() { return m_owner; }
58
59 void OnPaint( wxPaintEvent &event );
60 void OnMouse( wxMouseEvent &event );
61 void OnSetFocus( wxFocusEvent &event );
62
63 private:
64 wxDataViewCtrl *m_owner;
65 wxCursor *m_resizeCursor;
66
67 private:
68 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow)
69 DECLARE_EVENT_TABLE()
70 };
71
72 //-----------------------------------------------------------------------------
73 // wxDataViewRenameTimer
74 //-----------------------------------------------------------------------------
75
76 class wxDataViewRenameTimer: public wxTimer
77 {
78 private:
79 wxDataViewMainWindow *m_owner;
80
81 public:
82 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
83 void Notify();
84 };
85
86 //-----------------------------------------------------------------------------
87 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
88 //-----------------------------------------------------------------------------
89
90 class wxDataViewTextCtrlWrapper : public wxEvtHandler
91 {
92 public:
93 // NB: text must be a valid object but not Create()d yet
94 wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner,
95 wxTextCtrl *text,
96 wxDataViewListModel *model,
97 size_t col, size_t row,
98 wxRect cellLabel );
99
100 wxTextCtrl *GetText() const { return m_text; }
101
102 void AcceptChangesAndFinish();
103
104 protected:
105 void OnChar( wxKeyEvent &event );
106 void OnKeyUp( wxKeyEvent &event );
107 void OnKillFocus( wxFocusEvent &event );
108
109 bool AcceptChanges();
110 void Finish();
111
112 private:
113 wxDataViewMainWindow *m_owner;
114 wxTextCtrl *m_text;
115 wxString m_startValue;
116 wxDataViewListModel *m_model;
117 size_t m_col;
118 size_t m_row;
119 bool m_finished;
120 bool m_aboutToFinish;
121
122 DECLARE_EVENT_TABLE()
123 };
124
125 //-----------------------------------------------------------------------------
126 // wxDataViewMainWindow
127 //-----------------------------------------------------------------------------
128
129 WX_DEFINE_SORTED_ARRAY_SIZE_T( size_t, wxDataViewSelection );
130
131 class wxDataViewMainWindow: public wxWindow
132 {
133 public:
134 wxDataViewMainWindow( wxDataViewCtrl *parent,
135 wxWindowID id,
136 const wxPoint &pos = wxDefaultPosition,
137 const wxSize &size = wxDefaultSize,
138 const wxString &name = wxT("wxdataviewctrlmainwindow") );
139 ~wxDataViewMainWindow();
140
141 // notifications from wxDataViewListModel
142 bool RowAppended();
143 bool RowPrepended();
144 bool RowInserted( size_t before );
145 bool RowDeleted( size_t row );
146 bool RowChanged( size_t row );
147 bool ValueChanged( size_t col, size_t row );
148 bool RowsReordered( size_t *new_order );
149 bool Cleared();
150
151 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
152 wxDataViewCtrl *GetOwner() { return m_owner; }
153
154 void OnPaint( wxPaintEvent &event );
155 void OnArrowChar(size_t newCurrent, const wxKeyEvent& event);
156 void OnChar( wxKeyEvent &event );
157 void OnMouse( wxMouseEvent &event );
158 void OnSetFocus( wxFocusEvent &event );
159 void OnKillFocus( wxFocusEvent &event );
160
161 void UpdateDisplay();
162 void RecalculateDisplay();
163 void OnInternalIdle();
164
165 void OnRenameTimer();
166 void FinishEditing( wxTextCtrl *text );
167
168 void ScrollWindow( int dx, int dy, const wxRect *rect );
169
170 bool HasCurrentRow() { return m_currentRow != (size_t)-1; }
171
172 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); };
173 bool IsEmpty() { return GetRowCount() == 0; }
174
175 int GetCountPerPage();
176 int GetRowCount();
177
178 void SelectAllRows( bool on );
179 void SelectRow( size_t row, bool on );
180 void SelectRows( size_t from, size_t to, bool on );
181 void ReverseRowSelection( size_t row );
182 bool IsRowSelected( size_t row );
183
184 void RefreshRow( size_t row );
185 void RefreshRows( size_t from, size_t to );
186 void RefreshRowsAfter( size_t firstRow );
187
188 private:
189 wxDataViewCtrl *m_owner;
190 int m_lineHeight;
191 bool m_dirty;
192
193 wxDataViewColumn *m_currentCol;
194 size_t m_currentRow;
195 wxDataViewSelection m_selection;
196
197 wxDataViewRenameTimer *m_renameTimer;
198 wxDataViewTextCtrlWrapper *m_textctrlWrapper;
199 bool m_lastOnSame;
200
201 wxBrush *m_highlightBrush,
202 *m_highlightUnfocusedBrush;
203 bool m_hasFocus;
204
205
206 private:
207 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
208 DECLARE_EVENT_TABLE()
209 };
210
211 // ---------------------------------------------------------
212 // wxGenericDataViewListModelNotifier
213 // ---------------------------------------------------------
214
215 class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier
216 {
217 public:
218 wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow )
219 { m_mainWindow = mainWindow; }
220
221 virtual bool RowAppended()
222 { return m_mainWindow->RowAppended(); }
223 virtual bool RowPrepended()
224 { return m_mainWindow->RowPrepended(); }
225 virtual bool RowInserted( size_t before )
226 { return m_mainWindow->RowInserted( before ); }
227 virtual bool RowDeleted( size_t row )
228 { return m_mainWindow->RowDeleted( row ); }
229 virtual bool RowChanged( size_t row )
230 { return m_mainWindow->RowChanged( row ); }
231 virtual bool ValueChanged( size_t col, size_t row )
232 { return m_mainWindow->ValueChanged( col, row ); }
233 virtual bool RowsReordered( size_t *new_order )
234 { return m_mainWindow->RowsReordered( new_order ); }
235 virtual bool Cleared()
236 { return m_mainWindow->Cleared(); }
237
238 wxDataViewMainWindow *m_mainWindow;
239 };
240
241 // ---------------------------------------------------------
242 // wxDataViewCell
243 // ---------------------------------------------------------
244
245 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCell, wxDataViewCellBase)
246
247 wxDataViewCell::wxDataViewCell( const wxString &varianttype, wxDataViewCellMode mode ) :
248 wxDataViewCellBase( varianttype, mode )
249 {
250 m_dc = NULL;
251 }
252
253 wxDataViewCell::~wxDataViewCell()
254 {
255 if (m_dc)
256 delete m_dc;
257 }
258
259 wxDC *wxDataViewCell::GetDC()
260 {
261 if (m_dc == NULL)
262 {
263 if (GetOwner() == NULL)
264 return NULL;
265 if (GetOwner()->GetOwner() == NULL)
266 return NULL;
267 m_dc = new wxClientDC( GetOwner()->GetOwner() );
268 }
269
270 return m_dc;
271 }
272
273 // ---------------------------------------------------------
274 // wxDataViewCustomCell
275 // ---------------------------------------------------------
276
277 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomCell, wxDataViewCell)
278
279 wxDataViewCustomCell::wxDataViewCustomCell( const wxString &varianttype,
280 wxDataViewCellMode mode ) :
281 wxDataViewCell( varianttype, mode )
282 {
283 }
284
285 // ---------------------------------------------------------
286 // wxDataViewTextCell
287 // ---------------------------------------------------------
288
289 IMPLEMENT_ABSTRACT_CLASS(wxDataViewTextCell, wxDataViewCustomCell)
290
291 wxDataViewTextCell::wxDataViewTextCell( const wxString &varianttype, wxDataViewCellMode mode ) :
292 wxDataViewCustomCell( varianttype, mode )
293 {
294 }
295
296 bool wxDataViewTextCell::SetValue( const wxVariant &value )
297 {
298 m_text = value.GetString();
299
300 return true;
301 }
302
303 bool wxDataViewTextCell::GetValue( wxVariant& WXUNUSED(value) )
304 {
305 return false;
306 }
307
308 bool wxDataViewTextCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
309 {
310 dc->DrawText( m_text, cell.x, cell.y );
311
312 return true;
313 }
314
315 wxSize wxDataViewTextCell::GetSize()
316 {
317 return wxSize(80,20);
318 }
319
320 // ---------------------------------------------------------
321 // wxDataViewToggleCell
322 // ---------------------------------------------------------
323
324 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleCell, wxDataViewCustomCell)
325
326 wxDataViewToggleCell::wxDataViewToggleCell( const wxString &varianttype,
327 wxDataViewCellMode mode ) :
328 wxDataViewCustomCell( varianttype, mode )
329 {
330 m_toggle = false;
331 }
332
333 bool wxDataViewToggleCell::SetValue( const wxVariant &value )
334 {
335 m_toggle = value.GetBool();
336
337 return true;;
338 }
339
340 bool wxDataViewToggleCell::GetValue( wxVariant &WXUNUSED(value) )
341 {
342 return false;
343 }
344
345 bool wxDataViewToggleCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
346 {
347 // User wxRenderer here
348
349 wxRect rect;
350 rect.x = cell.x + cell.width/2 - 10;
351 rect.width = 20;
352 rect.y = cell.y + cell.height/2 - 10;
353 rect.height = 20;
354
355 int flags = 0;
356 if (m_toggle)
357 flags |= wxCONTROL_CHECKED;
358 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
359 flags |= wxCONTROL_DISABLED;
360
361 wxRendererNative::Get().DrawCheckButton(
362 GetOwner()->GetOwner(),
363 *dc,
364 rect,
365 flags );
366
367 return true;
368 }
369
370 bool wxDataViewToggleCell::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, size_t col, size_t row )
371 {
372 bool value = !m_toggle;
373 wxVariant variant = value;
374 model->SetValue( variant, col, row );
375 model->ValueChanged( col, row );
376 return true;
377 }
378
379 wxSize wxDataViewToggleCell::GetSize()
380 {
381 return wxSize(20,20);
382 }
383
384 // ---------------------------------------------------------
385 // wxDataViewProgressCell
386 // ---------------------------------------------------------
387
388 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressCell, wxDataViewCustomCell)
389
390 wxDataViewProgressCell::wxDataViewProgressCell( const wxString &label,
391 const wxString &varianttype, wxDataViewCellMode mode ) :
392 wxDataViewCustomCell( varianttype, mode )
393 {
394 m_label = label;
395 m_value = 0;
396 }
397
398 wxDataViewProgressCell::~wxDataViewProgressCell()
399 {
400 }
401
402 bool wxDataViewProgressCell::SetValue( const wxVariant &value )
403 {
404 m_value = (long) value;
405
406 if (m_value < 0) m_value = 0;
407 if (m_value > 100) m_value = 100;
408
409 return true;
410 }
411
412 bool wxDataViewProgressCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
413 {
414 double pct = (double)m_value / 100.0;
415 wxRect bar = cell;
416 bar.width = (int)(cell.width * pct);
417 dc->SetPen( *wxTRANSPARENT_PEN );
418 dc->SetBrush( *wxBLUE_BRUSH );
419 dc->DrawRectangle( bar );
420
421 dc->SetBrush( *wxTRANSPARENT_BRUSH );
422 dc->SetPen( *wxBLACK_PEN );
423 dc->DrawRectangle( cell );
424
425 return true;
426 }
427
428 wxSize wxDataViewProgressCell::GetSize()
429 {
430 return wxSize(40,12);
431 }
432
433 // ---------------------------------------------------------
434 // wxDataViewDateCell
435 // ---------------------------------------------------------
436
437 class wxDataViewDateCellPopupTransient: public wxPopupTransientWindow
438 {
439 public:
440 wxDataViewDateCellPopupTransient( wxWindow* parent, wxDateTime *value,
441 wxDataViewListModel *model, size_t col, size_t row ) :
442 wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
443 {
444 m_model = model;
445 m_col = col;
446 m_row = row;
447 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
448 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
449 sizer->Add( m_cal, 1, wxGROW );
450 SetSizer( sizer );
451 sizer->Fit( this );
452 }
453
454 virtual void OnDismiss()
455 {
456 }
457
458 void OnCalendar( wxCalendarEvent &event );
459
460 wxCalendarCtrl *m_cal;
461 wxDataViewListModel *m_model;
462 size_t m_col;
463 size_t m_row;
464
465 private:
466 DECLARE_EVENT_TABLE()
467 };
468
469 BEGIN_EVENT_TABLE(wxDataViewDateCellPopupTransient,wxPopupTransientWindow)
470 EVT_CALENDAR( wxID_ANY, wxDataViewDateCellPopupTransient::OnCalendar )
471 END_EVENT_TABLE()
472
473 void wxDataViewDateCellPopupTransient::OnCalendar( wxCalendarEvent &event )
474 {
475 wxDateTime date = event.GetDate();
476 wxVariant value = date;
477 m_model->SetValue( value, m_col, m_row );
478 m_model->ValueChanged( m_col, m_row );
479 DismissAndNotify();
480 }
481
482 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateCell, wxDataViewCustomCell)
483
484 wxDataViewDateCell::wxDataViewDateCell( const wxString &varianttype,
485 wxDataViewCellMode mode ) :
486 wxDataViewCustomCell( varianttype, mode )
487 {
488 }
489
490 bool wxDataViewDateCell::SetValue( const wxVariant &value )
491 {
492 m_date = value.GetDateTime();
493
494 return true;
495 }
496
497 bool wxDataViewDateCell::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
498 {
499 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
500 wxString tmp = m_date.FormatDate();
501 dc->DrawText( tmp, cell.x, cell.y );
502
503 return true;
504 }
505
506 wxSize wxDataViewDateCell::GetSize()
507 {
508 wxDataViewCtrl* view = GetOwner()->GetOwner();
509 wxString tmp = m_date.FormatDate();
510 wxCoord x,y,d;
511 view->GetTextExtent( tmp, &x, &y, &d );
512 return wxSize(x,y+d);
513 }
514
515 bool wxDataViewDateCell::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, size_t col, size_t row )
516 {
517 wxVariant variant;
518 model->GetValue( variant, col, row );
519 wxDateTime value = variant.GetDateTime();
520
521 wxDataViewDateCellPopupTransient *popup = new wxDataViewDateCellPopupTransient(
522 GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
523 wxPoint pos = wxGetMousePosition();
524 popup->Move( pos );
525 popup->Layout();
526 popup->Popup( popup->m_cal );
527
528 return true;
529 }
530
531 // ---------------------------------------------------------
532 // wxDataViewColumn
533 // ---------------------------------------------------------
534
535 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
536
537 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewCell *cell, size_t model_column,
538 int fixed_width, wxDataViewColumnSizing sizing, int flags ) :
539 wxDataViewColumnBase( title, cell, model_column, flags )
540 {
541 m_sizing = sizing;
542
543 m_width = fixed_width;
544 m_fixedWidth = fixed_width;
545 }
546
547 wxDataViewColumn::~wxDataViewColumn()
548 {
549 }
550
551 void wxDataViewColumn::SetTitle( const wxString &title )
552 {
553 wxDataViewColumnBase::SetTitle( title );
554
555 }
556
557 int wxDataViewColumn::GetWidth()
558 {
559 return m_width;
560 }
561
562 void wxDataViewColumn::SetFixedWidth( int width )
563 {
564 m_fixedWidth = width;
565
566 if (m_sizing == wxDATAVIEW_COL_WIDTH_FIXED)
567 {
568 m_width = width;
569 // Set dirty
570 }
571 }
572
573 int wxDataViewColumn::GetFixedWidth()
574 {
575 return m_fixedWidth;
576 }
577
578 //-----------------------------------------------------------------------------
579 // wxDataViewHeaderWindow
580 //-----------------------------------------------------------------------------
581
582 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow)
583
584 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow)
585 EVT_PAINT (wxDataViewHeaderWindow::OnPaint)
586 EVT_MOUSE_EVENTS (wxDataViewHeaderWindow::OnMouse)
587 EVT_SET_FOCUS (wxDataViewHeaderWindow::OnSetFocus)
588 END_EVENT_TABLE()
589
590 wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id,
591 const wxPoint &pos, const wxSize &size, const wxString &name ) :
592 wxWindow( parent, id, pos, size, 0, name )
593 {
594 SetOwner( parent );
595
596 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
597
598 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
599 SetOwnForegroundColour( attr.colFg );
600 SetOwnBackgroundColour( attr.colBg );
601 if (!m_hasFont)
602 SetOwnFont( attr.font );
603 }
604
605 wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
606 {
607 delete m_resizeCursor;
608 }
609
610 void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
611 {
612 int w, h;
613 GetClientSize( &w, &h );
614
615 wxPaintDC dc( this );
616
617 int xpix;
618 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
619
620 int x;
621 m_owner->GetViewStart( &x, NULL );
622
623 // account for the horz scrollbar offset
624 dc.SetDeviceOrigin( -x * xpix, 0 );
625
626 dc.SetFont( GetFont() );
627
628 size_t cols = GetOwner()->GetNumberOfColumns();
629 size_t i;
630 int xpos = 0;
631 for (i = 0; i < cols; i++)
632 {
633 wxDataViewColumn *col = GetOwner()->GetColumn( i );
634 int width = col->GetWidth();
635
636 // the width of the rect to draw: make it smaller to fit entirely
637 // inside the column rect
638 #ifdef __WXMAC__
639 int cw = width;
640 int ch = h;
641 #else
642 int cw = width - 2;
643 int ch = h - 2;
644 #endif
645
646 wxRendererNative::Get().DrawHeaderButton
647 (
648 this,
649 dc,
650 wxRect(xpos+1, 1, cw-1, ch-1),
651 m_parent->IsEnabled() ? 0
652 : (int)wxCONTROL_DISABLED
653 );
654
655 dc.DrawText( col->GetTitle(), xpos+3, 3 );
656
657 xpos += width;
658 }
659 }
660
661 void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
662 {
663 }
664
665 void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
666 {
667 GetParent()->SetFocus();
668 event.Skip();
669 }
670
671 //-----------------------------------------------------------------------------
672 // wxDataViewRenameTimer
673 //-----------------------------------------------------------------------------
674
675 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
676 {
677 m_owner = owner;
678 }
679
680 void wxDataViewRenameTimer::Notify()
681 {
682 m_owner->OnRenameTimer();
683 }
684
685 //-----------------------------------------------------------------------------
686 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
687 //-----------------------------------------------------------------------------
688
689 BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler)
690 EVT_CHAR (wxDataViewTextCtrlWrapper::OnChar)
691 EVT_KEY_UP (wxDataViewTextCtrlWrapper::OnKeyUp)
692 EVT_KILL_FOCUS (wxDataViewTextCtrlWrapper::OnKillFocus)
693 END_EVENT_TABLE()
694
695 wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
696 wxDataViewMainWindow *owner,
697 wxTextCtrl *text,
698 wxDataViewListModel *model,
699 size_t col, size_t row,
700 wxRect rectLabel )
701 {
702 m_owner = owner;
703 m_model = model;
704 m_row = row;
705 m_col = col;
706 m_text = text;
707
708 m_finished = false;
709 m_aboutToFinish = false;
710
711 wxVariant value;
712 model->GetValue( value, col, row );
713 m_startValue = value.GetString();
714
715 m_owner->GetOwner()->CalcScrolledPosition(
716 rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y );
717
718 m_text->Create( owner, wxID_ANY, m_startValue,
719 wxPoint(rectLabel.x-2,rectLabel.y-2),
720 wxSize(rectLabel.width+7,rectLabel.height+4) );
721 m_text->SetFocus();
722
723 m_text->PushEventHandler(this);
724 }
725
726 void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
727 {
728 m_aboutToFinish = true;
729
730 // Notify the owner about the changes
731 AcceptChanges();
732
733 // Even if vetoed, close the control (consistent with MSW)
734 Finish();
735 }
736
737 void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event )
738 {
739 switch ( event.m_keyCode )
740 {
741 case WXK_RETURN:
742 AcceptChangesAndFinish();
743 break;
744
745 case WXK_ESCAPE:
746 // m_owner->OnRenameCancelled( m_itemEdited );
747 Finish();
748 break;
749
750 default:
751 event.Skip();
752 }
753 }
754
755 void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
756 {
757 if (m_finished)
758 {
759 event.Skip();
760 return;
761 }
762
763 // auto-grow the textctrl
764 wxSize parentSize = m_owner->GetSize();
765 wxPoint myPos = m_text->GetPosition();
766 wxSize mySize = m_text->GetSize();
767 int sx, sy;
768 m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
769 if (myPos.x + sx > parentSize.x)
770 sx = parentSize.x - myPos.x;
771 if (mySize.x > sx)
772 sx = mySize.x;
773 m_text->SetSize(sx, wxDefaultCoord);
774
775 event.Skip();
776 }
777
778 void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
779 {
780 if ( !m_finished && !m_aboutToFinish )
781 {
782 AcceptChanges();
783 //if ( !AcceptChanges() )
784 // m_owner->OnRenameCancelled( m_itemEdited );
785
786 Finish();
787 }
788
789 // We must let the native text control handle focus
790 event.Skip();
791 }
792
793 bool wxDataViewTextCtrlWrapper::AcceptChanges()
794 {
795 const wxString value = m_text->GetValue();
796
797 if ( value == m_startValue )
798 // nothing changed, always accept
799 return true;
800
801 // if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
802 // vetoed by the user
803 // return false;
804
805 // accepted, do rename the item
806 wxVariant variant;
807 variant = value;
808 m_model->SetValue( variant, m_col, m_row );
809 m_model->ValueChanged( m_col, m_row );
810
811 return true;
812 }
813
814 void wxDataViewTextCtrlWrapper::Finish()
815 {
816 if ( !m_finished )
817 {
818 m_finished = true;
819
820 m_text->RemoveEventHandler(this);
821 m_owner->FinishEditing(m_text);
822
823 // delete later
824 wxPendingDelete.Append( this );
825 }
826 }
827
828 //-----------------------------------------------------------------------------
829 // wxDataViewMainWindow
830 //-----------------------------------------------------------------------------
831
832 int LINKAGEMODE wxDataViewSelectionCmp( size_t row1, size_t row2 )
833 {
834 if (row1 > row2) return 1;
835 if (row1 == row2) return 0;
836 return -1;
837 }
838
839
840 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
841
842 BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
843 EVT_PAINT (wxDataViewMainWindow::OnPaint)
844 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
845 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
846 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
847 EVT_CHAR (wxDataViewMainWindow::OnChar)
848 END_EVENT_TABLE()
849
850 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
851 const wxPoint &pos, const wxSize &size, const wxString &name ) :
852 wxWindow( parent, id, pos, size, 0, name ),
853 m_selection( wxDataViewSelectionCmp )
854
855 {
856 SetOwner( parent );
857
858 m_lastOnSame = false;
859 m_renameTimer = new wxDataViewRenameTimer( this );
860 m_textctrlWrapper = NULL;
861
862 // TODO: user better initial values/nothing selected
863 m_currentCol = NULL;
864 m_currentRow = 0;
865
866 // TODO: we need to calculate this smartly
867 m_lineHeight = 20;
868
869 m_highlightBrush = new wxBrush
870 (
871 wxSystemSettings::GetColour
872 (
873 wxSYS_COLOUR_HIGHLIGHT
874 ),
875 wxSOLID
876 );
877
878 m_highlightUnfocusedBrush = new wxBrush
879 (
880 wxSystemSettings::GetColour
881 (
882 wxSYS_COLOUR_BTNSHADOW
883 ),
884 wxSOLID
885 );
886
887 m_hasFocus = false;
888
889 UpdateDisplay();
890 }
891
892 wxDataViewMainWindow::~wxDataViewMainWindow()
893 {
894 delete m_renameTimer;
895 delete m_highlightBrush;
896 delete m_highlightUnfocusedBrush;
897 }
898
899 void wxDataViewMainWindow::OnRenameTimer()
900 {
901 // We have to call this here because changes may just have
902 // been made and no screen update taken place.
903 if ( m_dirty )
904 wxSafeYield();
905
906
907 int xpos = 0;
908 size_t cols = GetOwner()->GetNumberOfColumns();
909 size_t i;
910 for (i = 0; i < cols; i++)
911 {
912 wxDataViewColumn *c = GetOwner()->GetColumn( i );
913 if (c == m_currentCol)
914 break;
915 xpos += c->GetWidth();
916 }
917 wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight );
918
919 wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl);
920
921 wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
922 m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(),
923 m_currentCol->GetModelColumn(), m_currentRow, labelRect );
924 }
925
926 void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text )
927 {
928 delete text;
929 m_textctrlWrapper = NULL;
930 SetFocus();
931 // SetFocusIgnoringChildren();
932 }
933
934 bool wxDataViewMainWindow::RowAppended()
935 {
936 return false;
937 }
938
939 bool wxDataViewMainWindow::RowPrepended()
940 {
941 return false;
942 }
943
944 bool wxDataViewMainWindow::RowInserted( size_t WXUNUSED(before) )
945 {
946 return false;
947 }
948
949 bool wxDataViewMainWindow::RowDeleted( size_t WXUNUSED(row) )
950 {
951 return false;
952 }
953
954 bool wxDataViewMainWindow::RowChanged( size_t WXUNUSED(row) )
955 {
956 return false;
957 }
958
959 bool wxDataViewMainWindow::ValueChanged( size_t WXUNUSED(col), size_t row )
960 {
961 wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
962 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
963 Refresh( true, &rect );
964
965 return true;
966 }
967
968 bool wxDataViewMainWindow::RowsReordered( size_t *WXUNUSED(new_order) )
969 {
970 Refresh();
971
972 return true;
973 }
974
975 bool wxDataViewMainWindow::Cleared()
976 {
977 return false;
978 }
979
980 void wxDataViewMainWindow::UpdateDisplay()
981 {
982 m_dirty = true;
983 }
984
985 void wxDataViewMainWindow::OnInternalIdle()
986 {
987 wxWindow::OnInternalIdle();
988
989 if (m_dirty)
990 {
991 RecalculateDisplay();
992 m_dirty = false;
993 }
994 }
995
996 void wxDataViewMainWindow::RecalculateDisplay()
997 {
998 wxDataViewListModel *model = GetOwner()->GetModel();
999 if (!model)
1000 {
1001 Refresh();
1002 return;
1003 }
1004
1005 int width = 0;
1006 size_t cols = GetOwner()->GetNumberOfColumns();
1007 size_t i;
1008 for (i = 0; i < cols; i++)
1009 {
1010 wxDataViewColumn *col = GetOwner()->GetColumn( i );
1011 width += col->GetWidth();
1012 }
1013
1014 int height = model->GetNumberOfRows() * m_lineHeight;
1015
1016 SetVirtualSize( width, height );
1017 GetOwner()->SetScrollRate( 10, m_lineHeight );
1018
1019 Refresh();
1020 }
1021
1022 void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1023 {
1024 wxWindow::ScrollWindow( dx, dy, rect );
1025 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
1026 }
1027
1028 void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1029 {
1030 wxPaintDC dc( this );
1031
1032 GetOwner()->PrepareDC( dc );
1033
1034 dc.SetFont( GetFont() );
1035
1036 wxRect update = GetUpdateRegion().GetBox();
1037 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
1038
1039 wxDataViewListModel *model = GetOwner()->GetModel();
1040
1041 size_t item_start = wxMax( 0, (update.y / m_lineHeight) );
1042 size_t item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
1043 (int)(model->GetNumberOfRows()-item_start) );
1044
1045
1046 if (m_hasFocus)
1047 dc.SetBrush( *m_highlightBrush );
1048 else
1049 dc.SetBrush( *m_highlightUnfocusedBrush );
1050 dc.SetPen( *wxTRANSPARENT_PEN );
1051
1052 size_t item;
1053 for (item = item_start; item < item_start+item_count; item++)
1054 {
1055 if (m_selection.Index( item ) != wxNOT_FOUND)
1056 {
1057 wxRect rect( 0, item*m_lineHeight+1, 10000, m_lineHeight-2 );
1058 dc.DrawRectangle( rect );
1059 }
1060 }
1061
1062 dc.SetBrush( *wxTRANSPARENT_BRUSH );
1063 dc.SetPen( *wxBLACK_PEN );
1064 if (HasCurrentRow())
1065 {
1066 wxRect rect( 0, m_currentRow*m_lineHeight+1, 10000, m_lineHeight-2 );
1067 dc.DrawRectangle( rect );
1068 }
1069
1070 wxRect cell_rect;
1071 cell_rect.x = 0;
1072 cell_rect.height = m_lineHeight;
1073 size_t cols = GetOwner()->GetNumberOfColumns();
1074 size_t i;
1075 for (i = 0; i < cols; i++)
1076 {
1077 wxDataViewColumn *col = GetOwner()->GetColumn( i );
1078 wxDataViewCell *cell = col->GetCell();
1079 cell_rect.width = col->GetWidth();
1080
1081 for (item = item_start; item < item_start+item_count; item++)
1082 {
1083 cell_rect.y = item*m_lineHeight;
1084 wxVariant value;
1085 model->GetValue( value, col->GetModelColumn(), item );
1086 cell->SetValue( value );
1087 wxSize size = cell->GetSize();
1088 // cannot be bigger than allocated space
1089 size.x = wxMin( size.x, cell_rect.width );
1090 size.y = wxMin( size.y, cell_rect.height );
1091 // TODO: check for left/right/centre alignment here
1092 wxRect item_rect;
1093 // for now: centre
1094 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
1095 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
1096
1097 item_rect.width = size.x;
1098 item_rect.height= size.y;
1099 cell->Render( item_rect, &dc, 0 );
1100 }
1101
1102 cell_rect.x += cell_rect.width;
1103 }
1104 }
1105
1106 int wxDataViewMainWindow::GetCountPerPage()
1107 {
1108 wxSize size = GetClientSize();
1109 return size.y / m_lineHeight;
1110 }
1111
1112 int wxDataViewMainWindow::GetRowCount()
1113 {
1114 return GetOwner()->GetModel()->GetNumberOfRows();
1115 }
1116
1117 void wxDataViewMainWindow::SelectAllRows( bool on )
1118 {
1119 m_selection.Clear();
1120 if (on)
1121 {
1122 size_t i;
1123 for (i = 0; i < m_selection.GetCount(); i++)
1124 m_selection.Add( i );
1125 }
1126 Refresh();
1127 }
1128
1129 void wxDataViewMainWindow::SelectRow( size_t row, bool on )
1130 {
1131 if (m_selection.Index( row ) == wxNOT_FOUND)
1132 {
1133 if (on)
1134 {
1135 m_selection.Add( row );
1136 RefreshRow( row );
1137 }
1138 }
1139 else
1140 {
1141 if (!on)
1142 {
1143 m_selection.Remove( row );
1144 RefreshRow( row );
1145 }
1146 }
1147 }
1148
1149 void wxDataViewMainWindow::SelectRows( size_t from, size_t to, bool on )
1150 {
1151 if (from > to)
1152 {
1153 size_t tmp = from;
1154 from = to;
1155 to = tmp;
1156 }
1157
1158 size_t i;
1159 for (i = from; i <= to; i++)
1160 {
1161 if (m_selection.Index( i ) == wxNOT_FOUND)
1162 {
1163 if (on)
1164 m_selection.Add( i );
1165 }
1166 else
1167 {
1168 if (!on)
1169 m_selection.Remove( i );
1170 }
1171 }
1172 RefreshRows( from, to );
1173 }
1174
1175 void wxDataViewMainWindow::ReverseRowSelection( size_t row )
1176 {
1177 if (m_selection.Index( row ) == wxNOT_FOUND)
1178 m_selection.Add( row );
1179 else
1180 m_selection.Remove( row );
1181 Refresh( row );
1182 }
1183
1184 bool wxDataViewMainWindow::IsRowSelected( size_t row )
1185 {
1186 return (m_selection.Index( row ) != wxNOT_FOUND);
1187 }
1188
1189 void wxDataViewMainWindow::RefreshRow( size_t row )
1190 {
1191 wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
1192 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1193
1194 wxSize client_size = GetClientSize();
1195 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1196 wxRect intersect_rect = client_rect.Intersect( rect );
1197 if (intersect_rect.width > 0)
1198 Refresh( true, &intersect_rect );
1199 }
1200
1201 void wxDataViewMainWindow::RefreshRows( size_t from, size_t to )
1202 {
1203 if (from > to)
1204 {
1205 size_t tmp = to;
1206 to = from;
1207 from = tmp;
1208 }
1209
1210 wxRect rect( 0, from*m_lineHeight, 10000, (to-from+1) * m_lineHeight );
1211 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1212
1213 wxSize client_size = GetClientSize();
1214 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1215 wxRect intersect_rect = client_rect.Intersect( rect );
1216 if (intersect_rect.width > 0)
1217 Refresh( true, &intersect_rect );
1218 }
1219
1220 void wxDataViewMainWindow::RefreshRowsAfter( size_t firstRow )
1221 {
1222 size_t count = GetRowCount();
1223 if (firstRow > count) return;
1224
1225 wxRect rect( 0, firstRow*m_lineHeight, 10000, count * m_lineHeight );
1226 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1227
1228 wxSize client_size = GetClientSize();
1229 wxRect client_rect( 0, 0, client_size.x, client_size.y );
1230 wxRect intersect_rect = client_rect.Intersect( rect );
1231 if (intersect_rect.width > 0)
1232 Refresh( true, &intersect_rect );
1233 }
1234
1235 void wxDataViewMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
1236 {
1237 wxCHECK_RET( newCurrent < (size_t)GetRowCount(),
1238 _T("invalid item index in OnArrowChar()") );
1239
1240 // if there is no selection, we cannot move it anywhere
1241 if (!HasCurrentRow())
1242 return;
1243
1244 size_t oldCurrent = m_currentRow;
1245
1246 // in single selection we just ignore Shift as we can't select several
1247 // items anyhow
1248 if ( event.ShiftDown() /* && !IsSingleSel() */ )
1249 {
1250 RefreshRow( oldCurrent );
1251
1252 m_currentRow = newCurrent;
1253
1254 // select all the items between the old and the new one
1255 if ( oldCurrent > newCurrent )
1256 {
1257 newCurrent = oldCurrent;
1258 oldCurrent = m_currentRow;
1259 }
1260
1261 SelectRows( oldCurrent, newCurrent, true );
1262 }
1263 else // !shift
1264 {
1265 Refresh( oldCurrent );
1266
1267 // all previously selected items are unselected unless ctrl is held
1268 if ( !event.ControlDown() )
1269 SelectAllRows(false);
1270
1271 m_currentRow = newCurrent;
1272
1273 if ( !event.ControlDown() )
1274 SelectRow( m_currentRow, true );
1275 }
1276
1277 // MoveToFocus();
1278 }
1279
1280 void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
1281 {
1282 if (event.GetKeyCode() == WXK_TAB)
1283 {
1284 wxNavigationKeyEvent nevent;
1285 nevent.SetWindowChange( event.ControlDown() );
1286 nevent.SetDirection( !event.ShiftDown() );
1287 nevent.SetEventObject( GetParent()->GetParent() );
1288 nevent.SetCurrentFocus( m_parent );
1289 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
1290 return;
1291 }
1292
1293 // no item -> nothing to do
1294 if (!HasCurrentRow())
1295 {
1296 event.Skip();
1297 return;
1298 }
1299
1300 // don't use m_linesPerPage directly as it might not be computed yet
1301 const int pageSize = GetCountPerPage();
1302 wxCHECK_RET( pageSize, _T("should have non zero page size") );
1303
1304 switch ( event.GetKeyCode() )
1305 {
1306 case WXK_UP:
1307 if ( m_currentRow > 0 )
1308 OnArrowChar( m_currentRow - 1, event );
1309 break;
1310
1311 case WXK_DOWN:
1312 if ( m_currentRow < (size_t)GetRowCount() - 1 )
1313 OnArrowChar( m_currentRow + 1, event );
1314 break;
1315
1316 case WXK_END:
1317 if (!IsEmpty())
1318 OnArrowChar( GetRowCount() - 1, event );
1319 break;
1320
1321 case WXK_HOME:
1322 if (!IsEmpty())
1323 OnArrowChar( 0, event );
1324 break;
1325
1326 case WXK_PAGEUP:
1327 {
1328 int steps = pageSize - 1;
1329 int index = m_currentRow - steps;
1330 if (index < 0)
1331 index = 0;
1332
1333 OnArrowChar( index, event );
1334 }
1335 break;
1336
1337 case WXK_PAGEDOWN:
1338 {
1339 int steps = pageSize - 1;
1340 size_t index = m_currentRow + steps;
1341 size_t count = GetRowCount();
1342 if ( index >= count )
1343 index = count - 1;
1344
1345 OnArrowChar( index, event );
1346 }
1347 break;
1348
1349 default:
1350 event.Skip();
1351 }
1352 }
1353
1354 void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
1355 {
1356 int x = event.GetX();
1357 int y = event.GetY();
1358 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1359
1360 wxDataViewColumn *col = NULL;
1361
1362 int xpos = 0;
1363 size_t cols = GetOwner()->GetNumberOfColumns();
1364 size_t i;
1365 for (i = 0; i < cols; i++)
1366 {
1367 wxDataViewColumn *c = GetOwner()->GetColumn( i );
1368 if (x < xpos + c->GetWidth())
1369 {
1370 col = c;
1371 break;
1372 }
1373 xpos += c->GetWidth();
1374 }
1375 if (!col)
1376 return;
1377 wxDataViewCell *cell = col->GetCell();
1378
1379 size_t row = y / m_lineHeight;
1380
1381 wxDataViewListModel *model = GetOwner()->GetModel();
1382
1383 if (event.ButtonDClick())
1384 {
1385 m_renameTimer->Stop();
1386 m_lastOnSame = false;
1387 }
1388
1389 if (event.LeftDClick())
1390 {
1391 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
1392 {
1393 wxVariant value;
1394 model->GetValue( value, col->GetModelColumn(), row );
1395 cell->SetValue( value );
1396 wxRect cell_rect( xpos, row * m_lineHeight, col->GetWidth(), m_lineHeight );
1397 cell->Activate( cell_rect, model, col->GetModelColumn(), row );
1398 }
1399
1400 return;
1401 } else
1402 if (event.LeftUp())
1403 {
1404 if (m_lastOnSame)
1405 {
1406 if ((col == m_currentCol) & (row == m_currentRow) &&
1407 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
1408 {
1409 m_renameTimer->Start( 100, true );
1410 }
1411 }
1412
1413 m_lastOnSame = false;
1414 } else
1415 if (event.LeftDown())
1416 {
1417 wxDataViewColumn *oldCurrentCol = m_currentCol;
1418 size_t oldCurrentRow = m_currentRow;
1419
1420 // Update selection here...
1421 m_currentCol = col;
1422 m_currentRow = row;
1423 RefreshRow( oldCurrentRow );
1424 RefreshRow( m_currentRow );
1425
1426 m_lastOnSame = (col == oldCurrentCol) && (row == oldCurrentRow);
1427
1428 return;
1429 }
1430
1431 event.Skip();
1432 }
1433
1434 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
1435 {
1436 m_hasFocus = true;
1437
1438 if (HasCurrentRow())
1439 Refresh();
1440
1441 event.Skip();
1442 }
1443
1444 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
1445 {
1446 m_hasFocus = false;
1447
1448 if (HasCurrentRow())
1449 Refresh();
1450
1451 event.Skip();
1452 }
1453
1454 //-----------------------------------------------------------------------------
1455 // wxDataViewCtrl
1456 //-----------------------------------------------------------------------------
1457
1458 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1459
1460 BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
1461 EVT_SIZE(wxDataViewCtrl::OnSize)
1462 END_EVENT_TABLE()
1463
1464 wxDataViewCtrl::~wxDataViewCtrl()
1465 {
1466 if (m_notifier)
1467 GetModel()->RemoveNotifier( m_notifier );
1468 }
1469
1470 void wxDataViewCtrl::Init()
1471 {
1472 m_notifier = NULL;
1473 }
1474
1475 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
1476 const wxPoint& pos, const wxSize& size,
1477 long style, const wxValidator& validator )
1478 {
1479 if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
1480 return false;
1481
1482 Init();
1483
1484 #ifdef __WXMAC__
1485 MacSetClipChildren( true ) ;
1486 #endif
1487
1488 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
1489 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) );
1490
1491 SetTargetWindow( m_clientArea );
1492
1493 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1494 sizer->Add( m_headerArea, 0, wxGROW );
1495 sizer->Add( m_clientArea, 1, wxGROW );
1496 SetSizer( sizer );
1497
1498 return true;
1499 }
1500
1501 #ifdef __WXMSW__
1502 WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
1503 WXWPARAM wParam,
1504 WXLPARAM lParam)
1505 {
1506 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
1507
1508 #ifndef __WXWINCE__
1509 // we need to process arrows ourselves for scrolling
1510 if ( nMsg == WM_GETDLGCODE )
1511 {
1512 rc |= DLGC_WANTARROWS;
1513 }
1514 #endif
1515
1516 return rc;
1517 }
1518 #endif
1519
1520 void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
1521 {
1522 // We need to override OnSize so that our scrolled
1523 // window a) does call Layout() to use sizers for
1524 // positioning the controls but b) does not query
1525 // the sizer for their size and use that for setting
1526 // the scrollable area as set that ourselves by
1527 // calling SetScrollbar() further down.
1528
1529 Layout();
1530
1531 AdjustScrollbars();
1532 }
1533
1534 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1535 {
1536 if (!wxDataViewCtrlBase::AssociateModel( model ))
1537 return false;
1538
1539 m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea );
1540
1541 model->AddNotifier( m_notifier );
1542
1543 m_clientArea->UpdateDisplay();
1544
1545 return true;
1546 }
1547
1548 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1549 {
1550 if (!wxDataViewCtrlBase::AppendColumn(col))
1551 return false;
1552
1553 m_clientArea->UpdateDisplay();
1554
1555 return true;
1556 }
1557
1558 #endif
1559 // !wxUSE_GENERICDATAVIEWCTRL
1560
1561 #endif
1562 // wxUSE_DATAVIEWCTRL
1563