1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        dataview.cpp
3 // Purpose:     wxDataViewCtrl wxWidgets sample
4 // Author:      Robert Roebling
5 // Modified by: Francesco Montorsi, Bo Yang
6 // Created:     06/01/06
7 // Copyright:   (c) Robert Roebling
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // For compilers that support precompilation, includes "wx/wx.h".
16 #include "wx/wxprec.h"
17 
18 
19 #ifndef WX_PRECOMP
20     #include "wx/wx.h"
21 #endif
22 
23 #include "wx/artprov.h"
24 #include "wx/dataview.h"
25 #include "wx/datetime.h"
26 #include "wx/splitter.h"
27 #include "wx/aboutdlg.h"
28 #include "wx/colordlg.h"
29 #include "wx/choicdlg.h"
30 #include "wx/numdlg.h"
31 #include "wx/spinctrl.h"
32 #include "wx/imaglist.h"
33 #include "wx/itemattr.h"
34 #include "wx/notebook.h"
35 
36 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
37     #include "wx/headerctrl.h"
38 #endif // wxHAS_GENERIC_DATAVIEWCTRL
39 
40 #include "mymodels.h"
41 
42 // ----------------------------------------------------------------------------
43 // resources
44 // ----------------------------------------------------------------------------
45 
46 #ifndef wxHAS_IMAGES_IN_RESOURCES
47     #include "../sample.xpm"
48 #endif
49 
50 #include "wx_small.xpm"
51 
52 // ----------------------------------------------------------------------------
53 // MyApp
54 // ----------------------------------------------------------------------------
55 
56 class MyApp: public wxApp
57 {
58 public:
59     virtual bool OnInit() wxOVERRIDE;
60 };
61 
62 // ----------------------------------------------------------------------------
63 // MyFrame
64 // ----------------------------------------------------------------------------
65 
66 class MyFrame : public wxFrame
67 {
68 public:
69     MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int h);
70     ~MyFrame();
71 
72     void BuildDataViewCtrl(wxPanel* parent,
73                            unsigned int nPanel,
74                            unsigned long style = 0);
75 
76 private:
77     // event handlers
78     void OnStyleChange(wxCommandEvent& event);
79     void OnSetBackgroundColour(wxCommandEvent& event);
80     void OnCustomHeaderAttr(wxCommandEvent& event);
81 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
82     void OnCustomHeaderHeight(wxCommandEvent& event);
83 #endif // wxHAS_GENERIC_DATAVIEWCTRL
84     void OnGetPageInfo(wxCommandEvent& event);
85     void OnDisable(wxCommandEvent& event);
86     void OnSetForegroundColour(wxCommandEvent& event);
87     void OnIncIndent(wxCommandEvent& event);
88     void OnDecIndent(wxCommandEvent& event);
89 
90     void OnQuit(wxCommandEvent& event);
91     void OnAbout(wxCommandEvent& event);
92 
93     void OnClearLog(wxCommandEvent& event);
94     void OnPageChanged(wxBookCtrlEvent& event);
95 
96     void OnAddMozart(wxCommandEvent& event);
97     void OnDeleteSelected(wxCommandEvent& event);
98     void OnDeleteYear(wxCommandEvent& event);
99     void OnSelectNinth(wxCommandEvent& event);
100     void OnCollapse(wxCommandEvent& event);
101     void OnExpand(wxCommandEvent& event);
102     void OnShowCurrent(wxCommandEvent& event);
103     void OnSetNinthCurrent(wxCommandEvent& event);
104     void OnChangeNinthTitle(wxCommandEvent& event);
105 
106     void OnPrependList(wxCommandEvent& event);
107     void OnDeleteList(wxCommandEvent& event);
108 
109     // Third (wxDataViewListCtrl) page.
110     void OnListValueChanged(wxDataViewEvent& event);
111 
112     // Fourth page.
113     void OnDeleteTreeItem(wxCommandEvent& event);
114     void OnDeleteAllTreeItems(wxCommandEvent& event);
115     void OnAddTreeItem(wxCommandEvent& event);
116     void OnAddTreeContainerItem(wxCommandEvent& event);
117 
OnIndexListUseEnglish(wxCommandEvent &)118     void OnIndexListUseEnglish(wxCommandEvent&) { FillIndexList(Lang_English); }
OnIndexListUseFrench(wxCommandEvent &)119     void OnIndexListUseFrench(wxCommandEvent&) { FillIndexList(Lang_French); }
120     void OnIndexListResetModel(wxCommandEvent& event);
121     void OnIndexListSelectionChanged(wxDataViewEvent& event);
122 
123     void OnValueChanged( wxDataViewEvent &event );
124 
125     void OnActivated( wxDataViewEvent &event );
126     void OnExpanding( wxDataViewEvent &event );
127     void OnExpanded( wxDataViewEvent &event );
128     void OnCollapsing( wxDataViewEvent &event );
129     void OnCollapsed( wxDataViewEvent &event );
130     void OnSelectionChanged( wxDataViewEvent &event );
131 
132     void OnStartEditing( wxDataViewEvent &event );
133     void OnEditingStarted( wxDataViewEvent &event );
134     void OnEditingDone( wxDataViewEvent &event );
135 
136     void OnHeaderClick( wxDataViewEvent &event );
137     void OnAttrHeaderClick( wxDataViewEvent &event );
138     void OnHeaderRightClick( wxDataViewEvent &event );
139     void OnHeaderClickList( wxDataViewEvent &event );
140     void OnSorted( wxDataViewEvent &event );
141     void OnSortedList( wxDataViewEvent &event );
142     void OnColumnReordered( wxDataViewEvent &event);
143 
144     void OnContextMenu( wxDataViewEvent &event );
145 
146     void OnGoto( wxCommandEvent &event);
147     void OnAddMany( wxCommandEvent &event);
148     void OnHideAttributes( wxCommandEvent &event);
149     void OnShowAttributes( wxCommandEvent &event);
150 
151     void OnMultipleSort( wxCommandEvent &event);
152     void OnSortByFirstColumn( wxCommandEvent &event);
153 
154 #if wxUSE_DRAG_AND_DROP
155     void OnBeginDrag( wxDataViewEvent &event );
156     void OnDropPossible( wxDataViewEvent &event );
157     void OnDrop( wxDataViewEvent &event );
158 #endif // wxUSE_DRAG_AND_DROP
159 
160     void OnDataViewChar(wxKeyEvent& event);
161 
162     // helper used by both OnDeleteSelected() and OnDataViewChar()
163     void DeleteSelectedItems();
164 
165     // helper for the index list model fills the model with the weekday names
166     // in the specified language
167     enum Lang { Lang_English, Lang_French };
168     void FillIndexList(Lang lang);
169 
170     // HasValue page.
171     void OnHasValueValueChanged(wxDataViewEvent& event);
172 
173 
174     wxNotebook* m_notebook;
175 
176     // the controls stored in the various tabs of the main notebook:
177     enum Page
178     {
179         Page_Music,
180         Page_List,
181         Page_ListStore,
182         Page_TreeStore,
183         Page_VarHeight,
184         Page_IndexList,
185         Page_HasValue,
186         Page_Max
187     };
188 
189     wxDataViewCtrl* m_ctrl[Page_Max];
190 
191     // Some of the models associated with the controls:
192 
193     wxObjectDataPtr<MyMusicTreeModel> m_music_model;
194     wxObjectDataPtr<MyLongMusicTreeModel> m_long_music_model;
195     wxObjectDataPtr<MyListModel> m_list_model;
196     wxObjectDataPtr<MyIndexListModel> m_index_list_model;
197 
198     // other data:
199 
200     wxDataViewColumn* m_col;
201     wxDataViewColumn* m_attributes;
202 
203     wxTextCtrl* m_log;
204     wxLog *m_logOld;
205 
206 private:
207     // Flag used by OnListValueChanged(), see there.
208     bool m_eventFromProgram;
209 
210     wxDECLARE_EVENT_TABLE();
211 };
212 
213 
214 // ----------------------------------------------------------------------------
215 // MyCustomRenderer
216 // ----------------------------------------------------------------------------
217 
218 class MyCustomRenderer: public wxDataViewCustomRenderer
219 {
220 public:
221     // This renderer can be either activatable or editable, for demonstration
222     // purposes. In real programs, you should select whether the user should be
223     // able to activate or edit the cell and it doesn't make sense to switch
224     // between the two -- but this is just an example, so it doesn't stop us.
MyCustomRenderer(wxDataViewCellMode mode)225     explicit MyCustomRenderer(wxDataViewCellMode mode)
226         : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
227        { }
228 
Render(wxRect rect,wxDC * dc,int state)229     virtual bool Render( wxRect rect, wxDC *dc, int state ) wxOVERRIDE
230     {
231         dc->SetBrush( *wxLIGHT_GREY_BRUSH );
232         dc->SetPen( *wxTRANSPARENT_PEN );
233 
234         rect.Deflate(2);
235         dc->DrawRoundedRectangle( rect, 5 );
236 
237         RenderText(m_value,
238                    0, // no offset
239                    wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
240                    dc,
241                    state);
242         return true;
243     }
244 
ActivateCell(const wxRect & WXUNUSED (cell),wxDataViewModel * WXUNUSED (model),const wxDataViewItem & WXUNUSED (item),unsigned int WXUNUSED (col),const wxMouseEvent * mouseEvent)245     virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
246                               wxDataViewModel *WXUNUSED(model),
247                               const wxDataViewItem &WXUNUSED(item),
248                               unsigned int WXUNUSED(col),
249                               const wxMouseEvent *mouseEvent) wxOVERRIDE
250     {
251         wxString position;
252         if ( mouseEvent )
253             position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
254         else
255             position = "from keyboard";
256         wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
257         return false;
258     }
259 
GetSize() const260     virtual wxSize GetSize() const wxOVERRIDE
261     {
262         return GetView()->FromDIP(wxSize(60, 20));
263     }
264 
SetValue(const wxVariant & value)265     virtual bool SetValue( const wxVariant &value ) wxOVERRIDE
266     {
267         m_value = value.GetString();
268         return true;
269     }
270 
GetValue(wxVariant & WXUNUSED (value)) const271     virtual bool GetValue( wxVariant &WXUNUSED(value) ) const wxOVERRIDE { return true; }
272 
273 #if wxUSE_ACCESSIBILITY
GetAccessibleDescription() const274     virtual wxString GetAccessibleDescription() const wxOVERRIDE
275     {
276         return m_value;
277     }
278 #endif // wxUSE_ACCESSIBILITY
279 
HasEditorCtrl() const280     virtual bool HasEditorCtrl() const wxOVERRIDE { return true; }
281 
282     virtual wxWindow*
CreateEditorCtrl(wxWindow * parent,wxRect labelRect,const wxVariant & value)283     CreateEditorCtrl(wxWindow* parent,
284                      wxRect labelRect,
285                      const wxVariant& value) wxOVERRIDE
286     {
287         wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
288                                           labelRect.GetPosition(),
289                                           labelRect.GetSize(),
290                                           wxTE_PROCESS_ENTER);
291         text->SetInsertionPointEnd();
292 
293         return text;
294     }
295 
296     virtual bool
GetValueFromEditorCtrl(wxWindow * ctrl,wxVariant & value)297     GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) wxOVERRIDE
298     {
299         wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
300         if ( !text )
301             return false;
302 
303         value = text->GetValue();
304 
305         return true;
306     }
307 
308 private:
309     wxString m_value;
310 };
311 
312 
313 // ----------------------------------------------------------------------------
314 // MultiLineCustomRenderer
315 // ----------------------------------------------------------------------------
316 
317 class MultiLineCustomRenderer : public wxDataViewCustomRenderer
318 {
319 public:
320     // a simple renderer that wraps each word on a new line
MultiLineCustomRenderer()321     explicit MultiLineCustomRenderer()
322         : wxDataViewCustomRenderer("string", wxDATAVIEW_CELL_INERT, 0)
323     { }
324 
Render(wxRect rect,wxDC * dc,int state)325     virtual bool Render(wxRect rect, wxDC *dc, int state) wxOVERRIDE
326     {
327         RenderText(m_value, 0, rect, dc, state);
328         return true;
329     }
330 
GetSize() const331     virtual wxSize GetSize() const wxOVERRIDE
332     {
333         wxSize txtSize = GetTextExtent(m_value);
334         int lines = m_value.Freq('\n') + 1;
335         txtSize.SetHeight(txtSize.GetHeight() * lines);
336         return txtSize;
337     }
338 
SetValue(const wxVariant & value)339     virtual bool SetValue(const wxVariant &value) wxOVERRIDE
340     {
341         m_value = value.GetString();
342         m_value.Replace(" ", "\n");
343         return true;
344     }
345 
GetValue(wxVariant & WXUNUSED (value)) const346     virtual bool GetValue(wxVariant &WXUNUSED(value)) const wxOVERRIDE { return true; }
347 
348 #if wxUSE_ACCESSIBILITY
GetAccessibleDescription() const349     virtual wxString GetAccessibleDescription() const wxOVERRIDE
350     {
351         return m_value;
352     }
353 #endif // wxUSE_ACCESSIBILITY
354 
355 private:
356     wxString m_value;
357 };
358 
359 
360 // ============================================================================
361 // implementation
362 // ============================================================================
363 
364 // ----------------------------------------------------------------------------
365 // MyApp
366 // ----------------------------------------------------------------------------
367 
368 wxIMPLEMENT_APP(MyApp);
369 
OnInit()370 bool MyApp::OnInit()
371 {
372     if ( !wxApp::OnInit() )
373         return false;
374 
375     MyFrame *frame =
376         new MyFrame(NULL, "wxDataViewCtrl sample", 40, 40, 1000, 540);
377 
378     frame->Show(true);
379     return true;
380 }
381 
382 
383 // ----------------------------------------------------------------------------
384 // MyFrame
385 // ----------------------------------------------------------------------------
386 
387 enum
388 {
389     ID_CLEARLOG = wxID_HIGHEST+1,
390     ID_GET_PAGE_INFO,
391     ID_DISABLE,
392     ID_BACKGROUND_COLOUR,
393     ID_FOREGROUND_COLOUR,
394     ID_CUSTOM_HEADER_ATTR,
395 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
396     ID_CUSTOM_HEADER_HEIGHT,
397 #endif // wxHAS_GENERIC_DATAVIEWCTRL
398     ID_STYLE_MENU,
399     ID_INC_INDENT,
400     ID_DEC_INDENT,
401 
402     // file menu
403     //ID_SINGLE,        wxDV_SINGLE==0 so it's always present
404     ID_MULTIPLE,
405     ID_ROW_LINES,
406     ID_HORIZ_RULES,
407     ID_VERT_RULES,
408 
409     ID_EXIT = wxID_EXIT,
410 
411     // about menu
412     ID_ABOUT = wxID_ABOUT,
413 
414 
415     // control IDs
416 
417     ID_MUSIC_CTRL       = 50,
418     ID_ATTR_CTRL        = 51,
419 
420     ID_ADD_MOZART       = 100,
421     ID_DELETE_SEL       = 101,
422     ID_DELETE_YEAR      = 102,
423     ID_SELECT_NINTH     = 103,
424     ID_COLLAPSE         = 104,
425     ID_EXPAND           = 105,
426     ID_SHOW_CURRENT,
427     ID_SET_NINTH_CURRENT,
428     ID_CHANGE_NINTH_TITLE,
429 
430     ID_PREPEND_LIST     = 200,
431     ID_DELETE_LIST      = 201,
432     ID_GOTO             = 202,
433     ID_ADD_MANY         = 203,
434     ID_HIDE_ATTRIBUTES  = 204,
435     ID_SHOW_ATTRIBUTES  = 205,
436     ID_MULTIPLE_SORT    = 206,
437     ID_SORT_BY_FIRST_COLUMN,
438 
439     // Fourth page.
440     ID_DELETE_TREE_ITEM = 400,
441     ID_DELETE_ALL_TREE_ITEMS = 401,
442     ID_ADD_TREE_ITEM = 402,
443     ID_ADD_TREE_CONTAINER_ITEM = 403,
444 
445     // Index list model page
446     ID_INDEX_LIST_USE_ENGLISH = 500,
447     ID_INDEX_LIST_USE_FRENCH,
448     ID_INDEX_LIST_RESET_MODEL
449 };
450 
wxBEGIN_EVENT_TABLE(MyFrame,wxFrame)451 wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
452     EVT_MENU_RANGE( ID_MULTIPLE, ID_VERT_RULES, MyFrame::OnStyleChange )
453     EVT_MENU( ID_EXIT, MyFrame::OnQuit )
454     EVT_MENU( ID_ABOUT, MyFrame::OnAbout )
455     EVT_MENU( ID_CLEARLOG, MyFrame::OnClearLog )
456 
457     EVT_MENU( ID_GET_PAGE_INFO, MyFrame::OnGetPageInfo )
458     EVT_MENU( ID_DISABLE, MyFrame::OnDisable )
459     EVT_MENU( ID_FOREGROUND_COLOUR, MyFrame::OnSetForegroundColour )
460     EVT_MENU( ID_BACKGROUND_COLOUR, MyFrame::OnSetBackgroundColour )
461     EVT_MENU( ID_CUSTOM_HEADER_ATTR, MyFrame::OnCustomHeaderAttr )
462 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
463     EVT_MENU( ID_CUSTOM_HEADER_HEIGHT, MyFrame::OnCustomHeaderHeight )
464 #endif // wxHAS_GENERIC_DATAVIEWCTRL
465     EVT_MENU( ID_INC_INDENT, MyFrame::OnIncIndent )
466     EVT_MENU( ID_DEC_INDENT, MyFrame::OnDecIndent )
467 
468     EVT_NOTEBOOK_PAGE_CHANGED( wxID_ANY, MyFrame::OnPageChanged )
469 
470     EVT_BUTTON( ID_ADD_MOZART, MyFrame::OnAddMozart )
471     EVT_BUTTON( ID_DELETE_SEL, MyFrame::OnDeleteSelected )
472     EVT_BUTTON( ID_DELETE_YEAR, MyFrame::OnDeleteYear )
473     EVT_BUTTON( ID_SELECT_NINTH, MyFrame::OnSelectNinth )
474     EVT_BUTTON( ID_COLLAPSE, MyFrame::OnCollapse )
475     EVT_BUTTON( ID_EXPAND, MyFrame::OnExpand )
476     EVT_BUTTON( ID_SHOW_CURRENT, MyFrame::OnShowCurrent )
477     EVT_BUTTON( ID_SET_NINTH_CURRENT, MyFrame::OnSetNinthCurrent )
478     EVT_BUTTON( ID_CHANGE_NINTH_TITLE, MyFrame::OnChangeNinthTitle )
479 
480     EVT_BUTTON( ID_PREPEND_LIST, MyFrame::OnPrependList )
481     EVT_BUTTON( ID_DELETE_LIST, MyFrame::OnDeleteList )
482     EVT_BUTTON( ID_GOTO, MyFrame::OnGoto)
483     EVT_BUTTON( ID_ADD_MANY, MyFrame::OnAddMany)
484     EVT_BUTTON( ID_HIDE_ATTRIBUTES, MyFrame::OnHideAttributes)
485     EVT_BUTTON( ID_SHOW_ATTRIBUTES, MyFrame::OnShowAttributes)
486     EVT_CHECKBOX( ID_MULTIPLE_SORT, MyFrame::OnMultipleSort)
487     EVT_CHECKBOX( ID_SORT_BY_FIRST_COLUMN, MyFrame::OnSortByFirstColumn)
488 
489     // Fourth page.
490     EVT_BUTTON( ID_DELETE_TREE_ITEM, MyFrame::OnDeleteTreeItem )
491     EVT_BUTTON( ID_DELETE_ALL_TREE_ITEMS, MyFrame::OnDeleteAllTreeItems )
492     EVT_BUTTON( ID_ADD_TREE_ITEM, MyFrame::OnAddTreeItem )
493     EVT_BUTTON( ID_ADD_TREE_CONTAINER_ITEM, MyFrame::OnAddTreeContainerItem )
494 
495     EVT_BUTTON( ID_INDEX_LIST_USE_ENGLISH, MyFrame::OnIndexListUseEnglish )
496     EVT_BUTTON( ID_INDEX_LIST_USE_FRENCH, MyFrame::OnIndexListUseFrench )
497     EVT_BUTTON( ID_INDEX_LIST_RESET_MODEL, MyFrame::OnIndexListResetModel )
498 
499     EVT_DATAVIEW_ITEM_VALUE_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged )
500 
501     EVT_DATAVIEW_ITEM_ACTIVATED(ID_MUSIC_CTRL, MyFrame::OnActivated )
502     EVT_DATAVIEW_ITEM_EXPANDING(ID_MUSIC_CTRL, MyFrame::OnExpanding)
503     EVT_DATAVIEW_ITEM_EXPANDED(ID_MUSIC_CTRL, MyFrame::OnExpanded)
504     EVT_DATAVIEW_ITEM_COLLAPSING(ID_MUSIC_CTRL, MyFrame::OnCollapsing)
505     EVT_DATAVIEW_ITEM_COLLAPSED(ID_MUSIC_CTRL, MyFrame::OnCollapsed)
506     EVT_DATAVIEW_SELECTION_CHANGED(ID_MUSIC_CTRL, MyFrame::OnSelectionChanged)
507 
508     EVT_DATAVIEW_ITEM_START_EDITING(ID_MUSIC_CTRL, MyFrame::OnStartEditing)
509     EVT_DATAVIEW_ITEM_EDITING_STARTED(wxID_ANY, MyFrame::OnEditingStarted)
510     EVT_DATAVIEW_ITEM_EDITING_DONE(wxID_ANY, MyFrame::OnEditingDone)
511 
512     EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderClick)
513     EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderRightClick)
514     EVT_DATAVIEW_COLUMN_SORTED(ID_MUSIC_CTRL, MyFrame::OnSorted)
515     EVT_DATAVIEW_COLUMN_SORTED(ID_ATTR_CTRL, MyFrame::OnSortedList)
516     EVT_DATAVIEW_COLUMN_REORDERED(wxID_ANY, MyFrame::OnColumnReordered)
517     EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_ATTR_CTRL, MyFrame::OnHeaderClickList)
518 
519     EVT_DATAVIEW_ITEM_CONTEXT_MENU(ID_MUSIC_CTRL, MyFrame::OnContextMenu)
520 
521 #if wxUSE_DRAG_AND_DROP
522     EVT_DATAVIEW_ITEM_BEGIN_DRAG( ID_MUSIC_CTRL, MyFrame::OnBeginDrag )
523     EVT_DATAVIEW_ITEM_DROP_POSSIBLE( ID_MUSIC_CTRL, MyFrame::OnDropPossible )
524     EVT_DATAVIEW_ITEM_DROP( ID_MUSIC_CTRL, MyFrame::OnDrop )
525 #endif // wxUSE_DRAG_AND_DROP
526 
527     EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_ATTR_CTRL, MyFrame::OnAttrHeaderClick)
528 
529 wxEND_EVENT_TABLE()
530 
531 MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int h):
532   wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
533 {
534     m_log = NULL;
535     m_col = NULL;
536 
537     for ( int page = 0; page < Page_Max; ++page )
538         m_ctrl[page] = NULL;
539 
540     m_eventFromProgram = false;
541 
542     SetIcon(wxICON(sample));
543 
544 
545     // build the menus
546     // ----------------
547 
548     wxMenu *style_menu = new wxMenu;
549     //style_menu->AppendCheckItem(ID_SINGLE, "Single selection"));
550     style_menu->AppendCheckItem(ID_MULTIPLE, "Multiple selection");
551     style_menu->AppendCheckItem(ID_ROW_LINES, "Alternating colours");
552     style_menu->AppendCheckItem(ID_HORIZ_RULES, "Display horizontal rules");
553     style_menu->AppendCheckItem(ID_VERT_RULES, "Display vertical rules");
554 
555     wxMenu *file_menu = new wxMenu;
556     file_menu->Append(ID_CLEARLOG, "&Clear log\tCtrl-L");
557     file_menu->Append(ID_GET_PAGE_INFO, "Show current &page info");
558     file_menu->AppendCheckItem(ID_DISABLE, "&Disable\tCtrl-D");
559     file_menu->Append(ID_FOREGROUND_COLOUR, "Set &foreground colour...\tCtrl-S");
560     file_menu->Append(ID_BACKGROUND_COLOUR, "Set &background colour...\tCtrl-B");
561     file_menu->AppendCheckItem(ID_CUSTOM_HEADER_ATTR, "C&ustom header attributes");
562 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
563     file_menu->AppendCheckItem(ID_CUSTOM_HEADER_HEIGHT, "Custom header &height");
564 #endif // wxHAS_GENERIC_DATAVIEWCTRL
565     file_menu->Append(ID_STYLE_MENU, "&Style", style_menu);
566     file_menu->Append(ID_INC_INDENT, "&Increase indent\tCtrl-I");
567     file_menu->Append(ID_DEC_INDENT, "&Decrease indent\tShift-Ctrl-I");
568     file_menu->AppendSeparator();
569     file_menu->Append(ID_EXIT, "E&xit");
570 
571     wxMenu *about_menu = new wxMenu;
572     about_menu->Append(ID_ABOUT, "&About");
573 
574     wxMenuBar *menu_bar = new wxMenuBar;
575     menu_bar->Append(file_menu, "&File");
576     menu_bar->Append(about_menu, "&About");
577 
578     SetMenuBar(menu_bar);
579     CreateStatusBar();
580 
581 
582     // redirect logs from our event handlers to text control
583     m_log = new wxTextCtrl( this, wxID_ANY, wxString(), wxDefaultPosition,
584                             wxDefaultSize, wxTE_MULTILINE );
585     m_log->SetMinSize(wxSize(-1, 100));
586     m_logOld = wxLog::SetActiveTarget(new wxLogTextCtrl(m_log));
587     wxLogMessage( "This is the log window" );
588 
589 
590     // first page of the notebook
591     // --------------------------
592 
593     m_notebook = new wxNotebook( this, wxID_ANY );
594 
595     wxPanel *firstPanel = new wxPanel( m_notebook, wxID_ANY );
596 
597     BuildDataViewCtrl(firstPanel, Page_Music);
598 
599     const wxSizerFlags border = wxSizerFlags().DoubleBorder();
600 
601     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
602     button_sizer->Add( new wxButton( firstPanel, ID_ADD_MOZART,  "Add Mozart"),             border );
603     button_sizer->Add( new wxButton( firstPanel, ID_DELETE_SEL,  "Delete selected"),        border );
604     button_sizer->Add( new wxButton( firstPanel, ID_DELETE_YEAR, "Delete \"Year\" column"), border );
605     button_sizer->Add( new wxButton( firstPanel, ID_SELECT_NINTH,"Select ninth symphony"),  border );
606     button_sizer->Add( new wxButton( firstPanel, ID_COLLAPSE,    "Collapse"),               border );
607     button_sizer->Add( new wxButton( firstPanel, ID_EXPAND,      "Expand"),                 border );
608 
609     wxBoxSizer *sizerCurrent = new wxBoxSizer(wxHORIZONTAL);
610     sizerCurrent->Add(new wxButton(firstPanel, ID_SHOW_CURRENT,
611                                    "&Show current"), border);
612     sizerCurrent->Add(new wxButton(firstPanel, ID_SET_NINTH_CURRENT,
613                                    "Make &ninth symphony current"), border);
614     sizerCurrent->Add(new wxButton(firstPanel, ID_CHANGE_NINTH_TITLE,
615                                    "Change ninth &title"), border);
616 
617     wxSizer *firstPanelSz = new wxBoxSizer( wxVERTICAL );
618     m_ctrl[Page_Music]->SetMinSize(wxSize(-1, 200));
619     firstPanelSz->Add(m_ctrl[Page_Music], 1, wxGROW|wxALL, 5);
620     firstPanelSz->Add(
621         new wxStaticText(firstPanel, wxID_ANY, "Most of the cells above are editable!"),
622         0, wxGROW|wxALL, 5);
623     firstPanelSz->Add(button_sizer);
624     firstPanelSz->Add(sizerCurrent);
625     firstPanel->SetSizerAndFit(firstPanelSz);
626 
627 
628     // second page of the notebook
629     // ---------------------------
630 
631     wxPanel *secondPanel = new wxPanel( m_notebook, wxID_ANY );
632 
633     BuildDataViewCtrl(secondPanel, Page_List);
634 
635     wxBoxSizer *button_sizer2 = new wxBoxSizer( wxHORIZONTAL );
636     button_sizer2->Add( new wxButton( secondPanel, ID_PREPEND_LIST,"Prepend"),                0, wxALL, 10 );
637     button_sizer2->Add( new wxButton( secondPanel, ID_DELETE_LIST, "Delete selected"),        0, wxALL, 10 );
638     button_sizer2->Add( new wxButton( secondPanel, ID_GOTO,        "Goto 50"),                0, wxALL, 10 );
639     button_sizer2->Add( new wxButton( secondPanel, ID_ADD_MANY,    "Add 1000"),               0, wxALL, 10 );
640     button_sizer2->Add( new wxButton( secondPanel, ID_HIDE_ATTRIBUTES,    "Hide attributes"), 0, wxALL, 10 );
641     button_sizer2->Add( new wxButton( secondPanel, ID_SHOW_ATTRIBUTES,    "Show attributes"), 0, wxALL, 10 );
642 
643     wxBoxSizer *sortSizer = new wxBoxSizer(wxHORIZONTAL);
644     sortSizer->Add(new wxCheckBox(secondPanel, ID_SORT_BY_FIRST_COLUMN, "Sort by first column"),
645                    wxSizerFlags().Centre().DoubleBorder());
646     sortSizer->Add(new wxCheckBox(secondPanel, ID_MULTIPLE_SORT, "Allow multisort"),
647                    wxSizerFlags().Centre().DoubleBorder());
648 
649     wxSizer *secondPanelSz = new wxBoxSizer( wxVERTICAL );
650     secondPanelSz->Add(m_ctrl[Page_List], 1, wxGROW|wxALL, 5);
651     secondPanelSz->Add(button_sizer2);
652     secondPanelSz->Add(sortSizer);
653     secondPanel->SetSizerAndFit(secondPanelSz);
654 
655 
656     // third page of the notebook
657     // ---------------------------
658 
659     wxPanel *thirdPanel = new wxPanel( m_notebook, wxID_ANY );
660 
661     BuildDataViewCtrl(thirdPanel, Page_ListStore);
662 
663     wxSizer *thirdPanelSz = new wxBoxSizer( wxVERTICAL );
664     thirdPanelSz->Add(m_ctrl[Page_ListStore], 1, wxGROW|wxALL, 5);
665     thirdPanel->SetSizerAndFit(thirdPanelSz);
666 
667 
668     // fourth page of the notebook
669     // ---------------------------
670 
671     wxPanel *fourthPanel = new wxPanel( m_notebook, wxID_ANY );
672 
673     BuildDataViewCtrl(fourthPanel, Page_TreeStore);
674     // Buttons
675     wxBoxSizer *button_sizer4 = new wxBoxSizer( wxHORIZONTAL );
676     button_sizer4->Add( new wxButton( fourthPanel, ID_DELETE_TREE_ITEM, "Delete Selected"), 0, wxALL, 10 );
677     button_sizer4->Add( new wxButton( fourthPanel, ID_DELETE_ALL_TREE_ITEMS, "Delete All"), 0, wxALL, 10 );
678     button_sizer4->Add( new wxButton( fourthPanel, ID_ADD_TREE_ITEM, "Add Item"), 0, wxALL, 10 );
679     button_sizer4->Add( new wxButton( fourthPanel, ID_ADD_TREE_CONTAINER_ITEM, "Add Container"), 0, wxALL, 10 );
680 
681     wxSizer *fourthPanelSz = new wxBoxSizer( wxVERTICAL );
682     fourthPanelSz->Add(m_ctrl[Page_TreeStore], 1, wxGROW|wxALL, 5);
683     fourthPanelSz->Add(button_sizer4);
684     fourthPanel->SetSizerAndFit(fourthPanelSz);
685 
686     // fifth page of the notebook
687     // ---------------------------
688 
689     wxPanel *fifthPanel = new wxPanel(m_notebook, wxID_ANY);
690 
691     BuildDataViewCtrl(fifthPanel, Page_VarHeight);
692 
693     wxSizer *fifthPanelSz = new wxBoxSizer(wxVERTICAL);
694     fifthPanelSz->Add(m_ctrl[Page_VarHeight], 1, wxGROW | wxALL, 5);
695     fifthPanel->SetSizerAndFit(fifthPanelSz);
696 
697     // page showing the indexed list model
698     // -----------------------------------
699 
700     wxPanel* sixthPanel = new wxPanel(m_notebook, wxID_ANY);
701 
702     BuildDataViewCtrl(sixthPanel, Page_IndexList);
703 
704     wxBoxSizer *button_sizer6 = new wxBoxSizer(wxHORIZONTAL);
705     button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_USE_ENGLISH, "&English"),
706                        wxSizerFlags().DoubleBorder());
707     button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_USE_FRENCH, "&French"),
708                        wxSizerFlags().DoubleBorder());
709     button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_RESET_MODEL, "Reset &model"),
710                        wxSizerFlags().DoubleBorder());
711 
712     wxSizer *sixthPanelSz = new wxBoxSizer(wxVERTICAL);
713     sixthPanelSz->Add(m_ctrl[Page_IndexList], wxSizerFlags(1).Expand().Border());
714     sixthPanelSz->Add(button_sizer6);
715     sixthPanel->SetSizerAndFit(sixthPanelSz);
716 
717     // page showing that some columns don't have values for some items
718     // ---------------------------------------------------------------
719 
720     wxPanel *seventhPanel = new wxPanel( m_notebook, wxID_ANY );
721 
722     BuildDataViewCtrl(seventhPanel, Page_HasValue);
723 
724     wxSizer *seventhPanelSz = new wxBoxSizer( wxVERTICAL );
725     seventhPanelSz->Add(m_ctrl[Page_HasValue], 1, wxGROW|wxALL, 5);
726     seventhPanel->SetSizerAndFit(seventhPanelSz);
727 
728     // complete GUI
729     // ------------
730 
731     m_notebook->AddPage(firstPanel, "MyMusicTreeModel");
732     m_notebook->AddPage(secondPanel, "MyListModel");
733     m_notebook->AddPage(thirdPanel, "wxDataViewListCtrl");
734     m_notebook->AddPage(fourthPanel, "wxDataViewTreeCtrl");
735     m_notebook->AddPage(fifthPanel, "Variable line height");
736     m_notebook->AddPage(sixthPanel, "MyIndexListModel");
737     m_notebook->AddPage(seventhPanel, "MyDataViewHasValue");
738 
739     wxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
740 
741     mainSizer->Add( m_notebook, 1, wxGROW );
742     mainSizer->Add( m_log, 0, wxGROW );
743 
744     SetSizerAndFit(mainSizer);
745 
746     // Allow using the control from keyboard on startup.
747     m_ctrl[Page_Music]->SetFocus();
748 }
749 
~MyFrame()750 MyFrame::~MyFrame()
751 {
752     delete wxLog::SetActiveTarget(m_logOld);
753 }
754 
BuildDataViewCtrl(wxPanel * parent,unsigned int nPanel,unsigned long style)755 void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned long style)
756 {
757     wxASSERT(!m_ctrl[nPanel]); // should only be initialized once
758 
759     switch (nPanel)
760     {
761     case Page_Music:
762         {
763             m_ctrl[Page_Music] =
764                 new wxDataViewCtrl( parent, ID_MUSIC_CTRL, wxDefaultPosition,
765                                     wxDefaultSize, style );
766             m_ctrl[Page_Music]->Bind(wxEVT_CHAR, &MyFrame::OnDataViewChar, this);
767 
768             m_music_model = new MyMusicTreeModel;
769             m_ctrl[Page_Music]->AssociateModel( m_music_model.get() );
770 
771 #if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
772             m_ctrl[Page_Music]->EnableDragSource( wxDF_UNICODETEXT );
773             m_ctrl[Page_Music]->EnableDropTarget( wxDF_UNICODETEXT );
774 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
775 
776             // column 0 of the view control:
777 
778             wxDataViewTextRenderer *tr =
779                 new wxDataViewTextRenderer( "string", wxDATAVIEW_CELL_INERT );
780             wxDataViewColumn *column0 =
781                 new wxDataViewColumn( "title", tr, 0, FromDIP(200), wxALIGN_LEFT,
782                                       wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE );
783             m_ctrl[Page_Music]->AppendColumn( column0 );
784 #if 0
785             // Call this and sorting is enabled
786             // immediately upon start up.
787             column0->SetAsSortKey();
788 #endif
789 
790             // column 1 of the view control:
791 
792             tr = new wxDataViewTextRenderer( "string", wxDATAVIEW_CELL_EDITABLE );
793             wxDataViewColumn *column1 =
794                 new wxDataViewColumn( "artist", tr, 1, FromDIP(150), wxALIGN_LEFT,
795                                       wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE |
796                                       wxDATAVIEW_COL_RESIZABLE );
797             column1->SetMinWidth(FromDIP(150)); // this column can't be resized to be smaller
798             m_ctrl[Page_Music]->AppendColumn( column1 );
799 
800             // column 2 of the view control:
801 
802             wxDataViewSpinRenderer *sr =
803                 new wxDataViewSpinRenderer( 0, 2010, wxDATAVIEW_CELL_EDITABLE,
804                                             wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL);
805             wxDataViewColumn *column2 =
806                 new wxDataViewColumn( "year", sr, 2, FromDIP(60), wxALIGN_LEFT,
807                                       wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE );
808             m_ctrl[Page_Music]->AppendColumn( column2 );
809 
810             // column 3 of the view control:
811 
812             wxArrayString choices;
813             choices.Add( "good" );
814             choices.Add( "bad" );
815             choices.Add( "lousy" );
816             wxDataViewChoiceRenderer *c =
817                 new wxDataViewChoiceRenderer( choices, wxDATAVIEW_CELL_EDITABLE,
818                                               wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL);
819             wxDataViewColumn *column3 =
820                 new wxDataViewColumn( "rating", c, 3, FromDIP(100), wxALIGN_LEFT,
821                                       wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE );
822             m_ctrl[Page_Music]->AppendColumn( column3 );
823 
824             // column 4 of the view control:
825 
826             m_ctrl[Page_Music]->AppendProgressColumn( "popularity", 4, wxDATAVIEW_CELL_INERT, FromDIP(80) );
827 
828             // column 5 of the view control:
829 
830             MyCustomRenderer *cr = new MyCustomRenderer(wxDATAVIEW_CELL_ACTIVATABLE);
831             wxDataViewColumn *column5 =
832                 new wxDataViewColumn( "custom", cr, 5, wxCOL_WIDTH_DEFAULT, wxALIGN_LEFT,
833                                       wxDATAVIEW_COL_RESIZABLE );
834             column5->SetBitmap(wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MENU));
835             m_ctrl[Page_Music]->AppendColumn( column5 );
836 
837 
838             // select initially the ninth symphony:
839             m_ctrl[Page_Music]->Select(m_music_model->GetNinthItem());
840         }
841         break;
842 
843     case Page_List:
844         {
845             m_ctrl[Page_List] = new wxDataViewCtrl( parent, ID_ATTR_CTRL, wxDefaultPosition,
846                                             wxDefaultSize, style );
847 
848             m_list_model = new MyListModel;
849             m_ctrl[Page_List]->AssociateModel( m_list_model.get() );
850 
851             wxDataViewColumn* const colCheckIconText = new wxDataViewColumn
852                 (
853                      L"\u2714 + icon + text",
854                      new wxDataViewCheckIconTextRenderer(),
855                      MyListModel::Col_ToggleIconText,
856                      wxCOL_WIDTH_AUTOSIZE
857                 );
858             m_ctrl[Page_List]->AppendColumn(colCheckIconText);
859 
860             m_ctrl[Page_List]->AppendTextColumn("editable string",
861                                         MyListModel::Col_EditableText,
862                                         wxDATAVIEW_CELL_EDITABLE,
863                                         wxCOL_WIDTH_AUTOSIZE,
864                                         wxALIGN_NOT,
865                                         wxDATAVIEW_COL_SORTABLE);
866 
867             m_ctrl[Page_List]->AppendDateColumn("date",
868                                         MyListModel::Col_Date);
869 
870             wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer();
871 #if wxUSE_MARKUP
872             markupRenderer->EnableMarkup();
873 #endif // wxUSE_MARKUP
874             m_attributes =
875                 new wxDataViewColumn("attributes",
876                                      markupRenderer,
877                                      MyListModel::Col_TextWithAttr,
878                                      wxCOL_WIDTH_AUTOSIZE,
879                                      wxALIGN_RIGHT,
880                                      wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
881             m_ctrl[Page_List]->AppendColumn( m_attributes );
882 
883             m_ctrl[Page_List]->AppendColumn(
884                 new wxDataViewColumn("custom renderer",
885                                      new MyCustomRenderer(wxDATAVIEW_CELL_EDITABLE),
886                                      MyListModel::Col_Custom)
887             );
888         }
889         break;
890 
891     case Page_ListStore:
892         {
893             wxDataViewListCtrl* lc =
894                 new wxDataViewListCtrl( parent, wxID_ANY, wxDefaultPosition,
895                                         wxDefaultSize, style );
896             m_ctrl[Page_ListStore] = lc;
897 
898             MyListStoreDerivedModel* page2_model = new MyListStoreDerivedModel();
899             lc->AssociateModel(page2_model);
900             page2_model->DecRef();
901 
902             lc->AppendToggleColumn( "Toggle" );
903 
904             // We're not limited to convenience column-appending functions, it
905             // can also be done fully manually, which allows us to customize
906             // the renderer being used.
907             wxDataViewToggleRenderer* const rendererRadio =
908                 new wxDataViewToggleRenderer("bool", wxDATAVIEW_CELL_ACTIVATABLE);
909             rendererRadio->ShowAsRadio();
910             wxDataViewColumn* const colRadio =
911                 new wxDataViewColumn("Radio", rendererRadio, 1);
912             lc->AppendColumn(colRadio, "bool");
913 
914             lc->AppendTextColumn( "Text" );
915             lc->AppendProgressColumn( "Progress" )->SetMinWidth(FromDIP(100));
916 
917             wxVector<wxVariant> data;
918             for (unsigned int i=0; i<10; i++)
919             {
920                 data.clear();
921                 data.push_back( (i%3) == 0 );
922                 data.push_back( i == 7 ); // select a single (random) radio item
923                 data.push_back( wxString::Format("row %d", i) );
924                 data.push_back( long(5*i) );
925 
926                 lc->AppendItem( data );
927             }
928 
929             lc->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &MyFrame::OnListValueChanged, this);
930         }
931         break;
932 
933     case Page_TreeStore:
934         {
935             wxDataViewTreeCtrl* tc =
936                 new wxDataViewTreeCtrl( parent, wxID_ANY, wxDefaultPosition,
937                                         wxDefaultSize, style | wxDV_NO_HEADER );
938             m_ctrl[Page_TreeStore] = tc;
939 
940             wxImageList *ilist = new wxImageList( 16, 16 );
941             ilist->Add( wxIcon(wx_small_xpm) );
942             tc->AssignImageList( ilist );
943 
944             const wxDataViewItem root =
945                 tc->AppendContainer( wxDataViewItem(0), "The Root", 0 );
946             tc->AppendItem( root, "Child 1", 0 );
947             tc->AppendItem( root, "Child 2", 0 );
948             tc->AppendItem( root, "Child 3, very long, long, long, long", 0 );
949 
950             wxDataViewItem cont =
951                 tc->AppendContainer( root, "Container child", 0 );
952             tc->AppendItem( cont, "Child 4", 0 );
953             tc->AppendItem( cont, "Child 5", 0 );
954 
955             tc->Expand(cont);
956         }
957         break;
958 
959     case Page_VarHeight:
960         {
961             m_ctrl[Page_VarHeight] =
962                 new wxDataViewCtrl( parent, wxID_ANY, wxDefaultPosition,
963                                     wxDefaultSize, style | wxDV_VARIABLE_LINE_HEIGHT );
964 
965             m_long_music_model = new MyLongMusicTreeModel;
966             m_ctrl[Page_VarHeight]->AssociateModel(m_long_music_model.get());
967 
968             // column 0 of the view control:
969             MultiLineCustomRenderer *tr =
970                 new MultiLineCustomRenderer();
971             wxDataViewColumn *column0 =
972                 new wxDataViewColumn("title", tr, 0, FromDIP(200), wxALIGN_LEFT,
973                     wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE);
974             m_ctrl[Page_VarHeight]->AppendColumn(column0);
975 
976             // column 1 of the view control:
977             tr = new MultiLineCustomRenderer();
978             wxDataViewColumn *column1 =
979                 new wxDataViewColumn("artist", tr, 1, FromDIP(150), wxALIGN_LEFT,
980                     wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE |
981                     wxDATAVIEW_COL_RESIZABLE);
982             column1->SetMinWidth(FromDIP(150)); // this column can't be resized to be smaller
983             m_ctrl[Page_VarHeight]->AppendColumn(column1);
984         }
985         break;
986 
987     case Page_IndexList:
988         {
989             m_ctrl[Page_IndexList] = new wxDataViewCtrl(parent, wxID_ANY,
990                                                         wxDefaultPosition,
991                                                         wxDefaultSize,
992                                                         style);
993 
994             m_index_list_model = new MyIndexListModel;
995             m_ctrl[Page_IndexList]->AssociateModel(m_index_list_model.get());
996             m_ctrl[Page_IndexList]->AppendTextColumn("String", 0);
997 
998             FillIndexList(Lang_English);
999 
1000             m_ctrl[Page_IndexList]->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED,
1001                                          &MyFrame::OnIndexListSelectionChanged,
1002                                          this);
1003         }
1004         break;
1005 
1006     case Page_HasValue:
1007         {
1008             wxDataViewListCtrl* lc =
1009                 new wxDataViewListCtrl( parent, wxID_ANY, wxDefaultPosition,
1010                                         wxDefaultSize, style );
1011             m_ctrl[Page_HasValue] = lc;
1012 
1013             MyListStoreDerivedModel* page7_model = new MyListStoreHasValueModel();
1014             lc->AssociateModel(page7_model);
1015             page7_model->DecRef();
1016 
1017             lc->AppendToggleColumn( "Toggle" );
1018 
1019             // We're not limited to convenience column-appending functions, it
1020             // can also be done fully manually, which allows us to customize
1021             // the renderer being used.
1022             wxDataViewToggleRenderer* const rendererRadio =
1023                 new wxDataViewToggleRenderer("bool", wxDATAVIEW_CELL_ACTIVATABLE);
1024             rendererRadio->ShowAsRadio();
1025             wxDataViewColumn* const colRadio =
1026                 new wxDataViewColumn("Radio", rendererRadio, 1);
1027             lc->AppendColumn(colRadio, "bool");
1028 
1029             lc->AppendTextColumn( "Text" );
1030             lc->AppendProgressColumn( "Progress" )->SetMinWidth(FromDIP(100));
1031 
1032             wxVector<wxVariant> data;
1033             for (unsigned int i=0; i<10; i++)
1034             {
1035                 data.clear();
1036                 data.push_back( (i%3) == 0 );
1037                 data.push_back( i == 7 ); // select a single (random) radio item
1038                 data.push_back( wxString::Format("row %d", i) );
1039                 data.push_back( long(5*i) );
1040 
1041                 lc->AppendItem( data );
1042             }
1043 
1044             lc->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &MyFrame::OnHasValueValueChanged, this);
1045         }
1046         break;
1047     }
1048 
1049 }
1050 
1051 
1052 // ----------------------------------------------------------------------------
1053 // MyFrame - generic event handlers
1054 // ----------------------------------------------------------------------------
1055 
OnClearLog(wxCommandEvent & WXUNUSED (event))1056 void MyFrame::OnClearLog( wxCommandEvent& WXUNUSED(event) )
1057 {
1058     m_log->Clear();
1059 }
1060 
OnGetPageInfo(wxCommandEvent & WXUNUSED (event))1061 void MyFrame::OnGetPageInfo(wxCommandEvent& WXUNUSED(event))
1062 {
1063     wxDataViewCtrl* const dvc = m_ctrl[m_notebook->GetSelection()];
1064 
1065     const wxDataViewItem top = dvc->GetTopItem();
1066     wxString topDesc;
1067     if ( top.IsOk() )
1068     {
1069         wxVariant value;
1070         dvc->GetModel()->GetValue(value, top, 0);
1071         topDesc.Printf("Top item is \"%s\"", value.GetString());
1072     }
1073     else
1074     {
1075         topDesc = "There is no top item";
1076     }
1077 
1078     wxLogMessage("%s and there are %d items per page",
1079                  topDesc,
1080                  dvc->GetCountPerPage());
1081 }
1082 
OnDisable(wxCommandEvent & event)1083 void MyFrame::OnDisable(wxCommandEvent& event)
1084 {
1085     m_ctrl[m_notebook->GetSelection()]->Enable(!event.IsChecked());
1086 }
1087 
OnSetForegroundColour(wxCommandEvent & WXUNUSED (event))1088 void MyFrame::OnSetForegroundColour(wxCommandEvent& WXUNUSED(event))
1089 {
1090     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1091     wxColour col = wxGetColourFromUser(this, dvc->GetForegroundColour());
1092     if ( col.IsOk() )
1093     {
1094         dvc->SetForegroundColour(col);
1095         Refresh();
1096     }
1097 }
1098 
OnSetBackgroundColour(wxCommandEvent & WXUNUSED (event))1099 void MyFrame::OnSetBackgroundColour(wxCommandEvent& WXUNUSED(event))
1100 {
1101     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1102     wxColour col = wxGetColourFromUser(this, dvc->GetBackgroundColour());
1103     if ( col.IsOk() )
1104     {
1105         dvc->SetBackgroundColour(col);
1106         Refresh();
1107     }
1108 }
1109 
OnCustomHeaderAttr(wxCommandEvent & event)1110 void MyFrame::OnCustomHeaderAttr(wxCommandEvent& event)
1111 {
1112     wxItemAttr attr;
1113     if ( event.IsChecked() )
1114     {
1115         attr.SetTextColour(*wxRED);
1116         attr.SetFont(wxFontInfo(20).Bold());
1117     }
1118     //else: leave it as default to disable custom header attributes
1119 
1120     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1121     if ( !dvc->SetHeaderAttr(attr) )
1122         wxLogMessage("Sorry, header attributes not supported on this platform");
1123 }
1124 
1125 #ifdef wxHAS_GENERIC_DATAVIEWCTRL
OnCustomHeaderHeight(wxCommandEvent & event)1126 void MyFrame::OnCustomHeaderHeight(wxCommandEvent& event)
1127 {
1128     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1129     wxHeaderCtrl* const header = dvc->GenericGetHeader();
1130     if ( !header )
1131     {
1132         wxLogMessage("No header");
1133         return;
1134     }
1135 
1136     // Use a big height to show that this works.
1137     wxSize size = event.IsChecked() ? FromDIP(wxSize(0, 80)) : wxDefaultSize;
1138     header->SetMinSize(size);
1139     header->Refresh();
1140 
1141     dvc->Layout();
1142 }
1143 #endif // wxHAS_GENERIC_DATAVIEWCTRL
1144 
OnIncIndent(wxCommandEvent & WXUNUSED (event))1145 void MyFrame::OnIncIndent(wxCommandEvent& WXUNUSED(event))
1146 {
1147     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1148     dvc->SetIndent(dvc->GetIndent() + 5);
1149     wxLogMessage("Indent is now %d", dvc->GetIndent());
1150 }
1151 
OnDecIndent(wxCommandEvent & WXUNUSED (event))1152 void MyFrame::OnDecIndent(wxCommandEvent& WXUNUSED(event))
1153 {
1154     wxDataViewCtrl * const dvc = m_ctrl[m_notebook->GetSelection()];
1155     dvc->SetIndent(wxMax(dvc->GetIndent() - 5, 0));
1156     wxLogMessage("Indent is now %d", dvc->GetIndent());
1157 }
1158 
OnPageChanged(wxBookCtrlEvent & WXUNUSED (event))1159 void MyFrame::OnPageChanged( wxBookCtrlEvent& WXUNUSED(event) )
1160 {
1161     unsigned int nPanel = m_notebook->GetSelection();
1162 
1163     GetMenuBar()->FindItem(ID_STYLE_MENU)->SetItemLabel(
1164                 wxString::Format("Style of panel #%d", nPanel+1));
1165 
1166     for (unsigned int id = ID_MULTIPLE; id <= ID_VERT_RULES; id++)
1167     {
1168         unsigned long style = 0;
1169         switch (id)
1170         {
1171         /*case ID_SINGLE:
1172             style = wxDV_SINGLE;
1173             break;*/
1174         case ID_MULTIPLE:
1175             style = wxDV_MULTIPLE;
1176             break;
1177         case ID_ROW_LINES:
1178             style = wxDV_ROW_LINES;
1179             break;
1180         case ID_HORIZ_RULES:
1181             style = wxDV_HORIZ_RULES;
1182             break;
1183         case ID_VERT_RULES:
1184             style = wxDV_VERT_RULES;
1185             break;
1186         default:
1187             wxFAIL;
1188         }
1189 
1190         GetMenuBar()->FindItem(id)->Check( m_ctrl[nPanel]->HasFlag(style) );
1191     }
1192 
1193     GetMenuBar()->FindItem(ID_DISABLE)->Check(!m_ctrl[nPanel]->IsEnabled());
1194 }
1195 
OnStyleChange(wxCommandEvent & WXUNUSED (event))1196 void MyFrame::OnStyleChange( wxCommandEvent& WXUNUSED(event) )
1197 {
1198     unsigned int nPanel = m_notebook->GetSelection();
1199 
1200     // build the style
1201     unsigned long style = 0;
1202     /*if (GetMenuBar()->FindItem(ID_SINGLE)->IsChecked())
1203         style |= wxDV_SINGLE;*/
1204     if (GetMenuBar()->FindItem(ID_MULTIPLE)->IsChecked())
1205         style |= wxDV_MULTIPLE;
1206     if (GetMenuBar()->FindItem(ID_ROW_LINES)->IsChecked())
1207         style |= wxDV_ROW_LINES;
1208     if (GetMenuBar()->FindItem(ID_HORIZ_RULES)->IsChecked())
1209         style |= wxDV_HORIZ_RULES;
1210     if (GetMenuBar()->FindItem(ID_VERT_RULES)->IsChecked())
1211         style |= wxDV_VERT_RULES;
1212 
1213     wxSizer* sz = m_ctrl[nPanel]->GetContainingSizer();
1214     wxASSERT(sz);
1215 
1216     sz->Detach(m_ctrl[nPanel]);
1217     wxDELETE(m_ctrl[nPanel]);
1218     m_ctrl[nPanel] = NULL;
1219 
1220     if (nPanel == 0)
1221         m_music_model.reset(NULL);
1222     else if (nPanel == 1)
1223         m_list_model.reset(NULL);
1224     else if (nPanel == 4)
1225         m_long_music_model.reset(NULL);
1226 
1227     // rebuild the DVC for the selected panel:
1228     BuildDataViewCtrl((wxPanel*)m_notebook->GetPage(nPanel), nPanel, style);
1229 
1230     sz->Prepend(m_ctrl[nPanel], 1, wxGROW|wxALL, 5);
1231     sz->Layout();
1232 }
1233 
OnQuit(wxCommandEvent & WXUNUSED (event))1234 void MyFrame::OnQuit( wxCommandEvent& WXUNUSED(event) )
1235 {
1236     Close(true);
1237 }
1238 
OnAbout(wxCommandEvent & WXUNUSED (event))1239 void MyFrame::OnAbout( wxCommandEvent& WXUNUSED(event) )
1240 {
1241     wxAboutDialogInfo info;
1242     info.SetName(_("DataView sample"));
1243     info.SetDescription(_("This sample demonstrates wxDataViewCtrl"));
1244     info.SetCopyright("(C) 2007-2009 Robert Roebling");
1245     info.AddDeveloper("Robert Roebling");
1246     info.AddDeveloper("Francesco Montorsi");
1247 
1248     wxAboutBox(info, this);
1249 }
1250 
1251 
1252 // ----------------------------------------------------------------------------
1253 // MyFrame - event handlers for the first page
1254 // ----------------------------------------------------------------------------
1255 
1256 #if wxUSE_DRAG_AND_DROP
1257 
OnBeginDrag(wxDataViewEvent & event)1258 void MyFrame::OnBeginDrag( wxDataViewEvent &event )
1259 {
1260     wxDataViewItem item( event.GetItem() );
1261 
1262     // only allow drags for item, not containers
1263     if (m_music_model->IsContainer( item ) )
1264     {
1265         wxLogMessage("Forbidding starting dragging");
1266         event.Veto();
1267         return;
1268     }
1269 
1270     MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
1271     wxTextDataObject *obj = new wxTextDataObject;
1272     obj->SetText( node->m_title );
1273     event.SetDataObject( obj );
1274     event.SetDragFlags(wxDrag_AllowMove); // allows both copy and move
1275 
1276     wxLogMessage("Starting dragging \"%s\"", node->m_title);
1277 }
1278 
OnDropPossible(wxDataViewEvent & event)1279 void MyFrame::OnDropPossible( wxDataViewEvent &event )
1280 {
1281     if (event.GetDataFormat() != wxDF_UNICODETEXT)
1282         event.Veto();
1283     else
1284         event.SetDropEffect(wxDragMove); // check 'move' drop effect
1285 }
1286 
OnDrop(wxDataViewEvent & event)1287 void MyFrame::OnDrop( wxDataViewEvent &event )
1288 {
1289     wxDataViewItem item( event.GetItem() );
1290 
1291     if (event.GetDataFormat() != wxDF_UNICODETEXT)
1292     {
1293         event.Veto();
1294         return;
1295     }
1296 
1297     wxTextDataObject obj;
1298     obj.SetData( wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer() );
1299 
1300     if ( item.IsOk() )
1301     {
1302         if (m_music_model->IsContainer(item))
1303         {
1304             wxLogMessage("Text '%s' dropped in container '%s' (proposed index = %i)",
1305                          obj.GetText(), m_music_model->GetTitle(item), event.GetProposedDropIndex());
1306         }
1307         else
1308             wxLogMessage("Text '%s' dropped on item '%s'", obj.GetText(), m_music_model->GetTitle(item));
1309     }
1310     else
1311         wxLogMessage("Text '%s' dropped on background (proposed index = %i)", obj.GetText(), event.GetProposedDropIndex());
1312 }
1313 
1314 #endif // wxUSE_DRAG_AND_DROP
1315 
OnAddMozart(wxCommandEvent & WXUNUSED (event))1316 void MyFrame::OnAddMozart( wxCommandEvent& WXUNUSED(event) )
1317 {
1318     m_music_model->AddToClassical( "Eine kleine Nachtmusik", "Wolfgang Mozart", 1787 );
1319 }
1320 
DeleteSelectedItems()1321 void MyFrame::DeleteSelectedItems()
1322 {
1323     wxDataViewItemArray items;
1324     int len = m_ctrl[Page_Music]->GetSelections( items );
1325     for( int i = 0; i < len; i ++ )
1326         if (items[i].IsOk())
1327             m_music_model->Delete( items[i] );
1328 }
1329 
OnDeleteSelected(wxCommandEvent & WXUNUSED (event))1330 void MyFrame::OnDeleteSelected( wxCommandEvent& WXUNUSED(event) )
1331 {
1332     DeleteSelectedItems();
1333 }
1334 
OnDeleteYear(wxCommandEvent & WXUNUSED (event))1335 void MyFrame::OnDeleteYear( wxCommandEvent& WXUNUSED(event) )
1336 {
1337     m_ctrl[Page_Music]->DeleteColumn( m_ctrl[Page_Music]->GetColumn( 2 ) );
1338     FindWindow( ID_DELETE_YEAR )->Disable();
1339 }
1340 
OnSelectNinth(wxCommandEvent & WXUNUSED (event))1341 void MyFrame::OnSelectNinth( wxCommandEvent& WXUNUSED(event) )
1342 {
1343     if (!m_music_model->GetNinthItem().IsOk())
1344     {
1345         wxLogError( "Cannot select the ninth symphony: it was removed!" );
1346         return;
1347     }
1348 
1349     m_ctrl[Page_Music]->Select( m_music_model->GetNinthItem() );
1350 }
1351 
OnCollapse(wxCommandEvent & WXUNUSED (event))1352 void MyFrame::OnCollapse( wxCommandEvent& WXUNUSED(event) )
1353 {
1354     wxDataViewItem item = m_ctrl[Page_Music]->GetSelection();
1355     if (item.IsOk())
1356         m_ctrl[Page_Music]->Collapse( item );
1357 }
1358 
OnExpand(wxCommandEvent & WXUNUSED (event))1359 void MyFrame::OnExpand( wxCommandEvent& WXUNUSED(event) )
1360 {
1361     wxDataViewItem item = m_ctrl[Page_Music]->GetSelection();
1362     if (item.IsOk())
1363         m_ctrl[Page_Music]->Expand( item );
1364 }
1365 
OnShowCurrent(wxCommandEvent & WXUNUSED (event))1366 void MyFrame::OnShowCurrent(wxCommandEvent& WXUNUSED(event))
1367 {
1368     wxDataViewItem item = m_ctrl[Page_Music]->GetCurrentItem();
1369     if ( item.IsOk() )
1370     {
1371         wxLogMessage("Current item: \"%s\" by %s",
1372                      m_music_model->GetTitle(item),
1373                      m_music_model->GetArtist(item));
1374     }
1375     else
1376     {
1377         wxLogMessage("There is no current item.");
1378     }
1379 
1380     wxDataViewColumn *col = m_ctrl[Page_Music]->GetCurrentColumn();
1381     if ( col )
1382     {
1383         wxLogMessage("Current column: %d",
1384                      m_ctrl[Page_Music]->GetColumnPosition(col));
1385     }
1386     else
1387     {
1388         wxLogMessage("There is no current column.");
1389     }
1390 }
1391 
OnSetNinthCurrent(wxCommandEvent & WXUNUSED (event))1392 void MyFrame::OnSetNinthCurrent(wxCommandEvent& WXUNUSED(event))
1393 {
1394     wxDataViewItem item(m_music_model->GetNinthItem());
1395     if ( !item.IsOk() )
1396     {
1397         wxLogError( "Cannot make the ninth symphony current: it was removed!" );
1398         return;
1399     }
1400 
1401     m_ctrl[Page_Music]->SetCurrentItem(item);
1402 }
1403 
OnChangeNinthTitle(wxCommandEvent & WXUNUSED (event))1404 void MyFrame::OnChangeNinthTitle(wxCommandEvent& WXUNUSED(event))
1405 {
1406     wxDataViewItem item(m_music_model->GetNinthItem());
1407     if ( !item.IsOk() )
1408     {
1409         wxLogError( "Cannot change the ninth symphony title: it was removed!" );
1410         return;
1411     }
1412 
1413     m_music_model->SetValue("Symphony No. 9", item, 0);
1414     m_music_model->ItemChanged(item);
1415 }
1416 
OnValueChanged(wxDataViewEvent & event)1417 void MyFrame::OnValueChanged( wxDataViewEvent &event )
1418 {
1419     wxString title = m_music_model->GetTitle( event.GetItem() );
1420     wxLogMessage( "wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, Item Id: %s;  Column: %d",
1421                   title, event.GetColumn() );
1422 }
1423 
OnActivated(wxDataViewEvent & event)1424 void MyFrame::OnActivated( wxDataViewEvent &event )
1425 {
1426     wxString title = m_music_model->GetTitle( event.GetItem() );
1427     wxLogMessage( "wxEVT_DATAVIEW_ITEM_ACTIVATED, Item: %s; Column: %d",
1428                   title, event.GetColumn() );
1429 
1430     if (m_ctrl[Page_Music]->IsExpanded( event.GetItem() ))
1431     {
1432         wxLogMessage( "Item: %s is expanded", title );
1433     }
1434 }
1435 
OnSelectionChanged(wxDataViewEvent & event)1436 void MyFrame::OnSelectionChanged( wxDataViewEvent &event )
1437 {
1438     wxString title = m_music_model->GetTitle( event.GetItem() );
1439     if (title.empty())
1440         title = "None";
1441 
1442     wxLogMessage( "wxEVT_DATAVIEW_SELECTION_CHANGED, First selected Item: %s", title );
1443 }
1444 
OnExpanding(wxDataViewEvent & event)1445 void MyFrame::OnExpanding( wxDataViewEvent &event )
1446 {
1447     wxString title = m_music_model->GetTitle( event.GetItem() );
1448     wxLogMessage( "wxEVT_DATAVIEW_ITEM_EXPANDING, Item: %s", title );
1449 }
1450 
1451 
OnStartEditing(wxDataViewEvent & event)1452 void MyFrame::OnStartEditing( wxDataViewEvent &event )
1453 {
1454     wxString artist = m_music_model->GetArtist( event.GetItem() );
1455     if (artist == "Ludwig van Beethoven")
1456     {
1457         event.Veto();
1458 
1459         wxLogMessage( "wxEVT_DATAVIEW_ITEM_START_EDITING vetoed. Artist: %s", artist );
1460     }
1461     else
1462         wxLogMessage( "wxEVT_DATAVIEW_ITEM_START_EDITING not vetoed. Artist: %s", artist );
1463 
1464 }
1465 
OnEditingStarted(wxDataViewEvent & event)1466 void MyFrame::OnEditingStarted( wxDataViewEvent &event )
1467 {
1468     // This event doesn't, currently, carry the value, so get it ourselves.
1469     wxDataViewModel* const model = event.GetModel();
1470     wxVariant value;
1471     model->GetValue(value, event.GetItem(), event.GetColumn());
1472     wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_STARTED, current value %s",
1473                  value.GetString());
1474 }
1475 
OnEditingDone(wxDataViewEvent & event)1476 void MyFrame::OnEditingDone( wxDataViewEvent &event )
1477 {
1478     wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_DONE, new value %s",
1479                  event.IsEditCancelled()
1480                     ? wxString("unavailable because editing was cancelled")
1481                     : event.GetValue().GetString());
1482 }
1483 
OnExpanded(wxDataViewEvent & event)1484 void MyFrame::OnExpanded( wxDataViewEvent &event )
1485 {
1486     wxString title = m_music_model->GetTitle( event.GetItem() );
1487     wxLogMessage( "wxEVT_DATAVIEW_ITEM_EXPANDED, Item: %s", title );
1488 }
1489 
OnCollapsing(wxDataViewEvent & event)1490 void MyFrame::OnCollapsing( wxDataViewEvent &event )
1491 {
1492     wxString title = m_music_model->GetTitle( event.GetItem() );
1493     wxLogMessage( "wxEVT_DATAVIEW_ITEM_COLLAPSING, Item: %s", title );
1494 }
1495 
OnCollapsed(wxDataViewEvent & event)1496 void MyFrame::OnCollapsed( wxDataViewEvent &event )
1497 {
1498     wxString title = m_music_model->GetTitle( event.GetItem() );
1499     wxLogMessage( "wxEVT_DATAVIEW_ITEM_COLLAPSED, Item: %s", title );
1500 }
1501 
OnContextMenu(wxDataViewEvent & event)1502 void MyFrame::OnContextMenu( wxDataViewEvent &event )
1503 {
1504     wxString title = m_music_model->GetTitle( event.GetItem() );
1505     wxLogMessage( "wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, Item: %s", title );
1506 
1507     wxMenu menu;
1508     menu.Append( 1, "menuitem 1" );
1509     menu.Append( 2, "menuitem 2" );
1510     menu.Append( 3, "menuitem 3" );
1511 
1512     m_ctrl[Page_Music]->PopupMenu(&menu);
1513 }
1514 
OnAttrHeaderClick(wxDataViewEvent & event)1515 void MyFrame::OnAttrHeaderClick( wxDataViewEvent &event )
1516 {
1517     // we need to skip the event to let the default behaviour of sorting by
1518     // this column when it is clicked to take place
1519     event.Skip();
1520 
1521     int pos = m_ctrl[Page_List]->GetColumnPosition( event.GetDataViewColumn() );
1522 
1523     wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos );
1524     wxLogMessage( "Column title: %s  Column width: %d", event.GetDataViewColumn()->GetTitle(), event.GetDataViewColumn()->GetWidth() );
1525 }
1526 
OnHeaderClick(wxDataViewEvent & event)1527 void MyFrame::OnHeaderClick( wxDataViewEvent &event )
1528 {
1529     // we need to skip the event to let the default behaviour of sorting by
1530     // this column when it is clicked to take place
1531     event.Skip();
1532 
1533     int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
1534 
1535     wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos );
1536     wxLogMessage( "Column width: %d", event.GetDataViewColumn()->GetWidth() );
1537 }
1538 
OnHeaderRightClick(wxDataViewEvent & event)1539 void MyFrame::OnHeaderRightClick( wxDataViewEvent &event )
1540 {
1541     int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
1542 
1543     wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column position: %d", pos );
1544 }
1545 
OnColumnReordered(wxDataViewEvent & event)1546 void MyFrame::OnColumnReordered(wxDataViewEvent& event)
1547 {
1548     wxDataViewColumn* const col = event.GetDataViewColumn();
1549     if ( !col )
1550     {
1551         wxLogError("Unknown column reordered?");
1552         return;
1553     }
1554 
1555     wxLogMessage("wxEVT_DATAVIEW_COLUMN_REORDERED: \"%s\" is now at position %d",
1556                  col->GetTitle(), event.GetColumn());
1557 }
1558 
OnSortedList(wxDataViewEvent &)1559 void MyFrame::OnSortedList( wxDataViewEvent &/*event*/)
1560 {
1561     wxVector<wxDataViewColumn *> const columns = m_ctrl[Page_List]->GetSortingColumns();
1562     wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED using the following columns");
1563 
1564     for ( wxVector<wxDataViewColumn *>::const_iterator it = columns.begin(),
1565                                                       end = columns.end();
1566           it != end;
1567           ++it )
1568     {
1569         wxDataViewColumn* const col = *it;
1570 
1571         wxLogMessage("\t%d. %s %s",
1572                      col->GetModelColumn(),
1573                      col->GetTitle(),
1574                      col->IsSortOrderAscending() ? "ascending" : "descending");
1575     }
1576 }
1577 
OnHeaderClickList(wxDataViewEvent & event)1578 void MyFrame::OnHeaderClickList( wxDataViewEvent &event )
1579 {
1580     // Use control+click to toggle sorting by this column.
1581     if ( wxGetKeyState(WXK_CONTROL) )
1582         m_ctrl[Page_List]->ToggleSortByColumn(event.GetColumn());
1583     else
1584         event.Skip();
1585 }
1586 
OnSorted(wxDataViewEvent & event)1587 void MyFrame::OnSorted( wxDataViewEvent &event )
1588 {
1589     int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
1590 
1591     wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED, Column position: %d", pos );
1592 }
1593 
OnDataViewChar(wxKeyEvent & event)1594 void MyFrame::OnDataViewChar(wxKeyEvent& event)
1595 {
1596     if ( event.GetKeyCode() == WXK_DELETE )
1597         DeleteSelectedItems();
1598     else
1599         event.Skip();
1600 }
1601 
1602 // ----------------------------------------------------------------------------
1603 // MyFrame - event handlers for the second page
1604 // ----------------------------------------------------------------------------
1605 
OnPrependList(wxCommandEvent & WXUNUSED (event))1606 void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) )
1607 {
1608     m_list_model->Prepend("Test");
1609 }
1610 
OnDeleteList(wxCommandEvent & WXUNUSED (event))1611 void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) )
1612 {
1613     wxDataViewItemArray items;
1614     int len = m_ctrl[Page_List]->GetSelections( items );
1615     if (len > 0)
1616         m_list_model->DeleteItems( items );
1617 }
1618 
OnGoto(wxCommandEvent & WXUNUSED (event))1619 void MyFrame::OnGoto(wxCommandEvent& WXUNUSED(event))
1620 {
1621     wxDataViewItem item = m_list_model->GetItem( 50 );
1622     m_ctrl[Page_List]->EnsureVisible(item,m_col);
1623 }
1624 
OnAddMany(wxCommandEvent & WXUNUSED (event))1625 void MyFrame::OnAddMany(wxCommandEvent& WXUNUSED(event))
1626 {
1627     m_list_model->AddMany();
1628 }
1629 
OnHideAttributes(wxCommandEvent & WXUNUSED (event))1630 void MyFrame::OnHideAttributes(wxCommandEvent& WXUNUSED(event))
1631 {
1632     m_attributes->SetHidden(true);
1633 }
1634 
OnShowAttributes(wxCommandEvent & WXUNUSED (event))1635 void MyFrame::OnShowAttributes(wxCommandEvent& WXUNUSED(event))
1636 {
1637     m_attributes->SetHidden(false);
1638 }
1639 
1640 // ----------------------------------------------------------------------------
1641 // MyFrame - event handlers for the third (wxDataViewListCtrl) page
1642 // ----------------------------------------------------------------------------
1643 
OnListValueChanged(wxDataViewEvent & event)1644 void MyFrame::OnListValueChanged(wxDataViewEvent& event)
1645 {
1646     // Ignore changes coming from our own SetToggleValue() calls below.
1647     if ( m_eventFromProgram )
1648     {
1649         m_eventFromProgram = false;
1650         return;
1651     }
1652 
1653     wxDataViewListCtrl* const lc = static_cast<wxDataViewListCtrl*>(m_ctrl[Page_ListStore]);
1654 
1655     const int columnToggle = 1;
1656 
1657     // Handle selecting a radio button by unselecting all the other ones.
1658     if ( event.GetColumn() == columnToggle )
1659     {
1660         const int rowChanged = lc->ItemToRow(event.GetItem());
1661         if ( lc->GetToggleValue(rowChanged, columnToggle) )
1662         {
1663             for ( int row = 0; row < lc->GetItemCount(); ++row )
1664             {
1665                 if ( row != rowChanged )
1666                 {
1667                     m_eventFromProgram = true;
1668                     lc->SetToggleValue(false, row, columnToggle);
1669                 }
1670             }
1671         }
1672         else // The item was cleared.
1673         {
1674             // Explicitly check it back, we want to always have exactly one
1675             // checked radio item in this column.
1676             m_eventFromProgram = true;
1677             lc->SetToggleValue(true, rowChanged, columnToggle);
1678         }
1679     }
1680 }
1681 
1682 // ----------------------------------------------------------------------------
1683 // MyFrame - event handlers for the fourth page
1684 // ----------------------------------------------------------------------------
1685 
OnDeleteTreeItem(wxCommandEvent & WXUNUSED (event))1686 void MyFrame::OnDeleteTreeItem(wxCommandEvent& WXUNUSED(event))
1687 {
1688     wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
1689     wxDataViewItem selected = ctrl->GetSelection();
1690     if (!selected.IsOk())
1691         return;
1692 
1693     ctrl->DeleteItem(selected);
1694 }
1695 
OnDeleteAllTreeItems(wxCommandEvent & WXUNUSED (event))1696 void MyFrame::OnDeleteAllTreeItems(wxCommandEvent& WXUNUSED(event))
1697 {
1698     wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
1699     ctrl->DeleteAllItems();
1700 }
1701 
OnAddTreeItem(wxCommandEvent & WXUNUSED (event))1702 void MyFrame::OnAddTreeItem(wxCommandEvent& WXUNUSED(event))
1703 {
1704     wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
1705     wxDataViewItem selected = ctrl->GetSelection();
1706     if (ctrl->IsContainer(selected)) {
1707         wxDataViewItem newitem = ctrl->AppendItem( selected, "Item", 0 );
1708         ctrl->Select(newitem);
1709         ctrl->EditItem(newitem, ctrl->GetColumn(0));
1710     }
1711 }
1712 
OnAddTreeContainerItem(wxCommandEvent & WXUNUSED (event))1713 void MyFrame::OnAddTreeContainerItem(wxCommandEvent& WXUNUSED(event))
1714 {
1715     wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
1716     wxDataViewItem selected = ctrl->GetSelection();
1717     if (ctrl->IsContainer(selected))
1718         ctrl->AppendContainer(selected, "Container", 0 );
1719 }
1720 
OnMultipleSort(wxCommandEvent & event)1721 void MyFrame::OnMultipleSort( wxCommandEvent &event )
1722 {
1723     if ( !m_ctrl[Page_List]->AllowMultiColumnSort(event.IsChecked()) )
1724         wxLogMessage("Sorting by multiple columns not supported");
1725 }
1726 
OnSortByFirstColumn(wxCommandEvent & event)1727 void MyFrame::OnSortByFirstColumn(wxCommandEvent& event)
1728 {
1729     wxDataViewColumn* const col = m_ctrl[Page_List]->GetColumn(0);
1730     if ( event.IsChecked() )
1731         col->SetSortOrder(true /* ascending */);
1732     else
1733         col->UnsetAsSortKey();
1734 }
1735 
1736 // ----------------------------------------------------------------------------
1737 // Index list model page
1738 // ----------------------------------------------------------------------------
1739 
FillIndexList(Lang lang)1740 void MyFrame::FillIndexList(Lang lang)
1741 {
1742     const int DAYS_PER_WEEK = 7;
1743     const wxString weekdays[2][DAYS_PER_WEEK] =
1744     {
1745         { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" },
1746         { "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim" },
1747     };
1748 
1749     m_index_list_model->Fill(wxArrayString(DAYS_PER_WEEK, weekdays[lang]));
1750 }
1751 
OnIndexListResetModel(wxCommandEvent &)1752 void MyFrame::OnIndexListResetModel(wxCommandEvent&)
1753 {
1754     m_ctrl[Page_IndexList]->AssociateModel(NULL);
1755     m_ctrl[Page_IndexList]->AssociateModel(m_index_list_model.get());
1756 }
1757 
OnIndexListSelectionChanged(wxDataViewEvent & event)1758 void MyFrame::OnIndexListSelectionChanged(wxDataViewEvent& event)
1759 {
1760     // We don't expect any events during the control destruction.
1761     wxASSERT( !m_ctrl[Page_IndexList]->IsBeingDeleted() );
1762 
1763     wxString weekday;
1764     wxDataViewItem item = event.GetItem();
1765     if ( !item )
1766     {
1767         weekday = "[none]";
1768     }
1769     else
1770     {
1771         wxVariant val;
1772         m_index_list_model->GetValue(val, item, 0);
1773         weekday = val.GetString();
1774     }
1775 
1776     wxLogMessage("Selected week day: %s", weekday);
1777 }
1778 
1779 // ----------------------------------------------------------------------------
1780 // MyFrame - event handlers for the HasValue (wxDataViewListCtrl) page
1781 // ----------------------------------------------------------------------------
1782 
OnHasValueValueChanged(wxDataViewEvent & event)1783 void MyFrame::OnHasValueValueChanged(wxDataViewEvent& event)
1784 {
1785     // Ignore changes coming from our own SetToggleValue() calls below.
1786     if ( m_eventFromProgram )
1787     {
1788         m_eventFromProgram = false;
1789         return;
1790     }
1791 
1792     wxDataViewListCtrl* const lc = static_cast<wxDataViewListCtrl*>(m_ctrl[Page_HasValue]);
1793 
1794     const int columnToggle = 1;
1795 
1796     // Handle selecting a radio button by unselecting all the other ones.
1797     if ( event.GetColumn() == columnToggle )
1798     {
1799         const int rowChanged = lc->ItemToRow(event.GetItem());
1800         if ( lc->GetToggleValue(rowChanged, columnToggle) )
1801         {
1802             for ( int row = 0; row < lc->GetItemCount(); ++row )
1803             {
1804                 if ( row != rowChanged )
1805                 {
1806                     m_eventFromProgram = true;
1807                     lc->SetToggleValue(false, row, columnToggle);
1808                 }
1809             }
1810         }
1811         else // The item was cleared.
1812         {
1813             // Explicitly check it back, we want to always have exactly one
1814             // checked radio item in this column.
1815             m_eventFromProgram = true;
1816             lc->SetToggleValue(true, rowChanged, columnToggle);
1817         }
1818     }
1819 }
1820