mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-31 07:37:24 +00:00
Add a C++ Filter Model class (#1685)
Add a C++ Filter Model class This matches the FilterModel in the Rust API.
This commit is contained in:
parent
edcefac4c5
commit
5b95466fa6
4 changed files with 376 additions and 0 deletions
219
api/cpp/tests/models.cpp
Normal file
219
api/cpp/tests/models.cpp
Normal file
|
@ -0,0 +1,219 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
#include <chrono>
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
#include <slint.h>
|
||||
|
||||
struct ModelObserver : public slint::private_api::AbstractRepeaterView
|
||||
{
|
||||
void row_added(int index, int count) override { added_rows.push_back(Range { index, count }); }
|
||||
void row_changed(int index) override { changed_rows.push_back(index); }
|
||||
void row_removed(int index, int count) override
|
||||
{
|
||||
removed_rows.push_back(Range { index, count });
|
||||
}
|
||||
void reset() override { model_reset = true; }
|
||||
|
||||
void clear()
|
||||
{
|
||||
added_rows.clear();
|
||||
changed_rows.clear();
|
||||
removed_rows.clear();
|
||||
model_reset = false;
|
||||
}
|
||||
|
||||
struct Range
|
||||
{
|
||||
int row_index;
|
||||
int count;
|
||||
|
||||
bool operator==(const Range &) const = default;
|
||||
};
|
||||
std::vector<Range> added_rows;
|
||||
std::vector<int> changed_rows;
|
||||
std::vector<Range> removed_rows;
|
||||
bool model_reset = false;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ModelObserver::Range &value)
|
||||
{
|
||||
os << "{ row_index: " << value.row_index << "; count: " << value.count << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
SCENARIO("Filtering Model")
|
||||
{
|
||||
auto vec_model =
|
||||
std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });
|
||||
|
||||
auto even_rows = std::make_shared<slint::FilterModel<int>>(
|
||||
vec_model, [](auto value) { return value % 2 == 0; });
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
}
|
||||
|
||||
SCENARIO("Filtering Insert")
|
||||
{
|
||||
auto vec_model =
|
||||
std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });
|
||||
|
||||
auto even_rows = std::make_shared<slint::FilterModel<int>>(
|
||||
vec_model, [](auto value) { return value % 2 == 0; });
|
||||
|
||||
auto observer = std::make_shared<ModelObserver>();
|
||||
even_rows->attach_peer(observer);
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
|
||||
vec_model->insert(2, 10);
|
||||
|
||||
REQUIRE(observer->added_rows.size() == 1);
|
||||
REQUIRE(observer->added_rows[0] == ModelObserver::Range { 1, 1 });
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 4);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 10);
|
||||
REQUIRE(even_rows->row_data(2) == 4);
|
||||
REQUIRE(even_rows->row_data(3) == 6);
|
||||
|
||||
// insert odd number -> no change
|
||||
vec_model->insert(0, 1);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
}
|
||||
|
||||
SCENARIO("Filtering Change")
|
||||
{
|
||||
auto vec_model =
|
||||
std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });
|
||||
|
||||
auto even_rows = std::make_shared<slint::FilterModel<int>>(
|
||||
vec_model, [](auto value) { return value % 2 == 0; });
|
||||
|
||||
auto observer = std::make_shared<ModelObserver>();
|
||||
even_rows->attach_peer(observer);
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
|
||||
// change leading odd 1 to odd 3 -> no change
|
||||
vec_model->set_row_data(0, 3);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
|
||||
// change trailing 6 to odd 1 -> one row less
|
||||
vec_model->set_row_data(5, 1);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.size() == 1);
|
||||
REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 2, 1 });
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 2);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
|
||||
// change leading odd 3 to even 0 -> one new row
|
||||
vec_model->set_row_data(0, 0);
|
||||
|
||||
REQUIRE(observer->added_rows.size() == 1);
|
||||
REQUIRE(observer->added_rows[0] == ModelObserver::Range { 0, 1 });
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 0);
|
||||
REQUIRE(even_rows->row_data(1) == 2);
|
||||
REQUIRE(even_rows->row_data(2) == 4);
|
||||
|
||||
// change trailing filtered 4 to even 0 -> one changed row
|
||||
vec_model->set_row_data(3, 0);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.size() == 1);
|
||||
REQUIRE(observer->changed_rows[0] == 2);
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 0);
|
||||
REQUIRE(even_rows->row_data(1) == 2);
|
||||
REQUIRE(even_rows->row_data(2) == 0);
|
||||
}
|
||||
|
||||
SCENARIO("Filtering Model Remove")
|
||||
{
|
||||
auto vec_model =
|
||||
std::make_shared<slint::VectorModel<int>>(std::vector<int> { 1, 2, 3, 4, 5, 6 });
|
||||
|
||||
auto even_rows = std::make_shared<slint::FilterModel<int>>(
|
||||
vec_model, [](auto value) { return value % 2 == 0; });
|
||||
|
||||
auto observer = std::make_shared<ModelObserver>();
|
||||
even_rows->attach_peer(observer);
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
|
||||
// Erase unrelated row
|
||||
vec_model->erase(0);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.empty());
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 3);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
REQUIRE(even_rows->row_data(2) == 6);
|
||||
|
||||
// Erase trailing even 6
|
||||
vec_model->erase(4);
|
||||
|
||||
REQUIRE(observer->added_rows.empty());
|
||||
REQUIRE(observer->changed_rows.empty());
|
||||
REQUIRE(observer->removed_rows.size() == 1);
|
||||
REQUIRE(observer->removed_rows[0] == ModelObserver::Range { 2, 1 });
|
||||
REQUIRE(!observer->model_reset);
|
||||
observer->clear();
|
||||
|
||||
REQUIRE(even_rows->row_count() == 2);
|
||||
REQUIRE(even_rows->row_data(0) == 2);
|
||||
REQUIRE(even_rows->row_data(1) == 4);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue