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