Merge branch 'dvc-inconsist-fixes'

Fix several inconsistencies in wxDVC between wxGTK and the other
implementations.

See https://github.com/wxWidgets/wxWidgets/pull/1547
This commit is contained in:
Vadim Zeitlin
2019-09-18 14:33:34 +02:00
4 changed files with 281 additions and 159 deletions

View File

@@ -52,6 +52,10 @@
- wxDataViewModel::ItemsDeleted, - wxDataViewModel::ItemsDeleted,
- wxDataViewModel::ItemsChanged. - wxDataViewModel::ItemsChanged.
Note that Cleared() can be called for all changes involving many, or all,
of the model items and not only for deleting all of them (i.e. clearing the
model).
This class maintains a list of wxDataViewModelNotifier which link this class This class maintains a list of wxDataViewModelNotifier which link this class
to the specific implementations on the supported platforms so that e.g. calling to the specific implementations on the supported platforms so that e.g. calling
wxDataViewModel::ValueChanged on this model will just call wxDataViewModel::ValueChanged on this model will just call
@@ -129,8 +133,16 @@ public:
unsigned int col); unsigned int col);
/** /**
Called to inform the model that all data has been cleared. Called to inform the model that all of its data has been changed.
The control will reread the data from the model again.
This method should be called if so many of the model items have
changed, that the control should just reread all of them, repopulating
itself entirely.
Note that, contrary to the name of the method, it doesn't necessarily
indicate that model has become empty -- although this is the right
method to call, rather than ItemsDeleted(), if it was indeed cleared,
which explains the origin of its name.
*/ */
bool Cleared(); bool Cleared();

View File

