From 9457c35d42bc7ed09a070c7cb26b864781329065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Sun, 11 Oct 2020 18:00:39 +0200 Subject: [PATCH 1/2] Speed up wxDataViewCtrl::SetSelections() on macOS Don't make many single-item selection adjustments in SetSelections() in wxOSX and instead implement it with a single native call to selectRowIndexes:byExtendingSelection: This has a dramatic, orders of magnitude effect on this call's performance when selecting many items: selecting 10 thousand items goes from minutes of runtime and gigabytes of RAM to unobservable impact in both. --- include/wx/osx/cocoa/dataview.h | 1 + include/wx/osx/core/dataview.h | 1 + src/osx/cocoa/dataview.mm | 14 ++++++++++++++ src/osx/dataview_osx.cpp | 5 ++--- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/wx/osx/cocoa/dataview.h b/include/wx/osx/cocoa/dataview.h index 554dcbe0e6..41d16201d8 100644 --- a/include/wx/osx/cocoa/dataview.h +++ b/include/wx/osx/cocoa/dataview.h @@ -514,6 +514,7 @@ public: virtual int GetSelections(wxDataViewItemArray& sel) const; virtual bool IsSelected(const wxDataViewItem& item) const; virtual void Select(const wxDataViewItem& item); + virtual void Select(const wxDataViewItemArray& items); virtual void SelectAll(); virtual void Unselect(const wxDataViewItem& item); virtual void UnselectAll(); diff --git a/include/wx/osx/core/dataview.h b/include/wx/osx/core/dataview.h index b1d263ba20..f3ac6d33fd 100644 --- a/include/wx/osx/core/dataview.h +++ b/include/wx/osx/core/dataview.h @@ -90,6 +90,7 @@ public: virtual int GetSelections(wxDataViewItemArray& sel) const = 0; // returns all selected items in the native control virtual bool IsSelected (wxDataViewItem const& item) const = 0; // checks if the passed item is selected in the native control virtual void Select (wxDataViewItem const& item) = 0; // selects the passed item in the native control + virtual void Select (wxDataViewItemArray const& items) = 0; // selects the passed items in the native control virtual void SelectAll() = 0; // selects all items in the native control virtual void Unselect (wxDataViewItem const& item) = 0; // unselects the passed item in the native control virtual void UnselectAll() = 0; // unselects all items in the native control diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 24577504e2..770719e4a9 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -2508,6 +2508,20 @@ void wxCocoaDataViewControl::Select(const wxDataViewItem& item) byExtendingSelection:GetDataViewCtrl()->HasFlag(wxDV_MULTIPLE) ? YES : NO]; } +void wxCocoaDataViewControl::Select(const wxDataViewItemArray& items) +{ + NSMutableIndexSet *selection = [[NSMutableIndexSet alloc] init]; + + for ( const auto& i: items ) + { + if ( i.IsOk() ) + [selection addIndex:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:i]]]; + } + + [m_OutlineView selectRowIndexes:selection byExtendingSelection:NO]; + [selection release]; +} + void wxCocoaDataViewControl::SelectAll() { [m_OutlineView selectAll:m_OutlineView]; diff --git a/src/osx/dataview_osx.cpp b/src/osx/dataview_osx.cpp index c850b5052e..ad197cc85c 100644 --- a/src/osx/dataview_osx.cpp +++ b/src/osx/dataview_osx.cpp @@ -647,9 +647,8 @@ void wxDataViewCtrl::SetSelections(wxDataViewItemArray const& sel) last_parent = parent; } - // finally select the items: - for (i=0; iSelect(sel[i]); + // finally select the items: + dataViewWidgetPtr->Select(sel); } void wxDataViewCtrl::Unselect(wxDataViewItem const& item) From 1f40a7e4e3b25083651aa3fe4d3ac11042e1bf0e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 12 Oct 2020 17:05:59 +0200 Subject: [PATCH 2/2] Document that wxDataViewCtrl::SetSelections() skips invalid items Also add the unit test checking for this. --- interface/wx/dataview.h | 3 +++ tests/controls/dataviewctrltest.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 2abf7e778b..76266e4126 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1675,6 +1675,9 @@ public: /** Sets the selection to the array of wxDataViewItems. + + Note that if @a sel contains any invalid items, they are simply + ignored. */ virtual void SetSelections(const wxDataViewItemArray& sel); diff --git a/tests/controls/dataviewctrltest.cpp b/tests/controls/dataviewctrltest.cpp index 04d0876b33..1f400c8182 100644 --- a/tests/controls/dataviewctrltest.cpp +++ b/tests/controls/dataviewctrltest.cpp @@ -146,6 +146,30 @@ MultiColumnsDataViewCtrlTestCase::~MultiColumnsDataViewCtrlTestCase() // the tests themselves // ---------------------------------------------------------------------------- +TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase, + "wxDVC::Selection", + "[wxDataViewCtrl][select]") +{ + // Check selection round-trip. + wxDataViewItemArray sel; + sel.push_back(m_child1); + sel.push_back(m_grandchild); + REQUIRE_NOTHROW( m_dvc->SetSelections(sel) ); + + wxDataViewItemArray sel2; + CHECK( m_dvc->GetSelections(sel2) == sel.size() ); + + CHECK( sel2 == sel ); + + // Invalid items in GetSelections() input are supposed to be just skipped. + sel.clear(); + sel.push_back(wxDataViewItem()); + REQUIRE_NOTHROW( m_dvc->SetSelections(sel) ); + + CHECK( m_dvc->GetSelections(sel2) == 0 ); + CHECK( sel2.empty() ); +} + TEST_CASE_METHOD(MultiSelectDataViewCtrlTestCase, "wxDVC::DeleteSelected", "[wxDataViewCtrl][delete]")