From 54a8d1d8f370c6bc8516aca06da26933c9c2819e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 12 Sep 2019 23:36:20 +0200 Subject: [PATCH] Don't send events when changing model in wxGTK wxDataViewCtrl Sending events from e.g. AssociateModel(NULL) made the GTK version inconsistent with the other ones, neither of which sent any events in this case, and could result in a lot of grief in the user code if it didn't expect the event handler to be called at this moment (e.g. during the destruction). Make wxGTK compatible with the other ports and safer by always disabling the selection changed events before calling gtk_tree_view_set_model(). Note that it's still incompatible with the other ports because they also preserve the selection even after the change of model, but wxGTK loses it. Ideally this would be fixed too, but for now live with this as the lesser evil. --- src/gtk/dataview.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 79d534c1bd..62ebd65121 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -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 wxDataViewModel* GetDataViewModel() { return m_wx_model; } const wxDataViewModel* GetDataViewModel() const { return m_wx_model; } @@ -1865,20 +1870,16 @@ bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem &item, unsig bool wxGtkDataViewModelNotifier::BeforeReset() { - GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView(); - gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), NULL ); + m_internal->UseModel(false); return true; } bool wxGtkDataViewModelNotifier::AfterReset() { - GtkWidget *treeview = m_internal->GetOwner()->GtkGetTreeView(); - GtkWxTreeModel *wxgtk_model = m_internal->GetGtkModel(); - m_internal->Cleared(); - gtk_tree_view_set_model( GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(wxgtk_model) ); + m_internal->UseModel(true); return true; } @@ -3551,7 +3552,7 @@ wxDataViewCtrlInternal::wxDataViewCtrlInternal( wxDataViewCtrl *owner, wxDataVie if (!m_wx_model->IsVirtualListModel()) InitTree(); - gtk_tree_view_set_model( GTK_TREE_VIEW(m_owner->GtkGetTreeView()), GTK_TREE_MODEL(m_gtk_model) ); + UseModel(true); } wxDataViewCtrlInternal::~wxDataViewCtrlInternal() @@ -3559,7 +3560,7 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal() m_wx_model->RemoveNotifier( m_notifier ); // 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 ); @@ -3568,6 +3569,18 @@ wxDataViewCtrlInternal::~wxDataViewCtrlInternal() 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() { m_dirty = true;