diff --git a/include/wx/selstore.h b/include/wx/selstore.h index fec3c212a4..02545e12b3 100644 --- a/include/wx/selstore.h +++ b/include/wx/selstore.h @@ -47,12 +47,16 @@ public: // special case of SetItemCount(0) void Clear() { m_itemsSel.Clear(); m_count = 0; m_defaultState = false; } - // must be called when a new item is inserted/added - void OnItemAdd(unsigned WXUNUSED(item)) { wxFAIL_MSG( wxT("TODO") ); } + // must be called when new items are inserted/added + void OnItemsInserted(unsigned item, unsigned numItems); - // must be called when an item is deleted + // must be called when an items is deleted void OnItemDelete(unsigned item); + // more efficient version for notifying the selection about deleting + // several items at once, return true if any of them were selected + bool OnItemsDeleted(unsigned item, unsigned numItems); + // select one item, use SelectRange() insted if possible! // // returns true if the items selection really changed diff --git a/src/generic/selstore.cpp b/src/generic/selstore.cpp index 8ea6066c65..5ce9e5cd41 100644 --- a/src/generic/selstore.cpp +++ b/src/generic/selstore.cpp @@ -190,6 +190,31 @@ bool wxSelectionStore::SelectRange(unsigned itemFrom, unsigned itemTo, // callbacks // ---------------------------------------------------------------------------- +void wxSelectionStore::OnItemsInserted(unsigned item, unsigned numItems) +{ + const size_t count = m_itemsSel.GetCount(); + + size_t idx = m_itemsSel.IndexForInsert(item); + + for ( size_t i = idx; i < count; i++ ) + { + m_itemsSel[i] += numItems; + } + + if ( m_defaultState ) + { + // All newly inserted items are not selected, so if the default state + // is to be selected, we need to manually add them to the deselected + // items indices. + for ( unsigned n = item; n < item + numItems; n++ ) + { + m_itemsSel.AddAt(item, idx++); + } + } + + m_count += numItems; +} + void wxSelectionStore::OnItemDelete(unsigned item) { size_t count = m_itemsSel.GetCount(), @@ -211,8 +236,44 @@ void wxSelectionStore::OnItemDelete(unsigned item) m_itemsSel[i++]--; } + + m_count--; } +bool wxSelectionStore::OnItemsDeleted(unsigned item, unsigned numItems) +{ + bool anyDeletedInSelItems = false, + allDeletedInSelItems = true; + + size_t i = m_itemsSel.IndexForInsert(item); + + const unsigned firstAfterDeleted = item + numItems; + while ( i < m_itemsSel.size() ) + { + if ( m_itemsSel[i] < firstAfterDeleted ) + { + // This item is going to be deleted, so remove it from the + // selected indices entirely. Notice that we do not update i here + // as it now refers to the next element. + m_itemsSel.RemoveAt(i); + + anyDeletedInSelItems = true; + } + else + { + // This item remains, just update its index. + m_itemsSel[i++] -= numItems; + + allDeletedInSelItems = false; + } + } + + m_count -= numItems; + + return m_defaultState ? allDeletedInSelItems : anyDeletedInSelItems; +} + + void wxSelectionStore::SetItemCount(unsigned count) { // forget about all items whose indices are now invalid if the size diff --git a/tests/misc/selstoretest.cpp b/tests/misc/selstoretest.cpp index 3184383f84..b1169625b5 100644 --- a/tests/misc/selstoretest.cpp +++ b/tests/misc/selstoretest.cpp @@ -46,6 +46,7 @@ private: CPPUNIT_TEST( SetItemCount ); CPPUNIT_TEST( Clear ); CPPUNIT_TEST( Iterate ); + CPPUNIT_TEST( ItemsAddDelete ); CPPUNIT_TEST_SUITE_END(); void SelectItem(); @@ -53,6 +54,7 @@ private: void SetItemCount(); void Clear(); void Iterate(); + void ItemsAddDelete(); // NB: must be even static const unsigned NUM_ITEMS; @@ -154,3 +156,34 @@ void SelStoreTestCase::Iterate() m_store->SelectItem(0, false); CPPUNIT_ASSERT_EQUAL(1, m_store->GetFirstSelectedItem(cookie)); } + +void SelStoreTestCase::ItemsAddDelete() +{ + m_store->SelectItem(0); + m_store->SelectItem(NUM_ITEMS/2); + m_store->SelectItem(NUM_ITEMS - 1); + + m_store->OnItemsInserted(NUM_ITEMS/2 + 1, 1); + CPPUNIT_ASSERT(m_store->IsSelected(0)); + CPPUNIT_ASSERT(m_store->IsSelected(NUM_ITEMS/2)); + CPPUNIT_ASSERT(m_store->IsSelected(NUM_ITEMS)); + CPPUNIT_ASSERT_EQUAL(3, m_store->GetSelectedCount()); + + CPPUNIT_ASSERT(m_store->OnItemsDeleted(NUM_ITEMS/2 - 1, 2)); + CPPUNIT_ASSERT(m_store->IsSelected(0)); + CPPUNIT_ASSERT(m_store->IsSelected(NUM_ITEMS - 2)); + CPPUNIT_ASSERT_EQUAL(2, m_store->GetSelectedCount()); + + m_store->OnItemsInserted(0, 2); + CPPUNIT_ASSERT(m_store->IsSelected(2)); + CPPUNIT_ASSERT(m_store->IsSelected(NUM_ITEMS)); + CPPUNIT_ASSERT_EQUAL(2, m_store->GetSelectedCount()); + + m_store->OnItemDelete(0); + + m_store->SelectRange(0, NUM_ITEMS - 1); + CPPUNIT_ASSERT(m_store->OnItemsDeleted(0, NUM_ITEMS/2)); + CPPUNIT_ASSERT_EQUAL(NUM_ITEMS/2, m_store->GetSelectedCount()); + CPPUNIT_ASSERT(m_store->IsSelected(0)); + CPPUNIT_ASSERT(m_store->IsSelected(NUM_ITEMS/2)); +}