]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datavgen.cpp
Implement wxWindow::SetCursor to invalidate Cocoa's cursor rects.
[wxWidgets.git] / src / generic / datavgen.cpp
CommitLineData
4ed7af08 1/////////////////////////////////////////////////////////////////////////////
f554a14b 2// Name: src/generic/datavgen.cpp
4ed7af08
RR
3// Purpose: wxDataViewCtrl generic implementation
4// Author: Robert Roebling
87f0efe2 5// Modified by: Francesco Montorsi, Guru Kathiresan, Otto Wyss
4ed7af08
RR
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// For compilers that support precompilation, includes "wx.h".
12#include "wx/wxprec.h"
13
ed4b0fdc
WS
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
4ed7af08
RR
18#if wxUSE_DATAVIEWCTRL
19
20#include "wx/dataview.h"
21
22#ifdef wxUSE_GENERICDATAVIEWCTRL
23
f554a14b 24#ifndef WX_PRECOMP
57bd4c60 25 #ifdef __WXMSW__
87f0efe2 26 #include "wx/msw/private.h"
57bd4c60 27 #include "wx/msw/wrapwin.h"
87f0efe2 28 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
57bd4c60 29 #endif
f554a14b
WS
30 #include "wx/sizer.h"
31 #include "wx/log.h"
ed4b0fdc 32 #include "wx/dcclient.h"
c0badb70 33 #include "wx/timer.h"
9eddec69 34 #include "wx/settings.h"
8d0ca292 35 #include "wx/msgdlg.h"
99d471a5 36 #include "wx/dcscreen.h"
f554a14b
WS
37#endif
38
4ed7af08 39#include "wx/stockitem.h"
4ed7af08
RR
40#include "wx/calctrl.h"
41#include "wx/popupwin.h"
4ed7af08 42#include "wx/renderer.h"
2e992e06 43#include "wx/dcbuffer.h"
2586d4a1 44#include "wx/icon.h"
4ed7af08 45
4ed7af08
RR
46//-----------------------------------------------------------------------------
47// classes
48//-----------------------------------------------------------------------------
49
50class wxDataViewCtrl;
51
9861f022
RR
52static const int SCROLL_UNIT_X = 15;
53
54// the cell padding on the left/right
55static const int PADDING_RIGHTLEFT = 3;
56
57// the cell padding on the top/bottom
58static const int PADDING_TOPBOTTOM = 1;
59
3b6280be
RR
60// the expander space margin
61static const int EXPANDER_MARGIN = 4;
9861f022 62
a0f3af5f
RR
63//-----------------------------------------------------------------------------
64// wxDataViewHeaderWindow
65//-----------------------------------------------------------------------------
4ed7af08 66
87f0efe2
RR
67#define USE_NATIVE_HEADER_WINDOW 1
68
c741d33f
VZ
69// NB: for some reason, this class must be dllexport'ed or we get warnings from
70// MSVC in DLL build
71class WXDLLIMPEXP_ADV wxDataViewHeaderWindowBase : public wxControl
87f0efe2
RR
72{
73public:
74 wxDataViewHeaderWindowBase()
75 { m_owner = NULL; }
76
77 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 78 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
79 const wxString &name)
80 {
81 return wxWindow::Create(parent, id, pos, size, wxNO_BORDER, name);
82 }
83
84 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
85 wxDataViewCtrl *GetOwner() { return m_owner; }
86
87 // called on column addition/removal
88 virtual void UpdateDisplay() { /* by default, do nothing */ }
89
87f0efe2 90 // returns the n-th column
9861f022 91 virtual wxDataViewColumn *GetColumn(unsigned int n)
87f0efe2
RR
92 {
93 wxASSERT(m_owner);
c741d33f 94 wxDataViewColumn *ret = m_owner->GetColumn(n);
87f0efe2
RR
95 wxASSERT(ret);
96
c741d33f 97 return ret;
87f0efe2
RR
98 }
99
100protected:
101 wxDataViewCtrl *m_owner;
102
103 // sends an event generated from the n-th wxDataViewColumn
104 void SendEvent(wxEventType type, unsigned int n);
105};
106
107// on wxMSW the header window (only that part however) can be made native!
108#if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
109
9861f022 110#define COLUMN_WIDTH_OFFSET 2
87f0efe2
RR
111#define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow
112
113class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase
4ed7af08
RR
114{
115public:
87f0efe2
RR
116
117 wxDataViewHeaderWindowMSW( wxDataViewCtrl *parent,
9861f022
RR
118 wxWindowID id,
119 const wxPoint &pos = wxDefaultPosition,
120 const wxSize &size = wxDefaultSize,
121 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 122 {
87f0efe2
RR
123 Create(parent, id, pos, size, name);
124 }
4ed7af08 125
87f0efe2 126 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 127 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
128 const wxString &name);
129
130 ~wxDataViewHeaderWindowMSW();
131
9861f022
RR
132 // called when any column setting is changed and/or changed
133 // the column count
87f0efe2
RR
134 virtual void UpdateDisplay();
135
136 // called when the main window gets scrolled
137 virtual void ScrollWindow(int dx, int dy, const wxRect *rect = NULL);
138
139protected:
140 virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
9861f022
RR
141 virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags);
142
143 unsigned int GetColumnIdxFromHeader(NMHEADER *nmHDR);
144
145 wxDataViewColumn *GetColumnFromHeader(NMHEADER *nmHDR)
146 { return GetColumn(GetColumnIdxFromHeader(nmHDR)); }
147
87f0efe2
RR
148private:
149 DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW)
150};
151
152#else // !defined(__WXMSW__)
153
154#define HEADER_WINDOW_HEIGHT 25
9861f022
RR
155#define HEADER_HORIZ_BORDER 5
156#define HEADER_VERT_BORDER 3
87f0efe2
RR
157#define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow
158
159class wxGenericDataViewHeaderWindow : public wxDataViewHeaderWindowBase
160{
161public:
162 wxGenericDataViewHeaderWindow( wxDataViewCtrl *parent,
163 wxWindowID id,
164 const wxPoint &pos = wxDefaultPosition,
165 const wxSize &size = wxDefaultSize,
166 const wxString &name = wxT("wxdataviewctrlheaderwindow") )
c741d33f 167 {
87f0efe2
RR
168 Init();
169 Create(parent, id, pos, size, name);
170 }
171
172 bool Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f 173 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
174 const wxString &name);
175
176 ~wxGenericDataViewHeaderWindow()
177 {
178 delete m_resizeCursor;
179 }
180
c3112d56
RR
181 virtual void UpdateDisplay() { Refresh(); }
182
87f0efe2 183 // event handlers:
4ed7af08 184
a0f3af5f
RR
185 void OnPaint( wxPaintEvent &event );
186 void OnMouse( wxMouseEvent &event );
187 void OnSetFocus( wxFocusEvent &event );
f554a14b 188
87f0efe2
RR
189
190protected:
191
192 // vars used for column resizing:
193
a0f3af5f 194 wxCursor *m_resizeCursor;
87f0efe2
RR
195 const wxCursor *m_currentCursor;
196 bool m_isDragging;
197
198 bool m_dirty; // needs refresh?
199 int m_column; // index of the column being resized
200 int m_currentX; // divider line position in logical (unscrolled) coords
c741d33f 201 int m_minX; // minimal position beyond which the divider line
87f0efe2
RR
202 // can't be dragged in logical coords
203
9861f022
RR
204 // the pen used to draw the current column width drag line
205 // when resizing the columsn
206 wxPen m_penCurrent;
207
208
87f0efe2
RR
209 // internal utilities:
210
211 void Init()
212 {
213 m_currentCursor = (wxCursor *) NULL;
214 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
215
216 m_isDragging = false;
217 m_dirty = false;
218
219 m_column = wxNOT_FOUND;
220 m_currentX = 0;
221 m_minX = 0;
9861f022
RR
222
223 wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
224 m_penCurrent = wxPen(col, 1, wxSOLID);
87f0efe2
RR
225 }
226
227 void DrawCurrent();
228 void AdjustDC(wxDC& dc);
f554a14b 229
a0f3af5f 230private:
87f0efe2 231 DECLARE_DYNAMIC_CLASS(wxGenericDataViewHeaderWindow)
a0f3af5f
RR
232 DECLARE_EVENT_TABLE()
233};
4ed7af08 234
87f0efe2
RR
235#endif // defined(__WXMSW__)
236
0fcce6b9
RR
237//-----------------------------------------------------------------------------
238// wxDataViewRenameTimer
239//-----------------------------------------------------------------------------
240
241class wxDataViewRenameTimer: public wxTimer
242{
243private:
244 wxDataViewMainWindow *m_owner;
245
246public:
247 wxDataViewRenameTimer( wxDataViewMainWindow *owner );
248 void Notify();
249};
250
aba9bfd0
RR
251//-----------------------------------------------------------------------------
252// wxDataViewTreeNode
253//-----------------------------------------------------------------------------
254class wxDataViewTreeNode;
255WX_DEFINE_ARRAY_PTR( wxDataViewTreeNode *, wxDataViewTreeNodes );
256
257class wxDataViewTreeNode
258{
259public:
260 wxDataViewTreeNode( wxDataViewTreeNode * parent )
261 { this->parent = parent;
262 if( parent == NULL )
263 open = true;
264 else
265 open = false;
704c3490 266 hasChildren = false;
aba9bfd0
RR
267 }
268 //I don't know what I need to do in the destructure
269 ~wxDataViewTreeNode()
270 { }
271
272 wxDataViewTreeNode * GetParent() { return parent; }
273 void SetParent( wxDataViewTreeNode * parent ) { this->parent = parent; }
704c3490 274 wxDataViewTreeNodes & GetChildren() { return children; }
aba9bfd0
RR
275 void SetChildren( wxDataViewTreeNodes children ) { this->children = children; }
276
277 wxDataViewTreeNode * GetChild( unsigned int n ) { return children.Item( n ); }
278 void InsertChild( wxDataViewTreeNode * child, unsigned int n) { children.Insert( child, n); }
279 void AppendChild( wxDataViewTreeNode * child ) { children.Add( child ); }
280
281 wxDataViewItem & GetItem() { return item; }
282 void SetItem( wxDataViewItem & item ) { this->item = item; }
283
284 unsigned int GetChildrenNumber() { return children.GetCount(); }
3b6280be
RR
285 int GetIndentLevel()
286 {
287 int ret = 0 ;
288 wxDataViewTreeNode * node = this;
289 while( node->GetParent()->GetParent() != NULL )
290 {
291 node = node->GetParent();
292 ret ++;
293 }
294 return ret;
295 }
aba9bfd0
RR
296
297 bool IsOpen() { return open; }
3b6280be 298 void ToggleOpen(){ open = !open; }
704c3490
RR
299 bool HasChildren() { return hasChildren; }
300 void SetHasChildren( bool has ){ hasChildren = has; }
aba9bfd0
RR
301private:
302 wxDataViewTreeNode * parent;
303 wxDataViewTreeNodes children;
304 wxDataViewItem item;
305 bool open;
704c3490 306 bool hasChildren;
aba9bfd0
RR
307};
308
a0f3af5f
RR
309//-----------------------------------------------------------------------------
310// wxDataViewMainWindow
311//-----------------------------------------------------------------------------
4ed7af08 312
c741d33f 313WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSelection,
87f0efe2 314 WXDLLIMPEXP_ADV);
cab07038 315
a0f3af5f 316class wxDataViewMainWindow: public wxWindow
4ed7af08 317{
a0f3af5f
RR
318public:
319 wxDataViewMainWindow( wxDataViewCtrl *parent,
320 wxWindowID id,
321 const wxPoint &pos = wxDefaultPosition,
322 const wxSize &size = wxDefaultSize,
323 const wxString &name = wxT("wxdataviewctrlmainwindow") );
d3c7fc99 324 virtual ~wxDataViewMainWindow();
4ed7af08 325
aba9bfd0
RR
326 // notifications from wxDataViewModel
327 bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
328 bool ItemDeleted( const wxDataViewItem &item );
329 bool ItemChanged( const wxDataViewItem &item );
330 bool ValueChanged( const wxDataViewItem &item, unsigned int col );
a0f3af5f 331 bool Cleared();
4ed7af08 332
a0f3af5f
RR
333 void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; }
334 wxDataViewCtrl *GetOwner() { return m_owner; }
9861f022 335 const wxDataViewCtrl *GetOwner() const { return m_owner; }
4ed7af08 336
a0f3af5f 337 void OnPaint( wxPaintEvent &event );
0a71f9e9 338 void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event);
cab07038 339 void OnChar( wxKeyEvent &event );
a0f3af5f
RR
340 void OnMouse( wxMouseEvent &event );
341 void OnSetFocus( wxFocusEvent &event );
cab07038 342 void OnKillFocus( wxFocusEvent &event );
f554a14b 343
a0f3af5f
RR
344 void UpdateDisplay();
345 void RecalculateDisplay();
346 void OnInternalIdle();
f554a14b 347
0fcce6b9 348 void OnRenameTimer();
0fcce6b9 349
9861f022 350 void ScrollWindow( int dx, int dy, const wxRect *rect = NULL );
120b9b05 351
0a71f9e9
RR
352 bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; }
353 void ChangeCurrentRow( unsigned int row );
120b9b05 354
47b378bd 355 bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }
cab07038 356 bool IsEmpty() { return GetRowCount() == 0; }
120b9b05 357
9861f022
RR
358 int GetCountPerPage() const;
359 int GetEndOfLastCol() const;
360 unsigned int GetFirstVisibleRow() const;
3b6280be
RR
361 //I change this method to un const because in the tree view, the displaying number of the tree are changing along with the expanding/collapsing of the tree nodes
362 unsigned int GetLastVisibleRow();
363 unsigned int GetRowCount() ;
120b9b05 364
704c3490
RR
365 wxDataViewItem GetSelection();
366
87f0efe2 367 void Select( const wxArrayInt& aSelections );
cab07038 368 void SelectAllRows( bool on );
0a71f9e9
RR
369 void SelectRow( unsigned int row, bool on );
370 void SelectRows( unsigned int from, unsigned int to, bool on );
371 void ReverseRowSelection( unsigned int row );
372 bool IsRowSelected( unsigned int row );
120b9b05 373
0a71f9e9
RR
374 void RefreshRow( unsigned int row );
375 void RefreshRows( unsigned int from, unsigned int to );
376 void RefreshRowsAfter( unsigned int firstRow );
120b9b05 377
9861f022
RR
378 // returns the colour to be used for drawing the rules
379 wxColour GetRuleColour() const
380 {
381 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
382 }
383
384 //void EnsureVisible( unsigned int row );
385 wxRect GetLineRect( unsigned int row ) const;
386
aba9bfd0
RR
387 //Some useful functions for row and item mapping
388 wxDataViewItem GetItemByRow( unsigned int row );
389 unsigned int GetRowByItem( const wxDataViewItem & item );
390
391 //Methods for building the mapping tree
392 void BuildTree( wxDataViewModel * model );
393 void DestroyTree();
3b6280be
RR
394private:
395 wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row );
704c3490
RR
396 //We did not need this temporarily
397 //wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
3b6280be
RR
398
399 int RecalculateCount() ;
400
401 void OnExpanding( unsigned int row );
402 void OnCollapsing( unsigned int row );
aba9bfd0 403
a0f3af5f 404private:
0fcce6b9
RR
405 wxDataViewCtrl *m_owner;
406 int m_lineHeight;
407 bool m_dirty;
120b9b05 408
0fcce6b9 409 wxDataViewColumn *m_currentCol;
99d471a5 410 unsigned int m_currentRow;
cab07038 411 wxDataViewSelection m_selection;
120b9b05 412
0fcce6b9 413 wxDataViewRenameTimer *m_renameTimer;
0fcce6b9 414 bool m_lastOnSame;
f554a14b 415
cab07038
RR
416 bool m_hasFocus;
417
e21f75bd
RR
418 int m_dragCount;
419 wxPoint m_dragStart;
420
421 // for double click logic
0a71f9e9 422 unsigned int m_lineLastClicked,
e21f75bd
RR
423 m_lineBeforeLastClicked,
424 m_lineSelectSingleOnUp;
cab07038 425
9861f022
RR
426 // the pen used to draw horiz/vertical rules
427 wxPen m_penRule;
428
3b6280be
RR
429 // the pen used to draw the expander and the lines
430 wxPen m_penExpander;
431
aba9bfd0
RR
432 //This is the tree structure of the model
433 wxDataViewTreeNode * m_root;
3b6280be 434 int m_count;
a0f3af5f
RR
435private:
436 DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
437 DECLARE_EVENT_TABLE()
438};
4ed7af08 439
f554a14b 440// ---------------------------------------------------------
aba9bfd0 441// wxGenericDataViewModelNotifier
f554a14b 442// ---------------------------------------------------------
a0f3af5f 443
aba9bfd0 444class wxGenericDataViewModelNotifier: public wxDataViewModelNotifier
4ed7af08 445{
a0f3af5f 446public:
aba9bfd0 447 wxGenericDataViewModelNotifier( wxDataViewMainWindow *mainWindow )
a0f3af5f 448 { m_mainWindow = mainWindow; }
f554a14b 449
aba9bfd0
RR
450 virtual bool ItemAdded( const wxDataViewItem & parent, const wxDataViewItem & item )
451 { return m_mainWindow->ItemAdded( parent , item ); }
452 virtual bool ItemDeleted( const wxDataViewItem & item )
453 { return m_mainWindow->ItemDeleted( item ); }
454 virtual bool ItemChanged( const wxDataViewItem & item )
455 { return m_mainWindow->ItemChanged(item); }
456 virtual bool ValueChanged( const wxDataViewItem & item , unsigned int col )
457 { return m_mainWindow->ValueChanged( item, col ); }
a0f3af5f
RR
458 virtual bool Cleared()
459 { return m_mainWindow->Cleared(); }
f554a14b 460
a0f3af5f
RR
461 wxDataViewMainWindow *m_mainWindow;
462};
4ed7af08 463
f554a14b 464// ---------------------------------------------------------
baa9ebc4 465// wxDataViewRenderer
f554a14b 466// ---------------------------------------------------------
4ed7af08 467
baa9ebc4 468IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase)
4ed7af08 469
c741d33f 470wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype,
9861f022
RR
471 wxDataViewCellMode mode,
472 int align) :
473 wxDataViewRendererBase( varianttype, mode, align )
4ed7af08 474{
3d9d7cc4 475 m_dc = NULL;
9861f022
RR
476 m_align = align;
477 m_mode = mode;
4ed7af08
RR
478}
479
baa9ebc4 480wxDataViewRenderer::~wxDataViewRenderer()
3d9d7cc4
RR
481{
482 if (m_dc)
483 delete m_dc;
484}
485
baa9ebc4 486wxDC *wxDataViewRenderer::GetDC()
3d9d7cc4
RR
487{
488 if (m_dc == NULL)
489 {
490 if (GetOwner() == NULL)
491 return NULL;
492 if (GetOwner()->GetOwner() == NULL)
493 return NULL;
494 m_dc = new wxClientDC( GetOwner()->GetOwner() );
495 }
f554a14b 496
3d9d7cc4
RR
497 return m_dc;
498}
499
f554a14b 500// ---------------------------------------------------------
baa9ebc4 501// wxDataViewCustomRenderer
f554a14b 502// ---------------------------------------------------------
3d9d7cc4 503
baa9ebc4 504IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
3d9d7cc4 505
baa9ebc4 506wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
9861f022
RR
507 wxDataViewCellMode mode, int align ) :
508 wxDataViewRenderer( varianttype, mode, align )
3d9d7cc4
RR
509{
510}
511
f554a14b 512// ---------------------------------------------------------
baa9ebc4 513// wxDataViewTextRenderer
f554a14b 514// ---------------------------------------------------------
4ed7af08 515
baa9ebc4 516IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer)
4ed7af08 517
c741d33f 518wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype,
9861f022
RR
519 wxDataViewCellMode mode, int align ) :
520 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
521{
522}
523
baa9ebc4 524bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
4ed7af08 525{
90675b95 526 m_text = value.GetString();
f554a14b 527
90675b95 528 return true;
4ed7af08
RR
529}
530
9861f022 531bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
4ed7af08
RR
532{
533 return false;
534}
535
99d471a5
RR
536bool wxDataViewTextRenderer::HasEditorCtrl()
537{
538 return true;
539}
540
541wxControl* wxDataViewTextRenderer::CreateEditorCtrl( wxWindow *parent,
542 wxRect labelRect, const wxVariant &value )
543{
544 return new wxTextCtrl( parent, wxID_ANY, value,
545 wxPoint(labelRect.x,labelRect.y),
546 wxSize(labelRect.width,labelRect.height) );
547}
548
549bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl *editor, wxVariant &value )
550{
551 wxTextCtrl *text = (wxTextCtrl*) editor;
552 value = text->GetValue();
553 return true;
554}
555
87f0efe2 556bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int state )
3d9d7cc4 557{
87f0efe2
RR
558 wxDataViewCtrl *view = GetOwner()->GetOwner();
559 wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ?
560 wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) :
561 view->GetForegroundColour();
562
563 dc->SetTextForeground(col);
90675b95
RR
564 dc->DrawText( m_text, cell.x, cell.y );
565
566 return true;
3d9d7cc4
RR
567}
568
9861f022 569wxSize wxDataViewTextRenderer::GetSize() const
3d9d7cc4 570{
9861f022 571 const wxDataViewCtrl *view = GetView();
87f0efe2
RR
572 if (!m_text.empty())
573 {
574 int x,y;
575 view->GetTextExtent( m_text, &x, &y );
576 return wxSize( x, y );
577 }
3d9d7cc4
RR
578 return wxSize(80,20);
579}
580
2586d4a1 581// ---------------------------------------------------------
baa9ebc4 582// wxDataViewBitmapRenderer
2586d4a1
RR
583// ---------------------------------------------------------
584
baa9ebc4 585IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer)
2586d4a1 586
c741d33f 587wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype,
9861f022
RR
588 wxDataViewCellMode mode, int align ) :
589 wxDataViewCustomRenderer( varianttype, mode, align )
2586d4a1
RR
590{
591}
592
baa9ebc4 593bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value )
2586d4a1
RR
594{
595 if (value.GetType() == wxT("wxBitmap"))
596 m_bitmap << value;
597 if (value.GetType() == wxT("wxIcon"))
598 m_icon << value;
599
600 return true;
601}
602
9861f022 603bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
2586d4a1
RR
604{
605 return false;
606}
607
baa9ebc4 608bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
2586d4a1
RR
609{
610 if (m_bitmap.Ok())
611 dc->DrawBitmap( m_bitmap, cell.x, cell.y );
612 else if (m_icon.Ok())
613 dc->DrawIcon( m_icon, cell.x, cell.y );
614
615 return true;
616}
617
9861f022 618wxSize wxDataViewBitmapRenderer::GetSize() const
2586d4a1
RR
619{
620 if (m_bitmap.Ok())
621 return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() );
622 else if (m_icon.Ok())
623 return wxSize( m_icon.GetWidth(), m_icon.GetHeight() );
624
625 return wxSize(16,16);
626}
627
f554a14b 628// ---------------------------------------------------------
baa9ebc4 629// wxDataViewToggleRenderer
f554a14b 630// ---------------------------------------------------------
4ed7af08 631
baa9ebc4 632IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer)
4ed7af08 633
baa9ebc4 634wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
9861f022
RR
635 wxDataViewCellMode mode, int align ) :
636 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08 637{
90675b95 638 m_toggle = false;
4ed7af08
RR
639}
640
baa9ebc4 641bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
4ed7af08 642{
90675b95 643 m_toggle = value.GetBool();
f554a14b 644
a8461d31 645 return true;
4ed7af08
RR
646}
647
9861f022 648bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
4ed7af08
RR
649{
650 return false;
651}
f554a14b 652
baa9ebc4 653bool wxDataViewToggleRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08 654{
90675b95 655 // User wxRenderer here
f554a14b 656
90675b95
RR
657 wxRect rect;
658 rect.x = cell.x + cell.width/2 - 10;
659 rect.width = 20;
660 rect.y = cell.y + cell.height/2 - 10;
661 rect.height = 20;
120b9b05 662
862d8041 663 int flags = 0;
90675b95 664 if (m_toggle)
862d8041
RR
665 flags |= wxCONTROL_CHECKED;
666 if (GetMode() != wxDATAVIEW_CELL_ACTIVATABLE)
667 flags |= wxCONTROL_DISABLED;
668
90b903c2 669 wxRendererNative::Get().DrawCheckBox(
862d8041
RR
670 GetOwner()->GetOwner(),
671 *dc,
672 rect,
673 flags );
f554a14b 674
90675b95 675 return true;
4ed7af08
RR
676}
677
c741d33f 678bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell),
aba9bfd0
RR
679 wxDataViewModel *model,
680 const wxDataViewItem & item, unsigned int col)
0fdc2321
RR
681{
682 bool value = !m_toggle;
683 wxVariant variant = value;
aba9bfd0
RR
684 model->SetValue( variant, item, col);
685 model->ValueChanged( item, col );
0fdc2321
RR
686 return true;
687}
688
9861f022 689wxSize wxDataViewToggleRenderer::GetSize() const
4ed7af08 690{
3d9d7cc4 691 return wxSize(20,20);
4ed7af08
RR
692}
693
f554a14b 694// ---------------------------------------------------------
baa9ebc4 695// wxDataViewProgressRenderer
f554a14b 696// ---------------------------------------------------------
4ed7af08 697
baa9ebc4 698IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
4ed7af08 699
baa9ebc4 700wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
9861f022
RR
701 const wxString &varianttype, wxDataViewCellMode mode, int align ) :
702 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
703{
704 m_label = label;
705 m_value = 0;
706}
707
baa9ebc4 708wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
4ed7af08
RR
709{
710}
711
baa9ebc4 712bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
713{
714 m_value = (long) value;
f554a14b 715
4ed7af08
RR
716 if (m_value < 0) m_value = 0;
717 if (m_value > 100) m_value = 100;
f554a14b 718
4ed7af08
RR
719 return true;
720}
f554a14b 721
9861f022
RR
722bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
723{
724 value = (long) m_value;
725 return true;
726}
727
baa9ebc4 728bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
729{
730 double pct = (double)m_value / 100.0;
731 wxRect bar = cell;
732 bar.width = (int)(cell.width * pct);
733 dc->SetPen( *wxTRANSPARENT_PEN );
734 dc->SetBrush( *wxBLUE_BRUSH );
735 dc->DrawRectangle( bar );
736
737 dc->SetBrush( *wxTRANSPARENT_BRUSH );
738 dc->SetPen( *wxBLACK_PEN );
739 dc->DrawRectangle( cell );
f554a14b 740
4ed7af08
RR
741 return true;
742}
743
9861f022 744wxSize wxDataViewProgressRenderer::GetSize() const
4ed7af08
RR
745{
746 return wxSize(40,12);
747}
f554a14b
WS
748
749// ---------------------------------------------------------
baa9ebc4 750// wxDataViewDateRenderer
f554a14b 751// ---------------------------------------------------------
4ed7af08 752
21ead767
VZ
753#define wxUSE_DATE_RENDERER_POPUP (wxUSE_CALENDARCTRL && wxUSE_POPUPWIN)
754
755#if wxUSE_DATE_RENDERER_POPUP
8d0ca292 756
baa9ebc4 757class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
4ed7af08 758{
f554a14b 759public:
baa9ebc4 760 wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
aba9bfd0
RR
761 wxDataViewModel *model, const wxDataViewItem & item, unsigned int col) :
762 wxPopupTransientWindow( parent, wxBORDER_SIMPLE ),
763 m_item( item )
4ed7af08
RR
764 {
765 m_model = model;
766 m_col = col;
f554a14b 767 m_cal = new wxCalendarCtrl( this, wxID_ANY, *value );
4ed7af08
RR
768 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
769 sizer->Add( m_cal, 1, wxGROW );
770 SetSizer( sizer );
771 sizer->Fit( this );
772 }
f554a14b 773
4ed7af08 774 void OnCalendar( wxCalendarEvent &event );
f554a14b 775
4ed7af08 776 wxCalendarCtrl *m_cal;
aba9bfd0 777 wxDataViewModel *m_model;
0a71f9e9 778 unsigned int m_col;
aba9bfd0 779 const wxDataViewItem & m_item;
f554a14b 780
a8461d31
PC
781protected:
782 virtual void OnDismiss()
783 {
784 }
785
4ed7af08
RR
786private:
787 DECLARE_EVENT_TABLE()
788};
789
baa9ebc4
RR
790BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
791 EVT_CALENDAR( wxID_ANY, wxDataViewDateRendererPopupTransient::OnCalendar )
4ed7af08
RR
792END_EVENT_TABLE()
793
baa9ebc4 794void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
4ed7af08
RR
795{
796 wxDateTime date = event.GetDate();
797 wxVariant value = date;
aba9bfd0
RR
798 m_model->SetValue( value, m_item, m_col );
799 m_model->ValueChanged( m_item, m_col );
4ed7af08
RR
800 DismissAndNotify();
801}
802
21ead767 803#endif // wxUSE_DATE_RENDERER_POPUP
8d0ca292 804
baa9ebc4 805IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
4ed7af08 806
baa9ebc4 807wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
9861f022
RR
808 wxDataViewCellMode mode, int align ) :
809 wxDataViewCustomRenderer( varianttype, mode, align )
4ed7af08
RR
810{
811}
f554a14b 812
baa9ebc4 813bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
4ed7af08
RR
814{
815 m_date = value.GetDateTime();
f554a14b 816
4ed7af08
RR
817 return true;
818}
819
9861f022
RR
820bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const
821{
822 value = m_date;
823 return true;
824}
825
baa9ebc4 826bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
4ed7af08
RR
827{
828 dc->SetFont( GetOwner()->GetOwner()->GetFont() );
829 wxString tmp = m_date.FormatDate();
830 dc->DrawText( tmp, cell.x, cell.y );
831
832 return true;
833}
834
9861f022 835wxSize wxDataViewDateRenderer::GetSize() const
4ed7af08 836{
9861f022 837 const wxDataViewCtrl* view = GetView();
4ed7af08
RR
838 wxString tmp = m_date.FormatDate();
839 wxCoord x,y,d;
840 view->GetTextExtent( tmp, &x, &y, &d );
841 return wxSize(x,y+d);
842}
843
aba9bfd0
RR
844bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model,
845 const wxDataViewItem & item, unsigned int col )
4ed7af08
RR
846{
847 wxVariant variant;
aba9bfd0 848 model->GetValue( variant, item, col );
4ed7af08
RR
849 wxDateTime value = variant.GetDateTime();
850
21ead767 851#if wxUSE_DATE_RENDERER_POPUP
baa9ebc4 852 wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
aba9bfd0 853 GetOwner()->GetOwner()->GetParent(), &value, model, item, col);
4ed7af08
RR
854 wxPoint pos = wxGetMousePosition();
855 popup->Move( pos );
856 popup->Layout();
857 popup->Popup( popup->m_cal );
21ead767 858#else // !wxUSE_DATE_RENDERER_POPUP
8d0ca292 859 wxMessageBox(value.Format());
21ead767 860#endif // wxUSE_DATE_RENDERER_POPUP/!wxUSE_DATE_RENDERER_POPUP
4ed7af08
RR
861 return true;
862}
863
f554a14b 864// ---------------------------------------------------------
4ed7af08 865// wxDataViewColumn
f554a14b 866// ---------------------------------------------------------
4ed7af08
RR
867
868IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumn, wxDataViewColumnBase)
869
c741d33f 870wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
87f0efe2
RR
871 unsigned int model_column,
872 int width, wxAlignment align, int flags ) :
873 wxDataViewColumnBase( title, cell, model_column, width, align, flags )
4ed7af08 874{
9861f022
RR
875 SetAlignment(align);
876 SetTitle(title);
877 SetFlags(flags);
878
879 Init(width < 0 ? wxDVC_DEFAULT_WIDTH : width);
4ed7af08
RR
880}
881
c741d33f 882wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
87f0efe2
RR
883 unsigned int model_column,
884 int width, wxAlignment align, int flags ) :
885 wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags )
07a84e7b 886{
9861f022
RR
887 SetAlignment(align);
888 SetFlags(flags);
889
890 Init(width < 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH : width);
07a84e7b
RR
891}
892
9861f022
RR
893wxDataViewColumn::~wxDataViewColumn()
894{
895}
896
897void wxDataViewColumn::Init( int width )
47cef10f 898{
87f0efe2 899 m_width = width;
9861f022 900 m_minWidth = wxDVC_DEFAULT_MINWIDTH;
c3112d56 901 m_ascending = true;
47cef10f
RR
902}
903
9861f022 904void wxDataViewColumn::SetResizeable( bool resizeable )
31fb32e1 905{
9861f022
RR
906 if (resizeable)
907 m_flags |= wxDATAVIEW_COL_RESIZABLE;
908 else
909 m_flags &= ~wxDATAVIEW_COL_RESIZABLE;
910}
911
912void wxDataViewColumn::SetHidden( bool hidden )
913{
914 if (hidden)
915 m_flags |= wxDATAVIEW_COL_HIDDEN;
916 else
917 m_flags &= ~wxDATAVIEW_COL_HIDDEN;
918
919 // tell our owner to e.g. update its scrollbars:
920 if (GetOwner())
921 GetOwner()->OnColumnChange();
922}
923
924void wxDataViewColumn::SetSortable( bool sortable )
925{
926 if (sortable)
927 m_flags |= wxDATAVIEW_COL_SORTABLE;
928 else
929 m_flags &= ~wxDATAVIEW_COL_SORTABLE;
c3112d56
RR
930
931 // Update header button
932 if (GetOwner())
933 GetOwner()->OnColumnChange();
31fb32e1
RR
934}
935
c3112d56 936void wxDataViewColumn::SetSortOrder( bool ascending )
47cef10f 937{
c3112d56
RR
938 m_ascending = ascending;
939
940 // Update header button
941 if (GetOwner())
942 GetOwner()->OnColumnChange();
47cef10f
RR
943}
944
87f0efe2 945bool wxDataViewColumn::IsSortOrderAscending() const
31fb32e1 946{
c3112d56 947 return m_ascending;
31fb32e1
RR
948}
949
9861f022 950void wxDataViewColumn::SetInternalWidth( int width )
4ed7af08 951{
9861f022 952 m_width = width;
f554a14b 953
9861f022
RR
954 // the scrollbars of the wxDataViewCtrl needs to be recalculated!
955 if (m_owner && m_owner->m_clientArea)
956 m_owner->m_clientArea->RecalculateDisplay();
4ed7af08
RR
957}
958
9861f022 959void wxDataViewColumn::SetWidth( int width )
47cef10f 960{
9861f022 961 m_owner->m_headerArea->UpdateDisplay();
47cef10f 962
9861f022 963 SetInternalWidth(width);
47cef10f
RR
964}
965
533544f2 966
4ed7af08 967//-----------------------------------------------------------------------------
87f0efe2 968// wxDataViewHeaderWindowBase
4ed7af08
RR
969//-----------------------------------------------------------------------------
970
87f0efe2
RR
971void wxDataViewHeaderWindowBase::SendEvent(wxEventType type, unsigned int n)
972{
973 wxWindow *parent = GetParent();
974 wxDataViewEvent le(type, parent->GetId());
975
976 le.SetEventObject(parent);
977 le.SetColumn(n);
978 le.SetDataViewColumn(GetColumn(n));
979 le.SetModel(GetOwner()->GetModel());
980
981 // for events created by wxDataViewHeaderWindow the
982 // row / value fields are not valid
983
984 parent->GetEventHandler()->ProcessEvent(le);
985}
986
987#if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW
988
87f0efe2 989// implemented in msw/listctrl.cpp:
a68962fc 990int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
87f0efe2 991
5d3f234b 992IMPLEMENT_ABSTRACT_CLASS(wxDataViewHeaderWindowMSW, wxWindow)
87f0efe2
RR
993
994bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl *parent, wxWindowID id,
c741d33f 995 const wxPoint &pos, const wxSize &size,
87f0efe2
RR
996 const wxString &name )
997{
998 m_owner = parent;
999
1000 if ( !CreateControl(parent, id, pos, size, 0, wxDefaultValidator, name) )
1001 return false;
1002
1003 int x = pos.x == wxDefaultCoord ? 0 : pos.x,
1004 y = pos.y == wxDefaultCoord ? 0 : pos.y,
1005 w = size.x == wxDefaultCoord ? 1 : size.x,
1006 h = size.y == wxDefaultCoord ? 22 : size.y;
1007
1008 // create the native WC_HEADER window:
1009 WXHWND hwndParent = (HWND)parent->GetHandle();
1010 WXDWORD msStyle = WS_CHILD | HDS_BUTTONS | HDS_HORZ | HDS_HOTTRACK | HDS_FULLDRAG;
c741d33f
VZ
1011 m_hWnd = CreateWindowEx(0,
1012 WC_HEADER,
1013 (LPCTSTR) NULL,
87f0efe2
RR
1014 msStyle,
1015 x, y, w, h,
c741d33f
VZ
1016 (HWND)hwndParent,
1017 (HMENU)-1,
1018 wxGetInstance(),
87f0efe2 1019 (LPVOID) NULL);
c741d33f 1020 if (m_hWnd == NULL)
87f0efe2
RR
1021 {
1022 wxLogLastError(_T("CreateWindowEx"));
1023 return false;
1024 }
1025
5d3f234b 1026 // we need to subclass the m_hWnd to force wxWindow::HandleNotify
87f0efe2 1027 // to call wxDataViewHeaderWindow::MSWOnNotify
5d3f234b 1028 SubclassWin(m_hWnd);
87f0efe2 1029
c741d33f 1030 // the following is required to get the default win's font for
9861f022
RR
1031 // header windows and must be done befor sending the HDM_LAYOUT msg
1032 SetFont(GetFont());
87f0efe2 1033
9861f022
RR
1034 RECT rcParent;
1035 HDLAYOUT hdl;
1036 WINDOWPOS wp;
87f0efe2 1037
c741d33f
VZ
1038 // Retrieve the bounding rectangle of the parent window's
1039 // client area, and then request size and position values
1040 // from the header control.
1041 ::GetClientRect((HWND)hwndParent, &rcParent);
1042
1043 hdl.prc = &rcParent;
1044 hdl.pwpos = &wp;
1045 if (!SendMessage((HWND)m_hWnd, HDM_LAYOUT, 0, (LPARAM) &hdl))
87f0efe2
RR
1046 {
1047 wxLogLastError(_T("SendMessage"));
1048 return false;
1049 }
c741d33f
VZ
1050
1051 // Set the size, position, and visibility of the header control.
1052 SetWindowPos((HWND)m_hWnd,
1053 wp.hwndInsertAfter,
1054 wp.x, wp.y,
1055 wp.cx, wp.cy,
87f0efe2
RR
1056 wp.flags | SWP_SHOWWINDOW);
1057
1058 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1059 // a wxBoxSizer and in order to avoid super-big header windows,
1060 // we need to set our height as fixed
1061 SetMinSize(wxSize(-1, wp.cy));
1062 SetMaxSize(wxSize(-1, wp.cy));
1063
87f0efe2
RR
1064 return true;
1065}
1066
1067wxDataViewHeaderWindowMSW::~wxDataViewHeaderWindow()
1068{
5d3f234b 1069 UnsubclassWin();
87f0efe2
RR
1070}
1071
1072void wxDataViewHeaderWindowMSW::UpdateDisplay()
1073{
1074 // remove old columns
914e6945 1075 for (int j=0, max=Header_GetItemCount((HWND)m_hWnd); j < max; j++)
87f0efe2 1076 Header_DeleteItem((HWND)m_hWnd, 0);
c741d33f 1077
87f0efe2 1078 // add the updated array of columns to the header control
9861f022
RR
1079 unsigned int cols = GetOwner()->GetColumnCount();
1080 unsigned int added = 0;
87f0efe2
RR
1081 for (unsigned int i = 0; i < cols; i++)
1082 {
1083 wxDataViewColumn *col = GetColumn( i );
1084 if (col->IsHidden())
1085 continue; // don't add it!
1086
1087 HDITEM hdi;
1088 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
fab3f50e 1089 hdi.pszText = (wxChar *) col->GetTitle().wx_str();
87f0efe2
RR
1090 hdi.cxy = col->GetWidth();
1091 hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]);
1092 hdi.fmt = HDF_LEFT | HDF_STRING;
9861f022
RR
1093
1094 // lParam is reserved for application's use:
1095 // we store there the column index to use it later in MSWOnNotify
1096 // (since columns may have been hidden)
1097 hdi.lParam = (LPARAM)i;
1098
1099 // the native wxMSW implementation of the header window
c741d33f 1100 // draws the column separator COLUMN_WIDTH_OFFSET pixels
9861f022
RR
1101 // on the right: to correct this effect we make the column
1102 // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
1103 if (i == 0)
1104 hdi.cxy += COLUMN_WIDTH_OFFSET;
1105
1106 switch (col->GetAlignment())
1107 {
1108 case wxALIGN_LEFT:
1109 hdi.fmt |= HDF_LEFT;
1110 break;
1111 case wxALIGN_CENTER:
1112 case wxALIGN_CENTER_HORIZONTAL:
1113 hdi.fmt |= HDF_CENTER;
1114 break;
1115 case wxALIGN_RIGHT:
1116 hdi.fmt |= HDF_RIGHT;
1117 break;
5d3f234b
RR
1118
1119 default:
1120 // such alignment is not allowed for the column header!
1121 wxFAIL;
9861f022 1122 }
c741d33f
VZ
1123
1124 SendMessage((HWND)m_hWnd, HDM_INSERTITEM,
1125 (WPARAM)added, (LPARAM)&hdi);
9861f022 1126 added++;
87f0efe2
RR
1127 }
1128}
1129
9861f022
RR
1130unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR)
1131{
1132 unsigned int idx;
1133
1134 // NOTE: we don't just return nmHDR->iItem because when there are
1135 // hidden columns, nmHDR->iItem may be different from
1136 // nmHDR->pitem->lParam
1137
1138 if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM)
1139 {
1140 idx = (unsigned int)nmHDR->pitem->lParam;
1141 return idx;
1142 }
1143
1144 HDITEM item;
1145 item.mask = HDI_LPARAM;
1146 Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item);
1147
1148 return (unsigned int)item.lParam;
1149}
1150
87f0efe2
RR
1151bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
1152{
1153 NMHDR *nmhdr = (NMHDR *)lParam;
1154
1155 // is it a message from the header?
1156 if ( nmhdr->hwndFrom != (HWND)m_hWnd )
1157 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1158
1159 NMHEADER *nmHDR = (NMHEADER *)nmhdr;
1160 switch ( nmhdr->code )
1161 {
1162 case HDN_BEGINTRACK:
1163 // user has started to resize a column:
1164 // do we need to veto it?
1165 if (!GetColumn(nmHDR->iItem)->IsResizeable())
1166 {
1167 // veto it!
1168 *result = TRUE;
1169 }
1170 break;
1171
1172 case HDN_BEGINDRAG:
1173 // user has started to reorder a column
1174 break;
1175
9861f022 1176 case HDN_ITEMCHANGING:
c741d33f 1177 if (nmHDR->pitem != NULL &&
9861f022
RR
1178 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1179 {
1180 int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth();
1181 if (nmHDR->pitem->cxy < minWidth)
1182 {
c741d33f 1183 // do not allow the user to resize this column under
9861f022
RR
1184 // its minimal width:
1185 *result = TRUE;
1186 }
1187 }
1188 break;
1189
87f0efe2
RR
1190 case HDN_ITEMCHANGED: // user is resizing a column
1191 case HDN_ENDTRACK: // user has finished resizing a column
1192 case HDN_ENDDRAG: // user has finished reordering a column
1193
1194 // update the width of the modified column:
c741d33f 1195 if (nmHDR->pitem != NULL &&
9861f022
RR
1196 (nmHDR->pitem->mask & HDI_WIDTH) != 0)
1197 {
1198 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
1199 unsigned int w = nmHDR->pitem->cxy;
1200 wxDataViewColumn *col = GetColumn(idx);
1201
1202 // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
1203 if (idx == 0 && w > COLUMN_WIDTH_OFFSET)
1204 w -= COLUMN_WIDTH_OFFSET;
1205
1206 if (w >= (unsigned)col->GetMinWidth())
1207 col->SetInternalWidth(w);
1208 }
87f0efe2
RR
1209 break;
1210
1211 case HDN_ITEMCLICK:
1212 {
9861f022 1213 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
c741d33f 1214 wxEventType evt = nmHDR->iButton == 0 ?
87f0efe2
RR
1215 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1216 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
9861f022 1217 SendEvent(evt, idx);
87f0efe2
RR
1218 }
1219 break;
1220
1221 case NM_RCLICK:
1222 {
1223 // NOTE: for some reason (i.e. for a bug in Windows)
1224 // the HDN_ITEMCLICK notification is not sent on
1225 // right clicks, so we need to handle NM_RCLICK
1226
1227 POINT ptClick;
9861f022 1228 int column = wxMSWGetColumnClicked(nmhdr, &ptClick);
87f0efe2 1229 if (column != wxNOT_FOUND)
9861f022
RR
1230 {
1231 HDITEM item;
1232 item.mask = HDI_LPARAM;
1233 Header_GetItem((HWND)m_hWnd, column, &item);
1234
1235 // 'idx' may be different from 'column' if there are
1236 // hidden columns...
1237 unsigned int idx = (unsigned int)item.lParam;
87f0efe2 1238 SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
9861f022
RR
1239 idx);
1240 }
87f0efe2
RR
1241 }
1242 break;
1243
1244 case HDN_GETDISPINFOW:
1245 // see wxListCtrl::MSWOnNotify for more info!
1246 break;
1247
1248 case HDN_ITEMDBLCLICK:
1249 {
9861f022 1250 unsigned int idx = GetColumnIdxFromHeader(nmHDR);
87f0efe2
RR
1251 int w = GetOwner()->GetBestColumnWidth(idx);
1252
1253 // update the native control:
1254 HDITEM hd;
1255 ZeroMemory(&hd, sizeof(hd));
1256 hd.mask = HDI_WIDTH;
1257 hd.cxy = w;
c741d33f 1258 Header_SetItem(GetHwnd(),
9861f022
RR
1259 nmHDR->iItem, // NOTE: we don't want 'idx' here!
1260 &hd);
87f0efe2
RR
1261
1262 // update the wxDataViewColumn class:
9861f022 1263 GetColumn(idx)->SetInternalWidth(w);
87f0efe2
RR
1264 }
1265 break;
1266
1267 default:
1268 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
1269 }
1270
1271 return true;
1272}
1273
c741d33f 1274void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx), int WXUNUSED(dy),
87f0efe2
RR
1275 const wxRect *WXUNUSED(rect))
1276{
1277 wxSize ourSz = GetClientSize();
1278 wxSize ownerSz = m_owner->GetClientSize();
1279
1280 // where should the (logical) origin of this window be placed?
1281 int x1 = 0, y1 = 0;
1282 m_owner->CalcUnscrolledPosition(0, 0, &x1, &y1);
4ed7af08 1283
c741d33f
VZ
1284 // put this window on top of our parent and
1285 SetWindowPos((HWND)m_hWnd, HWND_TOP, -x1, 0,
1286 ownerSz.GetWidth() + x1, ourSz.GetHeight(),
87f0efe2
RR
1287 SWP_SHOWWINDOW);
1288}
1289
c741d33f
VZ
1290void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
1291 int WXUNUSED(w), int WXUNUSED(h),
9861f022
RR
1292 int WXUNUSED(f))
1293{
1294 // the wxDataViewCtrl's internal wxBoxSizer will call this function when
1295 // the wxDataViewCtrl window gets resized: the following dummy call
1296 // to ScrollWindow() is required in order to get this header window
1297 // correctly repainted when it's (horizontally) scrolled:
1298
1299 ScrollWindow(0, 0);
1300}
1301
87f0efe2
RR
1302#else // !defined(__WXMSW__)
1303
1304IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow, wxWindow)
1305BEGIN_EVENT_TABLE(wxGenericDataViewHeaderWindow, wxWindow)
1306 EVT_PAINT (wxGenericDataViewHeaderWindow::OnPaint)
1307 EVT_MOUSE_EVENTS (wxGenericDataViewHeaderWindow::OnMouse)
1308 EVT_SET_FOCUS (wxGenericDataViewHeaderWindow::OnSetFocus)
4ed7af08
RR
1309END_EVENT_TABLE()
1310
87f0efe2 1311bool wxGenericDataViewHeaderWindow::Create(wxDataViewCtrl *parent, wxWindowID id,
c741d33f
VZ
1312 const wxPoint &pos, const wxSize &size,
1313 const wxString &name )
4ed7af08 1314{
87f0efe2 1315 m_owner = parent;
4b3feaa7 1316
87f0efe2
RR
1317 if (!wxDataViewHeaderWindowBase::Create(parent, id, pos, size, name))
1318 return false;
f554a14b 1319
4ed7af08 1320 wxVisualAttributes attr = wxPanel::GetClassDefaultAttributes();
2e992e06 1321 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
4ed7af08
RR
1322 SetOwnForegroundColour( attr.colFg );
1323 SetOwnBackgroundColour( attr.colBg );
1324 if (!m_hasFont)
1325 SetOwnFont( attr.font );
4ed7af08 1326
87f0efe2
RR
1327 // set our size hints: wxDataViewCtrl will put this wxWindow inside
1328 // a wxBoxSizer and in order to avoid super-big header windows,
1329 // we need to set our height as fixed
1330 SetMinSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1331 SetMaxSize(wxSize(-1, HEADER_WINDOW_HEIGHT));
1332
1333 return true;
4ed7af08
RR
1334}
1335
87f0efe2 1336void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 1337{
4b3feaa7
RR
1338 int w, h;
1339 GetClientSize( &w, &h );
1340
2e992e06
VZ
1341 wxAutoBufferedPaintDC dc( this );
1342
1343 dc.SetBackground(GetBackgroundColour());
1344 dc.Clear();
f554a14b 1345
4ed7af08
RR
1346 int xpix;
1347 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1348
1349 int x;
1350 m_owner->GetViewStart( &x, NULL );
1351
1352 // account for the horz scrollbar offset
1353 dc.SetDeviceOrigin( -x * xpix, 0 );
f554a14b 1354
4ed7af08 1355 dc.SetFont( GetFont() );
f554a14b 1356
9861f022 1357 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 1358 unsigned int i;
4b3feaa7
RR
1359 int xpos = 0;
1360 for (i = 0; i < cols; i++)
1361 {
87f0efe2
RR
1362 wxDataViewColumn *col = GetColumn( i );
1363 if (col->IsHidden())
9861f022 1364 continue; // skip it!
f554a14b 1365
87f0efe2 1366 int cw = col->GetWidth();
4b3feaa7 1367 int ch = h;
4b3feaa7 1368
c3112d56
RR
1369 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE;
1370 if (col->IsSortable())
1371 {
1372 if (col->IsSortOrderAscending())
1373 sortArrow = wxHDR_SORT_ICON_UP;
1374 else
1375 sortArrow = wxHDR_SORT_ICON_DOWN;
1376 }
1377
4b3feaa7
RR
1378 wxRendererNative::Get().DrawHeaderButton
1379 (
1380 this,
1381 dc,
72664514 1382 wxRect(xpos, 0, cw, ch-1),
4b3feaa7 1383 m_parent->IsEnabled() ? 0
c3112d56
RR
1384 : (int)wxCONTROL_DISABLED,
1385 sortArrow
4b3feaa7
RR
1386 );
1387
9861f022
RR
1388 // align as required the column title:
1389 int x = xpos;
1390 wxSize titleSz = dc.GetTextExtent(col->GetTitle());
1391 switch (col->GetAlignment())
1392 {
1393 case wxALIGN_LEFT:
1394 x += HEADER_HORIZ_BORDER;
1395 break;
1396 case wxALIGN_CENTER:
1397 case wxALIGN_CENTER_HORIZONTAL:
1398 x += (cw - titleSz.GetWidth() - 2 * HEADER_HORIZ_BORDER)/2;
1399 break;
1400 case wxALIGN_RIGHT:
1401 x += cw - titleSz.GetWidth() - HEADER_HORIZ_BORDER;
1402 break;
1403 }
1404
1405 // always center the title vertically:
1406 int y = wxMax((ch - titleSz.GetHeight()) / 2, HEADER_VERT_BORDER);
1407
c741d33f 1408 dc.SetClippingRegion( xpos+HEADER_HORIZ_BORDER,
9861f022
RR
1409 HEADER_VERT_BORDER,
1410 wxMax(cw - 2 * HEADER_HORIZ_BORDER, 1), // width
1411 wxMax(ch - 2 * HEADER_VERT_BORDER, 1)); // height
1412 dc.DrawText( col->GetTitle(), x, y );
1413 dc.DestroyClippingRegion();
f554a14b 1414
87f0efe2 1415 xpos += cw;
4b3feaa7 1416 }
4ed7af08
RR
1417}
1418
87f0efe2 1419void wxGenericDataViewHeaderWindow::OnSetFocus( wxFocusEvent &event )
4ed7af08 1420{
87f0efe2
RR
1421 GetParent()->SetFocus();
1422 event.Skip();
4ed7af08
RR
1423}
1424
87f0efe2 1425void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event )
4ed7af08 1426{
87f0efe2
RR
1427 // we want to work with logical coords
1428 int x;
1429 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1430 int y = event.GetY();
1431
1432 if (m_isDragging)
1433 {
c741d33f 1434 // we don't draw the line beyond our window,
87f0efe2
RR
1435 // but we allow dragging it there
1436 int w = 0;
1437 GetClientSize( &w, NULL );
1438 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1439 w -= 6;
1440
1441 // erase the line if it was drawn
c741d33f 1442 if (m_currentX < w)
87f0efe2
RR
1443 DrawCurrent();
1444
c741d33f 1445 if (event.ButtonUp())
87f0efe2
RR
1446 {
1447 m_isDragging = false;
c741d33f 1448 if (HasCapture())
87f0efe2
RR
1449 ReleaseMouse();
1450
1451 m_dirty = true;
1452
9861f022 1453 GetColumn(m_column)->SetWidth(m_currentX - m_minX);
87f0efe2
RR
1454
1455 Refresh();
1456 GetOwner()->Refresh();
1457 }
1458 else
1459 {
1460 m_currentX = wxMax(m_minX + 7, x);
1461
1462 // draw in the new location
1463 if (m_currentX < w) DrawCurrent();
1464 }
1465
1466 }
1467 else // not dragging
1468 {
1469 m_minX = 0;
1470 m_column = wxNOT_FOUND;
1471
1472 bool hit_border = false;
1473
1474 // end of the current column
1475 int xpos = 0;
1476
1477 // find the column where this event occured
9861f022 1478 int countCol = m_owner->GetColumnCount();
c741d33f 1479 for (int column = 0; column < countCol; column++)
87f0efe2
RR
1480 {
1481 wxDataViewColumn *p = GetColumn(column);
1482
c741d33f 1483 if (p->IsHidden())
87f0efe2
RR
1484 continue; // skip if not shown
1485
1486 xpos += p->GetWidth();
1487 m_column = column;
c741d33f 1488 if ((abs(x-xpos) < 3) && (y < 22))
87f0efe2
RR
1489 {
1490 hit_border = true;
1491 break;
1492 }
1493
c741d33f 1494 if (x < xpos)
87f0efe2
RR
1495 {
1496 // inside the column
1497 break;
1498 }
1499
1500 m_minX = xpos;
1501 }
1502
1503 if (m_column == wxNOT_FOUND)
1504 return;
1505
1506 bool resizeable = GetColumn(m_column)->IsResizeable();
1507 if (event.LeftDClick() && resizeable)
1508 {
9861f022 1509 GetColumn(m_column)->SetWidth(GetOwner()->GetBestColumnWidth(m_column));
87f0efe2
RR
1510 Refresh();
1511 }
1512 else if (event.LeftDown() || event.RightUp())
1513 {
c741d33f 1514 if (hit_border && event.LeftDown() && resizeable)
87f0efe2
RR
1515 {
1516 m_isDragging = true;
1517 CaptureMouse();
1518 m_currentX = x;
1519 DrawCurrent();
1520 }
1521 else // click on a column
1522 {
c741d33f 1523 wxEventType evt = event.LeftDown() ?
87f0efe2
RR
1524 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
1525 wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
1526 SendEvent(evt, m_column);
1527 }
1528 }
1529 else if (event.Moving())
1530 {
c741d33f 1531 if (hit_border && resizeable)
87f0efe2
RR
1532 m_currentCursor = m_resizeCursor;
1533 else
1534 m_currentCursor = wxSTANDARD_CURSOR;
1535
1536 SetCursor(*m_currentCursor);
1537 }
1538 }
1539}
1540
1541void wxGenericDataViewHeaderWindow::DrawCurrent()
1542{
1543 int x1 = m_currentX;
1544 int y1 = 0;
1545 ClientToScreen (&x1, &y1);
1546
1547 int x2 = m_currentX-1;
1548#ifdef __WXMSW__
1549 ++x2; // but why ????
1550#endif
1551 int y2 = 0;
1552 m_owner->GetClientSize( NULL, &y2 );
1553 m_owner->ClientToScreen( &x2, &y2 );
1554
1555 wxScreenDC dc;
9861f022
RR
1556 dc.SetLogicalFunction(wxINVERT);
1557 dc.SetPen(m_penCurrent);
1558 dc.SetBrush(*wxTRANSPARENT_BRUSH);
87f0efe2 1559 AdjustDC(dc);
9861f022 1560 dc.DrawLine(x1, y1, x2, y2);
87f0efe2
RR
1561}
1562
1563void wxGenericDataViewHeaderWindow::AdjustDC(wxDC& dc)
1564{
1565 int xpix, x;
1566
1567 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1568 m_owner->GetViewStart( &x, NULL );
1569
1570 // shift the DC origin to match the position of the main window horizontal
1571 // scrollbar: this allows us to always use logical coords
1572 dc.SetDeviceOrigin( -x * xpix, 0 );
4ed7af08
RR
1573}
1574
87f0efe2
RR
1575#endif // defined(__WXMSW__)
1576
0fcce6b9
RR
1577//-----------------------------------------------------------------------------
1578// wxDataViewRenameTimer
1579//-----------------------------------------------------------------------------
1580
1581wxDataViewRenameTimer::wxDataViewRenameTimer( wxDataViewMainWindow *owner )
1582{
1583 m_owner = owner;
1584}
1585
1586void wxDataViewRenameTimer::Notify()
1587{
1588 m_owner->OnRenameTimer();
1589}
1590
4ed7af08
RR
1591//-----------------------------------------------------------------------------
1592// wxDataViewMainWindow
1593//-----------------------------------------------------------------------------
1594
704c3490
RR
1595//The tree building helper, declared firstly
1596void BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node);
1597
0a71f9e9 1598int LINKAGEMODE wxDataViewSelectionCmp( unsigned int row1, unsigned int row2 )
cab07038
RR
1599{
1600 if (row1 > row2) return 1;
1601 if (row1 == row2) return 0;
1602 return -1;
1603}
1604
1605
45778c96 1606IMPLEMENT_ABSTRACT_CLASS(wxDataViewMainWindow, wxWindow)
4ed7af08
RR
1607
1608BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
1609 EVT_PAINT (wxDataViewMainWindow::OnPaint)
1610 EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
1611 EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
cab07038
RR
1612 EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
1613 EVT_CHAR (wxDataViewMainWindow::OnChar)
4ed7af08
RR
1614END_EVENT_TABLE()
1615
1616wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID id,
1617 const wxPoint &pos, const wxSize &size, const wxString &name ) :
72664514 1618 wxWindow( parent, id, pos, size, wxWANTS_CHARS, name ),
cab07038 1619 m_selection( wxDataViewSelectionCmp )
120b9b05 1620
4ed7af08
RR
1621{
1622 SetOwner( parent );
f554a14b 1623
0fcce6b9
RR
1624 m_lastOnSame = false;
1625 m_renameTimer = new wxDataViewRenameTimer( this );
120b9b05 1626
0fcce6b9
RR
1627 // TODO: user better initial values/nothing selected
1628 m_currentCol = NULL;
1629 m_currentRow = 0;
1630
1631 // TODO: we need to calculate this smartly
c741d33f 1632 m_lineHeight =
87f0efe2
RR
1633#ifdef __WXMSW__
1634 17;
1635#else
1636 20;
1637#endif
9861f022 1638 wxASSERT(m_lineHeight > 2*PADDING_TOPBOTTOM);
e21f75bd
RR
1639
1640 m_dragCount = 0;
1641 m_dragStart = wxPoint(0,0);
0a71f9e9
RR
1642 m_lineLastClicked = (unsigned int) -1;
1643 m_lineBeforeLastClicked = (unsigned int) -1;
1644 m_lineSelectSingleOnUp = (unsigned int) -1;
120b9b05 1645
cab07038 1646 m_hasFocus = false;
f554a14b 1647
2e992e06 1648 SetBackgroundStyle( wxBG_STYLE_CUSTOM );
72664514
RR
1649 SetBackgroundColour( *wxWHITE );
1650
9861f022
RR
1651 m_penRule = wxPen(GetRuleColour(), 1, wxSOLID);
1652
3b6280be
RR
1653 //Here I compose a pen can draw black lines, maybe there are something system colour to use
1654 m_penExpander = wxPen( wxColour(0,0,0), 1, wxSOLID );
aba9bfd0
RR
1655 //Some new added code to deal with the tree structure
1656 m_root = new wxDataViewTreeNode( NULL );
704c3490
RR
1657 m_root->SetHasChildren(true);
1658
3b6280be
RR
1659 //Make m_count = -1 will cause the class recaculate the real displaying number of rows.
1660 m_count = -1 ;
4b3feaa7 1661 UpdateDisplay();
4ed7af08
RR
1662}
1663
1664wxDataViewMainWindow::~wxDataViewMainWindow()
1665{
aba9bfd0 1666 DestroyTree();
0fcce6b9
RR
1667 delete m_renameTimer;
1668}
1669
1670void wxDataViewMainWindow::OnRenameTimer()
1671{
1672 // We have to call this here because changes may just have
1673 // been made and no screen update taken place.
1674 if ( m_dirty )
1675 wxSafeYield();
1676
0fcce6b9 1677 int xpos = 0;
9861f022 1678 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 1679 unsigned int i;
0fcce6b9
RR
1680 for (i = 0; i < cols; i++)
1681 {
1682 wxDataViewColumn *c = GetOwner()->GetColumn( i );
9861f022
RR
1683 if (c->IsHidden())
1684 continue; // skip it!
1685
0fcce6b9
RR
1686 if (c == m_currentCol)
1687 break;
1688 xpos += c->GetWidth();
1689 }
c741d33f 1690 wxRect labelRect( xpos, m_currentRow * m_lineHeight,
87f0efe2 1691 m_currentCol->GetWidth(), m_lineHeight );
0fcce6b9 1692
1e510b1e
RR
1693 GetOwner()->CalcScrolledPosition( labelRect.x, labelRect.y,
1694 &labelRect.x, &labelRect.y);
1695
6cdcbce3
RR
1696 wxDataViewItem item = GetItemByRow( m_currentRow );
1697 m_currentCol->GetRenderer()->StartEditing( item, labelRect );
4ed7af08
RR
1698}
1699
d5025dc0
RR
1700//------------------------------------------------------------------
1701// Helper class for do operation on the tree node
1702//------------------------------------------------------------------
aba9bfd0 1703class DoJob
a0f3af5f 1704{
aba9bfd0
RR
1705public:
1706 DoJob(){};
d5025dc0
RR
1707 virtual ~DoJob(){};
1708
1709 //The return value control how the tree-walker tranverse the tree
1710 // 0: Job done, stop tranverse and return
1711 // 1: Ignore the current node's subtree and continue
1712 // 2: Job not done, continue
1713 enum { OK = 0 , IGR = 1, CONT = 2 };
1714 virtual int operator() ( wxDataViewTreeNode * node ) = 0 ;
aba9bfd0
RR
1715};
1716
1717class ItemAddJob: public DoJob
a0f3af5f 1718{
aba9bfd0 1719public:
704c3490
RR
1720 ItemAddJob( const wxDataViewItem & parent, const wxDataViewItem & item, int * count )
1721 { this->parent = parent ; this->item = item ; m_count = count; }
d5025dc0 1722 virtual ~ItemAddJob(){};
aba9bfd0 1723
d5025dc0 1724 virtual int operator() ( wxDataViewTreeNode * node )
aba9bfd0
RR
1725 {
1726 if( node->GetItem() == parent )
1727 {
704c3490 1728 node->SetHasChildren( true );
aba9bfd0 1729 wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node );
3b6280be
RR
1730 newnode->SetItem(item);
1731 node->AppendChild( newnode);
704c3490 1732 *m_count = -1;
d5025dc0 1733 return OK;
aba9bfd0 1734 }
d5025dc0 1735 return CONT;
aba9bfd0 1736 }
704c3490 1737
aba9bfd0 1738private:
704c3490 1739 int * m_count;
aba9bfd0
RR
1740 wxDataViewItem parent, item;
1741};
1742
1743bool Walker( wxDataViewTreeNode * node, DoJob & func )
1744{
3b6280be 1745 if( node==NULL || !node->HasChildren())
aba9bfd0
RR
1746 return false;
1747
1748 wxDataViewTreeNodes nodes = node->GetChildren();
1749 int len = node->GetChildrenNumber();
1750 int i = 0 ;
1751 for( ; i < len ; i ++ )
1752 {
1753 wxDataViewTreeNode * n = nodes[i];
d5025dc0
RR
1754 switch( func( n ) )
1755 {
1756 case DoJob::OK :
1757 return true ;
1758 case DoJob::IGR:
1759 continue;
1760 case DoJob::CONT:
1761 default:
1762 ;
1763 }
1764
1765 if( Walker( n , func ) )
1766 return true;
aba9bfd0
RR
1767 }
1768 return false;
a0f3af5f
RR
1769}
1770
aba9bfd0 1771bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
a0f3af5f 1772{
704c3490 1773 ItemAddJob job( parent, item, &m_count);
aba9bfd0 1774 Walker( m_root , job);
99d471a5
RR
1775 UpdateDisplay();
1776 return true;
a0f3af5f
RR
1777}
1778
704c3490
RR
1779class ItemDeleteJob: public DoJob
1780{
1781public:
1782 ItemDeleteJob( const wxDataViewItem & item, int * count ) { m_item = item; m_count = count; }
1783 virtual ~ItemDeleteJob(){}
1784 virtual int operator() ( wxDataViewTreeNode * node )
1785 {
1786 if( node->GetItem() == m_item )
1787 {
1788 node->GetParent()->GetChildren().Remove( node );
1789 delete node;
1790 *m_count = -1;
1791 return DoJob::OK;
1792 }
1793 return DoJob::CONT;
1794 }
1795
1796private:
1797 int * m_count;
1798 wxDataViewItem m_item;
1799};
1800
aba9bfd0 1801bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem & item)
a0f3af5f 1802{
704c3490
RR
1803 ItemDeleteJob job( item, &m_count);
1804 Walker( m_root, job);
99d471a5
RR
1805 UpdateDisplay();
1806 return true;
a0f3af5f
RR
1807}
1808
aba9bfd0 1809bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
a0f3af5f 1810{
704c3490
RR
1811 unsigned int row = GetRowByItem(item);
1812 RefreshRow( row );
99d471a5 1813 return true;
a0f3af5f
RR
1814}
1815
aba9bfd0 1816bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int WXUNUSED(col) )
a0f3af5f 1817{
9861f022 1818 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
aba9bfd0 1819/*#define MAX_VIRTUAL_WIDTH 100000
9861f022
RR
1820
1821 wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight );
0fdc2321
RR
1822 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
1823 Refresh( true, &rect );
1824
1825 return true;
aba9bfd0 1826*/
704c3490
RR
1827 unsigned int row = GetRowByItem(item);
1828 RefreshRow( row );
0fcce6b9 1829 return true;
a0f3af5f
RR
1830}
1831
1832bool wxDataViewMainWindow::Cleared()
1833{
704c3490 1834 DestroyTree();
99d471a5
RR
1835 UpdateDisplay();
1836 return true;
a0f3af5f
RR
1837}
1838
4b3feaa7
RR
1839void wxDataViewMainWindow::UpdateDisplay()
1840{
1841 m_dirty = true;
1842}
1843
1844void wxDataViewMainWindow::OnInternalIdle()
1845{
1846 wxWindow::OnInternalIdle();
f554a14b 1847
4b3feaa7
RR
1848 if (m_dirty)
1849 {
1850 RecalculateDisplay();
1851 m_dirty = false;
1852 }
1853}
1854
1855void wxDataViewMainWindow::RecalculateDisplay()
1856{
aba9bfd0 1857 wxDataViewModel *model = GetOwner()->GetModel();
4b3feaa7
RR
1858 if (!model)
1859 {
1860 Refresh();
1861 return;
1862 }
f554a14b 1863
9861f022 1864 int width = GetEndOfLastCol();
aba9bfd0 1865 int height = GetRowCount() * m_lineHeight;
4b3feaa7
RR
1866
1867 SetVirtualSize( width, height );
1868 GetOwner()->SetScrollRate( 10, m_lineHeight );
f554a14b 1869
4b3feaa7
RR
1870 Refresh();
1871}
1872
1873void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1874{
1875 wxWindow::ScrollWindow( dx, dy, rect );
9861f022
RR
1876
1877 if (GetOwner()->m_headerArea)
1878 GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
4b3feaa7
RR
1879}
1880
f554a14b 1881void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4ed7af08 1882{
aba9bfd0 1883 wxDataViewModel *model = GetOwner()->GetModel();
2e992e06
VZ
1884 wxAutoBufferedPaintDC dc( this );
1885
9861f022 1886 // prepare the DC
2e992e06
VZ
1887 dc.SetBackground(GetBackgroundColour());
1888 dc.Clear();
4b3feaa7 1889 GetOwner()->PrepareDC( dc );
4ed7af08 1890 dc.SetFont( GetFont() );
90675b95
RR
1891
1892 wxRect update = GetUpdateRegion().GetBox();
1893 m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y );
f554a14b 1894
9861f022 1895 // compute which items needs to be redrawn
0a71f9e9 1896 unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) );
c741d33f 1897 unsigned int item_count =
87f0efe2 1898 wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1),
3b6280be 1899 (int)(GetRowCount( )- item_start) );
9861f022
RR
1900 unsigned int item_last = item_start + item_count;
1901
1902 // compute which columns needs to be redrawn
1903 unsigned int cols = GetOwner()->GetColumnCount();
1904 unsigned int col_start = 0;
1905 unsigned int x_start = 0;
1906 for (x_start = 0; col_start < cols; col_start++)
1907 {
1908 wxDataViewColumn *col = GetOwner()->GetColumn(col_start);
1909 if (col->IsHidden())
1910 continue; // skip it!
1911
1912 unsigned int w = col->GetWidth();
1913 if (x_start+w >= (unsigned int)update.x)
1914 break;
1915
1916 x_start += w;
1917 }
90675b95 1918
9861f022
RR
1919 unsigned int col_last = col_start;
1920 unsigned int x_last = x_start;
1921 for (; col_last < cols; col_last++)
1922 {
1923 wxDataViewColumn *col = GetOwner()->GetColumn(col_last);
1924 if (col->IsHidden())
1925 continue; // skip it!
1926
1927 if (x_last > (unsigned int)update.GetRight())
1928 break;
1929
1930 x_last += col->GetWidth();
1931 }
1932
1933 // Draw horizontal rules if required
1934 if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
1935 {
1936 dc.SetPen(m_penRule);
1937 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1938
1939 for (unsigned int i = item_start; i <= item_last+1; i++)
1940 {
1941 int y = i * m_lineHeight;
1942 dc.DrawLine(x_start, y, x_last, y);
1943 }
1944 }
1945
1946 // Draw vertical rules if required
1947 if ( m_owner->HasFlag(wxDV_VERT_RULES) )
1948 {
1949 dc.SetPen(m_penRule);
1950 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1951
1952 int x = x_start;
1953 for (unsigned int i = col_start; i < col_last; i++)
1954 {
1955 wxDataViewColumn *col = GetOwner()->GetColumn(i);
1956 if (col->IsHidden())
1957 continue; // skip it
1958
1959 dc.DrawLine(x, item_start * m_lineHeight,
1960 x, item_last * m_lineHeight);
1961
1962 x += col->GetWidth();
1963 }
1964
1965 // Draw last vertical rule
c741d33f 1966 dc.DrawLine(x, item_start * m_lineHeight,
9861f022
RR
1967 x, item_last * m_lineHeight);
1968 }
1969
1970 // redraw the background for the items which are selected/current
1971 for (unsigned int item = item_start; item < item_last; item++)
cab07038 1972 {
87f0efe2
RR
1973 bool selected = m_selection.Index( item ) != wxNOT_FOUND;
1974 if (selected || item == m_currentRow)
cab07038 1975 {
5d3f234b 1976 int flags = selected ? (int)wxCONTROL_SELECTED : 0;
daebb44c
RR
1977 if (item == m_currentRow)
1978 flags |= wxCONTROL_CURRENT;
1979 if (m_hasFocus)
1980 flags |= wxCONTROL_FOCUSED;
9861f022
RR
1981
1982 wxRect rect( x_start, item*m_lineHeight, x_last, m_lineHeight );
daebb44c
RR
1983 wxRendererNative::Get().DrawItemSelectionRect
1984 (
1985 this,
1986 dc,
1987 rect,
1988 flags
1989 );
1990 }
cab07038 1991 }
120b9b05 1992
9861f022 1993 // redraw all cells for all rows which must be repainted and for all columns
90675b95 1994 wxRect cell_rect;
9861f022
RR
1995 cell_rect.x = x_start;
1996 cell_rect.height = m_lineHeight; // -1 is for the horizontal rules
1997 for (unsigned int i = col_start; i < col_last; i++)
90675b95
RR
1998 {
1999 wxDataViewColumn *col = GetOwner()->GetColumn( i );
baa9ebc4 2000 wxDataViewRenderer *cell = col->GetRenderer();
90675b95 2001 cell_rect.width = col->GetWidth();
f554a14b 2002
87f0efe2
RR
2003 if (col->IsHidden())
2004 continue; // skipt it!
2005
9861f022 2006 for (unsigned int item = item_start; item < item_last; item++)
90675b95 2007 {
87f0efe2 2008 // get the cell value and set it into the renderer
90675b95 2009 wxVariant value;
3b6280be
RR
2010 wxDataViewTreeNode * node = GetTreeNodeByRow(item);
2011 if( node == NULL )
2012 continue;
2013
2014 wxDataViewItem dataitem = node->GetItem();
2015 model->GetValue( value, dataitem, col->GetModelColumn());
90675b95 2016 cell->SetValue( value );
87f0efe2
RR
2017
2018 // update the y offset
9861f022 2019 cell_rect.y = item * m_lineHeight;
87f0efe2 2020
3b6280be
RR
2021 //Draw the expander here. Please notice that I use const number for all pixel data. When the final API are determined
2022 //I will change this to the data member of the class wxDataViewCtrl
2023 int indent = node->GetIndentLevel();
2024 if( col->GetModelColumn() == GetOwner()->GetExpanderColumn() )
2025 {
2026 //Calculate the indent first
d5025dc0
RR
2027 indent = cell_rect.x + GetOwner()->GetIndent() * indent;
2028
3b6280be 2029 int expander_width = m_lineHeight - 2*EXPANDER_MARGIN;
d5025dc0
RR
2030 // change the cell_rect.x to the appropriate pos
2031 int expander_x = indent + EXPANDER_MARGIN , expander_y = cell_rect.y + EXPANDER_MARGIN ;
3b6280be
RR
2032 indent = indent + m_lineHeight ; //try to use the m_lineHeight as the expander space
2033 dc.SetPen( m_penExpander );
d5025dc0
RR
2034 dc.SetBrush( wxNullBrush );
2035 if( node->HasChildren() )
2036 {
2037 //dc.DrawRoundedRectangle( expander_x,expander_y,expander_width,expander_width, 1.0);
2038 //dc.DrawLine( expander_x + 2 , expander_y + expander_width/2, expander_x + expander_width - 2, expander_y + expander_width/2 );
2039 wxRect rect( expander_x , expander_y, expander_width, expander_width);
2040 if( node->IsOpen() )
2041 wxRendererNative::Get().DrawTreeItemButton( this, dc, rect, wxCONTROL_EXPANDED );
2042 else
2043 wxRendererNative::Get().DrawTreeItemButton( this, dc, rect );
2044 }
2045 else
2046 {
2047 // I am wandering whether we should draw dot lines between tree nodes
2048 }
2049
2050 //force the expander column to left-center align
2051 cell->SetAlignment( wxALIGN_CENTER_VERTICAL );
3b6280be
RR
2052 }
2053
2054
2055 // cannot be bigger than allocated space
87f0efe2 2056 wxSize size = cell->GetSize();
d5025dc0 2057 // Because of the tree structure indent, here we should minus the width of the cell for drawing
3b6280be 2058 size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width - indent );
9861f022 2059 size.y = wxMin( size.y + 2*PADDING_TOPBOTTOM, cell_rect.height );
87f0efe2
RR
2060
2061 wxRect item_rect(cell_rect.GetTopLeft(), size);
9861f022 2062 int align = cell->GetAlignment();
87f0efe2
RR
2063
2064 // horizontal alignment:
9861f022
RR
2065 item_rect.x = cell_rect.x;
2066 if (align & wxALIGN_CENTER_HORIZONTAL)
2067 item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
2068 else if (align & wxALIGN_RIGHT)
87f0efe2
RR
2069 item_rect.x = cell_rect.x + cell_rect.width - size.x;
2070 //else: wxALIGN_LEFT is the default
2071
2072 // vertical alignment:
9861f022
RR
2073 item_rect.y = cell_rect.y;
2074 if (align & wxALIGN_CENTER_VERTICAL)
87f0efe2 2075 item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
9861f022 2076 else if (align & wxALIGN_BOTTOM)
87f0efe2
RR
2077 item_rect.y = cell_rect.y + cell_rect.height - size.y;
2078 //else: wxALIGN_TOP is the default
2079
9861f022
RR
2080 // add padding
2081 item_rect.x += PADDING_RIGHTLEFT;
2082 item_rect.y += PADDING_TOPBOTTOM;
2083 item_rect.width = size.x - 2 * PADDING_RIGHTLEFT;
2084 item_rect.height = size.y - 2 * PADDING_TOPBOTTOM;
64b3c262 2085
3b6280be
RR
2086 //Here we add the tree indent
2087 item_rect.x += indent;
2088
64b3c262 2089 int state = 0;
87f0efe2 2090 if (m_selection.Index(item) != wxNOT_FOUND)
64b3c262 2091 state |= wxDATAVIEW_CELL_SELECTED;
87f0efe2 2092
9861f022
RR
2093 // TODO: it would be much more efficient to create a clipping
2094 // region for the entire column being rendered (in the OnPaint
2095 // of wxDataViewMainWindow) instead of a single clip region for
2096 // each cell. However it would mean that each renderer should
2097 // respect the given wxRect's top & bottom coords, eventually
2098 // violating only the left & right coords - however the user can
2099 // make its own renderer and thus we cannot be sure of that.
2100 dc.SetClippingRegion( item_rect );
64b3c262 2101 cell->Render( item_rect, &dc, state );
9861f022 2102 dc.DestroyClippingRegion();
90675b95 2103 }
f554a14b 2104
90675b95
RR
2105 cell_rect.x += cell_rect.width;
2106 }
4ed7af08
RR
2107}
2108
9861f022 2109int wxDataViewMainWindow::GetCountPerPage() const
cab07038
RR
2110{
2111 wxSize size = GetClientSize();
2112 return size.y / m_lineHeight;
2113}
2114
9861f022 2115int wxDataViewMainWindow::GetEndOfLastCol() const
e21f75bd
RR
2116{
2117 int width = 0;
0a71f9e9 2118 unsigned int i;
9861f022 2119 for (i = 0; i < GetOwner()->GetColumnCount(); i++)
e21f75bd 2120 {
c741d33f 2121 const wxDataViewColumn *c =
9861f022
RR
2122 wx_const_cast(wxDataViewCtrl*, GetOwner())->GetColumn( i );
2123
2124 if (!c->IsHidden())
2125 width += c->GetWidth();
e21f75bd
RR
2126 }
2127 return width;
2128}
2129
9861f022 2130unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
72664514
RR
2131{
2132 int x = 0;
2133 int y = 0;
2134 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
120b9b05 2135
72664514
RR
2136 return y / m_lineHeight;
2137}
2138
3b6280be 2139unsigned int wxDataViewMainWindow::GetLastVisibleRow()
72664514
RR
2140{
2141 wxSize client_size = GetClientSize();
c741d33f 2142 m_owner->CalcUnscrolledPosition( client_size.x, client_size.y,
87f0efe2 2143 &client_size.x, &client_size.y );
72664514 2144
5637e131 2145 return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 );
72664514
RR
2146}
2147
3b6280be 2148unsigned int wxDataViewMainWindow::GetRowCount()
cab07038 2149{
3b6280be
RR
2150 if ( m_count == -1 )
2151 {
2152 m_count = RecalculateCount();
d5025dc0
RR
2153 int width, height;
2154 GetVirtualSize( &width, &height );
3b6280be
RR
2155 height = m_count * m_lineHeight;
2156
2157 SetVirtualSize( width, height );
2158 }
aba9bfd0 2159 return m_count;
cab07038
RR
2160}
2161
0a71f9e9 2162void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row )
e21f75bd
RR
2163{
2164 m_currentRow = row;
120b9b05 2165
e21f75bd
RR
2166 // send event
2167}
2168
cab07038
RR
2169void wxDataViewMainWindow::SelectAllRows( bool on )
2170{
4a851b11
VZ
2171 if (IsEmpty())
2172 return;
120b9b05 2173
cab07038
RR
2174 if (on)
2175 {
72664514 2176 m_selection.Clear();
0a71f9e9 2177 for (unsigned int i = 0; i < GetRowCount(); i++)
cab07038 2178 m_selection.Add( i );
72664514
RR
2179 Refresh();
2180 }
2181 else
2182 {
0a71f9e9
RR
2183 unsigned int first_visible = GetFirstVisibleRow();
2184 unsigned int last_visible = GetLastVisibleRow();
2185 unsigned int i;
72664514 2186 for (i = 0; i < m_selection.GetCount(); i++)
120b9b05 2187 {
0a71f9e9 2188 unsigned int row = m_selection[i];
72664514
RR
2189 if ((row >= first_visible) && (row <= last_visible))
2190 RefreshRow( row );
2191 }
2192 m_selection.Clear();
cab07038 2193 }
cab07038
RR
2194}
2195
0a71f9e9 2196void wxDataViewMainWindow::SelectRow( unsigned int row, bool on )
cab07038
RR
2197{
2198 if (m_selection.Index( row ) == wxNOT_FOUND)
2199 {
2200 if (on)
2201 {
2202 m_selection.Add( row );
2203 RefreshRow( row );
2204 }
2205 }
2206 else
2207 {
2208 if (!on)
2209 {
2210 m_selection.Remove( row );
2211 RefreshRow( row );
2212 }
2213 }
2214}
2215
0a71f9e9 2216void wxDataViewMainWindow::SelectRows( unsigned int from, unsigned int to, bool on )
cab07038
RR
2217{
2218 if (from > to)
2219 {
0a71f9e9 2220 unsigned int tmp = from;
cab07038
RR
2221 from = to;
2222 to = tmp;
2223 }
2224
0a71f9e9 2225 unsigned int i;
cab07038
RR
2226 for (i = from; i <= to; i++)
2227 {
2228 if (m_selection.Index( i ) == wxNOT_FOUND)
2229 {
2230 if (on)
2231 m_selection.Add( i );
2232 }
2233 else
2234 {
2235 if (!on)
2236 m_selection.Remove( i );
2237 }
2238 }
2239 RefreshRows( from, to );
2240}
2241
87f0efe2
RR
2242void wxDataViewMainWindow::Select( const wxArrayInt& aSelections )
2243{
2244 for (size_t i=0; i < aSelections.GetCount(); i++)
2245 {
2246 int n = aSelections[i];
2247
2248 m_selection.Add( n );
2249 RefreshRow( n );
2250 }
2251}
2252
0a71f9e9 2253void wxDataViewMainWindow::ReverseRowSelection( unsigned int row )
cab07038
RR
2254{
2255 if (m_selection.Index( row ) == wxNOT_FOUND)
2256 m_selection.Add( row );
2257 else
2258 m_selection.Remove( row );
120b9b05 2259 RefreshRow( row );
cab07038
RR
2260}
2261
0a71f9e9 2262bool wxDataViewMainWindow::IsRowSelected( unsigned int row )
cab07038
RR
2263{
2264 return (m_selection.Index( row ) != wxNOT_FOUND);
2265}
2266
0a71f9e9 2267void wxDataViewMainWindow::RefreshRow( unsigned int row )
cab07038 2268{
e21f75bd 2269 wxRect rect( 0, row*m_lineHeight, GetEndOfLastCol(), m_lineHeight );
cab07038 2270 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2271
cab07038
RR
2272 wxSize client_size = GetClientSize();
2273 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2274 wxRect intersect_rect = client_rect.Intersect( rect );
2275 if (intersect_rect.width > 0)
2276 Refresh( true, &intersect_rect );
2277}
2278
0a71f9e9 2279void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
cab07038
RR
2280{
2281 if (from > to)
2282 {
0a71f9e9 2283 unsigned int tmp = to;
cab07038
RR
2284 to = from;
2285 from = tmp;
2286 }
2287
e21f75bd 2288 wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
cab07038 2289 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2290
cab07038
RR
2291 wxSize client_size = GetClientSize();
2292 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2293 wxRect intersect_rect = client_rect.Intersect( rect );
2294 if (intersect_rect.width > 0)
2295 Refresh( true, &intersect_rect );
2296}
2297
0a71f9e9 2298void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
cab07038 2299{
0a71f9e9 2300 unsigned int count = GetRowCount();
4a851b11
VZ
2301 if (firstRow > count)
2302 return;
120b9b05 2303
e21f75bd 2304 wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
cab07038 2305 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
120b9b05 2306
cab07038
RR
2307 wxSize client_size = GetClientSize();
2308 wxRect client_rect( 0, 0, client_size.x, client_size.y );
2309 wxRect intersect_rect = client_rect.Intersect( rect );
2310 if (intersect_rect.width > 0)
2311 Refresh( true, &intersect_rect );
2312}
2313
0a71f9e9 2314void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
cab07038 2315{
4a851b11 2316 wxCHECK_RET( newCurrent < GetRowCount(),
cab07038
RR
2317 _T("invalid item index in OnArrowChar()") );
2318
2319 // if there is no selection, we cannot move it anywhere
2320 if (!HasCurrentRow())
2321 return;
2322
0a71f9e9 2323 unsigned int oldCurrent = m_currentRow;
cab07038
RR
2324
2325 // in single selection we just ignore Shift as we can't select several
2326 // items anyhow
e21f75bd 2327 if ( event.ShiftDown() && !IsSingleSel() )
cab07038
RR
2328 {
2329 RefreshRow( oldCurrent );
120b9b05 2330
e21f75bd 2331 ChangeCurrentRow( newCurrent );
cab07038
RR
2332
2333 // select all the items between the old and the new one
2334 if ( oldCurrent > newCurrent )
2335 {
2336 newCurrent = oldCurrent;
2337 oldCurrent = m_currentRow;
2338 }
2339
2340 SelectRows( oldCurrent, newCurrent, true );
2341 }
2342 else // !shift
2343 {
72664514 2344 RefreshRow( oldCurrent );
120b9b05 2345
cab07038
RR
2346 // all previously selected items are unselected unless ctrl is held
2347 if ( !event.ControlDown() )
2348 SelectAllRows(false);
2349
e21f75bd 2350 ChangeCurrentRow( newCurrent );
cab07038
RR
2351
2352 if ( !event.ControlDown() )
2353 SelectRow( m_currentRow, true );
72664514
RR
2354 else
2355 RefreshRow( m_currentRow );
cab07038
RR
2356 }
2357
9861f022
RR
2358 //EnsureVisible( m_currentRow );
2359}
2360
2361wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const
2362{
2363 wxRect rect;
2364 rect.x = 0;
2365 rect.y = m_lineHeight * row;
2366 rect.width = GetEndOfLastCol();
2367 rect.height = m_lineHeight;
2368
2369 return rect;
cab07038
RR
2370}
2371
aba9bfd0
RR
2372class RowToItemJob: public DoJob
2373{
2374public:
2375 RowToItemJob( unsigned int row , int current ) { this->row = row; this->current = current ;}
2376 virtual ~RowToItemJob(){};
2377
d5025dc0 2378 virtual int operator() ( wxDataViewTreeNode * node )
aba9bfd0 2379 {
704c3490 2380 if( current == static_cast<int>(row))
d5025dc0
RR
2381 {
2382 ret = node->GetItem() ;
2383 return DoJob::OK;
2384 }
2385 current ++;
2386 if ( node->IsOpen())
2387 return DoJob::CONT;
2388 else
2389 return DoJob::IGR;
2390 }
2391
2392 wxDataViewItem GetResult(){ return ret; }
aba9bfd0
RR
2393private:
2394 unsigned int row;
2395 int current ;
2396 wxDataViewItem ret;
2397};
2398
2399wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row)
2400{
2401 RowToItemJob job( row, 0 );
2402 Walker( m_root , job );
2403 return job.GetResult();
2404}
2405
3b6280be
RR
2406class RowToTreeNodeJob: public DoJob
2407{
2408public:
d5025dc0
RR
2409 RowToTreeNodeJob( unsigned int row , int current ) { this->row = row; this->current = current ; ret = NULL ; }
2410 virtual ~RowToTreeNodeJob(){};
3b6280be
RR
2411
2412 virtual int operator() ( wxDataViewTreeNode * node )
d5025dc0 2413 {
704c3490 2414 if( current == static_cast<int>(row))
d5025dc0
RR
2415 {
2416 ret = node ;
2417 return DoJob::OK;
3b6280be 2418 }
d5025dc0
RR
2419 current ++;
2420 if ( node->IsOpen())
2421 return DoJob::CONT;
2422 else
2423 return DoJob::IGR;
2424 }
3b6280be
RR
2425
2426 wxDataViewTreeNode * GetResult(){ return ret; }
2427private:
2428 unsigned int row;
2429 int current ;
2430 wxDataViewTreeNode * ret;
2431};
2432
2433
2434wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row)
2435{
2436 RowToTreeNodeJob job( row , 0 );
2437 Walker( m_root , job );
2438 return job.GetResult();
2439}
2440
2441class CountJob : public DoJob
2442{
2443public:
2444 CountJob(){ count = 0 ; }
d5025dc0 2445 virtual ~CountJob(){};
3b6280be
RR
2446
2447 virtual int operator () ( wxDataViewTreeNode * node )
2448 {
d5025dc0
RR
2449 count ++;
2450 if ( node->IsOpen())
2451 return DoJob::CONT;
2452 else
2453 return DoJob::IGR;
3b6280be
RR
2454 }
2455
2456 unsigned int GetResult()
2457 {
2458 return count ;
2459 }
2460private:
2461 unsigned int count;
2462};
2463
2464void wxDataViewMainWindow::OnExpanding( unsigned int row )
2465{
2466 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
2467 if( node != NULL )
2468 {
d5025dc0
RR
2469 if( node->HasChildren())
2470 if( !node->IsOpen())
3b6280be 2471 {
d5025dc0 2472 node->ToggleOpen();
704c3490
RR
2473 //Here I build the children of current node
2474 if( node->GetChildrenNumber() == 0 )
2475 BuildTreeHelper(GetOwner()->GetModel(), node->GetItem(), node);
d5025dc0
RR
2476 m_count = -1;
2477 Refresh();
3b6280be
RR
2478 }
2479 }
2480}
2481
2482void wxDataViewMainWindow::OnCollapsing(unsigned int row)
2483{
2484 wxDataViewTreeNode * node = GetTreeNodeByRow(row);
d5025dc0 2485 if( node != NULL )
3b6280be
RR
2486 {
2487 if( node->HasChildren() && node->IsOpen() )
2488 {
2489 node->ToggleOpen();
2490 m_count = -1;
2491 Refresh();
2492 //RefreshRows(row,GetLastVisibleRow());
d5025dc0
RR
2493 }
2494 else
2495 {
2496 node = node->GetParent();
2497 if( node != NULL )
2498 {
2499 int parent = GetRowByItem( node->GetItem()) ;
2500 SelectRow( row, false);
2501 SelectRow(parent , true );
2502 ChangeCurrentRow( parent );
2503 }
2504 }
3b6280be
RR
2505 }
2506}
2507
2508int wxDataViewMainWindow::RecalculateCount()
2509{
2510 CountJob job;
2511 Walker( m_root, job );
2512 return job.GetResult();
2513}
2514
aba9bfd0
RR
2515class ItemToRowJob : public DoJob
2516{
2517public:
3b6280be 2518 ItemToRowJob(const wxDataViewItem & item){ this->item = item ; ret = 0 ; }
aba9bfd0
RR
2519 virtual ~ItemToRowJob(){};
2520
d5025dc0
RR
2521 virtual int operator() ( wxDataViewTreeNode * node)
2522 {
2523 ret ++;
2524 if( node->GetItem() == item )
2525 return DoJob::OK;
2526
2527 if( node->IsOpen())
2528 return DoJob::CONT;
2529 else
2530 return DoJob::IGR;
2531 }
aba9bfd0 2532
3b6280be
RR
2533 //the row number is begin from zero
2534 int GetResult(){ return ret -1 ; }
aba9bfd0
RR
2535private:
2536 wxDataViewItem item;
2537 int ret;
2538};
2539
2540unsigned int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item)
2541{
2542 ItemToRowJob job( item );
2543 Walker(m_root , job );
2544 return job.GetResult();
2545}
2546
704c3490 2547void BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node)
aba9bfd0 2548{
aba9bfd0 2549 if( !model->HasChildren( item ) )
704c3490 2550 return ;
aba9bfd0
RR
2551
2552 wxDataViewItem i = model->GetFirstChild( item );
2553 while( i.IsOk() )
2554 {
2555 wxDataViewTreeNode * n = new wxDataViewTreeNode( node );
3b6280be 2556 n->SetItem(i);
704c3490 2557 n->SetHasChildren( model->HasChildren( i )) ;
3b6280be 2558 node->AppendChild(n);
704c3490 2559 //BuildTreeHelper( model, i, n) ;
3b6280be 2560 i = model->GetNextSibling( i );
aba9bfd0 2561 }
aba9bfd0
RR
2562}
2563
2564void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
2565{
2566 //First we define a invalid item to fetch the top-level elements
2567 wxDataViewItem item;
3b6280be
RR
2568 BuildTreeHelper( model, item, m_root);
2569 m_count = -1 ;
aba9bfd0
RR
2570}
2571
2572void DestroyTreeHelper( wxDataViewTreeNode * node )
2573{
2574 if( node->HasChildren() )
2575 {
2576 int len = node->GetChildrenNumber();
3b6280be
RR
2577 int i = 0 ;
2578 wxDataViewTreeNodes nodes = node->GetChildren();
2579 for( ; i < len; i ++ )
aba9bfd0
RR
2580 {
2581 DestroyTreeHelper(nodes[i]);
2582 }
2583 }
2584 delete node;
2585}
2586
2587void wxDataViewMainWindow::DestroyTree()
2588{
2589 DestroyTreeHelper(m_root);
2590 m_count = 0 ;
2591}
2592
cab07038
RR
2593void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
2594{
2595 if (event.GetKeyCode() == WXK_TAB)
2596 {
2597 wxNavigationKeyEvent nevent;
2598 nevent.SetWindowChange( event.ControlDown() );
2599 nevent.SetDirection( !event.ShiftDown() );
2600 nevent.SetEventObject( GetParent()->GetParent() );
2601 nevent.SetCurrentFocus( m_parent );
2602 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
2603 return;
2604 }
2605
2606 // no item -> nothing to do
2607 if (!HasCurrentRow())
2608 {
2609 event.Skip();
2610 return;
2611 }
120b9b05 2612
cab07038
RR
2613 // don't use m_linesPerPage directly as it might not be computed yet
2614 const int pageSize = GetCountPerPage();
2615 wxCHECK_RET( pageSize, _T("should have non zero page size") );
2616
2617 switch ( event.GetKeyCode() )
2618 {
2619 case WXK_UP:
2620 if ( m_currentRow > 0 )
2621 OnArrowChar( m_currentRow - 1, event );
2622 break;
2623
2624 case WXK_DOWN:
4a851b11 2625 if ( m_currentRow < GetRowCount() - 1 )
cab07038
RR
2626 OnArrowChar( m_currentRow + 1, event );
2627 break;
3b6280be
RR
2628 //Add the process for tree expanding/collapsing
2629 case WXK_LEFT:
2630 OnCollapsing(m_currentRow);
2631 break;
2632 case WXK_RIGHT:
2633 OnExpanding( m_currentRow);
2634 break;
cab07038
RR
2635 case WXK_END:
2636 if (!IsEmpty())
2637 OnArrowChar( GetRowCount() - 1, event );
2638 break;
2639
2640 case WXK_HOME:
2641 if (!IsEmpty())
2642 OnArrowChar( 0, event );
2643 break;
2644
2645 case WXK_PAGEUP:
2646 {
2647 int steps = pageSize - 1;
2648 int index = m_currentRow - steps;
2649 if (index < 0)
2650 index = 0;
2651
2652 OnArrowChar( index, event );
2653 }
2654 break;
2655
2656 case WXK_PAGEDOWN:
2657 {
2658 int steps = pageSize - 1;
0a71f9e9
RR
2659 unsigned int index = m_currentRow + steps;
2660 unsigned int count = GetRowCount();
cab07038
RR
2661 if ( index >= count )
2662 index = count - 1;
2663
2664 OnArrowChar( index, event );
2665 }
2666 break;
2667
2668 default:
2669 event.Skip();
2670 }
2671}
2672
4ed7af08
RR
2673void wxDataViewMainWindow::OnMouse( wxMouseEvent &event )
2674{
e21f75bd
RR
2675 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
2676 {
2677 // let the base handle mouse wheel events.
2678 event.Skip();
2679 return;
2680 }
2681
0fdc2321
RR
2682 int x = event.GetX();
2683 int y = event.GetY();
2684 m_owner->CalcUnscrolledPosition( x, y, &x, &y );
2685
2686 wxDataViewColumn *col = NULL;
2687
2688 int xpos = 0;
9861f022 2689 unsigned int cols = GetOwner()->GetColumnCount();
0a71f9e9 2690 unsigned int i;
0fdc2321
RR
2691 for (i = 0; i < cols; i++)
2692 {
2693 wxDataViewColumn *c = GetOwner()->GetColumn( i );
9861f022
RR
2694 if (c->IsHidden())
2695 continue; // skip it!
2696
0fdc2321
RR
2697 if (x < xpos + c->GetWidth())
2698 {
2699 col = c;
2700 break;
2701 }
2702 xpos += c->GetWidth();
2703 }
f554a14b 2704 if (!col)
0fdc2321 2705 return;
baa9ebc4 2706 wxDataViewRenderer *cell = col->GetRenderer();
f554a14b 2707
0a71f9e9 2708 unsigned int current = y / m_lineHeight;
120b9b05 2709
e21f75bd
RR
2710 if ((current > GetRowCount()) || (x > GetEndOfLastCol()))
2711 {
2712 // Unselect all if below the last row ?
2713 return;
2714 }
f554a14b 2715
aba9bfd0 2716 wxDataViewModel *model = GetOwner()->GetModel();
0fdc2321 2717
e21f75bd
RR
2718 if (event.Dragging())
2719 {
2720 if (m_dragCount == 0)
2721 {
2722 // we have to report the raw, physical coords as we want to be
2723 // able to call HitTest(event.m_pointDrag) from the user code to
2724 // get the item being dragged
2725 m_dragStart = event.GetPosition();
2726 }
2727
2728 m_dragCount++;
2729
2730 if (m_dragCount != 3)
2731 return;
2732
2733 if (event.LeftIsDown())
2734 {
2735 // Notify cell about drag
2736 }
2737 return;
2738 }
2739 else
2740 {
2741 m_dragCount = 0;
2742 }
2743
2744 bool forceClick = false;
2745
0fcce6b9
RR
2746 if (event.ButtonDClick())
2747 {
2748 m_renameTimer->Stop();
2749 m_lastOnSame = false;
2750 }
2751
0fdc2321
RR
2752 if (event.LeftDClick())
2753 {
e21f75bd 2754 if ( current == m_lineLastClicked )
0fdc2321 2755 {
e21f75bd
RR
2756 if (cell->GetMode() == wxDATAVIEW_CELL_ACTIVATABLE)
2757 {
6cdcbce3 2758 wxDataViewItem item = GetItemByRow(current);
e21f75bd 2759 wxVariant value;
6cdcbce3 2760 model->GetValue( value, item, col->GetModelColumn() );
e21f75bd 2761 cell->SetValue( value );
c741d33f 2762 wxRect cell_rect( xpos, current * m_lineHeight,
87f0efe2 2763 col->GetWidth(), m_lineHeight );
6cdcbce3 2764 cell->Activate( cell_rect, model, item, col->GetModelColumn() );
e21f75bd
RR
2765 }
2766 return;
2767 }
2768 else
2769 {
2770 // The first click was on another item, so don't interpret this as
2771 // a double click, but as a simple click instead
2772 forceClick = true;
0fdc2321 2773 }
120b9b05 2774 }
f554a14b 2775
0fcce6b9
RR
2776 if (event.LeftUp())
2777 {
0a71f9e9 2778 if (m_lineSelectSingleOnUp != (unsigned int)-1)
e21f75bd
RR
2779 {
2780 // select single line
2781 SelectAllRows( false );
2782 SelectRow( m_lineSelectSingleOnUp, true );
2783 }
120b9b05 2784
3b6280be 2785 //Process the event of user clicking the expander
d5025dc0
RR
2786 bool expander = false;
2787 wxDataViewTreeNode * node = GetTreeNodeByRow(current);
2788 if( node!=NULL && node->HasChildren() )
2789 {
2790 int indent = node->GetIndentLevel();
2791 indent = GetOwner()->GetIndent()*indent;
2792 wxRect rect( xpos + indent + EXPANDER_MARGIN, current * m_lineHeight + EXPANDER_MARGIN, m_lineHeight-2*EXPANDER_MARGIN,m_lineHeight-2*EXPANDER_MARGIN);
2793 if( rect.Contains( x, y) )
2794 {
2795 expander = true;
704c3490
RR
2796 if( node->IsOpen() )
2797 OnCollapsing(current);
2798 else
2799 OnExpanding( current );
d5025dc0
RR
2800 }
2801 }
3b6280be
RR
2802
2803 //If the user click the expander, we do not do editing even if the column with expander are editable
2804 if (m_lastOnSame && !expander )
0fcce6b9 2805 {
a8461d31 2806 if ((col == m_currentCol) && (current == m_currentRow) &&
0fcce6b9
RR
2807 (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) )
2808 {
2809 m_renameTimer->Start( 100, true );
2810 }
2811 }
2812
2813 m_lastOnSame = false;
0a71f9e9 2814 m_lineSelectSingleOnUp = (unsigned int)-1;
120b9b05 2815 }
e21f75bd
RR
2816 else
2817 {
2818 // This is necessary, because after a DnD operation in
2819 // from and to ourself, the up event is swallowed by the
2820 // DnD code. So on next non-up event (which means here and
2821 // now) m_lineSelectSingleOnUp should be reset.
0a71f9e9 2822 m_lineSelectSingleOnUp = (unsigned int)-1;
e21f75bd
RR
2823 }
2824
2825 if (event.RightDown())
2826 {
2827 m_lineBeforeLastClicked = m_lineLastClicked;
2828 m_lineLastClicked = current;
2829
2830 // If the item is already selected, do not update the selection.
2831 // Multi-selections should not be cleared if a selected item is clicked.
2832 if (!IsRowSelected(current))
2833 {
2834 SelectAllRows(false);
2835 ChangeCurrentRow(current);
2836 SelectRow(m_currentRow,true);
2837 }
2838
2839 // notify cell about right click
2840 // cell->...
120b9b05 2841
e21f75bd
RR
2842 // Allow generation of context menu event
2843 event.Skip();
2844 }
2845 else if (event.MiddleDown())
2846 {
2847 // notify cell about middle click
2848 // cell->...
2849 }
2850 if (event.LeftDown() || forceClick)
0fcce6b9 2851 {
72664514
RR
2852#ifdef __WXMSW__
2853 SetFocus();
2854#endif
120b9b05 2855
e21f75bd
RR
2856 m_lineBeforeLastClicked = m_lineLastClicked;
2857 m_lineLastClicked = current;
2858
0a71f9e9 2859 unsigned int oldCurrentRow = m_currentRow;
e21f75bd
RR
2860 bool oldWasSelected = IsRowSelected(m_currentRow);
2861
2862 bool cmdModifierDown = event.CmdDown();
2863 if ( IsSingleSel() || !(cmdModifierDown || event.ShiftDown()) )
2864 {
2865 if ( IsSingleSel() || !IsRowSelected(current) )
2866 {
2867 SelectAllRows( false );
2868
2869 ChangeCurrentRow(current);
2870
2871 SelectRow(m_currentRow,true);
2872 }
2873 else // multi sel & current is highlighted & no mod keys
2874 {
2875 m_lineSelectSingleOnUp = current;
2876 ChangeCurrentRow(current); // change focus
2877 }
2878 }
2879 else // multi sel & either ctrl or shift is down
2880 {
2881 if (cmdModifierDown)
2882 {
2883 ChangeCurrentRow(current);
2884
2885 ReverseRowSelection(m_currentRow);
2886 }
2887 else if (event.ShiftDown())
2888 {
2889 ChangeCurrentRow(current);
2890
0a71f9e9 2891 unsigned int lineFrom = oldCurrentRow,
e21f75bd
RR
2892 lineTo = current;
2893
2894 if ( lineTo < lineFrom )
2895 {
2896 lineTo = lineFrom;
2897 lineFrom = m_currentRow;
2898 }
2899
2900 SelectRows(lineFrom, lineTo, true);
2901 }
2902 else // !ctrl, !shift
2903 {
2904 // test in the enclosing if should make it impossible
2905 wxFAIL_MSG( _T("how did we get here?") );
2906 }
2907 }
2908
72664514
RR
2909 if (m_currentRow != oldCurrentRow)
2910 RefreshRow( oldCurrentRow );
e21f75bd 2911
0fcce6b9 2912 wxDataViewColumn *oldCurrentCol = m_currentCol;
120b9b05 2913
0fcce6b9
RR
2914 // Update selection here...
2915 m_currentCol = col;
120b9b05 2916
c741d33f 2917 m_lastOnSame = !forceClick && ((col == oldCurrentCol) &&
87f0efe2 2918 (current == oldCurrentRow)) && oldWasSelected;
0fdc2321 2919 }
4ed7af08
RR
2920}
2921
2922void wxDataViewMainWindow::OnSetFocus( wxFocusEvent &event )
2923{
cab07038 2924 m_hasFocus = true;
120b9b05 2925
cab07038
RR
2926 if (HasCurrentRow())
2927 Refresh();
120b9b05 2928
cab07038
RR
2929 event.Skip();
2930}
2931
2932void wxDataViewMainWindow::OnKillFocus( wxFocusEvent &event )
2933{
2934 m_hasFocus = false;
120b9b05 2935
cab07038
RR
2936 if (HasCurrentRow())
2937 Refresh();
120b9b05 2938
4ed7af08
RR
2939 event.Skip();
2940}
2941
704c3490
RR
2942wxDataViewItem wxDataViewMainWindow::GetSelection()
2943{
2944 if( m_selection.GetCount() != 1 )
2945 return wxDataViewItem();
2946 return GetItemByRow( m_selection.Item( 0 ) );
2947}
2948
4ed7af08
RR
2949//-----------------------------------------------------------------------------
2950// wxDataViewCtrl
2951//-----------------------------------------------------------------------------
2952
2953IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase)
2954
4b3feaa7
RR
2955BEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase)
2956 EVT_SIZE(wxDataViewCtrl::OnSize)
2957END_EVENT_TABLE()
2958
4ed7af08
RR
2959wxDataViewCtrl::~wxDataViewCtrl()
2960{
2961 if (m_notifier)
2962 GetModel()->RemoveNotifier( m_notifier );
2963}
2964
2965void wxDataViewCtrl::Init()
2966{
2967 m_notifier = NULL;
2968}
2969
2970bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id,
f554a14b 2971 const wxPoint& pos, const wxSize& size,
4ed7af08
RR
2972 long style, const wxValidator& validator )
2973{
c741d33f 2974 if (!wxControl::Create( parent, id, pos, size,
87f0efe2 2975 style | wxScrolledWindowStyle|wxSUNKEN_BORDER, validator))
4b3feaa7
RR
2976 return false;
2977
4ed7af08 2978 Init();
f554a14b 2979
4ed7af08
RR
2980#ifdef __WXMAC__
2981 MacSetClipChildren( true ) ;
2982#endif
2983
f554a14b 2984 m_clientArea = new wxDataViewMainWindow( this, wxID_ANY );
9861f022
RR
2985
2986 if (HasFlag(wxDV_NO_HEADER))
2987 m_headerArea = NULL;
2988 else
2989 m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY );
f554a14b 2990
4ed7af08 2991 SetTargetWindow( m_clientArea );
f554a14b 2992
4ed7af08 2993 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
9861f022
RR
2994 if (m_headerArea)
2995 sizer->Add( m_headerArea, 0, wxGROW );
4ed7af08
RR
2996 sizer->Add( m_clientArea, 1, wxGROW );
2997 SetSizer( sizer );
2998
2999 return true;
3000}
3001
3002#ifdef __WXMSW__
3003WXLRESULT wxDataViewCtrl::MSWWindowProc(WXUINT nMsg,
3004 WXWPARAM wParam,
3005 WXLPARAM lParam)
3006{
b910a8ad 3007 WXLRESULT rc = wxDataViewCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
4ed7af08
RR
3008
3009#ifndef __WXWINCE__
3010 // we need to process arrows ourselves for scrolling
3011 if ( nMsg == WM_GETDLGCODE )
3012 {
3013 rc |= DLGC_WANTARROWS;
3014 }
3015#endif
3016
3017 return rc;
3018}
3019#endif
3020
f554a14b 3021void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) )
4ed7af08 3022{
4b3feaa7
RR
3023 // We need to override OnSize so that our scrolled
3024 // window a) does call Layout() to use sizers for
3025 // positioning the controls but b) does not query
3026 // the sizer for their size and use that for setting
3027 // the scrollable area as set that ourselves by
3028 // calling SetScrollbar() further down.
3029
3030 Layout();
3031
3032 AdjustScrollbars();
4ed7af08
RR
3033}
3034
aba9bfd0 3035bool wxDataViewCtrl::AssociateModel( wxDataViewModel *model )
4ed7af08
RR
3036{
3037 if (!wxDataViewCtrlBase::AssociateModel( model ))
3038 return false;
3039
aba9bfd0 3040 m_notifier = new wxGenericDataViewModelNotifier( m_clientArea );
4ed7af08 3041
f554a14b 3042 model->AddNotifier( m_notifier );
4ed7af08 3043
aba9bfd0
RR
3044 m_clientArea->BuildTree(model);
3045
4b3feaa7 3046 m_clientArea->UpdateDisplay();
f554a14b 3047
4ed7af08
RR
3048 return true;
3049}
3050
3051bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
3052{
3053 if (!wxDataViewCtrlBase::AppendColumn(col))
3054 return false;
f554a14b 3055
9861f022 3056 OnColumnChange();
4ed7af08
RR
3057 return true;
3058}
3059
9861f022
RR
3060void wxDataViewCtrl::OnColumnChange()
3061{
3062 if (m_headerArea)
3063 m_headerArea->UpdateDisplay();
3064
3065 m_clientArea->UpdateDisplay();
3066}
3b6280be
RR
3067
3068void wxDataViewCtrl::DoSetExpanderColumn()
3069{
3070 m_clientArea->UpdateDisplay();
3071}
3072
3073void wxDataViewCtrl::DoSetIndent()
3074{
3075 m_clientArea->UpdateDisplay();
3076}
3077
704c3490
RR
3078wxDataViewItem wxDataViewCtrl::GetSelection()
3079{
3080 return m_clientArea->GetSelection();
3081}
3b6280be 3082
aba9bfd0 3083/********************************************************************
87f0efe2 3084void wxDataViewCtrl::SetSelection( int row )
6ff7eee7 3085{
87f0efe2 3086 m_clientArea->SelectRow(row, true);
6ff7eee7
RR
3087}
3088
87f0efe2 3089void wxDataViewCtrl::SetSelectionRange( unsigned int from, unsigned int to )
6ff7eee7 3090{
87f0efe2 3091 m_clientArea->SelectRows(from, to, true);
6ff7eee7
RR
3092}
3093
87f0efe2 3094void wxDataViewCtrl::SetSelections( const wxArrayInt& aSelections )
6ff7eee7 3095{
87f0efe2 3096 m_clientArea->Select(aSelections);
6ff7eee7 3097}
df387169
WS
3098
3099void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) )
fc211fe5 3100{
df387169 3101 // FIXME - TODO
fc211fe5
RR
3102}
3103
df387169 3104bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const
6ff7eee7 3105{
df387169
WS
3106 // FIXME - TODO
3107
6ff7eee7
RR
3108 return false;
3109}
3110
3111int wxDataViewCtrl::GetSelection() const
3112{
df387169
WS
3113 // FIXME - TODO
3114
6ff7eee7
RR
3115 return -1;
3116}
3117
df387169 3118int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const
6ff7eee7 3119{
df387169
WS
3120 // FIXME - TODO
3121
6ff7eee7
RR
3122 return 0;
3123}
aba9bfd0 3124*********************************************************************/
f554a14b 3125#endif
4ed7af08
RR
3126 // !wxUSE_GENERICDATAVIEWCTRL
3127
f554a14b 3128#endif
4ed7af08 3129 // wxUSE_DATAVIEWCTRL