From 81c3f0fce3cde0149d583f4d970532460e20e94a Mon Sep 17 00:00:00 2001 From: Francesco Montorsi Date: Wed, 4 Mar 2009 22:33:18 +0000 Subject: [PATCH] all code revisited. Main additions: - now it's possible to change the DVC style dynamically - make models more robust against deleting items, and against other allowed user actions - comment portions of the code to make it more didactive git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59323 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- samples/dataview/dataview.cpp | 617 ++++++++++++++++++++++------------ samples/dataview/mymodels.cpp | 236 ++++++++----- samples/dataview/mymodels.h | 107 +++--- 3 files changed, 607 insertions(+), 353 deletions(-) diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 3b5774ba7d..2b0dc8efd2 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -66,10 +66,18 @@ public: MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int h); ~MyFrame(); -public: + void BuildDataViewCtrl(wxPanel* parent, + unsigned int nPanel, + unsigned long style = 0); + +public: // event handlers + + void OnStyleChange(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); + void OnPageChanged(wxBookCtrlEvent& event); + void OnAddMozart(wxCommandEvent& event); void OnDeleteMusic(wxCommandEvent& event); void OnDeleteYear(wxCommandEvent& event); @@ -109,14 +117,12 @@ private: // the controls stored in the various tabs of the main notebook: - wxDataViewCtrl* m_myMusicModelViewCtrl; - wxObjectDataPtr m_music_model; + wxDataViewCtrl* m_ctrl[4]; - wxDataViewCtrl* m_myListModelViewCtrl; - wxObjectDataPtr m_list_model; + // the models associated with the first two DVC: - wxDataViewListCtrl* m_listctrl; - wxDataViewTreeCtrl* m_treectrl; + wxObjectDataPtr m_music_model; + wxObjectDataPtr m_list_model; // other data: @@ -145,17 +151,16 @@ public: { dc->SetBrush( *wxRED_BRUSH ); dc->SetPen( *wxTRANSPARENT_PEN ); - dc->DrawRectangle( rect ); + dc->DrawRectangle( rect.Deflate(2) ); return true; } - virtual bool Activate( wxRect WXUNUSED(cell), wxDataViewModel *WXUNUSED(model), const wxDataViewItem &WXUNUSED(item), unsigned int WXUNUSED(col) ) { - wxLogMessage( wxT("MyCustomRenderer Activate()") ); + wxLogMessage( "MyCustomRenderer Activate()" ); return false; } @@ -164,7 +169,7 @@ public: const wxDataViewItem &WXUNUSED(item), unsigned int WXUNUSED(col) ) { - wxLogMessage( wxT("MyCustomRenderer LeftClick( %d, %d )"), cursor.x, cursor.y ); + wxLogMessage( "MyCustomRenderer LeftClick( %d, %d )", cursor.x, cursor.y ); return false; } @@ -217,10 +222,23 @@ bool MyApp::OnInit() enum { + ID_STYLE_MENU = wxID_HIGHEST+1, + // file menu - ID_ABOUT = wxID_ABOUT, + //ID_SINGLE, wxDV_SINGLE==0 so it's always present + ID_MULTIPLE, + ID_ROW_LINES, + ID_HORIZ_RULES, + ID_VERT_RULES, + ID_EXIT = wxID_EXIT, + // about menu + ID_ABOUT = wxID_ABOUT, + + + // control IDs + ID_MUSIC_CTRL = 50, ID_ADD_MOZART = 100, @@ -235,8 +253,12 @@ enum }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU( ID_ABOUT, MyFrame::OnAbout ) + EVT_MENU_RANGE( ID_MULTIPLE, ID_VERT_RULES, MyFrame::OnStyleChange ) EVT_MENU( ID_EXIT, MyFrame::OnQuit ) + EVT_MENU( ID_ABOUT, MyFrame::OnAbout ) + + EVT_NOTEBOOK_PAGE_CHANGED( wxID_ANY, MyFrame::OnPageChanged ) + EVT_BUTTON( ID_ADD_MOZART, MyFrame::OnAddMozart ) EVT_BUTTON( ID_DELETE_MUSIC, MyFrame::OnDeleteMusic ) EVT_BUTTON( ID_DELETE_YEAR, MyFrame::OnDeleteYear ) @@ -277,19 +299,35 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int m_log = NULL; m_col = NULL; + m_ctrl[0] = NULL; + m_ctrl[1] = NULL; + m_ctrl[2] = NULL; + m_ctrl[3] = NULL; + SetIcon(wxICON(sample)); // build the menus // ---------------- + wxMenu *style_menu = new wxMenu; + //style_menu->AppendCheckItem(ID_SINGLE, wxT("Single selection")); + style_menu->AppendCheckItem(ID_MULTIPLE, wxT("Multiple selection")); + style_menu->AppendCheckItem(ID_ROW_LINES, wxT("Alternating colours")); + style_menu->AppendCheckItem(ID_HORIZ_RULES, wxT("Display horizontal rules")); + style_menu->AppendCheckItem(ID_VERT_RULES, wxT("Display vertical rules")); + wxMenu *file_menu = new wxMenu; - file_menu->Append(ID_ABOUT, wxT("&About")); + file_menu->Append(ID_STYLE_MENU, wxT("&Style"), style_menu); file_menu->AppendSeparator(); file_menu->Append(ID_EXIT, wxT("E&xit")); + wxMenu *about_menu = new wxMenu; + about_menu->Append(ID_ABOUT, wxT("&About")); + wxMenuBar *menu_bar = new wxMenuBar; menu_bar->Append(file_menu, wxT("&File")); + menu_bar->Append(about_menu, wxT("&About")); SetMenuBar(menu_bar); CreateStatusBar(); @@ -301,75 +339,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int m_notebook = new wxNotebook( this, wxID_ANY ); wxPanel *firstPanel = new wxPanel( m_notebook, wxID_ANY ); - m_myMusicModelViewCtrl = - new wxDataViewCtrl( firstPanel, ID_MUSIC_CTRL, wxDefaultPosition, - wxDefaultSize, wxDV_MULTIPLE|wxDV_VARIABLE_LINE_HEIGHT ); - - m_music_model = new MyMusicTreeModel; - m_myMusicModelViewCtrl->AssociateModel( m_music_model.get() ); - - m_myMusicModelViewCtrl->EnableDragSource( wxDF_UNICODETEXT ); - m_myMusicModelViewCtrl->EnableDropTarget( wxDF_UNICODETEXT ); - - // column 0 of the view control: - - wxDataViewTextRenderer *tr = - new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_INERT ); - wxDataViewColumn *column0 = - new wxDataViewColumn( wxT("title"), tr, 0, 200, wxALIGN_LEFT, - wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE ); - m_myMusicModelViewCtrl->AppendColumn( column0 ); -#if 0 - // Call this and sorting is enabled - // immediatly upon start up. - column0->SetAsSortKey(); -#endif - - // column 1 of the view control: - tr = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); - wxDataViewColumn *column1 = - new wxDataViewColumn( wxT("artist"), tr, 1, 150, wxALIGN_LEFT, - wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | - wxDATAVIEW_COL_RESIZABLE ); - column1->SetMinWidth(150); // this column can't be resized to be smaller - m_myMusicModelViewCtrl->AppendColumn( column1 ); - - // column 2 of the view control: - - wxDataViewSpinRenderer *sr = - new wxDataViewSpinRenderer( 0, 2010, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT ); - wxDataViewColumn *column2 = - new wxDataViewColumn( wxT("year"), sr, 2, 60, wxALIGN_LEFT, - wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE ); - m_myMusicModelViewCtrl->AppendColumn( column2 ); - - // column 3 of the view control: - - wxArrayString choices; - choices.Add( "good" ); - choices.Add( "bad" ); - choices.Add( "lousy" ); - wxDataViewChoiceRenderer *c = - new wxDataViewChoiceRenderer( choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT ); - wxDataViewColumn *column3 = - new wxDataViewColumn( wxT("rating"), c, 3, 100, wxALIGN_LEFT, - wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); - m_myMusicModelViewCtrl->AppendColumn( column3 ); - - // column 4 of the view control: - - m_myMusicModelViewCtrl->AppendProgressColumn( wxT("popularity"), 4, wxDATAVIEW_CELL_INERT, 80 ); - - // column 5 of the view control: - - MyCustomRenderer *cr = new MyCustomRenderer( wxDATAVIEW_CELL_ACTIVATABLE, wxALIGN_RIGHT ); - wxDataViewColumn *column5 = - new wxDataViewColumn( wxT("custom"), cr, 5, -1, wxALIGN_LEFT, - wxDATAVIEW_COL_RESIZABLE ); - m_myMusicModelViewCtrl->AppendColumn( column5 ); - - // complete this page: + BuildDataViewCtrl(firstPanel, 0); // sets m_ctrl[0] wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL ); button_sizer->Add( new wxButton( firstPanel, ID_ADD_MOZART, _("Add Mozart")), 0, wxALL, 10 ); @@ -378,8 +349,11 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int button_sizer->Add( new wxButton( firstPanel, ID_SELECT_NINTH,_("Select Ninth")), 0, wxALL, 10 ); wxSizer *firstPanelSz = new wxBoxSizer( wxVERTICAL ); - m_myMusicModelViewCtrl->SetMinSize(wxSize(-1, 200)); - firstPanelSz->Add(m_myMusicModelViewCtrl, 1, wxGROW|wxALL, 5); + m_ctrl[0]->SetMinSize(wxSize(-1, 200)); + firstPanelSz->Add(m_ctrl[0], 1, wxGROW|wxALL, 5); + firstPanelSz->Add( + new wxStaticText(firstPanel, wxID_ANY, wxT("Most of the cells above are editable!")), + 0, wxGROW|wxALL, 5); firstPanelSz->Add(button_sizer); firstPanel->SetSizerAndFit(firstPanelSz); @@ -389,24 +363,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int wxPanel *secondPanel = new wxPanel( m_notebook, wxID_ANY ); - m_myListModelViewCtrl = new wxDataViewCtrl( secondPanel, wxID_ANY, wxDefaultPosition, - wxDefaultSize, wxDV_MULTIPLE | wxDV_ROW_LINES); - - m_list_model = new MyListModel; - m_myListModelViewCtrl->AssociateModel( m_list_model.get() ); - - // the various columns -#if 1 - m_myListModelViewCtrl->AppendTextColumn (wxT("editable string"), 0, wxDATAVIEW_CELL_EDITABLE, 120 ); - m_myListModelViewCtrl->AppendIconTextColumn(wxIcon(wx_small_xpm), 1, wxDATAVIEW_CELL_INERT )->SetTitle( wxT("icon") ); -#else - m_myListModelViewCtrl->AppendTextColumn (wxT("editable string"), 0, wxDATAVIEW_CELL_EDITABLE ); - m_myListModelViewCtrl->AppendIconTextColumn(wxT("icon"), 1, wxDATAVIEW_CELL_INERT ); -#endif - m_myListModelViewCtrl->AppendColumn( - new wxDataViewColumn(wxT("attributes"), new wxDataViewTextRendererAttr, 2 )); - - // complete this page: + BuildDataViewCtrl(secondPanel, 1); // sets m_ctrl[1] wxBoxSizer *button_sizer2 = new wxBoxSizer( wxHORIZONTAL ); button_sizer2->Add( new wxButton( secondPanel, ID_PREPEND_LIST,_("Prepend")), 0, wxALL, 10 ); @@ -415,35 +372,20 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int button_sizer2->Add( new wxButton( secondPanel, ID_ADD_MANY, _("Add 1000")), 0, wxALL, 10 ); wxSizer *secondPanelSz = new wxBoxSizer( wxVERTICAL ); - secondPanelSz->Add(m_myListModelViewCtrl, 1, wxGROW|wxALL, 5); + secondPanelSz->Add(m_ctrl[1], 1, wxGROW|wxALL, 5); secondPanelSz->Add(button_sizer2); secondPanel->SetSizerAndFit(secondPanelSz); - // third page of the notebook // --------------------------- wxPanel *thirdPanel = new wxPanel( m_notebook, wxID_ANY ); - m_listctrl = new wxDataViewListCtrl( thirdPanel, wxID_ANY ); - m_listctrl->AppendToggleColumn( wxT("Toggle") ); - m_listctrl->AppendTextColumn( wxT("Text") ); - - wxVector data; - data.push_back( true ); - data.push_back( "row 1" ); - m_listctrl->AppendItem( data ); - - data.clear(); - data.push_back( false ); - data.push_back( "row 3" ); - m_listctrl->AppendItem( data ); - - // complete this page: + BuildDataViewCtrl(thirdPanel, 2); // sets m_ctrl[2] wxSizer *thirdPanelSz = new wxBoxSizer( wxVERTICAL ); - thirdPanelSz->Add(m_listctrl, 1, wxGROW|wxALL, 5); + thirdPanelSz->Add(m_ctrl[2], 1, wxGROW|wxALL, 5); thirdPanel->SetSizerAndFit(thirdPanelSz); @@ -452,21 +394,10 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int wxPanel *fourthPanel = new wxPanel( m_notebook, wxID_ANY ); - m_treectrl = new wxDataViewTreeCtrl( fourthPanel, wxID_ANY ); - - wxImageList *ilist = new wxImageList( 16, 16 ); - ilist->Add( wxIcon(wx_small_xpm) ); - m_treectrl->SetImageList( ilist ); - - wxDataViewItem parent2 = m_treectrl->AppendContainer( wxDataViewItem(0),wxT("Root 1"), 0 ); - m_treectrl->AppendItem( parent2, wxT("Child 1"), 0 ); - m_treectrl->AppendItem( parent2, wxT("Child 2"), 0 ); - m_treectrl->AppendItem( parent2, wxT("Child 3, very long, long, long, long"), 0 ); - - // complete this page: + BuildDataViewCtrl(fourthPanel, 3); // sets m_ctrl[3] wxSizer *fourthPanelSz = new wxBoxSizer( wxVERTICAL ); - fourthPanelSz->Add(m_treectrl, 1, wxGROW|wxALL, 5); + fourthPanelSz->Add(m_ctrl[3], 1, wxGROW|wxALL, 5); fourthPanel->SetSizerAndFit(fourthPanelSz); @@ -498,20 +429,322 @@ MyFrame::~MyFrame() delete wxLog::SetActiveTarget(m_logOld); } -void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) ) +void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned long style) +{ + switch (nPanel) + { + case 0: + { + wxASSERT(!m_ctrl[0] && !m_music_model); + m_ctrl[0] = + new wxDataViewCtrl( parent, ID_MUSIC_CTRL, wxDefaultPosition, + wxDefaultSize, style ); + + m_music_model = new MyMusicTreeModel; + m_ctrl[0]->AssociateModel( m_music_model.get() ); + + m_ctrl[0]->EnableDragSource( wxDF_UNICODETEXT ); + m_ctrl[0]->EnableDropTarget( wxDF_UNICODETEXT ); + + // column 0 of the view control: + + wxDataViewTextRenderer *tr = + new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_INERT ); + wxDataViewColumn *column0 = + new wxDataViewColumn( wxT("title"), tr, 0, 200, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE ); + m_ctrl[0]->AppendColumn( column0 ); +#if 0 + // Call this and sorting is enabled + // immediatly upon start up. + column0->SetAsSortKey(); +#endif + + // column 1 of the view control: + + tr = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); + wxDataViewColumn *column1 = + new wxDataViewColumn( wxT("artist"), tr, 1, 150, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | + wxDATAVIEW_COL_RESIZABLE ); + column1->SetMinWidth(150); // this column can't be resized to be smaller + m_ctrl[0]->AppendColumn( column1 ); + + // column 2 of the view control: + + wxDataViewSpinRenderer *sr = + new wxDataViewSpinRenderer( 0, 2010, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT ); + wxDataViewColumn *column2 = + new wxDataViewColumn( wxT("year"), sr, 2, 60, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE ); + m_ctrl[0]->AppendColumn( column2 ); + + // column 3 of the view control: + + wxArrayString choices; + choices.Add( "good" ); + choices.Add( "bad" ); + choices.Add( "lousy" ); + wxDataViewChoiceRenderer *c = + new wxDataViewChoiceRenderer( choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT ); + wxDataViewColumn *column3 = + new wxDataViewColumn( wxT("rating"), c, 3, 100, wxALIGN_LEFT, + wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); + m_ctrl[0]->AppendColumn( column3 ); + + // column 4 of the view control: + + m_ctrl[0]->AppendProgressColumn( wxT("popularity"), 4, wxDATAVIEW_CELL_INERT, 80 ); + + // column 5 of the view control: + + MyCustomRenderer *cr = new MyCustomRenderer( wxDATAVIEW_CELL_ACTIVATABLE, wxALIGN_RIGHT ); + wxDataViewColumn *column5 = + new wxDataViewColumn( wxT("custom"), cr, 5, -1, wxALIGN_LEFT, + wxDATAVIEW_COL_RESIZABLE ); + m_ctrl[0]->AppendColumn( column5 ); + + + // select initially the ninth symphony: + m_ctrl[0]->Select(m_music_model->GetNinthItem()); + } + break; + + case 1: + { + wxASSERT(!m_ctrl[1] && !m_list_model); + m_ctrl[1] = new wxDataViewCtrl( parent, wxID_ANY, wxDefaultPosition, + wxDefaultSize, style ); + + m_list_model = new MyListModel; + m_ctrl[1]->AssociateModel( m_list_model.get() ); + + // the various columns +#if 1 + m_ctrl[1]->AppendTextColumn (wxT("editable string"), 0, wxDATAVIEW_CELL_EDITABLE, 120 ); + m_ctrl[1]->AppendIconTextColumn(wxIcon(wx_small_xpm), 1, wxDATAVIEW_CELL_INERT )->SetTitle( wxT("icon") ); +#else + m_ctrl[1]->AppendTextColumn (wxT("editable string"), 0, wxDATAVIEW_CELL_EDITABLE ); + m_ctrl[1]->AppendIconTextColumn(wxT("icon"), 1, wxDATAVIEW_CELL_INERT ); +#endif + m_ctrl[1]->AppendColumn( + new wxDataViewColumn(wxT("attributes"), new wxDataViewTextRendererAttr, 2 )); + } + break; + + case 2: + { + wxASSERT(!m_ctrl[2]); + wxDataViewListCtrl* lc = + new wxDataViewListCtrl( parent, wxID_ANY, wxDefaultPosition, + wxDefaultSize, style ); + m_ctrl[2] = lc; + + lc->AppendToggleColumn( wxT("Toggle") ); + lc->AppendTextColumn( wxT("Text") ); + lc->AppendProgressColumn( wxT("Progress") ); + + wxVector data; + for (unsigned int i=0; i<10; i++) + { + data.clear(); + data.push_back( (i%3) == 0 ); + data.push_back( wxString::Format("row %d", i) ); + data.push_back( long(5*i) ); + + lc->AppendItem( data ); + } + } + break; + + case 3: + { + wxASSERT(!m_ctrl[3]); + wxDataViewTreeCtrl* tc = + new wxDataViewTreeCtrl( parent, wxID_ANY, wxDefaultPosition, + wxDefaultSize, style ); + m_ctrl[3] = tc; + + wxImageList *ilist = new wxImageList( 16, 16 ); + ilist->Add( wxIcon(wx_small_xpm) ); + tc->SetImageList( ilist ); + + wxDataViewItem parent = + tc->AppendContainer( wxDataViewItem(0), wxT("The Root"), 0 ); + tc->AppendItem( parent, wxT("Child 1"), 0 ); + tc->AppendItem( parent, wxT("Child 2"), 0 ); + tc->AppendItem( parent, wxT("Child 3, very long, long, long, long"), 0 ); + + wxDataViewItem cont = + tc->AppendContainer( parent, wxT("Container child"), 0 ); + tc->AppendItem( cont, wxT("Child 4"), 0 ); + tc->AppendItem( cont, wxT("Child 5"), 0 ); + + tc->Expand(cont); + } + break; + } +} + + +// ---------------------------------------------------------------------------- +// MyFrame - generic event handlers +// ---------------------------------------------------------------------------- + +void MyFrame::OnPageChanged(wxBookCtrlEvent& WXUNUSED(event) ) +{ + unsigned int nPanel = m_notebook->GetSelection(); + + GetMenuBar()->FindItem(ID_STYLE_MENU)->SetItemLabel( + wxString::Format("Style of panel #%d", nPanel+1)); + + for (unsigned int id = ID_MULTIPLE; id <= ID_VERT_RULES; id++) + { + unsigned long style = 0; + switch (id) + { + /*case ID_SINGLE: + style = wxDV_SINGLE; + break;*/ + case ID_MULTIPLE: + style = wxDV_MULTIPLE; + break; + case ID_ROW_LINES: + style = wxDV_ROW_LINES; + break; + case ID_HORIZ_RULES: + style = wxDV_HORIZ_RULES; + break; + case ID_VERT_RULES: + style = wxDV_VERT_RULES; + break; + default: + wxFAIL; + } + + GetMenuBar()->FindItem(id)->Check( m_ctrl[nPanel]->HasFlag(style) ); + } +} + +void MyFrame::OnStyleChange(wxCommandEvent& WXUNUSED(event) ) +{ + unsigned int nPanel = m_notebook->GetSelection(); + + // build the style + unsigned long style = 0; + /*if (GetMenuBar()->FindItem(ID_SINGLE)->IsChecked()) + style |= wxDV_SINGLE;*/ + if (GetMenuBar()->FindItem(ID_MULTIPLE)->IsChecked()) + style |= wxDV_MULTIPLE; + if (GetMenuBar()->FindItem(ID_ROW_LINES)->IsChecked()) + style |= wxDV_ROW_LINES; + if (GetMenuBar()->FindItem(ID_HORIZ_RULES)->IsChecked()) + style |= wxDV_HORIZ_RULES; + if (GetMenuBar()->FindItem(ID_VERT_RULES)->IsChecked()) + style |= wxDV_VERT_RULES; + + wxSizer* sz = m_ctrl[nPanel]->GetContainingSizer(); + wxASSERT(sz); + + sz->Detach(m_ctrl[nPanel]); + wxDELETE(m_ctrl[nPanel]); + m_ctrl[nPanel] = NULL; + + if (nPanel == 0) + m_music_model.reset(NULL); + else if (nPanel == 1) + m_list_model.reset(NULL); + + // rebuild the DVC for the selected panel: + BuildDataViewCtrl((wxPanel*)m_notebook->GetPage(nPanel), nPanel, style); + + sz->Prepend(m_ctrl[nPanel], 1, wxGROW|wxALL, 5); + sz->Layout(); +} + +void MyFrame::OnQuit( wxCommandEvent& WXUNUSED(event) ) { Close(true); } -void MyFrame::OnAddMozart(wxCommandEvent& WXUNUSED(event) ) +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) ) +{ + wxAboutDialogInfo info; + info.SetName(_("DataView sample")); + info.SetDescription(_("This sample demonstrates wxDataViewCtrl")); + info.SetCopyright(_T("(C) 2007-2009 Robert Roebling")); + info.AddDeveloper("Robert Roebling"); + info.AddDeveloper("Francesco Montorsi"); + + wxAboutBox(info); +} + + +// ---------------------------------------------------------------------------- +// MyFrame - event handlers for the first page +// ---------------------------------------------------------------------------- + +void MyFrame::OnBeginDrag( wxDataViewEvent &event ) +{ + wxDataViewItem item( event.GetItem() ); + + // only allow drags for item, not containers + if (m_music_model->IsContainer( item ) ) + { + event.Veto(); + return; + } + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); + wxTextDataObject *obj = new wxTextDataObject; + obj->SetText( node->m_title ); + event.SetDataObject( obj ); +} + +void MyFrame::OnDropPossible( wxDataViewEvent &event ) +{ + wxDataViewItem item( event.GetItem() ); + + // only allow drags for item, not containers + if (m_music_model->IsContainer( item ) ) + event.Veto(); + + if (event.GetDataFormat() != wxDF_UNICODETEXT) + event.Veto(); +} + +void MyFrame::OnDrop( wxDataViewEvent &event ) +{ + wxDataViewItem item( event.GetItem() ); + + // only allow drops for item, not containers + if (m_music_model->IsContainer( item ) ) + { + event.Veto(); + return; + } + + if (event.GetDataFormat() != wxDF_UNICODETEXT) + { + event.Veto(); + return; + } + + wxTextDataObject obj; + obj.SetData( wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer() ); + + wxLogMessage(wxT("Text dropped: %s"), obj.GetText() ); +} + +void MyFrame::OnAddMozart( wxCommandEvent& WXUNUSED(event) ) { m_music_model->AddToClassical( wxT("Kleine Nachtmusik"), wxT("Wolfgang Mozart"), 1787 ); } -void MyFrame::OnDeleteMusic(wxCommandEvent& WXUNUSED(event) ) +void MyFrame::OnDeleteMusic( wxCommandEvent& WXUNUSED(event) ) { wxDataViewItemArray items; - int len = m_myMusicModelViewCtrl->GetSelections( items ); + int len = m_ctrl[0]->GetSelections( items ); for( int i = 0; i < len; i ++ ) if (items[i].IsOk()) m_music_model->Delete( items[i] ); @@ -519,26 +752,13 @@ void MyFrame::OnDeleteMusic(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnDeleteYear( wxCommandEvent& WXUNUSED(event) ) { - m_myMusicModelViewCtrl->DeleteColumn( m_myMusicModelViewCtrl->GetColumn( 2 ) ); + m_ctrl[0]->DeleteColumn( m_ctrl[0]->GetColumn( 2 ) ); FindWindow( ID_DELETE_YEAR )->Disable(); } void MyFrame::OnSelectNinth( wxCommandEvent& WXUNUSED(event) ) { - m_myMusicModelViewCtrl->Select( m_music_model->GetNinthItem() ); -} - -void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) ) -{ - m_list_model->Prepend(wxT("Test")); -} - -void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) ) -{ - wxDataViewItemArray items; - int len = m_myListModelViewCtrl->GetSelections( items ); - if (len > 0) - m_list_model->DeleteItems( items ); + m_ctrl[0]->Select( m_music_model->GetNinthItem() ); } void MyFrame::OnValueChanged( wxDataViewEvent &event ) @@ -558,7 +778,7 @@ void MyFrame::OnActivated( wxDataViewEvent &event ) wxString title = m_music_model->GetTitle( event.GetItem() ); wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, Item: %s"), title ); - if (m_myMusicModelViewCtrl->IsExpanded( event.GetItem() )) + if (m_ctrl[0]->IsExpanded( event.GetItem() )) wxLogMessage(wxT("Item: %s is expanded"), title ); } @@ -642,10 +862,10 @@ void MyFrame::OnContextMenu( wxDataViewEvent &event ) menu.Append( 2, wxT("entry 2") ); menu.Append( 3, wxT("entry 3") ); - m_myMusicModelViewCtrl->PopupMenu(&menu); + m_ctrl[0]->PopupMenu(&menu); -// wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, Item: %s Value: %s"), -// title.GetData(), event.GetValue().GetString()); + wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, Item: %s Value: %s"), + title.GetData(), event.GetValue().GetString()); } void MyFrame::OnHeaderClick( wxDataViewEvent &event ) @@ -654,10 +874,10 @@ void MyFrame::OnHeaderClick( wxDataViewEvent &event ) // this column when it is clicked to take place event.Skip(); - if(!m_log) + if (!m_log) return; - int pos = m_myMusicModelViewCtrl->GetColumnPosition( event.GetDataViewColumn() ); + int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d"), pos ); } @@ -667,7 +887,7 @@ void MyFrame::OnHeaderRightClick( wxDataViewEvent &event ) if(!m_log) return; - int pos = m_myMusicModelViewCtrl->GetColumnPosition( event.GetDataViewColumn() ); + int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column position: %d"), pos ); } @@ -677,7 +897,7 @@ void MyFrame::OnSorted( wxDataViewEvent &event ) if(!m_log) return; - int pos = m_myMusicModelViewCtrl->GetColumnPosition( event.GetDataViewColumn() ); + int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); wxLogMessage(wxT("wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, Column position: %d"), pos ); } @@ -691,79 +911,32 @@ void MyFrame::OnRightClick( wxMouseEvent &event ) event.GetX(), event.GetY()); } -void MyFrame::OnGoto(wxCommandEvent& WXUNUSED(event)) -{ - wxDataViewItem item = m_list_model->GetItem( 50 ); - m_myListModelViewCtrl->EnsureVisible(item,m_col); -} - -void MyFrame::OnAddMany(wxCommandEvent& WXUNUSED(event)) -{ - m_list_model->AddMany(); -} +// ---------------------------------------------------------------------------- +// MyFrame - event handlers for the second page +// ---------------------------------------------------------------------------- -void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) ) +void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) ) { - wxAboutDialogInfo info; - info.SetName(_("DataView sample")); - info.SetDescription(_("This sample demonstrates wxDataViewCtrl")); - info.SetCopyright(_T("(C) 2007-2009 Robert Roebling")); - info.AddDeveloper("Robert Roebling"); - info.AddDeveloper("Francesco Montorsi"); - - wxAboutBox(info); + m_list_model->Prepend(wxT("Test")); } -void MyFrame::OnBeginDrag( wxDataViewEvent &event ) +void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) ) { - wxDataViewItem item( event.GetItem() ); - - // only allow drags for item, not containers - if (m_music_model->IsContainer( item ) ) - { - event.Veto(); - return; - } - - MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); - wxTextDataObject *obj = new wxTextDataObject; - obj->SetText( node->m_title ); - event.SetDataObject( obj ); + wxDataViewItemArray items; + int len = m_ctrl[1]->GetSelections( items ); + if (len > 0) + m_list_model->DeleteItems( items ); } -void MyFrame::OnDropPossible( wxDataViewEvent &event ) +void MyFrame::OnGoto(wxCommandEvent& WXUNUSED(event)) { - wxDataViewItem item( event.GetItem() ); - - // only allow drags for item, not containers - if (m_music_model->IsContainer( item ) ) - event.Veto(); - - if (event.GetDataFormat() != wxDF_UNICODETEXT) - event.Veto(); + wxDataViewItem item = m_list_model->GetItem( 50 ); + m_ctrl[1]->EnsureVisible(item,m_col); } -void MyFrame::OnDrop( wxDataViewEvent &event ) +void MyFrame::OnAddMany(wxCommandEvent& WXUNUSED(event)) { - wxDataViewItem item( event.GetItem() ); - - // only allow drops for item, not containers - if (m_music_model->IsContainer( item ) ) - { - event.Veto(); - return; - } - - if (event.GetDataFormat() != wxDF_UNICODETEXT) - { - event.Veto(); - return; - } - - wxTextDataObject obj; - obj.SetData( wxDF_TEXT, event.GetDataSize(), event.GetDataBuffer() ); - - wxLogMessage(wxT("Text dropped: %s"), obj.GetText() ); + m_list_model->AddMany(); } diff --git a/samples/dataview/mymodels.cpp b/samples/dataview/mymodels.cpp index 75d687bdf1..282e4e8a87 100644 --- a/samples/dataview/mymodels.cpp +++ b/samples/dataview/mymodels.cpp @@ -29,6 +29,7 @@ // ---------------------------------------------------------------------------- #include "null.xpm" +#include "wx_small.xpm" // ---------------------------------------------------------------------------- @@ -38,26 +39,31 @@ MyMusicTreeModel::MyMusicTreeModel() { m_root = new MyMusicTreeModelNode( NULL, wxT("My Music" )); + + // setup pop music m_pop = new MyMusicTreeModelNode( m_root, wxT("Pop music") ); + m_pop->Append( + new MyMusicTreeModelNode( m_pop, wxT("You are not alone"), wxT("Michael Jackson"), 1995 ) ); + m_pop->Append( + new MyMusicTreeModelNode( m_pop, wxT("Take a bow"), wxT("Madonna"), 1994 ) ); m_root->Append( m_pop ); - m_pop->Append( new MyMusicTreeModelNode( m_pop, - wxT("You are not alone"), wxT("Michael Jackson"), 1995 ) ); - m_pop->Append( new MyMusicTreeModelNode( m_pop, - wxT("Take a bow"), wxT("Madonna"), 1994 ) ); + + // setup classical music m_classical = new MyMusicTreeModelNode( m_root, wxT("Classical music") ); - m_root->Append( m_classical ); - m_ninth = new MyMusicTreeModelNode( m_classical, - wxT("Ninth symphony"), wxT("Ludwig van Beethoven"), 1824 ); + m_ninth = new MyMusicTreeModelNode( m_classical, wxT("Ninth symphony"), + wxT("Ludwig van Beethoven"), 1824 ); m_classical->Append( m_ninth ); - m_classical->Append( new MyMusicTreeModelNode( m_classical, - wxT("German Requiem"), wxT("Johannes Brahms"), 1868 ) ); + m_classical->Append( new MyMusicTreeModelNode( m_classical, wxT("German Requiem"), + wxT("Johannes Brahms"), 1868 ) ); + m_root->Append( m_classical ); + m_classicalMusicIsKnownToControl = false; } wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const { MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); - if (!node) + if (!node) // happens if item.IsOk()==false return wxEmptyString; return node->m_title; @@ -66,18 +72,27 @@ wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const { MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); - if (!node) + if (!node) // happens if item.IsOk()==false return 2000; return node->m_year; } -void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist, int year ) +void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist, + unsigned int year ) { - // add to data + if (!m_classical) + { + wxASSERT(m_root); + + // it was removed: restore it + m_classical = new MyMusicTreeModelNode( m_root, wxT("Classical music") ); + m_root->Append( m_classical ); + } + + // add to the classical music node a new node: MyMusicTreeModelNode *child_node = new MyMusicTreeModelNode( m_classical, title, artist, year ); - m_classical->Append( child_node ); if (m_classicalMusicIsKnownToControl) @@ -92,9 +107,33 @@ void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &ar void MyMusicTreeModel::Delete( const wxDataViewItem &item ) { MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); + if (!node) // happens if item.IsOk()==false + return; + wxDataViewItem parent( node->GetParent() ); + if (!parent.IsOk()) + { + wxASSERT(node == m_root); + // don't make the control completely empty: + wxLogError("Cannot remove the root item!"); + return; + } + + // is the node one of those we keep stored in special pointers? + if (node == m_pop) + m_pop = NULL; + else if (node == m_classical) + m_classical = NULL; + else if (node == m_ninth) + m_ninth = NULL; + + // first remove the node from the parent's array of children; + // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_ + // thus removing the node from it doesn't result in freeing it node->GetParent()->GetChildren().Remove( node ); + + // free the node delete node; // notify control @@ -104,9 +143,12 @@ void MyMusicTreeModel::Delete( const wxDataViewItem &item ) int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2, unsigned int column, bool ascending ) { + wxASSERT(item1.IsOk() && item2.IsOk()); + // should never happen + if (IsContainer(item1) && IsContainer(item2)) { - wxVariant value1,value2; + wxVariant value1, value2; GetValue( value1, item1, 0 ); GetValue( value2, item2, 0 ); @@ -128,60 +170,73 @@ int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem void MyMusicTreeModel::GetValue( wxVariant &variant, const wxDataViewItem &item, unsigned int col ) const { + wxASSERT(item.IsOk()); + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); switch (col) { - case 0: variant = node->m_title; break; - case 1: variant = node->m_artist; break; - case 2: variant = (long) node->m_year; break; - case 3: variant = node->m_quality; break; - case 4: - // wxMac doesn't conceal the popularity progress renderer, return 0 for containers - if (IsContainer(item)) - variant = (long) 0; - else - variant = (long) 80; // all music is very 80% popular - break; - case 5: - // Make size of red square depend on year - if (GetYear(item) < 1900) - variant = (long) 35; - else - variant = (long) 25; - break; - default: - { - wxLogError( wxT("MyMusicTreeModel::GetValue: wrong column %d"), col ); - - // provoke a crash when mouse button down - wxMouseState state = wxGetMouseState(); - if (state.ShiftDown()) - { - char *crash = 0; - *crash = 0; - } - } + case 0: + variant = node->m_title; + break; + case 1: + variant = node->m_artist; + break; + case 2: + variant = (long) node->m_year; + break; + case 3: + variant = node->m_quality; + break; + case 4: + // wxMac doesn't conceal the popularity progress renderer, return 0 for containers + if (IsContainer(item)) + variant = (long) 0; + else + variant = (long) 80; // all music is very 80% popular + break; + case 5: + // Make size of red square depend on year + if (GetYear(item) < 1900) + variant = (long) 35; + else + variant = (long) 25; + break; + + default: + wxLogError( wxT("MyMusicTreeModel::GetValue: wrong column %d"), col ); } } bool MyMusicTreeModel::SetValue( const wxVariant &variant, const wxDataViewItem &item, unsigned int col ) { + wxASSERT(item.IsOk()); + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID(); switch (col) { - case 0: node->m_title = variant.GetString(); return true; - case 1: node->m_artist = variant.GetString(); return true; - case 2: node->m_year = variant.GetLong(); return true; - case 3: node->m_quality = variant.GetString(); return true; - default: wxLogError( wxT("MyMusicTreeModel::SetValue: wrong column") ); + case 0: + node->m_title = variant.GetString(); + return true; + case 1: + node->m_artist = variant.GetString(); + return true; + case 2: + node->m_year = variant.GetLong(); + return true; + case 3: + node->m_quality = variant.GetString(); + return true; + + default: + wxLogError( wxT("MyMusicTreeModel::SetValue: wrong column") ); } return false; } wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const { - // the invisble root node has no parent + // the invisible root node has no parent if (!item.IsOk()) return wxDataViewItem(0); @@ -196,8 +251,8 @@ wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const { - // the invisble root node can have children (in - // our model always "MyMusic") + // the invisble root node can have children + // (in our model always "MyMusic") if (!item.IsOk()) return true; @@ -205,7 +260,8 @@ bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const return node->IsContainer(); } -unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent, wxDataViewItemArray &array ) const +unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent, + wxDataViewItemArray &array ) const { MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID(); if (!node) @@ -226,12 +282,12 @@ unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent, wxData } unsigned int count = node->GetChildren().GetCount(); - unsigned int pos; - for (pos = 0; pos < count; pos++) + for (unsigned int pos = 0; pos < count; pos++) { MyMusicTreeModelNode *child = node->GetChildren().Item( pos ); array.Add( wxDataViewItem( (void*) child ) ); } + return count; } @@ -251,28 +307,28 @@ static int my_sort( int *v1, int *v2 ) return *v1-*v2; } -MyListModel::MyListModel() : #ifdef __WXMAC__ - wxDataViewVirtualListModel( 1000 + 100 ) + #define INITIAL_NUMBER_OF_ITEMS 100 #else - wxDataViewVirtualListModel( 100000 + 100 ) + #define INITIAL_NUMBER_OF_ITEMS 100000 #endif + +MyListModel::MyListModel() : + wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS ) { -#ifdef __WXMAC__ - m_virtualItems = 1000; -#else - m_virtualItems = 100000; -#endif + m_virtualItems = INITIAL_NUMBER_OF_ITEMS; - unsigned int i; - for (i = 0; i < 100; i++) + // the first 100 items are really stored in this model; + // all the others are synthetized on request + for (unsigned int i = 0; i < 100; i++) { wxString str; - str.Printf( wxT("row number %d"), i ); + str.Printf( wxT("real row %d"), i ); m_array.Add( str ); } - m_icon = wxIcon( null_xpm ); + m_icon[0] = wxIcon( null_xpm ); + m_icon[1] = wxIcon( wx_small_xpm ); } void MyListModel::Prepend( const wxString &text ) @@ -294,14 +350,21 @@ void MyListModel::DeleteItem( const wxDataViewItem &item ) void MyListModel::DeleteItems( const wxDataViewItemArray &items ) { wxArrayInt rows; - unsigned int i; - for (i = 0; i < items.GetCount(); i++) + for (unsigned int i = 0; i < items.GetCount(); i++) { unsigned int row = GetRow( items[i] ); if (row < m_array.GetCount()) rows.Add( row ); } + if (rows.GetCount() == 0) + { + // none of the selected items were in the range of the items + // which we store... for simplicity, don't allow removing them + wxLogError("Cannot remove rows with an index greater than %d", m_array.GetCount()); + return; + } + // Sort in descending order so that the last // row will be deleted first. Otherwise the // remaining indeces would all be wrong. @@ -328,39 +391,35 @@ void MyListModel::GetValueByRow( wxVariant &variant, if (col==0) { if (row >= m_array.GetCount()) - { - wxString str; - str.Printf(wxT("row %d"), row - m_array.GetCount() ); - variant = str; - } + variant = wxString::Format( wxT("virtual row %d"), row ); else - { variant = m_array[ row ]; - } - } else - if (col==1) + } + else if (col==1) { - wxDataViewIconText data( wxT("test"), m_icon ); + wxDataViewIconText data( wxT("test"), m_icon[ row%2 ] ); variant << data; - } else - if (col==2) + } + else if (col==2) { if (row >= m_array.GetCount()) variant = wxT("plain"); else - variant = wxT("blue"); + variant = wxT("blue/green/red"); } } -bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col, wxDataViewItemAttr &attr ) +bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col, + wxDataViewItemAttr &attr ) { if (col != 2) return false; if (row < m_array.GetCount()) { - attr.SetColour( *wxBLUE ); - attr.SetItalic( true ); + attr.SetColour( (row%2) == 0 ? *wxBLUE : + ((row%3) == 0 ? *wxGREEN : *wxRED) ); + attr.SetItalic( (row%2) == 5 ); } return true; @@ -372,7 +431,12 @@ bool MyListModel::SetValueByRow( const wxVariant &variant, if (col == 0) { if (row >= m_array.GetCount()) + { + // the item is not in the range of the items + // which we store... for simplicity, don't allow editing it + wxLogError("Cannot edit rows with an index greater than %d", m_array.GetCount()); return false; + } m_array[row] = variant.GetString(); return true; diff --git a/samples/dataview/mymodels.h b/samples/dataview/mymodels.h index 2591c86e71..c55e8b2184 100644 --- a/samples/dataview/mymodels.h +++ b/samples/dataview/mymodels.h @@ -11,80 +11,92 @@ // ---------------------------------------------------------------------------- -// MyMusicTreeModel +// MyMusicTreeModelNode: a node inside MyMusicTreeModel // ---------------------------------------------------------------------------- -/* -Implement this data model - Title Artist Year Judgement --------------------------------------------------------------------------- -1: My Music: - 2: Pop music - 3: You are not alone Michael Jackson 1995 good - 4: Take a bow Madonna 1994 good - 5: Classical music - 6: Ninth Symphony Ludwig v. Beethoven 1824 good - 7: German Requiem Johannes Brahms 1868 good -*/ - class MyMusicTreeModelNode; -WX_DEFINE_ARRAY_PTR( MyMusicTreeModelNode*, MyMusicTreeModelNodes ); +WX_DEFINE_ARRAY_PTR( MyMusicTreeModelNode*, MyMusicTreeModelNodePtrArray ); class MyMusicTreeModelNode { public: MyMusicTreeModelNode( MyMusicTreeModelNode* parent, - const wxString &title, const wxString &artist, int year ) + const wxString &title, const wxString &artist, + unsigned int year ) { m_parent = parent; + m_title = title; m_artist = artist; m_year = year; m_quality = "good"; - m_isContainer = false; } MyMusicTreeModelNode( MyMusicTreeModelNode* parent, - const wxString &branch ) + const wxString &branch ) { m_parent = parent; + m_title = branch; m_year = -1; - m_isContainer = true; } ~MyMusicTreeModelNode() { + // free all our children nodes size_t count = m_children.GetCount(); - size_t i; - for (i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) { MyMusicTreeModelNode *child = m_children[i]; delete child; } } - bool IsContainer() { return m_isContainer; } - - MyMusicTreeModelNode* GetParent() { return m_parent; } - MyMusicTreeModelNodes &GetChildren() { return m_children; } - MyMusicTreeModelNode* GetNthChild( unsigned int n ) { return m_children.Item( n ); } - void Insert( MyMusicTreeModelNode* child, unsigned int n) { m_children.Insert( child, n); } - void Append( MyMusicTreeModelNode* child ) { m_children.Add( child ); } - unsigned int GetChildCount() { return m_children.GetCount(); } - -public: - wxString m_title; - wxString m_artist; - int m_year; - wxString m_quality; + bool IsContainer() const + { return m_children.GetCount()>0; } + + MyMusicTreeModelNode* GetParent() + { return m_parent; } + MyMusicTreeModelNodePtrArray& GetChildren() + { return m_children; } + MyMusicTreeModelNode* GetNthChild( unsigned int n ) + { return m_children.Item( n ); } + void Insert( MyMusicTreeModelNode* child, unsigned int n) + { m_children.Insert( child, n); } + void Append( MyMusicTreeModelNode* child ) + { m_children.Add( child ); } + unsigned int GetChildCount() const + { return m_children.GetCount(); } + +public: // public to avoid getters/setters + wxString m_title; + wxString m_artist; + int m_year; + wxString m_quality; private: - MyMusicTreeModelNode *m_parent; - MyMusicTreeModelNodes m_children; - bool m_isContainer; + MyMusicTreeModelNode *m_parent; + MyMusicTreeModelNodePtrArray m_children; }; + +// ---------------------------------------------------------------------------- +// MyMusicTreeModel +// ---------------------------------------------------------------------------- + +/* +Implement this data model + Title Artist Year Judgement +-------------------------------------------------------------------------- +1: My Music: + 2: Pop music + 3: You are not alone Michael Jackson 1995 good + 4: Take a bow Madonna 1994 good + 5: Classical music + 6: Ninth Symphony Ludwig v. Beethoven 1824 good + 7: German Requiem Johannes Brahms 1868 good +*/ + class MyMusicTreeModel: public wxDataViewModel { public: @@ -101,9 +113,15 @@ public: // helper methods to change the model - void AddToClassical( const wxString &title, const wxString &artist, int year ); + void AddToClassical( const wxString &title, const wxString &artist, + unsigned int year ); void Delete( const wxDataViewItem &item ); + wxDataViewItem GetNinthItem() const + { + return wxDataViewItem( m_ninth ); + } + // override sorting to always sort branches ascendingly int Compare( const wxDataViewItem &item1, const wxDataViewItem &item2, @@ -134,16 +152,15 @@ public: virtual unsigned int GetChildren( const wxDataViewItem &parent, wxDataViewItemArray &array ) const; - wxDataViewItem GetNinthItem() const - { - return wxDataViewItem( m_ninth ); - } - private: MyMusicTreeModelNode* m_root; + + // pointers to some "special" nodes of the tree: MyMusicTreeModelNode* m_pop; MyMusicTreeModelNode* m_classical; MyMusicTreeModelNode* m_ninth; + + // ?? bool m_classicalMusicIsKnownToControl; }; @@ -193,7 +210,7 @@ public: private: wxArrayString m_array; - wxIcon m_icon; + wxIcon m_icon[2]; int m_virtualItems; }; -- 2.47.2