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