1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/generic/datavgen.cpp
3 // Purpose:     wxDataViewCtrl generic implementation
4 // Author:      Robert Roebling
5 // Id:          $Id: datavgen.cpp 45498 2007-04-16 13:03:05Z VZ $
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 #ifdef __BORLANDC__
14     #pragma hdrstop
15 #endif
16 
17 #if wxUSE_DATAVIEWCTRL
18 
19 #include "wx/dataview.h"
20 
21 #ifdef wxUSE_GENERICDATAVIEWCTRL
22 
23 #ifndef WX_PRECOMP
24     #ifdef __WXMSW__
25         #include "wx/msw/wrapwin.h"
26     #endif
27     #include "wx/sizer.h"
28     #include "wx/log.h"
29     #include "wx/dcclient.h"
30     #include "wx/timer.h"
31     #include "wx/settings.h"
32     #include "wx/msgdlg.h"
33 #endif
34 
35 #include "wx/stockitem.h"
36 #include "wx/calctrl.h"
37 #include "wx/popupwin.h"
38 #include "wx/renderer.h"
39 #include "wx/dcbuffer.h"
40 #include "wx/icon.h"
41 
42 //-----------------------------------------------------------------------------
43 // classes
44 //-----------------------------------------------------------------------------
45 
46 class wxDataViewCtrl;
47 
48 //-----------------------------------------------------------------------------
49 // wxDataViewHeaderWindow
50 //-----------------------------------------------------------------------------
51 
52 class wxDataViewHeaderWindow: public wxWindow
53 {
54 public:
55     wxDataViewHeaderWindow( wxDataViewCtrl *parent,
56                             wxWindowID id,
57                             const wxPoint &pos = wxDefaultPosition,
58                             const wxSize &size = wxDefaultSize,
59                             const wxString &name = wxT("wxdataviewctrlheaderwindow") );
60     virtual ~wxDataViewHeaderWindow();
61 
SetOwner(wxDataViewCtrl * owner)62     void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
GetOwner()63     wxDataViewCtrl *GetOwner() { return m_owner; }
64 
65     void OnPaint( wxPaintEvent &event );
66     void OnMouse( wxMouseEvent &event );
67     void OnSetFocus( wxFocusEvent &event );
68 
69 private:
70     wxDataViewCtrl      *m_owner;
71     wxCursor            *m_resizeCursor;
72 
73 private:
74     DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindow)
75     DECLARE_EVENT_TABLE()
76 };
77 
78 //-----------------------------------------------------------------------------
79 // wxDataViewRenameTimer
80 //-----------------------------------------------------------------------------
81 
82 class wxDataViewRenameTimer: public wxTimer
83 {
84 private:
85     wxDataViewMainWindow *m_owner;
86 
87 public:
88     wxDataViewRenameTimer( wxDataViewMainWindow *owner );
89     void Notify();
90 };
91 
92 //-----------------------------------------------------------------------------
93 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
94 //-----------------------------------------------------------------------------
95 
96 class wxDataViewTextCtrlWrapper : public wxEvtHandler
97 {
98 public:
99     // NB: text must be a valid object but not Create()d yet
100     wxDataViewTextCtrlWrapper( wxDataViewMainWindow *owner,
101                                wxTextCtrl *text,
102                                wxDataViewListModel *model,
103                                unsigned int col, unsigned int row,
104                                wxRect cellLabel );
105 
GetText() const106     wxTextCtrl *GetText() const { return m_text; }
107 
108     void AcceptChangesAndFinish();
109 
110 protected:
111     void OnChar( wxKeyEvent &event );
112     void OnKeyUp( wxKeyEvent &event );
113     void OnKillFocus( wxFocusEvent &event );
114 
115     bool AcceptChanges();
116     void Finish();
117 
118 private:
119     wxDataViewMainWindow   *m_owner;
120     wxTextCtrl             *m_text;
121     wxString                m_startValue;
122     wxDataViewListModel    *m_model;
123     unsigned int                  m_col;
124     unsigned int                  m_row;
125     bool                    m_finished;
126     bool                    m_aboutToFinish;
127 
128     DECLARE_EVENT_TABLE()
129 };
130 
131 //-----------------------------------------------------------------------------
132 // wxDataViewMainWindow
133 //-----------------------------------------------------------------------------
134 
135 WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection, WXDLLIMPEXP_ADV);
136 
137 class wxDataViewMainWindow: public wxWindow
138 {
139 public:
140     wxDataViewMainWindow( wxDataViewCtrl *parent,
141                             wxWindowID id,
142                             const wxPoint &pos = wxDefaultPosition,
143                             const wxSize &size = wxDefaultSize,
144                             const wxString &name = wxT("wxdataviewctrlmainwindow") );
145     virtual ~wxDataViewMainWindow();
146 
147     // notifications from wxDataViewListModel
148     bool RowAppended();
149     bool RowPrepended();
150     bool RowInserted( unsigned int before );
151     bool RowDeleted( unsigned int row );
152     bool RowChanged( unsigned int row );
153     bool ValueChanged( unsigned int col, unsigned int row );
154     bool RowsReordered( unsigned int *new_order );
155     bool Cleared();
156 
SetOwner(wxDataViewCtrl * owner)157     void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
GetOwner()158     wxDataViewCtrl *GetOwner() { return m_owner; }
159 
160     void OnPaint( wxPaintEvent &event );
161     void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event);
162     void OnChar( wxKeyEvent &event );
163     void OnMouse( wxMouseEvent &event );
164     void OnSetFocus( wxFocusEvent &event );
165     void OnKillFocus( wxFocusEvent &event );
166 
167     void UpdateDisplay();
168     void RecalculateDisplay();
169     void OnInternalIdle();
170 
171     void OnRenameTimer();
172     void FinishEditing( wxTextCtrl *text );
173 
174     void ScrollWindow( int dx, int dy, const wxRect *rect );
175 
HasCurrentRow()176     bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; }
177     void ChangeCurrentRow( unsigned int row );
178 
IsSingleSel() const179     bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }
IsEmpty()180     bool IsEmpty() { return GetRowCount() == 0; }
181 
182     int GetCountPerPage();
183     int GetEndOfLastCol();
184     unsigned int GetFirstVisibleRow();
185     unsigned int GetLastVisibleRow();
186     unsigned int GetRowCount();
187 
188     void SelectAllRows( bool on );
189     void SelectRow( unsigned int row, bool on );
190     void SelectRows( unsigned int from, unsigned int to, bool on );
191     void ReverseRowSelection( unsigned int row );
192     bool IsRowSelected( unsigned int row );
193 
194     void RefreshRow( unsigned int row );
195     void RefreshRows( unsigned int from, unsigned int to );
196     void RefreshRowsAfter( unsigned int firstRow );
197 
198 private:
199     wxDataViewCtrl             *m_owner;
200     int                         m_lineHeight;
201     bool                        m_dirty;
202 
203     wxDataViewColumn           *m_currentCol;
204     unsigned int                      m_currentRow;
205     wxDataViewSelection         m_selection;
206 
207     wxDataViewRenameTimer      *m_renameTimer;
208     wxDataViewTextCtrlWrapper  *m_textctrlWrapper;
209     bool                        m_lastOnSame;
210 
211     bool                        m_hasFocus;
212 
213     int                         m_dragCount;
214     wxPoint                     m_dragStart;
215 
216     // for double click logic
217     unsigned int m_lineLastClicked,
218            m_lineBeforeLastClicked,
219            m_lineSelectSingleOnUp;
220 
221 private:
222     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
223     DECLARE_EVENT_TABLE()
224 };
225 
226 // ---------------------------------------------------------
227 // wxGenericDataViewListModelNotifier
228 // ---------------------------------------------------------
229 
230 class wxGenericDataViewListModelNotifier: public wxDataViewListModelNotifier
231 {
232 public:
wxGenericDataViewListModelNotifier(wxDataViewMainWindow * mainWindow)233     wxGenericDataViewListModelNotifier( wxDataViewMainWindow *mainWindow )
234         { m_mainWindow = mainWindow; }
235 
RowAppended()236     virtual bool RowAppended()
237         { return m_mainWindow->RowAppended(); }
RowPrepended()238     virtual bool RowPrepended()
239         { return m_mainWindow->RowPrepended(); }
RowInserted(unsigned int before)240     virtual bool RowInserted( unsigned int before )
241         { return m_mainWindow->RowInserted( before ); }
RowDeleted(unsigned int row)242     virtual bool RowDeleted( unsigned int row )
243         { return m_mainWindow->RowDeleted( row ); }
RowChanged(unsigned int row)244     virtual bool RowChanged( unsigned int row )
245         { return m_mainWindow->RowChanged( row ); }
ValueChanged(unsigned int col,unsigned int row)246     virtual bool ValueChanged( unsigned int col, unsigned int row )
247         { return m_mainWindow->ValueChanged( col, row ); }
RowsReordered(unsigned int * new_order)248     virtual bool RowsReordered( unsigned int *new_order )
249         { return m_mainWindow->RowsReordered( new_order ); }
Cleared()250     virtual bool Cleared()
251         { return m_mainWindow->Cleared(); }
252 
253     wxDataViewMainWindow    *m_mainWindow;
254 };
255 
256 // ---------------------------------------------------------
257 // wxDataViewRenderer
258 // ---------------------------------------------------------
259 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)260 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
261 
262 wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
263     wxDataViewRendererBase( varianttype, mode )
264 {
265     m_dc = NULL;
266 }
267 
~wxDataViewRenderer()268 wxDataViewRenderer::~wxDataViewRenderer()
269 {
270     if (m_dc)
271         delete m_dc;
272 }
273 
GetDC()274 wxDC *wxDataViewRenderer::GetDC()
275 {
276     if (m_dc == NULL)
277     {
278         if (GetOwner() == NULL)
279             return NULL;
280         if (GetOwner()->GetOwner() == NULL)
281             return NULL;
282         m_dc = new wxClientDC( GetOwner()->GetOwner() );
283     }
284 
285     return m_dc;
286 }
287 
288 // ---------------------------------------------------------
289 // wxDataViewCustomRenderer
290 // ---------------------------------------------------------
291 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer,wxDataViewRenderer)292 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
293 
294 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
295                           wxDataViewCellMode mode ) :
296     wxDataViewRenderer( varianttype, mode )
297 {
298 }
299 
300 // ---------------------------------------------------------
301 // wxDataViewTextRenderer
302 // ---------------------------------------------------------
303 
IMPLEMENT_CLASS(wxDataViewTextRenderer,wxDataViewCustomRenderer)304 IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer)
305 
306 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
307     wxDataViewCustomRenderer( varianttype, mode )
308 {
309 }
310 
SetValue(const wxVariant & value)311 bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
312 {
313     m_text = value.GetString();
314 
315     return true;
316 }
317 
GetValue(wxVariant & WXUNUSED (value))318 bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) )
319 {
320     return false;
321 }
322 
Render(wxRect cell,wxDC * dc,int WXUNUSED (state))323 bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
324 {
325     dc->DrawText( m_text, cell.x, cell.y );
326 
327     return true;
328 }
329 
GetSize()330 wxSize wxDataViewTextRenderer::GetSize()
331 {
332     return wxSize(80,20);
333 }
334 
335 // ---------------------------------------------------------
336 // wxDataViewBitmapRenderer
337 // ---------------------------------------------------------
338 
IMPLEMENT_CLASS(wxDataViewBitmapRenderer,wxDataViewCustomRenderer)339 IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer)
340 
341 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) :
342     wxDataViewCustomRenderer( varianttype, mode )
343 {
344 }
345 
SetValue(const wxVariant & value)346 bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
347 {
348     if (value.GetType() == wxT("wxBitmap"))
349         m_bitmap << value;
350     if (value.GetType() == wxT("wxIcon"))
351         m_icon << value;
352 
353     return true;
354 }
355 
GetValue(wxVariant & WXUNUSED (value))356 bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) )
357 {
358     return false;
359 }
360 
Render(wxRect cell,wxDC * dc,int WXUNUSED (state))361 bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
362 {
363     if (m_bitmap.Ok())
364         dc->DrawBitmap( m_bitmap, cell.x, cell.y );
365     else if (m_icon.Ok())
366         dc->DrawIcon( m_icon, cell.x, cell.y );
367 
368     return true;
369 }
370 
GetSize()371 wxSize wxDataViewBitmapRenderer::GetSize()
372 {
373     if (m_bitmap.Ok())
374         return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() );
375     else if (m_icon.Ok())
376         return wxSize( m_icon.GetWidth(), m_icon.GetHeight() );
377 
378     return wxSize(16,16);
379 }
380 
381 // ---------------------------------------------------------
382 // wxDataViewToggleRenderer
383 // ---------------------------------------------------------
384 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer,wxDataViewCustomRenderer)385 IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer)
386 
387 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
388                         wxDataViewCellMode mode ) :
389     wxDataViewCustomRenderer( varianttype, mode )
390 {
391     m_toggle = false;
392 }
393 
SetValue(const wxVariant & value)394 bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
395 {
396     m_toggle = value.GetBool();
397 
398     return true;
399 }
400 
GetValue(wxVariant & WXUNUSED (value))401 bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) )
402 {
403     return false;
404 }
405 
Render(wxRect cell,wxDC * dc,int WXUNUSED (state))406 bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
407 {
408     // User wxRenderer here
409 
410     wxRect rect;
411     rect.x = cell.x + cell.width/2 - 10;
412     rect.width = 20;
413     rect.y = cell.y + cell.height/2 - 10;
414     rect.height = 20;
415 
416     int flags = 0;
417     if (m_toggle)
418         flags |= wxCONTROL_CHECKED;
419     if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
420         flags |= wxCONTROL_DISABLED;
421 
422     wxRendererNative::Get().DrawCheckBox(
423             GetOwner()->GetOwner(),
424             *dc,
425             rect,
426             flags );
427 
428     return true;
429 }
430 
Activate(wxRect WXUNUSED (cell),wxDataViewListModel * model,unsigned int col,unsigned int row)431 bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row )
432 {
433     bool value = !m_toggle;
434     wxVariant variant = value;
435     model->SetValue( variant, col, row );
436     model->ValueChanged( col, row );
437     return true;
438 }
439 
GetSize()440 wxSize wxDataViewToggleRenderer::GetSize()
441 {
442     return wxSize(20,20);
443 }
444 
445 // ---------------------------------------------------------
446 // wxDataViewProgressRenderer
447 // ---------------------------------------------------------
448 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer,wxDataViewCustomRenderer)449 IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
450 
451 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
452     const wxString &varianttype, wxDataViewCellMode mode ) :
453     wxDataViewCustomRenderer( varianttype, mode )
454 {
455     m_label = label;
456     m_value = 0;
457 }
458 
~wxDataViewProgressRenderer()459 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
460 {
461 }
462 
SetValue(const wxVariant & value)463 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
464 {
465     m_value = (long) value;
466 
467     if (m_value < 0) m_value = 0;
468     if (m_value > 100) m_value = 100;
469 
470     return true;
471 }
472 
Render(wxRect cell,wxDC * dc,int WXUNUSED (state))473 bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
474 {
475     double pct = (double)m_value / 100.0;
476     wxRect bar = cell;
477     bar.width = (int)(cell.width * pct);
478     dc->SetPen( *wxTRANSPARENT_PEN );
479     dc->SetBrush( *wxBLUE_BRUSH );
480     dc->DrawRectangle( bar );
481 
482     dc->SetBrush( *wxTRANSPARENT_BRUSH );
483     dc->SetPen( *wxBLACK_PEN );
484     dc->DrawRectangle( cell );
485 
486     return true;
487 }
488 
GetSize()489 wxSize wxDataViewProgressRenderer::GetSize()
490 {
491     return wxSize(40,12);
492 }
493 
494 // ---------------------------------------------------------
495 // wxDataViewDateRenderer
496 // ---------------------------------------------------------
497 
498 #define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
499 
500 #if wxUSE_DATE_RENDERER_POPUP
501 
502 class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
503 {
504 public:
wxDataViewDateRendererPopupTransient(wxWindow * parent,wxDateTime * value,wxDataViewListModel * model,unsigned int col,unsigned int row)505     wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
506         wxDataViewListModel *model, unsigned int col, unsigned int row ) :
507         wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
508     {
509         m_model = model;
510         m_col = col;
511         m_row = row;
512         m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
513         wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
514         sizer->Add( m_cal, 1, wxGROW );
515         SetSizer( sizer );
516         sizer->Fit( this );
517     }
518 
519     void OnCalendar( wxCalendarEvent &event );
520 
521     wxCalendarCtrl      *m_cal;
522     wxDataViewListModel *m_model;
523     unsigned int               m_col;
524     unsigned int               m_row;
525 
526 protected:
OnDismiss()527     virtual void OnDismiss()
528     {
529     }
530 
531 private:
532     DECLARE_EVENT_TABLE()
533 };
534 
BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)535 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
536     EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar )
537 END_EVENT_TABLE()
538 
539 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
540 {
541     wxDateTime date = event.GetDate();
542     wxVariant value = date;
543     m_model->SetValue( value, m_col, m_row );
544     m_model->ValueChanged( m_col, m_row );
545     DismissAndNotify();
546 }
547 
548 #endif // wxUSE_DATE_RENDERER_POPUP
549 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer,wxDataViewCustomRenderer)550 IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
551 
552 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
553                         wxDataViewCellMode mode ) :
554     wxDataViewCustomRenderer( varianttype, mode )
555 {
556 }
557 
SetValue(const wxVariant & value)558 bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
559 {
560     m_date = value.GetDateTime();
561 
562     return true;
563 }
564 
Render(wxRect cell,wxDC * dc,int WXUNUSED (state))565 bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
566 {
567     dc->SetFont( GetOwner()->GetOwner()->GetFont() );
568     wxString tmp = m_date.FormatDate();
569     dc->DrawText( tmp, cell.x, cell.y );
570 
571     return true;
572 }
573 
GetSize()574 wxSize wxDataViewDateRenderer::GetSize()
575 {
576     wxDataViewCtrl* view = GetOwner()->GetOwner();
577     wxString tmp = m_date.FormatDate();
578     wxCoord x,y,d;
579     view->GetTextExtent( tmp, &x, &y, &d );
580     return wxSize(x,y+d);
581 }
582 
Activate(wxRect WXUNUSED (cell),wxDataViewListModel * model,unsigned int col,unsigned int row)583 bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewListModel *model, unsigned int col, unsigned int row )
584 {
585     wxVariant variant;
586     model->GetValue( variant, col, row );
587     wxDateTime value = variant.GetDateTime();
588 
589 #if wxUSE_DATE_RENDERER_POPUP
590     wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
591         GetOwner()->GetOwner()->GetParent(), &value, model, col, row );
592     wxPoint pos = wxGetMousePosition();
593     popup->Move( pos );
594     popup->Layout();
595     popup->Popup( popup->m_cal );
596 #else // !wxUSE_DATE_RENDERER_POPUP
597     wxMessageBox(value.Format());
598 #endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
599     return true;
600 }
601 
602 // ---------------------------------------------------------
603 // wxDataViewColumn
604 // ---------------------------------------------------------
605 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn,wxDataViewColumnBase)606 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
607 
608 wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell, unsigned int model_column,
609         int width, int flags ) :
610     wxDataViewColumnBase( title, cell, model_column, width, flags )
611 {
612     m_width = width;
613     if (m_width < 0)
614         m_width = 80;
615 }
616 
wxDataViewColumn(const wxBitmap & bitmap,wxDataViewRenderer * cell,unsigned int model_column,int width,int flags)617 wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, unsigned int model_column,
618         int width, int flags ) :
619     wxDataViewColumnBase( bitmap, cell, model_column, width, flags )
620 {
621     m_width = width;
622     if (m_width < 0)
623         m_width = 30;
624 }
625 
SetAlignment(wxAlignment WXUNUSED (align))626 void wxDataViewColumn::SetAlignment( wxAlignment WXUNUSED(align) )
627 {
628     // TODO
629 }
630 
SetSortable(bool WXUNUSED (sortable))631 void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) )
632 {
633     // TODO
634 }
635 
GetSortable()636 bool wxDataViewColumn::GetSortable()
637 {
638     // TODO
639     return false;
640 }
641 
SetSortOrder(bool WXUNUSED (ascending))642 void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) )
643 {
644     // TODO
645 }
646 
IsSortOrderAscending()647 bool wxDataViewColumn::IsSortOrderAscending()
648 {
649     // TODO
650     return true;
651 }
652 
653 
~wxDataViewColumn()654 wxDataViewColumn::~wxDataViewColumn()
655 {
656 }
657 
SetTitle(const wxString & title)658 void wxDataViewColumn::SetTitle( const wxString &title )
659 {
660     wxDataViewColumnBase::SetTitle( title );
661 
662 }
663 
SetBitmap(const wxBitmap & bitmap)664 void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
665 {
666     wxDataViewColumnBase::SetBitmap( bitmap );
667 
668 }
669 
GetWidth()670 int wxDataViewColumn::GetWidth()
671 {
672     return m_width;
673 }
674 
675 //-----------------------------------------------------------------------------
676 // wxDataViewHeaderWindow
677 //-----------------------------------------------------------------------------
678 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow,wxWindow)679 IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindow, wxWindow)
680 
681 BEGIN_EVENT_TABLE(wxDataViewHeaderWindow,wxWindow)
682     EVT_PAINT         (wxDataViewHeaderWindow::OnPaint)
683     EVT_MOUSE_EVENTS  (wxDataViewHeaderWindow::OnMouse)
684     EVT_SET_FOCUS     (wxDataViewHeaderWindow::OnSetFocus)
685 END_EVENT_TABLE()
686 
687 wxDataViewHeaderWindow::wxDataViewHeaderWindow( wxDataViewCtrl *parent, wxWindowID id,
688      const wxPoint &pos, const wxSize &size, const wxString &name ) :
689     wxWindow( parent, id, pos, size, 0, name )
690 {
691     SetOwner( parent );
692 
693     m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
694 
695     wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
696     SetBackgroundStyle( wxBG_STYLE_CUSTOM );
697     SetOwnForegroundColour( attr.colFg );
698     SetOwnBackgroundColour( attr.colBg );
699     if (!m_hasFont)
700         SetOwnFont( attr.font );
701 }
702 
~wxDataViewHeaderWindow()703 wxDataViewHeaderWindow::~wxDataViewHeaderWindow()
704 {
705     delete m_resizeCursor;
706 }
707 
OnPaint(wxPaintEvent & WXUNUSED (event))708 void wxDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
709 {
710     int w, h;
711     GetClientSize( &w, &h );
712 
713     wxAutoBufferedPaintDC dc( this );
714 
715     dc.SetBackground(GetBackgroundColour());
716     dc.Clear();
717 
718     int xpix;
719     m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
720 
721     int x;
722     m_owner->GetViewStart( &x, NULL );
723 
724     // account for the horz scrollbar offset
725     dc.SetDeviceOrigin( -x * xpix, 0 );
726 
727     dc.SetFont( GetFont() );
728 
729     unsigned int cols = GetOwner()->GetNumberOfColumns();
730     unsigned int i;
731     int xpos = 0;
732     for (i = 0; i < cols; i++)
733     {
734         wxDataViewColumn *col = GetOwner()->GetColumn( i );
735         int width = col->GetWidth();
736 
737         int cw = width;
738         int ch = h;
739 
740         wxRendererNative::Get().DrawHeaderButton
741                                 (
742                                     this,
743                                     dc,
744                                     wxRect(xpos, 0, cw, ch-1),
745                                     m_parent->IsEnabled() ? 0
746                                                           : (int)wxCONTROL_DISABLED
747                                 );
748 
749         dc.DrawText( col->GetTitle(), xpos+3, 3 );
750 
751         xpos += width;
752     }
753 }
754 
OnMouse(wxMouseEvent & WXUNUSED (event))755 void wxDataViewHeaderWindow::OnMouse( wxMouseEvent &WXUNUSED(event) )
756 {
757 }
758 
OnSetFocus(wxFocusEvent & event)759 void wxDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
760 {
761     GetParent()->SetFocus();
762     event.Skip();
763 }
764 
765 //-----------------------------------------------------------------------------
766 // wxDataViewRenameTimer
767 //-----------------------------------------------------------------------------
768 
wxDataViewRenameTimer(wxDataViewMainWindow * owner)769 wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
770 {
771     m_owner = owner;
772 }
773 
Notify()774 void wxDataViewRenameTimer::Notify()
775 {
776     m_owner->OnRenameTimer();
777 }
778 
779 //-----------------------------------------------------------------------------
780 // wxDataViewTextCtrlWrapper: wraps a wxTextCtrl for inline editing
781 //-----------------------------------------------------------------------------
782 
BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper,wxEvtHandler)783 BEGIN_EVENT_TABLE(wxDataViewTextCtrlWrapper, wxEvtHandler)
784     EVT_CHAR           (wxDataViewTextCtrlWrapper::OnChar)
785     EVT_KEY_UP         (wxDataViewTextCtrlWrapper::OnKeyUp)
786     EVT_KILL_FOCUS     (wxDataViewTextCtrlWrapper::OnKillFocus)
787 END_EVENT_TABLE()
788 
789 wxDataViewTextCtrlWrapper::wxDataViewTextCtrlWrapper(
790                         wxDataViewMainWindow *owner,
791                         wxTextCtrl *text,
792                         wxDataViewListModel *model,
793                         unsigned int col, unsigned int row,
794                         wxRect rectLabel )
795 {
796     m_owner = owner;
797     m_model = model;
798     m_row = row;
799     m_col = col;
800     m_text = text;
801 
802     m_finished = false;
803     m_aboutToFinish = false;
804 
805     wxVariant value;
806     model->GetValue( value, col, row );
807     m_startValue = value.GetString();
808 
809     m_owner->GetOwner()->CalcScrolledPosition(
810         rectLabel.x, rectLabel.y, &rectLabel.x, &rectLabel.y );
811 
812     m_text->Create( owner, wxID_ANY, m_startValue,
813                     wxPoint(rectLabel.x-2,rectLabel.y-2),
814                     wxSize(rectLabel.width+7,rectLabel.height+4) );
815     m_text->SetFocus();
816 
817     m_text->PushEventHandler(this);
818 }
819 
AcceptChangesAndFinish()820 void wxDataViewTextCtrlWrapper::AcceptChangesAndFinish()
821 {
822     m_aboutToFinish = true;
823 
824     // Notify the owner about the changes
825     AcceptChanges();
826 
827     // Even if vetoed, close the control (consistent with MSW)
828     Finish();
829 }
830 
OnChar(wxKeyEvent & event)831 void wxDataViewTextCtrlWrapper::OnChar( wxKeyEvent &event )
832 {
833     switch ( event.m_keyCode )
834     {
835         case WXK_RETURN:
836             AcceptChangesAndFinish();
837             break;
838 
839         case WXK_ESCAPE:
840             // m_owner->OnRenameCancelled( m_itemEdited );
841             Finish();
842             break;
843 
844         default:
845             event.Skip();
846     }
847 }
848 
OnKeyUp(wxKeyEvent & event)849 void wxDataViewTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
850 {
851     if (m_finished)
852     {
853         event.Skip();
854         return;
855     }
856 
857     // auto-grow the textctrl
858     wxSize parentSize = m_owner->GetSize();
859     wxPoint myPos = m_text->GetPosition();
860     wxSize mySize = m_text->GetSize();
861     int sx, sy;
862     m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
863     if (myPos.x + sx > parentSize.x)
864         sx = parentSize.x - myPos.x;
865     if (mySize.x > sx)
866         sx = mySize.x;
867     m_text->SetSize(sx, wxDefaultCoord);
868 
869     event.Skip();
870 }
871 
OnKillFocus(wxFocusEvent & event)872 void wxDataViewTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
873 {
874     if ( !m_finished && !m_aboutToFinish )
875     {
876         AcceptChanges();
877         //if ( !AcceptChanges() )
878         //    m_owner->OnRenameCancelled( m_itemEdited );
879 
880         Finish();
881     }
882 
883     // We must let the native text control handle focus
884     event.Skip();
885 }
886 
AcceptChanges()887 bool wxDataViewTextCtrlWrapper::AcceptChanges()
888 {
889     const wxString value = m_text->GetValue();
890 
891     if ( value == m_startValue )
892         // nothing changed, always accept
893         return true;
894 
895 //    if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
896         // vetoed by the user
897 //        return false;
898 
899     // accepted, do rename the item
900     wxVariant variant;
901     variant = value;
902     m_model->SetValue( variant, m_col, m_row );
903     m_model->ValueChanged( m_col, m_row );
904 
905     return true;
906 }
907 
Finish()908 void wxDataViewTextCtrlWrapper::Finish()
909 {
910     if ( !m_finished )
911     {
912         m_finished = true;
913 
914         m_text->RemoveEventHandler(this);
915         m_owner->FinishEditing(m_text);
916 
917         // delete later
918         wxPendingDelete.Append( this );
919     }
920 }
921 
922 //-----------------------------------------------------------------------------
923 // wxDataViewMainWindow
924 //-----------------------------------------------------------------------------
925 
wxDataViewSelectionCmp(unsigned int row1,unsigned int row2)926 int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
927 {
928     if (row1 > row2) return 1;
929     if (row1 == row2) return 0;
930     return -1;
931 }
932 
933 
IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow,wxWindow)934 IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
935 
936 BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
937     EVT_PAINT         (wxDataViewMainWindow::OnPaint)
938     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse)
939     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus)
940     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus)
941     EVT_CHAR          (wxDataViewMainWindow::OnChar)
942 END_EVENT_TABLE()
943 
944 wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
945     const wxPoint &pos, const wxSize &size, const wxString &name ) :
946     wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ),
947     m_selection( wxDataViewSelectionCmp )
948 
949 {
950     SetOwner( parent );
951 
952     m_lastOnSame = false;
953     m_renameTimer = new wxDataViewRenameTimer( this );
954     m_textctrlWrapper = NULL;
955 
956     // TODO: user better initial values/nothing selected
957     m_currentCol = NULL;
958     m_currentRow = 0;
959 
960     // TODO: we need to calculate this smartly
961     m_lineHeight = 20;
962 
963     m_dragCount = 0;
964     m_dragStart = wxPoint(0,0);
965     m_lineLastClicked = (unsigned int) -1;
966     m_lineBeforeLastClicked = (unsigned int) -1;
967     m_lineSelectSingleOnUp = (unsigned int) -1;
968 
969     m_hasFocus = false;
970 
971     SetBackgroundStyle( wxBG_STYLE_CUSTOM );
972     SetBackgroundColour( *wxWHITE );
973 
974     UpdateDisplay();
975 }
976 
~wxDataViewMainWindow()977 wxDataViewMainWindow::~wxDataViewMainWindow()
978 {
979     delete m_renameTimer;
980 }
981 
OnRenameTimer()982 void wxDataViewMainWindow::OnRenameTimer()
983 {
984     // We have to call this here because changes may just have
985     // been made and no screen update taken place.
986     if ( m_dirty )
987         wxSafeYield();
988 
989 
990     int xpos = 0;
991     unsigned int cols = GetOwner()->GetNumberOfColumns();
992     unsigned int i;
993     for (i = 0; i < cols; i++)
994     {
995         wxDataViewColumn *c = GetOwner()->GetColumn( i );
996         if (c == m_currentCol)
997             break;
998         xpos += c->GetWidth();
999     }
1000     wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight );
1001 
1002     wxClassInfo *textControlClass = CLASSINFO(wxTextCtrl);
1003 
1004     wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
1005     m_textctrlWrapper = new wxDataViewTextCtrlWrapper(this, text, GetOwner()->GetModel(),
1006         m_currentCol->GetModelColumn(), m_currentRow, labelRect );
1007 }
1008 
FinishEditing(wxTextCtrl * text)1009 void wxDataViewMainWindow::FinishEditing( wxTextCtrl *text )
1010 {
1011     delete text;
1012     m_textctrlWrapper = NULL;
1013     SetFocus();
1014   //  SetFocusIgnoringChildren();
1015 }
1016 
RowAppended()1017 bool wxDataViewMainWindow::RowAppended()
1018 {
1019     return false;
1020 }
1021 
RowPrepended()1022 bool wxDataViewMainWindow::RowPrepended()
1023 {
1024     return false;
1025 }
1026 
RowInserted(unsigned int WXUNUSED (before))1027 bool wxDataViewMainWindow::RowInserted( unsigned int WXUNUSED(before) )
1028 {
1029     return false;
1030 }
1031 
RowDeleted(unsigned int WXUNUSED (row))1032 bool wxDataViewMainWindow::RowDeleted( unsigned int WXUNUSED(row) )
1033 {
1034     return false;
1035 }
1036 
RowChanged(unsigned int WXUNUSED (row))1037 bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) )
1038 {
1039     return false;
1040 }
1041 
ValueChanged(unsigned int WXUNUSED (col),unsigned int row)1042 bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row )
1043 {
1044     wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight );
1045     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1046     Refresh( true, &rect );
1047 
1048     return true;
1049 }
1050 
RowsReordered(unsigned int * WXUNUSED (new_order))1051 bool wxDataViewMainWindow::RowsReordered( unsigned int *WXUNUSED(new_order) )
1052 {
1053     Refresh();
1054 
1055     return true;
1056 }
1057 
Cleared()1058 bool wxDataViewMainWindow::Cleared()
1059 {
1060     return false;
1061 }
1062 
UpdateDisplay()1063 void wxDataViewMainWindow::UpdateDisplay()
1064 {
1065     m_dirty = true;
1066 }
1067 
OnInternalIdle()1068 void wxDataViewMainWindow::OnInternalIdle()
1069 {
1070     wxWindow::OnInternalIdle();
1071 
1072     if (m_dirty)
1073     {
1074         RecalculateDisplay();
1075         m_dirty = false;
1076     }
1077 }
1078 
RecalculateDisplay()1079 void wxDataViewMainWindow::RecalculateDisplay()
1080 {
1081     wxDataViewListModel *model = GetOwner()->GetModel();
1082     if (!model)
1083     {
1084         Refresh();
1085         return;
1086     }
1087 
1088     int width = 0;
1089     unsigned int cols = GetOwner()->GetNumberOfColumns();
1090     unsigned int i;
1091     for (i = 0; i < cols; i++)
1092     {
1093         wxDataViewColumn *col = GetOwner()->GetColumn( i );
1094         width += col->GetWidth();
1095     }
1096 
1097     int height = model->GetNumberOfRows() * m_lineHeight;
1098 
1099     SetVirtualSize( width, height );
1100     GetOwner()->SetScrollRate( 10, m_lineHeight );
1101 
1102     Refresh();
1103 }
1104 
ScrollWindow(int dx,int dy,const wxRect * rect)1105 void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1106 {
1107     wxWindow::ScrollWindow( dx, dy, rect );
1108     GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
1109 }
1110 
OnPaint(wxPaintEvent & WXUNUSED (event))1111 void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1112 {
1113     wxAutoBufferedPaintDC dc( this );
1114 
1115     dc.SetBackground(GetBackgroundColour());
1116     dc.Clear();
1117 
1118     GetOwner()->PrepareDC( dc );
1119 
1120     dc.SetFont( GetFont() );
1121 
1122     wxRect update = GetUpdateRegion().GetBox();
1123     m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
1124 
1125     wxDataViewListModel *model = GetOwner()->GetModel();
1126 
1127     unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
1128     unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
1129                                (int)(model->GetNumberOfRows()-item_start) );
1130 
1131 
1132 
1133     unsigned int item;
1134     for (item = item_start; item < item_start+item_count; item++)
1135     {
1136         if (m_selection.Index( item ) != wxNOT_FOUND)
1137         {
1138             int flags = wxCONTROL_SELECTED;
1139             if (item == m_currentRow)
1140                 flags |= wxCONTROL_CURRENT;
1141             if (m_hasFocus)
1142                 flags |= wxCONTROL_FOCUSED;
1143             wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
1144             wxRendererNative::Get().DrawItemSelectionRect
1145                                 (
1146                                     this,
1147                                     dc,
1148                                     rect,
1149                                     flags
1150                                 );
1151         }
1152         else
1153         {
1154             if (item == m_currentRow)
1155             {
1156                 int flags = wxCONTROL_CURRENT;
1157                 if (m_hasFocus)
1158                     flags |= wxCONTROL_FOCUSED;  // should have no effect
1159                 wxRect rect( 0, item*m_lineHeight+1, GetEndOfLastCol(), m_lineHeight-2 );
1160                 wxRendererNative::Get().DrawItemSelectionRect
1161                                 (
1162                                     this,
1163                                     dc,
1164                                     rect,
1165                                     flags
1166                                 );
1167 
1168             }
1169         }
1170     }
1171 
1172     wxRect cell_rect;
1173     cell_rect.x = 0;
1174     cell_rect.height = m_lineHeight;
1175     unsigned int cols = GetOwner()->GetNumberOfColumns();
1176     unsigned int i;
1177     for (i = 0; i < cols; i++)
1178     {
1179         wxDataViewColumn *col = GetOwner()->GetColumn( i );
1180         wxDataViewRenderer *cell = col->GetRenderer();
1181         cell_rect.width = col->GetWidth();
1182 
1183         for (item = item_start; item < item_start+item_count; item++)
1184         {
1185             cell_rect.y = item*m_lineHeight;
1186             wxVariant value;
1187             model->GetValue( value, col->GetModelColumn(), item );
1188             cell->SetValue( value );
1189             wxSize size = cell->GetSize();
1190             // cannot be bigger than allocated space
1191             size.x = wxMin( size.x, cell_rect.width );
1192             size.y = wxMin( size.y, cell_rect.height );
1193             // TODO: check for left/right/centre alignment here
1194             wxRect item_rect;
1195             // for now: centre
1196             item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
1197             item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
1198 
1199             item_rect.width = size.x;
1200             item_rect.height= size.y;
1201 
1202             int state = 0;
1203             if (item == m_currentRow)
1204                 state |= wxDATAVIEW_CELL_SELECTED;
1205             cell->Render( item_rect, &dc, state );
1206         }
1207 
1208         cell_rect.x += cell_rect.width;
1209     }
1210 }
1211 
GetCountPerPage()1212 int wxDataViewMainWindow::GetCountPerPage()
1213 {
1214     wxSize size = GetClientSize();
1215     return size.y / m_lineHeight;
1216 }
1217 
GetEndOfLastCol()1218 int wxDataViewMainWindow::GetEndOfLastCol()
1219 {
1220     int width = 0;
1221     unsigned int i;
1222     for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++)
1223     {
1224         wxDataViewColumn *c = GetOwner()->GetColumn( i );
1225         width += c->GetWidth();
1226     }
1227     return width;
1228 }
1229 
GetFirstVisibleRow()1230 unsigned int wxDataViewMainWindow::GetFirstVisibleRow()
1231 {
1232     int x = 0;
1233     int y = 0;
1234     m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1235 
1236     return y / m_lineHeight;
1237 }
1238 
GetLastVisibleRow()1239 unsigned int wxDataViewMainWindow::GetLastVisibleRow()
1240 {
1241     wxSize client_size = GetClientSize();
1242     m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, &client_size.x, &client_size.y );
1243 
1244     return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 );
1245 }
1246 
GetRowCount()1247 unsigned int wxDataViewMainWindow::GetRowCount()
1248 {
1249     return GetOwner()->GetModel()->GetNumberOfRows();
1250 }
1251 
ChangeCurrentRow(unsigned int row)1252 void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
1253 {
1254     m_currentRow = row;
1255 
1256     // send event
1257 }
1258 
SelectAllRows(bool on)1259 void wxDataViewMainWindow::SelectAllRows( bool on )
1260 {
1261     if (IsEmpty())
1262         return;
1263 
1264     if (on)
1265     {
1266         m_selection.Clear();
1267         for (unsigned int i = 0; i < GetRowCount(); i++)
1268             m_selection.Add( i );
1269         Refresh();
1270     }
1271     else
1272     {
1273         unsigned int first_visible = GetFirstVisibleRow();
1274         unsigned int last_visible = GetLastVisibleRow();
1275         unsigned int i;
1276         for (i = 0; i < m_selection.GetCount(); i++)
1277         {
1278             unsigned int row = m_selection[i];
1279             if ((row >= first_visible) && (row <= last_visible))
1280                 RefreshRow( row );
1281         }
1282         m_selection.Clear();
1283     }
1284 }
1285 
SelectRow(unsigned int row,bool on)1286 void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
1287 {
1288     if (m_selection.Index( row ) == wxNOT_FOUND)
1289     {
1290         if (on)
1291         {
1292             m_selection.Add( row );
1293             RefreshRow( row );
1294         }
1295     }
1296     else
1297     {
1298         if (!on)
1299         {
1300             m_selection.Remove( row );
1301             RefreshRow( row );
1302         }
1303     }
1304 }
1305 
SelectRows(unsigned int from,unsigned int to,bool on)1306 void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
1307 {
1308     if (from > to)
1309     {
1310         unsigned int tmp = from;
1311         from = to;
1312         to = tmp;
1313     }
1314 
1315     unsigned int i;
1316     for (i = from; i <= to; i++)
1317     {
1318         if (m_selection.Index( i ) == wxNOT_FOUND)
1319         {
1320             if (on)
1321                 m_selection.Add( i );
1322         }
1323         else
1324         {
1325             if (!on)
1326                 m_selection.Remove( i );
1327         }
1328     }
1329     RefreshRows( from, to );
1330 }
1331 
ReverseRowSelection(unsigned int row)1332 void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
1333 {
1334     if (m_selection.Index( row ) == wxNOT_FOUND)
1335         m_selection.Add( row );
1336     else
1337         m_selection.Remove( row );
1338     RefreshRow( row );
1339 }
1340 
IsRowSelected(unsigned int row)1341 bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
1342 {
1343     return (m_selection.Index( row ) != wxNOT_FOUND);
1344 }
1345 
RefreshRow(unsigned int row)1346 void wxDataViewMainWindow::RefreshRow( unsigned int row )
1347 {
1348     wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
1349     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1350 
1351     wxSize client_size = GetClientSize();
1352     wxRect client_rect( 0, 0, client_size.x, client_size.y );
1353     wxRect intersect_rect = client_rect.Intersect( rect );
1354     if (intersect_rect.width > 0)
1355         Refresh( true, &intersect_rect );
1356 }
1357 
RefreshRows(unsigned int from,unsigned int to)1358 void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
1359 {
1360     if (from > to)
1361     {
1362         unsigned int tmp = to;
1363         to = from;
1364         from = tmp;
1365     }
1366 
1367     wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
1368     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1369 
1370     wxSize client_size = GetClientSize();
1371     wxRect client_rect( 0, 0, client_size.x, client_size.y );
1372     wxRect intersect_rect = client_rect.Intersect( rect );
1373     if (intersect_rect.width > 0)
1374         Refresh( true, &intersect_rect );
1375 }
1376 
RefreshRowsAfter(unsigned int firstRow)1377 void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
1378 {
1379     unsigned int count = GetRowCount();
1380     if (firstRow > count)
1381         return;
1382 
1383     wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
1384     m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1385 
1386     wxSize client_size = GetClientSize();
1387     wxRect client_rect( 0, 0, client_size.x, client_size.y );
1388     wxRect intersect_rect = client_rect.Intersect( rect );
1389     if (intersect_rect.width > 0)
1390         Refresh( true, &intersect_rect );
1391 }
1392 
OnArrowChar(unsigned int newCurrent,const wxKeyEvent & event)1393 void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
1394 {
1395     wxCHECK_RET( newCurrent < GetRowCount(),
1396                  _T("invalid item index in OnArrowChar()") );
1397 
1398     // if there is no selection, we cannot move it anywhere
1399     if (!HasCurrentRow())
1400         return;
1401 
1402     unsigned int oldCurrent = m_currentRow;
1403 
1404     // in single selection we just ignore Shift as we can't select several
1405     // items anyhow
1406     if ( event.ShiftDown() && !IsSingleSel() )
1407     {
1408         RefreshRow( oldCurrent );
1409 
1410         ChangeCurrentRow( newCurrent );
1411 
1412         // select all the items between the old and the new one
1413         if ( oldCurrent > newCurrent )
1414         {
1415             newCurrent = oldCurrent;
1416             oldCurrent = m_currentRow;
1417         }
1418 
1419         SelectRows( oldCurrent, newCurrent, true );
1420     }
1421     else // !shift
1422     {
1423         RefreshRow( oldCurrent );
1424 
1425         // all previously selected items are unselected unless ctrl is held
1426         if ( !event.ControlDown() )
1427             SelectAllRows(false);
1428 
1429         ChangeCurrentRow( newCurrent );
1430 
1431         if ( !event.ControlDown() )
1432             SelectRow( m_currentRow, true );
1433         else
1434             RefreshRow( m_currentRow );
1435     }
1436 
1437     // MoveToFocus();
1438 }
1439 
OnChar(wxKeyEvent & event)1440 void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
1441 {
1442     if (event.GetKeyCode() == WXK_TAB)
1443     {
1444         wxNavigationKeyEvent nevent;
1445         nevent.SetWindowChange( event.ControlDown() );
1446         nevent.SetDirection( !event.ShiftDown() );
1447         nevent.SetEventObject( GetParent()->GetParent() );
1448         nevent.SetCurrentFocus( m_parent );
1449         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
1450             return;
1451     }
1452 
1453     // no item -> nothing to do
1454     if (!HasCurrentRow())
1455     {
1456         event.Skip();
1457         return;
1458     }
1459 
1460     // don't use m_linesPerPage directly as it might not be computed yet
1461     const int pageSize = GetCountPerPage();
1462     wxCHECK_RET( pageSize, _T("should have non zero page size") );
1463 
1464     switch ( event.GetKeyCode() )
1465     {
1466         case WXK_UP:
1467             if ( m_currentRow > 0 )
1468                 OnArrowChar( m_currentRow - 1, event );
1469             break;
1470 
1471         case WXK_DOWN:
1472             if ( m_currentRow < GetRowCount() - 1 )
1473                 OnArrowChar( m_currentRow + 1, event );
1474             break;
1475 
1476         case WXK_END:
1477             if (!IsEmpty())
1478                 OnArrowChar( GetRowCount() - 1, event );
1479             break;
1480 
1481         case WXK_HOME:
1482             if (!IsEmpty())
1483                 OnArrowChar( 0, event );
1484             break;
1485 
1486         case WXK_PAGEUP:
1487             {
1488                 int steps = pageSize - 1;
1489                 int index = m_currentRow - steps;
1490                 if (index < 0)
1491                     index = 0;
1492 
1493                 OnArrowChar( index, event );
1494             }
1495             break;
1496 
1497         case WXK_PAGEDOWN:
1498             {
1499                 int steps = pageSize - 1;
1500                 unsigned int index = m_currentRow + steps;
1501                 unsigned int count = GetRowCount();
1502                 if ( index >= count )
1503                     index = count - 1;
1504 
1505                 OnArrowChar( index, event );
1506             }
1507             break;
1508 
1509         default:
1510             event.Skip();
1511     }
1512 }
1513 
OnMouse(wxMouseEvent & event)1514 void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
1515 {
1516     if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1517     {
1518         // let the base handle mouse wheel events.
1519         event.Skip();
1520         return;
1521     }
1522 
1523     int x = event.GetX();
1524     int y = event.GetY();
1525     m_owner->CalcUnscrolledPosition( x, y, &x, &y );
1526 
1527     wxDataViewColumn *col = NULL;
1528 
1529     int xpos = 0;
1530     unsigned int cols = GetOwner()->GetNumberOfColumns();
1531     unsigned int i;
1532     for (i = 0; i < cols; i++)
1533     {
1534         wxDataViewColumn *c = GetOwner()->GetColumn( i );
1535         if (x < xpos + c->GetWidth())
1536         {
1537             col = c;
1538             break;
1539         }
1540         xpos += c->GetWidth();
1541     }
1542     if (!col)
1543         return;
1544     wxDataViewRenderer *cell = col->GetRenderer();
1545 
1546     unsigned int current = y / m_lineHeight;
1547 
1548     if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
1549     {
1550         // Unselect all if below the last row ?
1551         return;
1552     }
1553 
1554     wxDataViewListModel *model = GetOwner()->GetModel();
1555 
1556     if (event.Dragging())
1557     {
1558         if (m_dragCount == 0)
1559         {
1560             // we have to report the raw, physical coords as we want to be
1561             // able to call HitTest(event.m_pointDrag) from the user code to
1562             // get the item being dragged
1563             m_dragStart = event.GetPosition();
1564         }
1565 
1566         m_dragCount++;
1567 
1568         if (m_dragCount != 3)
1569             return;
1570 
1571         if (event.LeftIsDown())
1572         {
1573             // Notify cell about drag
1574         }
1575         return;
1576     }
1577     else
1578     {
1579         m_dragCount = 0;
1580     }
1581 
1582     bool forceClick = false;
1583 
1584     if (event.ButtonDClick())
1585     {
1586         m_renameTimer->Stop();
1587         m_lastOnSame = false;
1588     }
1589 
1590     if (event.LeftDClick())
1591     {
1592         if ( current == m_lineLastClicked )
1593         {
1594             if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
1595             {
1596                 wxVariant value;
1597                 model->GetValue( value, col->GetModelColumn(), current );
1598                 cell->SetValue( value );
1599                 wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight );
1600                 cell->Activate( cell_rect, model, col->GetModelColumn(), current );
1601             }
1602             return;
1603         }
1604         else
1605         {
1606             // The first click was on another item, so don't interpret this as
1607             // a double click, but as a simple click instead
1608             forceClick = true;
1609         }
1610     }
1611 
1612     if (event.LeftUp())
1613     {
1614         if (m_lineSelectSingleOnUp != (unsigned int)-1)
1615         {
1616             // select single line
1617             SelectAllRows( false );
1618             SelectRow( m_lineSelectSingleOnUp, true );
1619         }
1620 
1621         if (m_lastOnSame)
1622         {
1623             if ((col == m_currentCol) && (current == m_currentRow) &&
1624                 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
1625             {
1626                 m_renameTimer->Start( 100, true );
1627             }
1628         }
1629 
1630         m_lastOnSame = false;
1631         m_lineSelectSingleOnUp = (unsigned int)-1;
1632     }
1633     else
1634     {
1635         // This is necessary, because after a DnD operation in
1636         // from and to ourself, the up event is swallowed by the
1637         // DnD code. So on next non-up event (which means here and
1638         // now) m_lineSelectSingleOnUp should be reset.
1639         m_lineSelectSingleOnUp = (unsigned int)-1;
1640     }
1641 
1642     if (event.RightDown())
1643     {
1644         m_lineBeforeLastClicked = m_lineLastClicked;
1645         m_lineLastClicked = current;
1646 
1647         // If the item is already selected, do not update the selection.
1648         // Multi-selections should not be cleared if a selected item is clicked.
1649         if (!IsRowSelected(current))
1650         {
1651             SelectAllRows(false);
1652             ChangeCurrentRow(current);
1653             SelectRow(m_currentRow,true);
1654         }
1655 
1656         // notify cell about right click
1657         // cell->...
1658 
1659         // Allow generation of context menu event
1660         event.Skip();
1661     }
1662     else if (event.MiddleDown())
1663     {
1664         // notify cell about middle click
1665         // cell->...
1666     }
1667     if (event.LeftDown() || forceClick)
1668     {
1669 #ifdef __WXMSW__
1670         SetFocus();
1671 #endif
1672 
1673         m_lineBeforeLastClicked = m_lineLastClicked;
1674         m_lineLastClicked = current;
1675 
1676         unsigned int oldCurrentRow = m_currentRow;
1677         bool oldWasSelected = IsRowSelected(m_currentRow);
1678 
1679         bool cmdModifierDown = event.CmdDown();
1680         if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
1681         {
1682             if ( IsSingleSel() || !IsRowSelected(current) )
1683             {
1684                 SelectAllRows( false );
1685 
1686                 ChangeCurrentRow(current);
1687 
1688                 SelectRow(m_currentRow,true);
1689             }
1690             else // multi sel & current is highlighted & no mod keys
1691             {
1692                 m_lineSelectSingleOnUp = current;
1693                 ChangeCurrentRow(current); // change focus
1694             }
1695         }
1696         else // multi sel & either ctrl or shift is down
1697         {
1698             if (cmdModifierDown)
1699             {
1700                 ChangeCurrentRow(current);
1701 
1702                 ReverseRowSelection(m_currentRow);
1703             }
1704             else if (event.ShiftDown())
1705             {
1706                 ChangeCurrentRow(current);
1707 
1708                 unsigned int lineFrom = oldCurrentRow,
1709                        lineTo = current;
1710 
1711                 if ( lineTo < lineFrom )
1712                 {
1713                     lineTo = lineFrom;
1714                     lineFrom = m_currentRow;
1715                 }
1716 
1717                 SelectRows(lineFrom, lineTo, true);
1718             }
1719             else // !ctrl, !shift
1720             {
1721                 // test in the enclosing if should make it impossible
1722                 wxFAIL_MSG( _T("how did we get here?") );
1723             }
1724         }
1725 
1726         if (m_currentRow != oldCurrentRow)
1727             RefreshRow( oldCurrentRow );
1728 
1729         wxDataViewColumn *oldCurrentCol = m_currentCol;
1730 
1731         // Update selection here...
1732         m_currentCol = col;
1733 
1734         m_lastOnSame = !forceClick && ((col == oldCurrentCol) && (current == oldCurrentRow)) && oldWasSelected;
1735     }
1736 }
1737 
OnSetFocus(wxFocusEvent & event)1738 void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
1739 {
1740     m_hasFocus = true;
1741 
1742     if (HasCurrentRow())
1743         Refresh();
1744 
1745     event.Skip();
1746 }
1747 
OnKillFocus(wxFocusEvent & event)1748 void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
1749 {
1750     m_hasFocus = false;
1751 
1752     if (HasCurrentRow())
1753         Refresh();
1754 
1755     event.Skip();
1756 }
1757 
1758 //-----------------------------------------------------------------------------
1759 // wxDataViewCtrl
1760 //-----------------------------------------------------------------------------
1761 
IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl,wxDataViewCtrlBase)1762 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
1763 
1764 BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
1765     EVT_SIZE(wxDataViewCtrl::OnSize)
1766 END_EVENT_TABLE()
1767 
1768 wxDataViewCtrl::~wxDataViewCtrl()
1769 {
1770     if (m_notifier)
1771         GetModel()->RemoveNotifier( m_notifier );
1772 }
1773 
Init()1774 void wxDataViewCtrl::Init()
1775 {
1776     m_notifier = NULL;
1777 }
1778 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator)1779 bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
1780            const wxPoint& pos, const wxSize& size,
1781            long style, const wxValidator& validator )
1782 {
1783     if (!wxControl::Create( parent, id, pos, size, style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
1784         return false;
1785 
1786     Init();
1787 
1788 #ifdef __WXMAC__
1789     MacSetClipChildren( true ) ;
1790 #endif
1791 
1792     m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
1793 #ifdef __WXMSW__
1794     m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,22) );
1795 #else
1796     m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY, wxDefaultPosition, wxSize(wxDefaultCoord,25) );
1797 #endif
1798 
1799     SetTargetWindow( m_clientArea );
1800 
1801     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
1802     sizer->Add( m_headerArea, 0, wxGROW );
1803     sizer->Add( m_clientArea, 1, wxGROW );
1804     SetSizer( sizer );
1805 
1806     return true;
1807 }
1808 
1809 #ifdef __WXMSW__
MSWWindowProc(WXUINT nMsg,WXWPARAM wParam,WXLPARAM lParam)1810 WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
1811                                        WXWPARAM wParam,
1812                                        WXLPARAM lParam)
1813 {
1814     WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
1815 
1816 #ifndef __WXWINCE__
1817     // we need to process arrows ourselves for scrolling
1818     if ( nMsg == WM_GETDLGCODE )
1819     {
1820         rc |= DLGC_WANTARROWS;
1821     }
1822 #endif
1823 
1824     return rc;
1825 }
1826 #endif
1827 
OnSize(wxSizeEvent & WXUNUSED (event))1828 void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
1829 {
1830     // We need to override OnSize so that our scrolled
1831     // window a) does call Layout() to use sizers for
1832     // positioning the controls but b) does not query
1833     // the sizer for their size and use that for setting
1834     // the scrollable area as set that ourselves by
1835     // calling SetScrollbar() further down.
1836 
1837     Layout();
1838 
1839     AdjustScrollbars();
1840 }
1841 
AssociateModel(wxDataViewListModel * model)1842 bool wxDataViewCtrl::AssociateModel( wxDataViewListModel *model )
1843 {
1844     if (!wxDataViewCtrlBase::AssociateModel( model ))
1845         return false;
1846 
1847     m_notifier = new wxGenericDataViewListModelNotifier( m_clientArea );
1848 
1849     model->AddNotifier( m_notifier );
1850 
1851     m_clientArea->UpdateDisplay();
1852 
1853     return true;
1854 }
1855 
AppendColumn(wxDataViewColumn * col)1856 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
1857 {
1858     if (!wxDataViewCtrlBase::AppendColumn(col))
1859         return false;
1860 
1861     m_clientArea->UpdateDisplay();
1862 
1863     return true;
1864 }
1865 
SetSelection(int WXUNUSED (row))1866 void wxDataViewCtrl::SetSelection( int WXUNUSED(row) )
1867 {
1868     // FIXME - TODO
1869 }
1870 
SetSelectionRange(unsigned int WXUNUSED (from),unsigned int WXUNUSED (to))1871 void wxDataViewCtrl::SetSelectionRange( unsigned int WXUNUSED(from), unsigned int WXUNUSED(to) )
1872 {
1873     // FIXME - TODO
1874 }
1875 
SetSelections(const wxArrayInt & WXUNUSED (aSelections))1876 void wxDataViewCtrl::SetSelections( const wxArrayInt& WXUNUSED(aSelections) )
1877 {
1878     // FIXME - TODO
1879 }
1880 
Unselect(unsigned int WXUNUSED (row))1881 void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) )
1882 {
1883     // FIXME - TODO
1884 }
1885 
IsSelected(unsigned int WXUNUSED (row)) const1886 bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const
1887 {
1888     // FIXME - TODO
1889 
1890     return false;
1891 }
1892 
GetSelection() const1893 int wxDataViewCtrl::GetSelection() const
1894 {
1895     // FIXME - TODO
1896 
1897     return -1;
1898 }
1899 
GetSelections(wxArrayInt & WXUNUSED (aSelections)) const1900 int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const
1901 {
1902     // FIXME - TODO
1903 
1904     return 0;
1905 }
1906 
1907 #endif
1908     // !wxUSE_GENERICDATAVIEWCTRL
1909 
1910 #endif
1911     // wxUSE_DATAVIEWCTRL
1912