From 6ee9056c16ea30cfc3b4592b17a093472a3da6c5 Mon Sep 17 00:00:00 2001 From: Martin Corino Date: Fri, 29 Dec 2023 10:59:39 +0100 Subject: [PATCH] Fix column reordering in wxHeaderCtrlSimple and related problems Override required functions in wxHeaderCtrlSimple to avoid asserts if its columns are reordered. Also bring the code behaviour in agreement with the documentation by calling UpdateColumn() after calling UpdateColumnVisibility(). Finally, only call UpdateColumnsOrder() if the corresponding event was not processed as the application should use one xor the other mechanism for reacting to columns reordering, but not both. Closes #24108. Closes #24172. --- include/wx/headerctrl.h | 3 +++ interface/wx/headerctrl.h | 14 ++++++++------ src/common/headerctrlcmn.cpp | 14 ++++++++++++++ src/generic/headerctrlg.cpp | 17 ++++++++++++++++- src/msw/headerctrl.cpp | 12 +++++++++++- 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/include/wx/headerctrl.h b/include/wx/headerctrl.h index b13abd9052..31b4d66edf 100644 --- a/include/wx/headerctrl.h +++ b/include/wx/headerctrl.h @@ -343,6 +343,9 @@ protected: virtual const wxHeaderColumn& GetColumn(unsigned int idx) const override; virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle) override; + virtual void UpdateColumnVisibility(unsigned int idx, bool show) override; + virtual void UpdateColumnsOrder(const wxArrayInt& order) override; + // and define another one to be overridden in the derived classes: it // should return the best width for the given column contents or -1 if not // implemented, we use it to implement UpdateColumnWidthToFit() diff --git a/interface/wx/headerctrl.h b/interface/wx/headerctrl.h index 3980a9a01e..b5e0987e7f 100644 --- a/interface/wx/headerctrl.h +++ b/interface/wx/headerctrl.h @@ -447,13 +447,15 @@ protected: /** Method called when the columns order is changed in the customization - dialog. + dialog @em or when the EVT_HEADER_END_REORDER event is not handled after + dragging a single column. - This method is only called from ShowCustomizeDialog() when the user - changes the order of columns. In particular it is @em not called if a - single column changes place because the user dragged it to the new - location, the EVT_HEADER_END_REORDER event handler should be used to - react to this. + This method is always called from ShowCustomizeDialog() when the user + changes the order of columns. In case a single column changes place + because the user dragged it to a new location, the EVT_HEADER_END_REORDER + event handler can be used to react to this. If this event + handler is not defined though UpdateColumnsOrder() will be called + instead. A typical implementation in a derived class will update the display order of the columns in the associated control, if any. Notice that diff --git a/src/common/headerctrlcmn.cpp b/src/common/headerctrlcmn.cpp index a7787c46ab..ee284267cf 100644 --- a/src/common/headerctrlcmn.cpp +++ b/src/common/headerctrlcmn.cpp @@ -317,6 +317,7 @@ bool wxHeaderCtrlBase::ShowColumnsMenu(const wxPoint& pt, const wxString& title) { const int columnIndex = rc - wxID_COLUMNS_BASE; UpdateColumnVisibility(columnIndex, !GetColumn(columnIndex).IsShown()); + UpdateColumn(columnIndex); } return true; @@ -469,6 +470,19 @@ wxHeaderCtrlSimple::UpdateColumnWidthToFit(unsigned int idx, int widthTitle) return true; } +void +wxHeaderCtrlSimple::UpdateColumnVisibility(unsigned int idx, bool show) +{ + ShowColumn(idx, show); +} + +void +wxHeaderCtrlSimple::UpdateColumnsOrder(const wxArrayInt& WXUNUSED(order)) +{ + // Nothing to do here, we only override this function to prevent the base + // class version from asserting that it should be implemented. +} + void wxHeaderCtrlSimple::OnHeaderResizing(wxHeaderCtrlEvent& evt) { m_cols[evt.GetColumn()].SetWidth(evt.GetWidth()); diff --git a/src/generic/headerctrlg.cpp b/src/generic/headerctrlg.cpp index d24a615f9f..8df6a27826 100644 --- a/src/generic/headerctrlg.cpp +++ b/src/generic/headerctrlg.cpp @@ -456,7 +456,22 @@ bool wxHeaderCtrl::EndReordering(int xPhysical) const unsigned pos = GetColumnPos(colNew); event.SetNewOrder(pos); - if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) + const bool processed = GetEventHandler()->ProcessEvent(event); + + if ( !processed ) + { + // get the reordered columns + wxArrayInt order = GetColumnsOrder(); + MoveColumnInOrderArray(order, colOld, pos); + + // As the event wasn't processed, call the virtual function + // callback. + UpdateColumnsOrder(order); + + // update columns order + SetColumnsOrder(order); + } + else if ( event.IsAllowed() ) { // do reorder the columns DoMoveCol(colOld, pos); diff --git a/src/msw/headerctrl.cpp b/src/msw/headerctrl.cpp index a0b474c8ab..56e3eb2e40 100644 --- a/src/msw/headerctrl.cpp +++ b/src/msw/headerctrl.cpp @@ -990,7 +990,17 @@ bool wxMSWHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // internal column indices array if this is allowed to go ahead as // the native control is going to reorder its columns now if ( evtType == wxEVT_HEADER_END_REORDER ) - m_header.MoveColumnInOrderArray(m_colIndices, idx, order); + { + // If the event handler didn't process the event, call the + // virtual function callback. + wxArrayInt colIndices = m_header.GetColumnsOrder(); + m_header.MoveColumnInOrderArray(colIndices, idx, order); + if ( !processed ) + m_header.UpdateColumnsOrder(colIndices); + + // And update internally columns indices in any case. + m_colIndices = colIndices; + } if ( processed ) {