diff --git a/docs/changes.txt b/docs/changes.txt index 9eb241556d..d7b1fbbaa5 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/dataview.h b/include/wx/dataview.h index 9162cd9d0d..58b0fdafe4 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()); @@ -853,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; } @@ -897,11 +902,12 @@ 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; } + void SetEditCancelled() { m_editCancelled = true; } + protected: wxDataViewItem m_item; int m_col; diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index b672b88f51..4cda6ba033 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -241,15 +241,18 @@ 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, 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; @@ -261,7 +264,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); }; 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/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/interface/wx/dataview.h b/interface/wx/dataview.h index 8c2b303bdc..81c493efa4 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. */ @@ -3633,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 even 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)} @@ -3660,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; @@ -3800,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/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 26773c624d..1393a86fee 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 ); @@ -416,13 +417,14 @@ 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) 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) @@ -1218,14 +1220,20 @@ 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", title ); + wxLogMessage("wxEVT_DATAVIEW_ITEM_EDITING_DONE, new value %s", + event.IsEditCancelled() + ? wxString("unavailable because editing was cancelled") + : event.GetValue().GetString()); } void MyFrame::OnExpanded( wxDataViewEvent &event ) @@ -1290,6 +1298,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/common/datavcmn.cpp b/src/common/datavcmn.cpp index df7ad9cd1f..9043cf3fd4 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -766,10 +766,10 @@ void wxDataViewRendererBase::DestroyEditControl() void wxDataViewRendererBase::CancelEditing() { - if (!m_editorCtrl) - return; + if ( m_editorCtrl ) + DestroyEditControl(); - DestroyEditControl(); + DoHandleEditingDone(NULL); } bool wxDataViewRendererBase::FinishEditing() @@ -777,34 +777,55 @@ bool wxDataViewRendererBase::FinishEditing() 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. - wxVariant value; - const bool gotValue = GetValueFromEditorCtrl(m_editorCtrl, value); + bool gotValue = false; - wxDataViewColumn* const column = GetOwner(); - wxDataViewCtrl* const dv_ctrl = column->GetOwner(); + wxVariant 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(); - dv_ctrl->GetMainWindow()->SetFocus(); + GetView()->GetMainWindow()->SetFocus(); - if ( !gotValue ) - return false; + return DoHandleEditingDone(gotValue ? &value : NULL); +} - bool isValid = Validate(value); - unsigned int col = GetOwner()->GetModelColumn(); +bool +wxDataViewRendererBase::DoHandleEditingDone(wxVariant* value) +{ + if ( value ) + { + 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. + value = NULL; + } + } + + wxDataViewColumn* const column = GetOwner(); + wxDataViewCtrl* const dv_ctrl = column->GetOwner(); + unsigned int col = column->GetModelColumn(); // 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 ( value ) + event.SetValue(*value); + else + event.SetEditCancelled(); + dv_ctrl->GetEventHandler()->ProcessEvent( event ); bool accepted = false; - if ( isValid && 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/generic/datavgen.cpp b/src/generic/datavgen.cpp index d9840af8ab..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 ) @@ -5781,9 +5784,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() diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index b677de2b69..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(); } @@ -2155,26 +2170,19 @@ bool wxDataViewRenderer::IsHighlighted() const GetOwner()->GetOwner()->IsSelected(m_itemBeingRendered); } -void -wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) +wxVariant +wxDataViewRenderer::GtkGetValueFromString(const wxString& str) const { - wxVariant value(str); - if (!Validate( value )) - return; - - wxDataViewItem - item(GetOwner()->GetOwner()->GTKPathToItem(wxGtkTreePath(itempath))); - - GtkOnCellChanged(value, item, GetOwner()->GetModelColumn()); + return str; } void -wxDataViewRenderer::GtkOnCellChanged(const wxVariant& value, - const wxDataViewItem& item, - unsigned col) +wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) { - wxDataViewModel *model = GetOwner()->GetOwner()->GetModel(); - model->ChangeValue( value, item, col ); + m_item = wxDataViewItem(GetView()->GTKPathToItem(wxGtkTreePath(itempath))); + + wxVariant value(GtkGetValueFromString(str)); + DoHandleEditingDone(&value); } void wxDataViewRenderer::SetAttr(const wxDataViewItemAttr& WXUNUSED(attr)) @@ -2941,17 +2949,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 +3025,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; } // --------------------------------------------------------- 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); }