From af78ad3b499e9258fc62b710db43cdcff4c4beea Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 15:27:02 +0100 Subject: [PATCH 1/9] Add wxDataViewCtrlBase::SetAlternateRowColour() Previously this method was only available in the generic wxDataViewCtrl, move it to the base class to make it possible calling it in portable code and document it. Closes #14617. --- include/wx/dataview.h | 6 ++++++ include/wx/generic/dataview.h | 5 +++-- interface/wx/dataview.h | 15 +++++++++++++++ src/generic/datavgen.cpp | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 9162cd9d0d..c94c8fe3c1 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -755,6 +755,12 @@ public: virtual bool SetHeaderAttr(const wxItemAttr& WXUNUSED(attr)) { return false; } + // Set the colour used for the "alternate" rows when wxDV_ROW_LINES is on. + // Also only supported in the generic version, which returns true to + // indicate it. + virtual bool SetAlternateRowColour(const wxColour& WXUNUSED(colour)) + { return false; } + virtual wxVisualAttributes GetDefaultAttributes() const wxOVERRIDE { return GetClassDefaultAttributes(GetWindowVariant()); diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 5efc0e1eec..6fe74d55db 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -277,10 +277,11 @@ public: virtual bool SetHeaderAttr(const wxItemAttr& attr) wxOVERRIDE; - // These methods are specific to generic wxDataViewCtrl implementation and + virtual bool SetAlternateRowColour(const wxColour& colour) wxOVERRIDE; + + // This method is specific to generic wxDataViewCtrl implementation and // should not be used in portable code. wxColour GetAlternateRowColour() const { return m_alternateRowColour; } - void SetAlternateRowColour(const wxColour& colour); // The returned pointer is null if the control has wxDV_NO_HEADER style. // diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 8c2b303bdc..90c9f1b6d6 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1566,6 +1566,21 @@ public: */ virtual void SelectAll(); + /** + Set custom colour for the alternate rows used with wxDV_ROW_LINES + style. + + Note that calling this method has no effect if wxDV_ROW_LINES is off. + + @param colour The colour to use for the alternate rows. + @return @true if customizing this colour is supported (currently only + in the generic version), @false if this method is not implemented + under this platform. + + @since 3.1.1 + */ + bool SetAlternateRowColour(const wxColour& colour); + /** Set which column shall contain the tree-like expanders. */ diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index d9840af8ab..298ff6bcb8 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -5781,9 +5781,10 @@ bool wxDataViewCtrl::SetHeaderAttr(const wxItemAttr& attr) return true; } -void wxDataViewCtrl::SetAlternateRowColour(const wxColour& colour) +bool wxDataViewCtrl::SetAlternateRowColour(const wxColour& colour) { m_alternateRowColour = colour; + return true; } void wxDataViewCtrl::SelectAll() From f33f1f2078ade742e8059d8be82829c8f68fda89 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 15:32:01 +0100 Subject: [PATCH 2/9] Fix a typo in EVT_DATAVIEW_COLUMN_REORDERED documentation See #14297. --- interface/wx/dataview.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 90c9f1b6d6..8e3312c126 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -3648,7 +3648,7 @@ public: Process a @c wxEVT_DATAVIEW_COLUMN_SORTED event. @event{EVT_DATAVIEW_COLUMN_REORDERED(id, func)} Process a @c wxEVT_DATAVIEW_COLUMN_REORDERED event. - Currently this even is only generated when using the native OS X + Currently this event is only generated when using the native OS X version. @event{EVT_DATAVIEW_ITEM_BEGIN_DRAG(id, func)} Process a @c wxEVT_DATAVIEW_ITEM_BEGIN_DRAG event. From 48fb2b42b137b0bd0e4611a054fba5d734b788d7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 15:45:23 +0100 Subject: [PATCH 3/9] Send wxEVT_DATAVIEW_COLUMN_REORDERED in generic wxDataViewCtrl Simply translate wxEVT_HEADER_END_REORDER into this event, which was previously only sent by the macOS version. GtkTreeView doesn't seem to support column drag-and-drop at all, so this event is still never generated by wxGTK. Closes #14297. --- include/wx/dataview.h | 4 ++-- interface/wx/dataview.h | 7 +++++-- samples/dataview/dataview.cpp | 15 +++++++++++++++ src/generic/datavgen.cpp | 7 +++++-- src/osx/cocoa/dataview.mm | 1 + 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index c94c8fe3c1..79b200cc09 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -903,11 +903,11 @@ public: wxDEPRECATED_MSG("Pass the argument to the ctor instead") void SetDataViewColumn( wxDataViewColumn *col ) { m_column = col; } wxDEPRECATED_MSG("Pass the argument to the ctor instead") - void SetColumn( int col ) { m_col = col; } - wxDEPRECATED_MSG("Pass the argument to the ctor instead") void SetItem( const wxDataViewItem &item ) { m_item = item; } #endif // WXWIN_COMPATIBILITY_3_0 + void SetColumn( int col ) { m_col = col; } + protected: wxDataViewItem m_item; int m_col; diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 8e3312c126..cbb5ba2566 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -3648,8 +3648,8 @@ public: Process a @c wxEVT_DATAVIEW_COLUMN_SORTED event. @event{EVT_DATAVIEW_COLUMN_REORDERED(id, func)} Process a @c wxEVT_DATAVIEW_COLUMN_REORDERED event. - Currently this event is only generated when using the native OS X - version. + Currently this event is not generated when using the native GTK+ + version of the control. @event{EVT_DATAVIEW_ITEM_BEGIN_DRAG(id, func)} Process a @c wxEVT_DATAVIEW_ITEM_BEGIN_DRAG event. @event{EVT_DATAVIEW_ITEM_DROP_POSSIBLE(id, func)} @@ -3675,6 +3675,9 @@ public: /** Returns the position of the column in the control or -1 if no column field was set by the event emitter. + + For wxEVT_DATAVIEW_COLUMN_REORDERED, this is the new position of the + column. */ int GetColumn() const; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 26773c624d..64e89e7b71 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -133,6 +133,7 @@ private: void OnHeaderClickList( wxDataViewEvent &event ); void OnSorted( wxDataViewEvent &event ); void OnSortedList( wxDataViewEvent &event ); + void OnColumnReordered( wxDataViewEvent &event); void OnContextMenu( wxDataViewEvent &event ); @@ -423,6 +424,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderRightClick) EVT_DATAVIEW_COLUMN_SORTED(ID_MUSIC_CTRL, MyFrame::OnSorted) EVT_DATAVIEW_COLUMN_SORTED(ID_ATTR_CTRL, MyFrame::OnSortedList) + EVT_DATAVIEW_COLUMN_REORDERED(wxID_ANY, MyFrame::OnColumnReordered) EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_ATTR_CTRL, MyFrame::OnHeaderClickList) EVT_DATAVIEW_ITEM_CONTEXT_MENU(ID_MUSIC_CTRL, MyFrame::OnContextMenu) @@ -1290,6 +1292,19 @@ void MyFrame::OnHeaderRightClick( wxDataViewEvent &event ) wxLogMessage( "wxEVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column position: %d", pos ); } +void MyFrame::OnColumnReordered(wxDataViewEvent& event) +{ + wxDataViewColumn* const col = event.GetDataViewColumn(); + if ( !col ) + { + wxLogError("Unknown column reordered?"); + return; + } + + wxLogMessage("wxEVT_DATAVIEW_COLUMN_REORDERED: \"%s\" is now at position %d", + col->GetTitle(), event.GetColumn()); +} + void MyFrame::OnSortedList( wxDataViewEvent &/*event*/) { wxVector const columns = m_ctrl[1]->GetSortingColumns(); diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 298ff6bcb8..54d745f6cf 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -5512,13 +5512,16 @@ unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const return max_width; } -void wxDataViewCtrl::ColumnMoved(wxDataViewColumn * WXUNUSED(col), - unsigned int WXUNUSED(new_pos)) +void wxDataViewCtrl::ColumnMoved(wxDataViewColumn *col, unsigned int new_pos) { // do _not_ reorder m_cols elements here, they should always be in the // order in which columns were added, we only display the columns in // different order m_clientArea->UpdateDisplay(); + + wxDataViewEvent event(wxEVT_DATAVIEW_COLUMN_REORDERED, this, col); + event.SetColumn(new_pos); + ProcessWindowEvent(event); } bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column ) diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 0b1ee6b419..abaf02276d 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -1881,6 +1881,7 @@ outlineView:(NSOutlineView*)outlineView wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); wxDataViewEvent event(wxEVT_DATAVIEW_COLUMN_REORDERED, dvc, col); + event.SetColumn(newColumnPosition); dvc->GetEventHandler()->ProcessEvent(event); } From 77231f59076486f396d6baff0fad066dadbe4675 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 22:20:22 +0100 Subject: [PATCH 4/9] Make wxDataViewRendererBase::DestroyEditControl() private This method is only supposed to be used by this class and not any derived classes, so prevent it from being used accidentally. No real changes. --- include/wx/dvrenderers.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index b672b88f51..0d2615b659 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -241,9 +241,6 @@ protected: // (typically selection with dark background). For internal use only. virtual bool IsHighlighted() const = 0; - // Called from {Cancel,Finish}Editing() to cleanup m_editorCtrl - void DestroyEditControl(); - // Helper of PrepareForItem() also used in StartEditing(): returns the // value checking that its type matches our GetVariantType(). wxVariant CheckedGetValue(const wxDataViewModel* model, @@ -261,7 +258,10 @@ protected: // renderer is required wxDataViewCtrl* GetView() const; -protected: +private: + // Called from {Called,Finish}Editing() and dtor to cleanup m_editorCtrl + void DestroyEditControl(); + wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRendererBase); }; From 7e3d28e79f1391b965330efb43a0f290b83f3a4a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 22:31:23 +0100 Subject: [PATCH 5/9] Rename wxDataViewEvent::SetEditCanceled() and remove its argument This method should be only used when the edit is really cancelled, so it doesn't need to take a boolean argument. It should also use the same spelling as IsEditCancelled() (and for consistency with the rest of wxWidgets API which uses British English). Also remove this method from the documentation, it is not part of the public API. --- include/wx/dataview.h | 2 +- interface/wx/dataview.h | 1 - src/common/datavcmn.cpp | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 79b200cc09..58b0fdafe4 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -859,7 +859,6 @@ public: // for wxEVT_DATAVIEW_ITEM_EDITING_DONE only bool IsEditCancelled() const { return m_editCancelled; } - void SetEditCanceled(bool editCancelled) { m_editCancelled = editCancelled; } // for wxEVT_DATAVIEW_COLUMN_HEADER_CLICKED only wxDataViewColumn *GetDataViewColumn() const { return m_column; } @@ -907,6 +906,7 @@ public: #endif // WXWIN_COMPATIBILITY_3_0 void SetColumn( int col ) { m_col = col; } + void SetEditCancelled() { m_editCancelled = true; } protected: wxDataViewItem m_item; diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index cbb5ba2566..81c493efa4 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -3818,7 +3818,6 @@ public: */ wxDataViewItem GetItem() const; void SetItem( const wxDataViewItem &item ); - void SetEditCanceled(bool editCancelled); void SetPosition( int x, int y ); void SetCache(int from, int to); wxDataObject *GetDataObject() const; diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index df7ad9cd1f..a7d7597fff 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -798,7 +798,8 @@ bool wxDataViewRendererBase::FinishEditing() // Now we should send Editing Done event wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EDITING_DONE, dv_ctrl, column, m_item); event.SetValue( value ); - event.SetEditCanceled( !isValid ); + if ( !isValid ) + event.SetEditCancelled(); dv_ctrl->GetEventHandler()->ProcessEvent( event ); bool accepted = false; From 1e3e5b72530d51d2465c8ba876869cfbb8d74b50 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 22:40:51 +0100 Subject: [PATCH 6/9] Send wxEVT_DATAVIEW_ITEM_EDITING_DONE after cancelling too Previously this event was not sent at all if editing the item was cancelled, e.g. by pressing Esc. Do send it now from the generic implementation and update the sample to show this event. See #17835. --- docs/changes.txt | 1 + include/wx/dvrenderers.h | 3 +++ samples/dataview/dataview.cpp | 6 ++++- src/common/datavcmn.cpp | 51 +++++++++++++++++++++++++---------- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 6ad30469d8..8520be4207 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -182,6 +182,7 @@ All (GUI): - Generate wxEVT_SEARCH on Enter under all platforms. - Extend wxRendererNative::DrawGauge() to work for vertical gauges too. - Add wxHD_BITMAP_ON_RIGHT style to wxHeaderCtrl. +- Send wxEVT_DATAVIEW_ITEM_EDITING_DONE when editing was cancelled too. wxGTK: diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index 0d2615b659..c1230cafcc 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -259,6 +259,9 @@ protected: wxDataViewCtrl* GetView() const; private: + // Common part of {Cancel,Finish}Editing(). + bool DoFinishOrCancelEditing(bool cancelled); + // Called from {Called,Finish}Editing() and dtor to cleanup m_editorCtrl void DestroyEditControl(); diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 64e89e7b71..240fc74d40 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -1227,7 +1227,11 @@ void MyFrame::OnEditingStarted( wxDataViewEvent &event ) void MyFrame::OnEditingDone( wxDataViewEvent &event ) { wxString title = m_music_model->GetTitle( event.GetItem() ); - wxLogMessage( "wxEVT_DATAVIEW_ITEM_EDITING_DONE, Item: %s", title ); + wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_DONE, Item: %s, new value %s", + title, + event.IsEditCancelled() + ? wxString("unavailable because editing was cancelled") + : event.GetValue().GetString()); } void MyFrame::OnExpanded( wxDataViewEvent &event ) diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index a7d7597fff..dcbc5cd101 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -766,44 +766,67 @@ void wxDataViewRendererBase::DestroyEditControl() void wxDataViewRendererBase::CancelEditing() { - if (!m_editorCtrl) - return; - - DestroyEditControl(); + DoFinishOrCancelEditing(true); } bool wxDataViewRendererBase::FinishEditing() +{ + return DoFinishOrCancelEditing(false); +} + +bool wxDataViewRendererBase::DoFinishOrCancelEditing(bool cancelled) { if (!m_editorCtrl) return true; - // Try to get the value, normally we should succeed but if we fail, don't - // return immediately, we still need to destroy the edit control. + bool gotValue = false; + wxVariant value; - const bool gotValue = GetValueFromEditorCtrl(m_editorCtrl, value); + if ( !cancelled ) + { + if ( GetValueFromEditorCtrl(m_editorCtrl, value) ) + { + // This is the normal case and we will use this value below (if it + // passes validation). + gotValue = true; + } + //else: Not really supposed to happen, but still proceed with + // destroying the edit control if it does. + } wxDataViewColumn* const column = GetOwner(); wxDataViewCtrl* const dv_ctrl = column->GetOwner(); DestroyEditControl(); - dv_ctrl->GetMainWindow()->SetFocus(); + // If we're cancelled, it can be because focus was switched elsewhere, + // don't bring it back here. + if ( !cancelled ) + dv_ctrl->GetMainWindow()->SetFocus(); - if ( !gotValue ) - return false; + if ( gotValue ) + { + if ( !Validate(value) ) + { + // Invalid value can't be used, so if it's the same as if we hadn't + // got it in the first place. + gotValue = false; + } + } - bool isValid = Validate(value); unsigned int col = GetOwner()->GetModelColumn(); // Now we should send Editing Done event wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EDITING_DONE, dv_ctrl, column, m_item); - event.SetValue( value ); - if ( !isValid ) + if ( gotValue ) + event.SetValue(value); + else event.SetEditCancelled(); + dv_ctrl->GetEventHandler()->ProcessEvent( event ); bool accepted = false; - if ( isValid && event.IsAllowed() ) + if ( gotValue && event.IsAllowed() ) { dv_ctrl->GetModel()->ChangeValue(value, m_item, col); accepted = true; From 0972dece2785442315570278d898d15e5619a19d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 4 Feb 2018 23:43:47 +0100 Subject: [PATCH 7/9] Catch EDITING_{STARTED,DONE} for all pages in dataview sample This is useful to allow checking that the expected events are sent for the custom editor in the second page of the sample too, in addition to the standard ones used in the first page. --- samples/dataview/dataview.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 240fc74d40..1393a86fee 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -417,8 +417,8 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_DATAVIEW_SELECTION_CHANGED(ID_MUSIC_CTRL, MyFrame::OnSelectionChanged) EVT_DATAVIEW_ITEM_START_EDITING(ID_MUSIC_CTRL, MyFrame::OnStartEditing) - EVT_DATAVIEW_ITEM_EDITING_STARTED(ID_MUSIC_CTRL, MyFrame::OnEditingStarted) - EVT_DATAVIEW_ITEM_EDITING_DONE(ID_MUSIC_CTRL, MyFrame::OnEditingDone) + EVT_DATAVIEW_ITEM_EDITING_STARTED(wxID_ANY, MyFrame::OnEditingStarted) + EVT_DATAVIEW_ITEM_EDITING_DONE(wxID_ANY, MyFrame::OnEditingDone) EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderClick) EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderRightClick) @@ -1220,15 +1220,17 @@ void MyFrame::OnStartEditing( wxDataViewEvent &event ) void MyFrame::OnEditingStarted( wxDataViewEvent &event ) { - wxString title = m_music_model->GetTitle( event.GetItem() ); - wxLogMessage( "wxEVT_DATAVIEW_ITEM_EDITING_STARTED, Item: %s", title ); + // This event doesn't, currently, carry the value, so get it ourselves. + wxDataViewModel* const model = event.GetModel(); + wxVariant value; + model->GetValue(value, event.GetItem(), event.GetColumn()); + wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_STARTED, current value %s", + value.GetString()); } void MyFrame::OnEditingDone( wxDataViewEvent &event ) { - wxString title = m_music_model->GetTitle( event.GetItem() ); - wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_DONE, Item: %s, new value %s", - title, + wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_DONE, new value %s", event.IsEditCancelled() ? wxString("unavailable because editing was cancelled") : event.GetValue().GetString()); From a00b8dec8b2eac69eeb399846758bac7ff409421 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 5 Feb 2018 00:01:52 +0100 Subject: [PATCH 8/9] Reduce code duplication in wxGTK wxDataViewRenderer classes The code was more complicated than necessary, with the base class providing both virtual GtkOnCellChanged() and GtkOnTextEdited() that were both overridden to achieve the same thing, namely customizing how the value entered by user is converted to wxVariant, in different derived classes. Make GtkOnTextEdited() non-virtual and remove GtkOnCellChanged() completely and add a new simple GtkGetValueFromString() which is called from GtkOnTextEdited() to do the conversion. This removes the existing code duplication and will make it simpler to modify this code in the future, without changing the behaviour. --- include/wx/gtk/dvrenderer.h | 17 +++++++++------ include/wx/gtk/dvrenderers.h | 6 ++---- src/gtk/dataview.cpp | 41 +++++++++++++----------------------- 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/include/wx/gtk/dvrenderer.h b/include/wx/gtk/dvrenderer.h index da5d540e2b..0704b89ff6 100644 --- a/include/wx/gtk/dvrenderer.h +++ b/include/wx/gtk/dvrenderer.h @@ -47,9 +47,10 @@ public: // called when the cell value was edited by user with the new value // - // it validates the new value and notifies the model about the change by - // calling GtkOnCellChanged() if it was accepted - virtual void GtkOnTextEdited(const char *itempath, const wxString& value); + // it uses GtkGetValueFromString() to parse the new value, then validates + // it by calling Validate() and notifies the model about the change if it + // passes validation + void GtkOnTextEdited(const char *itempath, const wxString& value); GtkCellRenderer* GetGtkHandle() { return m_renderer; } void GtkInitHandlers(); @@ -78,14 +79,16 @@ protected: virtual bool IsHighlighted() const wxOVERRIDE; - virtual void GtkOnCellChanged(const wxVariant& value, - const wxDataViewItem& item, - unsigned col); - // Apply our effective alignment (i.e. m_alignment if specified or the // associated column alignment by default) to the given renderer. void GtkApplyAlignment(GtkCellRenderer *renderer); + // This method is used to interpret the string entered by user and by + // default just uses it as is, but can be overridden for classes requiring + // special treatment. + virtual wxVariant GtkGetValueFromString(const wxString& str) const; + + GtkCellRenderer *m_renderer; int m_alignment; diff --git a/include/wx/gtk/dvrenderers.h b/include/wx/gtk/dvrenderers.h index 9169d09761..67d81df79e 100644 --- a/include/wx/gtk/dvrenderers.h +++ b/include/wx/gtk/dvrenderers.h @@ -228,9 +228,7 @@ public: virtual void GtkPackIntoColumn(GtkTreeViewColumn *column) wxOVERRIDE; protected: - virtual void GtkOnCellChanged(const wxVariant& value, - const wxDataViewItem& item, - unsigned col) wxOVERRIDE; + virtual wxVariant GtkGetValueFromString(const wxString& str) const wxOVERRIDE; private: wxDataViewIconText m_value; @@ -281,7 +279,7 @@ public: virtual bool GetValue( wxVariant &value ) const wxOVERRIDE; private: - virtual void GtkOnTextEdited(const char *itempath, const wxString& str) wxOVERRIDE; + virtual wxVariant GtkGetValueFromString(const wxString& str) const; }; diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index b677de2b69..d1f55061f6 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -2155,26 +2155,24 @@ bool wxDataViewRenderer::IsHighlighted() const GetOwner()->GetOwner()->IsSelected(m_itemBeingRendered); } +wxVariant +wxDataViewRenderer::GtkGetValueFromString(const wxString& str) const +{ + return str; +} + void wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) { - wxVariant value(str); + wxVariant value(GtkGetValueFromString(str)); if (!Validate( value )) return; wxDataViewItem item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath))); - GtkOnCellChanged(value, item, GetOwner()->GetModelColumn()); -} - -void -wxDataViewRenderer::GtkOnCellChanged(const wxVariant& value, - const wxDataViewItem& item, - unsigned col) -{ wxDataViewModel *model = GetOwner()->GetOwner()->GetModel(); - model->ChangeValue( value, item, col ); + model->ChangeValue( value, item, GetOwner()->GetModelColumn() ); } void wxDataViewRenderer::SetAttr(const wxDataViewItemAttr& WXUNUSED(attr)) @@ -2941,17 +2939,10 @@ wxDataViewChoiceByIndexRenderer::wxDataViewChoiceByIndexRenderer( const wxArrayS m_variantType = wxS("long"); } -void wxDataViewChoiceByIndexRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) +wxVariant +wxDataViewChoiceByIndexRenderer::GtkGetValueFromString(const wxString& str) const { - wxVariant value( (long) GetChoices().Index( str ) ); - - if (!Validate( value )) - return; - - wxDataViewItem - item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath))); - - GtkOnCellChanged(value, item, GetOwner()->GetModelColumn()); + return static_cast(GetChoices().Index(str)); } bool wxDataViewChoiceByIndexRenderer::SetValue( const wxVariant &value ) @@ -3024,17 +3015,15 @@ bool wxDataViewIconTextRenderer::GetValue(wxVariant& value) const return true; } -void -wxDataViewIconTextRenderer::GtkOnCellChanged(const wxVariant& value, - const wxDataViewItem& item, - unsigned col) +wxVariant +wxDataViewIconTextRenderer::GtkGetValueFromString(const wxString& str) const { // we receive just the text part of our value as it's the only one which // can be edited, but we need the full wxDataViewIconText value for the // model wxVariant valueIconText; - valueIconText << wxDataViewIconText(value.GetString(), m_value.GetIcon()); - wxDataViewTextRenderer::GtkOnCellChanged(valueIconText, item, col); + valueIconText << wxDataViewIconText(str, m_value.GetIcon()); + return valueIconText; } // --------------------------------------------------------- From 33cbefd7398ac5729c787c1a9fd21b0565a6241a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 5 Feb 2018 01:05:16 +0100 Subject: [PATCH 9/9] Send wxEVT_DATAVIEW_ITEM_EDITING_DONE for all renderers in wxGTK Previously this event was not sent for the standard renderers, such as wxDataViewTextRenderer, at all in wxGTK because the base class FinishEditing() class didn't do anything if m_editorCtrl was null, as it was always the case for non-custom renderers. Fix this by refactoring the base class code in yet another way and extracting the part which can be reused by both the generic and GTK implementation in a new DoHandleEditingDone() function and call it from wxGTK code. Finally, check "editing-canceled" property to also correctly generate the event with IsEditCancelled() returning true when editing is canceled by e.g. pressing Esc in a standard renderer too. And, as a final bonus, this makes the (just introduced) slightly artificial DoFinishOrCancelEditing() unnecessary, so it can be removed, without reintroducing any code duplication. See #17835. --- include/wx/dvrenderers.h | 9 ++++-- src/common/datavcmn.cpp | 69 +++++++++++++++++++--------------------- src/gtk/dataview.cpp | 28 ++++++++++------ 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index c1230cafcc..4cda6ba033 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -247,6 +247,12 @@ protected: const wxDataViewItem& item, unsigned column) const; + // Validates the given value (if it is non-null) and sends (in any case) + // ITEM_EDITING_DONE event and, finally, updates the model with the value + // (f it is valid, of course) if the event wasn't vetoed. + bool DoHandleEditingDone(wxVariant* value); + + wxString m_variantType; wxDataViewColumn *m_owner; wxWeakRef m_editorCtrl; @@ -259,9 +265,6 @@ protected: wxDataViewCtrl* GetView() const; private: - // Common part of {Cancel,Finish}Editing(). - bool DoFinishOrCancelEditing(bool cancelled); - // Called from {Called,Finish}Editing() and dtor to cleanup m_editorCtrl void DestroyEditControl(); diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index dcbc5cd101..9043cf3fd4 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -766,15 +766,13 @@ void wxDataViewRendererBase::DestroyEditControl() void wxDataViewRendererBase::CancelEditing() { - DoFinishOrCancelEditing(true); + if ( m_editorCtrl ) + DestroyEditControl(); + + DoHandleEditingDone(NULL); } bool wxDataViewRendererBase::FinishEditing() -{ - return DoFinishOrCancelEditing(false); -} - -bool wxDataViewRendererBase::DoFinishOrCancelEditing(bool cancelled) { if (!m_editorCtrl) return true; @@ -782,53 +780,52 @@ bool wxDataViewRendererBase::DoFinishOrCancelEditing(bool cancelled) bool gotValue = false; wxVariant value; - if ( !cancelled ) + if ( GetValueFromEditorCtrl(m_editorCtrl, value) ) { - if ( GetValueFromEditorCtrl(m_editorCtrl, value) ) + // This is the normal case and we will use this value below (if it + // passes validation). + gotValue = true; + } + //else: Not really supposed to happen, but still proceed with + // destroying the edit control if it does. + + DestroyEditControl(); + + GetView()->GetMainWindow()->SetFocus(); + + return DoHandleEditingDone(gotValue ? &value : NULL); +} + +bool +wxDataViewRendererBase::DoHandleEditingDone(wxVariant* value) +{ + if ( value ) + { + if ( !Validate(*value) ) { - // This is the normal case and we will use this value below (if it - // passes validation). - gotValue = true; + // Invalid value can't be used, so if it's the same as if we hadn't + // got it in the first place. + value = NULL; } - //else: Not really supposed to happen, but still proceed with - // destroying the edit control if it does. } wxDataViewColumn* const column = GetOwner(); wxDataViewCtrl* const dv_ctrl = column->GetOwner(); - - DestroyEditControl(); - - // If we're cancelled, it can be because focus was switched elsewhere, - // don't bring it back here. - if ( !cancelled ) - dv_ctrl->GetMainWindow()->SetFocus(); - - if ( gotValue ) - { - if ( !Validate(value) ) - { - // Invalid value can't be used, so if it's the same as if we hadn't - // got it in the first place. - gotValue = false; - } - } - - unsigned int col = GetOwner()->GetModelColumn(); + unsigned int col = column->GetModelColumn(); // Now we should send Editing Done event wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EDITING_DONE, dv_ctrl, column, m_item); - if ( gotValue ) - event.SetValue(value); + if ( value ) + event.SetValue(*value); else event.SetEditCancelled(); dv_ctrl->GetEventHandler()->ProcessEvent( event ); bool accepted = false; - if ( gotValue && event.IsAllowed() ) + if ( value && event.IsAllowed() ) { - dv_ctrl->GetModel()->ChangeValue(value, m_item, col); + dv_ctrl->GetModel()->ChangeValue(*value, m_item, col); accepted = true; } diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index d1f55061f6..6ed97b47b7 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -1932,9 +1932,24 @@ bool wxGtkDataViewModelNotifier::Cleared() // --------------------------------------------------------- static void -wxgtk_cell_editable_editing_done( GtkCellEditable *WXUNUSED(editable), +wxgtk_cell_editable_editing_done( GtkCellEditable *editable, wxDataViewRenderer *wxrenderer ) { + // "editing-cancelled" property is documented as being new since 2.20 in + // GtkCellEditable, but seems to have existed basically forever (since GTK+ + // 1.3 days) in GtkCellRendererText, so try to use it in any case. + if ( g_object_class_find_property(G_OBJECT_GET_CLASS(editable), + "editing-canceled") ) + { + gboolean wasCancelled; + g_object_get(editable, "editing-canceled", &wasCancelled, NULL); + if ( wasCancelled ) + { + wxrenderer->CancelEditing(); + return; + } + } + wxrenderer->FinishEditing(); } @@ -2164,15 +2179,10 @@ wxDataViewRenderer::GtkGetValueFromString(const wxString& str) const void wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) { + m_item = wxDataViewItem(GetView()->GTKPathToItem(wxGtkTreePath(itempath))); + wxVariant value(GtkGetValueFromString(str)); - if (!Validate( value )) - return; - - wxDataViewItem - item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath))); - - wxDataViewModel *model = GetOwner()->GetOwner()->GetModel(); - model->ChangeValue( value, item, GetOwner()->GetModelColumn() ); + DoHandleEditingDone(&value); } void wxDataViewRenderer::SetAttr(const wxDataViewItemAttr& WXUNUSED(attr))