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.
This commit is contained in:
Vadim Zeitlin
2018-02-05 01:05:16 +01:00
parent a00b8dec8b
commit 33cbefd739
3 changed files with 58 additions and 48 deletions

View File

@@ -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<wxWindow> 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();

View File

@@ -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;
}

View File

@@ -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))