@@ -118,6 +118,11 @@ private:
void OnAddTreeItem(wxCommandEvent& event); void OnAddTreeItem(wxCommandEvent& event);
void OnAddTreeContainerItem(wxCommandEvent& event); void OnAddTreeContainerItem(wxCommandEvent& event);
void OnIndexListUseEnglish(wxCommandEvent&) { FillIndexList(Lang_English); }
void OnIndexListUseFrench(wxCommandEvent&) { FillIndexList(Lang_French); }
void OnIndexListResetModel(wxCommandEvent& event);
void OnIndexListSelectionChanged(wxDataViewEvent& event);
void OnValueChanged( wxDataViewEvent &event ); void OnValueChanged( wxDataViewEvent &event );
void OnActivated( wxDataViewEvent &event ); void OnActivated( wxDataViewEvent &event );
@@ -160,18 +165,34 @@ private:
// helper used by both OnDeleteSelected() and OnDataViewChar() // helper used by both OnDeleteSelected() and OnDataViewChar()
void DeleteSelectedItems(); void DeleteSelectedItems();
// helper for the index list model fills the model with the weekday names
// in the specified language
enum Lang { Lang_English, Lang_French };
void FillIndexList(Lang lang);
wxNotebook* m_notebook; wxNotebook* m_notebook;
// the controls stored in the various tabs of the main notebook: // the controls stored in the various tabs of the main notebook:
enum Page
{
Page_Music,
Page_List,
Page_ListStore,
Page_TreeStore,
Page_VarHeight,
Page_IndexList,
Page_Max
};
wxDataViewCtrl* m_ctrl[5]; wxDataViewCtrl* m_ctrl[Page_Max];
// the models associated with the first two DVC: // Some of the models associated with the controls:
wxObjectDataPtr<MyMusicTreeModel> m_music_model; wxObjectDataPtr<MyMusicTreeModel> m_music_model;
wxObjectDataPtr<MyLongMusicTreeModel> m_long_music_model; wxObjectDataPtr<MyLongMusicTreeModel> m_long_music_model;
wxObjectDataPtr<MyListModel> m_list_model; wxObjectDataPtr<MyListModel> m_list_model;
wxObjectDataPtr<MyIndexListModel> m_index_list_model;
// other data: // other data:
@@ -418,7 +439,12 @@ enum
ID_DELETE_TREE_ITEM = 400, ID_DELETE_TREE_ITEM = 400,
ID_DELETE_ALL_TREE_ITEMS = 401, ID_DELETE_ALL_TREE_ITEMS = 401,
ID_ADD_TREE_ITEM = 402, ID_ADD_TREE_ITEM = 402,
ID_ADD_TREE_CONTAINER_ITEM = 403 ID_ADD_TREE_CONTAINER_ITEM = 403,
// Index list model page
ID_INDEX_LIST_USE_ENGLISH = 500,
ID_INDEX_LIST_USE_FRENCH,
ID_INDEX_LIST_RESET_MODEL
}; };
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
@@ -465,6 +491,10 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_BUTTON( ID_ADD_TREE_ITEM, MyFrame::OnAddTreeItem ) EVT_BUTTON( ID_ADD_TREE_ITEM, MyFrame::OnAddTreeItem )
EVT_BUTTON( ID_ADD_TREE_CONTAINER_ITEM, MyFrame::OnAddTreeContainerItem ) EVT_BUTTON( ID_ADD_TREE_CONTAINER_ITEM, MyFrame::OnAddTreeContainerItem )
EVT_BUTTON( ID_INDEX_LIST_USE_ENGLISH, MyFrame::OnIndexListUseEnglish )
EVT_BUTTON( ID_INDEX_LIST_USE_FRENCH, MyFrame::OnIndexListUseFrench )
EVT_BUTTON( ID_INDEX_LIST_RESET_MODEL, MyFrame::OnIndexListResetModel )
EVT_DATAVIEW_ITEM_VALUE_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged ) EVT_DATAVIEW_ITEM_VALUE_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged )
EVT_DATAVIEW_ITEM_ACTIVATED(ID_MUSIC_CTRL, MyFrame::OnActivated ) EVT_DATAVIEW_ITEM_ACTIVATED(ID_MUSIC_CTRL, MyFrame::OnActivated )
@@ -503,11 +533,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
m_log = NULL; m_log = NULL;
m_col = NULL; m_col = NULL;
m_ctrl[0] = NULL; for ( int page = 0; page < Page_Max; ++page )
m_ctrl[1] = NULL; m_ctrl[page] = NULL;
m_ctrl[2] = NULL;
m_ctrl[3] = NULL;
m_ctrl[4] = NULL;
m_eventFromProgram = false; m_eventFromProgram = false;
@@ -566,7 +593,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxPanel *firstPanel = new wxPanel( m_notebook, wxID_ANY ); wxPanel *firstPanel = new wxPanel( m_notebook, wxID_ANY );
BuildDataViewCtrl(firstPanel, 0); // sets m_ctrl[0] BuildDataViewCtrl(firstPanel, Page_Music);
const wxSizerFlags border = wxSizerFlags().DoubleBorder(); const wxSizerFlags border = wxSizerFlags().DoubleBorder();
@@ -587,8 +614,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
"Change ninth &title"), border); "Change ninth &title"), border);
wxSizer *firstPanelSz = new wxBoxSizer( wxVERTICAL ); wxSizer *firstPanelSz = new wxBoxSizer( wxVERTICAL );
m_ctrl[0]->SetMinSize(wxSize(-1, 200)); m_ctrl[Page_Music]->SetMinSize(wxSize(-1, 200));
firstPanelSz->Add(m_ctrl[0], 1, wxGROW|wxALL, 5); firstPanelSz->Add(m_ctrl[Page_Music], 1, wxGROW|wxALL, 5);
firstPanelSz->Add( firstPanelSz->Add(
new wxStaticText(firstPanel, wxID_ANY, "Most of the cells above are editable!"), new wxStaticText(firstPanel, wxID_ANY, "Most of the cells above are editable!"),
0, wxGROW|wxALL, 5); 0, wxGROW|wxALL, 5);
@@ -602,7 +629,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxPanel *secondPanel = new wxPanel( m_notebook, wxID_ANY ); wxPanel *secondPanel = new wxPanel( m_notebook, wxID_ANY );
BuildDataViewCtrl(secondPanel, 1); // sets m_ctrl[1] BuildDataViewCtrl(secondPanel, Page_List);
wxBoxSizer *button_sizer2 = new wxBoxSizer( wxHORIZONTAL ); wxBoxSizer *button_sizer2 = new wxBoxSizer( wxHORIZONTAL );
button_sizer2->Add( new wxButton( secondPanel, ID_PREPEND_LIST,"Prepend"), 0, wxALL, 10 ); button_sizer2->Add( new wxButton( secondPanel, ID_PREPEND_LIST,"Prepend"), 0, wxALL, 10 );
@@ -619,7 +646,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxSizerFlags().Centre().DoubleBorder()); wxSizerFlags().Centre().DoubleBorder());
wxSizer *secondPanelSz = new wxBoxSizer( wxVERTICAL ); wxSizer *secondPanelSz = new wxBoxSizer( wxVERTICAL );
secondPanelSz->Add(m_ctrl[1], 1, wxGROW|wxALL, 5); secondPanelSz->Add(m_ctrl[Page_List], 1, wxGROW|wxALL, 5);
secondPanelSz->Add(button_sizer2); secondPanelSz->Add(button_sizer2);
secondPanelSz->Add(sortSizer); secondPanelSz->Add(sortSizer);
secondPanel->SetSizerAndFit(secondPanelSz); secondPanel->SetSizerAndFit(secondPanelSz);
@@ -630,10 +657,10 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxPanel *thirdPanel = new wxPanel( m_notebook, wxID_ANY ); wxPanel *thirdPanel = new wxPanel( m_notebook, wxID_ANY );
BuildDataViewCtrl(thirdPanel, 2); // sets m_ctrl[2] BuildDataViewCtrl(thirdPanel, Page_ListStore);
wxSizer *thirdPanelSz = new wxBoxSizer( wxVERTICAL ); wxSizer *thirdPanelSz = new wxBoxSizer( wxVERTICAL );
thirdPanelSz->Add(m_ctrl[2], 1, wxGROW|wxALL, 5); thirdPanelSz->Add(m_ctrl[Page_ListStore], 1, wxGROW|wxALL, 5);
thirdPanel->SetSizerAndFit(thirdPanelSz); thirdPanel->SetSizerAndFit(thirdPanelSz);
@@ -642,7 +669,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxPanel *fourthPanel = new wxPanel( m_notebook, wxID_ANY ); wxPanel *fourthPanel = new wxPanel( m_notebook, wxID_ANY );
BuildDataViewCtrl(fourthPanel, 3); // sets m_ctrl[3] BuildDataViewCtrl(fourthPanel, Page_TreeStore);
// Buttons // Buttons
wxBoxSizer *button_sizer4 = new wxBoxSizer( wxHORIZONTAL ); wxBoxSizer *button_sizer4 = new wxBoxSizer( wxHORIZONTAL );
button_sizer4->Add( new wxButton( fourthPanel, ID_DELETE_TREE_ITEM, "Delete Selected"), 0, wxALL, 10 ); button_sizer4->Add( new wxButton( fourthPanel, ID_DELETE_TREE_ITEM, "Delete Selected"), 0, wxALL, 10 );
@@ -651,7 +678,7 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
button_sizer4->Add( new wxButton( fourthPanel, ID_ADD_TREE_CONTAINER_ITEM, "Add Container"), 0, wxALL, 10 ); button_sizer4->Add( new wxButton( fourthPanel, ID_ADD_TREE_CONTAINER_ITEM, "Add Container"), 0, wxALL, 10 );
wxSizer *fourthPanelSz = new wxBoxSizer( wxVERTICAL ); wxSizer *fourthPanelSz = new wxBoxSizer( wxVERTICAL );
fourthPanelSz->Add(m_ctrl[3], 1, wxGROW|wxALL, 5); fourthPanelSz->Add(m_ctrl[Page_TreeStore], 1, wxGROW|wxALL, 5);
fourthPanelSz->Add(button_sizer4); fourthPanelSz->Add(button_sizer4);
fourthPanel->SetSizerAndFit(fourthPanelSz); fourthPanel->SetSizerAndFit(fourthPanelSz);
@@ -660,12 +687,32 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
wxPanel *fifthPanel = new wxPanel(m_notebook, wxID_ANY); wxPanel *fifthPanel = new wxPanel(m_notebook, wxID_ANY);
BuildDataViewCtrl(fifthPanel, 4); // sets m_ctrl[4] BuildDataViewCtrl(fifthPanel, Page_VarHeight);
wxSizer *fifthPanelSz = new wxBoxSizer(wxVERTICAL); wxSizer *fifthPanelSz = new wxBoxSizer(wxVERTICAL);
fifthPanelSz->Add(m_ctrl[4], 1, wxGROW | wxALL, 5); fifthPanelSz->Add(m_ctrl[Page_VarHeight], 1, wxGROW | wxALL, 5);
fifthPanel->SetSizerAndFit(fifthPanelSz); fifthPanel->SetSizerAndFit(fifthPanelSz);
// page showing the indexed list model
// -----------------------------------
wxPanel* sixthPanel = new wxPanel(m_notebook, wxID_ANY);
BuildDataViewCtrl(sixthPanel, Page_IndexList);
wxBoxSizer *button_sizer6 = new wxBoxSizer(wxHORIZONTAL);
button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_USE_ENGLISH, "&English"),
wxSizerFlags().DoubleBorder());
button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_USE_FRENCH, "&French"),
wxSizerFlags().DoubleBorder());
button_sizer6->Add(new wxButton(sixthPanel, ID_INDEX_LIST_RESET_MODEL, "Reset &model"),
wxSizerFlags().DoubleBorder());
wxSizer *sixthPanelSz = new wxBoxSizer(wxVERTICAL);
sixthPanelSz->Add(m_ctrl[Page_IndexList], wxSizerFlags(1).Expand().Border());
sixthPanelSz->Add(button_sizer6);
sixthPanel->SetSizerAndFit(sixthPanelSz);
// complete GUI // complete GUI
// ------------ // ------------
@@ -674,7 +721,8 @@ MyFrame::MyFrame(wxFrame *frame, const wxString &title, int x, int y, int w, int
m_notebook->AddPage(secondPanel, "MyListModel"); m_notebook->AddPage(secondPanel, "MyListModel");
m_notebook->AddPage(thirdPanel, "wxDataViewListCtrl"); m_notebook->AddPage(thirdPanel, "wxDataViewListCtrl");
m_notebook->AddPage(fourthPanel, "wxDataViewTreeCtrl"); m_notebook->AddPage(fourthPanel, "wxDataViewTreeCtrl");
m_notebook->AddPage(fifthPanel, "wxDataViewTreeCtrl Variable line height"); m_notebook->AddPage(fifthPanel, "Variable line height");
m_notebook->AddPage(sixthPanel, "MyIndexListModel");
wxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); wxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
@@ -691,22 +739,23 @@ MyFrame::~MyFrame()
void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned long style) void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned long style)
{ {
wxASSERT(!m_ctrl[nPanel]); // should only be initialized once
switch (nPanel) switch (nPanel)
{ {
case 0: case Page_Music:
{ {
wxASSERT(!m_ctrl[0] && !m_music_model); m_ctrl[Page_Music] =
m_ctrl[0] =
new wxDataViewCtrl( parent, ID_MUSIC_CTRL, wxDefaultPosition, new wxDataViewCtrl( parent, ID_MUSIC_CTRL, wxDefaultPosition,
wxDefaultSize, style ); wxDefaultSize, style );
m_ctrl[0]->Bind(wxEVT_CHAR, &MyFrame::OnDataViewChar, this); m_ctrl[Page_Music]->Bind(wxEVT_CHAR, &MyFrame::OnDataViewChar, this);
m_music_model = new MyMusicTreeModel; m_music_model = new MyMusicTreeModel;
m_ctrl[0]->AssociateModel( m_music_model.get() ); m_ctrl[Page_Music]->AssociateModel( m_music_model.get() );
#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE #if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
m_ctrl[0]->EnableDragSource( wxDF_UNICODETEXT ); m_ctrl[Page_Music]->EnableDragSource( wxDF_UNICODETEXT );
m_ctrl[0]->EnableDropTarget( wxDF_UNICODETEXT ); m_ctrl[Page_Music]->EnableDropTarget( wxDF_UNICODETEXT );
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
// column 0 of the view control: // column 0 of the view control:
@@ -716,7 +765,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
wxDataViewColumn *column0 = wxDataViewColumn *column0 =
new wxDataViewColumn( "title", tr, 0, 200, wxALIGN_LEFT, new wxDataViewColumn( "title", tr, 0, 200, wxALIGN_LEFT,
wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE );
m_ctrl[0]->AppendColumn( column0 ); m_ctrl[Page_Music]->AppendColumn( column0 );
#if 0 #if 0
// Call this and sorting is enabled // Call this and sorting is enabled
// immediately upon start up. // immediately upon start up.
@@ -731,7 +780,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE |
wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_RESIZABLE );
column1->SetMinWidth(150); // this column can't be resized to be smaller column1->SetMinWidth(150); // this column can't be resized to be smaller
m_ctrl[0]->AppendColumn( column1 ); m_ctrl[Page_Music]->AppendColumn( column1 );
// column 2 of the view control: // column 2 of the view control:
@@ -741,7 +790,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
wxDataViewColumn *column2 = wxDataViewColumn *column2 =
new wxDataViewColumn( "year", sr, 2, 60, wxALIGN_LEFT, new wxDataViewColumn( "year", sr, 2, 60, wxALIGN_LEFT,
wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE ); wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE );
m_ctrl[0]->AppendColumn( column2 ); m_ctrl[Page_Music]->AppendColumn( column2 );
// column 3 of the view control: // column 3 of the view control:
@@ -755,11 +804,11 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
wxDataViewColumn *column3 = wxDataViewColumn *column3 =
new wxDataViewColumn( "rating", c, 3, 100, wxALIGN_LEFT, new wxDataViewColumn( "rating", c, 3, 100, wxALIGN_LEFT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE );
m_ctrl[0]->AppendColumn( column3 ); m_ctrl[Page_Music]->AppendColumn( column3 );
// column 4 of the view control: // column 4 of the view control:
m_ctrl[0]->AppendProgressColumn( "popularity", 4, wxDATAVIEW_CELL_INERT, 80 ); m_ctrl[Page_Music]->AppendProgressColumn( "popularity", 4, wxDATAVIEW_CELL_INERT, 80 );
// column 5 of the view control: // column 5 of the view control:
@@ -768,43 +817,42 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
new wxDataViewColumn( "custom", cr, 5, -1, wxALIGN_LEFT, new wxDataViewColumn( "custom", cr, 5, -1, wxALIGN_LEFT,
wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_RESIZABLE );
column5->SetBitmap(wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MENU)); column5->SetBitmap(wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MENU));
m_ctrl[0]->AppendColumn( column5 ); m_ctrl[Page_Music]->AppendColumn( column5 );
// select initially the ninth symphony: // select initially the ninth symphony:
m_ctrl[0]->Select(m_music_model->GetNinthItem()); m_ctrl[Page_Music]->Select(m_music_model->GetNinthItem());
} }
break; break;
case 1: case Page_List:
{ {
wxASSERT(!m_ctrl[1] && !m_list_model); m_ctrl[Page_List] = new wxDataViewCtrl( parent, ID_ATTR_CTRL, wxDefaultPosition,
m_ctrl[1] = new wxDataViewCtrl( parent, ID_ATTR_CTRL, wxDefaultPosition,
wxDefaultSize, style ); wxDefaultSize, style );
m_list_model = new MyListModel; m_list_model = new MyListModel;
m_ctrl[1]->AssociateModel( m_list_model.get() ); m_ctrl[Page_List]->AssociateModel( m_list_model.get() );
m_ctrl[1]->AppendToggleColumn(L"\u2714", m_ctrl[Page_List]->AppendToggleColumn(L"\u2714",
MyListModel::Col_Toggle, MyListModel::Col_Toggle,
wxDATAVIEW_CELL_ACTIVATABLE, wxDATAVIEW_CELL_ACTIVATABLE,
wxCOL_WIDTH_AUTOSIZE); wxCOL_WIDTH_AUTOSIZE);
// the various columns // the various columns
m_ctrl[1]->AppendTextColumn("editable string", m_ctrl[Page_List]->AppendTextColumn("editable string",
MyListModel::Col_EditableText, MyListModel::Col_EditableText,
wxDATAVIEW_CELL_EDITABLE, wxDATAVIEW_CELL_EDITABLE,
wxCOL_WIDTH_AUTOSIZE, wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT, wxALIGN_NOT,
wxDATAVIEW_COL_SORTABLE); wxDATAVIEW_COL_SORTABLE);
m_ctrl[1]->AppendIconTextColumn("icon", m_ctrl[Page_List]->AppendIconTextColumn("icon",
MyListModel::Col_IconText, MyListModel::Col_IconText,
wxDATAVIEW_CELL_EDITABLE, wxDATAVIEW_CELL_EDITABLE,
wxCOL_WIDTH_AUTOSIZE, wxCOL_WIDTH_AUTOSIZE,
wxALIGN_NOT, wxALIGN_NOT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_SORTABLE); wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_SORTABLE);
m_ctrl[1]->AppendDateColumn("date", m_ctrl[Page_List]->AppendDateColumn("date",
MyListModel::Col_Date); MyListModel::Col_Date);
wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer(); wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer();
@@ -818,9 +866,9 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
wxCOL_WIDTH_AUTOSIZE, wxCOL_WIDTH_AUTOSIZE,
wxALIGN_RIGHT, wxALIGN_RIGHT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE); wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE);
m_ctrl[1]->AppendColumn( m_attributes ); m_ctrl[Page_List]->AppendColumn( m_attributes );
m_ctrl[1]->AppendColumn( m_ctrl[Page_List]->AppendColumn(
new wxDataViewColumn("custom renderer", new wxDataViewColumn("custom renderer",
new MyCustomRenderer(wxDATAVIEW_CELL_EDITABLE), new MyCustomRenderer(wxDATAVIEW_CELL_EDITABLE),
MyListModel::Col_Custom) MyListModel::Col_Custom)
@@ -828,13 +876,12 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
} }
break; break;
case 2: case Page_ListStore:
{ {
wxASSERT(!m_ctrl[2]);
wxDataViewListCtrl* lc = wxDataViewListCtrl* lc =
new wxDataViewListCtrl( parent, wxID_ANY, wxDefaultPosition, new wxDataViewListCtrl( parent, wxID_ANY, wxDefaultPosition,
wxDefaultSize, style ); wxDefaultSize, style );
m_ctrl[2] = lc; m_ctrl[Page_ListStore] = lc;
MyListStoreDerivedModel* page2_model = new MyListStoreDerivedModel(); MyListStoreDerivedModel* page2_model = new MyListStoreDerivedModel();
lc->AssociateModel(page2_model); lc->AssociateModel(page2_model);
@@ -871,13 +918,12 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
} }
break; break;
case 3: case Page_TreeStore:
{ {
wxASSERT(!m_ctrl[3]);
wxDataViewTreeCtrl* tc = wxDataViewTreeCtrl* tc =
new wxDataViewTreeCtrl( parent, wxID_ANY, wxDefaultPosition, new wxDataViewTreeCtrl( parent, wxID_ANY, wxDefaultPosition,
wxDefaultSize, style | wxDV_NO_HEADER ); wxDefaultSize, style | wxDV_NO_HEADER );
m_ctrl[3] = tc; m_ctrl[Page_TreeStore] = tc;
wxImageList *ilist = new wxImageList( 16, 16 ); wxImageList *ilist = new wxImageList( 16, 16 );
ilist->Add( wxIcon(wx_small_xpm) ); ilist->Add( wxIcon(wx_small_xpm) );
@@ -898,34 +944,52 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
} }
break; break;
case 4: case Page_VarHeight:
{ {
wxASSERT(!m_ctrl[4] && !m_long_music_model); m_ctrl[Page_VarHeight] =
m_ctrl[4] = new wxDataViewCtrl( parent, wxID_ANY, wxDefaultPosition,
new wxDataViewCtrl( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style | wxDV_VARIABLE_LINE_HEIGHT );
wxDefaultSize, style | wxDV_VARIABLE_LINE_HEIGHT );
m_long_music_model = new MyLongMusicTreeModel; m_long_music_model = new MyLongMusicTreeModel;
m_ctrl[4]->AssociateModel(m_long_music_model.get()); m_ctrl[Page_VarHeight]->AssociateModel(m_long_music_model.get());
// column 0 of the view control: // column 0 of the view control:
MultiLineCustomRenderer *tr = MultiLineCustomRenderer *tr =
new MultiLineCustomRenderer(); new MultiLineCustomRenderer();
wxDataViewColumn *column0 = wxDataViewColumn *column0 =
new wxDataViewColumn("title", tr, 0, 200, wxALIGN_LEFT, new wxDataViewColumn("title", tr, 0, 200, wxALIGN_LEFT,
wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE);
m_ctrl[4]->AppendColumn(column0); m_ctrl[Page_VarHeight]->AppendColumn(column0);
// column 1 of the view control: // column 1 of the view control:
tr = new MultiLineCustomRenderer(); tr = new MultiLineCustomRenderer();
wxDataViewColumn *column1 = wxDataViewColumn *column1 =
new wxDataViewColumn("artist", tr, 1, 150, wxALIGN_LEFT, new wxDataViewColumn("artist", tr, 1, 150, wxALIGN_LEFT,
wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE |
wxDATAVIEW_COL_RESIZABLE); wxDATAVIEW_COL_RESIZABLE);
column1->SetMinWidth(150); // this column can't be resized to be smaller column1->SetMinWidth(150); // this column can't be resized to be smaller
m_ctrl[4]->AppendColumn(column1); m_ctrl[Page_VarHeight]->AppendColumn(column1);
} }
break; break;
case Page_IndexList:
{
m_ctrl[Page_IndexList] = new wxDataViewCtrl(parent, wxID_ANY,
wxDefaultPosition,
wxDefaultSize,
style);
m_index_list_model = new MyIndexListModel;
m_ctrl[Page_IndexList]->AssociateModel(m_index_list_model.get());
m_ctrl[Page_IndexList]->AppendTextColumn("String", 0);
FillIndexList(Lang_English);
m_ctrl[Page_IndexList]->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED,
&MyFrame::OnIndexListSelectionChanged,
this);
}
break;
} }
} }
@@ -1202,7 +1266,7 @@ void MyFrame::OnAddMozart( wxCommandEvent& WXUNUSED(event) )
void MyFrame::DeleteSelectedItems() void MyFrame::DeleteSelectedItems()
{ {
wxDataViewItemArray items; wxDataViewItemArray items;
int len = m_ctrl[0]->GetSelections( items ); int len = m_ctrl[Page_Music]->GetSelections( items );
for( int i = 0; i < len; i ++ ) for( int i = 0; i < len; i ++ )
if (items[i].IsOk()) if (items[i].IsOk())
m_music_model->Delete( items[i] ); m_music_model->Delete( items[i] );
@@ -1215,7 +1279,7 @@ void MyFrame::OnDeleteSelected( wxCommandEvent& WXUNUSED(event) )
void MyFrame::OnDeleteYear( wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnDeleteYear( wxCommandEvent& WXUNUSED(event) )
{ {
m_ctrl[0]->DeleteColumn( m_ctrl[0]->GetColumn( 2 ) ); m_ctrl[Page_Music]->DeleteColumn( m_ctrl[Page_Music]->GetColumn( 2 ) );
FindWindow( ID_DELETE_YEAR )->Disable(); FindWindow( ID_DELETE_YEAR )->Disable();
} }
@@ -1227,26 +1291,26 @@ void MyFrame::OnSelectNinth( wxCommandEvent& WXUNUSED(event) )
return; return;
} }
m_ctrl[0]->Select( m_music_model->GetNinthItem() ); m_ctrl[Page_Music]->Select( m_music_model->GetNinthItem() );
} }
void MyFrame::OnCollapse( wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnCollapse( wxCommandEvent& WXUNUSED(event) )
{ {
wxDataViewItem item = m_ctrl[0]->GetSelection(); wxDataViewItem item = m_ctrl[Page_Music]->GetSelection();
if (item.IsOk()) if (item.IsOk())
m_ctrl[0]->Collapse( item ); m_ctrl[Page_Music]->Collapse( item );
} }
void MyFrame::OnExpand( wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnExpand( wxCommandEvent& WXUNUSED(event) )
{ {
wxDataViewItem item = m_ctrl[0]->GetSelection(); wxDataViewItem item = m_ctrl[Page_Music]->GetSelection();
if (item.IsOk()) if (item.IsOk())
m_ctrl[0]->Expand( item ); m_ctrl[Page_Music]->Expand( item );
} }
void MyFrame::OnShowCurrent(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnShowCurrent(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewItem item = m_ctrl[0]->GetCurrentItem(); wxDataViewItem item = m_ctrl[Page_Music]->GetCurrentItem();
if ( item.IsOk() ) if ( item.IsOk() )
{ {
wxLogMessage("Current item: \"%s\" by %s", wxLogMessage("Current item: \"%s\" by %s",
@@ -1258,11 +1322,11 @@ void MyFrame::OnShowCurrent(wxCommandEvent& WXUNUSED(event))
wxLogMessage("There is no current item."); wxLogMessage("There is no current item.");
} }
wxDataViewColumn *col = m_ctrl[0]->GetCurrentColumn(); wxDataViewColumn *col = m_ctrl[Page_Music]->GetCurrentColumn();
if ( col ) if ( col )
{ {
wxLogMessage("Current column: %d", wxLogMessage("Current column: %d",
m_ctrl[0]->GetColumnPosition(col)); m_ctrl[Page_Music]->GetColumnPosition(col));
} }
else else
{ {
@@ -1279,7 +1343,7 @@ void MyFrame::OnSetNinthCurrent(wxCommandEvent& WXUNUSED(event))
return; return;
} }
m_ctrl[0]->SetCurrentItem(item); m_ctrl[Page_Music]->SetCurrentItem(item);
} }
void MyFrame::OnChangeNinthTitle(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnChangeNinthTitle(wxCommandEvent& WXUNUSED(event))
@@ -1308,7 +1372,7 @@ void MyFrame::OnActivated( wxDataViewEvent &event )
wxLogMessage( "wxEVT_DATAVIEW_ITEM_ACTIVATED, Item: %s; Column: %d", wxLogMessage( "wxEVT_DATAVIEW_ITEM_ACTIVATED, Item: %s; Column: %d",
title, event.GetColumn() ); title, event.GetColumn() );
if (m_ctrl[0]->IsExpanded( event.GetItem() )) if (m_ctrl[Page_Music]->IsExpanded( event.GetItem() ))
{ {
wxLogMessage( "Item: %s is expanded", title ); wxLogMessage( "Item: %s is expanded", title );
} }
@@ -1390,7 +1454,7 @@ void MyFrame::OnContextMenu( wxDataViewEvent &event )
menu.Append( 2, "menuitem 2" ); menu.Append( 2, "menuitem 2" );
menu.Append( 3, "menuitem 3" ); menu.Append( 3, "menuitem 3" );
m_ctrl[0]->PopupMenu(&menu); m_ctrl[Page_Music]->PopupMenu(&menu);
} }
void MyFrame::OnAttrHeaderClick( wxDataViewEvent &event ) void MyFrame::OnAttrHeaderClick( wxDataViewEvent &event )
@@ -1399,7 +1463,7 @@ void MyFrame::OnAttrHeaderClick( wxDataViewEvent &event )
// this column when it is clicked to take place // this column when it is clicked to take place
event.Skip(); event.Skip();
int pos = m_ctrl[1]->GetColumnPosition( event.GetDataViewColumn() ); int pos = m_ctrl[Page_List]->GetColumnPosition( event.GetDataViewColumn() );
wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos ); wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos );
wxLogMessage( "Column title: %s Column width: %d", event.GetDataViewColumn()->GetTitle(), event.GetDataViewColumn()->GetWidth() ); wxLogMessage( "Column title: %s Column width: %d", event.GetDataViewColumn()->GetTitle(), event.GetDataViewColumn()->GetWidth() );
@@ -1411,7 +1475,7 @@ void MyFrame::OnHeaderClick( wxDataViewEvent &event )
// this column when it is clicked to take place // this column when it is clicked to take place
event.Skip(); event.Skip();
int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos ); wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_CLICK, Column position: %d", pos );
wxLogMessage( "Column width: %d", event.GetDataViewColumn()->GetWidth() ); wxLogMessage( "Column width: %d", event.GetDataViewColumn()->GetWidth() );
@@ -1419,7 +1483,7 @@ void MyFrame::OnHeaderClick( wxDataViewEvent &event )
void MyFrame::OnHeaderRightClick( wxDataViewEvent &event ) void MyFrame::OnHeaderRightClick( wxDataViewEvent &event )
{ {
int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column position: %d", pos ); wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column position: %d", pos );
} }
@@ -1439,7 +1503,7 @@ void MyFrame::OnColumnReordered(wxDataViewEvent& event)
void MyFrame::OnSortedList( wxDataViewEvent &/*event*/) void MyFrame::OnSortedList( wxDataViewEvent &/*event*/)
{ {
wxVector<wxDataViewColumn *> const columns = m_ctrl[1]->GetSortingColumns(); wxVector<wxDataViewColumn *> const columns = m_ctrl[Page_List]->GetSortingColumns();
wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED using the following columns"); wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED using the following columns");
for ( wxVector<wxDataViewColumn *>::const_iterator it = columns.begin(), for ( wxVector<wxDataViewColumn *>::const_iterator it = columns.begin(),
@@ -1460,14 +1524,14 @@ void MyFrame::OnHeaderClickList( wxDataViewEvent &event )
{ {
// Use control+click to toggle sorting by this column. // Use control+click to toggle sorting by this column.
if ( wxGetKeyState(WXK_CONTROL) ) if ( wxGetKeyState(WXK_CONTROL) )
m_ctrl[1]->ToggleSortByColumn(event.GetColumn()); m_ctrl[Page_List]->ToggleSortByColumn(event.GetColumn());
else else
event.Skip(); event.Skip();
} }
void MyFrame::OnSorted( wxDataViewEvent &event ) void MyFrame::OnSorted( wxDataViewEvent &event )
{ {
int pos = m_ctrl[0]->GetColumnPosition( event.GetDataViewColumn() ); int pos = m_ctrl[Page_Music]->GetColumnPosition( event.GetDataViewColumn() );
wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED, Column position: %d", pos ); wxLogMessage( "wxEVT_DATAVIEW_COLUMN_SORTED, Column position: %d", pos );
} }
@@ -1492,7 +1556,7 @@ void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) )
void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) )
{ {
wxDataViewItemArray items; wxDataViewItemArray items;
int len = m_ctrl[1]->GetSelections( items ); int len = m_ctrl[Page_List]->GetSelections( items );
if (len > 0) if (len > 0)
m_list_model->DeleteItems( items ); m_list_model->DeleteItems( items );
} }
@@ -1500,7 +1564,7 @@ void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) )
void MyFrame::OnGoto(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnGoto(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewItem item = m_list_model->GetItem( 50 ); wxDataViewItem item = m_list_model->GetItem( 50 );
m_ctrl[1]->EnsureVisible(item,m_col); m_ctrl[Page_List]->EnsureVisible(item,m_col);
} }
void MyFrame::OnAddMany(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnAddMany(wxCommandEvent& WXUNUSED(event))
@@ -1531,7 +1595,7 @@ void MyFrame::OnListValueChanged(wxDataViewEvent& event)
return; return;
} }
wxDataViewListCtrl* const lc = static_cast<wxDataViewListCtrl*>(m_ctrl[2]); wxDataViewListCtrl* const lc = static_cast<wxDataViewListCtrl*>(m_ctrl[Page_ListStore]);
const int columnToggle = 1; const int columnToggle = 1;
@@ -1566,7 +1630,7 @@ void MyFrame::OnListValueChanged(wxDataViewEvent& event)
void MyFrame::OnDeleteTreeItem(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnDeleteTreeItem(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[3]; wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
wxDataViewItem selected = ctrl->GetSelection(); wxDataViewItem selected = ctrl->GetSelection();
if (!selected.IsOk()) if (!selected.IsOk())
return; return;
@@ -1576,13 +1640,13 @@ void MyFrame::OnDeleteTreeItem(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnDeleteAllTreeItems(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnDeleteAllTreeItems(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[3]; wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
ctrl->DeleteAllItems(); ctrl->DeleteAllItems();
} }
void MyFrame::OnAddTreeItem(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnAddTreeItem(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[3]; wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
wxDataViewItem selected = ctrl->GetSelection(); wxDataViewItem selected = ctrl->GetSelection();
if (ctrl->IsContainer(selected)) { if (ctrl->IsContainer(selected)) {
wxDataViewItem newitem = ctrl->AppendItem( selected, "Item", 0 ); wxDataViewItem newitem = ctrl->AppendItem( selected, "Item", 0 );
@@ -1593,7 +1657,7 @@ void MyFrame::OnAddTreeItem(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnAddTreeContainerItem(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnAddTreeContainerItem(wxCommandEvent& WXUNUSED(event))
{ {
wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[3]; wxDataViewTreeCtrl* ctrl = (wxDataViewTreeCtrl*) m_ctrl[Page_TreeStore];
wxDataViewItem selected = ctrl->GetSelection(); wxDataViewItem selected = ctrl->GetSelection();
if (ctrl->IsContainer(selected)) if (ctrl->IsContainer(selected))
ctrl->AppendContainer(selected, "Container", 0 ); ctrl->AppendContainer(selected, "Container", 0 );
@@ -1601,15 +1665,58 @@ void MyFrame::OnAddTreeContainerItem(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnMultipleSort( wxCommandEvent &event ) void MyFrame::OnMultipleSort( wxCommandEvent &event )
{ {
if ( !m_ctrl[1]->AllowMultiColumnSort(event.IsChecked()) ) if ( !m_ctrl[Page_List]->AllowMultiColumnSort(event.IsChecked()) )
wxLogMessage("Sorting by multiple columns not supported"); wxLogMessage("Sorting by multiple columns not supported");
} }
void MyFrame::OnSortByFirstColumn(wxCommandEvent& event) void MyFrame::OnSortByFirstColumn(wxCommandEvent& event)
{ {
wxDataViewColumn* const col = m_ctrl[1]->GetColumn(0); wxDataViewColumn* const col = m_ctrl[Page_List]->GetColumn(0);
if ( event.IsChecked() ) if ( event.IsChecked() )
col->SetSortOrder(true /* ascending */); col->SetSortOrder(true /* ascending */);
else else
col->UnsetAsSortKey(); col->UnsetAsSortKey();
} }
// ----------------------------------------------------------------------------
// Index list model page
// ----------------------------------------------------------------------------
void MyFrame::FillIndexList(Lang lang)
{
const int DAYS_PER_WEEK = 7;
const wxString weekdays[2][DAYS_PER_WEEK] =
{
{ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" },
{ "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim" },
};
m_index_list_model->Fill(wxArrayString(DAYS_PER_WEEK, weekdays[lang]));
}
void MyFrame::OnIndexListResetModel(wxCommandEvent&)
{
m_ctrl[Page_IndexList]->AssociateModel(NULL);
m_ctrl[Page_IndexList]->AssociateModel(m_index_list_model.get());
}
void MyFrame::OnIndexListSelectionChanged(wxDataViewEvent& event)
{
// We don't expect any events during the control destruction.
wxASSERT( !m_ctrl[Page_IndexList]->IsBeingDeleted() );
wxString weekday;
wxDataViewItem item = event.GetItem();
if ( !item )
{
weekday = "[none]";
}
else
{
wxVariant val;
m_index_list_model->GetValue(val, item, 0);
weekday = val.GetString();
}
wxLogMessage("Selected week day: %s", weekday);
}

View File

@@ -269,3 +269,38 @@ class MyListStoreDerivedModel : public wxDataViewListStore
public: public:
virtual bool IsEnabledByRow(unsigned int row, unsigned int col) const wxOVERRIDE; virtual bool IsEnabledByRow(unsigned int row, unsigned int col) const wxOVERRIDE;
}; };
// ----------------------------------------------------------------------------
// MyIndexListModel
// ----------------------------------------------------------------------------
class MyIndexListModel : public wxDataViewIndexListModel
{
public:
MyIndexListModel() { }
void Fill(const wxArrayString& strings)
{
m_strings = strings;
Reset(m_strings.size());
}
// Implement base class pure virtual methods.
unsigned GetColumnCount() const wxOVERRIDE { return 1; }
wxString GetColumnType(unsigned) const wxOVERRIDE { return "string"; }
unsigned GetCount() const wxOVERRIDE { return m_strings.size(); }
void GetValueByRow(wxVariant& val, unsigned row, unsigned) const wxOVERRIDE
{
val = m_strings[row];
}
bool SetValueByRow(const wxVariant&, unsigned, unsigned) wxOVERRIDE
{
return false;
}
private:
wxArrayString m_strings;
wxDECLARE_NO_COPY_CLASS(MyIndexListModel);
};

View File

@@ -250,6 +250,11 @@ public:
} }
// Associate our model with the tree view or disassociate it from it
// without generating any selection changed events, unlike
// gtk_tree_view_set_model() that this function wraps.
void UseModel(bool use);
// accessors // accessors
wxDataViewModel* GetDataViewModel() { return m_wx_model; } wxDataViewModel* GetDataViewModel() { return m_wx_model; }
const wxDataViewModel* GetDataViewModel() const { return m_wx_model; } const wxDataViewModel* GetDataViewModel() const { return m_wx_model; }
@@ -754,13 +759,6 @@ wxgtk_tree_model_get_path (GtkTreeModel *tree_model,
g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (tree_model), NULL); g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (tree_model), NULL);
GtkWxTreeModel *wxtree_model = GTK_WX_TREE_MODEL (tree_model); GtkWxTreeModel *wxtree_model = GTK_WX_TREE_MODEL (tree_model);
if ( wxtree_model->stamp == 0 )
{
// The model is temporarily invalid and can't be used, see Cleared(),
// but we need to return some valid path from here -- just return an
// empty one.
return gtk_tree_path_new();
}
g_return_val_if_fail (iter->stamp == wxtree_model->stamp, NULL); g_return_val_if_fail (iter->stamp == wxtree_model->stamp, NULL);
@@ -799,9 +797,6 @@ wxgtk_tree_model_iter_next (GtkTreeModel *tree_model,
{ {
GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model; GtkWxTreeModel *wxtree_model = (GtkWxTreeModel *) tree_model;
// This happens when clearing the view by calling .._set_model( NULL );
if (iter->stamp == 0) return FALSE;
g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE); g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model), FALSE);
g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE); g_return_val_if_fail (wxtree_model->stamp == iter->stamp, FALSE);
@@ -1875,55 +1870,23 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig
bool wxGtkDataViewModelNotifier::BeforeReset() bool wxGtkDataViewModelNotifier::BeforeReset()
{ {
GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView(); m_internal->UseModel(false);
gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL );
return true; return true;
} }
bool wxGtkDataViewModelNotifier::AfterReset() bool wxGtkDataViewModelNotifier::AfterReset()
{ {
GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView();
GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel();
m_internal->Cleared(); m_internal->Cleared();
gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(wxgtk_model) ); m_internal->UseModel(true);
return true; return true;
} }
bool wxGtkDataViewModelNotifier::Cleared() bool wxGtkDataViewModelNotifier::Cleared()
{ {
GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); return BeforeReset() && AfterReset();
// There is no call to tell the model that everything
// has been deleted so call row_deleted() for every
// child of root...
// It is important to avoid selection changed events being generated from
// here as they would reference the already deleted model items, which
// would result in crashes in any code attempting to handle these events.
wxDataViewCtrl::SelectionEventsSuppressor noSelection(m_internal->GetOwner());
// We also need to prevent wxGtkTreeCellDataFunc from using the model items
// not existing any longer, so change the model stamp to indicate that it
// temporarily can't be used.
const gint stampOrig = wxgtk_model->stamp;
wxgtk_model->stamp = 0;
{
wxGtkTreePath path(gtk_tree_path_new_first()); // points to root
const int count = m_internal->iter_n_children( NULL ); // number of children of root
for (int i = 0; i < count; i++)
gtk_tree_model_row_deleted( GTK_TREE_MODEL(wxgtk_model), path );
}
wxgtk_model->stamp = stampOrig;
m_internal->Cleared();
return true;
} }
// --------------------------------------------------------- // ---------------------------------------------------------
@@ -3104,13 +3067,6 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
g_return_if_fail (GTK_IS_WX_TREE_MODEL (model)); g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model; GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
if ( !tree_model->stamp )
{
// The model is temporarily invalid and can't be used, see the code in
// wxGtkDataViewModelNotifier::Cleared().
return;
}
wxDataViewRenderer *cell = (wxDataViewRenderer*) data; wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
wxDataViewItem item( (void*) iter->user_data ); wxDataViewItem item( (void*) iter->user_data );
@@ -3596,7 +3552,7 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataVie
if (!m_wx_model->IsVirtualListModel()) if (!m_wx_model->IsVirtualListModel())
InitTree(); InitTree();
gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()), GTK_TREE_MODEL(m_gtk_model) ); UseModel(true);
} }
wxDataViewCtrlInternal::~wxDataViewCtrlInternal() wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
@@ -3604,7 +3560,7 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
m_wx_model->RemoveNotifier( m_notifier ); m_wx_model->RemoveNotifier( m_notifier );
// remove the model from the GtkTreeView before it gets destroyed // remove the model from the GtkTreeView before it gets destroyed
gtk_tree_view_set_model( GTK_TREE_VIEW( m_owner->GtkGetTreeView() ), NULL ); UseModel(false);
g_object_unref( m_gtk_model ); g_object_unref( m_gtk_model );
@@ -3613,6 +3569,18 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal()
delete m_dropDataObject; delete m_dropDataObject;
} }
void wxDataViewCtrlInternal::UseModel(bool use)
{
// Avoid any selection changed events from gtk_tree_view_set_model() call
// below as they don't happen under the other platforms and can be
// unexpected with the possibly fatal consequences for the user-defined
// event handler.
wxDataViewCtrl::SelectionEventsSuppressor noSelection(m_owner);
gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()),
use ? GTK_TREE_MODEL(m_gtk_model) : NULL );
}
void wxDataViewCtrlInternal::ScheduleRefresh() void wxDataViewCtrlInternal::ScheduleRefresh()
{ {
m_dirty = true; m_dirty = true;